summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2008-08-23 11:16:44 +0200
committerAndreas Rumpf <rumpf_a@web.de>2008-08-23 11:16:44 +0200
commit07d5a8085bbcc21a1d9d06a2976ecc00e9c8d55b (patch)
treeb07a53afeb56f4bba917c1a3a843f48dd25b62be
parent916c25f9a70b68eb7a5e2c45d7cc2e10c6e3a525 (diff)
downloadNim-07d5a8085bbcc21a1d9d06a2976ecc00e9c8d55b.tar.gz
too many changes to list
-rw-r--r--config/doctempl.cfg11
-rw-r--r--config/nimrod.cfg296
-rw-r--r--data/ast.yml87
-rw-r--r--data/basicopt.txt5
-rw-r--r--data/keywords.txt4
-rw-r--r--data/magic.yml54
-rw-r--r--data/messages.yml28
-rw-r--r--diff/empty.txt (renamed from doc/html/empty.txt)0
-rw-r--r--doc/docs.txt6
-rw-r--r--doc/grammar.txt25
-rw-r--r--doc/lib.txt97
-rw-r--r--doc/manual.txt3487
-rw-r--r--doc/nimrodc.txt33
-rw-r--r--doc/posix.txt220
-rw-r--r--doc/readme.txt6
-rw-r--r--doc/regexprs.txt22
-rw-r--r--doc/theindex.txt3854
-rw-r--r--doc/tutorial.txt8
-rw-r--r--ide/main.nim400
-rw-r--r--ide/nimide.glade399
-rw-r--r--install.txt71
-rw-r--r--koch.py1115
-rw-r--r--kochmod.py1302
-rw-r--r--lib/ansi_c.nim6
-rw-r--r--lib/arithm.nim20
-rw-r--r--lib/assign.nim6
-rw-r--r--lib/base/cairo/cairo.nim34
-rw-r--r--lib/base/gtk/atk.nim6
-rw-r--r--lib/base/gtk/gdk2.nim80
-rw-r--r--lib/base/gtk/gdk2pixbuf.nim4
-rw-r--r--lib/base/gtk/glib2.nim98
-rw-r--r--lib/base/gtk/gtk2.nim173
-rw-r--r--lib/base/gtk/gtkhtml.nim4
-rw-r--r--lib/base/gtk/pango.nim54
-rw-r--r--lib/base/nregex.nim2
-rw-r--r--lib/base/pcre.nim4
-rw-r--r--lib/complex.nim6
-rw-r--r--lib/debugger.nim51
-rw-r--r--lib/dlmalloc.c10144
-rw-r--r--lib/excpt.nim55
-rw-r--r--lib/gc.nim626
-rw-r--r--lib/hti.nim51
-rw-r--r--lib/int64s.nim3
-rw-r--r--lib/math.nim214
-rw-r--r--lib/memman.nim217
-rw-r--r--lib/nimbase.h93
-rw-r--r--lib/optparse.nim39
-rw-r--r--lib/os.nim90
-rw-r--r--lib/posix/posix.nim80
-rw-r--r--lib/process.nim2
-rw-r--r--lib/ptrset.nim8
-rw-r--r--lib/repr.nim480
-rw-r--r--lib/strutils.nim80
-rw-r--r--lib/sysio.nim18
-rw-r--r--lib/sysstr.nim24
-rw-r--r--lib/system.nim626
-rw-r--r--lib/times.nim278
-rw-r--r--lib/typeinfo.nim221
-rw-r--r--lib/windows/mmsystem.nim170
-rw-r--r--lib/windows/nb30.nim26
-rw-r--r--lib/windows/shellapi.nim32
-rw-r--r--lib/windows/windows.nim1114
-rw-r--r--nim/ast.pas356
-rw-r--r--nim/astalgo.pas146
-rw-r--r--nim/bitsets.pas17
-rw-r--r--nim/ccgexprs.pas1350
-rw-r--r--nim/ccgstmts.pas211
-rw-r--r--nim/ccgtypes.pas595
-rw-r--r--nim/ccgutils.pas32
-rw-r--r--nim/cgen.pas370
-rw-r--r--nim/commands.pas35
-rw-r--r--nim/crc.pas2
-rw-r--r--nim/docgen.pas257
-rw-r--r--nim/ecmasgen.pas1869
-rw-r--r--nim/eval.pas1238
-rw-r--r--nim/extccomp.pas162
-rw-r--r--nim/genhelp.pas175
-rw-r--r--nim/hashes.pas14
-rw-r--r--nim/highlite.pas101
-rw-r--r--nim/importer.pas39
-rw-r--r--nim/instgen.pas76
-rw-r--r--nim/lexbase.pas2
-rw-r--r--nim/lookup.pas51
-rw-r--r--nim/main.pas33
-rw-r--r--nim/msgs.pas75
-rw-r--r--nim/nimconf.pas10
-rw-r--r--nim/nimrod.pas74
-rw-r--r--nim/nimsets.pas8
-rw-r--r--nim/nos.pas35
-rw-r--r--nim/nsystem.pas45
-rw-r--r--nim/nversion.pas92
-rw-r--r--nim/optast.pas34
-rw-r--r--nim/options.pas81
-rw-r--r--nim/parsecfg.pas414
-rw-r--r--nim/parseopt.pas153
-rw-r--r--nim/paslex.pas31
-rw-r--r--nim/pasparse.pas104
-rw-r--r--nim/platform.pas77
-rw-r--r--nim/pnimsyn.pas130
-rw-r--r--nim/pragmas.pas57
-rw-r--r--nim/rnimsyn.pas174
-rw-r--r--nim/rodgen.pas41
-rw-r--r--nim/ropes.pas160
-rw-r--r--nim/rst.pas123
-rw-r--r--nim/scanner.pas54
-rw-r--r--nim/sem.pas63
-rw-r--r--nim/semexprs.pas792
-rw-r--r--nim/semfold.pas150
-rw-r--r--nim/semstmts.pas384
-rw-r--r--nim/semtempl.pas19
-rw-r--r--nim/semtypes.pas149
-rw-r--r--nim/sigmatch.pas260
-rw-r--r--nim/strtabs.pas295
-rw-r--r--nim/strutils.pas23
-rw-r--r--nim/transf.pas217
-rw-r--r--nim/transtmp.pas3
-rw-r--r--nim/trees.pas51
-rw-r--r--nim/types.pas199
-rw-r--r--nim/vis.pas33
-rw-r--r--nim/wordrecg.pas34
-rw-r--r--nimrod.aip639
-rw-r--r--tests/bench/GCBench.c296
-rw-r--r--tests/bench/GCBench.cpp266
-rw-r--r--tests/bench/GCBench.java182
-rw-r--r--tests/bench/GCBench_OGC.cpp301
-rw-r--r--tests/bench/gcbench.nim172
-rw-r--r--tests/bench/prof.c63
-rw-r--r--tests/gc.bpf9
-rw-r--r--tests/gc.bpr85
-rw-r--r--tests/gctest.nim26
-rw-r--r--tests/hallo.bpf10
-rw-r--r--tests/hallo.bpr102
-rw-r--r--tests/iotest.bpf10
-rw-r--r--tests/iotest.bpr84
-rw-r--r--tests/minit.nim4
-rw-r--r--tests/mopaque.nim2
-rw-r--r--tests/rectest/rectest.nim6
-rw-r--r--tests/scantest.nim2
-rw-r--r--tests/seqcon.bpf8
-rw-r--r--tests/seqcon.bpr84
-rw-r--r--tests/tack.nim3
-rw-r--r--tests/tarray.nim7
-rw-r--r--tests/tassert.nim9
-rw-r--r--tests/tassign.nim11
-rw-r--r--tests/tblock1.nim3
-rw-r--r--tests/tconstr1.nim12
-rw-r--r--tests/tconstr2.nim11
-rw-r--r--tests/tcopy.nim2
-rw-r--r--tests/tformat.nim2
-rw-r--r--tests/tforwty.nim2
-rw-r--r--tests/tforwty2.nim4
-rw-r--r--tests/tgeneric.nim96
-rw-r--r--tests/thallo.dot6
-rw-r--r--tests/thallo.nim26
-rw-r--r--tests/tillrec.nim4
-rw-r--r--tests/tinit.nim2
-rw-r--r--tests/tinout.nim2
-rw-r--r--tests/tio.nim5
-rw-r--r--tests/titer.nim3
-rw-r--r--tests/tlastmod.nim2
-rw-r--r--tests/tloops.nim5
-rw-r--r--tests/tlowhigh.nim3
-rw-r--r--tests/tmath.nim3
-rw-r--r--tests/tnestif.nim3
-rw-r--r--tests/tnew.bpf10
-rw-r--r--tests/tnew.bpr84
-rw-r--r--tests/tobject2.nim3
-rw-r--r--tests/tobjects.nim3
-rw-r--r--tests/toverflw.nim3
-rw-r--r--tests/toverl.nim2
-rw-r--r--tests/toverlop.nim3
-rw-r--r--tests/tovfint.nim5
-rw-r--r--tests/tpos.nim3
-rw-r--r--tests/tprep.nim2
-rw-r--r--tests/tprocvar.nim3
-rw-r--r--tests/tpush.nim3
-rw-r--r--tests/tquit.nim3
-rw-r--r--tests/treadln.nim3
-rw-r--r--tests/trectype.nim2
-rw-r--r--tests/trefs.nim3
-rw-r--r--tests/tregex.nim2
-rw-r--r--tests/treguse.nim3
-rw-r--r--tests/trepr.nim5
-rw-r--r--tests/tseqcon.nim5
-rw-r--r--tests/tsizeof.nim5
-rw-r--r--tests/tstrdesc.nim7
-rw-r--r--tests/tstrdist.nim3
-rw-r--r--tests/tstrutil.nim2
-rw-r--r--tests/tvarious.nim6
-rw-r--r--tests/tvarnums.nim2
-rw-r--r--tests/twalker.nim4
-rw-r--r--tests/walker.bpf13
-rw-r--r--tests/walker.bpr102
-rw-r--r--todo.txt212
-rw-r--r--web/download.txt30
-rw-r--r--web/genweb.py52
-rw-r--r--web/index.txt45
-rw-r--r--web/news.txt39
-rw-r--r--web/question.txt242
-rw-r--r--web/sunset.tmpl2
200 files changed, 24286 insertions, 17751 deletions
diff --git a/config/doctempl.cfg b/config/doctempl.cfg
index 21869072e..4f99af78f 100644
--- a/config/doctempl.cfg
+++ b/config/doctempl.cfg
@@ -2,6 +2,10 @@
 # (c) 2008 Andreas Rumpf

 # Feel free to edit the templates as you need.

 

+split.item.toc = "25"  

+# too long entries in the table of contents get truncated

+# after this number of characters

+

 doc.section = """

 <div class="section" id="$sectionID">

 <h1><a class="toc-backref" href="#$sectionTitleID">$sectionTitle</a></h1>

@@ -52,10 +56,10 @@ $content
 """

 

 doc.file = """<?xml version="1.0" encoding="utf-8" ?>

-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 <!--  This file is generated by Nimrod. -->

+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

 <head>

 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

 <title>$title</title>

@@ -88,7 +92,7 @@ span.Command, span.Rule, span.Hyperlink, span.Label, span.Reference,
 span.Other  {color: black}

 

 div.navigation {

-  float: left; width: 20em;

+  float: left; width: 25em;

   margin: 0; padding: 0; /*

   border: 1px dashed gold; */

   outline: 3px outset #99ff99; //gold;

@@ -109,7 +113,7 @@ div.navigation ul li a:hover {
 }

 

 div.content {

-  margin-left: 20em;

+  margin-left: 25em;

   padding: 0 1em; 

   border: 1px dashed gold;

   min-width: 16em;

@@ -285,4 +289,3 @@ $content
 </html>

 """

 

-@write "used doctempl.cfg"

diff --git a/config/nimrod.cfg b/config/nimrod.cfg
index 8653b0449..0b4ddc6e7 100644
--- a/config/nimrod.cfg
+++ b/config/nimrod.cfg
@@ -1,140 +1,156 @@
-# Configuration file for the Nimrod Compiler.

-# Generated by the koch.py script.

-# (c) 2008 Andreas Rumpf

-

-# Feel free to edit the default values as you need.

-

-# You may set environment variables with

-# @putenv "key" "val"

-# Environment variables cannot be used in the options, however!

-

-# Just call the compiler with several options:

-cc = @if unix: gcc @else: llvm_gcc @end

-lib="$nimrod/lib"

-path="$lib/base"

-path="$lib/base/gtk"

-path="$lib/base/cairo"

-path="$lib/base/x11"

-path="$lib/windows"

-path="$lib/posix"

-path="$lib/extra"

-

-# additional defines:

-#define=""

-# additional options always passed to the compiler:

-force_build

-line_dir=off

-

-hint[LineTooLong]=off

-hint[XDeclaredButNotUsed]=off

-

-@if unix:

-  passl= "-ldl"

-  path = "$lib/base/gtk"

-@end

-

-@if icc:

-  passl = "-cxxlib"

-  passc = "-cxxlib"

-@end

-

-# Configuration for the LLVM GCC compiler:

-@if windows:

-  llvm_gcc.path = r"dist\llvm-gcc4.2\bin"

-@end

-llvm_gcc.options.debug = "-g"

-llvm_gcc.options.always = "-w"

-llvm_gcc.options.speed = "-O3 -ffast-math"

-llvm_gcc.options.size = "-Os -ffast-math"

-

-# Configuration for the Borland C++ Compiler:

-@if windows:

-  bcc.path = r"C:\eigenes\compiler\cbuilder5\bin"

-@end

-bcc.options.debug = ""

-# turn off warnings about unreachable code and inline procs:

-bcc.options.always = "-w- -H- -q -RT- -a8 -w-8027 -w-8066"

-bcc.options.speed = "-O2 -6"

-bcc.options.size = "-O1 -6"

-

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

-@if vcc:

-  @prepend_env path r"C:\Eigenes\compiler\vcc2005\Common7\IDE;"

-  @prepend_env INCLUDE r"C:\Eigenes\compiler\vcc2005\VC\include;C:\Eigenes\compiler\vcc2005\VC\ATLMFC\INCLUDE;"

-  @prepend_env LIB r"C:\Eigenes\compiler\vcc2005\VC\lib;C:\Eigenes\compiler\vcc2005\SDK\v2.0\Lib;"

-@end

-@if windows:

-  vcc.path = r"C:\Eigenes\compiler\vcc2005\VC\bin"

-@end

-vcc.options.debug = "/GZ /ZI"

-vcc.options.always = "/nologo"

-vcc.options.speed = "/Ogityb2 /G7 /arch:SSE2"

-vcc.options.size = "/O1 /G7"

-

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

-@if windows:

-  wcc.path = r"C:\eigenes\compiler\watcom\binnt"

-@end

-wcc.options.debug = "-d2"

-wcc.options.always = "-6 -zw -w-"

-wcc.options.speed = "-ox -on -6 -d0 -fp6 -zW"

-wcc.options.size = "-ox -on -6 -d0 -fp6 -zW"

-

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

-@if windows:

-  gcc.path = r"C:\eigenes\compiler\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 -ffast-math"

-gcc.options.size = "-Os -ffast-math"

-

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

-@if windows:

-  dmc.path = r"C:\eigenes\compiler\d\dm\bin"

-@end

-dmc.options.debug = "-g"

-dmc.options.always = "-Jm"

-dmc.options.speed = "-ff -o -6"

-dmc.options.size = "-ff -o -6"

-

-# Configuration for the LCC compiler:

-@if windows:

-  lcc.path = r"C:\eigenes\compiler\lcc\bin"

-@end

-lcc.options.debug = "-g5"

-lcc.options.always = "-e1"

-lcc.options.speed = "-O -p6"

-lcc.options.size = "-O -p6"

-

-# Configuration for the Tiny C Compiler:

-@if windows:

-  tcc.path = r"C:\eigenes\compiler\tcc\bin"

-@end

-tcc.options.debug = "-b"

-tcc.options.always = ""

-tcc.options.speed = ""

-tcc.options.size = ""

-

-# Configuration for the Pelles C compiler:

-@if windows:

-  pcc.path = r"C:\eigenes\compiler\pellesc\bin"

-@end

-pcc.options.debug = "-Zi"

-pcc.options.always = "-Ze"

-pcc.options.speed = "-Ox"

-pcc.options.size = "-Os"

-

-@if windows:

-  icc.path = r"c:\eignes\compiler\icc\bin"

-@end

-icc.options.debug = "-g"

-icc.options.always = "-w"

-icc.options.speed = "-O3 -ffast-math"

-icc.options.size = "-Os -ffast-math"

-

-@write "used default config file"

+# Configuration file for the Nimrod Compiler.
+# Generated by the koch.py script.
+# (c) 2008 Andreas Rumpf
+
+# Feel free to edit the default values as you need.
+
+# You may set environment variables with
+# @putenv "key" "val"
+# Environment variables cannot be used in the options, however!
+
+# Just call the compiler with several options:
+cc = @if unix: gcc @else: vcc @end
+lib="$nimrod/lib"
+path="$lib/base"
+path="$lib/base/gtk"
+path="$lib/base/cairo"
+path="$lib/base/x11"
+path="$lib/windows"
+path="$lib/posix"
+path="$lib/ecmas"
+path="$lib/extra"
+
+@if release:
+  checks:off
+  stacktrace:off
+  debugger:off
+  line_dir:off
+@end
+
+# additional defines:
+#define=""
+# additional options always passed to the compiler:
+force_build
+line_dir=off
+cfilecache=on
+
+hint[LineTooLong]=off
+hint[XDeclaredButNotUsed]=off
+
+@if unix:
+  passl= "-ldl"
+  path = "$lib/base/gtk"
+@end
+
+@if icc:
+  passl = "-cxxlib"
+  passc = "-cxxlib"
+@end
+
+# Configuration for the LLVM GCC compiler:
+@if windows:
+  llvm_gcc.path = r"$nimrod\dist\llvm-gcc4.2\bin"
+@end
+llvm_gcc.options.debug = "-g"
+llvm_gcc.options.always = "-w"
+llvm_gcc.options.speed = "-O3 -ffast-math"
+llvm_gcc.options.size = "-Os -ffast-math"
+
+# Configuration for the Borland C++ Compiler:
+@if windows:
+  bcc.path = r"C:\eigenes\compiler\cbuilder5\bin"
+@end
+bcc.options.debug = ""
+# turn off warnings about unreachable code and inline procs:
+bcc.options.always = "-w- -H- -q -RT- -a8 -w-8027 -w-8066"
+bcc.options.speed = "-O2 -6"
+bcc.options.size = "-O1 -6"
+
+# Configuration for the Visual C/C++ compiler:
+@if vcc:
+  @prepend_env path r"C:\Programme\Microsoft Visual Studio 9.0\Common7\IDE;"
+  @prepend_env INCLUDE r"C:\Programme\Microsoft Visual Studio 9.0\VC\include;C:\Programme\Microsoft Visual Studio 9.0\VC\ATLMFC\INCLUDE;C:\Programme\Microsoft SDKs\Windows\v6.0A\Include;"
+  @prepend_env LIB r"C:\Programme\Microsoft Visual Studio 9.0\VC\lib;C:\Programme\Microsoft Visual Studio 9.0\SDK\v2.0\Lib;C:\Programme\Microsoft SDKs\Windows\v6.0A\Lib;"
+  passl: r"/F33554432" # set the stack size to 8 MB
+@end
+@if windows:
+  vcc.path = r"C:\Programme\Microsoft Visual Studio 9.0\VC\bin"
+@end
+vcc.options.debug = "/RTC1 /ZI"
+vcc.options.always = "/nologo"
+vcc.options.speed = "/Ogityb2 /G7 /arch:SSE2"
+vcc.options.size = "/O1 /G7"
+
+# Configuration for the Watcom C/C++ compiler:
+@if windows:
+  wcc.path = r"C:\eigenes\compiler\watcom\binnt"
+@end
+wcc.options.debug = "-d2"
+wcc.options.always = "-6 -zw -w-"
+wcc.options.speed = "-ox -on -6 -d0 -fp6 -zW"
+wcc.options.size = "-ox -on -6 -d0 -fp6 -zW"
+
+# Configuration for the GNU C/C++ compiler:
+@if windows:
+  gcc.path = r"C:\eigenes\compiler\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 -ffast-math"
+gcc.options.size = "-Os -ffast-math"
+
+# Configuration for the Digital Mars C/C++ compiler:
+@if windows:
+  dmc.path = r"C:\eigenes\compiler\d\dm\bin"
+@end
+dmc.options.debug = "-g"
+dmc.options.always = "-Jm"
+dmc.options.speed = "-ff -o -6"
+dmc.options.size = "-ff -o -6"
+
+# Configuration for the LCC compiler:
+@if windows:
+  lcc.path = r"C:\eigenes\compiler\lcc\bin"
+@end
+lcc.options.debug = "-g5"
+lcc.options.always = "-e1"
+lcc.options.speed = "-O -p6"
+lcc.options.size = "-O -p6"
+
+# Configuration for the Tiny C Compiler:
+@if windows:
+  tcc.path = r"C:\Eigenes\compiler\tcc-0.9.23\tcc"
+  tcc.options.always = r"-IC:\Eigenes\compiler\tcc-0.9.23\include " &
+                   r"-IC:\Eigenes\compiler\tcc-0.9.23\include\winapi"
+@end
+tcc.options.debug = ""
+tcc.options.speed = ""
+tcc.options.size = ""
+
+# Configuration for the Pelles C compiler:
+@if windows:
+  pcc.path = r"C:\eigenes\compiler\pellesc\bin"
+@end
+pcc.options.debug = "-Zi"
+pcc.options.always = "-Ze"
+pcc.options.speed = "-Ox"
+pcc.options.size = "-Os"
+
+@if windows:
+  icc.path = r"c:\eignes\compiler\icc\bin"
+@end
+icc.options.debug = "-g"
+icc.options.always = "-w"
+icc.options.speed = "-O3 -ffast-math"
+icc.options.size = "-Os -ffast-math"
+
+@write "used special config file"
+
+@if ecmascript:
+  @write "Target is ECMAScript! No unsafe features are allowed!"
+@end
+
diff --git a/data/ast.yml b/data/ast.yml
index ee688909d..72a1b02b5 100644
--- a/data/ast.yml
+++ b/data/ast.yml
@@ -9,7 +9,7 @@
 
 {
 'SymFlag': [          # already 32 flags!
-  'sfGeneric',        # whether an operator, proc or type is generic
+  'sfTypeCheck',      # wether macro parameters should be type checked
   'sfForward',        # symbol is forward directed
   'sfImportc',        # symbol is external; imported
   'sfExportc',        # symbol is exported (under a specified name)
@@ -26,7 +26,7 @@
   'sfMainModule',     # module is the main module
   'sfSystemModule',   # module is the system module
   'sfNoReturn',       # proc never returns (an exit proc)
-  'sfReturnsNew',     # proc returns new allocated thing (allows optimizations)
+  'sfAddrTaken',      # the variable's address is taken (ex- or implicitely)
   'sfInInterface',    # symbol is in interface section declared
   'sfNoStatic',       # symbol is used within an iterator (needed for codegen)
                       # so it cannot be 'static' in the C code
@@ -56,32 +56,40 @@
                       # is used to speed up semantic checking a bit
   'tfEnumHasWholes',  # enum cannot be mapped into a range
   'tfVarargs',        # procedure has C styled varargs
-  'tfAssignable'      # can the type be assigned to?
+  'tfFinal'           # is the object final?
 ],
 
 'TypeKind': [        # order is important!
                      # Don't forget to change hti.nim if you make a change here
-   'tyNone', 'tyBool', 'tyChar',
-   'tyEmptySet', 'tyArrayConstr', 'tyNil', 'tyRecordConstr',
-   'tyGeneric',
-   'tyGenericInst', # instantiated generic type
-   'tyGenericParam',
-   'tyEnum', 'tyAnyEnum',
-   'tyArray',
-   'tyRecord',
-   'tyObject',
-   'tyTuple',
-   'tySet',
-   'tyRange',
-   'tyPtr', 'tyRef',
-   'tyVar',
-   'tySequence',
-   'tyProc',
-   'tyPointer', 'tyOpenArray',
-   'tyString', 'tyCString', 'tyForward',
-   # numerical types:
-   'tyInt', 'tyInt8', 'tyInt16', 'tyInt32', 'tyInt64', # signed integers
-   'tyFloat', 'tyFloat32', 'tyFloat64', 'tyFloat128'
+  'tyNone', 'tyBool', 'tyChar',
+  'tyEmptySet', 'tyArrayConstr', 'tyNil', 
+  'tyGeneric',
+  'tyGenericInst', # instantiated generic type
+  'tyGenericParam',
+  'tyEnum',
+  'tyAnyEnum',
+  'tyArray',
+  'tyObject',
+  'tyTuple',
+  'tySet',
+  'tyRange',
+  'tyPtr', 'tyRef',
+  'tyVar',
+  'tySequence',
+  'tyProc',
+  'tyPointer', 'tyOpenArray',
+  'tyString', 'tyCString', 'tyForward',
+  # numerical types:
+  'tyInt', 'tyInt8', 'tyInt16', 'tyInt32', 'tyInt64', # signed integers
+  'tyFloat', 'tyFloat32', 'tyFloat64', 'tyFloat128'
+],
+
+'NodeFlag': [ # keep this number under 16 for performance reasons!
+  'nfNone',
+  'nfBase2', # nfBase10 is default, so not needed
+  'nfBase8',
+  'nfBase16',
+  'nfAllConst' # used to mark complex expressions constant
 ],
 
 'NodeKind': [  # these are pure nodes
@@ -97,7 +105,6 @@
   'nkType',               # node is used for its typ field
 
   'nkCharLit',            # a character literal ''
-  'nkRCharLit',           # a raw character literal r''
 
   'nkIntLit',             # an integer literal
   'nkInt8Lit',
@@ -110,6 +117,8 @@
   'nkStrLit',             # a string literal ""
   'nkRStrLit',            # a raw string literal r""
   'nkTripleStrLit',       # a triple string literal """
+  'nkMetaNode',           # difficult to explan; represents itself
+                          # (used for macros)
   'nkNilLit',             # the nil literal
   # end of atoms
   'nkDotCall',            # used to temporarily flag a nkCall node; this is used
@@ -126,7 +135,7 @@
   'nkInfix',              # a call like (a + b)
   'nkPrefix',             # a call like !a
   'nkPostfix',            # something like a! (also used for visibility)
-  'nkPar',                # syntactic ()
+  'nkPar',                # syntactic (); may be a tuple constructor
   'nkCurly',              # syntactic {}
   'nkBracket',            # syntactic []
   'nkBracketExpr',        # an expression like a[i..j, k]
@@ -142,14 +151,7 @@
   'nkAccQuoted',          # `a` as a node
   'nkHeaderQuoted',       # `a(x: int)` as a node
 
-  'nkSetConstr',          # a set constructor {}
-  'nkConstSetConstr',     # a set constructor with only constant expressions
-  'nkArrayConstr',        # an array constructor []
-  'nkConstArrayConstr',   # an array constructor with only constant expressions
-  'nkRecordConstr',       # a record constructor []
-  'nkConstRecordConstr',  # a record constructor with only constant expressions
   'nkTableConstr',        # a table constructor {expr: expr}
-  'nkConstTableConstr',   # a table constructor with only constant expressions
   'nkQualified',          # describes a.b for qualified identifiers
   'nkHiddenStdConv',      # an implicit standard type conversion
   'nkHiddenSubConv',      # an implicit type conversion from a subtype
@@ -158,6 +160,16 @@
   'nkConv',               # a type conversion
   'nkCast',               # a type cast
   'nkAddr',               # a addr expression
+  'nkHiddenAddr',         # implicit address operator
+  'nkHiddenDeref',        # implicit ^ operator
+  'nkObjDownConv',        # down conversion between object types
+  'nkObjUpConv',          # up conversion between object types
+  'nkChckRangeF',         # range check for floats
+  'nkChckRange64',        # range check for 64 bit ints
+  'nkChckRange',          # range check for ints
+  'nkStringToCString',    # string to cstring
+  'nkCStringToString',    # cstring to string
+  'nkPassAsOpenArray',    # thing is passed as an open array
   # end of expressions
 
   'nkAsgn',               # a = b
@@ -198,8 +210,6 @@
   'nkBreakStmt',          # a break statement
   'nkContinueStmt',       # a continue statement
   'nkBlockStmt',          # a block statement
-  'nkGotoStmt',           # used by the transformation pass; first son is a sym
-                          # node containing a label
   'nkDiscardStmt',        # a discard statement
   'nkStmtList',           # a list of statements
   'nkImportStmt',         # an import statement
@@ -218,8 +228,8 @@
 
   # types as syntactic trees:
   'nkTypeOfExpr',
-  'nkRecordTy',
   'nkObjectTy',
+  'nkTupleTy',
   'nkRecList',            # list of record/object parts
   'nkRecCase',            # case section of record/object
   'nkRecWhen',            # when section of record/object
@@ -228,8 +238,9 @@
   'nkVarTy',
   'nkProcTy',
   'nkEnumTy',
-  'nkEnumFieldDef'        # `ident = expr` in an enumeration
-], 
+  'nkEnumFieldDef',       # `ident = expr` in an enumeration
+  'nkReturnToken',        # token used for interpretation
+],
 
 'SymKind': [
   # the different symbols (start with the prefix sk);
diff --git a/data/basicopt.txt b/data/basicopt.txt
index a6f6ffee5..dff49c3e8 100644
--- a/data/basicopt.txt
+++ b/data/basicopt.txt
@@ -4,7 +4,8 @@ Command::
   compile                   compile project with default code generator (C)
   compile_to_c              compile project with C code generator
   compile_to_cpp            compile project with C++ code generator
-  doc                       generate the documentation for inputfile; 
+  compile_to_ecmascript     compile project to ECMAScript code (experimental)
+  doc                       generate the documentation for inputfile;
                             with --run switch opens it with $BROWSER
 Arguments:
   arguments are passed to the program being run (if --run option is selected)
@@ -18,6 +19,8 @@ Options:
   --line_trace:on|off       code generation for line trace ON|OFF
   --debugger:on|off         turn Embedded Nimrod Debugger ON|OFF
   -x, --checks:on|off       code generation for all runtime checks ON|OFF
+  --obj_checks:on|off       code generation for obj conversion checks ON|OFF
+  --field_checks:on|off     code generation for case record fields ON|OFF
   --range_checks:on|off     code generation for range checks ON|OFF
   --bound_checks:on|off     code generation for bound checks ON|OFF
   --overflow_checks:on|off  code generation for over-/underflow checks ON|OFF
diff --git a/data/keywords.txt b/data/keywords.txt
index 4e5a1c8e6..5915bab05 100644
--- a/data/keywords.txt
+++ b/data/keywords.txt
@@ -10,9 +10,9 @@ macro method mod
 nil not notin
 object of or out
 proc ptr
-raise record ref return
+raise ref return
 shl shr
-template try type
+template try tuple type
 var
 when where while with without
 xor
diff --git a/data/magic.yml b/data/magic.yml
index a126b8075..519505eab 100644
--- a/data/magic.yml
+++ b/data/magic.yml
@@ -113,8 +113,13 @@
 'UnaryPlusF64',
 'UnaryMinusF64',
 'AbsF64',
-'Ze',
-'Ze64',
+'Ze8ToI',
+'Ze8ToI64',
+'Ze16ToI',
+'Ze16ToI64',
+'Ze32ToI64',
+'ZeIToI64',
+
 'ToU8',
 'ToU16',
 'ToU32',
@@ -123,6 +128,14 @@
 'ToInt',
 'ToBiggestInt',
 
+'CharToStr',
+'BoolToStr',
+'IntToStr',  # $ for ints
+'Int64ToStr',
+'FloatToStr',
+'CStrToStr',
+'StrToStr',
+
 # special ones:
 'And',
 'Or',
@@ -156,12 +169,12 @@
 'SetLengthSeq',
 'Assert',
 'Swap',
+'IsNil',
 
 # magic type constructors:
 'Array',
 'OpenArray',
 'Range',
-'Tuple',
 'Set',
 'Seq',
 
@@ -172,5 +185,38 @@
 'NimrodMajor',
 'NimrodMinor',
 'NimrodPatch',
-'CpuEndian'
+'CpuEndian',
+'NaN',
+'Inf',
+'NegInf',
+
+# magics for modifying the AST (macro support)
+'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'
 ]
diff --git a/data/messages.yml b/data/messages.yml
index e45c41754..8892b2c3f 100644
--- a/data/messages.yml
+++ b/data/messages.yml
@@ -23,7 +23,7 @@
 {'errInvalidToken': 'invalid token: $1'},
 {'errLineTooLong': 'line too long'},
 {'errInvalidNumber': '$1 is not a valid number'},
-{'errNumberOutOfRange': '$1 is too large or too small'},
+{'errNumberOutOfRange': 'number $1 out of valid range'},
 {'errNnotAllowedInCharacter': '\\n not allowed in character literal'},
 {'errClosingBracketExpected': "closing ']' expected, but end of file reached"},
 {'errMissingFinalQuote': "missing final '"},
@@ -32,10 +32,6 @@
 {'errTokenExpected': "'$1' expected"},
 {'errStringAfterIncludeExpected': "string after 'include' expected"},
 {'errRecursiveInclude': "recursive include file: '$1'"},
-{'errAtIfExpected': "'@if' expected"},
-{'errAtIfExpectedBeforeElse': "'@if' expected before '@else'"},
-{'errAtIfExpectedBeforeElif': "'@if' expected before '@elif'"},
-{'errAtEndExpected': "'@end' expected"},
 {'errOnOrOffExpected': "'on' or 'off' expected"},
 {'errNoneSpeedOrSizeExpected': "'none', 'speed' or 'size' expected"},
 {'errInvalidPragma': 'invalid pragma'},
@@ -157,13 +153,13 @@
 {'errSizeTooBig': "computing the type's size produced an overflow"},
 {'errSetTooBig': 'set is too large'},
 {'errBaseTypeMustBeOrdinal': 'base type of a set must be an ordinal'},
-{'errInheritanceOnlyWithObjects': 'inheritance only works with an object'},
+{'errInheritanceOnlyWithNonFinalObjects': 'inheritance only works non-final objects'},
 {'errInheritanceOnlyWithEnums': 'inheritance only works with an enum'},
 {'errIllegalRecursionInTypeX': "illegal recursion in type '$1'"},
 {'errCannotInstantiateX': "cannot instantiate: '$1'"},
-{'errExprHasNoAddress': 'expression has no address'},
+{'errExprHasNoAddress': "expression has no address"},
 {'errVarForOutParamNeeded':
-  'to an out parameter a variable needs to be passed'},
+  "for a 'var' type a variable needs to be passed"},
 {'errPureTypeMismatch': 'type mismatch'},
 {'errTypeMismatch': 'type mismatch: got ('},
 {'errButExpected': 'but expected one of: '},
@@ -243,6 +239,20 @@
 {'errWhitespaceExpected': "whitespace expected, got '$1'"},
 {'errXisNoValidIndexFile': "'$1' is no valid index file"},
 {'errCannotRenderX': "cannot render reStructuredText element '$1'"},
+{'errVarVarTypeNotAllowed': "type 'var var' is not allowed"},
+{'errIsExpectsTwoArguments': "'is' expects two arguments"},
+{'errIsExpectsObjectTypes': "'is' expects object types"},
+{'errXcanNeverBeOfThisSubtype': "'$1' can never be of this subtype"},
+{'errTooManyIterations': "interpretation requires too many iterations"},
+{'errCannotInterpretNodeX': "cannot interpret node kind '$1'"},
+{'errFieldXNotFound': "field '$1' cannot be found"},
+{'errInvalidConversionFromTypeX': "invalid conversion from type '$1'"},
+{'errAssertionFailed': "assertion failed"},
+{'errCannotGenerateCodeForX': "cannot generate code for '$1'"},
+{'errXNeedsReturnType': "converter needs return type"},
+{'errXRequiresOneArgument': "converter requires one parameter"},
+{'errUnhandledExceptionX': "unhandled exception: $1"},
+{'errCyclicTree': "macro returned a cyclic abstract syntax tree"},
 
 # user error message:
 {'errUser': '$1'},
@@ -276,6 +286,8 @@
 {'hintMo2FileInvalid': "mo2 file '$1' is invalid"},
 {'hintModuleHasChanged': "module '$1' has been changed"},
 {'hintCannotOpenMo2File': "mo2 file '$1' does not exist"},
+{'hintQuitCalled': "quit() called"},
+{'hintProcessing': "processing"},
 
 # user hint message:
 {'hintUser': '$1'}
diff --git a/doc/html/empty.txt b/diff/empty.txt
index 20f9a91e3..20f9a91e3 100644
--- a/doc/html/empty.txt
+++ b/diff/empty.txt
diff --git a/doc/docs.txt b/doc/docs.txt
index f58a16f48..b2fe3ebed 100644
--- a/doc/docs.txt
+++ b/doc/docs.txt
@@ -3,6 +3,9 @@
 
 The documentation consists of several documents:
 
+- | `First steps after installation <steps.html>`_
+  | Read this after installation for a quick introduction.
+
 - | `Nimrod manual <manual.html>`_
   | Read this to get to know the Nimrod programming system.
 
@@ -21,6 +24,5 @@ The documentation consists of several documents:
     this if you want to hack the compiler or develop advanced macros.
 
 - | `Index <theindex.html>`_
-  | The generated index. Often the quickest way to find the piece of 
+  | The generated index. Often the quickest way to find the piece of
     information you need.
-
diff --git a/doc/grammar.txt b/doc/grammar.txt
index 6bbf2c3e7..03f4b65b9 100644
--- a/doc/grammar.txt
+++ b/doc/grammar.txt
@@ -78,6 +78,7 @@ typeDescK ::= VAR typeDesc
             | REF typeDesc

             | PTR typeDesc

             | TYPE expr

+            | TUPLE tupleDesc

             | PROC paramList [pragma]

 

 typeDesc ::= typeDescK | primary

@@ -157,23 +158,23 @@ colonAndEquals ::= [COLON typeDesc] EQUALS expr
 constDecl ::= symbol ["*"] [pragma] colonAndEquals [COMMENT | IND COMMENT]

             | COMMENT

 constSection ::= CONST indPush constDecl (SAD constDecl)* DED

-typeDef ::= typeDesc | recordDef | objectDef | enumDef

+typeDef ::= typeDesc | objectDef | enumDef

 

-recordIdentPart ::=

+objectIdentPart ::=

    (symbol ["*" | "-"] [pragma] optComma)+ COLON typeDesc [COMMENT | IND COMMENT]

 

-recordWhen ::= WHEN expr COLON [COMMENT] recordPart

-              (ELIF expr COLON [COMMENT] recordPart)*

-              [ELSE COLON [COMMENT] recordPart]

-recordCase ::= CASE expr COLON typeDesc [COMMENT]

-              (OF sliceList COLON [COMMENT] recordPart)*

-              [ELSE COLON [COMMENT] recordPart]

+objectWhen ::= WHEN expr COLON [COMMENT] objectPart

+              (ELIF expr COLON [COMMENT] objectPart)*

+              [ELSE COLON [COMMENT] objectPart]

+objectCase ::= CASE expr COLON typeDesc [COMMENT]

+              (OF sliceList COLON [COMMENT] objectPart)*

+              [ELSE COLON [COMMENT] objectPart]

 

-recordPart ::= recordWhen | recordCase | recordIdentPart

-             | indPush recordPart (SAD recordPart)* DED

-recordDef ::= RECORD [pragma] recordPart

+objectPart ::= objectWhen | objectCase | objectIdentPart

+             | indPush objectPart (SAD objectPart)* DED

+tupleDesc ::= BRACKET_LE optInd ((symbol optComma)+ COLON typeDesc optComma)* BRACKET_RI

 

-objectDef ::= OBJECT [pragma] [OF typeDesc] recordPart

+objectDef ::= OBJECT [pragma] [OF typeDesc] objectPart

 enumDef ::= ENUM [OF typeDesc] (symbol [EQUALS expr] optComma [COMMENT | IND COMMENT])+

 

 typeDecl ::= COMMENT

diff --git a/doc/lib.txt b/doc/lib.txt
index 4e4f9caa0..2fef5934d 100644
--- a/doc/lib.txt
+++ b/doc/lib.txt
@@ -13,36 +13,119 @@ Advanced libraries are in the ``lib/base`` directory.
 Basic libraries

 ===============

 

-* `System <system.html>`_

+* `system <system.html>`_

   Basic procs and operators that every program needs. It also provides IO

   facilities for reading and writing text and binary files. It is imported

   implicitly by the compiler. Do not import it directly. It relies on compiler

   magic to work.

 

-* `Strutils <strutils.html>`_

+* `strutils <strutils.html>`_

   This module contains common string handling operations like converting a

   string into uppercase, splitting a string into substrings, searching for

   substrings, replacing substrings.

 

-* `OS <os.html>`_

+* `os <os.html>`_

   Basic operating system facilities like retrieving environment variables,

   reading command line arguments, working with directories, running shell

   commands, etc. This module is -- like any other basic library --

   platform independant.

 

-* `Math <math.html>`_

+* `math <math.html>`_

   Mathematical operations like cosine, square root.

 

-* `Complex <complex.html>`_

+* `complex <complex.html>`_

   This module implements complex numbers and their mathematical operations.

 

-* `Times <times.html>`_

+* `times <times.html>`_

   The ``times`` module contains basic support for working with time.

 

+* `parseopt <parseopt.html>`_

+  The ``parseopt`` module implements a command line option parser. This 

+  supports long and short command options with optional values and command line

+  arguments.

+

+* `parsecfg <parsecfg.html>`_

+  The ``parsecfg`` module implements a high performance configuration file 

+  parser. The configuration file's syntax is similar to the Windows ``.ini`` 

+  format, but much more powerful, as it is not a line based parser. String 

+  literals, raw string literals and triple quote string literals are supported 

+  as in the Nimrod programming language.

+

+* `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

+  style-insensitive mode. An efficient string substitution operator  ``%``

+  for the string table is also provided.

+

+* `hashes <hashes.html>`_

+  This module implements efficient computations of hash values for diverse

+  Nimrod types.

+

+* `lexbase <lexbase.html>`_

+  This is a low leve module that implements an extremely efficent buffering

+  scheme for lexers and parsers. This is used by the ``parsecfg`` module.

+

 

 Advanced libaries

 =================

 

-* `Regexprs <regexprs.html>`_

+* `regexprs <regexprs.html>`_

   This module contains procedures and operators for handling regular

   expressions.

+

+* `dialogs <dialogs.html>`_

+  This module implements portable dialogs for Nimrod; the implementation 

+  builds on the GTK interface. On Windows, native dialogs are shown if

+  appropriate.

+  

+

+Wrappers

+========

+

+Note that the generated HTML for some of these wrappers is so huge, that it is

+not contained in the distribution. You can then find them on the website.

+

+* `posix <posix.html>`_

+  Contains a wrapper for the POSIX standard.

+* `windows <windows.html>`_

+  Contains a wrapper for the Win32 API.

+* `shellapi <shellapi.html>`_

+  Contains a wrapper for the ``shellapi.h`` header.

+* `shfolder <shfolder.html>`_

+  Contains a wrapper for the ``shfolder.h`` header.

+* `mmsystem <mmsystem.html>`_

+  Contains a wrapper for the ``mmsystem.h`` header.

+* `ole2 <ole2.html>`_

+  Contains GUIDs for OLE2 automation support.

+* `nb30 <nb30.html>`_

+  This module contains the definitions for portable NetBIOS 3.0 support. 

+* `cairo <cairo.html>`_

+  Wrapper for the cairo library.

+* `cairoft <cairoft.html>`_

+  Wrapper for the cairoft library.

+* `cairowin32 <cairowin32.html>`_

+  Wrapper for the cairowin32 library.

+* `cairoxlib <cairoxlib.html>`_

+  Wrapper for the cairoxlib library.

+* `atk <atk.html>`_

+  Wrapper for the atk library.

+* `gdk2 <gdk2.html>`_

+  Wrapper for the gdk2 library.

+* `gdk2pixbuf <gdk2pixbuf.html>`_

+  Wrapper for the gdk2pixbuf library.

+* `gdkglext <gdkglext.html>`_

+  Wrapper for the gdkglext library.

+* `glib2 <glib2.html>`_

+  Wrapper for the glib2 library.

+* `gtk2 <gtk2.html>`_

+  Wrapper for the gtk2 library.

+* `gtkglext <gtkglext.html>`_

+  Wrapper for the gtkglext library.

+* `gtkhtml <gtkhtml.html>`_

+  Wrapper for the gtkhtml library.

+* `libglade2 <libglade2.html>`_

+  Wrapper for the libglade2 library.

+* `pango <pango.html>`_

+  Wrapper for the pango library.

+* `pangoutils <pangoutils.html>`_

+  Wrapper for the pangoutils library.

diff --git a/doc/manual.txt b/doc/manual.txt
index 8debb92a5..babd96813 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -1,1742 +1,1749 @@
-=============

-Nimrod Manual

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

-

-:Author: Andreas Rumpf

-:Version: |nimrodversion|

-

-.. contents::

-

-

-About this document

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

-

-This document describes the lexis, the syntax, and the semantics of Nimrod.

-

-The language constructs are explained using an extended BNF, in

-which ``(a)*`` means 0 or more ``a``'s, ``a+`` means 1 or more ``a``'s, and

-``(a)?`` means an optional *a*; an alternative spelling for optional parts is

-``[a]``. The ``|`` symbol is used to mark alternatives

-and has the lowest precedence. Parentheses may be used to group elements.

-Non-terminals are in lowercase, terminal symbols (including keywords) are in

-UPPERCASE. An example::

-

-  if_stmt ::= IF expr COLON stmts (ELIF expr COLON stmts)* [ELSE stmts]

-

-Other parts of Nimrod - like scoping rules or runtime semantics are only

-described in an informal manner. The reason is that formal semantics are

-difficult to write and understand. However, there is only one Nimrod

-implementation, so one may consider it as the formal specification;

-especially since the compiler's code is pretty clean (well, some parts of it).

-

-

-Definitions

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

-

-A Nimrod program specifies a computation that acts on a memory consisting of

-components called `locations`:idx:. A variable is basically a name for a 

-location. Each variable and location is of a certain `type`:idx:. The 

-variable's type is called `static type`:idx:, the location's type is called 

-`dynamic type`:idx:. If the static type is not the same as the dynamic type, 

-it is a supertype of the dynamic type.

-

-An `identifier`:idx: is a symbol declared as a name for a variable, type,

-procedure, etc. The region of the program over which a declaration applies is

-called the `scope`:idx: of the declaration. Scopes can be nested. The meaning 

-of an identifier is determined by the smallest enclosing scope in which the

-identifier is declared.

-

-An expression specifies a computation that produces a value or location.

-Expressions that produce locations are called `l-values`:idx:. An l-value

-can denote either a location or the value the location contains, depending on

-the context. Expressions whose values can be determined statically are called

-`constant expressions`:idx:; they are never l-values.

-

-A `static error`:idx: is an error that the implementation detects before

-program execution. Unless explicitly classified, an error is a static error.

-

-A `checked runtime error`:idx: is an error that the implementation detects

-and reports at runtime. The method for reporting such errors is via *raising

-exceptions*. However, the implementation provides a means to disable these

-runtime checks. See the section pragmas_ for details.

-

-An `unchecked runtime error`:idx: is an error that is not guaranteed to be

-detected, and can cause the subsequent behavior of the computation to

-be arbitrary. Unchecked runtime errors cannot occur if only `safe`:idx:

-language features are used.

-

-

-Lexical Analysis

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

-

-Encoding

---------

-

-All Nimrod source files are in the UTF-8 encoding (or its ASCII subset). Other

-encodings are not supported. Any of the standard platform line termination

-sequences can be used - the Unix form using ASCII LF (linefeed), the Windows

-form using the ASCII sequence CR LF (return followed by linefeed), or the old

-Macintosh form using the ASCII CR (return) character. All of these forms can be

-used equally, regardless of platform.

-

-

-Indentation

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

-

-Nimrod's standard grammar describes an `indentation sensitive`:idx: language.

-This means that all the control structures are recognized by indentation.

-Indentation consists only of spaces; tabulators are not allowed.

-

-The terminals ``IND`` (indentation), ``DED`` (dedentation) and ``SAD``

-(same indentation) are generated by the scanner, denoting an indentation.

-

-These terminals are only generated for lines that are not empty or contain

-only whitespace and comments.

-

-The parser and the scanner communicate over a stack which indentation terminal

-should be generated: The stack consists of integers counting the spaces. The

-stack is initialized with a zero on its top. The scanner reads from the stack:

-If the current indentation token consists of more spaces than the entry at the

-top of the stack, a ``IND`` token is generated, else if it consists of the same

-number of spaces, a ``SAD`` token is generated. If it consists of fewer spaces,

-a ``DED`` token is generated for any item on the stack that is greater than the

-current. These items are then popped from the stack by the scanner. At the end

-of the file, a ``DED`` token is generated for each number remaining on the

-stack that is larger than zero.

-

-Because the grammar contains some optional ``IND`` tokens, the scanner cannot

-push new indentation levels. This has to be done by the parser. The symbol

-``indPush`` indicates that an ``IND`` token is expected; the current number of

-leading spaces is pushed onto the stack by the parser.

-

-Comments

---------

-

-`Comments`:idx: start anywhere outside a string or character literal with the 

-hash character ``#``.

-Comments consist of a concatenation of `comment pieces`:idx:. A comment piece 

-starts with ``#`` and runs until the end of the line. The end of line characters

-belong to the piece. If the next line only consists of a comment piece which is

-aligned to the preceding one, it does not start a new comment:

-

-.. code-block:: nimrod

-

-  i = 0     # This is a single comment over multiple lines belonging to the 

-            # assignment statement. The scanner merges these two pieces.

-  # This is a new comment belonging to the current block, but to no particular

-  # statement.

-  i = i + 1 # This a new comment that is NOT

-  echo(i)   # continued here, because this comment refers to the echo statement

-

-Comments are tokens; they are only allowed at certain places in the input file

-as they belong to the syntax tree! This feature enables perfect source-to-source

-transformations (such as pretty-printing) and superior documentation generators.

-A side-effect is that the human reader of the code always knows exactly which

-code snippet the comment refers to.

-

-

-Identifiers & Keywords

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

-

-`Identifiers`:idx: in Nimrod can be any string of letters, digits

-and underscores, beginning with a letter. Two immediate following

-underscores ``__`` are not allowed::

-

-  letter ::= 'A'..'Z' | 'a'..'z' | '\x80'..'\xff'

-  digit ::= '0'..'9'

-  IDENTIFIER ::= letter ( ['_'] letter | digit )*

-

-The following `keywords`:idx: are reserved and cannot be used as identifiers:

-

-.. code-block:: nimrod

-   :file: ../data/keywords.txt

-

-Some keywords are unused; they are reserved for future developments of the

-language.

-

-Nimrod is a `style-insensitive`:idx: language. This means that it is not

-case-sensitive and even underscores are ignored:

-**type** is a reserved word, and so is **TYPE** or **T_Y_P_E**. The idea behind

-this is that this allows programmers to use their own prefered spelling style

-and libraries written by different programmers cannot use incompatible

-conventions. The editors or IDE can show the identifiers as preferred. Another

-advantage is that it frees the programmer from remembering the spelling of an

-identifier.

-

-

-Literal strings

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

-

-`Literal strings`:idx: can be delimited by matching double quotes, and can 

-contain the following `escape sequences`:idx:\ :

-

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

-  Escape sequence          Meaning

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

-  ``\n``                   `newline`:idx:

-  ``\r``                   `carriage return`:idx:

-  ``\l``                   `line feed`:idx:

-  ``\f``                   `form feed`:idx:

-  ``\t``                   `tabulator`:idx:

-  ``\v``                   `vertical tabulator`:idx:

-  ``\\``                   `backslash`:idx:

-  ``\"``                   `quotation mark`:idx:

-  ``\'``                   `apostrophe`:idx:

-  ``\d+``                  `character with decimal value d`:idx:;

-                           all decimal digits directly

-                           following are used for the

-                           character

-  ``\a``                   `alert`:idx:

-  ``\b``                   `backspace`:idx:

-  ``\e``                   `escape`:idx: `[ESC]`:idx:

-  ``\xHH``                 `character with hex value HH`:idx:;

-                           exactly two hex digits are allowed

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

-

-

-Strings in Nimrod may contain any 8-bit value, except embedded zeros

-which are not allowed for compability with `C`:idx:.

-

-Literal strings can also be delimited by three double squotes

-``"""`` ... ``"""``.

-Literals in this form may run for several lines, may contain ``"`` and do not

-interpret any escape sequences.

-For convenience, when the opening ``"""`` is immediately

-followed by a newline, the newline is not included in the string.

-There are also `raw string literals` that are preceded with the letter ``r``

-(or ``R``) and are delimited by matching double quotes (just like ordinary

-string literals) and do not interpret the escape sequences. This is especially

-convenient for regular expressions or Windows paths:

-

-.. code-block:: nimrod

-

-  var f = openFile(r"C:\texts\text.txt") # a raw string, so ``\t`` is no tab 

-

-

-Literal characters

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

-

-Character literals are enclosed in single quotes ``''`` and can contain the

-same escape sequences as strings - with one exception: ``\n`` is not allowed

-as it may be wider than one character (often it is the pair CR/LF for example).

-A character is not an Unicode character but a single byte. The reason for this

-is efficiency: For the overwhelming majority of use-cases, the resulting

-programs will still handle UTF-8 properly as UTF-8 was specially designed for

-this.

-Another reason is that Nimrod should support ``array[char, int]`` or

-``set[char]`` efficiently as many algorithms rely on this feature.

-

-

-Numerical constants

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

-

-`Numerical constants`:idx: are of a single type and have the form::

-

-  hexdigit ::= digit | 'A'..'F' | 'a'..'f'

-  octdigit ::= '0'..'7'

-  bindigit ::= '0'..'1'

-  INT_LIT ::= digit ( ['_'] digit )*

-            | '0' ('x' | 'X' ) hexdigit ( ['_'] hexdigit )*

-            | '0o' octdigit ( ['_'] octdigit )*

-            | '0' ('b' | 'B' ) bindigit ( ['_'] bindigit )*

-

-  INT8_LIT ::= INT_LIT '\'' ('i' | 'I' ) '8'

-  INT16_LIT ::= INT_LIT '\'' ('i' | 'I' ) '16'

-  INT32_LIT ::= INT_LIT '\'' ('i' | 'I' ) '32'

-  INT64_LIT ::= INT_LIT '\'' ('i' | 'I' ) '64'

-

-  exponent ::= ('e' | 'E' ) ['+' | '-'] digit ( ['_'] digit )*

-  FLOAT_LIT ::= digit (['_'] digit)*  ('.' (['_'] digit)* [exponent] |exponent)

-  FLOAT32_LIT ::= ( FLOAT_LIT | INT_LIT ) '\'' ('f' | 'F') '32'

-  FLOAT64_LIT ::= ( FLOAT_LIT | INT_LIT ) '\'' ('f' | 'F') '64'

-

-

-As can be seen in the productions, numerical constants can contain unterscores

-for readability. Integer and floating point literals may be given in decimal (no

-prefix), binary (prefix ``0b``), octal (prefix ``0o``) and

-hexadecimal (prefix ``0x``) notation.

-

-There exists a literal for each numerical type that is

-defined. The suffix starting with an apostophe ('\'') is called a

-`type suffix`:idx:. Literals without a type prefix are of the type ``int``, 

-unless the literal contains a dot or an ``E`` in which case it is of 

-type ``float``.

-

-The following table specifies type suffixes:

-

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

-  Type Suffix        Resulting type of literal

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

-  ``'i8``            int8

-  ``'i16``           int16

-  ``'i32``           int32

-  ``'i64``           int64

-  ``'f32``           float32

-  ``'f64``           float64

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

-

-Floating point literals may also be in binary, octal or hexadecimal

-notation:

-``0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64``

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

-

-

-

-Other tokens

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

-

-The following strings denote other tokens::

-

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

-       :     =     ^     ..    `

-

-`..`:tok: takes precedence over other tokens that contain a dot: `{..}`:tok: are 

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

-`{.`:tok:, `.}`:tok:.

-

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

-combination of the following characters that are not listed above::

-

-       +     -     *     /     <     >

-       =     @     $     ~     &     %

-       !     ?     ^     .     |

-

-These keywords are also operators:

-``and or not xor shl shr div mod in notin is isnot``.

-

-

-Syntax

-======

-

-This section lists Nimrod's standard syntax in ENBF. How the parser receives

-indentation tokens is already described in the Lexical Analysis section.

-

-Nimrod allows user-definable operators.

-Binary operators have 8 different levels of precedence. For user-defined

-operators, the precedence depends on the first character the operator consists

-of. All binary operators are left-associative.

-

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

-Precedence level    Operators                                     First characters    Terminal symbol

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

-  7 (highest)                                                     ``$``               OP7

-  6               ``*    /    div   mod   shl  shr  %``           ``* % \  /``        OP6

-  5               ``+    -``                                      ``+  ~  |``         OP5

-  4               ``&``                                           ``&``               OP4

-  3               ``==  <= < >= > !=  in  not_in  is  isnot``     ``= <  > !``        OP3

-  2               ``and``                                                             OP2

-  1               ``or xor``                                                          OP1

-  0 (lowest)                                                      ``? @ ^ ` : .``     OP0

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

-

-

-The grammar's start symbol is ``module``. The grammar is LL(1) and therefore

-not ambigious.

-

-.. include:: grammar.txt

-   :literal:

-

-

-

-Semantics

-=========

-

-Constants

----------

-

-`Constants`:idx: are symbols which are bound to a value. The constant's value

-cannot change. The compiler must be able to evaluate the expression in a

-constant declaration at compile time. 
+=============
+Nimrod Manual
+=============
+
+:Author: Andreas Rumpf
+:Version: |nimrodversion|
+
+.. contents::
+
+
+About this document
+===================
+
+This document describes the lexis, the syntax, and the semantics of Nimrod.
+
+The language constructs are explained using an extended BNF, in
+which ``(a)*`` means 0 or more ``a``'s, ``a+`` means 1 or more ``a``'s, and
+``(a)?`` means an optional *a*; an alternative spelling for optional parts is
+``[a]``. The ``|`` symbol is used to mark alternatives
+and has the lowest precedence. Parentheses may be used to group elements.
+Non-terminals are in lowercase, terminal symbols (including keywords) are in
+UPPERCASE. An example::
+
+  if_stmt ::= IF expr COLON stmts (ELIF expr COLON stmts)* [ELSE stmts]
+
+Other parts of Nimrod - like scoping rules or runtime semantics are only
+described in an informal manner. The reason is that formal semantics are
+difficult to write and understand. However, there is only one Nimrod
+implementation, so one may consider it as the formal specification;
+especially since the compiler's code is pretty clean (well, some parts of it).
+
+
+Definitions
+===========
+
+A Nimrod program specifies a computation that acts on a memory consisting of
+components called `locations`:idx:. A variable is basically a name for a
+location. Each variable and location is of a certain `type`:idx:. The
+variable's type is called `static type`:idx:, the location's type is called
+`dynamic type`:idx:. If the static type is not the same as the dynamic type,
+it is a supertype of the dynamic type.
+
+An `identifier`:idx: is a symbol declared as a name for a variable, type,
+procedure, etc. The region of the program over which a declaration applies is
+called the `scope`:idx: of the declaration. Scopes can be nested. The meaning
+of an identifier is determined by the smallest enclosing scope in which the
+identifier is declared.
+
+An expression specifies a computation that produces a value or location.
+Expressions that produce locations are called `l-values`:idx:. An l-value
+can denote either a location or the value the location contains, depending on
+the context. Expressions whose values can be determined statically are called
+`constant expressions`:idx:; they are never l-values.
+
+A `static error`:idx: is an error that the implementation detects before
+program execution. Unless explicitly classified, an error is a static error.
+
+A `checked runtime error`:idx: is an error that the implementation detects
+and reports at runtime. The method for reporting such errors is via *raising
+exceptions*. However, the implementation provides a means to disable these
+runtime checks. See the section pragmas_ for details.
+
+An `unchecked runtime error`:idx: is an error that is not guaranteed to be
+detected, and can cause the subsequent behavior of the computation to
+be arbitrary. Unchecked runtime errors cannot occur if only `safe`:idx:
+language features are used.
+
+
+Lexical Analysis
+================
+
+Encoding
+--------
+
+All Nimrod source files are in the UTF-8 encoding (or its ASCII subset). Other
+encodings are not supported. Any of the standard platform line termination
+sequences can be used - the Unix form using ASCII LF (linefeed), the Windows
+form using the ASCII sequence CR LF (return followed by linefeed), or the old
+Macintosh form using the ASCII CR (return) character. All of these forms can be
+used equally, regardless of platform.
+
+
+Indentation
+-----------
+
+Nimrod's standard grammar describes an `indentation sensitive`:idx: language.
+This means that all the control structures are recognized by indentation.
+Indentation consists only of spaces; tabulators are not allowed.
+
+The terminals ``IND`` (indentation), ``DED`` (dedentation) and ``SAD``
+(same indentation) are generated by the scanner, denoting an indentation.
+
+These terminals are only generated for lines that are not empty or contain
+only whitespace and comments.
+
+The parser and the scanner communicate over a stack which indentation terminal
+should be generated: The stack consists of integers counting the spaces. The
+stack is initialized with a zero on its top. The scanner reads from the stack:
+If the current indentation token consists of more spaces than the entry at the
+top of the stack, a ``IND`` token is generated, else if it consists of the same
+number of spaces, a ``SAD`` token is generated. If it consists of fewer spaces,
+a ``DED`` token is generated for any item on the stack that is greater than the
+current. These items are then popped from the stack by the scanner. At the end
+of the file, a ``DED`` token is generated for each number remaining on the
+stack that is larger than zero.
+
+Because the grammar contains some optional ``IND`` tokens, the scanner cannot
+push new indentation levels. This has to be done by the parser. The symbol
+``indPush`` indicates that an ``IND`` token is expected; the current number of
+leading spaces is pushed onto the stack by the parser.
+
+Comments
+--------
+
+`Comments`:idx: start anywhere outside a string or character literal with the
+hash character ``#``.
+Comments consist of a concatenation of `comment pieces`:idx:. A comment piece
+starts with ``#`` and runs until the end of the line. The end of line characters
+belong to the piece. If the next line only consists of a comment piece which is
+aligned to the preceding one, it does not start a new comment:
+
+.. code-block:: nimrod
+
+  i = 0     # This is a single comment over multiple lines belonging to the
+            # assignment statement. The scanner merges these two pieces.
+  # This is a new comment belonging to the current block, but to no particular
+  # statement.
+  i = i + 1 # This a new comment that is NOT
+  echo(i)   # continued here, because this comment refers to the echo statement
+
+Comments are tokens; they are only allowed at certain places in the input file
+as they belong to the syntax tree! This feature enables perfect source-to-source
+transformations (such as pretty-printing) and superior documentation generators.
+A side-effect is that the human reader of the code always knows exactly which
+code snippet the comment refers to.
+
+
+Identifiers & Keywords
+----------------------
+
+`Identifiers`:idx: in Nimrod can be any string of letters, digits
+and underscores, beginning with a letter. Two immediate following
+underscores ``__`` are not allowed::
+
+  letter ::= 'A'..'Z' | 'a'..'z' | '\x80'..'\xff'
+  digit ::= '0'..'9'
+  IDENTIFIER ::= letter ( ['_'] letter | digit )*
+
+The following `keywords`:idx: are reserved and cannot be used as identifiers:
+
+.. code-block:: nimrod
+   :file: ../data/keywords.txt
+
+Some keywords are unused; they are reserved for future developments of the
+language.
+
+Nimrod is a `style-insensitive`:idx: language. This means that it is not
+case-sensitive and even underscores are ignored:
+**type** is a reserved word, and so is **TYPE** or **T_Y_P_E**. The idea behind
+this is that this allows programmers to use their own prefered spelling style
+and libraries written by different programmers cannot use incompatible
+conventions. The editors or IDE can show the identifiers as preferred. Another
+advantage is that it frees the programmer from remembering the spelling of an
+identifier.
+
+
+Literal strings
+---------------
+
+`Literal strings`:idx: can be delimited by matching double quotes, and can
+contain the following `escape sequences`:idx:\ :
+
+==================         ===================================================
+  Escape sequence          Meaning
+==================         ===================================================
+  ``\n``                   `newline`:idx:
+  ``\r``                   `carriage return`:idx:
+  ``\l``                   `line feed`:idx:
+  ``\f``                   `form feed`:idx:
+  ``\t``                   `tabulator`:idx:
+  ``\v``                   `vertical tabulator`:idx:
+  ``\\``                   `backslash`:idx:
+  ``\"``                   `quotation mark`:idx:
+  ``\'``                   `apostrophe`:idx:
+  ``\d+``                  `character with decimal value d`:idx:;
+                           all decimal digits directly
+                           following are used for the
+                           character
+  ``\a``                   `alert`:idx:
+  ``\b``                   `backspace`:idx:
+  ``\e``                   `escape`:idx: `[ESC]`:idx:
+  ``\xHH``                 `character with hex value HH`:idx:;
+                           exactly two hex digits are allowed
+==================         ===================================================
+
+
+Strings in Nimrod may contain any 8-bit value, except embedded zeros
+which are not allowed for compability with `C`:idx:.
+
+Literal strings can also be delimited by three double squotes
+``"""`` ... ``"""``.
+Literals in this form may run for several lines, may contain ``"`` and do not
+interpret any escape sequences.
+For convenience, when the opening ``"""`` is immediately
+followed by a newline, the newline is not included in the string.
+There are also `raw string literals` that are preceded with the letter ``r``
+(or ``R``) and are delimited by matching double quotes (just like ordinary
+string literals) and do not interpret the escape sequences. This is especially
+convenient for regular expressions or Windows paths:
+
+.. code-block:: nimrod
+
+  var f = openFile(r"C:\texts\text.txt") # a raw string, so ``\t`` is no tab
+
+
+Literal characters
+------------------
+
+Character literals are enclosed in single quotes ``''`` and can contain the
+same escape sequences as strings - with one exception: ``\n`` is not allowed
+as it may be wider than one character (often it is the pair CR/LF for example).
+A character is not an Unicode character but a single byte. The reason for this
+is efficiency: For the overwhelming majority of use-cases, the resulting
+programs will still handle UTF-8 properly as UTF-8 was specially designed for
+this.
+Another reason is that Nimrod should support ``array[char, int]`` or
+``set[char]`` efficiently as many algorithms rely on this feature.
+
+
+Numerical constants
+-------------------
+
+`Numerical constants`:idx: are of a single type and have the form::
+
+  hexdigit ::= digit | 'A'..'F' | 'a'..'f'
+  octdigit ::= '0'..'7'
+  bindigit ::= '0'..'1'
+  INT_LIT ::= digit ( ['_'] digit )*
+            | '0' ('x' | 'X' ) hexdigit ( ['_'] hexdigit )*
+            | '0o' octdigit ( ['_'] octdigit )*
+            | '0' ('b' | 'B' ) bindigit ( ['_'] bindigit )*
+
+  INT8_LIT ::= INT_LIT '\'' ('i' | 'I' ) '8'
+  INT16_LIT ::= INT_LIT '\'' ('i' | 'I' ) '16'
+  INT32_LIT ::= INT_LIT '\'' ('i' | 'I' ) '32'
+  INT64_LIT ::= INT_LIT '\'' ('i' | 'I' ) '64'
+
+  exponent ::= ('e' | 'E' ) ['+' | '-'] digit ( ['_'] digit )*
+  FLOAT_LIT ::= digit (['_'] digit)*  ('.' (['_'] digit)* [exponent] |exponent)
+  FLOAT32_LIT ::= ( FLOAT_LIT | INT_LIT ) '\'' ('f' | 'F') '32'
+  FLOAT64_LIT ::= ( FLOAT_LIT | INT_LIT ) '\'' ('f' | 'F') '64'
+
+
+As can be seen in the productions, numerical constants can contain unterscores
+for readability. Integer and floating point literals may be given in decimal (no
+prefix), binary (prefix ``0b``), octal (prefix ``0o``) and
+hexadecimal (prefix ``0x``) notation.
+
+There exists a literal for each numerical type that is
+defined. The suffix starting with an apostophe ('\'') is called a
+`type suffix`:idx:. Literals without a type prefix are of the type ``int``,
+unless the literal contains a dot or an ``E`` in which case it is of
+type ``float``.
+
+The following table specifies type suffixes:
+
+=================    =========================
+  Type Suffix        Resulting type of literal
+=================    =========================
+  ``'i8``            int8
+  ``'i16``           int16
+  ``'i32``           int32
+  ``'i64``           int64
+  ``'f32``           float32
+  ``'f64``           float64
+=================    =========================
+
+Floating point literals may also be in binary, octal or hexadecimal
+notation:
+``0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64``
+is approximately 1.72826e35 according to the IEEE floating point standard.
+
+
+
+Other tokens
+------------
+
+The following strings denote other tokens::
+
+       (     )     {     }     [     ]     ,  ;   [.    .]  {.   .}  (.  .)
+       :     =     ^     ..    `
+
+`..`:tok: takes precedence over other tokens that contain a dot: `{..}`:tok: are
+the three tokens `{`:tok:, `..`:tok:, `}`:tok: and not the two tokens
+`{.`:tok:, `.}`:tok:.
+
+In Nimrod one can define his own operators. An `operator`:idx: is any
+combination of the following characters that are not listed above::
+
+       +     -     *     /     <     >
+       =     @     $     ~     &     %
+       !     ?     ^     .     |
+
+These keywords are also operators:
+``and or not xor shl shr div mod in notin is isnot``.
+
+
+Syntax
+======
+
+This section lists Nimrod's standard syntax in ENBF. How the parser receives
+indentation tokens is already described in the Lexical Analysis section.
+
+Nimrod allows user-definable operators.
+Binary operators have 8 different levels of precedence. For user-defined
+operators, the precedence depends on the first character the operator consists
+of. All binary operators are left-associative.
+
+================  ==============================================  ==================  ===============
+Precedence level    Operators                                     First characters    Terminal symbol
+================  ==============================================  ==================  ===============
+  7 (highest)                                                     ``$``               OP7
+  6               ``*    /    div   mod   shl  shr  %``           ``* % \  /``        OP6
+  5               ``+    -``                                      ``+  ~  |``         OP5
+  4               ``&``                                           ``&``               OP4
+  3               ``==  <= < >= > !=  in  not_in  is  isnot``     ``= <  > !``        OP3
+  2               ``and``                                                             OP2
+  1               ``or xor``                                                          OP1
+  0 (lowest)                                                      ``? @ ^ ` : .``     OP0
+================  ==============================================  ==================  ===============
+
+
+The grammar's start symbol is ``module``. The grammar is LL(1) and therefore
+not ambigious.
+
+.. include:: grammar.txt
+   :literal:
+
+
+
+Semantics
+=========
+
+Constants
+---------
+
+`Constants`:idx: are symbols which are bound to a value. The constant's value
+cannot change. The compiler must be able to evaluate the expression in a
+constant declaration at compile time.
 
 ..
-  Nimrod contains a sophisticated

-  compile-time evaluator, so procedures declared with the ``{.noSideEffect.}``

-  pragma can be used in constant expressions:

-

-  .. code-block:: nimrod

-    

-    from strutils import findSubStr

-    const

-      x = findSubStr('a', "hallo") # x is 1; this is computed at compile time!

-

-

-Types

------

-

-All expressions have a `type`:idx: which is known at compile time. Thus Nimrod 

-is statically typed. One can declare new types, which is in

-essence defining an identifier that can be used to denote this custom type.

-

-These are the major type classes:

-

-* ordinal types (consist of integer, bool, character, enumeration

-  (and subranges thereof) types)

-* floating point types

-* string type

-* structured types

-* reference (pointer) type

-* procedural type

-* generic type

-

-

-Ordinal types

-~~~~~~~~~~~~~

-`Ordinal types`:idx: have the following characteristics:

-

-- Ordinal types are countable and ordered. This property allows

-  the operation of functions as ``Inc``, ``Ord``, ``Dec`` on ordinal types to

-  be defined.

-- Ordinal values have a smallest possible value. Trying to count farther

-  down than the smallest value gives a checked runtime or static error.

-- Ordinal values have a largest possible value. Trying to count farther

-  than the largest value gives a checked runtime or static error.

-

-Integers, bool, characters and enumeration types (and subrange of these

-types) belong to ordinal types.

-

-

-Pre-defined numerical types

-~~~~~~~~~~~~~~~~~~~~~~~~~~~

-These integer types are pre-defined:

-

-``int``

-  the generic signed integer type; its size is platform dependant

-  (the compiler chooses the processor's fastest integer type)

-  this type should be used in general. An integer literal that has no type

-  suffix is of this type.

-

-intXX

-  additional signed integer types of XX bits use this naming scheme

-  (example: int16 is a 16 bit wide integer).

-  The current implementation supports ``int8``, ``int16``, ``int32``, ``int64``.

-  Literals of these types have the suffix 'iXX.

-

-

-There are no `unsigned integer`:idx: types, only `unsigned operations`:idx: 

-that treat their arguments as unsigned. Unsigned operations all wrap around; 

-they may not lead to over- or underflow errors. Unsigned operations use the 

-``%`` postfix as convention:

-

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

-operation                meaning

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

-``a +% b``               unsigned integer addition

-``a -% b``               unsigned integer substraction

-``a *% b``               unsigned integer multiplication

-``a /% b``               unsigned integer division

-``a %% b``               unsigned integer modulo operation

-``a <% b``               treat ``a`` and ``b`` as unsigned and compare

-``a <=% b``              treat ``a`` and ``b`` as unsigned and compare

-``ze(a)``                extends the bits of ``a`` with zeros until it has the

-                         width of the ``int`` type

-``toU8(a)``              treats ``a`` as unsigned and converts it to an

-                         unsigned integer of 8 bits (but still the

-                         ``int8`` type)                         

-``toU16(a)``             treats ``a`` as unsigned and converts it to an

-                         unsigned integer of 16 bits (but still the

-                         ``int16`` type)

-``toU32(a)``             treats ``a`` as unsigned and converts it to an

-                         unsigned integer of 32 bits (but still the

-                         ``int32`` type)

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

-

-The following floating point types are pre-defined:

-

-``float``

-  the generic floating point type; its size is platform dependant

-  (the compiler chooses the processor's fastest floating point type)

-  this type should be used in general

-

-floatXX

-  an implementation may define additional floating point types of XX bits using

-  this naming scheme (example: float64 is a 64 bit wide float). The current

-  implementation supports ``float32`` and ``float64``. Literals of these types

-  have the suffix 'fXX.

-

-`Automatic type conversion`:idx: in expressions where different kinds

-of integer types are used is performed. However, if the type conversion

-loses information, the `EInvalidValue`:idx: exception is raised. Certain cases 

-of the convert error are detected at compile time.

-

-Automatic type conversion in expressions with different kinds

-of floating point types is performed: The smaller type is

-converted to the larger. Arithmetic performed on floating point types

-follows the IEEE standard. Only the ``int`` type is converted to a floating

-point type automatically, other integer types are not. 

-

-

-Boolean type

-~~~~~~~~~~~~

-The `boolean`:idx: type is named ``bool`` in Nimrod and can be one of the two

-pre-defined values ``true`` and ``false``. Conditions in while,

-if, elif, when statements need to be of type bool.

-

-This condition holds::

-

-  ord(false) == 0 and ord(true) == 1

-

-The operators ``not, and, or, xor, implies, <, <=, >, >=, !=, ==`` are defined

-for the bool type. The ``and`` and ``or`` operators perform short-cut

-evaluation. Example:

-

-.. code-block:: nimrod

-

-  while p != nil and p.name != "xyz":

-    # p.name is not evaluated if p == nil

-    p = p.next

-

-

-The size of the bool type is one byte.

-

-

-Character type

-~~~~~~~~~~~~~~

-The `character type`:idx: is named ``char`` in Nimrod. Its size is one byte. 

-Thus it cannot represent an UTF-8 character, but a part of it. 

-The reason for this is efficiency: For the overwhelming majority of use-cases,

-the resulting programs will still handle UTF-8 properly as UTF-8 was specially

-designed for this.

-Another reason is that Nimrod can support ``array[char, int]`` or

-``set[char]`` efficiently as many algorithms rely on this feature. The

-`TUniChar` type is used for Unicode characters, it can represent any Unicode

-character. ``TUniChar`` is declared the ``unicode`` standard module. 

-

-

-

-Enumeration types

-~~~~~~~~~~~~~~~~~

-`Enumeration`:idx: types define a new type whose values consist only of the ones

-specified.

-The values are ordered by the order in enum's declaration. Example:

-

-.. code-block:: nimrod

-

-  type

-    TDirection = enum

-      north, east, south, west

-

-

-Now the following holds::

-

-  ord(north) == 0

-  ord(east) == 1

-  ord(south) == 2

-  ord(west) == 3

-

-Thus, north < east < south < west. The comparison operators can be used

-with enumeration types.

-

-For better interfacing to other programming languages, the fields of enum

-types can be assigned an explicit ordinal value. However, the ordinal values

-have to be in ascending order. A field whose ordinal value that is not

-explicitly given, is assigned the value of the previous field + 1.

-

-An explicit ordered enum can have *wholes*:

-

-.. code-block:: nimrod

-  type

-    TTokenType = enum

-      a = 2, b = 4, c = 89 # wholes are valid

-

-However, it is then not an ordinal anymore, so it is not possible to use these

-enums as an index type for arrays. The procedures ``inc``, ``dec``, ``succ``

-and ``pred`` are not available for them either.

-

-

-Subrange types

-~~~~~~~~~~~~~~

-A `subrange`:idx: type is a range of values from an ordinal type (the host 

-type). To define a subrange type, one must specify it's limiting values: the 

-highest and lowest value of the type:

-

-.. code-block:: nimrod

-  type

-    TSubrange = range[0..5]

-

-

-``TSubrange`` is a subrange of an integer which can only hold the values 0

-to 5. Assigning any other value to a variable of type ``TSubrange`` is a

-checked runtime error (or static error if it can be statically

-determined). Assignments from the base type to one of its subrange types

-(and vice versa) are allowed.

-

-A subrange type has the same size as its base type (``int`` in the example).

-

-

-String type

-~~~~~~~~~~~

-All string literals are of the type `string`:idx:. A string in Nimrod is very

-similar to a sequence of characters. However, strings in Nimrod both are

-zero-terminated and have a length field. One can retrieve the length with the

-builtin ``len`` procedure; the length never counts the terminating zero.

-The assignment operator for strings always copies the string.

-

-Strings are compared by their lexicographical order. All comparison operators

-are available. Strings can be indexed like arrays (lower bound is 0). Unlike

-arrays, they can be used in case statements:

-

-.. code-block:: nimrod

-

-  case paramStr(i)

-  of "-v": incl(options, optVerbose)

-  of "-h", "-?": incl(options, optHelp)

-  else: write(stdout, "invalid command line option!\n")

-

-Per convention, all strings are UTF-8 strings, but this is not enforced. For

-example, when reading strings from binary files, they are merely a sequence of

-bytes. The index operation ``s[i]`` means the i-th *char* of ``s``, not the

-i-th *unichar*. The iterator ``unichars`` from the ``unicode`` standard

-module can be used for iteration over all unicode characters.

-

-

-Structured types

-~~~~~~~~~~~~~~~~

-A variable of a `structured type`:idx: can hold multiple values at the same 

-time. Stuctured types can be nested to unlimited levels. Arrays, sequences, 

-records, objects and sets belong to the structured types.

-

-Array and sequence types

-~~~~~~~~~~~~~~~~~~~~~~~~

-`Arrays`:idx: are a homogenous type, meaning that each element in the array 

-has the same type. Arrays always have a fixed length which is specified at 

-compile time (except for open arrays). They can be indexed by any ordinal type.

-A parameter ``A`` may be an *open array*, in which case it is indexed by 

-integers from 0 to ``len(A)-1``.

-

-`Sequences`:idx: are similar to arrays but of dynamic length which may change

-during runtime (like strings). A sequence ``S`` is always indexed by integers

-from 0 to ``len(S)-1`` and its bounds are checked. Sequences can also be

-constructed by the array constructor ``[]``.

-

-A sequence may be passed to a parameter that is of type *open array*, but

-not to a multi-dimensional open array, because it is impossible to do so in an

-efficient manner.

-

-An array expression may be constructed by the array constructor ``[]``.

-A constructed array is assignment compatible to a sequence.

-

-Example:

-

-.. code-block:: nimrod

-

-  type

-    TIntArray = array[0..5, int] # an array that is indexed with 0..5

-    TIntSeq = seq[int] # a sequence of integers

-  var

-    x: TIntArray

-    y: TIntSeq

-  x = [1, 2, 3, 4, 5, 6] # [] this is the array constructor that is compatible

-                         # with arrays, open arrays and

-  y = [1, 2, 3, 4, 5, 6] # sequences

-

-The lower bound of an array may be received by the built-in proc

-``low()``, the higher bound by ``high()``. The length may be

-received by ``len()``.

-

-Arrays are always bounds checked (at compile-time or at runtime). These

-checks can be disabled via pragmas or invoking the compiler with the

-``--bound_checks:off`` command line switch.

-

-

-Tuples, record and object types

-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-A variable of a `record`:idx: or `object`:idx: type is a heterogenous storage 

-container.

-A record or object defines various named *fields* of a type. The assignment

-operator for records and objects always copies the whole record/object. The

-constructor ``()`` can be used to initialize records/objects. A field may

-be given a default value. Fields with default values do not have to be listed

-in a record construction, all other fields have to be listed.

-

-.. code-block:: nimrod

-

-  type

-    TPerson = record   # type representing a person

-      name: string     # a person consists of a name

-      age: int = 30    # and an age which default value is 30

-

-  var

-    person: TPerson

-  person = (name: "Peter") # person.age is its default value (30)

-

-The implementation aligns the fields for best access performance. The alignment

-is done in a way that is compatible the way the C compiler does it.

-

-The difference between records and objects is that objects allow inheritance.

-Objects have access to their type at runtime, so that the ``is`` operator

-can be used to determine the object's type. Assignment from an object to its

-parents' object leads to a static or runtime error (the

-`EInvalidObjectAssignment`:idx: exception is raised).

-

-.. code-block:: nimrod

-

-  type

-    TPerson = object

-      name: string

-      age: int

-

-    TStudent = object of TPerson # a student is a person

-      id: int                    # with an id field

-

-  var

-    student: TStudent

-    person: TPerson

-  student = (name: "Peter", age: 89, id: 3)

-  person = (name: "Mary", age: 17)

-  assert(student is TStudent) # is true

-  person = student # this is an error; person has no storage for id.

-

-

-Set type

-~~~~~~~~

-The `set type`:idx: models the mathematical notion of a set. The set's

-basetype can only be an ordinal type. The reason is that sets are implemented

-as bit vectors. Sets are designed for high performance computing.

-

-Note: The sets module can be used for sets of other types.

-

-Sets can be constructed via the set constructor: ``{}`` is the empty set. The

-empty set is type combatible with any special set type. The constructor

-can also be used to include elements (and ranges of elements) in the set:

-

-.. code-block:: nimrod

-

-  {'a'..'z', '0'..'9'} # This constructs a set that conains the

-                       # letters from 'a' to 'z' and the digits

-                       # from '0' to '9'

-

-These operations are supported by sets:

-

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

-operation             meaning

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

-``A + B``             union of two sets

-``A * B``             intersection of two sets

-``A - B``             difference of two sets (A without B's elements)

-``A == B``            set equality

-``A <= B``            subset relation (A is subset of B or equal to B)

-``A < B``             strong subset relation (A is a real subset of B)

-``e in A``            set membership (A contains element e)

-``A -+- B``           symmetric set difference (= (A - B) + (B - A))

-``card(A)``           the cardinality of A (number of elements in A)

-``incl(A, elem)``     same as A = A + {elem}, but may be faster

-``excl(A, elem)``     same as A = A - {elem}, but may be faster

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

-

-Reference type

-~~~~~~~~~~~~~~

-References (similiar to `pointers`:idx: in other programming languages) are a 

-way to introduce many-to-one relationships. This means different references can

-point to and modify the same location in memory. References should be used 

-sparingly in a program. They are only needed for constructing graphs.

-

-Nimrod distinguishes between `traced`:idx: and `untraced`:idx: references. 

-Untraced references are also called *pointers*. The difference between them is 

-that traced references are garbage collected, untraced are not. Thus untraced

-references are *unsafe*. However for certain low-level operations (accessing

-the hardware) untraced references are unavoidable.

-

-Traced references are declared with the **ref** keyword, untraced references

-are declared with the **ptr** keyword.

-

-The ``^`` operator can be used to derefer a reference, the ``addr`` procedure

-returns the address of an item. An address is always an untraced reference.

-Thus the usage of ``addr`` is an *unsafe* feature.

-

-The ``.`` (access a record field operator) and ``[]`` (array/string/sequence

-index operator) operators perform implicit dereferencing operations for

-reference types:

-

-.. code-block:: nimrod

-

-  type

-    PNode = ref TNode

-    TNode = record

-      le, ri: PNode

-      data: int

-

-  var

-    n: PNode

-  new(n)

-  n.data = 9 # no need to write n^.data

-

-To allocate a new traced object, the built-in procedure ``new`` has to be used.

-To deal with untraced memory, the procedures ``alloc``, ``dealloc`` and

-``realloc`` can be used. The documentation of the system module contains

-further information.

-

-Special care has to be taken if an untraced object contains traced objects like

-traced references, strings or sequences: In order to free everything properly,

-the built-in procedure ``finalize`` has to be called before freeing the

-untraced memory manually!

-

-.. XXX finalizers for traced objects

-

-Procedural type

-~~~~~~~~~~~~~~~

-A `procedural type`:idx: is internally a pointer to procedure. ``nil`` is 

-an allowed value for variables of a procedural type. Nimrod uses procedural 

-types to achieve `functional`:idx: programming techniques. Dynamic dispatch 

-for OOP constructs can also be implemented with procedural types.

-

-Example:

-

-.. code-block:: nimrod

-

-  type

-    TCallback = proc (x: int) {.cdecl.}

-

-  proc printItem(x: Int) = ...

-

-  proc forEach(c: TCallback) =

-    ...

-

-  forEach(printItem)  # this will NOT work because calling conventions differ

-

-A subtle issue with procedural types is that the calling convention of the

-procedure influences the type compability: Procedural types are only compatible

-if they have the same calling convention.

-

-Nimrod supports these `calling conventions`:idx:, which are all incompatible to

-each other:

-

-`stdcall`:idx:

-    This the stdcall convention as specified by Microsoft. The generated C

-    procedure is declared with the ``__stdcall`` keyword.

-

-`cdecl`:idx:

-    The cdecl convention means that a procedure shall use the same convention

-    as the C compiler. Under windows the generated C procedure is declared with

-    the ``__cdecl`` keyword.

-

-`safecall`:idx:

-    This is the safecall convention as specified by Microsoft. The generated C

-    procedure is declared with the ``__safecall`` keyword. The word *safe*

-    refers to the fact that all hardware registers shall be pushed to the

-    hardware stack.

-

-`inline`:idx:

-    The inline convention means the the caller should not call the procedure,

-    but inline its code directly. Note that Nimrod does not inline, but leaves

-    this to the C compiler. Thus it generates ``__inline`` procedures. This is

-    only a hint for the compiler: It may completely ignore it and

-    it may inline procedures that are not marked as ``inline``.

-

-`fastcall`:idx:

-    Fastcall means different things to different C compilers. One gets whatever

-    the C ``__fastcall`` means.

-

-`nimcall`:idx:

-    Nimcall is the default convention used for Nimrod procedures. It is the

-    same as ``fastcall``, but only for C compilers that support ``fastcall``.

-

-`closure`:idx:

-    indicates that the procedure expects a context, a closure that needs

-    to be passed to the procedure. The implementation is the

-    same as ``cdecl``, but with a hidden pointer parameter (the

-    *closure*). The hidden parameter is always the last one.

-

-`syscall`:idx:

-    The syscall convention is the same as ``__syscall`` in C. It is used for

-    interrupts.

-

-`noconv`:idx:

-    The generated C code will not have any explicit calling convention and thus

-    use the C compiler's default calling convention. This is needed because

-    Nimrod's default calling convention for procedures is ``fastcall`` to

-    improve speed. This is unlikely to be needed by the user.

-

-Most calling conventions exist only for the Windows 32-bit platform.

-

-

-

-Statements

-----------

-Nimrod uses the common statement/expression paradigma: `Statements`:idx: do not

-produce a value in contrast to expressions. Call expressions are statements.

-If the called procedure returns a value, it is not a valid statement

-as statements do not produce values. To evaluate an expression for

-side-effects and throwing its value away, one can use the ``discard``

-statement.

-

-Statements are separated into `simple statements`:idx: and 

-`complex statements`:idx:.

-Simple statements are statements that cannot contain other statements, like

-assignments, calls or the ``return`` statement; complex statements can

-contain other statements. To avoid the `dangling else problem`:idx:, complex

-statements always have to be intended::

-

-  simpleStmt ::= returnStmt

-             | yieldStmt

-             | discardStmt

-             | raiseStmt

-             | breakStmt

-             | continueStmt

-             | pragma

-             | importStmt

-             | fromStmt

-             | includeStmt

-             | exprStmt

-  complexStmt ::= ifStmt | whileStmt | caseStmt | tryStmt | forStmt

-                   | blockStmt | asmStmt

-                   | procDecl | iteratorDecl | macroDecl | templateDecl

-                   | constDecl | typeDecl | whenStmt | varStmt

-

-

-

-Discard statement

-~~~~~~~~~~~~~~~~~

-

-Syntax::

-

-  discardStmt ::= DISCARD expr

-

-Example:

-

-.. code-block:: nimrod

-

-  discard proc_call("arg1", "arg2") # discard the return value of `proc_call`

-

-The `discard`:idx: statement evaluates its expression for side-effects and 

-throws the expression's resulting value away. If the expression has no 

-side-effects, this generates a static error. Ignoring the return value of a 

-procedure without using a discard statement is not allowed.

-

-

-Var statement

-~~~~~~~~~~~~~

-

-Syntax::

-

-  colonOrEquals ::= COLON typeDesc [EQUALS expr] | EQUALS expr

-  varPart ::= (symbol ["*" | "-"] [pragma] optComma)+ colonOrEquals [COMMENT]

-  varStmt ::= VAR (varPart | indPush varPart (SAD varPart)* DED)

-

-`Var`:idx: statements declare new local and global variables and 

-initialize them. A comma seperated list of variables can be used to specify

-variables of the same type:

-

-.. code-block:: nimrod

-

-  var

-    a: int = 0

-    x, y, z: int

-

-If an initializer is given the type can be omitted: The variable is of the

-same type as the initializing expression. Variables are always initialized

-with a default value if there is no initializing expression. The default

-value depends on the type and is always a zero in binary.

-

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

-Type                            default value

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

-any integer type                0

-any float                       0.0

-char                            '\0'

-bool                            false

-ref or pointer type             nil

-procedural type                 nil

-sequence                        nil

-string                          nil (**not** "")

-tuple[A, B, ...]                (default(A), default(B), ...)

-                                (analogous for objects and records)

-array[0..., T]                  [default(T), ...]

-range[T]                        default(T); this may be out of the valid range

-T = enum                        cast[T](0); this may be an invalid value

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

-

-

-Const section

-~~~~~~~~~~~~~

-

-Syntax::

-

-  colonAndEquals ::= [COLON typeDesc] EQUALS expr

-  constDecl ::= CONST

-           indPush

-                symbol ["*"] [pragma] colonAndEquals

-           (SAD symbol ["*"] [pragma] colonAndEquals)*

-           DED

-

-Example:

-

-.. code-block:: nimrod

-

-  const

-    MyFilename = "/home/my/file.txt"

-    debugMode: bool = false

-

-The `const`:idx: section declares symbolic constants. A symbolic constant is 

-a name for a constant expression. Symbolic constants only allow read-access.

-

-

-If statement

-~~~~~~~~~~~~

-

-Syntax::

-

-  ifStmt ::= IF expr COLON stmt (ELIF expr COLON stmt)* [ELSE COLON stmt]

-

-Example:

-

-.. code-block:: nimrod

-

-  var name = readLine(stdin)

-

-  if name == "Andreas":

-    echo("What a nice name!")

-  elif name == "":

-    echo("Don't you have a name?")

-  else:

-    echo("Boring name...")

-

-The `if`:idx: statement is a simple way to make a branch in the control flow:

-The expression after the keyword ``if`` is evaluated, if it is true

-the corresponding statements after the ``:`` are executed. Otherwise

-the expression after the ``elif`` is evaluated (if there is an

-``elif`` branch), if it is true the corresponding statements after

-the ``:`` are executed. This goes on until the last ``elif``. If all

-conditions fail, the ``else`` part is executed. If there is no ``else``

-part, execution continues with the statement after the ``if`` statement.

-

-

-Case statement

-~~~~~~~~~~~~~~

-

-Syntax::

-

-  caseStmt ::= CASE expr (OF sliceList COLON stmt)*

-                         (ELIF expr COLON stmt)*

-                         [ELSE COLON stmt]

-

-Example:

-

-.. code-block:: nimrod

-

-  case readline(stdin)

-  of "delete-everything", "restart-computer":

-    echo("permission denied")

-  of "go-for-a-walk":     echo("please yourself")

-  else:                   echo("unknown command")

-

-The `case`:idx: statement is similar to the if statement, but it represents

-a multi-branch selection. The expression after the keyword ``case`` is

-evaluated and if its value is in a *vallist* the corresponding statements

-(after the ``of`` keyword) are executed. If the value is no given *vallist*

-the ``else`` part is executed. If there is no ``else`` part and not all

-possible values that ``expr`` can hold occur in a ``vallist``, a static

-error is given. This holds only for expressions of ordinal types.

-If the expression is not of an ordinal type, and no ``else`` part is

-given, control just passes after the ``case`` statement.

-

-To suppress the static error in the ordinal case the programmer needs

-to write an ``else`` part with a ``nil`` statement.

-

-

-When statement

-~~~~~~~~~~~~~~

-

-Syntax::

-

-  whenStmt ::= WHEN expr COLON stmt (ELIF expr COLON stmt)* [ELSE COLON stmt]

-

-Example:

-

-.. code-block:: nimrod

-  

-  when sizeof(int) == 2:

-    echo("running on a 16 bit system!")

-  elif sizeof(int) == 4:

-    echo("running on a 32 bit system!")

-  elif sizeof(int) == 8:

-    echo("running on a 64 bit system!")

-  else:

-    echo("cannot happen!")

-

-The `when`:idx: statement is almost identical to the ``if`` statement with some

-exceptions:

-

-* Each ``expr`` has to be a constant expression (of type ``bool``).

-* The statements do not open a new scope if they introduce new identifiers.

-* The statements that belong to the expression that evaluated to true are

-  translated by the compiler, the other statements are not checked for

-  syntax or semantics at all! This holds also for any ``expr`` coming

-  after the expression that evaluated to true.

-

-The ``when`` statement enables conditional compilation techniques. As

-a special syntatic extension, the ``when`` construct is also available

-within ``record`` or ``object`` definitions.

-

-

-Raise statement

-~~~~~~~~~~~~~~~

-

-Syntax::

-

-  raiseStmt ::= RAISE [expr]

-  

-Example:

-  

-.. code-block:: nimrod

-  raise EOS("operating system failed")

-

-Apart from built-in operations like array indexing, memory allocation, etc.

-the ``raise`` statement is the only way to raise an exception. The

-identifier has to be the name of a previously declared exception. A

-comma followed by an expression may follow; the expression must be of type

-``string`` or ``cstring``; this is an error message that can be extracted

-with the `getCurrentExceptionMsg`:idx: procedure in the module ``system``.

-

-If no exception name is given, the current exception is `re-raised`:idx:. The

-`ENoExceptionToReraise`:idx: exception is raised if there is no exception to

-re-raise. It follows that the ``raise`` statement *always* raises an

-exception.

-

-

-Try statement

-~~~~~~~~~~~~~

-

-Syntax::

-

-  exceptList ::= (qualifiedIdent optComma)*

-  tryStmt ::= TRY COLON stmt

-             (EXCEPT exceptList COLON stmt)*

-             [FINALLY COLON stmt]

-

-Example:

-

-.. code-block:: nimrod

-  # read the first two lines of a text file that should contain numbers

-  # and tries to add them

-  var

-    f: TFile

-  if openFile(f, "numbers.txt"):

-    try:

-      var a = readLine(f)

-      var b = readLine(f)

-      echo("sum: " & $(parseInt(a) + parseInt(b)))

-    except EOverflow:

-      echo("overflow!")

-    except EValue:

-      echo("could not convert string to integer")

-    except EIO:

-      echo("IO error!")

-    finally:

-      closeFile(f)

-

-The statements after the `try`:idx: are executed in sequential order unless

-an exception ``e`` is raised. If the exception type of ``e`` matches any

-of the list ``exceptlist`` the corresponding statements are executed.

-The statements following the ``except`` clauses are called

-`exception handlers`:idx:.

-

-The empty `except`:idx: clause is executed if there is an exception that is

-in no list. It is similiar to an ``else`` clause in ``if`` statements.

-

-If there is a `finally`:idx: clause, it is always executed after the

-exception handlers.

-

-The exception is *consumed* in an exception handler. However, an

-exception handler may raise another exception. If the exception is not

-handled, it is propagated through the call stack. This means that often

-the rest of the procedure - that is not within a ``finally`` clause -

-is not executed (if an exception occurs).

-

-

-Return statement

-~~~~~~~~~~~~~~~~

-

-Syntax::

-

-  returnStmt ::= RETURN [expr]

-

-Example:

-  

-.. code-block:: nimrod

-  return 40+2

-

-The `return`:idx: statement ends the execution of the current procedure. 

-It is only allowed in procedures. If there is an ``expr``, this is syntactic 

-sugar for:

-

-.. code-block:: nimrod

-  result = expr

-  return

-

-The `result`:idx: variable is always the return value of the procedure. It is

-automatically declared by the compiler.

-

-

-Yield statement

-~~~~~~~~~~~~~~~

-

-Syntax::

-

-  yieldStmt ::= YIELD expr

-  

-Example:

-

-.. code-block:: nimrod

-  yield (1, 2, 3)

-  

-The `yield`:idx: statement is used instead of the ``return`` statement in 

-iterators. It is only valid in iterators. Execution is returned to the body 

-of the for loop that called the iterator. Yield does not end the iteration 

-process, but execution is passed back to the iterator if the next iteration

-starts. See the section about iterators (`Iterators and the for statement`_) 

-for further information.

-

-

-Block statement

-~~~~~~~~~~~~~~~

-

-Syntax::

-

-  blockStmt ::= BLOCK [symbol] COLON stmt

-  

-Example:

-

-.. code-block:: nimrod

-  var found = false

-  block myblock:  

-    for i in 0..3:

-      for j in 0..3:

-        if a[j][i] == 7:

-          found = true

-          break myblock # leave the block, in this case both for-loops

-  echo(found)

-

-The block statement is a means to group statements to a (named) `block`:idx:.

-Inside the block, the ``break`` statement is allowed to leave the block

-immediately. A ``break`` statement can contain a name of a surrounding

-block to specify which block is to leave.

-

-

-Break statement

-~~~~~~~~~~~~~~~

-

-Syntax::

-

-  breakStmt ::= BREAK [symbol]

-  

-Example:

-

-.. code-block:: nimrod 

-  break

-

-The `break`:idx: statement is used to leave a block immediately. If ``symbol``

-is given, it is the name of the enclosing block that is to leave. If it is

-absent, the innermost block is leaved.

-

-

-While statement

-~~~~~~~~~~~~~~~

-

-Syntax::

-  

-  whileStmt ::= WHILE expr COLON stmt

-  

-Example:

-

-.. code-block:: nimrod

-  echo("Please tell me your password: \n")

-  var pw = readLine(stdin)

-  while pw != "12345":

-    echo("Wrong password! Next try: \n")

-    pw = readLine(stdin)

-

-

-The `while`:idx: statement is executed until the ``expr`` evaluates to false.

-Endless loops are no error. ``while`` statements open an `implicit block`,

-so that they can be leaved with a ``break`` statement.

-

-

-Continue statement

-~~~~~~~~~~~~~~~~~~

-

-Syntax::

-

-  continueStmt ::= CONTINUE

-

-A `continue`:idx: statement leads to the immediate next iteration of the 

-surrounding loop construct. It is only allowed within a loop. A continue 

-statement is syntactic sugar for a nested block:

-

-.. code-block:: nimrod

-  while expr1:

-    stmt1

-    continue

-    stmt2

-    

-  # is equivalent to:

-  while expr1:

-    block myBlockName:

-      stmt1

-      break myBlockName

-      stmt2

-

-

-Assembler statement

-~~~~~~~~~~~~~~~~~~~

-Syntax::

-

-  asmStmt ::= ASM [pragma] (STR_LIT | RSTR_LIT | TRIPLESTR_LIT)

-

-The direct embedding of `assembler`:idx: code into Nimrod code is supported 

-by the unsafe ``asm`` statement. Identifiers in the assembler code that refer to

-Nimrod identifiers shall be enclosed in a special character which can be

-specified in the statement's pragmas. The default special character is ``'`'``.

-

-

-Procedures

-~~~~~~~~~~

-What most programming languages call `methods`:idx: or `funtions`:idx: are 

-called `procedures`:idx: in Nimrod (which is the correct terminology). A 

-procedure declaration defines an identifier and associates it with a block 

-of code. A procedure may call itself recursively. The syntax is::

-

-  paramList ::= [PAR_LE ((symbol optComma)+ COLON typeDesc optComma)* PAR_RI]

-                [COLON typeDesc]

-  genericParams ::= BRACKET_LE (symbol [EQUALS typeDesc] )* BRACKET_RI

-

-  procDecl ::= PROC symbol ["*"] [genericParams] paramList [pragma]

-               [EQUALS stmt]

-

-If the ``EQUALS stms`` part is missing, it is a `forward`:idx: declaration. If 

-the proc returns a value, the procedure body can access an implicit declared

-variable named `result`:idx: that represents the return value. Procs can be

-overloaded. The overloading resolution algorithm tries to find the proc that is

-the best match for the arguments. A parameter may be given a default value that

-is used if the caller does not provide a value for this parameter. Example:

-

-.. code-block:: nimrod

-

-  proc toLower(c: Char): Char = # toLower for characters

-    if c in {'A'..'Z'}:

-      result = chr(ord(c) + (ord('a') - ord('A')))

-    else:

-      result = c

-  

-  proc toLower(s: string): string = # toLower for strings

-    result = newString(len(s))

-    for i in 0..len(s) - 1:

-      result[i] = toLower(s[i]) # calls toLower for characters; no recursion!

-      

-`Operators`:idx: are procedures with a special operator symbol as identifier:

-

-.. code-block:: nimrod

-  proc `$` (x: int): string =     # converts an integer to a string;

-                                  # since it has one parameter this is a prefix

-                                  # operator. With two parameters it would be 

-                                  # an infix operator.

-    return intToStr(x)

-

-Calling a procedure can be done in many different ways:

-

-.. code-block:: nimrod

-  proc callme(x, y: int, s: string = "", c: char, b: bool = false) = ...

-  

-  # call with positional arguments# parameter bindings:

-  callme(0, 1, "abc", '\t', true) # (x=0, y=1, s="abc", c='\t', b=true)

-  # call with named and positional arguments:

-  callme(y=1, x=0, "abd", '\t')   # (x=0, y=1, s="abd", c='\t', b=false)

-  # call with named arguments (order is not relevant):

-  callme(c='\t', y=1, x=0)        # (x=0, y=1, s="", c='\t', b=false)

-  # call as a command statement: no () or , needed:

-  callme 0 1 "abc" '\t'

-

-

-Iterators and the for statement

-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-

-Syntax::

-

-  forStmt ::= FOR (symbol optComma)+ IN expr [DOTDOT expr] COLON stmt

-  

-  paramList ::= [PAR_LE ((symbol optComma)+ COLON typeDesc optComma)* PAR_RI]

-                [COLON typeDesc]

-  genericParams ::= BRACKET_LE (symbol [EQUALS typeDesc] )* BRACKET_RI

-  

-  iteratorDecl ::= ITERATOR symbol ["*"] [genericParams] paramList [pragma]

-               [EQUALS stmt]

-

-The `for`:idx: statement is an abstract mechanism to iterate over the elements

-of a container. It relies on an `iterator`:idx: to do so. Like ``while``

-statements, ``for`` statements open an `implicit block`:idx:, so that they

-can be leaved with a ``break`` statement. The ``for`` loop declares 

-iteration variables (``x`` in the example) - their scope reaches until the 

-end of the loop body. The iteration variables' types are inferred by the

-return type of the iterator. 

-

-An iterator is similar to a procedure, except that it is always called in the

-context of a ``for`` loop. Iterators provide a way to specify the iteration over

-an abstract type. A key role in the execution of a ``for`` loop plays the 

-``yield`` statement in the called iterator. Whenever a ``yield`` statement is

-reached the data is bound to the ``for`` loop variables and control continues

-in the body of the ``for`` loop. The iterator's local variables and execution 

-state are automatically saved between calls. Example:

-  

-.. code-block:: nimrod

-  # this definition exists in the system module

-  iterator items*(a: string): char {.inline.} =

-    var i = 0

-    while i < len(a):

-      yield a[i]

-      inc(i)

-      

-  for ch in items("hello world"): # `ch` is an iteration variable

-    echo(ch)

-

-The compiler generates code as if the programmer would have written this:

-

-.. code-block:: nimrod

-  var i = 0

-  while i < len(a):

-    var ch = a[i]

-    echo(ch)

-    inc(i)

-    

-The current implementation always inlines the iterator code leading to zero

-overhead for the abstraction. But this may increase the code size. Later

-versions of the compiler will only inline iterators which have the calling

-convention ``inline``. 

-

-If the iterator yields a tuple, there have to be as many iteration variables

-as there are components in the tuple. The i'th iteration variable's type is

-the one of the i'th component.

-

-

-Type sections

-~~~~~~~~~~~~~

-

-Syntax::

-

-  typeDef ::= typeDesc | recordDef | objectDef | enumDef

-  genericParams ::= BRACKET_LE (symbol [EQUALS typeDesc] )* BRACKET_RI

-

-  typeDecl ::= TYPE

-           indPush

-                symbol ["*"] [genericParams] [EQUALS typeDef]

-           (SAD symbol ["*"] [genericParams] [EQUALS typeDef])*

-           DED

-           

-Example:

-  

-.. code-block:: nimrod

-  type # example demonstrates mutually recursive types

-    PNode = ref TNode # a traced pointer to a TNode

-    TNode = record

-      le, ri: PNode   # left and right subtrees

-      sym: ref TSym   # leaves contain a reference to a TSym

-      

-    TSym = record     # a symbol

-      name: string    # the symbol's name

-      line: int       # the line the symbol was declared in

-      code: PNode     # the symbol's abstract syntax tree

-

-A `type`:idx: section begins with the ``type`` keyword. It contains multiple 

-type definitions. A type definition binds a type to a name. Type definitions 

-can be recursive or even mutually recursive. Mutually Recursive types are only

-possible within a single ``type`` section.

-

-

-Generics

-~~~~~~~~

-

-Example:

-

-.. code-block:: nimrod

-  type

-    TBinaryTree[T] = record      # TBinaryTree is a generic type with

-                                 # with generic param ``T``

-      le, ri: ref TBinaryTree[T] # left and right subtrees; may be nil

-      data: T                    # the data stored in a node

-    PBinaryTree[T] = ref TBinaryTree[T] # a shorthand for notational convenience

-    

-  proc newNode[T](data: T): PBinaryTree[T] = # constructor for a node

-    new(result)

-    result.dat = data

-    

-  proc add[T](root: var PBinaryTree[T], n: PBinaryTree[T]) =

-    if root == nil:

-      root = n

-    else:

-      var it = root

-      while it != nil:

-        var c = cmp(it.data, n.data) # compare the data items; uses

-                                     # the generic ``cmd`` proc that works for

-                                     # any type that has a ``==`` and ``<``

-                                     # operator

-        if c < 0:

-          if it.le == nil:

-            it.le = n

-            return

-          it = it.le

-        else:

-          if it.ri == nil:

-            it.ri = n

-            return

-          it = it.ri

-  

-  iterator inorder[T](root: PBinaryTree[T]): T =

-    # inorder traversal of a binary tree

-    # recursive iterators are not yet implemented, so this does not work in

-    # the current compiler!

-    if root.le != nil:

-      yield inorder(root.le)

-    yield root.data

-    if root.ri != nil:

-      yield inorder(root.ri)

-  

-  var

-    root: PBinaryTree[string] # instantiate a PBinaryTree with the type string

-  add(root, newNode("hallo")) # instantiates generic procs ``newNode`` and

-  add(root, newNode("world")) # ``add``

-  for str in inorder(root):

-    writeln(stdout, str)

-

-`Generics`:idx: are Nimrod's means to parametrize procs, iterators or types with

-`type parameters`:idx:. Depending on context, the brackets are used either to

-introduce type parameters or to instantiate a generic proc, iterator or type.

-

-

-Templates

-~~~~~~~~~

-

-A `template`:idx: is a simple form of a macro. It operates on parse trees and is

-processed in the semantic pass of the compiler. So they integrate well with the

-rest of the language and share none of C's preprocessor macros flaws. However,

-they may lead to code that is harder to understand and maintain. So one ought

-to use them sparingly. The usage of ordinary procs, iterators or generics is

-preferred to the usage of templates.

-

-Example:

-

-.. code-block:: nimrod

-  template `!=` (a, b: expr): expr =

-    # this definition exists in the System module

-    not (a == b)

-    

-  writeln(5 != 6) # the compiler rewrites that to: writeln(not (5 == 6))

-

-

-Macros

-~~~~~~

-

-`Macros`:idx: are the most powerful feature of Nimrod. They should be used 

-only to implement `domain specific languages`:idx:. They may lead to code 

-that is harder to understand and maintain. So one ought to use them sparingly. 

-The usage of ordinary procs, iterators or generics is preferred to the usage of

-macros.

-

-

-Modules

--------

-Nimrod supports splitting a program into pieces by a `module`:idx: concept. 

-Modules make separate compilation possible. Each module needs to be in its 

-own file. Modules enable `information hiding`:idx: and 

-`separate compilation`:idx:. A module may gain access to symbols of another 

-module by the `import`:idx: statement. `Recursive module dependancies`:idx: are 

-allowed, but slightly subtle.

-

-The algorithm for compiling modules is:

-

-- Compile the whole module as usual, following import statements recursively

-- if we have a cycle only import the already parsed symbols (that are 

-  exported); if an unknown identifier occurs then abort

-

-This is best illustrated by an example:

-

-.. code-block:: nimrod

-  # Module A

-  type

-    T1* = int

-  import B # the compiler starts parsing B

-

-  proc main() =

-    var i = p(3) # works because B has been parsed completely here

-

-  main()

-

-

-  # Module B

-  import A  # A is not parsed here! Only the already known symbols

-            # of A are imported here.

-

-  proc p*(x: A.T1): A.T1 # this works because the compiler has already

-                         # added T1 to A's interface symbol table

-

-  proc p(x: A.T1): A.T1 = return x + 1

-

-

-Scope rules

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

-Identifiers are valid from the point of their declaration until the end of

-the block in which the declaration occurred. The range where the identifier

-is known is the `scope`:idx: of the identifier. The exact scope of an 

-identifier depends on the way it was declared.

-

-Block scope

-~~~~~~~~~~~

-The *scope* of a variable declared in the declaration part of a block

-is valid from the point of declaration until the end of the block. If a

-block contains a second block, in which the identifier is redeclared,

-then inside this block, the second declaration will be valid. Upon

-leaving the inner block, the first declaration is valid again. An

-identifier cannot be redefined in the same block, except if valid for

-procedure or iterator overloading purposes.

-

-

-Record or object scope

-~~~~~~~~~~~~~~~~~~~~~~

-The field identifiers inside a record or object definition are valid in the

-following places:

-

-* To the end of the record definition

-* Field designators of a variable of the given record type.

-* In all descendent types of the object type.

-

-Module scope

-~~~~~~~~~~~~

-All identifiers in the interface part of a module are valid from the point of

-declaration, until the end of the module. Furthermore, the identifiers are

-known in other modules that import the module. Identifiers from indirectly

-dependent modules are *not* available. The `system`:idx: module is automatically 

-imported in all other modules.

-

-If a module imports an identifier by two different modules,

-each occurance of the identifier has to be qualified, unless it is an

-overloaded procedure or iterator in which case the overloading

-resolution takes place:

-

-.. code-block:: nimrod

-  # Module A

-  var x*: string

-

-  # Module B

-  var x*: int

-

-  # Module C

-  import A, B

-  write(stdout, x) # error: x is ambigious

-  write(sdtout, A.x) # no error: qualifier used

-  

-  var x = 4

-  write(stdout, x) # not ambigious: uses the module C's x

-

-

-Messages

-========

-

-The Nimrod compiler emits different kinds of messages: `hint`:idx:,

-`warning`:idx:, and `error`:idx: messages. An *error* message is emitted if 

-the compiler encounters any static error.

-

-Pragmas

-=======

-

-Syntax::

-  

-  pragma ::= CURLYDOT_LE (expr [COLON expr] optComma)+ (CURLYDOT_RI | CURLY_RI)

-

-Pragmas are Nimrod's method to give the compiler additional information/

-commands without introducing a massive number of new keywords. Pragmas are

-processed on the fly during parsing. Pragmas are always enclosed in the

-special ``{.`` and ``.}`` curly brackets.

-

-

-define pragma

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

-The `define`:idx: pragma defines a conditional symbol. This symbol may only be

-used in other pragmas and in the ``defined`` expression and not in ordinary

-Nimrod source code. The conditional symbols go into a special symbol table.

-The compiler defines the target processor and the target operating

-system as conditional symbols.

-

-

-undef pragma

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

-The `undef`:idx: pragma the counterpart to the define pragma. It undefines a

-conditional symbol.

-

-

-error pragma

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

-The `error`:idx: pragma is used to make the compiler output an error message 

-with the given content. Compilation currently aborts after an error, but this 

-may be changed in later versions.

-

-

-fatal pragma

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

-The `fatal`:idx: pragma is used to make the compiler output an error message 

-with the given content. In contrast to the ``error`` pragma, compilation

-is guaranteed to be aborted by this pragma. 

-

-warning pragma

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

-The `warning`:idx: pragma is used to make the compiler output a warning message 

-with the given content. Compilation continues after the warning. 

-

-hint pragma

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

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

-the given content. Compilation continues after the hint.

-

-

-compilation option pragmas

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

-The listed pragmas here can be used to override the code generation options

-for a section of code.

-::

-

-  "{." pragma: val {pragma: val} ".}"

-

-

-The implementation currently provides the following possible options (later

-various others may be added).

-

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

-pragma           allowed values   description

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

-checks           on|off           Turns the code generation for all runtime

-                                  checks on or off.

-bound_checks     on|off           Turns the code generation for array bound

-                                  checks on or off.

-overflow_checks  on|off           Turns the code generation for over- or

-                                  underflow checks on or off.

-nil_checks       on|off           Turns the code generation for nil pointer

-                                  checks on or off.

-assertions       on|off           Turns the code generation for assertions

-                                  on or off.

-warnings         on|off           Turns the warning messages of the compiler

-                                  on or off.

-hints            on|off           Turns the hint messages of the compiler

-                                  on or off.

-optimization     none|speed|size  Optimize the code for speed or size, or

-                                  disable optimization. For non-optimizing

-                                  compilers this option has no effect.

-                                  Neverless they must parse it properly.

-callconv         cdecl|...        Specifies the default calling convention for

-                                  all procedures (and procedure types) that

-                                  follow.

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

-

-Example:

-

-.. code-block:: nimrod

-  {.checks: off, optimization: speed.}

-  # compile without runtime checks and optimize for speed

-

-

-push and pop pragmas

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

-The `push/pop`:idx: pragmas are very similar to the option directive,

-but are used to override the settings temporarily. Example:

-

-.. code-block:: nimrod

-  {.push checks: off.}

-  # compile this section without runtime checks as it is

-  # speed critical

-  # ... some code ...

-  {.pop.} # restore old settings

+  Nimrod contains a sophisticated
+  compile-time evaluator, so procedures declared with the ``{.noSideEffect.}``
+  pragma can be used in constant expressions:
+
+  .. code-block:: nimrod
+
+    from strutils import findSubStr
+    const
+      x = findSubStr('a', "hallo") # x is 1; this is computed at compile time!
+
+
+Types
+-----
+
+All expressions have a `type`:idx: which is known at compile time. Thus Nimrod
+is statically typed. One can declare new types, which is in
+essence defining an identifier that can be used to denote this custom type.
+
+These are the major type classes:
+
+* ordinal types (consist of integer, bool, character, enumeration
+  (and subranges thereof) types)
+* floating point types
+* string type
+* structured types
+* reference (pointer) type
+* procedural type
+* generic type
+
+
+Ordinal types
+~~~~~~~~~~~~~
+`Ordinal types`:idx: have the following characteristics:
+
+- Ordinal types are countable and ordered. This property allows
+  the operation of functions as ``Inc``, ``Ord``, ``Dec`` on ordinal types to
+  be defined.
+- Ordinal values have a smallest possible value. Trying to count farther
+  down than the smallest value gives a checked runtime or static error.
+- Ordinal values have a largest possible value. Trying to count farther
+  than the largest value gives a checked runtime or static error.
+
+Integers, bool, characters and enumeration types (and subrange of these
+types) belong to ordinal types.
+
+
+Pre-defined numerical types
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+These integer types are pre-defined:
+
+``int``
+  the generic signed integer type; its size is platform dependant
+  (the compiler chooses the processor's fastest integer type)
+  this type should be used in general. An integer literal that has no type
+  suffix is of this type.
+
+intXX
+  additional signed integer types of XX bits use this naming scheme
+  (example: int16 is a 16 bit wide integer).
+  The current implementation supports ``int8``, ``int16``, ``int32``, ``int64``.
+  Literals of these types have the suffix 'iXX.
+
+
+There are no `unsigned integer`:idx: types, only `unsigned operations`:idx:
+that treat their arguments as unsigned. Unsigned operations all wrap around;
+they may not lead to over- or underflow errors. Unsigned operations use the
+``%`` postfix as convention:
+
+======================   ======================================================
+operation                meaning
+======================   ======================================================
+``a +% b``               unsigned integer addition
+``a -% b``               unsigned integer substraction
+``a *% b``               unsigned integer multiplication
+``a /% b``               unsigned integer division
+``a %% b``               unsigned integer modulo operation
+``a <% b``               treat ``a`` and ``b`` as unsigned and compare
+``a <=% b``              treat ``a`` and ``b`` as unsigned and compare
+``ze(a)``                extends the bits of ``a`` with zeros until it has the
+                         width of the ``int`` type
+``toU8(a)``              treats ``a`` as unsigned and converts it to an
+                         unsigned integer of 8 bits (but still the
+                         ``int8`` type)
+``toU16(a)``             treats ``a`` as unsigned and converts it to an
+                         unsigned integer of 16 bits (but still the
+                         ``int16`` type)
+``toU32(a)``             treats ``a`` as unsigned and converts it to an
+                         unsigned integer of 32 bits (but still the
+                         ``int32`` type)
+======================   ======================================================
+
+The following floating point types are pre-defined:
+
+``float``
+  the generic floating point type; its size is platform dependant
+  (the compiler chooses the processor's fastest floating point type)
+  this type should be used in general
+
+floatXX
+  an implementation may define additional floating point types of XX bits using
+  this naming scheme (example: float64 is a 64 bit wide float). The current
+  implementation supports ``float32`` and ``float64``. Literals of these types
+  have the suffix 'fXX.
+
+`Automatic type conversion`:idx: in expressions where different kinds
+of integer types are used is performed. However, if the type conversion
+loses information, the `EInvalidValue`:idx: exception is raised. Certain cases
+of the convert error are detected at compile time.
+
+Automatic type conversion in expressions with different kinds
+of floating point types is performed: The smaller type is
+converted to the larger. Arithmetic performed on floating point types
+follows the IEEE standard. Only the ``int`` type is converted to a floating
+point type automatically, other integer types are not.
+
+
+Boolean type
+~~~~~~~~~~~~
+The `boolean`:idx: type is named ``bool`` in Nimrod and can be one of the two
+pre-defined values ``true`` and ``false``. Conditions in while,
+if, elif, when statements need to be of type bool.
+
+This condition holds::
+
+  ord(false) == 0 and ord(true) == 1
+
+The operators ``not, and, or, xor, implies, <, <=, >, >=, !=, ==`` are defined
+for the bool type. The ``and`` and ``or`` operators perform short-cut
+evaluation. Example:
+
+.. code-block:: nimrod
+
+  while p != nil and p.name != "xyz":
+    # p.name is not evaluated if p == nil
+    p = p.next
+
+
+The size of the bool type is one byte.
+
+
+Character type
+~~~~~~~~~~~~~~
+The `character type`:idx: is named ``char`` in Nimrod. Its size is one byte.
+Thus it cannot represent an UTF-8 character, but a part of it.
+The reason for this is efficiency: For the overwhelming majority of use-cases,
+the resulting programs will still handle UTF-8 properly as UTF-8 was specially
+designed for this.
+Another reason is that Nimrod can support ``array[char, int]`` or
+``set[char]`` efficiently as many algorithms rely on this feature. The
+`TUniChar` type is used for Unicode characters, it can represent any Unicode
+character. ``TUniChar`` is declared the ``unicode`` standard module.
+
+
+
+Enumeration types
+~~~~~~~~~~~~~~~~~
+`Enumeration`:idx: types define a new type whose values consist only of the ones
+specified.
+The values are ordered by the order in enum's declaration. Example:
+
+.. code-block:: nimrod
+
+  type
+    TDirection = enum
+      north, east, south, west
+
+
+Now the following holds::
+
+  ord(north) == 0
+  ord(east) == 1
+  ord(south) == 2
+  ord(west) == 3
+
+Thus, north < east < south < west. The comparison operators can be used
+with enumeration types.
+
+For better interfacing to other programming languages, the fields of enum
+types can be assigned an explicit ordinal value. However, the ordinal values
+have to be in ascending order. A field whose ordinal value that is not
+explicitly given, is assigned the value of the previous field + 1.
+
+An explicit ordered enum can have *wholes*:
+
+.. code-block:: nimrod
+  type
+    TTokenType = enum
+      a = 2, b = 4, c = 89 # wholes are valid
+
+However, it is then not an ordinal anymore, so it is not possible to use these
+enums as an index type for arrays. The procedures ``inc``, ``dec``, ``succ``
+and ``pred`` are not available for them either.
+
+
+Subrange types
+~~~~~~~~~~~~~~
+A `subrange`:idx: type is a range of values from an ordinal type (the host
+type). To define a subrange type, one must specify it's limiting values: the
+highest and lowest value of the type:
+
+.. code-block:: nimrod
+  type
+    TSubrange = range[0..5]
+
+
+``TSubrange`` is a subrange of an integer which can only hold the values 0
+to 5. Assigning any other value to a variable of type ``TSubrange`` is a
+checked runtime error (or static error if it can be statically
+determined). Assignments from the base type to one of its subrange types
+(and vice versa) are allowed.
+
+A subrange type has the same size as its base type (``int`` in the example).
+
+
+String type
+~~~~~~~~~~~
+All string literals are of the type `string`:idx:. A string in Nimrod is very
+similar to a sequence of characters. However, strings in Nimrod both are
+zero-terminated and have a length field. One can retrieve the length with the
+builtin ``len`` procedure; the length never counts the terminating zero.
+The assignment operator for strings always copies the string.
+
+Strings are compared by their lexicographical order. All comparison operators
+are available. Strings can be indexed like arrays (lower bound is 0). Unlike
+arrays, they can be used in case statements:
+
+.. code-block:: nimrod
+
+  case paramStr(i)
+  of "-v": incl(options, optVerbose)
+  of "-h", "-?": incl(options, optHelp)
+  else: write(stdout, "invalid command line option!\n")
+
+Per convention, all strings are UTF-8 strings, but this is not enforced. For
+example, when reading strings from binary files, they are merely a sequence of
+bytes. The index operation ``s[i]`` means the i-th *char* of ``s``, not the
+i-th *unichar*. The iterator ``unichars`` from the ``unicode`` standard
+module can be used for iteration over all unicode characters.
+
+
+Structured types
+~~~~~~~~~~~~~~~~
+A variable of a `structured type`:idx: can hold multiple values at the same
+time. Stuctured types can be nested to unlimited levels. Arrays, sequences,
+tuples, objects and sets belong to the structured types.
+
+Array and sequence types
+~~~~~~~~~~~~~~~~~~~~~~~~
+`Arrays`:idx: are a homogenous type, meaning that each element in the array
+has the same type. Arrays always have a fixed length which is specified at
+compile time (except for open arrays). They can be indexed by any ordinal type.
+A parameter ``A`` may be an *open array*, in which case it is indexed by
+integers from 0 to ``len(A)-1``.
+
+`Sequences`:idx: are similar to arrays but of dynamic length which may change
+during runtime (like strings). A sequence ``S`` is always indexed by integers
+from 0 to ``len(S)-1`` and its bounds are checked. Sequences can also be
+constructed by the array constructor ``[]``.
+
+A sequence may be passed to a parameter that is of type *open array*, but
+not to a multi-dimensional open array, because it is impossible to do so in an
+efficient manner.
+
+An array expression may be constructed by the array constructor ``[]``.
+A constructed array is assignment compatible to a sequence.
+
+Example:
+
+.. code-block:: nimrod
+
+  type
+    TIntArray = array[0..5, int] # an array that is indexed with 0..5
+    TIntSeq = seq[int] # a sequence of integers
+  var
+    x: TIntArray
+    y: TIntSeq
+  x = [1, 2, 3, 4, 5, 6] # [] this is the array constructor that is compatible
+                         # with arrays, open arrays and
+  y = [1, 2, 3, 4, 5, 6] # sequences
+
+The lower bound of an array may be received by the built-in proc
+``low()``, the higher bound by ``high()``. The length may be
+received by ``len()``.
+
+Arrays are always bounds checked (at compile-time or at runtime). These
+checks can be disabled via pragmas or invoking the compiler with the
+``--bound_checks:off`` command line switch.
+
+
+Tuples and object types
+~~~~~~~~~~~~~~~~~~~~~~~
+A variable of a `tuple`:idx: or `object`:idx: type is a heterogenous storage
+container.
+A tuple or object defines various named *fields* of a type. A tuple defines an
+*order* of the fields additionally. Tuples are meant for heterogenous storage
+types with no overhead and few abstraction possibilities. The constructor ``()`` 
+can be used to construct tuples. The order of the fields in the constructor 
+must match the order of the tuple's definition. Different tuple-types are 
+*equivalent* if they specify the same fields of the same type in the same 
+order. 
+
+The assignment operator for tuples copies each component. 
+The default assignment operator for objects is not defined. The programmer may 
+provide one, however. 
+
+.. code-block:: nimrod
+
+  type
+    TPerson = tuple[name: string, age: int] # type representing a person
+                                            # a person consists of a name
+                                            # and an age
+  var
+    person: TPerson
+  person = (name: "Peter", age: 30) 
+  # the same, but less readable:
+  person = ("Peter", 30)
+
+The implementation aligns the fields for best access performance. The alignment
+is done in a way that is compatible the way the C compiler does it.
+
+Objects provide many features that tuples do not. Object provide inheritance
+and information hiding. Objects have access to their type at runtime, so that 
+the ``is`` operator can be used to determine the object's type. 
+
+.. code-block:: nimrod
+
+  type
+    TPerson = object
+      name*: string   # the * means that `name` is accessible from the outside
+      age: int        # no * means that the field is hidden
+
+    TStudent = object of TPerson # a student is a person
+      id: int                    # with an id field
+
+  var
+    student: TStudent
+    person: TPerson
+  assert(student is TStudent) # is true
+
+Object fields that should be visible outside from the defining module, have to
+marked by ``*``. In contrast to tuples, different object types are 
+never *equivalent*.
+
+
+Set type
+~~~~~~~~
+The `set type`:idx: models the mathematical notion of a set. The set's
+basetype can only be an ordinal type. The reason is that sets are implemented
+as bit vectors. Sets are designed for high performance computing.
+
+Note: The sets module can be used for sets of other types.
+
+Sets can be constructed via the set constructor: ``{}`` is the empty set. The
+empty set is type combatible with any special set type. The constructor
+can also be used to include elements (and ranges of elements) in the set:
+
+.. code-block:: nimrod
+
+  {'a'..'z', '0'..'9'} # This constructs a set that conains the
+                       # letters from 'a' to 'z' and the digits
+                       # from '0' to '9'
+
+These operations are supported by sets:
+
+==================    ========================================================
+operation             meaning
+==================    ========================================================
+``A + B``             union of two sets
+``A * B``             intersection of two sets
+``A - B``             difference of two sets (A without B's elements)
+``A == B``            set equality
+``A <= B``            subset relation (A is subset of B or equal to B)
+``A < B``             strong subset relation (A is a real subset of B)
+``e in A``            set membership (A contains element e)
+``A -+- B``           symmetric set difference (= (A - B) + (B - A))
+``card(A)``           the cardinality of A (number of elements in A)
+``incl(A, elem)``     same as A = A + {elem}, but may be faster
+``excl(A, elem)``     same as A = A - {elem}, but may be faster
+==================    ========================================================
+
+Reference type
+~~~~~~~~~~~~~~
+References (similiar to `pointers`:idx: in other programming languages) are a
+way to introduce many-to-one relationships. This means different references can
+point to and modify the same location in memory. References should be used
+sparingly in a program. They are only needed for constructing graphs.
+
+Nimrod distinguishes between `traced`:idx: and `untraced`:idx: references.
+Untraced references are also called *pointers*. The difference between them is
+that traced references are garbage collected, untraced are not. Thus untraced
+references are *unsafe*. However for certain low-level operations (accessing
+the hardware) untraced references are unavoidable.
+
+Traced references are declared with the **ref** keyword, untraced references
+are declared with the **ptr** keyword.
+
+The ``^`` operator can be used to derefer a reference, the ``addr`` procedure
+returns the address of an item. An address is always an untraced reference.
+Thus the usage of ``addr`` is an *unsafe* feature.
+
+The ``.`` (access a tuple/object field operator) 
+and ``[]`` (array/string/sequence index operator) operators perform implicit
+dereferencing operations for reference types:
+
+.. code-block:: nimrod
+
+  type
+    PNode = ref TNode
+    TNode = object
+      le, ri: PNode
+      data: int
+
+  var
+    n: PNode
+  new(n)
+  n.data = 9 # no need to write n^.data
+
+To allocate a new traced object, the built-in procedure ``new`` has to be used.
+To deal with untraced memory, the procedures ``alloc``, ``dealloc`` and
+``realloc`` can be used. The documentation of the system module contains
+further information.
+
+Special care has to be taken if an untraced object contains traced objects like
+traced references, strings or sequences: In order to free everything properly,
+the built-in procedure ``finalize`` has to be called before freeing the
+untraced memory manually!
+
+.. XXX finalizers for traced objects
+
+Procedural type
+~~~~~~~~~~~~~~~
+A `procedural type`:idx: is internally a pointer to procedure. ``nil`` is
+an allowed value for variables of a procedural type. Nimrod uses procedural
+types to achieve `functional`:idx: programming techniques. Dynamic dispatch
+for OOP constructs can also be implemented with procedural types.
+
+Example:
+
+.. code-block:: nimrod
+
+  type
+    TCallback = proc (x: int) {.cdecl.}
+
+  proc printItem(x: Int) = ...
+
+  proc forEach(c: TCallback) =
+    ...
+
+  forEach(printItem)  # this will NOT work because calling conventions differ
+
+A subtle issue with procedural types is that the calling convention of the
+procedure influences the type compability: Procedural types are only compatible
+if they have the same calling convention.
+
+Nimrod supports these `calling conventions`:idx:, which are all incompatible to
+each other:
+
+`stdcall`:idx:
+    This the stdcall convention as specified by Microsoft. The generated C
+    procedure is declared with the ``__stdcall`` keyword.
+
+`cdecl`:idx:
+    The cdecl convention means that a procedure shall use the same convention
+    as the C compiler. Under windows the generated C procedure is declared with
+    the ``__cdecl`` keyword.
+
+`safecall`:idx:
+    This is the safecall convention as specified by Microsoft. The generated C
+    procedure is declared with the ``__safecall`` keyword. The word *safe*
+    refers to the fact that all hardware registers shall be pushed to the
+    hardware stack.
+
+`inline`:idx:
+    The inline convention means the the caller should not call the procedure,
+    but inline its code directly. Note that Nimrod does not inline, but leaves
+    this to the C compiler. Thus it generates ``__inline`` procedures. This is
+    only a hint for the compiler: It may completely ignore it and
+    it may inline procedures that are not marked as ``inline``.
+
+`fastcall`:idx:
+    Fastcall means different things to different C compilers. One gets whatever
+    the C ``__fastcall`` means.
+
+`nimcall`:idx:
+    Nimcall is the default convention used for Nimrod procedures. It is the
+    same as ``fastcall``, but only for C compilers that support ``fastcall``.
+
+`closure`:idx:
+    indicates that the procedure expects a context, a closure that needs
+    to be passed to the procedure. The implementation is the
+    same as ``cdecl``, but with a hidden pointer parameter (the
+    *closure*). The hidden parameter is always the last one.
+
+`syscall`:idx:
+    The syscall convention is the same as ``__syscall`` in C. It is used for
+    interrupts.
+
+`noconv`:idx:
+    The generated C code will not have any explicit calling convention and thus
+    use the C compiler's default calling convention. This is needed because
+    Nimrod's default calling convention for procedures is ``fastcall`` to
+    improve speed. This is unlikely to be needed by the user.
+
+Most calling conventions exist only for the Windows 32-bit platform.
+
+
+
+Statements
+----------
+Nimrod uses the common statement/expression paradigma: `Statements`:idx: do not
+produce a value in contrast to expressions. Call expressions are statements.
+If the called procedure returns a value, it is not a valid statement
+as statements do not produce values. To evaluate an expression for
+side-effects and throwing its value away, one can use the ``discard``
+statement.
+
+Statements are separated into `simple statements`:idx: and
+`complex statements`:idx:.
+Simple statements are statements that cannot contain other statements, like
+assignments, calls or the ``return`` statement; complex statements can
+contain other statements. To avoid the `dangling else problem`:idx:, complex
+statements always have to be intended::
+
+  simpleStmt ::= returnStmt
+             | yieldStmt
+             | discardStmt
+             | raiseStmt
+             | breakStmt
+             | continueStmt
+             | pragma
+             | importStmt
+             | fromStmt
+             | includeStmt
+             | exprStmt
+  complexStmt ::= ifStmt | whileStmt | caseStmt | tryStmt | forStmt
+                   | blockStmt | asmStmt
+                   | procDecl | iteratorDecl | macroDecl | templateDecl
+                   | constDecl | typeDecl | whenStmt | varStmt
+
+
+
+Discard statement
+~~~~~~~~~~~~~~~~~
+
+Syntax::
+
+  discardStmt ::= DISCARD expr
+
+Example:
+
+.. code-block:: nimrod
+
+  discard proc_call("arg1", "arg2") # discard the return value of `proc_call`
+
+The `discard`:idx: statement evaluates its expression for side-effects and
+throws the expression's resulting value away. If the expression has no
+side-effects, this generates a static error. Ignoring the return value of a
+procedure without using a discard statement is not allowed.
+
+
+Var statement
+~~~~~~~~~~~~~
+
+Syntax::
+
+  colonOrEquals ::= COLON typeDesc [EQUALS expr] | EQUALS expr
+  varPart ::= (symbol ["*" | "-"] [pragma] optComma)+ colonOrEquals [COMMENT]
+  varStmt ::= VAR (varPart | indPush varPart (SAD varPart)* DED)
+
+`Var`:idx: statements declare new local and global variables and
+initialize them. A comma seperated list of variables can be used to specify
+variables of the same type:
+
+.. code-block:: nimrod
+
+  var
+    a: int = 0
+    x, y, z: int
+
+If an initializer is given the type can be omitted: The variable is of the
+same type as the initializing expression. Variables are always initialized
+with a default value if there is no initializing expression. The default
+value depends on the type and is always a zero in binary.
+
+============================    ==============================================
+Type                            default value
+============================    ==============================================
+any integer type                0
+any float                       0.0
+char                            '\0'
+bool                            false
+ref or pointer type             nil
+procedural type                 nil
+sequence                        nil
+string                          nil (**not** "")
+tuple[x: A, y: B, ...]          (default(A), default(B), ...)
+                                (analogous for objects)
+array[0..., T]                  [default(T), ...]
+range[T]                        default(T); this may be out of the valid range
+T = enum                        cast[T](0); this may be an invalid value
+============================    ==============================================
+
+
+Const section
+~~~~~~~~~~~~~
+
+Syntax::
+
+  colonAndEquals ::= [COLON typeDesc] EQUALS expr
+  constDecl ::= CONST
+           indPush
+                symbol ["*"] [pragma] colonAndEquals
+           (SAD symbol ["*"] [pragma] colonAndEquals)*
+           DED
+
+Example:
+
+.. code-block:: nimrod
+
+  const
+    MyFilename = "/home/my/file.txt"
+    debugMode: bool = false
+
+The `const`:idx: section declares symbolic constants. A symbolic constant is
+a name for a constant expression. Symbolic constants only allow read-access.
+
+
+If statement
+~~~~~~~~~~~~
+
+Syntax::
+
+  ifStmt ::= IF expr COLON stmt (ELIF expr COLON stmt)* [ELSE COLON stmt]
+
+Example:
+
+.. code-block:: nimrod
+
+  var name = readLine(stdin)
+
+  if name == "Andreas":
+    echo("What a nice name!")
+  elif name == "":
+    echo("Don't you have a name?")
+  else:
+    echo("Boring name...")
+
+The `if`:idx: statement is a simple way to make a branch in the control flow:
+The expression after the keyword ``if`` is evaluated, if it is true
+the corresponding statements after the ``:`` are executed. Otherwise
+the expression after the ``elif`` is evaluated (if there is an
+``elif`` branch), if it is true the corresponding statements after
+the ``:`` are executed. This goes on until the last ``elif``. If all
+conditions fail, the ``else`` part is executed. If there is no ``else``
+part, execution continues with the statement after the ``if`` statement.
+
+
+Case statement
+~~~~~~~~~~~~~~
+
+Syntax::
+
+  caseStmt ::= CASE expr (OF sliceList COLON stmt)*
+                         (ELIF expr COLON stmt)*
+                         [ELSE COLON stmt]
+
+Example:
+
+.. code-block:: nimrod
+
+  case readline(stdin)
+  of "delete-everything", "restart-computer":
+    echo("permission denied")
+  of "go-for-a-walk":     echo("please yourself")
+  else:                   echo("unknown command")
+
+The `case`:idx: statement is similar to the if statement, but it represents
+a multi-branch selection. The expression after the keyword ``case`` is
+evaluated and if its value is in a *vallist* the corresponding statements
+(after the ``of`` keyword) are executed. If the value is no given *vallist*
+the ``else`` part is executed. If there is no ``else`` part and not all
+possible values that ``expr`` can hold occur in a ``vallist``, a static
+error is given. This holds only for expressions of ordinal types.
+If the expression is not of an ordinal type, and no ``else`` part is
+given, control just passes after the ``case`` statement.
+
+To suppress the static error in the ordinal case the programmer needs
+to write an ``else`` part with a ``nil`` statement.
+
+
+When statement
+~~~~~~~~~~~~~~
+
+Syntax::
+
+  whenStmt ::= WHEN expr COLON stmt (ELIF expr COLON stmt)* [ELSE COLON stmt]
+
+Example:
+
+.. code-block:: nimrod
+
+  when sizeof(int) == 2:
+    echo("running on a 16 bit system!")
+  elif sizeof(int) == 4:
+    echo("running on a 32 bit system!")
+  elif sizeof(int) == 8:
+    echo("running on a 64 bit system!")
+  else:
+    echo("cannot happen!")
+
+The `when`:idx: statement is almost identical to the ``if`` statement with some
+exceptions:
+
+* Each ``expr`` has to be a constant expression (of type ``bool``).
+* The statements do not open a new scope if they introduce new identifiers.
+* The statements that belong to the expression that evaluated to true are
+  translated by the compiler, the other statements are not checked for
+  syntax or semantics at all! This holds also for any ``expr`` coming
+  after the expression that evaluated to true.
+
+The ``when`` statement enables conditional compilation techniques. As
+a special syntatic extension, the ``when`` construct is also available
+within ``object`` definitions.
+
+
+Raise statement
+~~~~~~~~~~~~~~~
+
+Syntax::
+
+  raiseStmt ::= RAISE [expr]
+
+Example:
+
+.. code-block:: nimrod
+  raise EOS("operating system failed")
+
+Apart from built-in operations like array indexing, memory allocation, etc.
+the ``raise`` statement is the only way to raise an exception. The
+identifier has to be the name of a previously declared exception. A
+comma followed by an expression may follow; the expression must be of type
+``string`` or ``cstring``; this is an error message that can be extracted
+with the `getCurrentExceptionMsg`:idx: procedure in the module ``system``.
+
+If no exception name is given, the current exception is `re-raised`:idx:. The
+`ENoExceptionToReraise`:idx: exception is raised if there is no exception to
+re-raise. It follows that the ``raise`` statement *always* raises an
+exception.
+
+
+Try statement
+~~~~~~~~~~~~~
+
+Syntax::
+
+  exceptList ::= (qualifiedIdent optComma)*
+  tryStmt ::= TRY COLON stmt
+             (EXCEPT exceptList COLON stmt)*
+             [FINALLY COLON stmt]
+
+Example:
+
+.. code-block:: nimrod
+  # read the first two lines of a text file that should contain numbers
+  # and tries to add them
+  var
+    f: TFile
+  if openFile(f, "numbers.txt"):
+    try:
+      var a = readLine(f)
+      var b = readLine(f)
+      echo("sum: " & $(parseInt(a) + parseInt(b)))
+    except EOverflow:
+      echo("overflow!")
+    except EInvalidValue:
+      echo("could not convert string to integer")
+    except EIO:
+      echo("IO error!")
+    finally:
+      closeFile(f)
+
+The statements after the `try`:idx: are executed in sequential order unless
+an exception ``e`` is raised. If the exception type of ``e`` matches any
+of the list ``exceptlist`` the corresponding statements are executed.
+The statements following the ``except`` clauses are called
+`exception handlers`:idx:.
+
+The empty `except`:idx: clause is executed if there is an exception that is
+in no list. It is similiar to an ``else`` clause in ``if`` statements.
+
+If there is a `finally`:idx: clause, it is always executed after the
+exception handlers.
+
+The exception is *consumed* in an exception handler. However, an
+exception handler may raise another exception. If the exception is not
+handled, it is propagated through the call stack. This means that often
+the rest of the procedure - that is not within a ``finally`` clause -
+is not executed (if an exception occurs).
+
+
+Return statement
+~~~~~~~~~~~~~~~~
+
+Syntax::
+
+  returnStmt ::= RETURN [expr]
+
+Example:
+
+.. code-block:: nimrod
+  return 40+2
+
+The `return`:idx: statement ends the execution of the current procedure.
+It is only allowed in procedures. If there is an ``expr``, this is syntactic
+sugar for:
+
+.. code-block:: nimrod
+  result = expr
+  return
+
+The `result`:idx: variable is always the return value of the procedure. It is
+automatically declared by the compiler.
+
+
+Yield statement
+~~~~~~~~~~~~~~~
+
+Syntax::
+
+  yieldStmt ::= YIELD expr
+
+Example:
+
+.. code-block:: nimrod
+  yield (1, 2, 3)
+
+The `yield`:idx: statement is used instead of the ``return`` statement in
+iterators. It is only valid in iterators. Execution is returned to the body
+of the for loop that called the iterator. Yield does not end the iteration
+process, but execution is passed back to the iterator if the next iteration
+starts. See the section about iterators (`Iterators and the for statement`_)
+for further information.
+
+
+Block statement
+~~~~~~~~~~~~~~~
+
+Syntax::
+
+  blockStmt ::= BLOCK [symbol] COLON stmt
+
+Example:
+
+.. code-block:: nimrod
+  var found = false
+  block myblock:
+    for i in 0..3:
+      for j in 0..3:
+        if a[j][i] == 7:
+          found = true
+          break myblock # leave the block, in this case both for-loops
+  echo(found)
+
+The block statement is a means to group statements to a (named) `block`:idx:.
+Inside the block, the ``break`` statement is allowed to leave the block
+immediately. A ``break`` statement can contain a name of a surrounding
+block to specify which block is to leave.
+
+
+Break statement
+~~~~~~~~~~~~~~~
+
+Syntax::
+
+  breakStmt ::= BREAK [symbol]
+
+Example:
+
+.. code-block:: nimrod
+  break
+
+The `break`:idx: statement is used to leave a block immediately. If ``symbol``
+is given, it is the name of the enclosing block that is to leave. If it is
+absent, the innermost block is leaved.
+
+
+While statement
+~~~~~~~~~~~~~~~
+
+Syntax::
+
+  whileStmt ::= WHILE expr COLON stmt
+
+Example:
+
+.. code-block:: nimrod
+  echo("Please tell me your password: \n")
+  var pw = readLine(stdin)
+  while pw != "12345":
+    echo("Wrong password! Next try: \n")
+    pw = readLine(stdin)
+
+
+The `while`:idx: statement is executed until the ``expr`` evaluates to false.
+Endless loops are no error. ``while`` statements open an `implicit block`,
+so that they can be leaved with a ``break`` statement.
+
+
+Continue statement
+~~~~~~~~~~~~~~~~~~
+
+Syntax::
+
+  continueStmt ::= CONTINUE
+
+A `continue`:idx: statement leads to the immediate next iteration of the
+surrounding loop construct. It is only allowed within a loop. A continue
+statement is syntactic sugar for a nested block:
+
+.. code-block:: nimrod
+  while expr1:
+    stmt1
+    continue
+    stmt2
+
+  # is equivalent to:
+  while expr1:
+    block myBlockName:
+      stmt1
+      break myBlockName
+      stmt2
+
+
+Assembler statement
+~~~~~~~~~~~~~~~~~~~
+Syntax::
+
+  asmStmt ::= ASM [pragma] (STR_LIT | RSTR_LIT | TRIPLESTR_LIT)
+
+The direct embedding of `assembler`:idx: code into Nimrod code is supported
+by the unsafe ``asm`` statement. Identifiers in the assembler code that refer to
+Nimrod identifiers shall be enclosed in a special character which can be
+specified in the statement's pragmas. The default special character is ``'`'``.
+
+
+Procedures
+~~~~~~~~~~
+What most programming languages call `methods`:idx: or `funtions`:idx: are
+called `procedures`:idx: in Nimrod (which is the correct terminology). A
+procedure declaration defines an identifier and associates it with a block
+of code. A procedure may call itself recursively. The syntax is::
+
+  paramList ::= [PAR_LE ((symbol optComma)+ COLON typeDesc optComma)* PAR_RI]
+                [COLON typeDesc]
+  genericParams ::= BRACKET_LE (symbol [EQUALS typeDesc] )* BRACKET_RI
+
+  procDecl ::= PROC symbol ["*"] [genericParams] paramList [pragma]
+               [EQUALS stmt]
+
+If the ``EQUALS stms`` part is missing, it is a `forward`:idx: declaration. If
+the proc returns a value, the procedure body can access an implicit declared
+variable named `result`:idx: that represents the return value. Procs can be
+overloaded. The overloading resolution algorithm tries to find the proc that is
+the best match for the arguments. A parameter may be given a default value that
+is used if the caller does not provide a value for this parameter. Example:
+
+.. code-block:: nimrod
+
+  proc toLower(c: Char): Char = # toLower for characters
+    if c in {'A'..'Z'}:
+      result = chr(ord(c) + (ord('a') - ord('A')))
+    else:
+      result = c
+
+  proc toLower(s: string): string = # toLower for strings
+    result = newString(len(s))
+    for i in 0..len(s) - 1:
+      result[i] = toLower(s[i]) # calls toLower for characters; no recursion!
+
+`Operators`:idx: are procedures with a special operator symbol as identifier:
+
+.. code-block:: nimrod
+  proc `$` (x: int): string =     # converts an integer to a string;
+                                  # since it has one parameter this is a prefix
+                                  # operator. With two parameters it would be
+                                  # an infix operator.
+    return intToStr(x)
+
+Calling a procedure can be done in many different ways:
+
+.. code-block:: nimrod
+  proc callme(x, y: int, s: string = "", c: char, b: bool = false) = ...
+
+  # call with positional arguments# parameter bindings:
+  callme(0, 1, "abc", '\t', true) # (x=0, y=1, s="abc", c='\t', b=true)
+  # call with named and positional arguments:
+  callme(y=1, x=0, "abd", '\t')   # (x=0, y=1, s="abd", c='\t', b=false)
+  # call with named arguments (order is not relevant):
+  callme(c='\t', y=1, x=0)        # (x=0, y=1, s="", c='\t', b=false)
+  # call as a command statement: no () or , needed:
+  callme 0 1 "abc" '\t'
+
+
+Iterators and the for statement
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Syntax::
+
+  forStmt ::= FOR (symbol optComma)+ IN expr [DOTDOT expr] COLON stmt
+
+  paramList ::= [PAR_LE ((symbol optComma)+ COLON typeDesc optComma)* PAR_RI]
+                [COLON typeDesc]
+  genericParams ::= BRACKET_LE (symbol [EQUALS typeDesc] )* BRACKET_RI
+
+  iteratorDecl ::= ITERATOR symbol ["*"] [genericParams] paramList [pragma]
+               [EQUALS stmt]
+
+The `for`:idx: statement is an abstract mechanism to iterate over the elements
+of a container. It relies on an `iterator`:idx: to do so. Like ``while``
+statements, ``for`` statements open an `implicit block`:idx:, so that they
+can be leaved with a ``break`` statement. The ``for`` loop declares
+iteration variables (``x`` in the example) - their scope reaches until the
+end of the loop body. The iteration variables' types are inferred by the
+return type of the iterator.
+
+An iterator is similar to a procedure, except that it is always called in the
+context of a ``for`` loop. Iterators provide a way to specify the iteration over
+an abstract type. A key role in the execution of a ``for`` loop plays the
+``yield`` statement in the called iterator. Whenever a ``yield`` statement is
+reached the data is bound to the ``for`` loop variables and control continues
+in the body of the ``for`` loop. The iterator's local variables and execution
+state are automatically saved between calls. Example:
+
+.. code-block:: nimrod
+  # this definition exists in the system module
+  iterator items*(a: string): char {.inline.} =
+    var i = 0
+    while i < len(a):
+      yield a[i]
+      inc(i)
+
+  for ch in items("hello world"): # `ch` is an iteration variable
+    echo(ch)
+
+The compiler generates code as if the programmer would have written this:
+
+.. code-block:: nimrod
+  var i = 0
+  while i < len(a):
+    var ch = a[i]
+    echo(ch)
+    inc(i)
+
+The current implementation always inlines the iterator code leading to zero
+overhead for the abstraction. But this may increase the code size. Later
+versions of the compiler will only inline iterators which have the calling
+convention ``inline``.
+
+If the iterator yields a tuple, there have to be as many iteration variables
+as there are components in the tuple. The i'th iteration variable's type is
+the one of the i'th component.
+
+
+Type sections
+~~~~~~~~~~~~~
+
+Syntax::
+
+  typeDef ::= typeDesc | objectDef | enumDef
+  genericParams ::= BRACKET_LE (symbol [EQUALS typeDesc] )* BRACKET_RI
+
+  typeDecl ::= TYPE
+           indPush
+                symbol ["*"] [genericParams] [EQUALS typeDef]
+           (SAD symbol ["*"] [genericParams] [EQUALS typeDef])*
+           DED
+
+Example:
+
+.. code-block:: nimrod
+  type # example demonstrates mutually recursive types
+    PNode = ref TNode # a traced pointer to a TNode
+    TNode = object
+      le, ri: PNode   # left and right subtrees
+      sym: ref TSym   # leaves contain a reference to a TSym
+
+    TSym = object     # a symbol
+      name: string    # the symbol's name
+      line: int       # the line the symbol was declared in
+      code: PNode     # the symbol's abstract syntax tree
+
+A `type`:idx: section begins with the ``type`` keyword. It contains multiple
+type definitions. A type definition binds a type to a name. Type definitions
+can be recursive or even mutually recursive. Mutually Recursive types are only
+possible within a single ``type`` section.
+
+
+Generics
+~~~~~~~~
+
+Example:
+
+.. code-block:: nimrod
+  type
+    TBinaryTree[T] = object      # TBinaryTree is a generic type with
+                                 # with generic param ``T``
+      le, ri: ref TBinaryTree[T] # left and right subtrees; may be nil
+      data: T                    # the data stored in a node
+    PBinaryTree[T] = ref TBinaryTree[T] # a shorthand for notational convenience
+
+  proc newNode[T](data: T): PBinaryTree[T] = # constructor for a node
+    new(result)
+    result.dat = data
+
+  proc add[T](root: var PBinaryTree[T], n: PBinaryTree[T]) =
+    if root == nil:
+      root = n
+    else:
+      var it = root
+      while it != nil:
+        var c = cmp(it.data, n.data) # compare the data items; uses
+                                     # the generic ``cmd`` proc that works for
+                                     # any type that has a ``==`` and ``<``
+                                     # operator
+        if c < 0:
+          if it.le == nil:
+            it.le = n
+            return
+          it = it.le
+        else:
+          if it.ri == nil:
+            it.ri = n
+            return
+          it = it.ri
+
+  iterator inorder[T](root: PBinaryTree[T]): T =
+    # inorder traversal of a binary tree
+    # recursive iterators are not yet implemented, so this does not work in
+    # the current compiler!
+    if root.le != nil:
+      yield inorder(root.le)
+    yield root.data
+    if root.ri != nil:
+      yield inorder(root.ri)
+
+  var
+    root: PBinaryTree[string] # instantiate a PBinaryTree with the type string
+  add(root, newNode("hallo")) # instantiates generic procs ``newNode`` and
+  add(root, newNode("world")) # ``add``
+  for str in inorder(root):
+    writeln(stdout, str)
+
+`Generics`:idx: are Nimrod's means to parametrize procs, iterators or types with
+`type parameters`:idx:. Depending on context, the brackets are used either to
+introduce type parameters or to instantiate a generic proc, iterator or type.
+
+
+Templates
+~~~~~~~~~
+
+A `template`:idx: is a simple form of a macro. It operates on parse trees and is
+processed in the semantic pass of the compiler. So they integrate well with the
+rest of the language and share none of C's preprocessor macros flaws. However,
+they may lead to code that is harder to understand and maintain. So one ought
+to use them sparingly. The usage of ordinary procs, iterators or generics is
+preferred to the usage of templates.
+
+Example:
+
+.. code-block:: nimrod
+  template `!=` (a, b: expr): expr =
+    # this definition exists in the System module
+    not (a == b)
+
+  writeln(5 != 6) # the compiler rewrites that to: writeln(not (5 == 6))
+
+
+Macros
+~~~~~~
+
+`Macros`:idx: are the most powerful feature of Nimrod. They should be used
+only to implement `domain specific languages`:idx:. They may lead to code
+that is harder to understand and maintain. So one ought to use them sparingly.
+The usage of ordinary procs, iterators or generics is preferred to the usage of
+macros.
+
+
+Modules
+-------
+Nimrod supports splitting a program into pieces by a `module`:idx: concept.
+Modules make separate compilation possible. Each module needs to be in its
+own file. Modules enable `information hiding`:idx: and
+`separate compilation`:idx:. A module may gain access to symbols of another
+module by the `import`:idx: statement. `Recursive module dependancies`:idx: are
+allowed, but slightly subtle. Only top-level symbols that are marked with an
+asterisk (``*``) are exported. 
+
+The algorithm for compiling modules is:
+
+- Compile the whole module as usual, following import statements recursively
+- if we have a cycle only import the already parsed symbols (that are
+  exported); if an unknown identifier occurs then abort
+
+This is best illustrated by an example:
+
+.. code-block:: nimrod
+  # Module A
+  type
+    T1* = int
+  import B # the compiler starts parsing B
+
+  proc main() =
+    var i = p(3) # works because B has been parsed completely here
+
+  main()
+
+
+  # Module B
+  import A  # A is not parsed here! Only the already known symbols
+            # of A are imported here.
+
+  proc p*(x: A.T1): A.T1 # this works because the compiler has already
+                         # added T1 to A's interface symbol table
+
+  proc p(x: A.T1): A.T1 = return x + 1
+
+
+Scope rules
+-----------
+Identifiers are valid from the point of their declaration until the end of
+the block in which the declaration occurred. The range where the identifier
+is known is the `scope`:idx: of the identifier. The exact scope of an
+identifier depends on the way it was declared.
+
+Block scope
+~~~~~~~~~~~
+The *scope* of a variable declared in the declaration part of a block
+is valid from the point of declaration until the end of the block. If a
+block contains a second block, in which the identifier is redeclared,
+then inside this block, the second declaration will be valid. Upon
+leaving the inner block, the first declaration is valid again. An
+identifier cannot be redefined in the same block, except if valid for
+procedure or iterator overloading purposes.
+
+
+Tuple or object scope
+~~~~~~~~~~~~~~~~~~~~~~
+The field identifiers inside a tuple or object definition are valid in the
+following places:
+
+* To the end of the tuple/object definition
+* Field designators of a variable of the given tuple/object type.
+* In all descendent types of the object type.
+
+Module scope
+~~~~~~~~~~~~
+All identifiers in the interface part of a module are valid from the point of
+declaration, until the end of the module. Furthermore, the identifiers are
+known in other modules that import the module. Identifiers from indirectly
+dependent modules are *not* available. The `system`:idx: module is automatically
+imported in all other modules.
+
+If a module imports an identifier by two different modules,
+each occurance of the identifier has to be qualified, unless it is an
+overloaded procedure or iterator in which case the overloading
+resolution takes place:
+
+.. code-block:: nimrod
+  # Module A
+  var x*: string
+
+  # Module B
+  var x*: int
+
+  # Module C
+  import A, B
+  write(stdout, x) # error: x is ambigious
+  write(sdtout, A.x) # no error: qualifier used
+
+  var x = 4
+  write(stdout, x) # not ambigious: uses the module C's x
+
+
+Messages
+========
+
+The Nimrod compiler emits different kinds of messages: `hint`:idx:,
+`warning`:idx:, and `error`:idx: messages. An *error* message is emitted if
+the compiler encounters any static error.
+
+Pragmas
+=======
+
+Syntax::
+
+  pragma ::= CURLYDOT_LE (expr [COLON expr] optComma)+ (CURLYDOT_RI | CURLY_RI)
+
+Pragmas are Nimrod's method to give the compiler additional information/
+commands without introducing a massive number of new keywords. Pragmas are
+processed on the fly during parsing. Pragmas are always enclosed in the
+special ``{.`` and ``.}`` curly brackets.
+
+
+define pragma
+-------------
+The `define`:idx: pragma defines a conditional symbol. This symbol may only be
+used in other pragmas and in the ``defined`` expression and not in ordinary
+Nimrod source code. The conditional symbols go into a special symbol table.
+The compiler defines the target processor and the target operating
+system as conditional symbols.
+
+
+undef pragma
+------------
+The `undef`:idx: pragma the counterpart to the define pragma. It undefines a
+conditional symbol.
+
+
+error pragma
+------------
+The `error`:idx: pragma is used to make the compiler output an error message
+with the given content. Compilation currently aborts after an error, but this
+may be changed in later versions.
+
+
+fatal pragma
+------------
+The `fatal`:idx: pragma is used to make the compiler output an error message
+with the given content. In contrast to the ``error`` pragma, compilation
+is guaranteed to be aborted by this pragma.
+
+warning pragma
+--------------
+The `warning`:idx: pragma is used to make the compiler output a warning message
+with the given content. Compilation continues after the warning.
+
+hint pragma
+-----------
+The `hint`:idx: pragma is used to make the compiler output a hint message with
+the given content. Compilation continues after the hint.
+
+
+compilation option pragmas
+--------------------------
+The listed pragmas here can be used to override the code generation options
+for a section of code.
+::
+
+  "{." pragma: val {pragma: val} ".}"
+
+
+The implementation currently provides the following possible options (later
+various others may be added).
+
+===============  ===============  ============================================
+pragma           allowed values   description
+===============  ===============  ============================================
+checks           on|off           Turns the code generation for all runtime
+                                  checks on or off.
+bound_checks     on|off           Turns the code generation for array bound
+                                  checks on or off.
+overflow_checks  on|off           Turns the code generation for over- or
+                                  underflow checks on or off.
+nil_checks       on|off           Turns the code generation for nil pointer
+                                  checks on or off.
+assertions       on|off           Turns the code generation for assertions
+                                  on or off.
+warnings         on|off           Turns the warning messages of the compiler
+                                  on or off.
+hints            on|off           Turns the hint messages of the compiler
+                                  on or off.
+optimization     none|speed|size  Optimize the code for speed or size, or
+                                  disable optimization. For non-optimizing
+                                  compilers this option has no effect.
+                                  Neverless they must parse it properly.
+callconv         cdecl|...        Specifies the default calling convention for
+                                  all procedures (and procedure types) that
+                                  follow.
+===============  ===============  ============================================
+
+Example:
+
+.. code-block:: nimrod
+  {.checks: off, optimization: speed.}
+  # compile without runtime checks and optimize for speed
+
+
+push and pop pragmas
+--------------------
+The `push/pop`:idx: pragmas are very similar to the option directive,
+but are used to override the settings temporarily. Example:
+
+.. code-block:: nimrod
+  {.push checks: off.}
+  # compile this section without runtime checks as it is
+  # speed critical
+  # ... some code ...
+  {.pop.} # restore old settings
diff --git a/doc/nimrodc.txt b/doc/nimrodc.txt
index 72e2d205f..e49dfacb6 100644
--- a/doc/nimrodc.txt
+++ b/doc/nimrodc.txt
@@ -86,8 +86,8 @@ the C code. Thus it makes the following possible, for example:
 
 .. code-block:: Nimrod
   var
-    EOF {.import: "EOF", no_decl.}: cint # pretend EOF was a variable, as
-                                         # Nimrod does not know its value
+    EOF {.importc: "EOF", no_decl.}: cint # pretend EOF was a variable, as
+                                          # Nimrod does not know its value
 
 Varargs Pragma
 ~~~~~~~~~~~~~~
@@ -110,7 +110,7 @@ declared but also that it leads to the inclusion of a given header file:
 
 .. code-block:: Nimrod
   type
-    PFile {.import: "FILE*", header: "<stdio.h>".} = pointer
+    PFile {.importc: "FILE*", header: "<stdio.h>".} = pointer
       # import C's FILE* type; Nimrod will treat it as a new pointer type
 
 The ``header`` pragma expects always a string constant. The string contant
@@ -149,7 +149,7 @@ is raised.
 
 Debugger Option
 ~~~~~~~~~~~~~~~
-The `debugger`:idx: option enables or disables the *Embedded Nimrod Debugger*. 
+The `debugger`:idx: option enables or disables the *Embedded Nimrod Debugger*.
 See the documentation of endb_ for further information.
 
 
@@ -239,3 +239,28 @@ However it is not efficient to do:
 String case statements are optimized too. A hashing scheme is used for them
 if several different string constants are used. This is likely to be more
 efficient than any hand-coded scheme.
+
+
+The ECMAScript code generator
+=============================
+
+Note: I use the term `ECMAScript`:idx: here instead of `JavaScript`:idx:, since
+it is the proper term.
+
+Nimrod targets ECMAScript 1.5 which is supported by any widely used browser.
+Since ECMAScript does not have a portable means to include another module,
+Nimrod just generate a long ``.js`` file.
+
+Features or modules that the ECMAScript platform does not support are not
+available. This includes:
+
+* manual memory management (``alloc``, etc.)
+* casting and other unsafe operations (``cast`` operator, ``zeroMem``, etc.)
+* file management (``openfile``, etc.)
+* most modules of the Standard library
+* proper 64 bit integer arithmetic
+* proper unsigned integer arithmetic
+
+However, the modules `strutils`:idx:, `math`:idx:, and `times`:idx: are
+available! To access the DOM, use the `dom`:idx: module that is only available
+for the ECMAScript platform.
diff --git a/doc/posix.txt b/doc/posix.txt
deleted file mode 100644
index e71b08f53..000000000
--- a/doc/posix.txt
+++ /dev/null
@@ -1,220 +0,0 @@
-Function	POSIX Description

-access   	Tests for file accessibility

-alarm 	        Schedules an alarm

-asctime 	Converts a time structure to a string

-cfgetispeed 	Reads terminal input baud rate

-cfgetospeed 	Reads terminal output baud rate

-cfsetispeed 	Sets terminal input baud rate

-cfsetospeed 	Sets terminal output baud rate

-chdir 	        Changes current working directory

-chmod 	        Changes file mode

-chown 	        Changes owner and/or group of a file

-close 	        Closes a file

-closedir 	Ends directory read operation

-creat 	        Creates a new file or rewrites an existing one

-ctermid 	Generates terminal pathname

-cuserid 	Gets user name

-dup 	        Duplicates an open file descriptor

-dup2 	        Duplicates an open file descriptor

-execl 	        Executes a file

-execle 	        Executes a file

-execlp 	        Executes a file

-execv 	        Executes a file

-execve 	        Executes a file

-execvp 	        Executes a file

-_exit 	        Terminates a process

-fcntl 	        Manipulates an open file descriptor

-fdopen 	        Opens a stream on a file descriptor

-fork 	        Creates a process

-fpathconf 	Gets configuration variable for an open file

-fstat 	        Gets file status

-getcwd 	        Gets current working directory

-getegid 	Gets effective group ID

-getenv 	        Gets environment variable

-geteuid 	Gets effective user ID

-getgid 	        Gets real group ID

-getgrgid 	Reads groups database based on group ID

-getgrnam 	Reads groups database based on group name

-getgroups 	Gets supplementary group IDs

-getlogin 	Gets user name

-getpgrp 	Gets process group ID

-getpid 	        Gets process ID

-getppid 	Gets parent process ID

-getpwnam 	Reads user database based on user name

-getpwuid 	Reads user database based on user ID

-getuid 	        Gets real user ID

-isatty 	        Determines if a file descriptor is associated with a terminal

-kill 	        Sends a kill signal to a process

-link 	        Creates a link to a file

-longjmp 	Restores the calling environment

-lseek 	        Repositions read/write file offset

-mkdir 	        Makes a directory

-mkfifo 	        Makes a FIFO special file

-open 	        Opens a file

-opendir 	Opens a directory

-pathconf 	Gets configuration variables for a path

-pause 	        Suspends a process execution

-pipe 	        Creates an interprocess channel

-read 	        Reads from a file

-readdir 	Reads a directory

-rename 	        Renames a file

-rewinddir 	Resets the readdir() pointer

-rmdir 	        Removes a directory

-setgid 	        Sets group ID

-setjmp 	        Saves the calling environment for use by longjmp()

-setlocale 	Sets or queries a program's locale

-setpgid 	Sets a process group ID for job control

-setuid 	        Sets the user ID

-sigaction 	Examines and changes signal action

-sigaddset 	Adds a signal to a signal set

-sigdelset 	Removes a signal to a signal set

-sigemptyset 	Creates an empty signal set

-sigfillset 	Creates a full set of signals

-sigismember 	Tests a signal for a selected member

-siglongjmp 	Goes to and restores signal mask

-sigpending 	Examines pending signals

-sigprocmask 	Examines and changes blocked signals

-sigsetjmp 	Saves state for siglongjmp()

-sigsuspend 	Waits for a signal

-sleep 	        Delays process execution

-stat 	        Gets information about a file

-sysconf 	Gets system configuration information

-tcdrain 	Waits for all output to be transmitted to the terminal

-tcflow 	        Suspends/restarts terminal output

-tcflush 	Discards terminal data

-tcgetattr 	Gets terminal attributes

-tcgetpgrp 	Gets foreground process group ID

-tcsendbreak 	Sends a break to a terminal

-tcsetattr 	Sets terminal attributes

-tcsetpgrp 	Sets foreground process group ID

-time 	        Determines the current calendar time

-times 	        Gets process times

-ttyname 	Determines a terminal pathname

-tzset 	        Sets the timezone from environment variables

-umask 	        Sets the file creation mask

-uname 	        Gets system name

-unlink 	        Removes a directory entry

-utime 	        Sets file access and modification times

-waitpid 	Waits for process termination

-write 	        Writes to a file

-

- 

-POSIX.1b function calls Function	POSIX Description

-aio_cancel 	        Tries to cancel an asynchronous operation

-aio_error 	        Retrieves the error status for an asynchronous operation

-aio_read 	        Asynchronously reads from a file

-aio_return 	        Retrieves the return status for an asynchronous operation

-aio_suspend 	        Waits for an asynchronous operation to complete

-aio_write 	        Asynchronously writes to a file

-clock_getres 	        Gets resolution of a POSIX.1b clock

-clock_gettime 	        Gets the time according to a particular POSIX.1b clock

-clock_settime 	        Sets the time according to a particular POSIX.1b clock

-fdatasync 	        Synchronizes at least the data part of a file with the underlying media

-fsync 	                Synchronizes a file with the underlying media

-kill, sigqueue 	        Sends signals to a process

-lio_listio 	        Performs a list of I/O operations, synchronously or asynchronously

-mlock 	                Locks a range of memory

-mlockall 	        Locks the entire memory space down

-mmap 	                Maps a shared memory object (or possibly another file) into process's address space

-mprotect 	        Changes memory protection on a mapped area

-mq_close 	        Terminates access to a POSIX.1b message queue

-mq_getattr 	        Gets POSIX.1b message queue attributes

-mq_notify 	        Registers a request to be notified when a message arrives on an empty message queue

-mq_open 	        Creates/accesses a POSIX.1b message queue

-mq_receive 	        Receives a message from a POSIX.1b message queue

-mq_send 	        Sends a message on a POSIX.1b message queue

-mq_setattr 	        Sets a subset of POSIX.1b message queue attributes

-msync 	                Makes a mapping consistent with the underlying object

-munlock 	        Unlocks a range of memory

-munlockall 	        Unlocks the entire address space

-munmap 	                Undo mapping established by mmap

-nanosleep 	        Pauses execution for a number of nanoseconds

-sched_get_priority_max 	Gets maximum priority value for a scheduler

-sched_get_priority_min 	Gets minimum priority value for a scheduler

-sched_getparam 	        Retrieves scheduling parameters for a particular process

-sched_getscheduler 	Retrieves scheduling algorithm for a particular purpose

-sched_rr_get_interval 	Gets the SCHED_RR interval for the named process

-sched_setparam 	        Sets scheduling parameters for a process

-sched_setscheduler 	Sets scheduling algorithm/parameters for a process

-sched_yield 	        Yields the processor

-sem_close 	        Terminates access to a POSIX.1b semaphore

-sem_destroy 	        De-initializes a POSIX.1b unnamed semaphore

-sem_getvalue 	        Gets the value of a POSIX.1b semaphore

-sem_open 	        Creates/accesses a POSIX.1b named semaphore

-sem_post 	        Posts (signal) a POSIX.1b named or unnamed semaphore

-sem_unlink 	        Destroys a POSIX.1b named semaphore

-sem_wait, sem_trywait 	Waits on a POSIX.1b named or unnamed semaphore

-shm_open 	        Creates/accesses a POSIX.1b shared memory object

-shm_unlink 	        Destroys a POSIX.1b shared memory object

-sigwaitinfosigtimedwait Synchronously awaits signal arrival; avoid calling handler

-timer_create 	        Creates a POSIX.1b timer based on a particular clock

-timer_delete 	        Deletes a POSIX.1b timer

-timer_gettime 	        Time remaining on a POSIX.1b timer before expiration

-timer_settime 	        Sets expiration time/interval for a POSIX.1b timer

-wait, waitpid 	        Retrieves status of a terminated process and clean up corpse

-

- 

-POSIX.1c function calls Function	POSIX Description

-pthread_atfork  	        Declares procedures to be called before and after a fork

-pthread_attr_destroy 	        Destroys a thread attribute object

-pthread_attr_getdetachstate 	Obtains the setting of the detached state of a thread

-pthread_attr_getinheritsched 	Obtains the setting of the scheduling inheritance of a thread

-pthread_attr_getschedparam 	Obtains the parameters associated with the scheduling policy attribute of a thread

-pthread_attr_getschedpolicy 	Obtains the setting of the scheduling policy of a thread

-pthread_attr_getscope 	        Obtains the setting of the scheduling scope of a thread

-pthread_attr_getstackaddr 	Obtains the stack address of a thread

-pthread_attr_getstacksize 	Obtains the stack size of a thread

-pthread_attr_init 	        Initializes a thread attribute object

-pthread_attr_setdetachstate 	Adjusts the detached state of a thread

-pthread_attr_setinheritsched 	Adjusts the scheduling inheritance of a thread

-pthread_attr_setschedparam 	Adjusts the parameters associated with the scheduling policy of a thread

-pthread_attr_setschedpolicy 	Adjusts the scheduling policy of a thread

-pthread_attr_setscope 	        Adjusts the scheduling scope of a thread

-pthread_attr_setstackaddr 	Adjusts the stack address of a thread

-pthread_attr_setstacksize 	Adjusts the stack size of a thread

-pthread_cancel 	                Cancels the specific thread

-pthread_cleanup_pop 	        Removes the routine from the top of a thread's cleanup stack, and if execute is nonzero, runs it

-pthread_cleanup_push 	        Places a routine on the top of a thread's cleanup stack

-pthread_condattr_destroy 	Destroys a condition variable attribute object

-pthread_condattr_getpshared 	Obtains the process-shared setting of a condition variable attribute object

-pthread_condattr_init 	        Initializes a condition variable attribute object

-pthread_condattr_setpshared 	Sets the process-shared attribute in a condition variable attribute object to either PTHREAD_PROCESS_SHARED or PTHREAD_PROCESS_PRIVATE

-pthread_cond_broadcast 	        Unblocks all threads that are waiting on a condition variable

-pthread_cond_destroy 	        Destroys a condition variable

-pthread_cond_init 	        Initializes a condition variable with the attributes specified in the specified condition variable attribute object

-pthread_cond_signal 	        Unblocks at least one thread waiting on a condition variable

-pthread_cond_timedwait 	        Automatically unlocks the specified mutex, and places the calling thread into a wait state

-pthread_cond_wait 	        Automatically unlocks the specified mutex, and places the calling thread into a wait state

-pthread_create 	                Creates a thread with the attributes specified in attr

-pthread_detach 	                Marks a threads internal data structures for deletion

-pthread_equal 	                Compares one thread handle to another thread handle

-pthread_exit 	                Terminates the calling thread

-pthread_getschedparam 	        Obtains both scheduling policy and scheduling parameters of an existing thread

-pthread_getspecific 	        Obtains the thread specific data value associated with the specific key in the calling thread

-pthread_join 	                Causes the calling thread to wait for the specific thread’s termination

-pthread_key_create 	        Generates a unique thread-specific key that's visible to all threads in a process

-pthread_key_delete 	        Deletes a thread specific key

-pthread_kill 	                Delivers a signal to the specified thread

-pthread_mutexattr_destroy 	Destroys a mutex attribute object

-pthread_mutexattr_getprioceiling 	Obtains the priority ceiling of a mutex attribute object

-pthread_mutexattr_getprotocol 	Obtains protocol of a mutex attribute object

-pthread_mutexattr_getpshared 	Obtains a process-shared setting of a mutex attribute object

-pthread_mutexattr_init 	        Initializes a mutex attribute object

-pthread_mutexattr_setprioceiling 	Sets the priority ceiling attribute of a mutex attribute object

-pthread_mutexattr_setprotocol 	Sets the protocol attribute of a mutex attribute object

-pthread_mutexattr_setpshared 	Sets the process-shared attribute of a mutex attribute object to either PTHREAD_PROCESS_SHARED or PTHREAD_PROCESS_PRIVATE

-pthread_mutex_destroy 	        Destroys a mutex

-pthread_mutex_init 	        Initializes a mutex with the attributes specified in the specified mutex attribute object

-pthread_mutex_lock 	        Locks an unlocked mutex

-pthread_mutex_trylock 	        Tries to lock a not tested

-pthread_mutex_unlock 	        Unlocks a mutex

-pthread_once 	                Ensures that init_routine will run just once regardless of how many threads in the process call it

-pthread_self 	                Obtains a thread handle of a calling thread

-pthread_setcancelstate 	        Sets a thread's cancelability state

-pthread_setcanceltype 	        Sets a thread's cancelability type

-pthread_setschedparam 	        Adjusts the scheduling policy and scheduling parameters of an existing thread

-pthread_setspecific 	        Sets the thread-specific data value associated with the specific key in the calling thread

-pthread_sigmask 	        Examines or changes the calling thread's signal mask

-pthread_testcancel 	        Requests that any pending cancellation request be delivered to the calling thread

-

- 

diff --git a/doc/readme.txt b/doc/readme.txt
index 02d7477d4..7f509bd39 100644
--- a/doc/readme.txt
+++ b/doc/readme.txt
@@ -4,8 +4,4 @@ Nimrod's documenation system
 

 This folder contains Nimrod's documentation. The documentation

 is written in a format called *reStructuredText*, a markup language that reads

-like ASCII and can be converted to HTML, Tex and other formats automatically!

-

-Unfortunately reStructuredText does not allow to colorize source code in the

-HTML page. Therefore a postprocessor runs over the generated HTML code, looking

-for Nimrod code fragments and colorizing them.

+like ASCII and can be converted to HTML automatically!

diff --git a/doc/regexprs.txt b/doc/regexprs.txt
index 572a39260..930352948 100644
--- a/doc/regexprs.txt
+++ b/doc/regexprs.txt
@@ -272,25 +272,3 @@ end of the subject string, whatever options are set.
 The difference between ``\Z`` and ``\z`` is that ``\Z`` matches before
 a newline that is the last character of the string as well as at the end
 of the string, whereas ``\z`` matches only at the end.
-
-.. 
-  Regular expressions in Nimrod itself!
-  -------------------------------------
-  
-  'a' -- matches the character a
-  'a'-'z'  -- range operator '-'
-  'A' | 'B' -- alternative operator |
-  * 'a' -- prefix * is needed
-  + 'a' -- prefix + is needed
-  ? 'a' -- prefix ? is needed
-  letter  -- character classes with real names!
-  letters
-  white
-  whites
-  any   -- any character
-  ()    -- are Nimrod syntax
-  ! 'a'-'z'
-  
-  -- concatentation via proc call:
-  
-  re('A' 'Z' word * )
diff --git a/doc/theindex.txt b/doc/theindex.txt
index c681f21ed..0c0e621e7 100644
--- a/doc/theindex.txt
+++ b/doc/theindex.txt
@@ -10,33 +10,34 @@ Index
      `system.html#235 <system.html#235>`_

 

    `$`:idx:

-     * `system.html#326 <system.html#326>`_

-     * `system.html#327 <system.html#327>`_

      * `system.html#328 <system.html#328>`_

      * `system.html#329 <system.html#329>`_

      * `system.html#330 <system.html#330>`_

      * `system.html#331 <system.html#331>`_

      * `system.html#332 <system.html#332>`_

+     * `system.html#333 <system.html#333>`_

+     * `system.html#334 <system.html#334>`_

      * `times.html#109 <times.html#109>`_

      * `times.html#110 <times.html#110>`_

 

    `%`:idx:

-     * `strutils.html#128 <strutils.html#128>`_

      * `strutils.html#129 <strutils.html#129>`_

+     * `strutils.html#130 <strutils.html#130>`_

+     * `strtabs.html#112 <strtabs.html#112>`_

 

    `%%`:idx:

-     * `system.html#318 <system.html#318>`_

-     * `system.html#319 <system.html#319>`_

+     * `system.html#320 <system.html#320>`_

+     * `system.html#321 <system.html#321>`_

 

    `&`:idx:

      * `system.html#245 <system.html#245>`_

      * `system.html#246 <system.html#246>`_

      * `system.html#247 <system.html#247>`_

      * `system.html#248 <system.html#248>`_

-     * `system.html#349 <system.html#349>`_

-     * `system.html#350 <system.html#350>`_

-     * `system.html#351 <system.html#351>`_

-     * `system.html#352 <system.html#352>`_

+     * `system.html#358 <system.html#358>`_

+     * `system.html#359 <system.html#359>`_

+     * `system.html#360 <system.html#360>`_

+     * `system.html#361 <system.html#361>`_

 

    `*`:idx:

      * `system.html#159 <system.html#159>`_

@@ -46,8 +47,8 @@ Index
      * `complex.html#107 <complex.html#107>`_

 

    `*%`:idx:

-     * `system.html#314 <system.html#314>`_

-     * `system.html#315 <system.html#315>`_

+     * `system.html#316 <system.html#316>`_

+     * `system.html#317 <system.html#317>`_

 

    `+`:idx:

      * `system.html#154 <system.html#154>`_

@@ -60,8 +61,8 @@ Index
      * `complex.html#103 <complex.html#103>`_

 

    `+%`:idx:

-     * `system.html#310 <system.html#310>`_

-     * `system.html#311 <system.html#311>`_

+     * `system.html#312 <system.html#312>`_

+     * `system.html#313 <system.html#313>`_

 

    `-`:idx:

      * `system.html#155 <system.html#155>`_

@@ -76,8 +77,8 @@ Index
      * `times.html#113 <times.html#113>`_

 

    `-%`:idx:

-     * `system.html#312 <system.html#312>`_

-     * `system.html#313 <system.html#313>`_

+     * `system.html#314 <system.html#314>`_

+     * `system.html#315 <system.html#315>`_

 

    `-+-`:idx:

      `system.html#210 <system.html#210>`_

@@ -88,8 +89,8 @@ Index
      * `complex.html#106 <complex.html#106>`_

 

    `/%`:idx:

-     * `system.html#316 <system.html#316>`_

-     * `system.html#317 <system.html#317>`_

+     * `system.html#318 <system.html#318>`_

+     * `system.html#319 <system.html#319>`_

 

    `/../`:idx:

      `os.html#121 <os.html#121>`_

@@ -108,8 +109,8 @@ Index
      * `system.html#234 <system.html#234>`_

 

    `<%`:idx:

-     * `system.html#322 <system.html#322>`_

-     * `system.html#323 <system.html#323>`_

+     * `system.html#324 <system.html#324>`_

+     * `system.html#325 <system.html#325>`_

 

    `<=`:idx:

      * `system.html#168 <system.html#168>`_

@@ -124,8 +125,8 @@ Index
      * `system.html#226 <system.html#226>`_

 

    `<=%`:idx:

-     * `system.html#320 <system.html#320>`_

-     * `system.html#321 <system.html#321>`_

+     * `system.html#322 <system.html#322>`_

+     * `system.html#323 <system.html#323>`_

 

    `==`:idx:

      * `system.html#167 <system.html#167>`_

@@ -140,30 +141,96 @@ Index
      * `system.html#217 <system.html#217>`_

      * `system.html#218 <system.html#218>`_

      * `system.html#219 <system.html#219>`_

-     * `system.html#353 <system.html#353>`_

+     * `system.html#363 <system.html#363>`_

      * `complex.html#102 <complex.html#102>`_

 

    `>`:idx:

      `system.html#237 <system.html#237>`_

 

    `>%`:idx:

-     `system.html#325 <system.html#325>`_

+     `system.html#327 <system.html#327>`_

 

    `>=`:idx:

      `system.html#236 <system.html#236>`_

 

    `>=%`:idx:

-     `system.html#324 <system.html#324>`_

+     `system.html#326 <system.html#326>`_

+

+   `[]`:idx:

+     `strtabs.html#107 <strtabs.html#107>`_

+

+   `[]=`:idx:

+     `strtabs.html#106 <strtabs.html#106>`_

 

    `[ESC]`:idx:

      `manual.html#134 <manual.html#134>`_

 

+   `ABDAY_1`:idx:

+     `posix.html#400 <posix.html#400>`_

+

+   `ABDAY_2`:idx:

+     `posix.html#401 <posix.html#401>`_

+

+   `ABDAY_3`:idx:

+     `posix.html#402 <posix.html#402>`_

+

+   `ABDAY_4`:idx:

+     `posix.html#403 <posix.html#403>`_

+

+   `ABDAY_5`:idx:

+     `posix.html#404 <posix.html#404>`_

+

+   `ABDAY_6`:idx:

+     `posix.html#405 <posix.html#405>`_

+

+   `ABDAY_7`:idx:

+     `posix.html#406 <posix.html#406>`_

+

+   `ABMON_1`:idx:

+     `posix.html#419 <posix.html#419>`_

+

+   `ABMON_10`:idx:

+     `posix.html#428 <posix.html#428>`_

+

+   `ABMON_11`:idx:

+     `posix.html#429 <posix.html#429>`_

+

+   `ABMON_12`:idx:

+     `posix.html#430 <posix.html#430>`_

+

+   `ABMON_2`:idx:

+     `posix.html#420 <posix.html#420>`_

+

+   `ABMON_3`:idx:

+     `posix.html#421 <posix.html#421>`_

+

+   `ABMON_4`:idx:

+     `posix.html#422 <posix.html#422>`_

+

+   `ABMON_5`:idx:

+     `posix.html#423 <posix.html#423>`_

+

+   `ABMON_6`:idx:

+     `posix.html#424 <posix.html#424>`_

+

+   `ABMON_7`:idx:

+     `posix.html#425 <posix.html#425>`_

+

+   `ABMON_8`:idx:

+     `posix.html#426 <posix.html#426>`_

+

+   `ABMON_9`:idx:

+     `posix.html#427 <posix.html#427>`_

+

    `abs`:idx:

      * `system.html#170 <system.html#170>`_

      * `system.html#189 <system.html#189>`_

      * `system.html#201 <system.html#201>`_

      * `complex.html#108 <complex.html#108>`_

 

+   `access`:idx:

+     `posix.html#959 <posix.html#959>`_

+

    `add`:idx:

      * `system.html#249 <system.html#249>`_

      * `system.html#250 <system.html#250>`_

@@ -174,11 +241,44 @@ Index
    `addQuitProc`:idx:

      `system.html#287 <system.html#287>`_

 

+   `AIO_ALLDONE`:idx:

+     `posix.html#204 <posix.html#204>`_

+

+   `aio_cancel`:idx:

+     `posix.html#778 <posix.html#778>`_

+

+   `AIO_CANCELED`:idx:

+     `posix.html#205 <posix.html#205>`_

+

+   `aio_error`:idx:

+     `posix.html#779 <posix.html#779>`_

+

+   `aio_fsync`:idx:

+     `posix.html#780 <posix.html#780>`_

+

+   `AIO_NOTCANCELED`:idx:

+     `posix.html#206 <posix.html#206>`_

+

+   `aio_read`:idx:

+     `posix.html#781 <posix.html#781>`_

+

+   `aio_return`:idx:

+     `posix.html#782 <posix.html#782>`_

+

+   `aio_suspend`:idx:

+     `posix.html#783 <posix.html#783>`_

+

+   `aio_write`:idx:

+     `posix.html#784 <posix.html#784>`_

+

+   `alarm`:idx:

+     `posix.html#960 <posix.html#960>`_

+

    `alert`:idx:

      `manual.html#131 <manual.html#131>`_

 

    `allCharsInSet`:idx:

-     `strutils.html#133 <strutils.html#133>`_

+     `strutils.html#134 <strutils.html#134>`_

 

    `alloc`:idx:

      `system.html#296 <system.html#296>`_

@@ -186,9 +286,15 @@ Index
    `alloc0`:idx:

      `system.html#297 <system.html#297>`_

 

+   `ALT_DIGITS`:idx:

+     `posix.html#435 <posix.html#435>`_

+

    `AltSep`:idx:

      `os.html#104 <os.html#104>`_

 

+   `AM_STR`:idx:

+     `posix.html#391 <posix.html#391>`_

+

    `and`:idx:

      * `system.html#164 <system.html#164>`_

      * `system.html#183 <system.html#183>`_

@@ -201,16 +307,16 @@ Index
      `os.html#127 <os.html#127>`_

 

    `arccos`:idx:

-     `math.html#110 <math.html#110>`_

+     `math.html#115 <math.html#115>`_

 

    `arcsin`:idx:

-     `math.html#111 <math.html#111>`_

+     `math.html#116 <math.html#116>`_

 

    `arctan`:idx:

-     `math.html#112 <math.html#112>`_

+     `math.html#117 <math.html#117>`_

 

    `arctan2`:idx:

-     `math.html#113 <math.html#113>`_

+     `math.html#118 <math.html#118>`_

 

    `array`:idx:

      `system.html#108 <system.html#108>`_

@@ -218,8 +324,14 @@ Index
    `Arrays`:idx:

      `manual.html#153 <manual.html#153>`_

 

+   `asctime`:idx:

+     `posix.html#1085 <posix.html#1085>`_

+

+   `asctime_r`:idx:

+     `posix.html#1086 <posix.html#1086>`_

+

    `assembler`:idx:

-     `manual.html#198 <manual.html#198>`_

+     `manual.html#197 <manual.html#197>`_

 

    `assert`:idx:

      `system.html#301 <system.html#301>`_

@@ -234,6 +346,9 @@ Index
    `backspace`:idx:

      `manual.html#132 <manual.html#132>`_

 

+   `basename`:idx:

+     `posix.html#838 <posix.html#838>`_

+

    `BiggestFloat`:idx:

      `system.html#257 <system.html#257>`_

 

@@ -241,25 +356,28 @@ Index
      `system.html#256 <system.html#256>`_

 

    `block`:idx:

-     `manual.html#194 <manual.html#194>`_

+     `manual.html#193 <manual.html#193>`_

 

    `boolean`:idx:

      `manual.html#147 <manual.html#147>`_

 

    `break`:idx:

-     `manual.html#195 <manual.html#195>`_

+     `manual.html#194 <manual.html#194>`_

 

    `breakpoint`:idx:

      `endb.html#103 <endb.html#103>`_

 

+   `bsd_signal`:idx:

+     `posix.html#1115 <posix.html#1115>`_

+

    `Byte`:idx:

-     `system.html#113 <system.html#113>`_

+     `system.html#112 <system.html#112>`_

 

    `C`:idx:

      `manual.html#136 <manual.html#136>`_

 

    `calling conventions`:idx:

-     `manual.html#164 <manual.html#164>`_

+     `manual.html#163 <manual.html#163>`_

 

    `capitalize`:idx:

      `strutils.html#110 <strutils.html#110>`_

@@ -271,13 +389,22 @@ Index
      `manual.html#122 <manual.html#122>`_

 

    `case`:idx:

-     `manual.html#182 <manual.html#182>`_

+     `manual.html#181 <manual.html#181>`_

+

+   `catclose`:idx:

+     `posix.html#1142 <posix.html#1142>`_

+

+   `catgets`:idx:

+     `posix.html#1143 <posix.html#1143>`_

+

+   `catopen`:idx:

+     `posix.html#1144 <posix.html#1144>`_

 

    `cchar`:idx:

      `system.html#258 <system.html#258>`_

 

    `cdecl`:idx:

-     `manual.html#166 <manual.html#166>`_

+     `manual.html#165 <manual.html#165>`_

 

    `cdouble`:idx:

      `system.html#265 <system.html#265>`_

@@ -297,17 +424,131 @@ Index
    `character with hex value HH`:idx:

      `manual.html#135 <manual.html#135>`_

 

+   `chdir`:idx:

+     `posix.html#961 <posix.html#961>`_

+

    `checked runtime error`:idx:

      `manual.html#110 <manual.html#110>`_

 

+   `chmod`:idx:

+     `posix.html#1051 <posix.html#1051>`_

+

+   `ChooseDir`:idx:

+     `dialogs.html#108 <dialogs.html#108>`_

+

+   `ChooseFilesToOpen`:idx:

+     `dialogs.html#106 <dialogs.html#106>`_

+

+   `ChooseFileToOpen`:idx:

+     `dialogs.html#105 <dialogs.html#105>`_

+

+   `ChooseFileToSave`:idx:

+     `dialogs.html#107 <dialogs.html#107>`_

+

+   `chown`:idx:

+     `posix.html#962 <posix.html#962>`_

+

    `chr`:idx:

      `system.html#153 <system.html#153>`_

 

    `cint`:idx:

      `system.html#261 <system.html#261>`_

 

+   `C_IRGRP`:idx:

+     `posix.html#104 <posix.html#104>`_

+

+   `C_IROTH`:idx:

+     `posix.html#107 <posix.html#107>`_

+

+   `C_IRUSR`:idx:

+     `posix.html#101 <posix.html#101>`_

+

+   `C_ISBLK`:idx:

+     `posix.html#116 <posix.html#116>`_

+

+   `C_ISCHR`:idx:

+     `posix.html#117 <posix.html#117>`_

+

+   `C_ISCTG`:idx:

+     `posix.html#118 <posix.html#118>`_

+

+   `C_ISDIR`:idx:

+     `posix.html#113 <posix.html#113>`_

+

+   `C_ISFIFO`:idx:

+     `posix.html#114 <posix.html#114>`_

+

+   `C_ISGID`:idx:

+     `posix.html#111 <posix.html#111>`_

+

+   `C_ISLNK`:idx:

+     `posix.html#119 <posix.html#119>`_

+

+   `C_ISREG`:idx:

+     `posix.html#115 <posix.html#115>`_

+

+   `C_ISSOCK`:idx:

+     `posix.html#120 <posix.html#120>`_

+

+   `C_ISUID`:idx:

+     `posix.html#110 <posix.html#110>`_

+

+   `C_ISVTX`:idx:

+     `posix.html#112 <posix.html#112>`_

+

+   `C_IWGRP`:idx:

+     `posix.html#105 <posix.html#105>`_

+

+   `C_IWOTH`:idx:

+     `posix.html#108 <posix.html#108>`_

+

+   `C_IWUSR`:idx:

+     `posix.html#102 <posix.html#102>`_

+

+   `C_IXGRP`:idx:

+     `posix.html#106 <posix.html#106>`_

+

+   `C_IXOTH`:idx:

+     `posix.html#109 <posix.html#109>`_

+

+   `C_IXUSR`:idx:

+     `posix.html#103 <posix.html#103>`_

+

    `classify`:idx:

-     `math.html#123 <math.html#123>`_

+     `math.html#102 <math.html#102>`_

+

+   `clock`:idx:

+     `posix.html#1087 <posix.html#1087>`_

+

+   `clock_getcpuclockid`:idx:

+     `posix.html#1088 <posix.html#1088>`_

+

+   `clock_getres`:idx:

+     `posix.html#1089 <posix.html#1089>`_

+

+   `clock_gettime`:idx:

+     `posix.html#1090 <posix.html#1090>`_

+

+   `CLOCK_MONOTONIC`:idx:

+     `posix.html#697 <posix.html#697>`_

+

+   `clock_nanosleep`:idx:

+     `posix.html#1091 <posix.html#1091>`_

+

+   `CLOCK_PROCESS_CPUTIME_ID`:idx:

+     `posix.html#693 <posix.html#693>`_

+

+   `CLOCK_REALTIME`:idx:

+     `posix.html#695 <posix.html#695>`_

+

+   `clock_settime`:idx:

+     `posix.html#1092 <posix.html#1092>`_

+

+   `CLOCKS_PER_SEC`:idx:

+     `posix.html#692 <posix.html#692>`_

+

+   `CLOCK_THREAD_CPUTIME_ID`:idx:

+     `posix.html#694 <posix.html#694>`_

 

    `clong`:idx:

      `system.html#262 <system.html#262>`_

@@ -318,11 +559,18 @@ Index
    `clonglong`:idx:

      `system.html#263 <system.html#263>`_

 

+   `close`:idx:

+     * `parsecfg.html#106 <parsecfg.html#106>`_

+     * `posix.html#963 <posix.html#963>`_

+

+   `closedir`:idx:

+     `posix.html#794 <posix.html#794>`_

+

    `CloseFile`:idx:

-     `system.html#367 <system.html#367>`_

+     `system.html#378 <system.html#378>`_

 

    `closure`:idx:

-     `manual.html#171 <manual.html#171>`_

+     `manual.html#170 <manual.html#170>`_

 

    `cmp`:idx:

      * `system.html#243 <system.html#243>`_

@@ -337,6 +585,9 @@ Index
    `cmpPaths`:idx:

      `os.html#126 <os.html#126>`_

 

+   `CODESET`:idx:

+     `posix.html#386 <posix.html#386>`_

+

    `comment pieces`:idx:

      `manual.html#115 <manual.html#115>`_

 

@@ -350,10 +601,13 @@ Index
      `system.html#276 <system.html#276>`_

 

    `complex statements`:idx:

-     `manual.html#176 <manual.html#176>`_

+     `manual.html#175 <manual.html#175>`_

+

+   `confstr`:idx:

+     `posix.html#964 <posix.html#964>`_

 

    `const`:idx:

-     `manual.html#180 <manual.html#180>`_

+     `manual.html#179 <manual.html#179>`_

 

    `constant expressions`:idx:

      `manual.html#108 <manual.html#108>`_

@@ -362,7 +616,7 @@ Index
      `manual.html#140 <manual.html#140>`_

 

    `continue`:idx:

-     `manual.html#197 <manual.html#197>`_

+     `manual.html#196 <manual.html#196>`_

 

    `copy`:idx:

      * `system.html#288 <system.html#288>`_

@@ -375,43 +629,130 @@ Index
      `system.html#293 <system.html#293>`_

 

    `cos`:idx:

-     `math.html#114 <math.html#114>`_

+     `math.html#119 <math.html#119>`_

 

    `cosh`:idx:

-     `math.html#115 <math.html#115>`_

+     `math.html#120 <math.html#120>`_

 

    `countBits`:idx:

-     `math.html#103 <math.html#103>`_

+     `math.html#105 <math.html#105>`_

 

    `countdown`:idx:

-     `system.html#341 <system.html#341>`_

+     `system.html#344 <system.html#344>`_

 

    `countup`:idx:

-     `system.html#342 <system.html#342>`_

+     `system.html#345 <system.html#345>`_

 

    `cpuEndian`:idx:

      `system.html#281 <system.html#281>`_

 

+   `creat`:idx:

+     `posix.html#805 <posix.html#805>`_

+

    `createDir`:idx:

      `os.html#135 <os.html#135>`_

 

+   `CRNCYSTR`:idx:

+     `posix.html#440 <posix.html#440>`_

+

+   `crypt`:idx:

+     `posix.html#965 <posix.html#965>`_

+

    `cschar`:idx:

      `system.html#259 <system.html#259>`_

 

    `cshort`:idx:

      `system.html#260 <system.html#260>`_

 

+   `cSIG_HOLD`:idx:

+     `posix.html#718 <posix.html#718>`_

+

+   `CS_PATH`:idx:

+     `posix.html#479 <posix.html#479>`_

+

+   `CS_POSIX_V6_ILP32_OFF32_CFLAGS`:idx:

+     `posix.html#480 <posix.html#480>`_

+

+   `CS_POSIX_V6_ILP32_OFF32_LDFLAGS`:idx:

+     `posix.html#481 <posix.html#481>`_

+

+   `CS_POSIX_V6_ILP32_OFF32_LIBS`:idx:

+     `posix.html#482 <posix.html#482>`_

+

+   `CS_POSIX_V6_ILP32_OFFBIG_CFLAGS`:idx:

+     `posix.html#483 <posix.html#483>`_

+

+   `CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS`:idx:

+     `posix.html#484 <posix.html#484>`_

+

+   `CS_POSIX_V6_ILP32_OFFBIG_LIBS`:idx:

+     `posix.html#485 <posix.html#485>`_

+

+   `CS_POSIX_V6_LP64_OFF64_CFLAGS`:idx:

+     `posix.html#486 <posix.html#486>`_

+

+   `CS_POSIX_V6_LP64_OFF64_LDFLAGS`:idx:

+     `posix.html#487 <posix.html#487>`_

+

+   `CS_POSIX_V6_LP64_OFF64_LIBS`:idx:

+     `posix.html#488 <posix.html#488>`_

+

+   `CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS`:idx:

+     `posix.html#489 <posix.html#489>`_

+

+   `CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS`:idx:

+     `posix.html#490 <posix.html#490>`_

+

+   `CS_POSIX_V6_LPBIG_OFFBIG_LIBS`:idx:

+     `posix.html#491 <posix.html#491>`_

+

+   `CS_POSIX_V6_WIDTH_RESTRICTED_ENVS`:idx:

+     `posix.html#492 <posix.html#492>`_

+

    `cstringArray`:idx:

      `system.html#267 <system.html#267>`_

 

+   `ctermid`:idx:

+     `posix.html#966 <posix.html#966>`_

+

+   `ctime`:idx:

+     `posix.html#1093 <posix.html#1093>`_

+

+   `ctime_r`:idx:

+     `posix.html#1094 <posix.html#1094>`_

+

    `CurDir`:idx:

      `os.html#101 <os.html#101>`_

 

    `dangling else problem`:idx:

-     `manual.html#177 <manual.html#177>`_

+     `manual.html#176 <manual.html#176>`_

+

+   `DAY_1`:idx:

+     `posix.html#393 <posix.html#393>`_

+

+   `DAY_2`:idx:

+     `posix.html#394 <posix.html#394>`_

+

+   `DAY_3`:idx:

+     `posix.html#395 <posix.html#395>`_

+

+   `DAY_4`:idx:

+     `posix.html#396 <posix.html#396>`_

+

+   `DAY_5`:idx:

+     `posix.html#397 <posix.html#397>`_

+

+   `DAY_6`:idx:

+     `posix.html#398 <posix.html#398>`_

+

+   `DAY_7`:idx:

+     `posix.html#399 <posix.html#399>`_

+

+   `daylight`:idx:

+     `posix.html#698 <posix.html#698>`_

 

    `dbgLineHook`:idx:

-     `system.html#337 <system.html#337>`_

+     `system.html#340 <system.html#340>`_

 

    `dealloc`:idx:

      `system.html#299 <system.html#299>`_

@@ -423,60 +764,185 @@ Index
      `system.html#144 <system.html#144>`_

 

    `define`:idx:

-     `manual.html#224 <manual.html#224>`_

+     `manual.html#223 <manual.html#223>`_

 

    `defined`:idx:

      `system.html#101 <system.html#101>`_

 

+   `deinitBaseLexer`:idx:

+     `lexbase.html#106 <lexbase.html#106>`_

+

    `deleteStr`:idx:

      `strutils.html#115 <strutils.html#115>`_

 

+   `D_FMT`:idx:

+     `posix.html#388 <posix.html#388>`_

+

+   `difftime`:idx:

+     `posix.html#1095 <posix.html#1095>`_

+

+   `dirname`:idx:

+     `posix.html#839 <posix.html#839>`_

+

    `DirSep`:idx:

      `os.html#103 <os.html#103>`_

 

    `discard`:idx:

-     `manual.html#178 <manual.html#178>`_

+     `manual.html#177 <manual.html#177>`_

 

    `div`:idx:

      * `system.html#160 <system.html#160>`_

      * `system.html#179 <system.html#179>`_

 

+   `dlclose`:idx:

+     `posix.html#801 <posix.html#801>`_

+

+   `dlerror`:idx:

+     `posix.html#802 <posix.html#802>`_

+

+   `dlopen`:idx:

+     `posix.html#803 <posix.html#803>`_

+

+   `dlsym`:idx:

+     `posix.html#804 <posix.html#804>`_

+

+   `dom`:idx:

+     `nimrodc.html#116 <nimrodc.html#116>`_

+

    `domain specific languages`:idx:

-     `manual.html#213 <manual.html#213>`_

+     `manual.html#212 <manual.html#212>`_

+

+   `D_T_FMT`:idx:

+     `posix.html#387 <posix.html#387>`_

+

+   `dup`:idx:

+     `posix.html#967 <posix.html#967>`_

+

+   `dup2`:idx:

+     `posix.html#968 <posix.html#968>`_

 

    `dynamic type`:idx:

      `manual.html#104 <manual.html#104>`_

 

+   `E2BIG`:idx:

+     `posix.html#217 <posix.html#217>`_

+

+   `EACCES`:idx:

+     `posix.html#218 <posix.html#218>`_

+

    `EAccessViolation`:idx:

-     `system.html#128 <system.html#128>`_

+     `system.html#127 <system.html#127>`_

+

+   `EADDRINUSE`:idx:

+     `posix.html#219 <posix.html#219>`_

+

+   `EADDRNOTAVAIL`:idx:

+     `posix.html#220 <posix.html#220>`_

+

+   `EAFNOSUPPORT`:idx:

+     `posix.html#221 <posix.html#221>`_

+

+   `EAGAIN`:idx:

+     `posix.html#222 <posix.html#222>`_

+

+   `EALREADY`:idx:

+     `posix.html#223 <posix.html#223>`_

 

    `EArithmetic`:idx:

-     `system.html#125 <system.html#125>`_

+     `system.html#124 <system.html#124>`_

 

    `EAssertionFailed`:idx:

-     `system.html#129 <system.html#129>`_

+     `system.html#128 <system.html#128>`_

 

    `EAsynch`:idx:

-     `system.html#119 <system.html#119>`_

+     `system.html#118 <system.html#118>`_

+

+   `EBADF`:idx:

+     `posix.html#224 <posix.html#224>`_

+

+   `EBADMSG`:idx:

+     `posix.html#225 <posix.html#225>`_

 

    `E_Base`:idx:

-     `system.html#118 <system.html#118>`_

+     `system.html#117 <system.html#117>`_

+

+   `EBUSY`:idx:

+     `posix.html#226 <posix.html#226>`_

+

+   `ECANCELED`:idx:

+     `posix.html#227 <posix.html#227>`_

+

+   `ECHILD`:idx:

+     `posix.html#228 <posix.html#228>`_

 

    `echo`:idx:

-     `system.html#380 <system.html#380>`_

+     `system.html#371 <system.html#371>`_

+

+   `ECMAScript`:idx:

+     `nimrodc.html#111 <nimrodc.html#111>`_

+

+   `ECONNABORTED`:idx:

+     `posix.html#229 <posix.html#229>`_

+

+   `ECONNREFUSED`:idx:

+     `posix.html#230 <posix.html#230>`_

+

+   `ECONNRESET`:idx:

+     `posix.html#231 <posix.html#231>`_

 

    `EControlC`:idx:

-     `system.html#130 <system.html#130>`_

+     `system.html#129 <system.html#129>`_

+

+   `EDEADLK`:idx:

+     `posix.html#232 <posix.html#232>`_

+

+   `EDESTADDRREQ`:idx:

+     `posix.html#233 <posix.html#233>`_

 

    `EDivByZero`:idx:

-     `system.html#126 <system.html#126>`_

+     `system.html#125 <system.html#125>`_

 

-   `EInvalidIndex`:idx:

+   `EDOM`:idx:

+     `posix.html#234 <posix.html#234>`_

+

+   `EDQUOT`:idx:

+     `posix.html#235 <posix.html#235>`_

+

+   `EEXIST`:idx:

+     `posix.html#236 <posix.html#236>`_

+

+   `EFAULT`:idx:

+     `posix.html#237 <posix.html#237>`_

+

+   `EFBIG`:idx:

+     `posix.html#238 <posix.html#238>`_

+

+   `EHOSTUNREACH`:idx:

+     `posix.html#239 <posix.html#239>`_

+

+   `EIDRM`:idx:

+     `posix.html#240 <posix.html#240>`_

+

+   `EILSEQ`:idx:

+     `posix.html#241 <posix.html#241>`_

+

+   `EINPROGRESS`:idx:

+     `posix.html#242 <posix.html#242>`_

+

+   `EINTR`:idx:

+     `posix.html#243 <posix.html#243>`_

+

+   `EINVAL`:idx:

+     `posix.html#244 <posix.html#244>`_

+

+   `EInvalidField`:idx:

      `system.html#133 <system.html#133>`_

 

+   `EInvalidIndex`:idx:

+     `system.html#132 <system.html#132>`_

+

    `EInvalidObjectAssignment`:idx:

-     * `manual.html#157 <manual.html#157>`_

-     * `system.html#137 <system.html#137>`_

+     `system.html#137 <system.html#137>`_

 

    `EInvalidObjectConversion`:idx:

      `system.html#138 <system.html#138>`_

@@ -486,51 +952,204 @@ Index
 

    `EInvalidValue`:idx:

      * `manual.html#146 <manual.html#146>`_

-     * `system.html#131 <system.html#131>`_

+     * `system.html#130 <system.html#130>`_

 

    `EIO`:idx:

-     `system.html#122 <system.html#122>`_

+     * `system.html#121 <system.html#121>`_

+     * `posix.html#245 <posix.html#245>`_

+

+   `EISCONN`:idx:

+     `posix.html#246 <posix.html#246>`_

+

+   `EISDIR`:idx:

+     `posix.html#247 <posix.html#247>`_

+

+   `ELOOP`:idx:

+     `posix.html#248 <posix.html#248>`_

 

    `Embedded Nimrod Debugger`:idx:

      `endb.html#101 <endb.html#101>`_

 

+   `EMFILE`:idx:

+     `posix.html#249 <posix.html#249>`_

+

+   `EMLINK`:idx:

+     `posix.html#250 <posix.html#250>`_

+

+   `EMSGSIZE`:idx:

+     `posix.html#251 <posix.html#251>`_

+

+   `EMULTIHOP`:idx:

+     `posix.html#252 <posix.html#252>`_

+

+   `ENAMETOOLONG`:idx:

+     `posix.html#253 <posix.html#253>`_

+

+   `encrypt`:idx:

+     `posix.html#969 <posix.html#969>`_

+

    `ENDB`:idx:

      `endb.html#102 <endb.html#102>`_

 

+   `endgrent`:idx:

+     `posix.html#832 <posix.html#832>`_

+

    `EndOfFile`:idx:

-     `system.html#368 <system.html#368>`_

+     * `system.html#379 <system.html#379>`_

+     * `lexbase.html#101 <lexbase.html#101>`_

+

+   `endpwent`:idx:

+     `posix.html#856 <posix.html#856>`_

 

    `endsWith`:idx:

-     `strutils.html#132 <strutils.html#132>`_

+     `strutils.html#133 <strutils.html#133>`_

+

+   `ENETDOWN`:idx:

+     `posix.html#254 <posix.html#254>`_

+

+   `ENETRESET`:idx:

+     `posix.html#255 <posix.html#255>`_

+

+   `ENETUNREACH`:idx:

+     `posix.html#256 <posix.html#256>`_

+

+   `ENFILE`:idx:

+     `posix.html#257 <posix.html#257>`_

+

+   `ENOBUFS`:idx:

+     `posix.html#258 <posix.html#258>`_

+

+   `ENODATA`:idx:

+     `posix.html#259 <posix.html#259>`_

+

+   `ENODEV`:idx:

+     `posix.html#260 <posix.html#260>`_

+

+   `ENOENT`:idx:

+     `posix.html#261 <posix.html#261>`_

 

    `ENoExceptionToReraise`:idx:

-     * `manual.html#186 <manual.html#186>`_

+     * `manual.html#185 <manual.html#185>`_

      * `system.html#136 <system.html#136>`_

 

+   `ENOEXEC`:idx:

+     `posix.html#262 <posix.html#262>`_

+

+   `ENOLCK`:idx:

+     `posix.html#263 <posix.html#263>`_

+

+   `ENOLINK`:idx:

+     `posix.html#264 <posix.html#264>`_

+

+   `ENOMEM`:idx:

+     `posix.html#265 <posix.html#265>`_

+

+   `ENOMSG`:idx:

+     `posix.html#266 <posix.html#266>`_

+

+   `ENOPROTOOPT`:idx:

+     `posix.html#267 <posix.html#267>`_

+

+   `ENOSPC`:idx:

+     `posix.html#268 <posix.html#268>`_

+

+   `ENOSR`:idx:

+     `posix.html#269 <posix.html#269>`_

+

+   `ENOSTR`:idx:

+     `posix.html#270 <posix.html#270>`_

+

+   `ENOSYS`:idx:

+     `posix.html#271 <posix.html#271>`_

+

+   `ENOTCONN`:idx:

+     `posix.html#272 <posix.html#272>`_

+

+   `ENOTDIR`:idx:

+     `posix.html#273 <posix.html#273>`_

+

+   `ENOTEMPTY`:idx:

+     `posix.html#274 <posix.html#274>`_

+

+   `ENOTSOCK`:idx:

+     `posix.html#275 <posix.html#275>`_

+

+   `ENOTSUP`:idx:

+     `posix.html#276 <posix.html#276>`_

+

+   `ENOTTY`:idx:

+     `posix.html#277 <posix.html#277>`_

+

    `Enumeration`:idx:

      `manual.html#149 <manual.html#149>`_

 

+   `ENXIO`:idx:

+     `posix.html#278 <posix.html#278>`_

+

+   `EOPNOTSUPP`:idx:

+     `posix.html#279 <posix.html#279>`_

+

    `EOS`:idx:

-     `system.html#123 <system.html#123>`_

+     `system.html#122 <system.html#122>`_

 

    `EOutOfMemory`:idx:

-     `system.html#132 <system.html#132>`_

+     `system.html#131 <system.html#131>`_

 

    `EOutOfRange`:idx:

      `system.html#134 <system.html#134>`_

 

    `EOverflow`:idx:

-     `system.html#127 <system.html#127>`_

+     `system.html#126 <system.html#126>`_

+

+   `EOVERFLOW`:idx:

+     `posix.html#280 <posix.html#280>`_

+

+   `EPERM`:idx:

+     `posix.html#281 <posix.html#281>`_

+

+   `EPIPE`:idx:

+     `posix.html#282 <posix.html#282>`_

+

+   `EPROTO`:idx:

+     `posix.html#283 <posix.html#283>`_

+

+   `EPROTONOSUPPORT`:idx:

+     `posix.html#284 <posix.html#284>`_

+

+   `EPROTOTYPE`:idx:

+     `posix.html#285 <posix.html#285>`_

 

    `equalMem`:idx:

      `system.html#295 <system.html#295>`_

 

+   `ERA`:idx:

+     `posix.html#431 <posix.html#431>`_

+

+   `ERA_D_FMT`:idx:

+     `posix.html#432 <posix.html#432>`_

+

+   `ERA_D_T_FMT`:idx:

+     `posix.html#433 <posix.html#433>`_

+

+   `ERANGE`:idx:

+     `posix.html#286 <posix.html#286>`_

+

+   `ERA_T_FMT`:idx:

+     `posix.html#434 <posix.html#434>`_

+

    `ERessourceExhausted`:idx:

-     `system.html#124 <system.html#124>`_

+     `system.html#123 <system.html#123>`_

+

+   `EROFS`:idx:

+     `posix.html#287 <posix.html#287>`_

+

+   `errno`:idx:

+     `posix.html#216 <posix.html#216>`_

 

    `error`:idx:

-     * `manual.html#223 <manual.html#223>`_

-     * `manual.html#226 <manual.html#226>`_

+     * `manual.html#222 <manual.html#222>`_

+     * `manual.html#225 <manual.html#225>`_

+     * `dialogs.html#104 <dialogs.html#104>`_

 

    `escape`:idx:

      `manual.html#133 <manual.html#133>`_

@@ -538,30 +1157,72 @@ Index
    `escape sequences`:idx:

      `manual.html#120 <manual.html#120>`_

 

+   `ESPIPE`:idx:

+     `posix.html#288 <posix.html#288>`_

+

+   `ESRCH`:idx:

+     `posix.html#289 <posix.html#289>`_

+

    `EStackOverflow`:idx:

      `system.html#135 <system.html#135>`_

 

+   `ESTALE`:idx:

+     `posix.html#290 <posix.html#290>`_

+

    `ESynch`:idx:

-     `system.html#120 <system.html#120>`_

+     `system.html#119 <system.html#119>`_

 

    `ESystem`:idx:

-     `system.html#121 <system.html#121>`_

+     `system.html#120 <system.html#120>`_

+

+   `ETIME`:idx:

+     `posix.html#291 <posix.html#291>`_

+

+   `ETIMEDOUT`:idx:

+     `posix.html#292 <posix.html#292>`_

+

+   `ETXTBSY`:idx:

+     `posix.html#293 <posix.html#293>`_

+

+   `EWOULDBLOCK`:idx:

+     `posix.html#294 <posix.html#294>`_

 

    `except`:idx:

-     `manual.html#189 <manual.html#189>`_

+     `manual.html#188 <manual.html#188>`_

 

    `exception handlers`:idx:

-     `manual.html#188 <manual.html#188>`_

+     `manual.html#187 <manual.html#187>`_

 

    `excl`:idx:

      `system.html#150 <system.html#150>`_

 

+   `EXDEV`:idx:

+     `posix.html#295 <posix.html#295>`_

+

+   `execl`:idx:

+     `posix.html#970 <posix.html#970>`_

+

+   `execle`:idx:

+     `posix.html#971 <posix.html#971>`_

+

+   `execlp`:idx:

+     `posix.html#972 <posix.html#972>`_

+

    `executeProcess`:idx:

      `os.html#129 <os.html#129>`_

 

    `executeShellCommand`:idx:

      `os.html#130 <os.html#130>`_

 

+   `execv`:idx:

+     `posix.html#973 <posix.html#973>`_

+

+   `execve`:idx:

+     `posix.html#974 <posix.html#974>`_

+

+   `execvp`:idx:

+     `posix.html#975 <posix.html#975>`_

+

    `existsDir`:idx:

      `os.html#136 <os.html#136>`_

 

@@ -572,7 +1233,7 @@ Index
      `os.html#115 <os.html#115>`_

 

    `exp`:idx:

-     `math.html#108 <math.html#108>`_

+     `math.html#112 <math.html#112>`_

 

    `expandFilename`:idx:

      `os.html#114 <os.html#114>`_

@@ -587,10 +1248,124 @@ Index
      `os.html#107 <os.html#107>`_

 

    `fastcall`:idx:

-     `manual.html#169 <manual.html#169>`_

+     `manual.html#168 <manual.html#168>`_

 

    `fatal`:idx:

-     `manual.html#227 <manual.html#227>`_

+     `manual.html#226 <manual.html#226>`_

+

+   `fchdir`:idx:

+     `posix.html#977 <posix.html#977>`_

+

+   `fchmod`:idx:

+     `posix.html#1052 <posix.html#1052>`_

+

+   `fchown`:idx:

+     `posix.html#976 <posix.html#976>`_

+

+   `fcntl`:idx:

+     `posix.html#806 <posix.html#806>`_

+

+   `fdatasync`:idx:

+     `posix.html#978 <posix.html#978>`_

+

+   `FD_CLOEXEC`:idx:

+     `posix.html#306 <posix.html#306>`_

+

+   `FD_CLR`:idx:

+     `posix.html#1154 <posix.html#1154>`_

+

+   `FD_ISSET`:idx:

+     `posix.html#1155 <posix.html#1155>`_

+

+   `FD_SET`:idx:

+     `posix.html#1156 <posix.html#1156>`_

+

+   `FD_SETSIZE`:idx:

+     `posix.html#771 <posix.html#771>`_

+

+   `F_DUPFD`:idx:

+     `posix.html#296 <posix.html#296>`_

+

+   `FD_ZERO`:idx:

+     `posix.html#1157 <posix.html#1157>`_

+

+   `FE_ALL_EXCEPT`:idx:

+     `posix.html#334 <posix.html#334>`_

+

+   `feclearexcept`:idx:

+     `posix.html#810 <posix.html#810>`_

+

+   `FE_DFL_ENV`:idx:

+     `posix.html#339 <posix.html#339>`_

+

+   `FE_DIVBYZERO`:idx:

+     `posix.html#329 <posix.html#329>`_

+

+   `FE_DOWNWARD`:idx:

+     `posix.html#335 <posix.html#335>`_

+

+   `fegetenv`:idx:

+     `posix.html#817 <posix.html#817>`_

+

+   `fegetexceptflag`:idx:

+     `posix.html#811 <posix.html#811>`_

+

+   `fegetround`:idx:

+     `posix.html#815 <posix.html#815>`_

+

+   `feholdexcept`:idx:

+     `posix.html#818 <posix.html#818>`_

+

+   `FE_INEXACT`:idx:

+     `posix.html#330 <posix.html#330>`_

+

+   `FE_INVALID`:idx:

+     `posix.html#331 <posix.html#331>`_

+

+   `FE_OVERFLOW`:idx:

+     `posix.html#332 <posix.html#332>`_

+

+   `feraiseexcept`:idx:

+     `posix.html#812 <posix.html#812>`_

+

+   `fesetenv`:idx:

+     `posix.html#819 <posix.html#819>`_

+

+   `fesetexceptflag`:idx:

+     `posix.html#813 <posix.html#813>`_

+

+   `fesetround`:idx:

+     `posix.html#816 <posix.html#816>`_

+

+   `fetestexcept`:idx:

+     `posix.html#814 <posix.html#814>`_

+

+   `FE_TONEAREST`:idx:

+     `posix.html#336 <posix.html#336>`_

+

+   `FE_TOWARDZERO`:idx:

+     `posix.html#337 <posix.html#337>`_

+

+   `FE_UNDERFLOW`:idx:

+     `posix.html#333 <posix.html#333>`_

+

+   `feupdateenv`:idx:

+     `posix.html#820 <posix.html#820>`_

+

+   `FE_UPWARD`:idx:

+     `posix.html#338 <posix.html#338>`_

+

+   `F_GETFD`:idx:

+     `posix.html#297 <posix.html#297>`_

+

+   `F_GETFL`:idx:

+     `posix.html#299 <posix.html#299>`_

+

+   `F_GETLK`:idx:

+     `posix.html#301 <posix.html#301>`_

+

+   `F_GETOWN`:idx:

+     `posix.html#304 <posix.html#304>`_

 

    `fileNewer`:idx:

      `os.html#138 <os.html#138>`_

@@ -599,7 +1374,7 @@ Index
      `os.html#106 <os.html#106>`_

 

    `finally`:idx:

-     `manual.html#190 <manual.html#190>`_

+     `manual.html#189 <manual.html#189>`_

 

    `find`:idx:

      * `regexprs.html#109 <regexprs.html#109>`_

@@ -609,50 +1384,167 @@ Index
      * `strutils.html#112 <strutils.html#112>`_

      * `strutils.html#113 <strutils.html#113>`_

 

+   `F_LOCK`:idx:

+     `posix.html#493 <posix.html#493>`_

+

    `FlushFile`:idx:

-     `system.html#370 <system.html#370>`_

+     `system.html#381 <system.html#381>`_

+

+   `fmtmsg`:idx:

+     `posix.html#821 <posix.html#821>`_

+

+   `fnmatch`:idx:

+     `posix.html#822 <posix.html#822>`_

+

+   `FNM_NOESCAPE`:idx:

+     `posix.html#362 <posix.html#362>`_

+

+   `FNM_NOMATCH`:idx:

+     `posix.html#359 <posix.html#359>`_

+

+   `FNM_NOSYS`:idx:

+     `posix.html#363 <posix.html#363>`_

+

+   `FNM_PATHNAME`:idx:

+     `posix.html#360 <posix.html#360>`_

+

+   `FNM_PERIOD`:idx:

+     `posix.html#361 <posix.html#361>`_

+

+   `F_OK`:idx:

+     `posix.html#475 <posix.html#475>`_

 

    `for`:idx:

-     `manual.html#205 <manual.html#205>`_

+     `manual.html#204 <manual.html#204>`_

+

+   `fork`:idx:

+     `posix.html#979 <posix.html#979>`_

 

    `form feed`:idx:

      `manual.html#124 <manual.html#124>`_

 

    `forward`:idx:

-     `manual.html#202 <manual.html#202>`_

+     `manual.html#201 <manual.html#201>`_

+

+   `fpathconf`:idx:

+     `posix.html#980 <posix.html#980>`_

+

+   `F_RDLCK`:idx:

+     `posix.html#307 <posix.html#307>`_

 

    `frexp`:idx:

-     `math.html#109 <math.html#109>`_

+     `math.html#113 <math.html#113>`_

+

+   `F_SETFD`:idx:

+     `posix.html#298 <posix.html#298>`_

+

+   `F_SETFL`:idx:

+     `posix.html#300 <posix.html#300>`_

+

+   `F_SETLK`:idx:

+     `posix.html#302 <posix.html#302>`_

+

+   `F_SETLKW`:idx:

+     `posix.html#303 <posix.html#303>`_

+

+   `F_SETOWN`:idx:

+     `posix.html#305 <posix.html#305>`_

+

+   `fstat`:idx:

+     `posix.html#1053 <posix.html#1053>`_

+

+   `fstatvfs`:idx:

+     `posix.html#1050 <posix.html#1050>`_

+

+   `fsync`:idx:

+     `posix.html#981 <posix.html#981>`_

+

+   `F_TEST`:idx:

+     `posix.html#494 <posix.html#494>`_

+

+   `F_TLOCK`:idx:

+     `posix.html#495 <posix.html#495>`_

+

+   `ftok`:idx:

+     `posix.html#1048 <posix.html#1048>`_

+

+   `ftruncate`:idx:

+     `posix.html#982 <posix.html#982>`_

+

+   `ftw`:idx:

+     `posix.html#823 <posix.html#823>`_

+

+   `FTW_CHDIR`:idx:

+     `posix.html#374 <posix.html#374>`_

+

+   `FTW_D`:idx:

+     `posix.html#365 <posix.html#365>`_

+

+   `FTW_DEPTH`:idx:

+     `posix.html#373 <posix.html#373>`_

+

+   `FTW_DNR`:idx:

+     `posix.html#366 <posix.html#366>`_

+

+   `FTW_DP`:idx:

+     `posix.html#367 <posix.html#367>`_

+

+   `FTW_F`:idx:

+     `posix.html#364 <posix.html#364>`_

+

+   `FTW_MOUNT`:idx:

+     `posix.html#372 <posix.html#372>`_

+

+   `FTW_NS`:idx:

+     `posix.html#368 <posix.html#368>`_

+

+   `FTW_PHYS`:idx:

+     `posix.html#371 <posix.html#371>`_

+

+   `FTW_SL`:idx:

+     `posix.html#369 <posix.html#369>`_

+

+   `FTW_SLN`:idx:

+     `posix.html#370 <posix.html#370>`_

+

+   `F_ULOCK`:idx:

+     `posix.html#496 <posix.html#496>`_

 

    `functional`:idx:

-     `manual.html#163 <manual.html#163>`_

+     `manual.html#162 <manual.html#162>`_

+

+   `F_UNLCK`:idx:

+     `posix.html#308 <posix.html#308>`_

 

    `funtions`:idx:

-     `manual.html#200 <manual.html#200>`_

+     `manual.html#199 <manual.html#199>`_

+

+   `F_WRLCK`:idx:

+     `posix.html#309 <posix.html#309>`_

 

    `GC_disable`:idx:

-     `system.html#354 <system.html#354>`_

+     `system.html#364 <system.html#364>`_

 

    `GC_disableMarkAndSweep`:idx:

-     `system.html#360 <system.html#360>`_

+     `system.html#370 <system.html#370>`_

 

    `GC_enable`:idx:

-     `system.html#355 <system.html#355>`_

+     `system.html#365 <system.html#365>`_

 

    `GC_enableMarkAndSweep`:idx:

-     `system.html#359 <system.html#359>`_

+     `system.html#369 <system.html#369>`_

 

    `GC_fullCollect`:idx:

-     `system.html#356 <system.html#356>`_

+     `system.html#366 <system.html#366>`_

 

    `GC_setStrategy`:idx:

-     `system.html#358 <system.html#358>`_

+     `system.html#368 <system.html#368>`_

 

    `generic character types`:idx:

      `regexprs.html#102 <regexprs.html#102>`_

 

    `Generics`:idx:

-     `manual.html#209 <manual.html#209>`_

+     `manual.html#208 <manual.html#208>`_

 

    `getApplicationDir`:idx:

      `os.html#108 <os.html#108>`_

@@ -663,48 +1555,145 @@ Index
    `getClockStr`:idx:

      `times.html#112 <times.html#112>`_

 

+   `getColNumber`:idx:

+     `lexbase.html#108 <lexbase.html#108>`_

+

+   `getColumn`:idx:

+     `parsecfg.html#108 <parsecfg.html#108>`_

+

    `getConfigDir`:idx:

      `os.html#113 <os.html#113>`_

 

+   `getcontext`:idx:

+     `posix.html#1181 <posix.html#1181>`_

+

    `getCurrentDir`:idx:

      `os.html#110 <os.html#110>`_

 

    `getCurrentExceptionMsg`:idx:

-     * `manual.html#184 <manual.html#184>`_

-     * `system.html#334 <system.html#334>`_

+     * `manual.html#183 <manual.html#183>`_

+     * `system.html#336 <system.html#336>`_

+

+   `getCurrentLine`:idx:

+     `lexbase.html#107 <lexbase.html#107>`_

+

+   `getcwd`:idx:

+     `posix.html#983 <posix.html#983>`_

+

+   `getdate`:idx:

+     `posix.html#1096 <posix.html#1096>`_

 

    `getDateStr`:idx:

      `times.html#111 <times.html#111>`_

 

+   `getegid`:idx:

+     `posix.html#984 <posix.html#984>`_

+

    `getEnv`:idx:

      `os.html#140 <os.html#140>`_

 

+   `geteuid`:idx:

+     `posix.html#985 <posix.html#985>`_

+

+   `getFilename`:idx:

+     `parsecfg.html#110 <parsecfg.html#110>`_

+

    `getFilePos`:idx:

-     `system.html#389 <system.html#389>`_

+     `system.html#401 <system.html#401>`_

 

    `getFileSize`:idx:

-     `system.html#381 <system.html#381>`_

+     `system.html#393 <system.html#393>`_

 

    `getFreeMem`:idx:

-     `system.html#339 <system.html#339>`_

+     `system.html#342 <system.html#342>`_

+

+   `getgid`:idx:

+     `posix.html#986 <posix.html#986>`_

 

    `getGMTime`:idx:

      `times.html#107 <times.html#107>`_

 

+   `getgrent`:idx:

+     `posix.html#831 <posix.html#831>`_

+

+   `getgrgid`:idx:

+     `posix.html#827 <posix.html#827>`_

+

+   `getgrgid_r`:idx:

+     `posix.html#829 <posix.html#829>`_

+

+   `getgrnam`:idx:

+     `posix.html#828 <posix.html#828>`_

+

+   `getgrnam_r`:idx:

+     `posix.html#830 <posix.html#830>`_

+

+   `getgroups`:idx:

+     `posix.html#987 <posix.html#987>`_

+

    `getHomeDir`:idx:

      `os.html#112 <os.html#112>`_

 

+   `gethostid`:idx:

+     `posix.html#988 <posix.html#988>`_

+

+   `gethostname`:idx:

+     `posix.html#989 <posix.html#989>`_

+

    `getLastModificationTime`:idx:

      `os.html#137 <os.html#137>`_

 

+   `getLine`:idx:

+     `parsecfg.html#109 <parsecfg.html#109>`_

+

    `getLocalTime`:idx:

      `times.html#106 <times.html#106>`_

 

+   `getlogin`:idx:

+     `posix.html#990 <posix.html#990>`_

+

+   `getlogin_r`:idx:

+     `posix.html#991 <posix.html#991>`_

+

    `getOccupiedMem`:idx:

-     `system.html#338 <system.html#338>`_

+     `system.html#341 <system.html#341>`_

+

+   `getopt`:idx:

+     * `parseopt.html#106 <parseopt.html#106>`_

+     * `posix.html#992 <posix.html#992>`_

+

+   `getpgid`:idx:

+     `posix.html#993 <posix.html#993>`_

+

+   `getpgrp`:idx:

+     `posix.html#994 <posix.html#994>`_

+

+   `getpid`:idx:

+     `posix.html#995 <posix.html#995>`_

+

+   `getppid`:idx:

+     `posix.html#996 <posix.html#996>`_

+

+   `getpwent`:idx:

+     `posix.html#857 <posix.html#857>`_

+

+   `getpwnam`:idx:

+     `posix.html#853 <posix.html#853>`_

+

+   `getpwuid`:idx:

+     `posix.html#854 <posix.html#854>`_

+

+   `getpwuid_r`:idx:

+     `posix.html#855 <posix.html#855>`_

 

    `getRefcount`:idx:

-     `system.html#333 <system.html#333>`_

+     `system.html#335 <system.html#335>`_

+

+   `getRestOfCommandLine`:idx:

+     `parseopt.html#105 <parseopt.html#105>`_

+

+   `getsid`:idx:

+     `posix.html#997 <posix.html#997>`_

 

    `getStartMilsecs`:idx:

      `times.html#114 <times.html#114>`_

@@ -713,7 +1702,83 @@ Index
      `times.html#105 <times.html#105>`_

 

    `getTotalMem`:idx:

-     `system.html#340 <system.html#340>`_

+     `system.html#343 <system.html#343>`_

+

+   `getuid`:idx:

+     `posix.html#998 <posix.html#998>`_

+

+   `getwd`:idx:

+     `posix.html#999 <posix.html#999>`_

+

+   `glob`:idx:

+     `posix.html#825 <posix.html#825>`_

+

+   `GLOB_ABORTED`:idx:

+     `posix.html#382 <posix.html#382>`_

+

+   `GLOB_APPEND`:idx:

+     `posix.html#375 <posix.html#375>`_

+

+   `GLOB_DOOFFS`:idx:

+     `posix.html#376 <posix.html#376>`_

+

+   `GLOB_ERR`:idx:

+     `posix.html#377 <posix.html#377>`_

+

+   `globfree`:idx:

+     `posix.html#826 <posix.html#826>`_

+

+   `GLOB_MARK`:idx:

+     `posix.html#378 <posix.html#378>`_

+

+   `GLOB_NOCHECK`:idx:

+     `posix.html#379 <posix.html#379>`_

+

+   `GLOB_NOESCAPE`:idx:

+     `posix.html#380 <posix.html#380>`_

+

+   `GLOB_NOMATCH`:idx:

+     `posix.html#383 <posix.html#383>`_

+

+   `GLOB_NOSORT`:idx:

+     `posix.html#381 <posix.html#381>`_

+

+   `GLOB_NOSPACE`:idx:

+     `posix.html#384 <posix.html#384>`_

+

+   `GLOB_NOSYS`:idx:

+     `posix.html#385 <posix.html#385>`_

+

+   `gmtime`:idx:

+     `posix.html#1097 <posix.html#1097>`_

+

+   `gmtime_r`:idx:

+     `posix.html#1098 <posix.html#1098>`_

+

+   `HandleCR`:idx:

+     `lexbase.html#109 <lexbase.html#109>`_

+

+   `HandleLF`:idx:

+     `lexbase.html#110 <lexbase.html#110>`_

+

+   `hash`:idx:

+     * `hashes.html#103 <hashes.html#103>`_

+     * `hashes.html#104 <hashes.html#104>`_

+     * `hashes.html#105 <hashes.html#105>`_

+     * `hashes.html#106 <hashes.html#106>`_

+     * `hashes.html#107 <hashes.html#107>`_

+

+   `hashData`:idx:

+     `hashes.html#102 <hashes.html#102>`_

+

+   `hashIgnoreCase`:idx:

+     `hashes.html#109 <hashes.html#109>`_

+

+   `hashIgnoreStyle`:idx:

+     `hashes.html#108 <hashes.html#108>`_

+

+   `hasKey`:idx:

+     `strtabs.html#108 <strtabs.html#108>`_

 

    `header`:idx:

      `nimrodc.html#103 <nimrodc.html#103>`_

@@ -722,11 +1787,26 @@ Index
      `system.html#105 <system.html#105>`_

 

    `hint`:idx:

-     * `manual.html#221 <manual.html#221>`_

-     * `manual.html#229 <manual.html#229>`_

+     * `manual.html#220 <manual.html#220>`_

+     * `manual.html#228 <manual.html#228>`_

+

+   `htonl`:idx:

+     `posix.html#786 <posix.html#786>`_

+

+   `htons`:idx:

+     `posix.html#787 <posix.html#787>`_

 

    `hypot`:idx:

-     `math.html#116 <math.html#116>`_

+     `math.html#121 <math.html#121>`_

+

+   `iconv`:idx:

+     `posix.html#835 <posix.html#835>`_

+

+   `iconv_close`:idx:

+     `posix.html#836 <posix.html#836>`_

+

+   `iconv_open`:idx:

+     `posix.html#834 <posix.html#834>`_

 

    `identifier`:idx:

      `manual.html#105 <manual.html#105>`_

@@ -735,13 +1815,13 @@ Index
      `manual.html#116 <manual.html#116>`_

 

    `if`:idx:

-     `manual.html#181 <manual.html#181>`_

+     `manual.html#180 <manual.html#180>`_

 

    `implicit block`:idx:

-     `manual.html#207 <manual.html#207>`_

+     `manual.html#206 <manual.html#206>`_

 

    `import`:idx:

-     `manual.html#217 <manual.html#217>`_

+     `manual.html#216 <manual.html#216>`_

 

    `in`:idx:

      `system.html#239 <system.html#239>`_

@@ -755,14 +1835,38 @@ Index
    `indentation sensitive`:idx:

      `manual.html#113 <manual.html#113>`_

 

+   `inet_addr`:idx:

+     `posix.html#790 <posix.html#790>`_

+

+   `inet_ntoa`:idx:

+     `posix.html#791 <posix.html#791>`_

+

+   `inet_ntop`:idx:

+     `posix.html#792 <posix.html#792>`_

+

+   `inet_pton`:idx:

+     `posix.html#793 <posix.html#793>`_

+

    `inf`:idx:

-     `system.html#335 <system.html#335>`_

+     `system.html#337 <system.html#337>`_

+

+   `info`:idx:

+     `dialogs.html#102 <dialogs.html#102>`_

 

    `information hiding`:idx:

-     `manual.html#215 <manual.html#215>`_

+     `manual.html#214 <manual.html#214>`_

+

+   `init`:idx:

+     `parseopt.html#103 <parseopt.html#103>`_

+

+   `initBaseLexer`:idx:

+     `lexbase.html#104 <lexbase.html#104>`_

+

+   `initBaseLexerFromBuffer`:idx:

+     `lexbase.html#105 <lexbase.html#105>`_

 

    `inline`:idx:

-     `manual.html#168 <manual.html#168>`_

+     `manual.html#167 <manual.html#167>`_

 

    `in_Operator`:idx:

      * `strutils.html#121 <strutils.html#121>`_

@@ -774,29 +1878,64 @@ Index
    `intToStr`:idx:

      `strutils.html#124 <strutils.html#124>`_

 

+   `IPC_CREAT`:idx:

+     `posix.html#639 <posix.html#639>`_

+

+   `IPC_EXCL`:idx:

+     `posix.html#640 <posix.html#640>`_

+

+   `IPC_NOWAIT`:idx:

+     `posix.html#641 <posix.html#641>`_

+

+   `IPC_PRIVATE`:idx:

+     `posix.html#642 <posix.html#642>`_

+

+   `IPC_RMID`:idx:

+     `posix.html#643 <posix.html#643>`_

+

+   `IPC_SET`:idx:

+     `posix.html#644 <posix.html#644>`_

+

+   `IPC_STAT`:idx:

+     `posix.html#645 <posix.html#645>`_

+

    `is`:idx:

      `system.html#241 <system.html#241>`_

 

+   `isatty`:idx:

+     `posix.html#1000 <posix.html#1000>`_

+

+   `isNil`:idx:

+     * `system.html#352 <system.html#352>`_

+     * `system.html#353 <system.html#353>`_

+     * `system.html#354 <system.html#354>`_

+     * `system.html#355 <system.html#355>`_

+     * `system.html#356 <system.html#356>`_

+     * `system.html#357 <system.html#357>`_

+

    `is_not`:idx:

      `system.html#242 <system.html#242>`_

 

    `isPowerOfTwo`:idx:

-     `math.html#102 <math.html#102>`_

+     `math.html#103 <math.html#103>`_

 

    `items`:idx:

-     * `system.html#343 <system.html#343>`_

-     * `system.html#344 <system.html#344>`_

-     * `system.html#345 <system.html#345>`_

      * `system.html#346 <system.html#346>`_

      * `system.html#347 <system.html#347>`_

      * `system.html#348 <system.html#348>`_

+     * `system.html#349 <system.html#349>`_

+     * `system.html#350 <system.html#350>`_

+     * `system.html#351 <system.html#351>`_

 

    `iterator`:idx:

-     `manual.html#206 <manual.html#206>`_

+     `manual.html#205 <manual.html#205>`_

 

    `iterOverEnvironment`:idx:

      `os.html#145 <os.html#145>`_

 

+   `JavaScript`:idx:

+     `nimrodc.html#112 <nimrodc.html#112>`_

+

    `JoinPath`:idx:

      * `os.html#116 <os.html#116>`_

      * `os.html#118 <os.html#118>`_

@@ -804,14 +1943,45 @@ Index
    `keywords`:idx:

      `manual.html#117 <manual.html#117>`_

 

+   `kill`:idx:

+     `posix.html#1116 <posix.html#1116>`_

+

+   `killpg`:idx:

+     `posix.html#1117 <posix.html#1117>`_

+

    `l-values`:idx:

      `manual.html#107 <manual.html#107>`_

 

+   `LC_ALL`:idx:

+     `posix.html#441 <posix.html#441>`_

+

+   `LC_COLLATE`:idx:

+     `posix.html#442 <posix.html#442>`_

+

+   `LC_CTYPE`:idx:

+     `posix.html#443 <posix.html#443>`_

+

+   `lchown`:idx:

+     `posix.html#1001 <posix.html#1001>`_

+

+   `LC_MESSAGES`:idx:

+     `posix.html#444 <posix.html#444>`_

+

+   `LC_MONETARY`:idx:

+     `posix.html#445 <posix.html#445>`_

+

+   `LC_NUMERIC`:idx:

+     `posix.html#446 <posix.html#446>`_

+

+   `LC_TIME`:idx:

+     `posix.html#447 <posix.html#447>`_

+

    `len`:idx:

      * `system.html#145 <system.html#145>`_

      * `system.html#146 <system.html#146>`_

      * `system.html#147 <system.html#147>`_

      * `system.html#148 <system.html#148>`_

+     * `strtabs.html#109 <strtabs.html#109>`_

 

    `line feed`:idx:

      `manual.html#123 <manual.html#123>`_

@@ -820,28 +1990,85 @@ Index
      `nimrodc.html#105 <nimrodc.html#105>`_

 

    `lines`:idx:

-     `system.html#390 <system.html#390>`_

+     `system.html#402 <system.html#402>`_

 

    `line_trace`:idx:

      `nimrodc.html#107 <nimrodc.html#107>`_

 

+   `link`:idx:

+     `posix.html#1002 <posix.html#1002>`_

+

+   `lio_listio`:idx:

+     `posix.html#785 <posix.html#785>`_

+

+   `LIO_NOP`:idx:

+     `posix.html#207 <posix.html#207>`_

+

+   `LIO_NOWAIT`:idx:

+     `posix.html#208 <posix.html#208>`_

+

+   `LIO_READ`:idx:

+     `posix.html#209 <posix.html#209>`_

+

+   `LIO_WAIT`:idx:

+     `posix.html#210 <posix.html#210>`_

+

+   `LIO_WRITE`:idx:

+     `posix.html#211 <posix.html#211>`_

+

    `Literal strings`:idx:

      `manual.html#119 <manual.html#119>`_

 

    `ln`:idx:

-     `math.html#107 <math.html#107>`_

+     `math.html#109 <math.html#109>`_

+

+   `localeconv`:idx:

+     `posix.html#840 <posix.html#840>`_

+

+   `localtime`:idx:

+     `posix.html#1099 <posix.html#1099>`_

+

+   `localtime_r`:idx:

+     `posix.html#1100 <posix.html#1100>`_

 

    `locations`:idx:

      `manual.html#101 <manual.html#101>`_

 

+   `lockf`:idx:

+     `posix.html#1003 <posix.html#1003>`_

+

    `log10`:idx:

-     `math.html#117 <math.html#117>`_

+     `math.html#110 <math.html#110>`_

+

+   `log2`:idx:

+     `math.html#111 <math.html#111>`_

 

    `low`:idx:

      `system.html#106 <system.html#106>`_

 

+   `lseek`:idx:

+     `posix.html#1004 <posix.html#1004>`_

+

+   `lstat`:idx:

+     `posix.html#1054 <posix.html#1054>`_

+

    `Macros`:idx:

-     `manual.html#212 <manual.html#212>`_

+     `manual.html#211 <manual.html#211>`_

+

+   `makecontext`:idx:

+     `posix.html#1182 <posix.html#1182>`_

+

+   `MAP_FAILED`:idx:

+     `posix.html#683 <posix.html#683>`_

+

+   `MAP_FIXED`:idx:

+     `posix.html#677 <posix.html#677>`_

+

+   `MAP_PRIVATE`:idx:

+     `posix.html#676 <posix.html#676>`_

+

+   `MAP_SHARED`:idx:

+     `posix.html#675 <posix.html#675>`_

 

    `match`:idx:

      * `regexprs.html#106 <regexprs.html#106>`_

@@ -850,6 +2077,9 @@ Index
    `matchLen`:idx:

      `regexprs.html#108 <regexprs.html#108>`_

 

+   `math`:idx:

+     `nimrodc.html#114 <nimrodc.html#114>`_

+

    `max`:idx:

      * `system.html#172 <system.html#172>`_

      * `system.html#191 <system.html#191>`_

@@ -858,20 +2088,161 @@ Index
    `MaxSubpatterns`:idx:

      `regexprs.html#105 <regexprs.html#105>`_

 

+   `MCL_CURRENT`:idx:

+     `posix.html#681 <posix.html#681>`_

+

+   `MCL_FUTURE`:idx:

+     `posix.html#682 <posix.html#682>`_

+

    `methods`:idx:

-     `manual.html#199 <manual.html#199>`_

+     `manual.html#198 <manual.html#198>`_

 

    `min`:idx:

      * `system.html#171 <system.html#171>`_

      * `system.html#190 <system.html#190>`_

      * `system.html#202 <system.html#202>`_

 

+   `MINSIGSTKSZ`:idx:

+     `posix.html#763 <posix.html#763>`_

+

+   `mkdir`:idx:

+     `posix.html#1055 <posix.html#1055>`_

+

+   `mkfifo`:idx:

+     `posix.html#1056 <posix.html#1056>`_

+

+   `mknod`:idx:

+     `posix.html#1057 <posix.html#1057>`_

+

+   `mktime`:idx:

+     `posix.html#1101 <posix.html#1101>`_

+

+   `mlock`:idx:

+     `posix.html#1071 <posix.html#1071>`_

+

+   `mlockall`:idx:

+     `posix.html#1072 <posix.html#1072>`_

+

+   `mmap`:idx:

+     `posix.html#1073 <posix.html#1073>`_

+

+   `MM_APPL`:idx:

+     `posix.html#343 <posix.html#343>`_

+

+   `MM_CONSOLE`:idx:

+     `posix.html#354 <posix.html#354>`_

+

+   `MM_ERROR`:idx:

+     `posix.html#349 <posix.html#349>`_

+

+   `MM_FIRM`:idx:

+     `posix.html#342 <posix.html#342>`_

+

+   `MM_HALT`:idx:

+     `posix.html#348 <posix.html#348>`_

+

+   `MM_HARD`:idx:

+     `posix.html#340 <posix.html#340>`_

+

+   `MM_INFO`:idx:

+     `posix.html#351 <posix.html#351>`_

+

+   `MM_NOCON`:idx:

+     `posix.html#358 <posix.html#358>`_

+

+   `MM_NOMSG`:idx:

+     `posix.html#357 <posix.html#357>`_

+

+   `MM_NOSEV`:idx:

+     `posix.html#352 <posix.html#352>`_

+

+   `MM_NOTOK`:idx:

+     `posix.html#356 <posix.html#356>`_

+

+   `MM_NRECOV`:idx:

+     `posix.html#347 <posix.html#347>`_

+

+   `MM_NULLACT`:idx:

+     `posix.html#125 <posix.html#125>`_

+

+   `MM_NULLLBL`:idx:

+     `posix.html#121 <posix.html#121>`_

+

+   `MM_NULLMC`:idx:

+     `posix.html#123 <posix.html#123>`_

+

+   `MM_NULLSEV`:idx:

+     `posix.html#122 <posix.html#122>`_

+

+   `MM_NULLTAG`:idx:

+     `posix.html#126 <posix.html#126>`_

+

+   `MM_NULLTXT`:idx:

+     `posix.html#124 <posix.html#124>`_

+

+   `MM_OK`:idx:

+     `posix.html#355 <posix.html#355>`_

+

+   `MM_OPSYS`:idx:

+     `posix.html#345 <posix.html#345>`_

+

+   `MM_PRINT`:idx:

+     `posix.html#353 <posix.html#353>`_

+

+   `MM_RECOVER`:idx:

+     `posix.html#346 <posix.html#346>`_

+

+   `MM_SOFT`:idx:

+     `posix.html#341 <posix.html#341>`_

+

+   `MM_UTIL`:idx:

+     `posix.html#344 <posix.html#344>`_

+

+   `MM_WARNING`:idx:

+     `posix.html#350 <posix.html#350>`_

+

    `mod`:idx:

      * `system.html#161 <system.html#161>`_

      * `system.html#180 <system.html#180>`_

 

    `module`:idx:

-     `manual.html#214 <manual.html#214>`_

+     `manual.html#213 <manual.html#213>`_

+

+   `MON_1`:idx:

+     `posix.html#407 <posix.html#407>`_

+

+   `MON_10`:idx:

+     `posix.html#416 <posix.html#416>`_

+

+   `MON_11`:idx:

+     `posix.html#417 <posix.html#417>`_

+

+   `MON_12`:idx:

+     `posix.html#418 <posix.html#418>`_

+

+   `MON_2`:idx:

+     `posix.html#408 <posix.html#408>`_

+

+   `MON_3`:idx:

+     `posix.html#409 <posix.html#409>`_

+

+   `MON_4`:idx:

+     `posix.html#410 <posix.html#410>`_

+

+   `MON_5`:idx:

+     `posix.html#411 <posix.html#411>`_

+

+   `MON_6`:idx:

+     `posix.html#412 <posix.html#412>`_

+

+   `MON_7`:idx:

+     `posix.html#413 <posix.html#413>`_

+

+   `MON_8`:idx:

+     `posix.html#414 <posix.html#414>`_

+

+   `MON_9`:idx:

+     `posix.html#415 <posix.html#415>`_

 

    `moveFile`:idx:

      `os.html#132 <os.html#132>`_

@@ -879,11 +2250,71 @@ Index
    `moveMem`:idx:

      `system.html#294 <system.html#294>`_

 

+   `mprotect`:idx:

+     `posix.html#1074 <posix.html#1074>`_

+

+   `mq_close`:idx:

+     `posix.html#843 <posix.html#843>`_

+

+   `mq_getattr`:idx:

+     `posix.html#844 <posix.html#844>`_

+

+   `mq_notify`:idx:

+     `posix.html#845 <posix.html#845>`_

+

+   `mq_open`:idx:

+     `posix.html#846 <posix.html#846>`_

+

+   `mq_receive`:idx:

+     `posix.html#847 <posix.html#847>`_

+

+   `mq_send`:idx:

+     `posix.html#848 <posix.html#848>`_

+

+   `mq_setattr`:idx:

+     `posix.html#849 <posix.html#849>`_

+

+   `mq_timedreceive`:idx:

+     `posix.html#850 <posix.html#850>`_

+

+   `mq_timedsend`:idx:

+     `posix.html#851 <posix.html#851>`_

+

+   `mq_unlink`:idx:

+     `posix.html#852 <posix.html#852>`_

+

+   `MS_ASYNC`:idx:

+     `posix.html#678 <posix.html#678>`_

+

+   `MS_INVALIDATE`:idx:

+     `posix.html#680 <posix.html#680>`_

+

+   `MS_SYNC`:idx:

+     `posix.html#679 <posix.html#679>`_

+

+   `msync`:idx:

+     `posix.html#1075 <posix.html#1075>`_

+

+   `munlock`:idx:

+     `posix.html#1076 <posix.html#1076>`_

+

+   `munlockall`:idx:

+     `posix.html#1077 <posix.html#1077>`_

+

+   `munmap`:idx:

+     `posix.html#1078 <posix.html#1078>`_

+

    `nan`:idx:

-     `system.html#336 <system.html#336>`_

+     `system.html#339 <system.html#339>`_

+

+   `nanosleep`:idx:

+     `posix.html#1102 <posix.html#1102>`_

 

    `Natural`:idx:

-     `system.html#114 <system.html#114>`_

+     `system.html#113 <system.html#113>`_

+

+   `neginf`:idx:

+     `system.html#338 <system.html#338>`_

 

    `new`:idx:

      * `system.html#103 <system.html#103>`_

@@ -892,14 +2323,31 @@ Index
    `newline`:idx:

      `manual.html#121 <manual.html#121>`_

 

+   `NewLines`:idx:

+     `lexbase.html#102 <lexbase.html#102>`_

+

    `newString`:idx:

      `system.html#291 <system.html#291>`_

 

+   `newStringTable`:idx:

+     * `strtabs.html#104 <strtabs.html#104>`_

+     * `strtabs.html#105 <strtabs.html#105>`_

+

+   `next`:idx:

+     * `parseopt.html#104 <parseopt.html#104>`_

+     * `parsecfg.html#107 <parsecfg.html#107>`_

+

    `nextPowerOfTwo`:idx:

-     `math.html#101 <math.html#101>`_

+     `math.html#104 <math.html#104>`_

+

+   `nftw`:idx:

+     `posix.html#824 <posix.html#824>`_

+

+   `nice`:idx:

+     `posix.html#1005 <posix.html#1005>`_

 

    `nimcall`:idx:

-     `manual.html#170 <manual.html#170>`_

+     `manual.html#169 <manual.html#169>`_

 

    `NimrodMajor`:idx:

      `system.html#278 <system.html#278>`_

@@ -916,12 +2364,24 @@ Index
    `nl`:idx:

      `strutils.html#104 <strutils.html#104>`_

 

+   `NL_CAT_LOCALE`:idx:

+     `posix.html#766 <posix.html#766>`_

+

+   `nl_langinfo`:idx:

+     `posix.html#837 <posix.html#837>`_

+

+   `NL_SETD`:idx:

+     `posix.html#765 <posix.html#765>`_

+

    `noconv`:idx:

-     `manual.html#173 <manual.html#173>`_

+     `manual.html#172 <manual.html#172>`_

 

    `no_decl`:idx:

      `nimrodc.html#101 <nimrodc.html#101>`_

 

+   `NOEXPR`:idx:

+     `posix.html#439 <posix.html#439>`_

+

    `normalize`:idx:

      `strutils.html#111 <strutils.html#111>`_

 

@@ -936,23 +2396,62 @@ Index
    `not_in`:idx:

      `system.html#240 <system.html#240>`_

 

+   `ntohl`:idx:

+     `posix.html#788 <posix.html#788>`_

+

+   `ntohs`:idx:

+     `posix.html#789 <posix.html#789>`_

+

    `Numerical constants`:idx:

      `manual.html#137 <manual.html#137>`_

 

+   `O_ACCMODE`:idx:

+     `posix.html#319 <posix.html#319>`_

+

+   `O_APPEND`:idx:

+     `posix.html#314 <posix.html#314>`_

+

    `object`:idx:

      `manual.html#156 <manual.html#156>`_

 

+   `O_CREAT`:idx:

+     `posix.html#310 <posix.html#310>`_

+

+   `O_DSYNC`:idx:

+     `posix.html#315 <posix.html#315>`_

+

+   `O_EXCL`:idx:

+     `posix.html#311 <posix.html#311>`_

+

+   `O_NOCTTY`:idx:

+     `posix.html#312 <posix.html#312>`_

+

+   `O_NONBLOCK`:idx:

+     `posix.html#316 <posix.html#316>`_

+

+   `open`:idx:

+     `posix.html#807 <posix.html#807>`_

+

+   `Open`:idx:

+     `parsecfg.html#104 <parsecfg.html#104>`_

+

    `openarray`:idx:

      `system.html#109 <system.html#109>`_

 

+   `opendir`:idx:

+     `posix.html#795 <posix.html#795>`_

+

    `OpenFile`:idx:

-     `system.html#366 <system.html#366>`_

+     `system.html#377 <system.html#377>`_

+

+   `OpenFromBuffer`:idx:

+     `parsecfg.html#105 <parsecfg.html#105>`_

 

    `operator`:idx:

      `manual.html#139 <manual.html#139>`_

 

    `Operators`:idx:

-     `manual.html#204 <manual.html#204>`_

+     `manual.html#203 <manual.html#203>`_

 

    `or`:idx:

      * `system.html#165 <system.html#165>`_

@@ -965,6 +2464,30 @@ Index
    `Ordinal types`:idx:

      `manual.html#142 <manual.html#142>`_

 

+   `O_RDONLY`:idx:

+     `posix.html#320 <posix.html#320>`_

+

+   `O_RDWR`:idx:

+     `posix.html#321 <posix.html#321>`_

+

+   `O_RSYNC`:idx:

+     `posix.html#317 <posix.html#317>`_

+

+   `O_SYNC`:idx:

+     `posix.html#318 <posix.html#318>`_

+

+   `O_TRUNC`:idx:

+     `posix.html#313 <posix.html#313>`_

+

+   `O_WRONLY`:idx:

+     `posix.html#322 <posix.html#322>`_

+

+   `pairs`:idx:

+     `strtabs.html#110 <strtabs.html#110>`_

+

+   `P_ALL`:idx:

+     `posix.html#713 <posix.html#713>`_

+

    `paramCount`:idx:

      `os.html#142 <os.html#142>`_

 

@@ -977,15 +2500,81 @@ Index
    `parentDir`:idx:

      `os.html#120 <os.html#120>`_

 

-   `ParseFloat`:idx:

+   `ParseBiggestInt`:idx:

      `strutils.html#126 <strutils.html#126>`_

 

+   `ParseFloat`:idx:

+     `strutils.html#127 <strutils.html#127>`_

+

    `ParseInt`:idx:

      `strutils.html#125 <strutils.html#125>`_

 

+   `pathconf`:idx:

+     `posix.html#1006 <posix.html#1006>`_

+

    `PathSep`:idx:

      `os.html#105 <os.html#105>`_

 

+   `pause`:idx:

+     `posix.html#1007 <posix.html#1007>`_

+

+   `PC_2_SYMLINKS`:idx:

+     `posix.html#497 <posix.html#497>`_

+

+   `PC_ALLOC_SIZE_MIN`:idx:

+     `posix.html#498 <posix.html#498>`_

+

+   `PC_ASYNC_IO`:idx:

+     `posix.html#499 <posix.html#499>`_

+

+   `PC_CHOWN_RESTRICTED`:idx:

+     `posix.html#500 <posix.html#500>`_

+

+   `PC_FILESIZEBITS`:idx:

+     `posix.html#501 <posix.html#501>`_

+

+   `PC_LINK_MAX`:idx:

+     `posix.html#502 <posix.html#502>`_

+

+   `PC_MAX_CANON`:idx:

+     `posix.html#503 <posix.html#503>`_

+

+   `PC_MAX_INPUT`:idx:

+     `posix.html#504 <posix.html#504>`_

+

+   `PC_NAME_MAX`:idx:

+     `posix.html#505 <posix.html#505>`_

+

+   `PC_NO_TRUNC`:idx:

+     `posix.html#506 <posix.html#506>`_

+

+   `PC_PATH_MAX`:idx:

+     `posix.html#507 <posix.html#507>`_

+

+   `PC_PIPE_BUF`:idx:

+     `posix.html#508 <posix.html#508>`_

+

+   `PC_PRIO_IO`:idx:

+     `posix.html#509 <posix.html#509>`_

+

+   `PC_REC_INCR_XFER_SIZE`:idx:

+     `posix.html#510 <posix.html#510>`_

+

+   `PC_REC_MIN_XFER_SIZE`:idx:

+     `posix.html#511 <posix.html#511>`_

+

+   `PC_REC_XFER_ALIGN`:idx:

+     `posix.html#512 <posix.html#512>`_

+

+   `PC_SYMLINK_MAX`:idx:

+     `posix.html#513 <posix.html#513>`_

+

+   `PC_SYNC_IO`:idx:

+     `posix.html#514 <posix.html#514>`_

+

+   `PC_VDISABLE`:idx:

+     `posix.html#515 <posix.html#515>`_

+

    `PFloat32`:idx:

      `system.html#269 <system.html#269>`_

 

@@ -998,33 +2587,597 @@ Index
    `PInt64`:idx:

      `system.html#271 <system.html#271>`_

 

+   `pipe`:idx:

+     `posix.html#1008 <posix.html#1008>`_

+

+   `PM_STR`:idx:

+     `posix.html#392 <posix.html#392>`_

+

    `PObject`:idx:

-     `system.html#117 <system.html#117>`_

+     `system.html#116 <system.html#116>`_

 

    `pointers`:idx:

-     `manual.html#159 <manual.html#159>`_

+     `manual.html#158 <manual.html#158>`_

 

    `Positive`:idx:

-     `system.html#115 <system.html#115>`_

+     `system.html#114 <system.html#114>`_

+

+   `POSIX_ASYNC_IO`:idx:

+     `posix.html#472 <posix.html#472>`_

+

+   `POSIX_FADV_DONTNEED`:idx:

+     `posix.html#327 <posix.html#327>`_

+

+   `posix_fadvise`:idx:

+     `posix.html#808 <posix.html#808>`_

+

+   `POSIX_FADV_NOREUSE`:idx:

+     `posix.html#328 <posix.html#328>`_

+

+   `POSIX_FADV_NORMAL`:idx:

+     `posix.html#323 <posix.html#323>`_

+

+   `POSIX_FADV_RANDOM`:idx:

+     `posix.html#325 <posix.html#325>`_

+

+   `POSIX_FADV_SEQUENTIAL`:idx:

+     `posix.html#324 <posix.html#324>`_

+

+   `POSIX_FADV_WILLNEED`:idx:

+     `posix.html#326 <posix.html#326>`_

+

+   `posix_fallocate`:idx:

+     `posix.html#809 <posix.html#809>`_

+

+   `POSIX_MADV_DONTNEED`:idx:

+     `posix.html#688 <posix.html#688>`_

+

+   `posix_madvise`:idx:

+     `posix.html#1079 <posix.html#1079>`_

+

+   `POSIX_MADV_NORMAL`:idx:

+     `posix.html#684 <posix.html#684>`_

+

+   `POSIX_MADV_RANDOM`:idx:

+     `posix.html#686 <posix.html#686>`_

+

+   `POSIX_MADV_SEQUENTIAL`:idx:

+     `posix.html#685 <posix.html#685>`_

+

+   `POSIX_MADV_WILLNEED`:idx:

+     `posix.html#687 <posix.html#687>`_

+

+   `posix_mem_offset`:idx:

+     `posix.html#1080 <posix.html#1080>`_

+

+   `POSIX_PRIO_IO`:idx:

+     `posix.html#473 <posix.html#473>`_

+

+   `posix_spawn`:idx:

+     `posix.html#1160 <posix.html#1160>`_

+

+   `posix_spawnattr_destroy`:idx:

+     `posix.html#1166 <posix.html#1166>`_

+

+   `posix_spawnattr_getflags`:idx:

+     `posix.html#1168 <posix.html#1168>`_

+

+   `posix_spawnattr_getpgroup`:idx:

+     `posix.html#1169 <posix.html#1169>`_

+

+   `posix_spawnattr_getschedparam`:idx:

+     `posix.html#1170 <posix.html#1170>`_

+

+   `posix_spawnattr_getschedpolicy`:idx:

+     `posix.html#1171 <posix.html#1171>`_

+

+   `posix_spawnattr_getsigdefault`:idx:

+     `posix.html#1167 <posix.html#1167>`_

+

+   `posix_spawnattr_getsigmask`:idx:

+     `posix.html#1172 <posix.html#1172>`_

+

+   `posix_spawnattr_init`:idx:

+     `posix.html#1173 <posix.html#1173>`_

+

+   `posix_spawnattr_setflags`:idx:

+     `posix.html#1175 <posix.html#1175>`_

+

+   `posix_spawnattr_setpgroup`:idx:

+     `posix.html#1176 <posix.html#1176>`_

+

+   `posix_spawnattr_setschedparam`:idx:

+     `posix.html#1177 <posix.html#1177>`_

+

+   `posix_spawnattr_setschedpolicy`:idx:

+     `posix.html#1178 <posix.html#1178>`_

+

+   `posix_spawnattr_setsigdefault`:idx:

+     `posix.html#1174 <posix.html#1174>`_

+

+   `posix_spawnattr_setsigmask`:idx:

+     `posix.html#1179 <posix.html#1179>`_

+

+   `posix_spawn_file_actions_addclose`:idx:

+     `posix.html#1161 <posix.html#1161>`_

+

+   `posix_spawn_file_actions_adddup2`:idx:

+     `posix.html#1162 <posix.html#1162>`_

+

+   `posix_spawn_file_actions_addopen`:idx:

+     `posix.html#1163 <posix.html#1163>`_

+

+   `posix_spawn_file_actions_destroy`:idx:

+     `posix.html#1164 <posix.html#1164>`_

+

+   `posix_spawn_file_actions_init`:idx:

+     `posix.html#1165 <posix.html#1165>`_

+

+   `posix_spawnp`:idx:

+     `posix.html#1180 <posix.html#1180>`_

+

+   `POSIX_SPAWN_RESETIDS`:idx:

+     `posix.html#772 <posix.html#772>`_

+

+   `POSIX_SPAWN_SETPGROUP`:idx:

+     `posix.html#773 <posix.html#773>`_

+

+   `POSIX_SPAWN_SETSCHEDPARAM`:idx:

+     `posix.html#774 <posix.html#774>`_

+

+   `POSIX_SPAWN_SETSCHEDULER`:idx:

+     `posix.html#775 <posix.html#775>`_

+

+   `POSIX_SPAWN_SETSIGDEF`:idx:

+     `posix.html#776 <posix.html#776>`_

+

+   `POSIX_SPAWN_SETSIGMASK`:idx:

+     `posix.html#777 <posix.html#777>`_

+

+   `POSIX_SYNC_IO`:idx:

+     `posix.html#474 <posix.html#474>`_

+

+   `POSIX_TYPED_MEM_ALLOCATE`:idx:

+     `posix.html#689 <posix.html#689>`_

+

+   `POSIX_TYPED_MEM_ALLOCATE_CONTIG`:idx:

+     `posix.html#690 <posix.html#690>`_

+

+   `posix_typed_mem_get_info`:idx:

+     `posix.html#1081 <posix.html#1081>`_

+

+   `POSIX_TYPED_MEM_MAP_ALLOCATABLE`:idx:

+     `posix.html#691 <posix.html#691>`_

+

+   `posix_typed_mem_open`:idx:

+     `posix.html#1082 <posix.html#1082>`_

 

    `pow`:idx:

-     `math.html#121 <math.html#121>`_

+     `math.html#125 <math.html#125>`_

+

+   `P_PGID`:idx:

+     `posix.html#715 <posix.html#715>`_

+

+   `P_PID`:idx:

+     `posix.html#714 <posix.html#714>`_

+

+   `pread`:idx:

+     `posix.html#1009 <posix.html#1009>`_

 

    `pred`:idx:

      `system.html#142 <system.html#142>`_

 

    `procedural type`:idx:

-     `manual.html#162 <manual.html#162>`_

+     `manual.html#161 <manual.html#161>`_

 

    `procedures`:idx:

-     `manual.html#201 <manual.html#201>`_

+     `manual.html#200 <manual.html#200>`_

+

+   `PROT_EXEC`:idx:

+     `posix.html#673 <posix.html#673>`_

+

+   `PROT_NONE`:idx:

+     `posix.html#674 <posix.html#674>`_

+

+   `PROT_READ`:idx:

+     `posix.html#671 <posix.html#671>`_

+

+   `PROT_WRITE`:idx:

+     `posix.html#672 <posix.html#672>`_

+

+   `pselect`:idx:

+     `posix.html#1158 <posix.html#1158>`_

+

+   `PStringTable`:idx:

+     `strtabs.html#103 <strtabs.html#103>`_

+

+   `pthread_atfork`:idx:

+     `posix.html#860 <posix.html#860>`_

+

+   `pthread_attr_destroy`:idx:

+     `posix.html#861 <posix.html#861>`_

+

+   `pthread_attr_getdetachstate`:idx:

+     `posix.html#862 <posix.html#862>`_

+

+   `pthread_attr_getguardsize`:idx:

+     `posix.html#863 <posix.html#863>`_

+

+   `pthread_attr_getinheritsched`:idx:

+     `posix.html#864 <posix.html#864>`_

+

+   `pthread_attr_getschedparam`:idx:

+     `posix.html#865 <posix.html#865>`_

+

+   `pthread_attr_getschedpolicy`:idx:

+     `posix.html#866 <posix.html#866>`_

+

+   `pthread_attr_getscope`:idx:

+     `posix.html#867 <posix.html#867>`_

+

+   `pthread_attr_getstack`:idx:

+     `posix.html#868 <posix.html#868>`_

+

+   `pthread_attr_getstackaddr`:idx:

+     `posix.html#869 <posix.html#869>`_

+

+   `pthread_attr_getstacksize`:idx:

+     `posix.html#870 <posix.html#870>`_

+

+   `pthread_attr_init`:idx:

+     `posix.html#871 <posix.html#871>`_

+

+   `pthread_attr_setdetachstate`:idx:

+     `posix.html#872 <posix.html#872>`_

+

+   `pthread_attr_setguardsize`:idx:

+     `posix.html#873 <posix.html#873>`_

+

+   `pthread_attr_setinheritsched`:idx:

+     `posix.html#874 <posix.html#874>`_

+

+   `pthread_attr_setschedparam`:idx:

+     `posix.html#875 <posix.html#875>`_

+

+   `pthread_attr_setschedpolicy`:idx:

+     `posix.html#876 <posix.html#876>`_

+

+   `pthread_attr_setscope`:idx:

+     `posix.html#877 <posix.html#877>`_

+

+   `pthread_attr_setstack`:idx:

+     `posix.html#878 <posix.html#878>`_

+

+   `pthread_attr_setstackaddr`:idx:

+     `posix.html#879 <posix.html#879>`_

+

+   `pthread_attr_setstacksize`:idx:

+     `posix.html#880 <posix.html#880>`_

+

+   `pthread_barrierattr_destroy`:idx:

+     `posix.html#884 <posix.html#884>`_

+

+   `pthread_barrierattr_getpshared`:idx:

+     `posix.html#885 <posix.html#885>`_

+

+   `pthread_barrierattr_init`:idx:

+     `posix.html#886 <posix.html#886>`_

+

+   `pthread_barrierattr_setpshared`:idx:

+     `posix.html#887 <posix.html#887>`_

+

+   `pthread_barrier_destroy`:idx:

+     `posix.html#881 <posix.html#881>`_

+

+   `pthread_barrier_init`:idx:

+     `posix.html#882 <posix.html#882>`_

+

+   `PTHREAD_BARRIER_SERIAL_THREAD`:idx:

+     `posix.html#448 <posix.html#448>`_

+

+   `pthread_barrier_wait`:idx:

+     `posix.html#883 <posix.html#883>`_

+

+   `pthread_cancel`:idx:

+     `posix.html#888 <posix.html#888>`_

+

+   `PTHREAD_CANCEL_ASYNCHRONOUS`:idx:

+     `posix.html#449 <posix.html#449>`_

+

+   `PTHREAD_CANCEL_DEFERRED`:idx:

+     `posix.html#451 <posix.html#451>`_

+

+   `PTHREAD_CANCEL_DISABLE`:idx:

+     `posix.html#452 <posix.html#452>`_

+

+   `PTHREAD_CANCELED`:idx:

+     `posix.html#453 <posix.html#453>`_

+

+   `PTHREAD_CANCEL_ENABLE`:idx:

+     `posix.html#450 <posix.html#450>`_

+

+   `pthread_cleanup_pop`:idx:

+     `posix.html#890 <posix.html#890>`_

+

+   `pthread_cleanup_push`:idx:

+     `posix.html#889 <posix.html#889>`_

+

+   `pthread_condattr_destroy`:idx:

+     `posix.html#897 <posix.html#897>`_

+

+   `pthread_condattr_getclock`:idx:

+     `posix.html#898 <posix.html#898>`_

+

+   `pthread_condattr_getpshared`:idx:

+     `posix.html#899 <posix.html#899>`_

+

+   `pthread_condattr_init`:idx:

+     `posix.html#900 <posix.html#900>`_

+

+   `pthread_condattr_setclock`:idx:

+     `posix.html#901 <posix.html#901>`_

+

+   `pthread_condattr_setpshared`:idx:

+     `posix.html#902 <posix.html#902>`_

+

+   `pthread_cond_broadcast`:idx:

+     `posix.html#891 <posix.html#891>`_

+

+   `pthread_cond_destroy`:idx:

+     `posix.html#892 <posix.html#892>`_

+

+   `pthread_cond_init`:idx:

+     `posix.html#893 <posix.html#893>`_

+

+   `PTHREAD_COND_INITIALIZER`:idx:

+     `posix.html#454 <posix.html#454>`_

+

+   `pthread_cond_signal`:idx:

+     `posix.html#894 <posix.html#894>`_

+

+   `pthread_cond_timedwait`:idx:

+     `posix.html#895 <posix.html#895>`_

+

+   `pthread_cond_wait`:idx:

+     `posix.html#896 <posix.html#896>`_

+

+   `pthread_create`:idx:

+     `posix.html#903 <posix.html#903>`_

+

+   `PTHREAD_CREATE_DETACHED`:idx:

+     `posix.html#455 <posix.html#455>`_

+

+   `PTHREAD_CREATE_JOINABLE`:idx:

+     `posix.html#456 <posix.html#456>`_

+

+   `pthread_detach`:idx:

+     `posix.html#904 <posix.html#904>`_

+

+   `pthread_equal`:idx:

+     `posix.html#905 <posix.html#905>`_

+

+   `pthread_exit`:idx:

+     `posix.html#906 <posix.html#906>`_

+

+   `PTHREAD_EXPLICIT_SCHED`:idx:

+     `posix.html#457 <posix.html#457>`_

+

+   `pthread_getconcurrency`:idx:

+     `posix.html#907 <posix.html#907>`_

+

+   `pthread_getcpuclockid`:idx:

+     `posix.html#908 <posix.html#908>`_

+

+   `pthread_getschedparam`:idx:

+     `posix.html#909 <posix.html#909>`_

+

+   `pthread_getspecific`:idx:

+     `posix.html#910 <posix.html#910>`_

+

+   `PTHREAD_INHERIT_SCHED`:idx:

+     `posix.html#458 <posix.html#458>`_

+

+   `pthread_join`:idx:

+     `posix.html#911 <posix.html#911>`_

+

+   `pthread_key_create`:idx:

+     `posix.html#912 <posix.html#912>`_

+

+   `pthread_key_delete`:idx:

+     `posix.html#913 <posix.html#913>`_

+

+   `pthread_kill`:idx:

+     `posix.html#1118 <posix.html#1118>`_

+

+   `pthread_mutexattr_destroy`:idx:

+     `posix.html#922 <posix.html#922>`_

+

+   `pthread_mutexattr_getprioceiling`:idx:

+     `posix.html#923 <posix.html#923>`_

+

+   `pthread_mutexattr_getprotocol`:idx:

+     `posix.html#924 <posix.html#924>`_

+

+   `pthread_mutexattr_getpshared`:idx:

+     `posix.html#925 <posix.html#925>`_

+

+   `pthread_mutexattr_gettype`:idx:

+     `posix.html#926 <posix.html#926>`_

+

+   `pthread_mutexattr_init`:idx:

+     `posix.html#927 <posix.html#927>`_

+

+   `pthread_mutexattr_setprioceiling`:idx:

+     `posix.html#928 <posix.html#928>`_

+

+   `pthread_mutexattr_setprotocol`:idx:

+     `posix.html#929 <posix.html#929>`_

+

+   `pthread_mutexattr_setpshared`:idx:

+     `posix.html#930 <posix.html#930>`_

+

+   `pthread_mutexattr_settype`:idx:

+     `posix.html#931 <posix.html#931>`_

+

+   `PTHREAD_MUTEX_DEFAULT`:idx:

+     `posix.html#459 <posix.html#459>`_

+

+   `pthread_mutex_destroy`:idx:

+     `posix.html#914 <posix.html#914>`_

+

+   `PTHREAD_MUTEX_ERRORCHECK`:idx:

+     `posix.html#460 <posix.html#460>`_

+

+   `pthread_mutex_getprioceiling`:idx:

+     `posix.html#915 <posix.html#915>`_

+

+   `pthread_mutex_init`:idx:

+     `posix.html#916 <posix.html#916>`_

+

+   `PTHREAD_MUTEX_INITIALIZER`:idx:

+     `posix.html#461 <posix.html#461>`_

+

+   `pthread_mutex_lock`:idx:

+     `posix.html#917 <posix.html#917>`_

+

+   `PTHREAD_MUTEX_NORMAL`:idx:

+     `posix.html#462 <posix.html#462>`_

+

+   `PTHREAD_MUTEX_RECURSIVE`:idx:

+     `posix.html#463 <posix.html#463>`_

+

+   `pthread_mutex_setprioceiling`:idx:

+     `posix.html#918 <posix.html#918>`_

+

+   `pthread_mutex_timedlock`:idx:

+     `posix.html#919 <posix.html#919>`_

+

+   `pthread_mutex_trylock`:idx:

+     `posix.html#920 <posix.html#920>`_

+

+   `pthread_mutex_unlock`:idx:

+     `posix.html#921 <posix.html#921>`_

+

+   `pthread_once`:idx:

+     `posix.html#932 <posix.html#932>`_

+

+   `PTHREAD_ONCE_INIT`:idx:

+     `posix.html#464 <posix.html#464>`_

+

+   `PTHREAD_PRIO_INHERIT`:idx:

+     `posix.html#465 <posix.html#465>`_

+

+   `PTHREAD_PRIO_NONE`:idx:

+     `posix.html#466 <posix.html#466>`_

+

+   `PTHREAD_PRIO_PROTECT`:idx:

+     `posix.html#467 <posix.html#467>`_

+

+   `PTHREAD_PROCESS_PRIVATE`:idx:

+     `posix.html#469 <posix.html#469>`_

+

+   `PTHREAD_PROCESS_SHARED`:idx:

+     `posix.html#468 <posix.html#468>`_

+

+   `pthread_rwlockattr_destroy`:idx:

+     `posix.html#942 <posix.html#942>`_

+

+   `pthread_rwlockattr_getpshared`:idx:

+     `posix.html#943 <posix.html#943>`_

+

+   `pthread_rwlockattr_init`:idx:

+     `posix.html#944 <posix.html#944>`_

+

+   `pthread_rwlockattr_setpshared`:idx:

+     `posix.html#945 <posix.html#945>`_

+

+   `pthread_rwlock_destroy`:idx:

+     `posix.html#933 <posix.html#933>`_

+

+   `pthread_rwlock_init`:idx:

+     `posix.html#934 <posix.html#934>`_

+

+   `pthread_rwlock_rdlock`:idx:

+     `posix.html#935 <posix.html#935>`_

+

+   `pthread_rwlock_timedrdlock`:idx:

+     `posix.html#936 <posix.html#936>`_

+

+   `pthread_rwlock_timedwrlock`:idx:

+     `posix.html#937 <posix.html#937>`_

+

+   `pthread_rwlock_tryrdlock`:idx:

+     `posix.html#938 <posix.html#938>`_

+

+   `pthread_rwlock_trywrlock`:idx:

+     `posix.html#939 <posix.html#939>`_

+

+   `pthread_rwlock_unlock`:idx:

+     `posix.html#940 <posix.html#940>`_

+

+   `pthread_rwlock_wrlock`:idx:

+     `posix.html#941 <posix.html#941>`_

+

+   `PTHREAD_SCOPE_PROCESS`:idx:

+     `posix.html#470 <posix.html#470>`_

+

+   `PTHREAD_SCOPE_SYSTEM`:idx:

+     `posix.html#471 <posix.html#471>`_

+

+   `pthread_self`:idx:

+     `posix.html#946 <posix.html#946>`_

+

+   `pthread_setcancelstate`:idx:

+     `posix.html#947 <posix.html#947>`_

+

+   `pthread_setcanceltype`:idx:

+     `posix.html#948 <posix.html#948>`_

+

+   `pthread_setconcurrency`:idx:

+     `posix.html#949 <posix.html#949>`_

+

+   `pthread_setschedparam`:idx:

+     `posix.html#950 <posix.html#950>`_

+

+   `pthread_setschedprio`:idx:

+     `posix.html#951 <posix.html#951>`_

+

+   `pthread_setspecific`:idx:

+     `posix.html#952 <posix.html#952>`_

+

+   `pthread_sigmask`:idx:

+     `posix.html#1119 <posix.html#1119>`_

+

+   `pthread_spin_destroy`:idx:

+     `posix.html#953 <posix.html#953>`_

+

+   `pthread_spin_init`:idx:

+     `posix.html#954 <posix.html#954>`_

+

+   `pthread_spin_lock`:idx:

+     `posix.html#955 <posix.html#955>`_

+

+   `pthread_spin_trylock`:idx:

+     `posix.html#956 <posix.html#956>`_

+

+   `pthread_spin_unlock`:idx:

+     `posix.html#957 <posix.html#957>`_

+

+   `pthread_testcancel`:idx:

+     `posix.html#958 <posix.html#958>`_

 

    `push/pop`:idx:

-     `manual.html#230 <manual.html#230>`_

+     `manual.html#229 <manual.html#229>`_

 

    `putEnv`:idx:

      `os.html#139 <os.html#139>`_

 

+   `PWindow`:idx:

+     `dialogs.html#101 <dialogs.html#101>`_

+

+   `pwrite`:idx:

+     `posix.html#1010 <posix.html#1010>`_

+

    `quit`:idx:

      `system.html#286 <system.html#286>`_

 

@@ -1037,44 +3190,62 @@ Index
    `quotation mark`:idx:

      `manual.html#128 <manual.html#128>`_

 

+   `quoteIfSpaceExists`:idx:

+     `strutils.html#135 <strutils.html#135>`_

+

+   `RADIXCHAR`:idx:

+     `posix.html#436 <posix.html#436>`_

+

+   `raise`:idx:

+     `posix.html#1120 <posix.html#1120>`_

+

    `random`:idx:

-     `math.html#104 <math.html#104>`_

+     `math.html#106 <math.html#106>`_

 

    `randomize`:idx:

-     `math.html#105 <math.html#105>`_

+     `math.html#107 <math.html#107>`_

 

    `range`:idx:

      `system.html#107 <system.html#107>`_

 

    `re-raised`:idx:

-     `manual.html#185 <manual.html#185>`_

+     `manual.html#184 <manual.html#184>`_

+

+   `read`:idx:

+     `posix.html#1011 <posix.html#1011>`_

 

    `readBuffer`:idx:

-     `system.html#384 <system.html#384>`_

+     `system.html#396 <system.html#396>`_

 

    `ReadBytes`:idx:

-     `system.html#382 <system.html#382>`_

+     `system.html#394 <system.html#394>`_

 

    `readChar`:idx:

-     `system.html#369 <system.html#369>`_

+     `system.html#380 <system.html#380>`_

 

    `ReadChars`:idx:

-     `system.html#383 <system.html#383>`_

+     `system.html#395 <system.html#395>`_

+

+   `readdir`:idx:

+     `posix.html#796 <posix.html#796>`_

+

+   `readdir_r`:idx:

+     `posix.html#797 <posix.html#797>`_

 

    `readFile`:idx:

-     `system.html#371 <system.html#371>`_

+     `system.html#382 <system.html#382>`_

 

    `readLine`:idx:

-     `system.html#378 <system.html#378>`_

+     `system.html#390 <system.html#390>`_

+

+   `readlink`:idx:

+     `posix.html#1012 <posix.html#1012>`_

 

    `realloc`:idx:

      `system.html#298 <system.html#298>`_

 

-   `record`:idx:

-     `manual.html#155 <manual.html#155>`_

-

    `Recursive module dependancies`:idx:

-     `manual.html#218 <manual.html#218>`_

+     `manual.html#217 <manual.html#217>`_

 

    `register`:idx:

      `nimrodc.html#110 <nimrodc.html#110>`_

@@ -1086,7 +3257,7 @@ Index
      `os.html#133 <os.html#133>`_

 

    `repeatChar`:idx:

-     `strutils.html#130 <strutils.html#130>`_

+     `strutils.html#131 <strutils.html#131>`_

 

    `replaceStr`:idx:

      `strutils.html#114 <strutils.html#114>`_

@@ -1095,31 +3266,520 @@ Index
      `system.html#254 <system.html#254>`_

 

    `result`:idx:

-     * `manual.html#192 <manual.html#192>`_

-     * `manual.html#203 <manual.html#203>`_

+     * `manual.html#191 <manual.html#191>`_

+     * `manual.html#202 <manual.html#202>`_

 

    `return`:idx:

-     `manual.html#191 <manual.html#191>`_

+     `manual.html#190 <manual.html#190>`_

+

+   `rewinddir`:idx:

+     `posix.html#798 <posix.html#798>`_

+

+   `rmdir`:idx:

+     `posix.html#1013 <posix.html#1013>`_

+

+   `R_OK`:idx:

+     `posix.html#476 <posix.html#476>`_

+

+   `round`:idx:

+     `math.html#114 <math.html#114>`_

+

+   `RTLD_GLOBAL`:idx:

+     `posix.html#214 <posix.html#214>`_

+

+   `RTLD_LAZY`:idx:

+     `posix.html#212 <posix.html#212>`_

+

+   `RTLD_LOCAL`:idx:

+     `posix.html#215 <posix.html#215>`_

+

+   `RTLD_NOW`:idx:

+     `posix.html#213 <posix.html#213>`_

 

    `safe`:idx:

      `manual.html#112 <manual.html#112>`_

 

    `safecall`:idx:

-     `manual.html#167 <manual.html#167>`_

+     `manual.html#166 <manual.html#166>`_

 

    `sameFile`:idx:

      `os.html#144 <os.html#144>`_

 

+   `SA_NOCLDSTOP`:idx:

+     `posix.html#751 <posix.html#751>`_

+

+   `SA_NOCLDWAIT`:idx:

+     `posix.html#759 <posix.html#759>`_

+

+   `SA_NODEFER`:idx:

+     `posix.html#760 <posix.html#760>`_

+

+   `SA_ONSTACK`:idx:

+     `posix.html#755 <posix.html#755>`_

+

+   `SA_RESETHAND`:idx:

+     `posix.html#756 <posix.html#756>`_

+

+   `SA_RESTART`:idx:

+     `posix.html#757 <posix.html#757>`_

+

+   `SA_SIGINFO`:idx:

+     `posix.html#758 <posix.html#758>`_

+

+   `SC_2_C_BIND`:idx:

+     `posix.html#516 <posix.html#516>`_

+

+   `SC_2_C_DEV`:idx:

+     `posix.html#517 <posix.html#517>`_

+

+   `SC_2_CHAR_TERM`:idx:

+     `posix.html#518 <posix.html#518>`_

+

+   `SC_2_FORT_DEV`:idx:

+     `posix.html#519 <posix.html#519>`_

+

+   `SC_2_FORT_RUN`:idx:

+     `posix.html#520 <posix.html#520>`_

+

+   `SC_2_LOCALEDEF`:idx:

+     `posix.html#521 <posix.html#521>`_

+

+   `SC_2_PBS`:idx:

+     `posix.html#522 <posix.html#522>`_

+

+   `SC_2_PBS_ACCOUNTING`:idx:

+     `posix.html#523 <posix.html#523>`_

+

+   `SC_2_PBS_CHECKPOINT`:idx:

+     `posix.html#524 <posix.html#524>`_

+

+   `SC_2_PBS_LOCATE`:idx:

+     `posix.html#525 <posix.html#525>`_

+

+   `SC_2_PBS_MESSAGE`:idx:

+     `posix.html#526 <posix.html#526>`_

+

+   `SC_2_PBS_TRACK`:idx:

+     `posix.html#527 <posix.html#527>`_

+

+   `SC_2_SW_DEV`:idx:

+     `posix.html#528 <posix.html#528>`_

+

+   `SC_2_UPE`:idx:

+     `posix.html#529 <posix.html#529>`_

+

+   `SC_2_VERSION`:idx:

+     `posix.html#530 <posix.html#530>`_

+

+   `SC_ADVISORY_INFO`:idx:

+     `posix.html#531 <posix.html#531>`_

+

+   `SC_AIO_LISTIO_MAX`:idx:

+     `posix.html#532 <posix.html#532>`_

+

+   `SC_AIO_MAX`:idx:

+     `posix.html#533 <posix.html#533>`_

+

+   `SC_AIO_PRIO_DELTA_MAX`:idx:

+     `posix.html#534 <posix.html#534>`_

+

+   `SC_ARG_MAX`:idx:

+     `posix.html#535 <posix.html#535>`_

+

+   `SC_ASYNCHRONOUS_IO`:idx:

+     `posix.html#536 <posix.html#536>`_

+

+   `SC_ATEXIT_MAX`:idx:

+     `posix.html#537 <posix.html#537>`_

+

+   `SC_BARRIERS`:idx:

+     `posix.html#538 <posix.html#538>`_

+

+   `SC_BC_BASE_MAX`:idx:

+     `posix.html#539 <posix.html#539>`_

+

+   `SC_BC_DIM_MAX`:idx:

+     `posix.html#540 <posix.html#540>`_

+

+   `SC_BC_SCALE_MAX`:idx:

+     `posix.html#541 <posix.html#541>`_

+

+   `SC_BC_STRING_MAX`:idx:

+     `posix.html#542 <posix.html#542>`_

+

+   `SC_CHILD_MAX`:idx:

+     `posix.html#543 <posix.html#543>`_

+

+   `SC_CLK_TCK`:idx:

+     `posix.html#544 <posix.html#544>`_

+

+   `SC_CLOCK_SELECTION`:idx:

+     `posix.html#545 <posix.html#545>`_

+

+   `SC_COLL_WEIGHTS_MAX`:idx:

+     `posix.html#546 <posix.html#546>`_

+

+   `SC_CPUTIME`:idx:

+     `posix.html#547 <posix.html#547>`_

+

+   `SC_DELAYTIMER_MAX`:idx:

+     `posix.html#548 <posix.html#548>`_

+

+   `SC_EXPR_NEST_MAX`:idx:

+     `posix.html#549 <posix.html#549>`_

+

+   `SC_FSYNC`:idx:

+     `posix.html#550 <posix.html#550>`_

+

+   `SC_GETGR_R_SIZE_MAX`:idx:

+     `posix.html#551 <posix.html#551>`_

+

+   `SC_GETPW_R_SIZE_MAX`:idx:

+     `posix.html#552 <posix.html#552>`_

+

+   `SCHED_FIFO`:idx:

+     `posix.html#767 <posix.html#767>`_

+

+   `sched_getparam`:idx:

+     `posix.html#1147 <posix.html#1147>`_

+

+   `sched_get_priority_max`:idx:

+     `posix.html#1145 <posix.html#1145>`_

+

+   `sched_get_priority_min`:idx:

+     `posix.html#1146 <posix.html#1146>`_

+

+   `sched_getscheduler`:idx:

+     `posix.html#1148 <posix.html#1148>`_

+

+   `SCHED_OTHER`:idx:

+     `posix.html#770 <posix.html#770>`_

+

+   `SCHED_RR`:idx:

+     `posix.html#768 <posix.html#768>`_

+

+   `sched_rr_get_interval`:idx:

+     `posix.html#1149 <posix.html#1149>`_

+

+   `sched_setparam`:idx:

+     `posix.html#1150 <posix.html#1150>`_

+

+   `sched_setscheduler`:idx:

+     `posix.html#1151 <posix.html#1151>`_

+

+   `SCHED_SPORADIC`:idx:

+     `posix.html#769 <posix.html#769>`_

+

+   `sched_yield`:idx:

+     `posix.html#1152 <posix.html#1152>`_

+

+   `SC_HOST_NAME_MAX`:idx:

+     `posix.html#553 <posix.html#553>`_

+

+   `SC_IOV_MAX`:idx:

+     `posix.html#554 <posix.html#554>`_

+

+   `SC_IPV6`:idx:

+     `posix.html#555 <posix.html#555>`_

+

+   `SC_JOB_CONTROL`:idx:

+     `posix.html#556 <posix.html#556>`_

+

+   `SC_LINE_MAX`:idx:

+     `posix.html#557 <posix.html#557>`_

+

+   `SC_LOGIN_NAME_MAX`:idx:

+     `posix.html#558 <posix.html#558>`_

+

+   `SC_MAPPED_FILES`:idx:

+     `posix.html#559 <posix.html#559>`_

+

+   `SC_MEMLOCK`:idx:

+     `posix.html#560 <posix.html#560>`_

+

+   `SC_MEMLOCK_RANGE`:idx:

+     `posix.html#561 <posix.html#561>`_

+

+   `SC_MEMORY_PROTECTION`:idx:

+     `posix.html#562 <posix.html#562>`_

+

+   `SC_MESSAGE_PASSING`:idx:

+     `posix.html#563 <posix.html#563>`_

+

+   `SC_MONOTONIC_CLOCK`:idx:

+     `posix.html#564 <posix.html#564>`_

+

+   `SC_MQ_OPEN_MAX`:idx:

+     `posix.html#565 <posix.html#565>`_

+

+   `SC_MQ_PRIO_MAX`:idx:

+     `posix.html#566 <posix.html#566>`_

+

+   `SC_NGROUPS_MAX`:idx:

+     `posix.html#567 <posix.html#567>`_

+

    `scope`:idx:

      * `manual.html#106 <manual.html#106>`_

-     * `manual.html#219 <manual.html#219>`_

+     * `manual.html#218 <manual.html#218>`_

+

+   `SC_OPEN_MAX`:idx:

+     `posix.html#568 <posix.html#568>`_

+

+   `SC_PAGE_SIZE`:idx:

+     `posix.html#569 <posix.html#569>`_

+

+   `SC_PRIORITIZED_IO`:idx:

+     `posix.html#570 <posix.html#570>`_

+

+   `SC_PRIORITY_SCHEDULING`:idx:

+     `posix.html#571 <posix.html#571>`_

+

+   `SC_RAW_SOCKETS`:idx:

+     `posix.html#572 <posix.html#572>`_

+

+   `SC_READER_WRITER_LOCKS`:idx:

+     `posix.html#574 <posix.html#574>`_

+

+   `SC_REALTIME_SIGNALS`:idx:

+     `posix.html#575 <posix.html#575>`_

+

+   `SC_RE_DUP_MAX`:idx:

+     `posix.html#573 <posix.html#573>`_

+

+   `SC_REGEXP`:idx:

+     `posix.html#576 <posix.html#576>`_

+

+   `SC_RTSIG_MAX`:idx:

+     `posix.html#577 <posix.html#577>`_

+

+   `SC_SAVED_IDS`:idx:

+     `posix.html#578 <posix.html#578>`_

+

+   `SC_SEMAPHORES`:idx:

+     `posix.html#581 <posix.html#581>`_

+

+   `SC_SEM_NSEMS_MAX`:idx:

+     `posix.html#579 <posix.html#579>`_

+

+   `SC_SEM_VALUE_MAX`:idx:

+     `posix.html#580 <posix.html#580>`_

+

+   `SC_SHARED_MEMORY_OBJECTS`:idx:

+     `posix.html#582 <posix.html#582>`_

+

+   `SC_SHELL`:idx:

+     `posix.html#583 <posix.html#583>`_

+

+   `SC_SIGQUEUE_MAX`:idx:

+     `posix.html#584 <posix.html#584>`_

+

+   `SC_SPAWN`:idx:

+     `posix.html#585 <posix.html#585>`_

+

+   `SC_SPIN_LOCKS`:idx:

+     `posix.html#586 <posix.html#586>`_

+

+   `SC_SPORADIC_SERVER`:idx:

+     `posix.html#587 <posix.html#587>`_

+

+   `SC_SS_REPL_MAX`:idx:

+     `posix.html#588 <posix.html#588>`_

+

+   `SC_STREAM_MAX`:idx:

+     `posix.html#589 <posix.html#589>`_

+

+   `SC_SYMLOOP_MAX`:idx:

+     `posix.html#590 <posix.html#590>`_

+

+   `SC_SYNCHRONIZED_IO`:idx:

+     `posix.html#591 <posix.html#591>`_

+

+   `SC_THREAD_ATTR_STACKADDR`:idx:

+     `posix.html#592 <posix.html#592>`_

+

+   `SC_THREAD_ATTR_STACKSIZE`:idx:

+     `posix.html#593 <posix.html#593>`_

+

+   `SC_THREAD_CPUTIME`:idx:

+     `posix.html#594 <posix.html#594>`_

+

+   `SC_THREAD_DESTRUCTOR_ITERATIONS`:idx:

+     `posix.html#595 <posix.html#595>`_

+

+   `SC_THREAD_KEYS_MAX`:idx:

+     `posix.html#596 <posix.html#596>`_

+

+   `SC_THREAD_PRIO_INHERIT`:idx:

+     `posix.html#597 <posix.html#597>`_

+

+   `SC_THREAD_PRIO_PROTECT`:idx:

+     `posix.html#598 <posix.html#598>`_

+

+   `SC_THREAD_PRIORITY_SCHEDULING`:idx:

+     `posix.html#599 <posix.html#599>`_

+

+   `SC_THREAD_PROCESS_SHARED`:idx:

+     `posix.html#600 <posix.html#600>`_

+

+   `SC_THREADS`:idx:

+     `posix.html#605 <posix.html#605>`_

+

+   `SC_THREAD_SAFE_FUNCTIONS`:idx:

+     `posix.html#601 <posix.html#601>`_

+

+   `SC_THREAD_SPORADIC_SERVER`:idx:

+     `posix.html#602 <posix.html#602>`_

+

+   `SC_THREAD_STACK_MIN`:idx:

+     `posix.html#603 <posix.html#603>`_

+

+   `SC_THREAD_THREADS_MAX`:idx:

+     `posix.html#604 <posix.html#604>`_

+

+   `SC_TIMEOUTS`:idx:

+     `posix.html#606 <posix.html#606>`_

+

+   `SC_TIMER_MAX`:idx:

+     `posix.html#607 <posix.html#607>`_

+

+   `SC_TIMERS`:idx:

+     `posix.html#608 <posix.html#608>`_

+

+   `SC_TRACE`:idx:

+     `posix.html#609 <posix.html#609>`_

+

+   `SC_TRACE_EVENT_FILTER`:idx:

+     `posix.html#610 <posix.html#610>`_

+

+   `SC_TRACE_EVENT_NAME_MAX`:idx:

+     `posix.html#611 <posix.html#611>`_

+

+   `SC_TRACE_INHERIT`:idx:

+     `posix.html#612 <posix.html#612>`_

+

+   `SC_TRACE_LOG`:idx:

+     `posix.html#613 <posix.html#613>`_

+

+   `SC_TRACE_NAME_MAX`:idx:

+     `posix.html#614 <posix.html#614>`_

+

+   `SC_TRACE_SYS_MAX`:idx:

+     `posix.html#615 <posix.html#615>`_

+

+   `SC_TRACE_USER_EVENT_MAX`:idx:

+     `posix.html#616 <posix.html#616>`_

+

+   `SC_TTY_NAME_MAX`:idx:

+     `posix.html#617 <posix.html#617>`_

+

+   `SC_TYPED_MEMORY_OBJECTS`:idx:

+     `posix.html#618 <posix.html#618>`_

+

+   `SC_TZNAME_MAX`:idx:

+     `posix.html#619 <posix.html#619>`_

+

+   `SC_V6_ILP32_OFF32`:idx:

+     `posix.html#620 <posix.html#620>`_

+

+   `SC_V6_ILP32_OFFBIG`:idx:

+     `posix.html#621 <posix.html#621>`_

+

+   `SC_V6_LP64_OFF64`:idx:

+     `posix.html#622 <posix.html#622>`_

+

+   `SC_V6_LPBIG_OFFBIG`:idx:

+     `posix.html#623 <posix.html#623>`_

+

+   `SC_VERSION`:idx:

+     `posix.html#624 <posix.html#624>`_

+

+   `SC_XBS5_ILP32_OFF32`:idx:

+     `posix.html#625 <posix.html#625>`_

+

+   `SC_XBS5_ILP32_OFFBIG`:idx:

+     `posix.html#626 <posix.html#626>`_

+

+   `SC_XBS5_LP64_OFF64`:idx:

+     `posix.html#627 <posix.html#627>`_

+

+   `SC_XBS5_LPBIG_OFFBIG`:idx:

+     `posix.html#628 <posix.html#628>`_

+

+   `SC_XOPEN_CRYPT`:idx:

+     `posix.html#629 <posix.html#629>`_

+

+   `SC_XOPEN_ENH_I18N`:idx:

+     `posix.html#630 <posix.html#630>`_

+

+   `SC_XOPEN_LEGACY`:idx:

+     `posix.html#631 <posix.html#631>`_

+

+   `SC_XOPEN_REALTIME`:idx:

+     `posix.html#632 <posix.html#632>`_

+

+   `SC_XOPEN_REALTIME_THREADS`:idx:

+     `posix.html#633 <posix.html#633>`_

+

+   `SC_XOPEN_SHM`:idx:

+     `posix.html#634 <posix.html#634>`_

+

+   `SC_XOPEN_STREAMS`:idx:

+     `posix.html#635 <posix.html#635>`_

+

+   `SC_XOPEN_UNIX`:idx:

+     `posix.html#636 <posix.html#636>`_

+

+   `SC_XOPEN_VERSION`:idx:

+     `posix.html#637 <posix.html#637>`_

+

+   `seekdir`:idx:

+     `posix.html#799 <posix.html#799>`_

+

+   `select`:idx:

+     `posix.html#1159 <posix.html#1159>`_

+

+   `sem_close`:idx:

+     `posix.html#1038 <posix.html#1038>`_

+

+   `sem_destroy`:idx:

+     `posix.html#1039 <posix.html#1039>`_

+

+   `SEM_FAILED`:idx:

+     `posix.html#638 <posix.html#638>`_

+

+   `sem_getvalue`:idx:

+     `posix.html#1040 <posix.html#1040>`_

+

+   `sem_init`:idx:

+     `posix.html#1041 <posix.html#1041>`_

+

+   `sem_open`:idx:

+     `posix.html#1042 <posix.html#1042>`_

+

+   `sem_post`:idx:

+     `posix.html#1043 <posix.html#1043>`_

+

+   `sem_timedwait`:idx:

+     `posix.html#1044 <posix.html#1044>`_

+

+   `sem_trywait`:idx:

+     `posix.html#1045 <posix.html#1045>`_

+

+   `sem_unlink`:idx:

+     `posix.html#1046 <posix.html#1046>`_

+

+   `sem_wait`:idx:

+     `posix.html#1047 <posix.html#1047>`_

 

    `separate compilation`:idx:

-     `manual.html#216 <manual.html#216>`_

+     `manual.html#215 <manual.html#215>`_

 

    `seq`:idx:

      `system.html#110 <system.html#110>`_

 

+   `seqToPtr`:idx:

+     `system.html#362 <system.html#362>`_

+

    `Sequences`:idx:

      `manual.html#154 <manual.html#154>`_

 

@@ -1127,38 +3787,353 @@ Index
      `system.html#111 <system.html#111>`_

 

    `set type`:idx:

-     `manual.html#158 <manual.html#158>`_

+     `manual.html#157 <manual.html#157>`_

+

+   `setcontext`:idx:

+     `posix.html#1183 <posix.html#1183>`_

 

    `setCurrentDir`:idx:

      `os.html#111 <os.html#111>`_

 

+   `setegid`:idx:

+     `posix.html#1014 <posix.html#1014>`_

+

+   `seteuid`:idx:

+     `posix.html#1015 <posix.html#1015>`_

+

    `setFilePos`:idx:

-     `system.html#388 <system.html#388>`_

+     `system.html#400 <system.html#400>`_

+

+   `setgid`:idx:

+     `posix.html#1016 <posix.html#1016>`_

+

+   `setgrent`:idx:

+     `posix.html#833 <posix.html#833>`_

 

    `setLen`:idx:

      * `system.html#290 <system.html#290>`_

      * `system.html#300 <system.html#300>`_

 

+   `setlocale`:idx:

+     `posix.html#841 <posix.html#841>`_

+

+   `setpgid`:idx:

+     `posix.html#1017 <posix.html#1017>`_

+

+   `setpgrp`:idx:

+     `posix.html#1018 <posix.html#1018>`_

+

+   `setpwent`:idx:

+     `posix.html#858 <posix.html#858>`_

+

+   `setregid`:idx:

+     `posix.html#1019 <posix.html#1019>`_

+

+   `setreuid`:idx:

+     `posix.html#1020 <posix.html#1020>`_

+

+   `setsid`:idx:

+     `posix.html#1021 <posix.html#1021>`_

+

+   `setuid`:idx:

+     `posix.html#1022 <posix.html#1022>`_

+

    `shl`:idx:

      * `system.html#163 <system.html#163>`_

      * `system.html#182 <system.html#182>`_

 

+   `shm_open`:idx:

+     `posix.html#1083 <posix.html#1083>`_

+

+   `shm_unlink`:idx:

+     `posix.html#1084 <posix.html#1084>`_

+

    `shr`:idx:

      * `system.html#162 <system.html#162>`_

      * `system.html#181 <system.html#181>`_

 

+   `S_IFBLK`:idx:

+     `posix.html#647 <posix.html#647>`_

+

+   `S_IFCHR`:idx:

+     `posix.html#648 <posix.html#648>`_

+

+   `S_IFDIR`:idx:

+     `posix.html#651 <posix.html#651>`_

+

+   `S_IFIFO`:idx:

+     `posix.html#649 <posix.html#649>`_

+

+   `S_IFLNK`:idx:

+     `posix.html#652 <posix.html#652>`_

+

+   `S_IFMT`:idx:

+     `posix.html#646 <posix.html#646>`_

+

+   `S_IFREG`:idx:

+     `posix.html#650 <posix.html#650>`_

+

+   `S_IFSOCK`:idx:

+     `posix.html#653 <posix.html#653>`_

+

+   `SIGABRT`:idx:

+     `posix.html#723 <posix.html#723>`_

+

+   `sigaction`:idx:

+     `posix.html#1121 <posix.html#1121>`_

+

+   `sigaddset`:idx:

+     `posix.html#1122 <posix.html#1122>`_

+

+   `SIGALRM`:idx:

+     `posix.html#724 <posix.html#724>`_

+

+   `sigaltstack`:idx:

+     `posix.html#1123 <posix.html#1123>`_

+

+   `SIG_BLOCK`:idx:

+     `posix.html#752 <posix.html#752>`_

+

+   `SIGBUS`:idx:

+     `posix.html#725 <posix.html#725>`_

+

+   `SIGCHLD`:idx:

+     `posix.html#726 <posix.html#726>`_

+

+   `SIGCONT`:idx:

+     `posix.html#727 <posix.html#727>`_

+

+   `sigdelset`:idx:

+     `posix.html#1124 <posix.html#1124>`_

+

+   `SIG_DFL`:idx:

+     `posix.html#716 <posix.html#716>`_

+

+   `sigemptyset`:idx:

+     `posix.html#1125 <posix.html#1125>`_

+

+   `SIG_ERR`:idx:

+     `posix.html#717 <posix.html#717>`_

+

+   `SIGEV_NONE`:idx:

+     `posix.html#720 <posix.html#720>`_

+

+   `SIGEV_SIGNAL`:idx:

+     `posix.html#721 <posix.html#721>`_

+

+   `SIGEV_THREAD`:idx:

+     `posix.html#722 <posix.html#722>`_

+

+   `sigfillset`:idx:

+     `posix.html#1126 <posix.html#1126>`_

+

+   `SIGFPE`:idx:

+     `posix.html#728 <posix.html#728>`_

+

+   `sighold`:idx:

+     `posix.html#1127 <posix.html#1127>`_

+

+   `SIGHUP`:idx:

+     `posix.html#729 <posix.html#729>`_

+

+   `SIG_IGN`:idx:

+     `posix.html#719 <posix.html#719>`_

+

+   `sigignore`:idx:

+     `posix.html#1128 <posix.html#1128>`_

+

+   `SIGILL`:idx:

+     `posix.html#730 <posix.html#730>`_

+

+   `SIGINT`:idx:

+     `posix.html#731 <posix.html#731>`_

+

+   `siginterrupt`:idx:

+     `posix.html#1129 <posix.html#1129>`_

+

+   `sigismember`:idx:

+     `posix.html#1130 <posix.html#1130>`_

+

+   `SIGKILL`:idx:

+     `posix.html#732 <posix.html#732>`_

+

+   `signal`:idx:

+     `posix.html#1131 <posix.html#1131>`_

+

+   `sigpause`:idx:

+     `posix.html#1132 <posix.html#1132>`_

+

+   `sigpending`:idx:

+     `posix.html#1133 <posix.html#1133>`_

+

+   `SIGPIPE`:idx:

+     `posix.html#733 <posix.html#733>`_

+

+   `SIGPOLL`:idx:

+     `posix.html#743 <posix.html#743>`_

+

+   `sigprocmask`:idx:

+     `posix.html#1134 <posix.html#1134>`_

+

+   `SIGPROF`:idx:

+     `posix.html#744 <posix.html#744>`_

+

+   `sigqueue`:idx:

+     `posix.html#1135 <posix.html#1135>`_

+

+   `SIGQUIT`:idx:

+     `posix.html#734 <posix.html#734>`_

+

+   `sigrelse`:idx:

+     `posix.html#1136 <posix.html#1136>`_

+

+   `SIGSEGV`:idx:

+     `posix.html#735 <posix.html#735>`_

+

+   `sigset`:idx:

+     `posix.html#1137 <posix.html#1137>`_

+

+   `SIG_SETMASK`:idx:

+     `posix.html#754 <posix.html#754>`_

+

+   `SIGSTKSZ`:idx:

+     `posix.html#764 <posix.html#764>`_

+

+   `SIGSTOP`:idx:

+     `posix.html#736 <posix.html#736>`_

+

+   `sigsuspend`:idx:

+     `posix.html#1138 <posix.html#1138>`_

+

+   `SIGSYS`:idx:

+     `posix.html#745 <posix.html#745>`_

+

+   `SIGTERM`:idx:

+     `posix.html#737 <posix.html#737>`_

+

+   `sigtimedwait`:idx:

+     `posix.html#1139 <posix.html#1139>`_

+

+   `SIGTRAP`:idx:

+     `posix.html#746 <posix.html#746>`_

+

+   `SIGTSTP`:idx:

+     `posix.html#738 <posix.html#738>`_

+

+   `SIGTTIN`:idx:

+     `posix.html#739 <posix.html#739>`_

+

+   `SIGTTOU`:idx:

+     `posix.html#740 <posix.html#740>`_

+

+   `SIG_UNBLOCK`:idx:

+     `posix.html#753 <posix.html#753>`_

+

+   `SIGURG`:idx:

+     `posix.html#747 <posix.html#747>`_

+

+   `SIGUSR1`:idx:

+     `posix.html#741 <posix.html#741>`_

+

+   `SIGUSR2`:idx:

+     `posix.html#742 <posix.html#742>`_

+

+   `SIGVTALRM`:idx:

+     `posix.html#748 <posix.html#748>`_

+

+   `sigwait`:idx:

+     `posix.html#1140 <posix.html#1140>`_

+

+   `sigwaitinfo`:idx:

+     `posix.html#1141 <posix.html#1141>`_

+

+   `SIGXCPU`:idx:

+     `posix.html#749 <posix.html#749>`_

+

+   `SIGXFSZ`:idx:

+     `posix.html#750 <posix.html#750>`_

+

    `simple assertions`:idx:

      `regexprs.html#103 <regexprs.html#103>`_

 

    `simple statements`:idx:

-     `manual.html#175 <manual.html#175>`_

+     `manual.html#174 <manual.html#174>`_

 

    `sinh`:idx:

-     `math.html#118 <math.html#118>`_

+     `math.html#122 <math.html#122>`_

+

+   `S_IRGRP`:idx:

+     `posix.html#659 <posix.html#659>`_

+

+   `S_IROTH`:idx:

+     `posix.html#663 <posix.html#663>`_

+

+   `S_IRUSR`:idx:

+     `posix.html#655 <posix.html#655>`_

+

+   `S_IRWXG`:idx:

+     `posix.html#658 <posix.html#658>`_

+

+   `S_IRWXO`:idx:

+     `posix.html#662 <posix.html#662>`_

+

+   `S_IRWXU`:idx:

+     `posix.html#654 <posix.html#654>`_

+

+   `S_ISBLK`:idx:

+     `posix.html#1060 <posix.html#1060>`_

+

+   `S_ISCHR`:idx:

+     `posix.html#1061 <posix.html#1061>`_

+

+   `S_ISDIR`:idx:

+     `posix.html#1062 <posix.html#1062>`_

+

+   `S_ISFIFO`:idx:

+     `posix.html#1063 <posix.html#1063>`_

+

+   `S_ISGID`:idx:

+     `posix.html#667 <posix.html#667>`_

+

+   `S_ISLNK`:idx:

+     `posix.html#1065 <posix.html#1065>`_

+

+   `S_ISREG`:idx:

+     `posix.html#1064 <posix.html#1064>`_

+

+   `S_ISSOCK`:idx:

+     `posix.html#1066 <posix.html#1066>`_

+

+   `S_ISUID`:idx:

+     `posix.html#666 <posix.html#666>`_

+

+   `S_ISVTX`:idx:

+     `posix.html#668 <posix.html#668>`_

+

+   `S_IWGRP`:idx:

+     `posix.html#660 <posix.html#660>`_

+

+   `S_IWOTH`:idx:

+     `posix.html#664 <posix.html#664>`_

+

+   `S_IWUSR`:idx:

+     `posix.html#656 <posix.html#656>`_

+

+   `S_IXGRP`:idx:

+     `posix.html#661 <posix.html#661>`_

+

+   `S_IXOTH`:idx:

+     `posix.html#665 <posix.html#665>`_

+

+   `S_IXUSR`:idx:

+     `posix.html#657 <posix.html#657>`_

 

    `sizeof`:idx:

      `system.html#140 <system.html#140>`_

 

+   `sleep`:idx:

+     `posix.html#1023 <posix.html#1023>`_

+

    `split`:idx:

      `strutils.html#117 <strutils.html#117>`_

 

@@ -1172,17 +4147,26 @@ Index
      `strutils.html#118 <strutils.html#118>`_

 

    `sqrt`:idx:

-     * `math.html#106 <math.html#106>`_

+     * `math.html#108 <math.html#108>`_

      * `complex.html#109 <complex.html#109>`_

 

+   `SS_DISABLE`:idx:

+     `posix.html#762 <posix.html#762>`_

+

+   `SS_ONSTACK`:idx:

+     `posix.html#761 <posix.html#761>`_

+

    `stack_trace`:idx:

      `nimrodc.html#106 <nimrodc.html#106>`_

 

    `startsWith`:idx:

-     `strutils.html#131 <strutils.html#131>`_

+     `strutils.html#132 <strutils.html#132>`_

+

+   `stat`:idx:

+     `posix.html#1058 <posix.html#1058>`_

 

    `Statements`:idx:

-     `manual.html#174 <manual.html#174>`_

+     `manual.html#173 <manual.html#173>`_

 

    `static error`:idx:

      `manual.html#109 <manual.html#109>`_

@@ -1190,17 +4174,35 @@ Index
    `static type`:idx:

      `manual.html#103 <manual.html#103>`_

 

+   `statvfs`:idx:

+     `posix.html#1049 <posix.html#1049>`_

+

    `stdcall`:idx:

-     `manual.html#165 <manual.html#165>`_

+     `manual.html#164 <manual.html#164>`_

 

    `stderr`:idx:

-     `system.html#365 <system.html#365>`_

+     `system.html#376 <system.html#376>`_

 

    `stdin`:idx:

-     `system.html#363 <system.html#363>`_

+     `system.html#374 <system.html#374>`_

 

    `stdout`:idx:

-     `system.html#364 <system.html#364>`_

+     `system.html#375 <system.html#375>`_

+

+   `ST_NOSUID`:idx:

+     `posix.html#670 <posix.html#670>`_

+

+   `ST_RDONLY`:idx:

+     `posix.html#669 <posix.html#669>`_

+

+   `strerror`:idx:

+     `posix.html#1153 <posix.html#1153>`_

+

+   `strfmon`:idx:

+     `posix.html#842 <posix.html#842>`_

+

+   `strftime`:idx:

+     `posix.html#1103 <posix.html#1103>`_

 

    `string`:idx:

      `manual.html#151 <manual.html#151>`_

@@ -1208,29 +4210,62 @@ Index
    `strip`:idx:

      `strutils.html#105 <strutils.html#105>`_

 

+   `strptime`:idx:

+     `posix.html#1104 <posix.html#1104>`_

+

    `strStart`:idx:

      `strutils.html#103 <strutils.html#103>`_

 

    `structured type`:idx:

      `manual.html#152 <manual.html#152>`_

 

+   `strutils`:idx:

+     `nimrodc.html#113 <nimrodc.html#113>`_

+

    `style-insensitive`:idx:

      `manual.html#118 <manual.html#118>`_

 

+   `S_TYPEISMQ`:idx:

+     `posix.html#1067 <posix.html#1067>`_

+

+   `S_TYPEISSEM`:idx:

+     `posix.html#1068 <posix.html#1068>`_

+

+   `S_TYPEISSHM`:idx:

+     `posix.html#1069 <posix.html#1069>`_

+

+   `S_TYPEISTMO`:idx:

+     `posix.html#1070 <posix.html#1070>`_

+

    `subrange`:idx:

      `manual.html#150 <manual.html#150>`_

 

    `succ`:idx:

      `system.html#141 <system.html#141>`_

 

+   `swab`:idx:

+     `posix.html#1024 <posix.html#1024>`_

+

    `swap`:idx:

      `system.html#302 <system.html#302>`_

 

+   `swapcontext`:idx:

+     `posix.html#1184 <posix.html#1184>`_

+

+   `symlink`:idx:

+     `posix.html#1025 <posix.html#1025>`_

+

+   `sync`:idx:

+     `posix.html#1026 <posix.html#1026>`_

+

    `syscall`:idx:

-     `manual.html#172 <manual.html#172>`_

+     `manual.html#171 <manual.html#171>`_

+

+   `sysconf`:idx:

+     `posix.html#1027 <posix.html#1027>`_

 

    `system`:idx:

-     `manual.html#220 <manual.html#220>`_

+     `manual.html#219 <manual.html#219>`_

 

    `tabulator`:idx:

      `manual.html#125 <manual.html#125>`_

@@ -1238,42 +4273,204 @@ Index
    `TAddress`:idx:

      `system.html#255 <system.html#255>`_

 

+   `Taiocb`:idx:

+     `posix.html#127 <posix.html#127>`_

+

    `tan`:idx:

-     `math.html#119 <math.html#119>`_

+     `math.html#123 <math.html#123>`_

 

    `tanh`:idx:

-     `math.html#120 <math.html#120>`_

+     `math.html#124 <math.html#124>`_

+

+   `TBaseLexer`:idx:

+     `lexbase.html#103 <lexbase.html#103>`_

+

+   `Tblkcnt`:idx:

+     `posix.html#141 <posix.html#141>`_

+

+   `Tblksize`:idx:

+     `posix.html#142 <posix.html#142>`_

+

+   `TCfgEvent`:idx:

+     `parsecfg.html#102 <parsecfg.html#102>`_

+

+   `TCfgEventKind`:idx:

+     `parsecfg.html#101 <parsecfg.html#101>`_

+

+   `TCfgParser`:idx:

+     `parsecfg.html#103 <parsecfg.html#103>`_

+

+   `tcgetpgrp`:idx:

+     `posix.html#1028 <posix.html#1028>`_

 

    `TCharSet`:idx:

      `strutils.html#101 <strutils.html#101>`_

 

+   `TClock`:idx:

+     `posix.html#143 <posix.html#143>`_

+

+   `TClockId`:idx:

+     `posix.html#144 <posix.html#144>`_

+

+   `TCmdLineKind`:idx:

+     `parseopt.html#101 <parseopt.html#101>`_

+

    `TComplex`:idx:

      `complex.html#101 <complex.html#101>`_

 

+   `tcsetpgrp`:idx:

+     `posix.html#1029 <posix.html#1029>`_

+

+   `TDev`:idx:

+     `posix.html#145 <posix.html#145>`_

+

+   `TDIR`:idx:

+     `posix.html#128 <posix.html#128>`_

+

+   `Tdirent`:idx:

+     `posix.html#129 <posix.html#129>`_

+

+   `telldir`:idx:

+     `posix.html#800 <posix.html#800>`_

+

    `template`:idx:

-     `manual.html#211 <manual.html#211>`_

+     `manual.html#210 <manual.html#210>`_

 

    `TEndian`:idx:

      `system.html#268 <system.html#268>`_

 

+   `Tfd_set`:idx:

+     `posix.html#199 <posix.html#199>`_

+

+   `Tfenv`:idx:

+     `posix.html#131 <posix.html#131>`_

+

+   `Tfexcept`:idx:

+     `posix.html#132 <posix.html#132>`_

+

    `TFile`:idx:

-     `system.html#361 <system.html#361>`_

+     `system.html#372 <system.html#372>`_

 

    `TFileMode`:idx:

-     `system.html#362 <system.html#362>`_

+     `system.html#373 <system.html#373>`_

 

    `TFloatClass`:idx:

-     `math.html#122 <math.html#122>`_

+     `math.html#101 <math.html#101>`_

+

+   `Tflock`:idx:

+     `posix.html#130 <posix.html#130>`_

+

+   `T_FMT`:idx:

+     `posix.html#389 <posix.html#389>`_

+

+   `T_FMT_AMPM`:idx:

+     `posix.html#390 <posix.html#390>`_

+

+   `TFormatFlag`:idx:

+     `strtabs.html#111 <strtabs.html#111>`_

+

+   `Tfsblkcnt`:idx:

+     `posix.html#146 <posix.html#146>`_

+

+   `Tfsfilcnt`:idx:

+     `posix.html#147 <posix.html#147>`_

+

+   `TFTW`:idx:

+     `posix.html#133 <posix.html#133>`_

 

    `TGC_Strategy`:idx:

-     `system.html#357 <system.html#357>`_

+     `system.html#367 <system.html#367>`_

+

+   `TGid`:idx:

+     `posix.html#148 <posix.html#148>`_

+

+   `TGlob`:idx:

+     `posix.html#134 <posix.html#134>`_

+

+   `TGroup`:idx:

+     `posix.html#135 <posix.html#135>`_

+

+   `THash`:idx:

+     `hashes.html#101 <hashes.html#101>`_

+

+   `THOUSEP`:idx:

+     `posix.html#437 <posix.html#437>`_

+

+   `Ticonv`:idx:

+     `posix.html#136 <posix.html#136>`_

+

+   `Tid`:idx:

+     `posix.html#149 <posix.html#149>`_

+

+   `time`:idx:

+     `posix.html#1105 <posix.html#1105>`_

 

    `TimeInfoToTime`:idx:

      `times.html#108 <times.html#108>`_

 

+   `TIMER_ABSTIME`:idx:

+     `posix.html#696 <posix.html#696>`_

+

+   `timer_create`:idx:

+     `posix.html#1106 <posix.html#1106>`_

+

+   `timer_delete`:idx:

+     `posix.html#1107 <posix.html#1107>`_

+

+   `timer_getoverrun`:idx:

+     `posix.html#1109 <posix.html#1109>`_

+

+   `timer_gettime`:idx:

+     `posix.html#1108 <posix.html#1108>`_

+

+   `timer_settime`:idx:

+     `posix.html#1110 <posix.html#1110>`_

+

+   `times`:idx:

+     `nimrodc.html#115 <nimrodc.html#115>`_

+

+   `timezone`:idx:

+     `posix.html#699 <posix.html#699>`_

+

+   `Tino`:idx:

+     `posix.html#150 <posix.html#150>`_

+

+   `Tipc_perm`:idx:

+     `posix.html#180 <posix.html#180>`_

+

+   `titimerspec`:idx:

+     `posix.html#186 <posix.html#186>`_

+

+   `TKey`:idx:

+     `posix.html#151 <posix.html#151>`_

+

+   `Tlconv`:idx:

+     `posix.html#137 <posix.html#137>`_

+

+   `Tmcontext`:idx:

+     `posix.html#202 <posix.html#202>`_

+

+   `TMode`:idx:

+     `posix.html#152 <posix.html#152>`_

+

    `TMonth`:idx:

      `times.html#101 <times.html#101>`_

 

+   `TMqAttr`:idx:

+     `posix.html#139 <posix.html#139>`_

+

+   `TMqd`:idx:

+     `posix.html#138 <posix.html#138>`_

+

+   `Tnl_catd`:idx:

+     `posix.html#196 <posix.html#196>`_

+

+   `TNlink`:idx:

+     `posix.html#153 <posix.html#153>`_

+

+   `Tnl_item`:idx:

+     `posix.html#195 <posix.html#195>`_

+

    `toBiggestFloat`:idx:

      `system.html#283 <system.html#283>`_

 

@@ -1281,10 +4478,13 @@ Index
      `system.html#285 <system.html#285>`_

 

    `toBin`:idx:

-     `strutils.html#135 <strutils.html#135>`_

+     `strutils.html#137 <strutils.html#137>`_

 

    `TObject`:idx:

-     `system.html#116 <system.html#116>`_

+     `system.html#115 <system.html#115>`_

+

+   `TOff`:idx:

+     `posix.html#154 <posix.html#154>`_

 

    `toFloat`:idx:

      `system.html#282 <system.html#282>`_

@@ -1300,35 +4500,143 @@ Index
      * `strutils.html#107 <strutils.html#107>`_

 

    `toOct`:idx:

-     `strutils.html#134 <strutils.html#134>`_

+     `strutils.html#136 <strutils.html#136>`_

 

    `toOctal`:idx:

      `strutils.html#116 <strutils.html#116>`_

 

+   `TOptParser`:idx:

+     `parseopt.html#102 <parseopt.html#102>`_

+

    `toString`:idx:

-     `strutils.html#127 <strutils.html#127>`_

+     `strutils.html#128 <strutils.html#128>`_

 

    `toU16`:idx:

-     `system.html#308 <system.html#308>`_

+     `system.html#310 <system.html#310>`_

 

    `toU32`:idx:

-     `system.html#309 <system.html#309>`_

+     `system.html#311 <system.html#311>`_

 

    `toU8`:idx:

-     `system.html#307 <system.html#307>`_

+     `system.html#309 <system.html#309>`_

 

    `toUpper`:idx:

      * `strutils.html#108 <strutils.html#108>`_

      * `strutils.html#109 <strutils.html#109>`_

 

+   `TPasswd`:idx:

+     `posix.html#140 <posix.html#140>`_

+

+   `TPid`:idx:

+     `posix.html#155 <posix.html#155>`_

+

+   `Tposix_spawnattr`:idx:

+     `posix.html#200 <posix.html#200>`_

+

+   `Tposix_spawn_file_actions`:idx:

+     `posix.html#201 <posix.html#201>`_

+

+   `Tposix_typed_mem_info`:idx:

+     `posix.html#183 <posix.html#183>`_

+

+   `Tpthread`:idx:

+     `posix.html#168 <posix.html#168>`_

+

+   `Tpthread_attr`:idx:

+     `posix.html#156 <posix.html#156>`_

+

+   `Tpthread_barrier`:idx:

+     `posix.html#157 <posix.html#157>`_

+

+   `Tpthread_barrierattr`:idx:

+     `posix.html#158 <posix.html#158>`_

+

+   `Tpthread_cond`:idx:

+     `posix.html#159 <posix.html#159>`_

+

+   `Tpthread_condattr`:idx:

+     `posix.html#160 <posix.html#160>`_

+

+   `Tpthread_key`:idx:

+     `posix.html#161 <posix.html#161>`_

+

+   `Tpthread_mutex`:idx:

+     `posix.html#162 <posix.html#162>`_

+

+   `Tpthread_mutexattr`:idx:

+     `posix.html#163 <posix.html#163>`_

+

+   `Tpthread_once`:idx:

+     `posix.html#164 <posix.html#164>`_

+

+   `Tpthread_rwlock`:idx:

+     `posix.html#165 <posix.html#165>`_

+

+   `Tpthread_rwlockattr`:idx:

+     `posix.html#166 <posix.html#166>`_

+

+   `Tpthread_spinlock`:idx:

+     `posix.html#167 <posix.html#167>`_

+

    `traced`:idx:

-     `manual.html#160 <manual.html#160>`_

+     `manual.html#159 <manual.html#159>`_

 

    `TResult`:idx:

      `system.html#139 <system.html#139>`_

 

+   `truncate`:idx:

+     `posix.html#1030 <posix.html#1030>`_

+

    `try`:idx:

-     `manual.html#187 <manual.html#187>`_

+     `manual.html#186 <manual.html#186>`_

+

+   `Tsched_param`:idx:

+     `posix.html#197 <posix.html#197>`_

+

+   `TSem`:idx:

+     `posix.html#179 <posix.html#179>`_

+

+   `TSigaction`:idx:

+     `posix.html#191 <posix.html#191>`_

+

+   `Tsig_atomic`:idx:

+     `posix.html#187 <posix.html#187>`_

+

+   `TsigEvent`:idx:

+     `posix.html#189 <posix.html#189>`_

+

+   `TsigInfo`:idx:

+     `posix.html#194 <posix.html#194>`_

+

+   `Tsigset`:idx:

+     `posix.html#188 <posix.html#188>`_

+

+   `TSigStack`:idx:

+     `posix.html#193 <posix.html#193>`_

+

+   `TsigVal`:idx:

+     `posix.html#190 <posix.html#190>`_

+

+   `TStack`:idx:

+     `posix.html#192 <posix.html#192>`_

+

+   `TStat`:idx:

+     `posix.html#181 <posix.html#181>`_

+

+   `TStatvfs`:idx:

+     `posix.html#182 <posix.html#182>`_

+

+   `TStringTable`:idx:

+     `strtabs.html#102 <strtabs.html#102>`_

+

+   `TStringTableMode`:idx:

+     `strtabs.html#101 <strtabs.html#101>`_

+

+   `Tsuseconds`:idx:

+     `posix.html#169 <posix.html#169>`_

+

+   `Ttime`:idx:

+     `posix.html#170 <posix.html#170>`_

 

    `TTime`:idx:

      `times.html#103 <times.html#103>`_

@@ -1336,8 +4644,50 @@ Index
    `TTimeInfo`:idx:

      `times.html#104 <times.html#104>`_

 

+   `Ttimer`:idx:

+     `posix.html#171 <posix.html#171>`_

+

+   `Ttimespec`:idx:

+     `posix.html#185 <posix.html#185>`_

+

+   `Ttimeval`:idx:

+     `posix.html#198 <posix.html#198>`_

+

+   `Ttm`:idx:

+     `posix.html#184 <posix.html#184>`_

+

+   `Ttrace_attr`:idx:

+     `posix.html#172 <posix.html#172>`_

+

+   `Ttrace_event_id`:idx:

+     `posix.html#173 <posix.html#173>`_

+

+   `Ttrace_event_set`:idx:

+     `posix.html#174 <posix.html#174>`_

+

+   `Ttrace_id`:idx:

+     `posix.html#175 <posix.html#175>`_

+

+   `ttyname`:idx:

+     `posix.html#1031 <posix.html#1031>`_

+

+   `ttyname_r`:idx:

+     `posix.html#1032 <posix.html#1032>`_

+

+   `Tucontext`:idx:

+     `posix.html#203 <posix.html#203>`_

+

+   `Tuid`:idx:

+     `posix.html#176 <posix.html#176>`_

+

    `tuple`:idx:

-     `system.html#112 <system.html#112>`_

+     `manual.html#155 <manual.html#155>`_

+

+   `Tuseconds`:idx:

+     `posix.html#177 <posix.html#177>`_

+

+   `Tutsname`:idx:

+     `posix.html#178 <posix.html#178>`_

 

    `TWeekDay`:idx:

      `times.html#102 <times.html#102>`_

@@ -1345,23 +4695,38 @@ Index
    `type`:idx:

      * `manual.html#102 <manual.html#102>`_

      * `manual.html#141 <manual.html#141>`_

-     * `manual.html#208 <manual.html#208>`_

+     * `manual.html#207 <manual.html#207>`_

 

    `type parameters`:idx:

-     `manual.html#210 <manual.html#210>`_

+     `manual.html#209 <manual.html#209>`_

 

    `type suffix`:idx:

      `manual.html#138 <manual.html#138>`_

 

+   `tzset`:idx:

+     `posix.html#1111 <posix.html#1111>`_

+

+   `ualarm`:idx:

+     `posix.html#1033 <posix.html#1033>`_

+

+   `umask`:idx:

+     `posix.html#1059 <posix.html#1059>`_

+

+   `uname`:idx:

+     `posix.html#859 <posix.html#859>`_

+

    `unchecked runtime error`:idx:

      `manual.html#111 <manual.html#111>`_

 

    `undef`:idx:

-     `manual.html#225 <manual.html#225>`_

+     `manual.html#224 <manual.html#224>`_

 

    `UnixToNativePath`:idx:

      `os.html#122 <os.html#122>`_

 

+   `unlink`:idx:

+     `posix.html#1034 <posix.html#1034>`_

+

    `unsigned integer`:idx:

      `manual.html#143 <manual.html#143>`_

 

@@ -1369,10 +4734,13 @@ Index
      `manual.html#144 <manual.html#144>`_

 

    `untraced`:idx:

-     `manual.html#161 <manual.html#161>`_

+     `manual.html#160 <manual.html#160>`_

+

+   `usleep`:idx:

+     `posix.html#1035 <posix.html#1035>`_

 

    `Var`:idx:

-     `manual.html#179 <manual.html#179>`_

+     `manual.html#178 <manual.html#178>`_

 

    `varargs`:idx:

      `nimrodc.html#102 <nimrodc.html#102>`_

@@ -1380,60 +4748,126 @@ Index
    `vertical tabulator`:idx:

      `manual.html#126 <manual.html#126>`_

 

+   `vfork`:idx:

+     `posix.html#1036 <posix.html#1036>`_

+

    `volatile`:idx:

      `nimrodc.html#109 <nimrodc.html#109>`_

 

+   `wait`:idx:

+     `posix.html#1112 <posix.html#1112>`_

+

+   `waitid`:idx:

+     `posix.html#1113 <posix.html#1113>`_

+

+   `waitpid`:idx:

+     `posix.html#1114 <posix.html#1114>`_

+

    `walkFiles`:idx:

      `os.html#146 <os.html#146>`_

 

    `warning`:idx:

-     * `manual.html#222 <manual.html#222>`_

-     * `manual.html#228 <manual.html#228>`_

+     * `manual.html#221 <manual.html#221>`_

+     * `manual.html#227 <manual.html#227>`_

+     * `dialogs.html#103 <dialogs.html#103>`_

+

+   `WCONTINUED`:idx:

+     `posix.html#711 <posix.html#711>`_

+

+   `WEXITED`:idx:

+     `posix.html#709 <posix.html#709>`_

+

+   `WEXITSTATUS`:idx:

+     `posix.html#702 <posix.html#702>`_

 

    `when`:idx:

-     `manual.html#183 <manual.html#183>`_

+     `manual.html#182 <manual.html#182>`_

 

    `while`:idx:

-     `manual.html#196 <manual.html#196>`_

+     `manual.html#195 <manual.html#195>`_

 

    `Whitespace`:idx:

      `strutils.html#102 <strutils.html#102>`_

 

+   `WIFCONTINUED`:idx:

+     `posix.html#703 <posix.html#703>`_

+

+   `WIFEXITED`:idx:

+     `posix.html#704 <posix.html#704>`_

+

+   `WIFSIGNALED`:idx:

+     `posix.html#705 <posix.html#705>`_

+

+   `WIFSTOPPED`:idx:

+     `posix.html#706 <posix.html#706>`_

+

+   `WNOHANG`:idx:

+     `posix.html#700 <posix.html#700>`_

+

+   `WNOWAIT`:idx:

+     `posix.html#712 <posix.html#712>`_

+

+   `W_OK`:idx:

+     `posix.html#477 <posix.html#477>`_

+

    `write`:idx:

-     * `system.html#372 <system.html#372>`_

-     * `system.html#373 <system.html#373>`_

-     * `system.html#374 <system.html#374>`_

-     * `system.html#375 <system.html#375>`_

-     * `system.html#376 <system.html#376>`_

-     * `system.html#377 <system.html#377>`_

+     * `system.html#383 <system.html#383>`_

+     * `system.html#384 <system.html#384>`_

+     * `system.html#385 <system.html#385>`_

+     * `system.html#386 <system.html#386>`_

+     * `system.html#387 <system.html#387>`_

+     * `system.html#388 <system.html#388>`_

+     * `system.html#389 <system.html#389>`_

+     * `posix.html#1037 <posix.html#1037>`_

 

    `writeBuffer`:idx:

-     `system.html#387 <system.html#387>`_

+     `system.html#399 <system.html#399>`_

 

    `writeBytes`:idx:

-     `system.html#385 <system.html#385>`_

+     `system.html#397 <system.html#397>`_

 

    `writeChars`:idx:

-     `system.html#386 <system.html#386>`_

+     `system.html#398 <system.html#398>`_

 

    `writeln`:idx:

-     `system.html#379 <system.html#379>`_

+     * `system.html#391 <system.html#391>`_

+     * `system.html#392 <system.html#392>`_

+

+   `WSTOPPED`:idx:

+     `posix.html#710 <posix.html#710>`_

+

+   `WSTOPSIG`:idx:

+     `posix.html#707 <posix.html#707>`_

+

+   `WTERMSIG`:idx:

+     `posix.html#708 <posix.html#708>`_

+

+   `WUNTRACED`:idx:

+     `posix.html#701 <posix.html#701>`_

+

+   `X_OK`:idx:

+     `posix.html#478 <posix.html#478>`_

 

    `xor`:idx:

      * `system.html#166 <system.html#166>`_

      * `system.html#185 <system.html#185>`_

      * `system.html#206 <system.html#206>`_

 

+   `YESEXPR`:idx:

+     `posix.html#438 <posix.html#438>`_

+

    `yield`:idx:

-     `manual.html#193 <manual.html#193>`_

+     `manual.html#192 <manual.html#192>`_

 

    `ze`:idx:

      * `system.html#303 <system.html#303>`_

      * `system.html#304 <system.html#304>`_

-     * `system.html#306 <system.html#306>`_

 

    `ze64`:idx:

-     `system.html#305 <system.html#305>`_

+     * `system.html#305 <system.html#305>`_

+     * `system.html#306 <system.html#306>`_

+     * `system.html#307 <system.html#307>`_

+     * `system.html#308 <system.html#308>`_

 

    `zeroMem`:idx:

      `system.html#292 <system.html#292>`_
\ No newline at end of file
diff --git a/doc/tutorial.txt b/doc/tutorial.txt
index f37b116c4..795fc0d90 100644
--- a/doc/tutorial.txt
+++ b/doc/tutorial.txt
@@ -85,13 +85,13 @@ We start the tour with a modified "hallo world" program:
 
 Save this code to the file "greeting.nim". Now compile and run it::
 
-  nimrod run greeting.nim
+  nimrod compile --run greeting.nim
 
-As you see, with the ``run`` command Nimrod executes the file automatically
+As you see, with the ``--run`` switch Nimrod executes the file automatically
 after compilation. You can even give your program command line arguments by
 appending them after the filename that is to be compiled and run::
 
-  nimrod run greeting.nim arg1 arg2
+  nimrod compile --run greeting.nim arg1 arg2
 
 Though it should be pretty obvious what the program does, I will explain the
 syntax: Statements which are not indented are executed when the program
@@ -198,7 +198,7 @@ An example showing the most common statement types:
   
   .. code-block:: Nimrod
     type
-      TMyRecord = record
+      TMyRecord = object
         x, y: int
   
   
diff --git a/ide/main.nim b/ide/main.nim
index 76b6757a3..0e985c985 100644
--- a/ide/main.nim
+++ b/ide/main.nim
@@ -1,63 +1,38 @@
 
-import glib2, gtk2, libglade2
- 
-proc on_window_destroy(obj: PGtkObject, data: pointer) {.exportc, cdecl.} =
+import glib2, gtk2, libglade2, dialogs
+
+proc on_window_destroy(obj: PGtkObject, data: pointer) {.cdecl.} =
   gtk_main_quit()
- 
+
 const
   GuiTemplate = "/media/hda4/nimrod/ide/nimide.glade"
- 
+
 type
-  TMyTextEditor = record
+  TTab = object of TObject
+    textview: PGtkTextView
+    filename: string
+    untitled: bool
+
+  TMyTextEditor = object of TObject
     window: PGtkWindow
     statusbar: PGtkStatusBar
     textview: PGtkTextview
     statusbarContextId: int
-    filename: string
 
-proc error_message(msg: string) = 
-  var
-    dialog: PGtkDialog
-  dialog = GTK_DIALOG(gtk_message_dialog_new(nil, 
-              GTK_DIALOG_MODAL or GTK_DIALOG_DESTROY_WITH_PARENT,
-              GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, msg))
-  
-  gtk_window_set_title(dialog, "Error!")
-  gtk_dialog_run(dialog)
-  gtk_widget_destroy(dialog)
 
 
-proc get_open_filename(e: TMyTextEditor): string =
-  var
-    chooser: PGtkDialog                
-  chooser = gtk_file_chooser_dialog_new("Open File...", e.window,
-              GTK_FILE_CHOOSER_ACTION_OPEN,
-              GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-              GTK_STOCK_OPEN, GTK_RESPONSE_OK, nil)
-                                               
-  if gtk_dialog_run(chooser) == GTK_RESPONSE_OK:
-    result = $gtk_file_chooser_get_filename(chooser)
-  else:
-    result = ""        
-  gtk_widget_destroy(chooser)
+proc on_about_menu_item_activate(menuItem: PGtkMenuItem,
+                                 e: var TMyTextEditor) {.cdecl.} =
+  gtk_show_about_dialog(e.window,
+    "comments", "A fast and leight-weight IDE for Nimrod",
+    "copyright", "Copyright \xc2\xa9 2008 Andreas Rumpf",
+    "version", "0.1",
+    "website", "http://nimrod.ethexor.com",
+    "program-name", "Nimrod IDE",
+    nil)
 
-  
-proc get_save_filename(e: TMyTextEditor): string = 
-  var
-    chooser: PGtkDialog                
-  chooser = gtk_file_chooser_dialog_new("Save File...", e.window,
-              GTK_FILE_CHOOSER_ACTION_SAVE,
-              GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-              GTK_STOCK_OPEN, GTK_RESPONSE_OK, nil)
-                                               
-  if gtk_dialog_run(chooser) == GTK_RESPONSE_OK:
-    result = $gtk_file_chooser_get_filename(chooser)
-  else:
-    result = ""        
-  gtk_widget_destroy(chooser)
-  
 proc load_file(e: var TMyTextEditor, filename: string) =
-  var 
+  var
     err: ptr GError
     status: cstring
     text: cstring
@@ -65,13 +40,13 @@ proc load_file(e: var TMyTextEditor, filename: string) =
     buffer: PGtkTextBuffer
   gtk_statusbar_push(e.statusbar, e.statusbar_context_id, "Loading...")
   while gtk_events_pending(): gtk_main_iteration()
-  
+
   # get the file contents
   result = g_file_get_contents(filename, addr(text), nil, addr(err))
   if not result:
     error_message("Cannot load file")
     g_error_free(err)
-  
+
   # disable the text view while loading the buffer with the text
   gtk_widget_set_sensitive(e.text_view, false)
   buffer = gtk_text_view_get_buffer(e.text_view)
@@ -79,13 +54,13 @@ proc load_file(e: var TMyTextEditor, filename: string) =
   gtk_text_buffer_set_modified(buffer, false)
   gtk_widget_set_sensitive(e.text_view, true)
   g_free(text)
-  
+
   e.filename = filename
   gtk_statusbar_pop(e.statusbar, e.statusbar_context_id)
   reset_default_status(e)
 
 proc write_file(e: var TMyTextEditor, filename: string) =
-  var 
+  var
     err: ptr GError
     status: cstring
     text: cstring
@@ -95,7 +70,7 @@ proc write_file(e: var TMyTextEditor, filename: string) =
   # add Saving message to status bar and ensure GUI is current
   gtk_statusbar_push(e.statusbar, e.statusbar_context_id, "Saving....")
   while gtk_events_pending(): gtk_main_iteration()
-  
+
   # disable text view and get contents of buffer
   gtk_widget_set_sensitive(editor->text_view, FALSE)
   buffer = gtk_text_view_get_buffer(e.text_view)
@@ -113,48 +88,63 @@ proc write_file(e: var TMyTextEditor, filename: string) =
     error_message("cannot save")
     g_error_free(err)
   g_free(text)
-  if filename != "": 
+  if filename != "":
     e.filename = filename
   gtk_statusbar_pop(e.statusbar, e.statusbar_context_id)
   reset_default_status(editor)
 
 
-proc initApp(e: var TMyTextEditor) = 
+proc check_for_save(e: var TMyTextEditor): bool =
+  GtkTextBuffer           *buffer;
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
+  if gtk_text_buffer_get_modified(buffer):
+    GtkWidget       *dialog;
+    const gchar *msg  = "Do you want to save the changes you have made?";
+    dialog = gtk_message_dialog_new (nil,
+                                     GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                                     GTK_MESSAGE_QUESTION,
+                                     GTK_BUTTONS_YES_NO,
+                                     msg);
+    gtk_window_set_title (GTK_WINDOW (dialog), "Save?");
+    result = gtk_dialog_run(dialog) != GTK_RESPONSE_NO
+    gtk_widget_destroy(dialog)
+
+proc initApp(e: var TMyTextEditor) =
   var
     builder: PGladeXML
     window: PGtkWidget
     fontDesc: PPangoFontDescription
     id: int
   builder = glade_xml_new(GuiTemplate, nil, nil)
-  if builder == nil: 
+  if builder == nil:
     error_message("cannot open: " & GuiTemplate)
     quit(1)
   # get the components:
   e.window = GTK_WINDOW(glade_xml_get_widget(builder, "window"))
   e.statusbar = GTK_STATUSBAR(glade_xml_get_widget(builder, "statusbar"))
   e.textview = GTK_TEXTVIEW(glade_xml_get_widget(builder, "textview"))
-  
+
   # connect the signal handlers:
-  glade_xml_signal_connect(builder, "on_window_destroy", 
-                           cast[TGCallback](on_window_destroy))
-  
+  glade_xml_signal_connect(builder, "on_window_destroy",
+                           GCallback(on_window_destroy))
+
   font_desc = pango_font_description_from_string("monospace 10")
   gtk_widget_modify_font(e.textview, font_desc)
   pango_font_description_free(font_desc)
   gtk_window_set_default_icon_name(GTK_STOCK_EDIT)
-  
+
   id = gtk_statusbar_get_context_id(e.statusbar, "Nimrod IDE")
   e.statusbarContextId = id
   reset_default_status(e)
-  
+
   e.filename = ""
 
- 
+
 proc main() =
-  var 
-    editor: TMyTextEditor 
+  var
+    editor: TMyTextEditor
 
-  gtk_nimrod_init()  
+  gtk_nimrod_init()
   initApp(editor)
   gtk_widget_show(editor.window)
   gtk_main()
@@ -162,208 +152,82 @@ proc main() =
 main()
 
 
-proc reset_default_status(e: var TMyTextEditor)
-  gchar           *file;
-  gchar           *status;
-  
-  if e.filename == "":
-    file = g_strdup("(UNTITLED)")
-  else:
-    file = g_path_get_basename(editor->filename)
-  
-  status = g_strdup_printf("File: %s", file)
-  gtk_statusbar_pop(e.statusbar,
-                    e.statusbar_context_id)
-  gtk_statusbar_push(e.statusbar,
-                     e.statusbar_context_id, status)
-  g_free(status)
-  g_free(file)
-
-        
-gboolean
-check_for_save(e: var TMyTextEditor)
-  gboolean                ret = FALSE;
-  GtkTextBuffer           *buffer;  
-  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
-  if (gtk_text_buffer_get_modified (buffer) == TRUE)
+
+proc on_window_delete_event(widget: PGtkWidget, event: PGdkEvent,
+                       e: TMyTextEditor): bool {.cdecl.} =
+  if check_for_save(editor):
+    on_save_menu_item_activate(nil, editor)
+  result = false
+
+proc on_new_menu_item_activate(GtkMenuItem *menuitem, TutorialTextEditor *editor)
+  GtkTextBuffer           *buffer;
+
+  if check_for_save(editor):
+    on_save_menu_item_activate(nil, editor)
+
+  /* clear editor for a new file */
+  editor->filename = nil;
+  buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW (editor->text_view));
+  gtk_text_buffer_set_text(buffer, "", -1);
+  gtk_text_buffer_set_modified(buffer, FALSE);
+
+  reset_default_status(editor);
+
+
+proc on_open_menu_item_activate(menuItem: PGtkMenuItem,
+                                TutorialTextEditor *editor) =
+  gchar                   *filename;
+
+  if check_for_save(editor):
+    on_save_menu_item_activate(nil, editor)
+  filename = get_open_filename(editor)
+  if filename != nil: load_file(editor, filename)
+
+proc on_save_menu_item_activate(menuItem: PGtkMenuItem, TutorialTextEditor *editor) =
+  gchar                   *filename;
+  if (editor->filename == nil)
   {
-    GtkWidget       *dialog;
-    const gchar *msg  = "Do you want to save the changes you have made?";
-    dialog = gtk_message_dialog_new (NULL, 
-                                     GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
-                                     GTK_MESSAGE_QUESTION,
-                                     GTK_BUTTONS_YES_NO,
-                                     msg);
-    gtk_window_set_title (GTK_WINDOW (dialog), "Save?");
-    if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_NO)
-    {
-      ret = FALSE;
-    } else ret = TRUE;
-    gtk_widget_destroy (dialog);      
-  }     
-  return ret;
-
-
-/*
-When the window is requested to be closed, we need to check if they have 
-unsaved work. We use this callback to prompt the user to save their work before
-they exit the application. From the "delete-event" signal, we can choose to
-effectively cancel the close based on the value we return.
-*/
-gboolean 
-on_window_delete_event(GtkWidget *widget, GdkEvent *event, 
-                       TutorialTextEditor *editor)
-{
-  if (check_for_save (editor) == TRUE)
-    on_save_menu_item_activate (NULL, editor);  
-  return FALSE;   /* propogate event */
-}
-
-/*
-Called when the user clicks the 'New' menu. We need to prompt for save if the
-file has been modified, and then delete the buffer and clear the modified flag.
-*/
-void on_new_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
-{
-        GtkTextBuffer           *buffer;
-        
-        if (check_for_save (editor) == TRUE)
-        {
-              on_save_menu_item_activate (NULL, editor);  
-        }
-        
-        /* clear editor for a new file */
-        editor->filename = NULL;
-        buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
-        gtk_text_buffer_set_text (buffer, "", -1);
-        gtk_text_buffer_set_modified (buffer, FALSE);
-        
-        reset_default_status (editor);
-}
-
-/*
-Called when the user clicks the 'Open' menu. We need to prompt for save if the
-file has been modified, allow the user to choose a file to open, and then call
-load_file() on that file.
-*/
-void on_open_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
-{
-        gchar                   *filename;
-        
-        if (check_for_save (editor) == TRUE)
-        {
-              on_save_menu_item_activate (NULL, editor);  
-        }
-        
-        filename = get_open_filename (editor);
-        if (filename != NULL) load_file (editor, filename); 
-}
-
-/*
-Called when the user clicks the 'Save' menu. We need to allow the user to choose 
-a file to save if it's an untitled document, and then call write_file() on that 
-file.
-*/
-void on_save_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
-{
-        gchar                   *filename;
-        
-        if (editor->filename == NULL) 
-        {
-                filename = get_save_filename (editor);
-                if (filename != NULL) write_file (editor, filename); 
-        }
-        else write_file (editor, NULL);
-        
-}
-
-/*
-Called when the user clicks the 'Save As' menu. We need to allow the user to 
-choose a file to save and then call write_file() on that file.
-*/
-void on_save_as_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
-{
-        gchar                   *filename;
-        
-        filename = get_save_filename (editor);
-        if (filename != NULL) write_file (editor, filename); 
-}
-
-/*
-Called when the user clicks the 'Quit' menu. We need to prompt for save if the
-file has been modified and then break out of the GTK+ main loop.
-*/
-void on_quit_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
-{
-        if (check_for_save (editor) == TRUE)
-        {
-              on_save_menu_item_activate (NULL, editor);  
-        }
-        gtk_main_quit();
-}
-
-/*
-Called when the user clicks the 'Cut' menu. 
-*/
-void on_cut_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
-{
-        GtkTextBuffer           *buffer;
-        GtkClipboard            *clipboard;
-        
-        clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
-        buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
-        gtk_text_buffer_cut_clipboard (buffer, clipboard, TRUE);
-}
-
-/*
-Called when the user clicks the 'Copy' menu. 
-*/
-void on_copy_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
-{
-        GtkTextBuffer           *buffer;
-        GtkClipboard            *clipboard;
-        
-        clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
-        buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
-        gtk_text_buffer_copy_clipboard (buffer, clipboard);
-}
-
-/*
-Called when the user clicks the 'Paste' menu. 
-*/
-void on_paste_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
-{
-        GtkTextBuffer           *buffer;
-        GtkClipboard            *clipboard;
-        clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
-        buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
-        gtk_text_buffer_paste_clipboard (buffer, clipboard, NULL, TRUE);
-}
-
-/*
-Called when the user clicks the 'Delete' menu. 
-*/
-void on_delete_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
-{
-        GtkTextBuffer           *buffer;
-        buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->text_view));
-        gtk_text_buffer_delete_selection (buffer, FALSE, TRUE);
-}
-
-void on_about_menu_item_activate (GtkMenuItem *menuitem, TutorialTextEditor *editor)
-{
-  static const gchar * const authors[] = {
-		"Micah Carrick <email@micahcarrick.com>",
-		NULL
-	};
-	static const gchar copyright[] = "Copyright \xc2\xa9 2008 Andreas Rumpf";
-	static const gchar comments[] = "GTK+ and Glade3 GUI Programming Tutorial";
-	gtk_show_about_dialog (e.window,
-	  "authors", authors,
-	  "comments", comments,
-	  "copyright", copyright,
-		"version", "0.1",
-		"website", "http://www.micahcarrick.com",
-		"program-name", "GTK+ Text Editor",
-		"logo-icon-name", GTK_STOCK_EDIT, nil) 
-}
+    filename = get_save_filename(editor);
+    if (filename != nil) write_file(editor, filename);
+  }
+  else write_file(editor, nil);
+
+proc on_save_as_menu_item_activate(GtkMenuItem *menuitem,
+                                   TutorialTextEditor *editor) =
+  gchar                   *filename;
+
+  filename = get_save_filename(editor)
+  if filename != nil: write_file(editor, filename)
+
+proc on_quit_menu_item_activate(GtkMenuItem *menuitem, TutorialTextEditor *editor)
+  if check_for_save(editor):
+    on_save_menu_item_activate(nil, editor)
+  gtk_main_quit()
+
+proc on_cut_menu_item_activate(GtkMenuItem *menuitem, TutorialTextEditor *editor) =
+  GtkTextBuffer           *buffer;
+  GtkClipboard            *clipboard;
+
+  clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
+  buffer = gtk_text_view_get_buffer(editor->text_view)
+  gtk_text_buffer_cut_clipboard(buffer, clipboard, TRUE)
+
+proc on_copy_menu_item_activate(GtkMenuItem *menuitem, TutorialTextEditor *editor) =
+  GtkTextBuffer           *buffer;
+  GtkClipboard            *clipboard;
+  clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD)
+  buffer = gtk_text_view_get_buffer(editor->text_view)
+  gtk_text_buffer_copy_clipboard(buffer, clipboard)
+
+
+proc on_paste_menu_item_activate(GtkMenuItem *menuitem, TutorialTextEditor *editor)
+  GtkTextBuffer           *buffer;
+  GtkClipboard            *clipboard;
+  clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD)
+  buffer = gtk_text_view_get_buffer(editor->text_view)
+  gtk_text_buffer_paste_clipboard(buffer, clipboard, nil, TRUE)
+
+proc on_delete_menu_item_activate(GtkMenuItem *menuitem, TutorialTextEditor *editor)
+  GtkTextBuffer           *buffer;
+  buffer = gtk_text_view_get_buffer(editor->text_view);
+  gtk_text_buffer_delete_selection(buffer, FALSE, TRUE);
diff --git a/ide/nimide.glade b/ide/nimide.glade
index a902e6544..0bd5f11f1 100644
--- a/ide/nimide.glade
+++ b/ide/nimide.glade
@@ -1,175 +1,224 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
-<!--Generated with glade3 3.4.2 on Sat Jun 21 14:12:42 2008 -->
-<glade-interface>
-  <widget class="GtkWindow" id="window">
-    <property name="extension_events">GDK_EXTENSION_EVENTS_ALL</property>
-    <signal name="destroy" handler="on_window_destroy" object="destroy"/>
-    <child>
-      <widget class="GtkVBox" id="mainvbox">
-        <property name="visible">True</property>
-        <child>
-          <widget class="GtkMenuBar" id="menubar">
-            <property name="visible">True</property>
-            <child>
-              <widget class="GtkMenuItem" id="menuitem1">
-                <property name="visible">True</property>
-                <property name="label" translatable="yes">_Datei</property>
-                <property name="use_underline">True</property>
-                <child>
-                  <widget class="GtkMenu" id="menu1">
-                    <property name="visible">True</property>
-                    <child>
-                      <widget class="GtkImageMenuItem" id="new_menu_item">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">gtk-new</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkImageMenuItem" id="open_menu_item">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">gtk-open</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkImageMenuItem" id="save_menu_item">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">gtk-save</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkImageMenuItem" id="save_as_menu_item">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">gtk-save-as</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
-                        <property name="visible">True</property>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkImageMenuItem" id="quit_menu_item">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">gtk-quit</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                      </widget>
-                    </child>
-                  </widget>
-                </child>
-              </widget>
-            </child>
-            <child>
-              <widget class="GtkMenuItem" id="menuitem2">
-                <property name="visible">True</property>
-                <property name="label" translatable="yes">_Bearbeiten</property>
-                <property name="use_underline">True</property>
-                <child>
-                  <widget class="GtkMenu" id="menu2">
-                    <property name="visible">True</property>
-                    <child>
-                      <widget class="GtkImageMenuItem" id="cut_menu_item">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">gtk-cut</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkImageMenuItem" id="copy_menu_item">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">gtk-copy</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkImageMenuItem" id="paste_menu_item">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">gtk-paste</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkImageMenuItem" id="delete_menu_item">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">gtk-delete</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                      </widget>
-                    </child>
-                  </widget>
-                </child>
-              </widget>
-            </child>
-            <child>
-              <widget class="GtkMenuItem" id="menuitem4">
-                <property name="visible">True</property>
-                <property name="label" translatable="yes">_Hilfe</property>
-                <property name="use_underline">True</property>
-                <child>
-                  <widget class="GtkMenu" id="menu3">
-                    <property name="visible">True</property>
-                    <child>
-                      <widget class="GtkImageMenuItem" id="about_menu_item">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">gtk-about</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                      </widget>
-                    </child>
-                  </widget>
-                </child>
-              </widget>
-            </child>
-          </widget>
-          <packing>
-            <property name="expand">False</property>
-          </packing>
-        </child>
-        <child>
-          <widget class="GtkScrolledWindow" id="scrolledwindow">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="extension_events">GDK_EXTENSION_EVENTS_ALL</property>
-            <property name="border_width">1</property>
-            <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-            <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-            <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-            <child>
-              <widget class="GtkTextView" id="textview">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="left_margin">2</property>
-                <property name="right_margin">2</property>
-              </widget>
-            </child>
-          </widget>
-          <packing>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child>
-          <widget class="GtkStatusbar" id="statusbar">
-            <property name="visible">True</property>
-            <property name="spacing">2</property>
-          </widget>
-          <packing>
-            <property name="expand">False</property>
-            <property name="position">2</property>
-          </packing>
-        </child>
-      </widget>
-    </child>
-  </widget>
-</glade-interface>
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->

+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">

+

+<glade-interface>

+

+<widget class="GtkWindow" id="window">

+  <property name="extension_events">GDK_EXTENSION_EVENTS_ALL</property>

+  <property name="title" translatable="yes"></property>

+  <property name="type">GTK_WINDOW_TOPLEVEL</property>

+  <property name="window_position">GTK_WIN_POS_NONE</property>

+  <property name="modal">False</property>

+  <property name="resizable">True</property>

+  <property name="destroy_with_parent">False</property>

+  <property name="decorated">True</property>

+  <property name="skip_taskbar_hint">False</property>

+  <property name="skip_pager_hint">False</property>

+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>

+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>

+  <property name="focus_on_map">True</property>

+  <property name="urgency_hint">False</property>

+  <signal name="destroy" handler="on_window_destroy" object="destroy"/>

+

+  <child>

+    <widget class="GtkVBox" id="mainvbox">

+      <property name="width_request">600</property>

+      <property name="height_request">400</property>

+      <property name="visible">True</property>

+      <property name="homogeneous">False</property>

+      <property name="spacing">0</property>

+

+      <child>

+	<widget class="GtkMenuBar" id="menubar">

+	  <property name="visible">True</property>

+	  <property name="pack_direction">GTK_PACK_DIRECTION_LTR</property>

+	  <property name="child_pack_direction">GTK_PACK_DIRECTION_LTR</property>

+

+	  <child>

+	    <widget class="GtkMenuItem" id="menuitem1">

+	      <property name="visible">True</property>

+	      <property name="label" translatable="yes">_Datei</property>

+	      <property name="use_underline">True</property>

+

+	      <child>

+		<widget class="GtkMenu" id="menu1">

+		  <property name="visible">True</property>

+

+		  <child>

+		    <widget class="GtkImageMenuItem" id="new_menu_item">

+		      <property name="visible">True</property>

+		      <property name="label">gtk-new</property>

+		      <property name="use_stock">True</property>

+		    </widget>

+		  </child>

+

+		  <child>

+		    <widget class="GtkImageMenuItem" id="open_menu_item">

+		      <property name="visible">True</property>

+		      <property name="label">gtk-open</property>

+		      <property name="use_stock">True</property>

+		    </widget>

+		  </child>

+

+		  <child>

+		    <widget class="GtkImageMenuItem" id="save_menu_item">

+		      <property name="visible">True</property>

+		      <property name="label">gtk-save</property>

+		      <property name="use_stock">True</property>

+		    </widget>

+		  </child>

+

+		  <child>

+		    <widget class="GtkImageMenuItem" id="save_as_menu_item">

+		      <property name="visible">True</property>

+		      <property name="label">gtk-save-as</property>

+		      <property name="use_stock">True</property>

+		    </widget>

+		  </child>

+

+		  <child>

+		    <widget class="GtkSeparatorMenuItem" id="separatormenuitem1">

+		      <property name="visible">True</property>

+		    </widget>

+		  </child>

+

+		  <child>

+		    <widget class="GtkImageMenuItem" id="quit_menu_item">

+		      <property name="visible">True</property>

+		      <property name="label">gtk-quit</property>

+		      <property name="use_stock">True</property>

+		    </widget>

+		  </child>

+		</widget>

+	      </child>

+	    </widget>

+	  </child>

+

+	  <child>

+	    <widget class="GtkMenuItem" id="menuitem2">

+	      <property name="visible">True</property>

+	      <property name="label" translatable="yes">_Bearbeiten</property>

+	      <property name="use_underline">True</property>

+

+	      <child>

+		<widget class="GtkMenu" id="menu2">

+		  <property name="visible">True</property>

+

+		  <child>

+		    <widget class="GtkImageMenuItem" id="cut_menu_item">

+		      <property name="visible">True</property>

+		      <property name="label">gtk-cut</property>

+		      <property name="use_stock">True</property>

+		    </widget>

+		  </child>

+

+		  <child>

+		    <widget class="GtkImageMenuItem" id="copy_menu_item">

+		      <property name="visible">True</property>

+		      <property name="label">gtk-copy</property>

+		      <property name="use_stock">True</property>

+		    </widget>

+		  </child>

+

+		  <child>

+		    <widget class="GtkImageMenuItem" id="paste_menu_item">

+		      <property name="visible">True</property>

+		      <property name="label">gtk-paste</property>

+		      <property name="use_stock">True</property>

+		    </widget>

+		  </child>

+

+		  <child>

+		    <widget class="GtkImageMenuItem" id="delete_menu_item">

+		      <property name="visible">True</property>

+		      <property name="label">gtk-delete</property>

+		      <property name="use_stock">True</property>

+		    </widget>

+		  </child>

+		</widget>

+	      </child>

+	    </widget>

+	  </child>

+

+	  <child>

+	    <widget class="GtkMenuItem" id="menuitem4">

+	      <property name="visible">True</property>

+	      <property name="label" translatable="yes">_Hilfe</property>

+	      <property name="use_underline">True</property>

+

+	      <child>

+		<widget class="GtkMenu" id="menu3">

+		  <property name="visible">True</property>

+

+		  <child>

+		    <widget class="GtkImageMenuItem" id="about_menu_item">

+		      <property name="visible">True</property>

+		      <property name="label">gtk-about</property>

+		      <property name="use_stock">True</property>

+		    </widget>

+		  </child>

+		</widget>

+	      </child>

+	    </widget>

+	  </child>

+	</widget>

+	<packing>

+	  <property name="padding">0</property>

+	  <property name="expand">False</property>

+	  <property name="fill">True</property>

+	</packing>

+      </child>

+

+      <child>

+	<widget class="GtkScrolledWindow" id="scrolledwindow">

+	  <property name="border_width">1</property>

+	  <property name="visible">True</property>

+	  <property name="can_focus">True</property>

+	  <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>

+	  <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>

+	  <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>

+	  <property name="window_placement">GTK_CORNER_TOP_LEFT</property>

+

+	  <child>

+	    <widget class="GtkTextView" id="textview">

+	      <property name="visible">True</property>

+	      <property name="can_focus">True</property>

+	      <property name="editable">True</property>

+	      <property name="overwrite">False</property>

+	      <property name="accepts_tab">True</property>

+	      <property name="justification">GTK_JUSTIFY_LEFT</property>

+	      <property name="wrap_mode">GTK_WRAP_NONE</property>

+	      <property name="cursor_visible">True</property>

+	      <property name="pixels_above_lines">0</property>

+	      <property name="pixels_below_lines">0</property>

+	      <property name="pixels_inside_wrap">0</property>

+	      <property name="left_margin">2</property>

+	      <property name="right_margin">2</property>

+	      <property name="indent">0</property>

+	      <property name="text" translatable="yes"></property>

+	    </widget>

+	  </child>

+	</widget>

+	<packing>

+	  <property name="padding">0</property>

+	  <property name="expand">True</property>

+	  <property name="fill">True</property>

+	</packing>

+      </child>

+

+      <child>

+	<widget class="GtkStatusbar" id="statusbar">

+	  <property name="visible">True</property>

+	  <property name="has_resize_grip">True</property>

+	</widget>

+	<packing>

+	  <property name="padding">0</property>

+	  <property name="expand">False</property>

+	  <property name="fill">True</property>

+	</packing>

+      </child>

+    </widget>

+  </child>

+</widget>

+

+</glade-interface>

diff --git a/install.txt b/install.txt
index 741181237..2b1422107 100644
--- a/install.txt
+++ b/install.txt
@@ -1,43 +1,22 @@
 Installation
 ============
 
-Installation on Windows - the easy way
---------------------------------------
-
-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; 
-do not use a temporary one! You should add the ``bin`` directory of Nimrod to 
-your ``$PATH`` environment variable.
-
 
-
-Installation on UNIX
---------------------
+Installation on Linux/UNIX
+--------------------------
 
 Note:
   A C compiler is required - knowledge of C is not!
 
-**Note: Installation under UNIX does not work yet** - you have to bootstrap. 
-Play with the ``koch.py`` script to compile the compiler. Under Windows the
-``nim.exe`` is provided, so you don't need to do anything. Under UNIX you need
-to install the `FreePascal <www.freepascal.org>`_ compiler. 
-Compile the compiler:: 
-
-  python koch.py nim
-
-To bootstrap (does not work yet)::
-
-  python koch.py boot
-
 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 Linux
-distributions do not ship with a C compiler preinstalled - then you have to
-install one.
+distributions do not ship with a GCC compiler preinstalled - then you have to
+install it.
 
 After you have made sure that a C compiler is available, 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; do not use a temporary one! Good choices are ``/opt/nimrod`` or - 
+directory; do not use a temporary one! Good choices are ``/opt/nimrod`` or -
 if you don't have root access - ``~/programs/nimrod``.
 Then run the following command::
 
@@ -46,7 +25,7 @@ Then run the following command::
 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. The alternative is to create a symbolic link in ``/usr/bin``::
+manually. An alternative is to create a symbolic link in ``/usr/bin``::
 
   [sudo] ln -s $your_install_dir/bin/nimrod  /usr/bin/nimrod
 
@@ -55,35 +34,43 @@ Installation on the Macintosh
 -----------------------------
 
 Only MacOS X is supported.
-Since MacOS X is UNIX based too, it works like the installation on UNIX. You
+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 - the easy way
+--------------------------------------
+
+Install Nimrod by downloading and running
+the ``nimrod_windows_$version.exe`` file. The installation procedure detects
+which C compilers are installed and writes the ``config/nimrod.cfg`` file
+for you. If no installed C compiler is found, the ``LLVM-GCC`` compiler is
+used that is bundled with this installer. So it should just work.
+
+
 Installation on Windows - the hard way
 --------------------------------------
 
 Windows does not ship with a C compiler; you have to install one. The
 following C compilers are supported under Windows:
 
-- | Digital Mars C++
-  | http://www.digitalmars.com/download/freecompiler.html
-- | Watcom C++
-  | http://www.openwatcom.org/ftp/
-- | Borland C++ (5.5 or above; including Borland C++Builder)
-  | http://www.borland.com/downloads/download_cbuilder.html
-  | (Download the package under "compiler" - this requires registration though.)
 - | Microsoft's Visual C++
   | http://msdn.microsoft.com/visualc
   | (You may need the SDK too - but not the full one: Essential are only
     the win32api header files and import libraries.)
+- | Borland C++ (5.5 or above; including Borland C++Builder)
+  | http://www.borland.com/downloads/download_cbuilder.html
+  | (Download the package under "compiler" - this requires registration though.)
 - | 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
-- | Pelles C Compiler
+- | Digital Mars C++
+  | http://www.digitalmars.com/download/freecompiler.html
+- | Pelles C Compiler (bootstrapping does not work with PCC!)
   | http://www.smorgasbordet.com/pellesc
-- | Lcc-win32
+- | Lcc-win32 (bootstrapping does not work with LCC!)
   | http://www.cs.virginia.edu/~lcc-win32
 
 All of the above compilers are available for free!
@@ -95,11 +82,5 @@ LLVM.
 After you have made sure that a C compiler is available, 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; do not use a temporary one! Then adapt the ``config/nimrod.cfg`` 
-file appropriately. Choose your C compiler and press ``OK``. You should
-add Nimrod to your ``$PATH``.
-
-Alternatively, you can install Nimrod with the ``koch.py`` script just like
-in the UNIX installation instructions. 
-
-Nimrod does not use the Registry and can be removed by just deleting its folder.
+directory; do not use a temporary one! Then adapt the ``config/nimrod.cfg``
+file appropriately. You should add Nimrod to your ``$PATH``.
diff --git a/koch.py b/koch.py
index 73b38cdaf..5dc380e82 100644
--- a/koch.py
+++ b/koch.py
@@ -7,7 +7,7 @@
 ##                                                                      ##
 ##########################################################################
 
-import os, os.path, sys, re, zipfile, filecmp, shutil, cPickle, time
+import os, os.path, sys, re, zipfile, shutil, cPickle, time
 import string, getopt, textwrap, glob, shutil, getopt, string, stat
 
 
@@ -18,9 +18,9 @@ from kochmod import *
 
 # --------------------- constants  ----------------------------------------
 
-CFLAGS = ""  # modify to set flags to the first compilation step
+CC_FLAGS = "-w"  # modify to set flags to the first compilation step
 
-NIMROD_VERSION = '0.5.1'
+NIMROD_VERSION = '0.6.0'
 # 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**
@@ -32,17 +32,59 @@ NIMROD_VERSION = '0.5.1'
 #             backwards-compatible)
 # Patch level: is increased for every patch
 
+SUPPORTED_OSES = "linux macosx windows solaris".split()
+# The list of supported operating systems
+SUPPORTED_CPUS = "i386 amd64 sparc".split()
+# The list of supported CPUs
+
+SUPPORTED_PLATTFORMS = """
+linux_i386* linux_amd64* linux_sparc
+macosx_i386* macosx_amd64
+solaris_i386 solaris_amd64 solaris_sparc
+windows_i386* windows_amd64
+""".split()
+# a star marks the tested ones
+
+NICE_NAMES = {
+  "linux": "Linux",
+  "macosx": "Mac OS X",
+  "windows": "Windows",
+  "solaris": "Solaris",
+}
 
 EXPLAIN = True
 force = False
 
+GENERATE_DIFF = False
+# if set, a diff.log file is generated when bootstrapping
+# this uses quite a good amount of RAM (ca. 12 MB), so it should not be done
+# on underpowered systems.
+
+USE_FPC = True
 INNOSETUP = r"c:\programme\innosetup5\iscc.exe /Q "
-ADV_SETUP = r"C:\Programme\AdvancedInstaller6.1\AdvancedInstaller.com " \
-            r"/build %s -force"
 PYINSTALLER = r"C:\Eigenes\DownLoad\Python\pyinstaller-1.3"
 
 # --------------------------------------------------------------------------
 
+DOC = """endb intern lib manual nimrodc steps
+         overview""".split()
+SRCDOC = """system os strutils base/regexprs math complex times
+            parseopt hashes strtabs lexbase parsecfg base/dialogs
+            posix/posix
+         """.split()
+
+ADD_SRCDOC = """windows/windows windows/mmsystem windows/nb30
+                windows/ole2 windows/shellapi windows/shfolder
+                base/cairo/cairo  base/cairo/cairoft
+                base/cairo/cairowin32  base/cairo/cairoxlib
+                base/gtk/atk  base/gtk/gdk2 base/gtk/gdk2pixbuf
+                base/gtk/gdkglext base/gtk/glib2  base/gtk/gtk2
+                base/gtk/gtkglext base/gtk/gtkhtml base/gtk/libglade2
+                base/gtk/pango base/gtk/pangoutils
+            """.split()
+
+# --------------------------------------------------------------------------
+
 def ask():
   return sys.stdin.readline().strip("\t \n\r\f").lower()
 
@@ -77,20 +119,21 @@ def cmd_nim():
   CogRule("wordrecg", "nim/wordrecg.pas", "data/keywords.txt")
   CogRule("commands", "nim/commands.pas",
           "data/basicopt.txt data/advopt.txt data/changes.txt")
-  c = Changed("nim", Glob("nim/*.pas"),
-              EXPLAIN)
+  CogRule("macros", "lib/macros.nim", "koch.py data/ast.yml")
+  c = Changed("nim", Glob("nim/*.pas"), EXPLAIN)
   if c or force:
     Exec(FPC_CMD)
     if Exists(ExeExt("bin/nim")):
       c.success()
+    return True
+  return False
 
 def cmd_rod(options):
-  cmd_nim()
   prereqs = Glob("lib/*.nim") + Glob("rod/*.nim") + [
     "lib/nimbase.h", "lib/dlmalloc.c", "lib/dlmalloc.h",
     "config/nimrod.cfg"]
   c = Changed("rod", prereqs, EXPLAIN)
-  if c or force:
+  if cmd_nim() or c or force:
     buildRod(options)
     if Exists(ExeExt("bin/nimrod")):
       c.success()
@@ -107,7 +150,9 @@ HELP = """\
 Usage:
   koch.py [options] command [options for command]
 Options:
-  --force, -f, -B, -b      force rebuild
+  --force, -f, -B, -b      forces rebuild
+  --diff                   generates a diff.log file when bootstrapping
+  --no_fpc                 bootstrap without FPC
   --help, -h               shows this help and quits
 Possible Commands:
   install [options]        installs the Nimrod Compiler: options
@@ -118,11 +163,12 @@ Possible Commands:
   configure                configures the environment for developing Nimrod
   doc                      builds the documentation in HTML
   clean                    cleans Nimrod project; removes generated files
-  dist [target]            produces a distribution as
-                           nimrod_$target_$version.zip
+  dist [os] [cpu]          produces a distribution as nimrod_$os_$cpu.zip
+  alldist                  produces all sensible download packages
   boot [options]           bootstraps with given command line options
   rodsrc                   generates Nimrod version from Pascal version
   web                      generates the website (requires Cheetah)
+  tests [options]          run the testsuite (with options)
 """ % (NIMROD_VERSION + ' ' * (44-len(NIMROD_VERSION)))
 
 def main(args):
@@ -138,6 +184,12 @@ def main(args):
       elif a in ("-h", "--help", "-?"):
         print HELP
         return
+      elif a == "--diff":
+        global GENERATE_DIFF
+        GENERATE_DIFF = True
+      elif a == "--no_fpc":
+        global USE_FPC
+        USE_FPC = False
       else:
         Error("illegal option: " + a)
       i += 1
@@ -148,119 +200,232 @@ def main(args):
     elif cmd == "configure": cmd_configure()
     elif cmd == "doc": cmd_doc()
     elif cmd == "clean": cmd_clean()
-    elif cmd == "dist": 
-      if i < len(args)-1: cmd_dist(args[i+1])
-      else: cmd_dist()
+    elif cmd == "dist":
+      if i < len(args)-2:
+        cmd_dist(args[i+1], args[i+2])
+      elif i < len(args)-1:
+        cmd_dist(args[i+1])
+      else:
+        cmd_dist()
+    elif cmd == "alldist": cmd_alldist()
     elif cmd == "boot": cmd_boot(" ".join(args[i+1:]))
     #elif cmd == "tests": cmd_tests(" ".join(args[i+1:]))
     elif cmd == "install": cmd_install(args[i+1:])
     elif cmd == "rodsrc": cmd_rodsrc()
     elif cmd == "web": cmd_web()
+    elif cmd == "tests": cmd_tests(" ".join(args[i+1:]))
     else: Error("illegal command: " + cmd)
 
 # -------------------------- bootstrap ----------------------------------------
 
+def readCFiles():
+  result = {}
+  if GENERATE_DIFF:
+    for f in Glob("rod/rod_gen/*.c") + Glob("lib/rod_gen/*.c"):
+      x = os.path.split(f)[1]
+      result[x] = file(f).readlines()[1:]
+  return result
+
+def genBootDiff(genA, genB):
+  def interestingDiff(a, b):
+    a = re.sub(r"([a-zA-Z_]+)([0-9]+)", r"\1____", a)
+    b = re.sub(r"([a-zA-Z_]+)([0-9]+)", r"\1____", b)
+    return a != b
+
+  BOOTLOG = "bootdiff.log"
+  result = False
+  for f in Glob("diff/*.c"): Remove(f)
+  if Exists(BOOTLOG): Remove(BOOTLOG)
+  if GENERATE_DIFF:
+    lines = [] # lines of the generated logfile
+    if len(genA) != len(genB): Warn("number of generated files differ!")
+    for filename, acontent in genA.iteritems():
+      bcontent = genB[filename]
+      #g = difflib.unified_diff(acontent, bcontent, filename + " generation A",
+      #                        filename + " generation B", lineterm='')
+      #for d in g: lines.append(d)
+      if bcontent != acontent:
+        lines.append("------------------------------------------------------")
+        lines.append(filename + " differs")
+        # write the interesting lines to the log file:
+        for i in range(min(len(acontent), len(bcontent))):
+          la = acontent[i][:-1] # without newline!
+          lb = bcontent[i][:-1]
+          if interestingDiff(la, lb):
+            lines.append("%6d - %s" % (i, la))
+            lines.append("%6d + %s" % (i, lb))
+        if len(acontent) > len(bcontent):
+          cont = acontent
+          marker = "-"
+        else:
+          cont = bcontent
+          marker = "+"
+        for i in range(min(len(acontent), len(bcontent)), len(cont)):
+          lines.append("%6d %s %s" % (i, marker, cont[i]))
+        file(os.path.join("diff", "a_"+filename), "w+").write("".join(acontent))
+        file(os.path.join("diff", "b_"+filename), "w+").write("".join(bcontent))
+    if lines: result = True
+    file(BOOTLOG, "w+").write("\n".join(lines))
+  return result
+
 def cmd_rodsrc():
   "converts the src/*.pas files into Nimrod syntax"
   PAS_FILES_BLACKLIST = """nsystem nmath nos ntime strutils""".split()
-  CMD = "nim boot --skip_proj_cfg -o:rod/%s.nim nim/%s"
-  cmd_nim()
+  if USE_FPC and detect("fpc -h"):
+    cmd_nim()
+    compiler = "nim"
+  else:
+    compiler = "nimrod"
+  CMD = "%s boot --skip_proj_cfg -o:rod/%s.nim nim/%s"
   result = False
   for fi in Glob("nim/*.pas"):
     f = FilenameNoExt(fi)
     if f in PAS_FILES_BLACKLIST: continue
     c = Changed(f+"__rodsrc", fi, EXPLAIN)
     if c or force:
-      Exec(CMD % (f, f+".pas"))
-      Exec("nim parse rod/%s.nim" % f)
+      Exec(CMD % (compiler, f, f+".pas"))
+      Exec("%s parse rod/%s.nim" % (compiler, f))
       c.success()
       result = True
   return result
 
 def cmd_boot(args):
+  def moveExes():
+    if Exists(ExeExt("rod/nimrod")):
+      Move(ExeExt("rod/nimrod"), ExeExt("bin/nimrod"))
+    else:
+      Move(ExeExt("rod/rod_gen/nimrod"), ExeExt("bin/nimrod"))
+
   writePlatdefC(getNimrodPath())
   d = detect("fpc -h")
-  if d:
+  if USE_FPC and d:
     Echo("'%s' detected" % d)
     cmd_nim()
     compiler = "nim"
   else:
-    Warn("Free Pascal is not installed; skipping Pascal step")
-    cmd_install(args)
+    if not detect("nimrod") and not detect("bin/nimrod"): cmd_install(args)
     compiler = "nimrod"
 
   cmd_rodsrc() # regenerate nimrod version of the files
 
   # move the new executable to bin directory (is done by cmd_rod())
   # use the new executable to compile the files in the bootstrap directory:
-  Exec("%s compile --compile:build/platdef.c %s rod/nimrod.nim" %
-       (compiler, args))
+  BOOTCMD = "%s compile --listcmd --debuginfo --compile:build/platdef.c " \
+            "--cfilecache:off %s rod/nimrod.nim"
+  Exec(BOOTCMD % (compiler, args))
+  genA = readCFiles() # first generation of generated C files
   # move the new executable to bin directory:
-  Move(ExeExt("rod/nimrod"), ExeExt("bin/nimrod"))
+  moveExes()
   # compile again and compare:
-  Exec("nimrod compile --compile:build/platdef.c %s rod/nimrod.nim" % args)
-
+  Exec(BOOTCMD % ("nimrod", args))
+  genB = readCFiles() # second generation of generated C files
+  diff = genBootDiff(genA, genB)
+  if diff:
+    Warn("generated C files are not equal: cycle once again...")
   # check if the executables are the same (they should!):
-  if filecmp.cmp(Path(ExeExt("rod/nimrod")),
-                 Path(ExeExt("bin/nimrod"))):
-    Echo("files are equal: everything seems fine!")
+  if FileCmp(Path(ExeExt("rod/nimrod")),
+             Path(ExeExt("bin/nimrod"))):
+    Echo("executables are equal: everything seems fine!")
   else:
-    Warn("files are not equal: cycle once again...")
+    Echo("executables are not equal: cycle once again...")
+    diff = True
+  if diff:
     # move the new executable to bin directory:
-    Move(ExeExt("rod/nimrod"), ExeExt("bin/nimrod"))
+    moveExes()
     # use the new executable to compile Nimrod:
-    Exec("nimrod compile %s rod/nimrod.nim" % args)
-    if filecmp.cmp(Path(ExeExt("rod/nimrod")),
-                   Path(ExeExt("bin/nimrod"))):
-      Echo("files are equal: everything seems fine!")
+    Exec(BOOTCMD % ("nimrod", args))
+    if FileCmp(Path(ExeExt("rod/nimrod")),
+               Path(ExeExt("bin/nimrod"))):
+      Echo("executables are equal: SUCCESS!")
     else:
-      Error("files are still not equal")
+      Warn("executables are still not equal")
 
 # ------------------ web ------------------------------------------------------
 
 def buildDoc(destPath):
-  DOC = "endb intern lib manual nimrodc tutorial overview".split()
-  SRCDOC = "system os strutils base/regexprs math complex times".split()
   # call nim for the documentation:
   for d in DOC:
-    Exec("nim rst2html --putenv:nimrodversion=%s -o:%s/%s.html "
+    Exec("nimrod rst2html --putenv:nimrodversion=%s -o:%s/%s.html "
           "--index=%s/theindex doc/%s" %
          (NIMROD_VERSION, destPath, d, destPath, d))
   for d in SRCDOC:
-    Exec("nim doc --putenv:nimrodversion=%s -o:%s/%s.html "
+    Exec("nimrod doc --putenv:nimrodversion=%s -o:%s/%s.html "
          "--index=%s/theindex lib/%s" %
          (NIMROD_VERSION, destPath, FilenameNoExt(d), destPath, d))
-  Exec("nim rst2html -o:%s/theindex.html %s/theindex" % (destPath, destPath))
+  Exec("nimrod rst2html -o:%s/theindex.html %s/theindex" % (destPath, destPath))
+
+def buildAddDoc(destPath):
+  # build additional documentation (without the index):
+  for d in ADD_SRCDOC:
+    c = Changed("web__"+d, ["lib/"+d+".nim"], EXPLAIN)
+    if c or force:
+      Exec("nimrod doc --putenv:nimrodversion=%s -o:%s/%s.html "
+           " lib/%s" % (NIMROD_VERSION, destPath, FilenameNoExt(d), d))
+      c.success()
+
+def buildDownloadTxt():
+  result = """\
+    "There are two major products that come out of Berkeley: LSD and UNIX.
+    We don't believe this to be a coincidence." -- Jeremy S. Anderson.
+
+Here you can download the latest version of the Nimrod Compiler.
+Please choose your platform:
+"""
+  for p in SUPPORTED_PLATTFORMS:
+    ops, cpu = p.split("_")
+    n = NICE_NAMES[ops]
+    if cpu[-1] == '*':
+      cpu = cpu[:-1]
+      tested = ""
+    else:
+      tested = ", untested!"
+    result += Subs("* source for $nice (${cpu}${tested}): `<download/"
+                   "nimrod_${ops}_${cpu}_${version}.zip>`_\n",
+                   nice=n, ops=ops, cpu=cpu, tested=tested,
+                   version=NIMROD_VERSION)
+  result += Subs("""\
+* installer for Windows (i386): `<download/nimrod_windows_${version}.exe>`_
+  (includes LLVM and everything else you need)
+
+.. include:: ../install.txt
+""", version=NIMROD_VERSION)
+  return result
 
 
 def cmd_web():
   import Cheetah.Template
+  # write the web/download.txt file, because maintaining it sucks:
+  f = file("web/download.txt", "w+")
+  f.write(buildDownloadTxt())
+  f.close()
+
   TABS = [ # Our tabs: (Menu entry, filename)
     ("home", "index"),
+    ("news", "news"),
     ("documentation", "documentation"),
     ("download", "download"),
     ("FAQ", "question"),
     ("links", "links")
   ]
   TEMPLATE_FILE = "web/sunset.tmpl"
-  #CMD = "rst2html.py --template=web/docutils.tmpl web/%s.txt web/%s.temp "
-  CMD = "nim rst2html --compileonly " \
+  CMD = "nimrod rst2html --compileonly " \
         " --putenv:nimrodversion=%s -o:web/%s.temp web/%s.txt"
 
+  buildAddDoc("web/upload")
   c = Changed("web", Glob("web/*.txt") + [TEMPLATE_FILE, "koch.py"] +
                      Glob("doc/*.txt") + Glob("lib/*.txt") + Glob("lib/*.nim")+
-                     Glob("config/*.cfg"),
+                     Glob("config/*.cfg") + ["install.txt"],
               EXPLAIN)
   if c or force:
     cmd_nim() # we need Nimrod for processing the documentation
-    Exec(CMD % (NIMROD_VERSION, "news","news"))
-    newsText = file("web/news.temp").read()
+    Exec(CMD % (NIMROD_VERSION, "ticker","ticker"))
+    tickerText = file("web/ticker.temp").read()
     for t in TABS:
       Exec(CMD % (NIMROD_VERSION, t[1],t[1]))
 
       tmpl = Cheetah.Template.Template(file=TEMPLATE_FILE)
       tmpl.content = file("web/%s.temp" % t[1]).read()
-      tmpl.news = newsText
+      tmpl.ticker = tickerText
       tmpl.tab = t[1]
       tmpl.tabs = TABS
       tmpl.lastupdate = time.strftime("%Y-%m-%d %X", time.gmtime())
@@ -268,7 +433,7 @@ def cmd_web():
       f.write(str(tmpl))
       f.close()
     # remove temporaries:
-    Remove("web/news.temp")
+    Remove("web/ticker.temp")
     for t in TABS: Remove("web/%s.temp" % t[1])
     buildDoc("web/upload")
     if Exists("web/upload/index.html"):
@@ -299,8 +464,9 @@ CLEAN_EXT = "ppu o obj dcu ~pas ~inc ~dsk ~dpr map tds err bak pyc exe rod"
 def cmd_clean(dir = "."):
   extRegEx = re.compile("|".join([r".*\."+ x +"$" for x in CLEAN_EXT.split()]))
   Remove("koch.dat")
+  for f in Glob("*.pdb"): Remove(f)
+  for f in Glob("*.idb"): Remove(f)
   for f in Glob("web/*.html"): Remove(f)
-  for f in Glob("doc/html/*.html"): Remove(f)
   for f in Glob("doc/*.html"): Remove(f)
   for f in Glob("rod/*.nim"): Remove(f) # remove generated source code
 
@@ -331,38 +497,50 @@ distlist = {
     "lib/*.nim -> lib",
 
     "rod/*.* -> rod",
-    "build/*.* -> build",
+    "build/empty.txt -> build/empty.txt",
     "nim/*.* -> nim",
 
     "data/*.yml -> data",
     "data/*.txt -> data",
     "obj/*.txt",
+    "diff/*.txt",
+
+    "config/doctempl.cfg -> config/doctempl.cfg",
+    # other config file is generated
 
-    "config/*.cfg -> config",
     # documentation:
     "doc/*.txt",
     "doc/*.html",
+    "doc/*.cfg",
     # tests:
-    "tests/*.*",
+    "tests/*.nim",
+    "tests/*.html",
+    "tests/*.txt",
+    "tests/*.cfg",
+    "tests/gtk/*.nim",
     # library:
     "lib/base/*.c -> lib/base",
     "lib/base/*.nim -> lib/base",
     "lib/base/gtk/*.nim -> lib/base/gtk",
     "lib/base/cairo/*.nim -> lib/base/cairo",
     "lib/windows/*.nim -> lib/windows",
-    "lib/posix/*.nim -> lib/posix"
+    "lib/posix/*.nim -> lib/posix",
       # don't be too clever here; maybe useful on Linux
       # for cross-compiling to Windows?
   ),
   'windows': (
     "bin/nim.exe -> bin/nim.exe",
+    "bin/nimrod.exe -> bin/nimrod.exe",
     "lib/dlmalloc.h -> lib/dlmalloc.h",
     "lib/dlmalloc.c -> lib/dlmalloc.c",
     "dist/llvm-gcc4.2",
   ),
   'unix': (
+    "bin/empty.txt -> bin/empty.txt",
     "lib/rod_gen/*.c -> build",
     "rod/rod_gen/*.c -> build",
+    "lib/*.h -> build",
+    "lib/*.c -> build",
     "lib/dlmalloc.h -> lib/dlmalloc.h",
     "lib/dlmalloc.c -> lib/dlmalloc.c",
   )
@@ -391,7 +569,7 @@ def iterInstallFiles(target=getHost()):
         source, dest = splittedRule
         if '*' in source:
           for f in Glob(source):
-            if not stat.S_ISDIR(os.stat(f)[stat.ST_MODE]):        
+            if not stat.S_ISDIR(os.stat(f)[stat.ST_MODE]):
               yield (Path(f), Path(dest + '/' + os.path.split(f)[1]))
         else:
           yield (Path(source), Path(dest))
@@ -405,20 +583,186 @@ def iterInstallFiles(target=getHost()):
           if not stat.S_ISDIR(os.stat(f)[stat.ST_MODE]):
             yield (Path(f), Path(f))
 
-def cmd_dist(target=""):
+def cmd_dist(ops="", cpu="i386"):
   from zipfile import ZipFile
-  if not target:
-    if os.name == "nt": target = "windows"
-    else: target = "unix"
-  distfile = Path('web/upload/download/nimrod_%s_%s.zip' %
-                 (target, getVersion()))
+  if not ops: ops = getHost()
+  Exec("nimrod compile --cfilecache:off --compileonly " \
+       " --os:%s --cpu:%s rod/nimrod.nim" % (ops, cpu))
+  # assure that we transfer the right C files to the archive
+  distfile = Path('web/upload/download/nimrod_%s_%s_%s.zip' %
+                 (ops, cpu, getVersion()))
   Echo("creating: %s..." % distfile)
   z = ZipFile(distfile, 'w', zipfile.ZIP_DEFLATED)
+  if ops == "windows": target = "windows"
+  else: target = "unix"
   for source, dest in iterInstallFiles(target):
-    z.write(source, Path(dest))
+    z.write(source, os.path.join("nimrod", Path(dest)))
   z.close()
   Echo("... done!")
 
+def cmd_alldist():
+  cmd_rodsrc()
+  cmd_doc() # assure that the docs are packed
+  if getHost() == "windows":
+    # build the Windows installer too:
+    cmd_installer()
+  for p in SUPPORTED_PLATTFORMS:
+    o, c = p.split("_")
+    c = c.replace("*", "")
+    cmd_dist(o, c)
+
+# ------------------ config template -----------------------------------------
+
+CONFIG_TEMPLATE = r"""# Configuration file for the Nimrod Compiler.
+# Template from the koch.py script.
+# (c) 2008 Andreas Rumpf
+
+# Feel free to edit the default values as you need.
+
+# You may set environment variables with
+# @putenv "key" "val"
+# Environment variables cannot be used in the options, however!
+
+# Just call the compiler with several options:
+cc = $defaultcc
+lib="$$nimrod/lib"
+path="$$lib/base"
+path="$$lib/base/gtk"
+path="$$lib/base/cairo"
+path="$$lib/base/x11"
+path="$$lib/windows"
+path="$$lib/posix"
+path="$$lib/ecmas"
+path="$$lib/extra"
+
+@if release:
+  checks:off
+  stacktrace:off
+  debugger:off
+  line_dir:off
+@end
+
+# additional defines:
+#define=""
+# additional options always passed to the compiler:
+force_build
+line_dir=off
+
+hint[LineTooLong]=off
+hint[XDeclaredButNotUsed]=off
+
+@if unix:
+  passl= "-ldl"
+@end
+
+@if icc:
+  passl = "-cxxlib"
+  passc = "-cxxlib"
+@end
+
+# Configuration for the LLVM GCC compiler:
+@if windows:
+  llvm_gcc.path = r"$$nimrod\dist\llvm-gcc4.2\bin"
+@end
+llvm_gcc.options.debug = "-g"
+llvm_gcc.options.always = "-w"
+llvm_gcc.options.speed = "-O3 -ffast-math"
+llvm_gcc.options.size = "-Os -ffast-math"
+
+# Configuration for the Borland C++ Compiler:
+@if windows:
+  bcc.path = r"${bcc_path}"
+@end
+bcc.options.debug = ""
+# turn off warnings about unreachable code and inline procs:
+bcc.options.always = "-w- -H- -q -RT- -a8 -w-8027 -w-8066"
+bcc.options.speed = "-O2 -6"
+bcc.options.size = "-O1 -6"
+
+# Configuration for the Visual C/C++ compiler:
+@if vcc:
+  @prepend_env path r"${vcc_path}\..\..\Common7\IDE;"
+  @prepend_env INCLUDE r"${vcc_path}\..\include;$vcc_path\..\ATLMFC\INCLUDE;"
+  @prepend_env LIB r"${vcc_path}\..\lib;$vcc_path\..\..\SDK\v2.0\Lib;"
+  passl: r"/F33554432" # set the stack size to 32 MB
+@end
+@if windows:
+  vcc.path = r"${vcc_path}"
+@end
+vcc.options.debug = "/RTC1 /ZI"
+vcc.options.always = "/nologo"
+vcc.options.speed = "/Ogityb2 /G7 /arch:SSE2"
+vcc.options.size = "/O1 /G7"
+
+# Configuration for the Watcom C/C++ compiler:
+@if windows:
+  wcc.path = r""
+@end
+wcc.options.debug = "-d2"
+wcc.options.always = "-6 -zw -w-"
+wcc.options.speed = "-ox -on -6 -d0 -fp6 -zW"
+wcc.options.size = "-ox -on -6 -d0 -fp6 -zW"
+
+# Configuration for the GNU C/C++ compiler:
+@if windows:
+  gcc.path = r"${gcc_path}"
+@end
+gcc.options.debug = "-g"
+@if macosx:
+  gcc.options.always = "-w -fasm-blocks"
+@else:
+  gcc.options.always = "-w"
+@end
+gcc.options.speed = "-O3 -ffast-math"
+gcc.options.size = "-Os -ffast-math"
+
+# Configuration for the Digital Mars C/C++ compiler:
+@if windows:
+  dmc.path = r"${dmc_path}"
+@end
+dmc.options.debug = "-g"
+dmc.options.always = "-Jm"
+dmc.options.speed = "-ff -o -6"
+dmc.options.size = "-ff -o -6"
+
+# Configuration for the LCC compiler:
+@if windows:
+  lcc.path = r"${lcc_path}"
+@end
+lcc.options.debug = "-g5"
+lcc.options.always = "-e1"
+lcc.options.speed = "-O -p6"
+lcc.options.size = "-O -p6"
+
+# Configuration for the Tiny C Compiler:
+@if windows:
+  tcc.path = r""
+@end
+tcc.options.debug = "-b"
+tcc.options.always = ""
+tcc.options.speed = ""
+tcc.options.size = ""
+
+# Configuration for the Pelles C compiler:
+@if windows:
+  pcc.path = r"${pcc_path}"
+@end
+pcc.options.debug = "-Zi"
+pcc.options.always = "-Ze"
+pcc.options.speed = "-Ox"
+pcc.options.size = "-Os"
+
+@if windows:
+  icc.path = r""
+@end
+icc.options.debug = "-g"
+icc.options.always = "-w"
+icc.options.speed = "-O3 -ffast-math"
+icc.options.size = "-Os -ffast-math"
+
+@write "used default config file"
+"""
+
 # ------------------------------ windows installer ----------------------------
 
 WIN_INSTALLER_TEMPLATE = (r"""
@@ -436,6 +780,7 @@ OutputBaseFilename=nimrod_windows_$version
 Compression=lzma
 SolidCompression=yes
 PrivilegesRequired=none
+ChangesEnvironment=yes
 
 [Languages]
 Name: english; MessagesFile: compiler:Default.isl
@@ -445,15 +790,21 @@ $files
 
 [Icons]
 Name: {group}\Console for Nimrod; Filename: {cmd}
-Name: {group}\Documentation; Filename: {app}\doc\index.html
+Name: {group}\Documentation; Filename: {app}\doc\overview.html
 Name: {group}\{cm:UninstallProgram,Nimrod Compiler}; Filename: {uninstallexe}
 
 [UninstallDelete]
 Type: files; Name: "{app}\config\nimrod.cfg"
 
-[Run]
-Filename: "{app}\bin\nimconf.exe"; Description: "Launch configuration"; """ +
-"""Flags: postinstall nowait skipifsilent
+;[Run]
+;Filename: "{app}\bin\nimconf.exe"; Description: "Launch configuration"; """ +
+r"""Flags: postinstall nowait skipifsilent
+
+[Tasks]
+Name: generateconfigfile; """ +
+r"""Description: &Generate configuration file;
+Name: modifypath; Description: """ +
+r"""&Add Nimrod your system path (if not in path already);
 
 [Code]
 function GiveMeAPath(const DefaultPathName: string): string;
@@ -463,13 +814,377 @@ begin
   Result := Result + '\' + DefaultPathName;
 end;
 
-function setEnvCmd(const default: string): string;
+// ----------------------------------------------------------------------------
+//
+// Inno Setup Ver:  5.2.1
+// Script Version:  1.3.1
+// Author:          Jared Breland <jbreland@legroom.net>
+// Homepage:    http://www.legroom.net/software
+//
+// Script Function:
+//  Enable modification of system path directly from Inno Setup installers
+//
+// Instructions:
+//  Copy modpath.iss to the same directory as your setup script
+//
+//  Add this statement to your [Setup] section
+//    ChangesEnvironment=yes
+//
+//  Add this statement to your [Tasks] section
+//  You can change the Description or Flags, but the Name must be modifypath
+//    Name: modifypath; Description: &Add application directory to your
+//    system path; Flags: unchecked
+//
+//  Add the following to the end of your [Code] section
+//  setArrayLength must specify the total number of dirs to be added
+//  Dir[0] contains first directory, Dir[1] contains second, etc.
+
+function ModPathDir(): TArrayOfString;
+begin
+  setArrayLength(result, 2);
+  result[0] := ExpandConstant('{app}') + '\bin';
+  result[1] := ExpandConstant('{app}') + '\dist\llvm-gcc4.2\bin';
+end;
+
+// ----------------------------------------------------------------------------
+
+procedure ModPath();
+var
+  oldpath, newpath, aExecFile: String;
+  pathArr, aExecArr, pathdir: TArrayOfString;
+  i, d: Integer;
+begin
+  // Get array of new directories and act on each individually
+  pathdir := ModPathDir();
+  for d := 0 to GetArrayLength(pathdir)-1 do begin
+    // Modify WinNT path
+    if UsingWinNT() then begin
+      // Get current path, split into an array
+      RegQueryStringValue(HKEY_LOCAL_MACHINE,
+        'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
+        'Path', oldpath);
+      oldpath := oldpath + ';';
+      i := 0;
+      while (Pos(';', oldpath) > 0) do begin
+        SetArrayLength(pathArr, i+1);
+        pathArr[i] := Copy(oldpath, 0, Pos(';', oldpath)-1);
+        oldpath := Copy(oldpath, Pos(';', oldpath)+1, Length(oldpath));
+        i := i + 1;
+        // Check if current directory matches app dir
+        if pathdir[d] = pathArr[i-1] then begin
+          // if uninstalling, remove dir from path
+          if IsUninstaller() then continue
+          // if installing, abort because dir was already in path
+          else abort;
+        end;
+        // Add current directory to new path
+        if i = 1 then newpath := pathArr[i-1]
+        else newpath := newpath + ';' + pathArr[i-1];
+      end;
+      // Append app dir to path if not already included
+      if not IsUninstaller() then
+        newpath := newpath + ';' + pathdir[d];
+      // Write new path
+      RegWriteStringValue(HKEY_LOCAL_MACHINE,
+        'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
+        'Path', newpath);
+    end
+    else begin
+      // Modify Win9x path
+      // Convert to shortened dirname
+      pathdir[d] := GetShortName(pathdir[d]);
+      // If autoexec.bat exists, check if app dir already exists in path
+      aExecFile := 'C:\AUTOEXEC.BAT';
+      if FileExists(aExecFile) then begin
+        LoadStringsFromFile(aExecFile, aExecArr);
+        for i := 0 to GetArrayLength(aExecArr)-1 do begin
+          if not IsUninstaller() then begin
+            // If app dir already exists while installing, abort add
+            if (Pos(pathdir[d], aExecArr[i]) > 0) then
+              abort;
+          end
+          else begin
+            // If app dir exists and = what we originally set,
+            // then delete at uninstall
+            if aExecArr[i] = 'SET PATH=%PATH%;' + pathdir[d] then
+              aExecArr[i] := '';
+          end;
+        end;
+      end;
+      // If app dir not found, or autoexec.bat didn't exist, then
+      // (create and) append to current path
+      if not IsUninstaller() then begin
+        SaveStringToFile(aExecFile, #13#10 + 'SET PATH=%PATH%;' + pathdir[d],
+                         True);
+      end
+      else begin
+        // If uninstalling, write the full autoexec out
+        SaveStringsToFile(aExecFile, aExecArr, False);
+      end;
+    end;
+
+    // Write file to flag modifypath was selected
+    // Workaround since IsTaskSelected() cannot be called at uninstall and
+    // AppName and AppId cannot be "read" in Code section
+    if not IsUninstaller() then
+      SaveStringToFile(ExpandConstant('{app}') + '\uninsTasks.txt',
+                       WizardSelectedTasks(False), False);
+  end;
+end;
+
+// We check for C compilers in the following order:
+//   Visual C++ (via registry), Borland C++ (via registry),
+//   Lcc (via registry), Pcc (via registry), DMC (via PATH),
+//   LLVM-GCC (via PATH), GCC (via PATH)
+// The user is informed which C compilers have been found and whether
+// LLVM-GCC should be installed
+const
+  IdxVisualC = 0;
+  IdxBorlandC = 1;
+  IdxLcc = 2;
+  IdxPcc = 3;
+  IdxDMC = 4;
+  IdxLLVMGCC = 5;
+  IdxGCC = 6;
+  NumberCC = 7; // number of C compilers
+
+function idxToLongName(idx: integer): string;
+begin
+  case idx of
+    IdxVisualC: result := 'Microsoft Visual C/C++ Compiler';
+    IdxBorlandC: result := 'Borland C/C++ Compiler';
+    IdxLcc: result := 'Jacob Navia''s LCC-win32';
+    IdxPcc: result := 'Pelles C Compiler';
+    IdxDMC: result := 'Digital Mars C/C++ Compiler';
+    IdxLLVMGCC: result := 'LLVM GCC Compiler';
+    IdxGCC: result := 'GNU C/C++ Compiler';
+    else result := '';
+  end
+end;
+
+function idxToShortName(idx: integer): string;
+begin
+  case idx of
+    IdxVisualC: result := 'vcc';
+    IdxBorlandC: result := 'bcc';
+    IdxLcc: result := 'lcc';
+    IdxPcc: result := 'pcc';
+    IdxDMC: result := 'dmc';
+    IdxLLVMGCC: result := 'llvm_gcc';
+    IdxGCC: result := 'gcc';
+    else result := '';
+  end
+end;
+
+function idxToExe(idx: integer): string;
+begin
+  case idx of
+    IdxVisualC: result := 'cl.exe';
+    IdxBorlandC: result := 'bcc32.exe';
+    IdxLcc: result := 'lcc.exe';
+    IdxPcc: result := 'cc.exe';
+    IdxDMC: result := 'dmc.exe';
+    IdxLLVMGCC: result := 'llvm-gcc.exe';
+    IdxGCC: result := 'gcc.exe';
+    else result := '';
+  end
+end;
+
+function ReadStrFromRegistry(const RootKey: Integer;
+                             const SubKeyName, ValueName: String): string;
+begin
+  result := '';
+  RegQueryStringValue(rootKey, removeBackslash(subkeyName),
+                      valueName, result);
+end;
+
+function detectCCompiler(idx: integer): string;
 var
-  op, app: string;
+  i: integer;
 begin
-  app := ExpandConstant('{app}');
-  if IsAdminLoggedOn then op := '' else op := 'u';
-  result := '"' + app + '\bin\setenv.exe" -' + op + 'a PATH "%' + app + '\bin"'
+  result := '';
+  case idx of
+    IdxVisualC: begin
+      for i := 20 downto 6 do begin
+        result := ReadStrFromRegistry(HKEY_LOCAL_MACHINE,
+          'SOFTWARE\Microsoft\DevStudio\' + IntToStr(i) +
+          '.0\Products\Microsoft Visual C++\', 'ProductDir');
+        if result <> '' then begin
+          result := result + '\bin'; // the path we want needs a \bin
+          break
+        end;
+        result := ReadStrFromRegistry(HKEY_LOCAL_MACHINE,
+          'SOFTWARE\Microsoft\VisualStudio\' + IntToStr(i) +
+          '.0\Setup', 'Dbghelp_path');
+        if result <> '' then
+          result := ReadStrFromRegistry(HKEY_LOCAL_MACHINE,
+            'SOFTWARE\Microsoft\VCExpress\' + IntToStr(i) +
+            '.0\', 'InstallDir');
+        if result <> '' then begin
+          // something like: 'C:\eigenes\compiler\vcc2005\Common7\IDE\'
+          // we need: 'C:\eigenes\compiler\vcc2005\vc\bin'
+          result := ExtractFilePath(RemoveBackslash(
+                       ExtractFilePath(RemoveBackslash(result))))
+            + 'vc\bin'; // the path we want needs a vc\bin
+          break
+        end
+      end
+    end;
+    IdxBorlandC: begin
+      for i := 20 downto 2 do begin
+        result := ReadStrFromRegistry(HKEY_LOCAL_MACHINE,
+          'SOFTWARE\Borland\C++Builder\' + IntToStr(i) + '.0\', 'RootDir');
+        if result <> '' then begin
+          result := result + '\bin';
+          break
+        end
+      end
+    end;
+    IdxLcc: begin
+      result := ReadStrFromRegistry(HKEY_CURRENT_USER,
+        'Software\lcc\compiler\', 'includepath');
+      if result <> '' then begin
+        result := RemoveBackslash(ExtractFilePath(result)) + '\bin';
+        // because we get something like 'c:\..\lcc\include'
+      end
+    end;
+    IdxPcc: begin
+      result := ReadStrFromRegistry(HKEY_LOCAL_MACHINE,
+        'SOFTWARE\PellesC', '');
+      if result <> '' then
+        result := result + '\bin';
+    end;
+    else begin end
+  end;
+  if (result <> '') then
+    if not FileExists(RemoveBackslash(result) + '\' + idxToExe(idx)) then
+      result := '';
+end;
+
+function myfind(const x: string; const inArray: array of string): integer;
+var
+  i: integer;
+begin
+  i := 0;
+  while i < GetArrayLength(inArray)-1 do begin
+    if CompareText(x, inArray[i]) = 0 then begin
+      result := i; exit
+    end;
+    i := i + 2;
+  end;
+  result := -1
+end;
+
+function mycopy(const s: string; a, b: integer): string;
+begin
+  result := copy(s, a, b-a+1);
+end;
+
+function isPatternChar(c: Char): boolean;
+begin
+  result := (c >= 'a') and (c <= 'z') or
+            (c >= 'A') and (c <= 'Z') or
+            (c >= '0') and (c <= '9') or
+            (c = '_');
+end;
+
+function myformat(const f: string; const args: array of string): string;
+var
+  i, j, x: integer;
+begin
+  result := '';
+  i := 1;
+  while i <= length(f) do
+    if f[i] = '$' then begin
+      case f[i+1] of
+        '$': begin
+          result := result + '$';
+          i := i + 2;
+        end;
+        '1', '2', '3', '4', '5', '6', '7', '8', '9': begin
+          result := result + args[ord(f[i+1]) - ord('0') - 1];
+          i := i + 2;
+        end;
+        '{': begin
+          j := i+1;
+          while (j <= length(f)) and (f[j] <> '}') do j := j+1;
+          x := myfind(mycopy(f, i+2, j-1), args);
+          if (x >= 0) and (x < GetArrayLength(args)-1) then
+            result := result + args[x+1];
+          i := j+1
+        end;
+        else if isPatternChar(f[i+1]) then begin
+          j := i+1;
+          while (j <= length(f)) and isPatternChar(f[j]) do j := j +1;
+          x := myfind(mycopy(f, i+1, j-1), args);
+          if (x >= 0) and (x < GetArrayLength(args)-1) then
+            result := result + args[x+1];
+          i := j
+        end
+        else i := i + 1;
+      end
+    end
+    else begin
+      result := result + f[i];
+      i := i + 1;
+    end
+end;
+
+$config_template
+
+procedure generateconfigfile();
+var
+  data: TArrayOfString;
+  i: integer;
+  outfile, d: string;
+begin
+  // set default compiler:
+  setArrayLength(data, (NumberCC+2) * 2); // *2 for key: value pairs
+  data[0] := 'defaultcc';
+  for i := 0 to NumberCC-1 do begin
+    data[4+i*2] := idxToShortName(i) + '_path';
+    d := detectCCompiler(i);
+    data[5+i*2] := d;
+    if d <> '' then begin
+      if data[1] = '' then data[1] := idxToShortName(i);
+      // first found C compiler is default
+    end
+  end;
+  if data[1] = '' then data[1] := 'llvm_gcc';
+  // set the library path:
+  data[2] := 'libpath';
+  data[3] := ExpandConstant('{app}') + '\lib';
+  // write the file:
+  outfile := ExpandConstant('{app}') + '\config\nimrod.cfg';
+  SaveStringToFile(outfile, myformat(template, data), false);
+end;
+
+procedure CurStepChanged(CurStep: TSetupStep);
+begin
+  if CurStep = ssPostInstall then begin
+    if IsTaskSelected('modifypath') then
+      ModPath();
+    if IsTaskSelected('generateconfigfile') then
+      generateconfigfile();
+  end
+end;
+
+procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
+var
+  appdir, selectedTasks: String;
+begin
+  appdir := ExpandConstant('{app}');
+  if CurUninstallStep = usUninstall then begin
+    if LoadStringFromFile(appdir + '\uninsTasks.txt', selectedTasks) then
+      if Pos('modifypath', selectedTasks) > 0 then
+        ModPath();
+    DeleteFile(appdir + '\uninsTasks.txt')
+  end;
+end;
+
+function NeedRestart(): Boolean;
+begin
+  result := IsTaskSelected('modifypath') and not UsingWinNT()
 end;
 """)
 
@@ -488,13 +1203,19 @@ def makeKochExe():
 
 def cmd_wininstaller():
   FILENAME = "install_nimrod.iss"
+  cmd_doc()
   # generate an installer file
   files = ""
   for source, dest in iterInstallFiles("windows"):
     files += ("Source: " + source + "; DestDir: {app}\\" +
               os.path.split(dest)[0] + "; Flags: ignoreversion\n")
   f = file(FILENAME, "w+")
-  f.write(Subs(WIN_INSTALLER_TEMPLATE, files=files, version=getVersion()))
+  pasconfig = "const template = ''"
+  for line in CONFIG_TEMPLATE.splitlines():
+    pasconfig += "  + '%s'+#13#10\n" % line
+  pasconfig += ";\n"
+  f.write(SafeSubs(WIN_INSTALLER_TEMPLATE, files=files, version=getVersion(),
+               config_template=pasconfig))
   f.close()
   if RawExec(INNOSETUP + FILENAME) == 0:
     # we cannot use ``Exec()`` here as this would
@@ -514,41 +1235,17 @@ def cmd_wininstaller():
 # Tests which contain none of the two directives should compile. Thus they
 # are executed after successful compilation and their output is verified
 # against the results specified with the '#OUT' directive.
-# (Tests which require user interaction are currently not possible.)
+# (Tests which require user interaction are not possible.)
 # Tests can have an #ERROR_MSG directive specifiying the error message
 # Nimrod shall produce.
-# The code here needs reworking or at least documentation, but I don't have
-# the time and it has been debugged and optimized.
-
-try:
-  import subprocess
-  HAS_SUBPROCESS = True
-except ImportError:
-  HAS_SUBPROCESS = False
-
-def runProg(args, inp=None):
-  """Executes the program + args given in args and
-     returns the output of the program as a string."""
-  if HAS_SUBPROCESS:
-    process = subprocess.Popen(args, bufsize=0, shell=True,
-      stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=inp,
-      universal_newlines=True)
-    standardOut, standardErr = process.communicate(inp)
-    process.wait() # be on the safe side
-    return standardOut
-  else:
-    if inp:
-      standardIn = file('buildin.tmp', 'w')
-      standardIn.write(inp)
-      standardIn.close()
-      b = " <buildin.tmp"
-    else:
-      b = ""
-    os.system(args + b + " >build.tmp")
-    result = file('build.tmp').read()
-    if not result: result = ""
-    return result
-    # system() is not optimal, but every Python version should have it
+
+def runProg(cmd):
+  pipe = os.popen4(cmd)[1]
+  result = ""
+  for line in pipe:
+    result += line
+  pipe.close()
+  return result
 
 class Spec(object): pass # specification object
 
@@ -567,8 +1264,11 @@ def parseTest(filename):
   spec.out = None  # output that should be produced
 
   for s in file(filename, 'rU'):
-    # we have to use this inefficient method for getting the current line
     i += 1 # our line-counter
+    obj = reOut.search(s)
+    if obj:
+      spec.out = obj.group(1)
+      break
     obj = reError.search(s)
     if obj:
       spec.line = i
@@ -582,16 +1282,11 @@ def parseTest(filename):
       spec.err = True
       if '.' not in specfile: specfile += ".nim"
       break
-    obj = reOut.search(s)
-    if obj:
-      spec.out = obj.group(1)
-      break
     obj = reErrorMsg.search(s)
     if obj:
       spec.out = obj.group(1)
       spec.err = True
       break
-
   return spec
 
 def doTest(filename, spec, options):
@@ -605,8 +1300,8 @@ def doTest(filename, spec, options):
   comp.out = None
   comp.err = False
   # call the compiler and read the compiler message:
-  results = runProg("nim compile --hints:on " + options + " " + filename)
-  print results
+  results = runProg("nimrod compile --hints:on " + options + " " + filename)
+  #print results
   # compiled regular expressions:
   reLineInfoError = re.compile(r"^((.*)\((\d+), \d+\)\s*Error\:\s*(.*))",
                                re.MULTILINE)
@@ -630,9 +1325,10 @@ def doTest(filename, spec, options):
     else:
       obj = reSuccess.search(results)
       if not obj: comp.err = True
+      else: comp.out = "Success"
 
   if comp.err and not comp.out:
-  # the compiler did not say "[Error]" nor "Compilation sucessful"
+    # the compiler did not say "[Error]" nor "Compilation sucessful"
     Echo("[Tester] %s -- FAILED; COMPILER BROKEN" % shortfile)
     return False
 
@@ -643,7 +1339,7 @@ def doTest(filename, spec, options):
     if spec.out:
       Echo("[Tester] %s -- FAILED\n"
            "Compiler says: %s\n"
-           "But specification says: Error %s"
+           "But specification says: Output %s"
            % (shortfile, comp.out, spec.out) )
     elif spec.err:
       if spec.file is None: spec.file = filename
@@ -703,148 +1399,6 @@ def cmd_tests(options): # run the testsuite
 
 # --------------- install target ----------------------------------------------
 
-CONFIG_TEMPLATE = r"""# Configuration file for the Nimrod Compiler.
-# Generated by the koch.py script.
-# (c) 2008 Andreas Rumpf
-
-# Feel free to edit the default values as you need.
-
-# You may set environment variables with
-# @putenv "key" "val"
-# Environment variables cannot be used in the options, however!
-
-# Just call the compiler with several options:
-cc = @if unix: %(cc)s @else: llvm_gcc @end
-lib="$nimrod/lib"
-path="$lib/base"
-path="$lib/base/gtk"
-path="$lib/base/cairo"
-path="$lib/base/x11"
-path="$lib/windows"
-path="$lib/posix"
-path="$lib/extra"
-
-# additional defines:
-#define=""
-# additional options always passed to the compiler:
-force_build
-line_dir=off
-
-hint[LineTooLong]=off
-hint[XDeclaredButNotUsed]=off
-
-@if unix:
-  passl= "-ldl"
-  path = "$lib/base/gtk"
-@end
-
-@if icc:
-  passl = "-cxxlib"
-  passc = "-cxxlib"
-@end
-
-# Configuration for the LLVM GCC compiler:
-@if windows:
-  llvm_gcc.path = r"dist\llvm-gcc4.2\bin"
-@end
-llvm_gcc.options.debug = "-g"
-llvm_gcc.options.always = "-w"
-llvm_gcc.options.speed = "-O3 -ffast-math"
-llvm_gcc.options.size = "-Os -ffast-math"
-
-# Configuration for the Borland C++ Compiler:
-@if windows:
-  bcc.path = r"C:\eigenes\compiler\cbuilder5\bin"
-@end
-bcc.options.debug = ""
-# turn off warnings about unreachable code and inline procs:
-bcc.options.always = "-w- -H- -q -RT- -a8 -w-8027 -w-8066"
-bcc.options.speed = "-O2 -6"
-bcc.options.size = "-O1 -6"
-
-# Configuration for the Visual C/C++ compiler:
-@if vcc:
-  @prepend_env path r"C:\Eigenes\compiler\vcc2005\Common7\IDE;"
-  @prepend_env INCLUDE r"C:\Eigenes\compiler\vcc2005\VC\include;C:\Eigenes\compiler\vcc2005\VC\ATLMFC\INCLUDE;"
-  @prepend_env LIB r"C:\Eigenes\compiler\vcc2005\VC\lib;C:\Eigenes\compiler\vcc2005\SDK\v2.0\Lib;"
-@end
-@if windows:
-  vcc.path = r"C:\Eigenes\compiler\vcc2005\VC\bin"
-@end
-vcc.options.debug = "/GZ /ZI"
-vcc.options.always = "/nologo"
-vcc.options.speed = "/Ogityb2 /G7 /arch:SSE2"
-vcc.options.size = "/O1 /G7"
-
-# Configuration for the Watcom C/C++ compiler:
-@if windows:
-  wcc.path = r"C:\eigenes\compiler\watcom\binnt"
-@end
-wcc.options.debug = "-d2"
-wcc.options.always = "-6 -zw -w-"
-wcc.options.speed = "-ox -on -6 -d0 -fp6 -zW"
-wcc.options.size = "-ox -on -6 -d0 -fp6 -zW"
-
-# Configuration for the GNU C/C++ compiler:
-@if windows:
-  gcc.path = r"C:\eigenes\compiler\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 -ffast-math"
-gcc.options.size = "-Os -ffast-math"
-
-# Configuration for the Digital Mars C/C++ compiler:
-@if windows:
-  dmc.path = r"C:\eigenes\compiler\d\dm\bin"
-@end
-dmc.options.debug = "-g"
-dmc.options.always = "-Jm"
-dmc.options.speed = "-ff -o -6"
-dmc.options.size = "-ff -o -6"
-
-# Configuration for the LCC compiler:
-@if windows:
-  lcc.path = r"C:\eigenes\compiler\lcc\bin"
-@end
-lcc.options.debug = "-g5"
-lcc.options.always = "-e1"
-lcc.options.speed = "-O -p6"
-lcc.options.size = "-O -p6"
-
-# Configuration for the Tiny C Compiler:
-@if windows:
-  tcc.path = r"C:\eigenes\compiler\tcc\bin"
-@end
-tcc.options.debug = "-b"
-tcc.options.always = ""
-tcc.options.speed = ""
-tcc.options.size = ""
-
-# Configuration for the Pelles C compiler:
-@if windows:
-  pcc.path = r"C:\eigenes\compiler\pellesc\bin"
-@end
-pcc.options.debug = "-Zi"
-pcc.options.always = "-Ze"
-pcc.options.speed = "-Ox"
-pcc.options.size = "-Os"
-
-@if windows:
-  icc.path = r"c:\eignes\compiler\icc\bin"
-@end
-icc.options.debug = "-g"
-icc.options.always = "-w"
-icc.options.speed = "-O3 -ffast-math"
-icc.options.size = "-Os -ffast-math"
-
-@write "used default config file"
-"""
-
 def writePlatdefC(nimrodpath):
   import os
   host = getHost()
@@ -856,9 +1410,8 @@ def writePlatdefC(nimrodpath):
     processor = "sparc"
   f = file(os.path.join(nimrodpath, "build/platdef.c"), "w+")
   f.write('/* Generated by koch.py */\n'
-          '#include "nimbase.h"\n'
-          'N_NIMCALL(char*, nimOS)(void) { return "%s"; }\n'
-          'N_NIMCALL(char*, nimCPU)(void) { return "%s"; }\n'
+          'char* nimOS(void) { return "%s"; }\n'
+          'char* nimCPU(void) { return "%s"; }\n'
           '\n' % (host, processor))
   f.close()
 
@@ -866,7 +1419,7 @@ def detect(cmd, lookFor="version"):
   pipe = os.popen4(cmd)[1]
   result = None
   for line in pipe:
-    if lookFor in line:
+    if lookFor in line.lower():
       result = line[:-1]
       break
   pipe.close()
@@ -900,9 +1453,15 @@ def getNimrodPath():
 def writeCfg(nimrodpath, ccSymbol=None):
   if not ccSymbol:
     ccSymbol = lookForCC()
-  configFile = os.path.join(nimrodpath, "config/nimrod.cfg")
-  script = CONFIG_TEMPLATE % {'cc': ccSymbol, 'nimrodpath': nimrodpath}
-  config = file(configFile)
+  configFile = os.path.join(nimrodpath, os.path.join("config", "nimrod.cfg"))
+  script = Subs(CONFIG_TEMPLATE, defaultcc=ccSymbol,
+                gcc_path="", lcc_path="", llvm_gcc_path="",
+                pcc_path="", bcc_path="", dmc_path="",
+                vcc_path="", wcc_path="")
+  try:
+    config = file(configFile)
+  except IOError:
+    config = None
   if config:
     if config.read().strip() != script.strip():
       config.close()
@@ -922,15 +1481,16 @@ def writeCfg(nimrodpath, ccSymbol=None):
           Echo("What do you mean? (y/n) ")
     else:
       config.close()
+  else:
+    file(configFile, "w+").write(script)
   return ccSymbol
 
 def cmd_install(args):
-  Echo("Nimrod should be in '%s'" % getNimrodPath())
+  nimrodpath = getNimrodPath()
+  Echo("Nimrod should be in '%s'" % nimrodpath)
   # We know that the user has already unzipped this archive into the
   # final directory. So we just create the config file and build Nimrod.
 
-  # write the configuration file, but check if one exists!
-  nimrodpath = getNimrodPath()
   try:
     opts, args = getopt.getopt(args, "", ["cc=", "ld="])
   except getopt.GetoptError:
@@ -942,9 +1502,10 @@ def cmd_install(args):
     if o == "--cc":   ccSymbol = a
     elif o == "--ld": ldSymbol = a
 
+  # write the configuration file, but check if one exists!
   ccSymbol = writeCfg(nimrodpath, ccSymbol)
   if not ldSymbol:
-    ldSymbol = ccSymbol.split()[0] + " -ldl -o bin/nimrod "
+    ldSymbol = ccSymbol.split()[0] + " -ldl -lm -o bin/nimrod "
 
   writePlatdefC(nimrodpath)
 
@@ -954,7 +1515,7 @@ def cmd_install(args):
     objfile = os.path.splitext(f)[0] + ".o"
     link += " " + objfile
     # compile only:
-    if Exec(ccSymbol + " " + CFLAGS + " -c -o " + objfile + " " + f) != 0:
+    if Exec(ccSymbol + " " + CC_FLAGS + " -c -o " + objfile + " " + f) != 0:
       Error("the C compiler did not like: " + f)
   if link == "":
     Error("could not find Nimrod's sources\n"
@@ -963,12 +1524,7 @@ def cmd_install(args):
   if Exec(ldSymbol + link) != 0:
     Error("the linking step failed!")
   # now we have a Nimrod executable :-)
-
-  nimrodpath = getNimrodPath()
-  writeScript(CONFIG_TEMPLATE % {'cc': ccSymbol, 'nimrodpath': nimrodpath},
-              os.path.join(nimrodpath, "config/nimrod.cfg"))
-
-  # remove the generated .o files as they take 1 MB:
+  # remove the generated .o files as they take 1 MB easily:
   for f in Glob("build/*.o"): Remove(f)
   Echo("SUCCESS!")
 
@@ -981,15 +1537,6 @@ def cmd_installer():
 
 # ------------------ configure ------------------------------------------------
 
-def writeScript(script, filename):
-  if os.name != "posix": filename += ".bat"
-  f = file(filename, "w+")
-  f.write(script)
-  f.close()
-  # make the script executable:
-  if os.name == "posix":
-    os.chmod(filename, 493) # 0o755
-
 def cmd_configure():
   d = detect("fpc -h")
   if d:
diff --git a/kochmod.py b/kochmod.py
index 87ef2621e..ca303cadf 100644
--- a/kochmod.py
+++ b/kochmod.py
@@ -1,640 +1,662 @@
-# This is kochmod, a simple module for make-like functionality.

-# For further documentation see koch.txt or koch.html.

-# (c) 2007 Andreas Rumpf

-

-VERSION = "1.0.3"

-

-import os, os.path, inspect, re, shutil, glob, cPickle, zlib, string, \

-  getopt, sys

-from types import *

-

-def Error(msg): sys.exit("[Koch] *** ERROR: " + msg)

-def Warn(msg): print "[Koch] *** WARNING: " + msg

-def Echo(msg): print "[Koch] " + msg

-def _Info(msg): print "[Koch] " + msg

-

-_FINGERPRINTS_FILE = "koch.dat"

-  # in this file all the fingerprints are kept to allow recognizing when a file

-  # has changed. This works reliably, which cannot be said from just taking

-  # filetime-stamps.

-

-# ---------------- C Compilers ------------------------------------------------

-

-# We support the following C compilers:

-C_Compilers = ["gcc", "lcc", "bcc", "dmc", "wcc", "tcc", "pcc", "ucc", "llvm"]

-

-_CC_Info = [

-  dict(

-    name = "gcc",

-    objExt = "o",

-    optSpeed = " -O3 -ffast-math ",

-    optSize = " -Os -ffast-math ",

-    comp = "gcc -c $options $include -o $objfile $file",

-    buildGui = " -mwindows",

-    buildDll = " -mdll",

-    link = "gcc $options $buildgui $builddll -o $exefile $objfiles",

-    includeCmd = " -I",

-    debug = "",

-    defineValue = " -D$name=$value",

-    define = " -D$name",

-    undef = " -U$name",

-    pic = "-fPIC"

-  ), dict(

-    name = "lcc",

-    objExt = "obj",

-    optSpeed = " -O -p6 ",

-    optSize = " -O -p6 ",

-    comp = "lcc -e1 $options $include -Fo$objfile $file",

-    buildGui = " -subsystem windows",

-    buildDll = " -dll",

-    link = "lcclnk $options $buildgui $builddll -O $exefile $objfiles",

-    includeCmd = " -I",

-    debug = " -g5 ",

-    defineValue = " -D$name=$value",

-    define = " -D$name",

-    undef = " -U$name",

-    pic = ""

-  ), dict(

-    name = "bcc",

-    objExt = "obj",

-    optSpeed = " -O2 -6 ",

-    optSize = " -O1 -6 ",

-    comp = "bcc32 -c -H- -q -RT- -a8 $options $include -o$objfile $file",

-    buildGui = " -tW",

-    buildDll = " -tWD",

-    link = "bcc32 $options $buildgui $builddll -e$exefile $objfiles",

-    includeCmd = " -I",

-    debug = "",

-    defineValue = " -D$name=$value",

-    define = " -D$name",

-    undef = " -U$name",

-    pic = ""

-  ), dict(

-    name = "dmc",

-    objExt = "obj",

-    optSpeed = " -ff -o -6 ",

-    optSize = " -ff -o -6 ",

-    comp = "dmc -c -Jm $options $include -o$objfile $file",

-    buildGui = " -L/exet:nt/su:windows",

-    buildDll = " -WD",

-    link = "dmc $options $buildgui $builddll -o$exefile $objfiles",

-    includeCmd = " -I",

-    debug = " -g ",

-    defineValue = " -D$name=$value",

-    define = " -D$name",

-    undef = " -U$name", # XXX: dmc does not have -U ?

-    pic = ""

-  ), dict(

-    name = "wcc",

-    objExt = "obj",

-    optSpeed = " -ox -on -6 -d0 -fp6 -zW ",

-    optSize = "",

-    comp = "wcl386 -c -6 -zw $options $include -fo=$objfile $file",

-    buildGui = " -bw",

-    buildDll = " -bd",

-    link = "wcl386 $options $buildgui $builddll -fe=$exefile $objfiles ",

-    includeCmd = " -i=",

-    debug = " -d2 ",

-    defineValue = " -d$name=$value",

-    define = " -d$name",

-    undef = " -u$name",

-    pic = ""

-  ), dict(

-    name = "vcc",

-    objExt = "obj",

-    optSpeed = " /Ogityb2 /G7 /arch:SSE2 ",

-    optSize = " /O1 /G7 ",

-    comp = "cl /c $options $include /Fo$objfile $file",

-    buildGui = " /link /SUBSYSTEM:WINDOWS ",

-    buildDll = " /LD",

-    link = "cl $options $builddll /Fe$exefile $objfiles $buildgui",

-    includeCmd = " /I",

-    debug = " /GZ /Zi ",

-    defineValue = " /D$name=$value",

-    define = " /D$name",

-    undef = " /U$name",

-    pic = ""

-  ), dict(

-    name = "tcc",

-    objExt = "o",

-    optSpeed = "", # Tiny C has no optimizer

-    optSize = "",

-    comp = "tcc -c $options $include -o $objfile $file",

-    buildGui = "UNAVAILABLE!",

-    buildDll = " -shared",

-    link = "tcc -o $exefile $options $buildgui $builddll $objfiles",

-    includeCmd = " -I",

-    debug = " -b ",

-    defineValue = " -D$name=$value",

-    define = " -D$name",

-    undef = " -U$name",

-    pic = ""

-  ), dict(

-    name = "pcc", # Pelles C

-    objExt = "obj",

-    optSpeed = " -Ox ",

-    optSize = " -Os ",

-    comp = "cc -c $options $include -Fo$objfile $file",

-    buildGui = " -SUBSYSTEM:WINDOWS",

-    buildDll = " -DLL",

-    link = "cc $options $buildgui $builddll -OUT:$exefile $objfiles",

-    includeCmd = " -I",

-    debug = " -Zi ",

-    defineValue = " -D$name=$value",

-    define = " -D$name",

-    undef = " -U$name",

-    pic = ""

-  ), dict(

-    name = "ucc",

-    objExt = "o",

-    optSpeed = " -O3 ",

-    optSize = " -O1 ",

-    comp = "cc -c $options $include -o $objfile $file",

-    buildGui = "",

-    buildDll = " -shared ",

-    link = "cc -o $exefile $options $buildgui $builddll $objfiles",

-    includeCmd = " -I",

-    debug = "",

-    defineValue = " -D$name=$value",

-    define = " -D$name",

-    undef = " -U$name",

-    pic = ""

-  ), dict(

-    name = "llvm_gcc", # its options are the same as GCC's

-    objExt = "o",

-    optSpeed = " -O3 -ffast-math ",

-    optSize = " -Os -ffast-math ",

-    comp = "llvm-gcc -c $options $include -o $objfile $file",

-    buildGui = " -mwindows",

-    buildDll = " -mdll",

-    link = "llvm-gcc $options $buildgui $builddll -o $exefile $objfiles",

-    includeCmd = " -I",

-    debug = "",

-    defineValue = " -D$name=$value",

-    define = " -D$name",

-    undef = " -U$name",

-    pic = "-fPIC"

-  )

-]

-

-#  --------------- little helpers ---------------------------------------------

-

-def Subs(frmt, **substitution):

-  if isinstance(frmt, basestring):

-    return string.Template(frmt).substitute(substitution)

-  else:

-    return tuple([string.Template(x).substitute(substitution) for x in frmt])

-

-_baseDir = os.getcwd()

-BaseDir = _baseDir

-

-def Path(a):

-  # Gets a UNIX like path and converts it to a path on this platform.

-  # With UNIX like, I mean: slashes, not backslashes, only relative

-  # paths ('../etc' can be used)

-  result = a

-  if os.sep != "/": result = result.replace("/", os.sep)

-  if os.pardir != "..": result = result.replace("..", os.pardir)

-  return result

-

-def Join(*args):

-  result = ""

-  for a in args[:-1]:

-    result += a

-    if result[-1] != "/":

-      result += "/"

-  result += args[-1]

-  return result.replace("//", "/")

-

-def Exec(command):

-  c = Path(command)

-  Echo(c)

-  result = os.system(c)

-  if result != 0: Error("execution of an external program failed")

-  return result

-

-def TryExec(command):

-  c = Path(command)

-  Echo(c)

-  result = os.system(c)

-  return result

-

-def RawExec(command):

-  Echo(command)

-  result = os.system(command)

-  if result != 0: Error("execution of an external program failed")

-  return result

-

-def Move(src, dest):

-  s = Path(src)

-  d = Path(dest)

-  try:

-    shutil.move(s, d)

-  except IOError, OSError:

-    Warn("could not move %s to %s" % (s, d))

-

-def Copy(src, dest):

-  s = Path(src)

-  d = Path(dest)

-  try:

-    shutil.copyfile(s, d)

-  except IOError, OSError:

-    Warn("could not copy %s to %s" % (s, d))

-

-def Remove(f):

-  try:

-    os.remove(Path(f))

-  except OSError:

-    Warn("could not remove: %s" % f)

-

-def RemoveDir(f):

-  try:

-    shutil.rmtree(Path(f))

-  except OSError:

-    Warn("could not remove: %s" % f)

-

-def Exists(f): return os.path.exists(Path(f))

-

-def Chdir(dest):

-  d = Path(dest)

-  try:

-    os.chdir(d)

-  except OSError:

-    Warn("could not switch to directory: " + d)

-

-def Mkdir(dest):

-  d = Path(dest)

-  try:

-    os.mkdir(d)

-  except OSError:

-    Warn("could not create directory: " + d)

-

-def Glob(pattern): # needed because glob.glob() is buggy on Windows 95:

-  # things like tests/t*.mor won't work

-  global _baseDir

-  (head, tail) = os.path.split(Path(pattern))

-  try:

-    os.chdir(os.path.join(_baseDir, head))

-    result = []

-    for f in glob.glob(tail):

-      result.append(os.path.join(head, f))

-  except OSError:

-    result = []

-  finally:

-    os.chdir(_baseDir)

-  return result

-

-def FilenameNoExt(f): 

-  return os.path.splitext(os.path.basename(f))[0]

-

-def _Ext(trunc, posixFormat, winFormat):

-  (head, tail) = os.path.split(Path(trunc))

-  if os.name == "posix": frmt = posixFormat

-  else:                  frmt = winFormat

-  return os.path.join(head, Subs(frmt, trunc=tail))

-

-def DynExt(trunc):

-  """Makes a dynamic library out of a trunc. This means it either

-     does '${trunc}.dll' or 'lib${trunc}.so'.

-  """

-  return _Ext(trunc, 'lib${trunc}.so', '${trunc}.dll')

-

-def LibExt(trunc):

-  """Makes a static library out of a trunc. This means it either

-     does '${trunc}.lib' or '${trunc}.a'.

-  """

-  return _Ext(trunc, '${trunc}.a', '${trunc}.lib')

-

-def ScriptExt(trunc):

-  """Makes a script out of a trunc. This means it either

-     does '${trunc}.bat' or '${trunc}.sh'.

-  """

-  return _Ext(trunc, '${trunc}.sh', '${trunc}.bat')

-

-def ExeExt(trunc):

-  """Makes an executable out of a trunc. This means it either

-     does '${trunc}.exe' or '${trunc}'.

-  """

-  return _Ext(trunc, '${trunc}', '${trunc}.exe')

-

-def MakeExecutable(file):

-  os.chmod(file, 493)

-

-# ----------------- Dependency Analyser Core ---------------------------------

-# We simply store the rules in a list until building the things. Checking is

-# also delayed.

-_rules = {}

-_importantTargets = [] # used for command line switches

-_commands = {} # other commands

-# a command is a tuple: (name, description, function, number of arguments)

-

-def Command(name, desc, func, args=0):

-  """if args == -1, a variable number of arguments is given to the ``func``

-     as a list"""

-  _commands[name] = (desc, func, args)

-

-def _applyPath(x):

-  if type(x) == ListType:

-    return map(Path, x)

-  else:

-    return Path(x)

-

-def Rule(name = None, desc = "", prereqs = [], cmds = None, outputfile = None,

-         modifies = []):

-  """Defines a rule. Name must be a single word, not a file!"""

-  if not name:

-    t = "#" + str(len(_rules.keys()))

-  else:

-    t = name

-  if t in _rules: Error("target '%s' already exists!" % t)

-  _rules[t] = (_applyPath(prereqs), cmds, outputfile, _applyPath(modifies))

-  if desc:

-    _importantTargets.append((t, desc))

-

-

-class Changed(object):

-  """ Returns a Changed object. This object evals to true if one of the

-      given files has changed, false otherwise in a boolean context. You have

-      to call the object's success() method if the building has been a success.

-

-      Example:

-

-      c = Changed("unique_name", "file1.pas file2.pas file3.pas")

-      if c:

-        Exec("fpc file1.pas")

-        # Exec raises an exception if it fails, thus if we get to here, it was

-        # a success:

-        c.success()

-  """

-  def __init__(self, id, files, explain=False,

-              fingerprintsfile=_FINGERPRINTS_FILE):

-    # load the fingerprints file:

-    # fingerprints is a dict[target, files] where files is a dict[filename, hash]

-    self.fingers = {} # default value

-    if Exists(fingerprintsfile):

-      try:

-        self.fingers = cPickle.load(file(fingerprintsfile))

-      except OSError:

-        Error("Cannot read from " + fingerprintsfile)

-    self.filename = fingerprintsfile

-    self.id = id

-    self.files = files

-    self._hashStr = zlib.adler32 # our hash function

-    self.explain = explain

-

-  def _hashFile(self, f):

-    x = file(f)

-    result = self._hashStr(x.read())

-    x.close() # for other Python implementations

-    return result

-

-  def __nonzero__(self):

-    if type(self.files) == type(""):

-      self.files = self.files.split()

-    result = False

-    target = self.id

-    if not (target in self.fingers):

-      self.fingers[target] = {}

-      if self.explain: _Info("no entries for target '%s'" % target)

-      result = True

-    for d in self.files:

-      if Exists(d):

-        n = self._hashFile(d)

-        if d not in self.fingers[target] or n != self.fingers[target][d]:

-          result = True

-          if self.explain: _Info("'%s' modified since last build" % d)

-          self.fingers[target][d] = n

-      else:

-        Warn("'%s' does not exist!" % d)

-        result = True

-    return result

-

-  def update(self, filename):

-    self.fingers[self.id][filename] = self._hashFile(filename)

-

-  def success(self):

-    cPickle.dump(self.fingers, file(self.filename, "w+"))

-

-

-class _Koch(object):

-  def _loadFingerprints(self, filename):

-  # fingerprints is a dict[target, files] where files is a dict[filename, hash]

-    if Exists(filename):

-      try:

-        self.fingers = cPickle.load(file(filename))

-      except OSError:

-        Error("Cannot read from " + filename)

-    else:

-      self.fingers = {} # we have no fingerprints :-(

-

-  def _saveFingerprints(self, filename):

-    cPickle.dump(self.fingers, file(filename, "w+"))

-

-  def __init__(self, options):

-    self._loadFingerprints(_FINGERPRINTS_FILE)

-    self.newfingers = {}

-    self.rules = _rules

-    self._hashStr = zlib.adler32 # our hash function

-    self.options = options

-

-  def _doRebuild(self, cmd):

-    if cmd is None: return 0

-    if type(cmd) is StringType:

-      if cmd:

-        c = Path(cmd)

-        _Info(c)

-        return os.system(c)

-      else:

-        return 0

-    elif type(cmd) is FunctionType:

-      return cmd()

-    elif type(cmd) is ListType:

-      for c in cmd:

-        res = self._doRebuild(c)

-        if res != 0: break

-      return res

-    else:

-      Error("invalid rule: command must be a string or a function")

-

-  def _hashFile(self, f):

-    x = file(f)

-    result = self._hashStr(x.read())

-    x.close() # for other Python implementations

-    return result

-

-  def _getDeps(self, target):

-    depslist = self.rules[target][0]

-    if type(depslist) is StringType:

-      result = depslist.split()

-    elif type(depslist) is FunctionType:

-      result = depslist()

-    elif type(depslist) is ListType:

-      result = []

-      for d in depslist:

-        if type(d) is StringType:

-          result.append(d)

-        elif type(d) is FunctionType:

-          result.append(d())

-        else:

-          Error("invalid rule: prereqs must be a string, list, or a function")

-    for i in range(0, len(result)):

-      result[i] = Path(result[i])

-    return result

-

-  def _hasChanged(self, target, d):

-    if not (target in self.newfingers):

-      self.newfingers[target] = {}

-    if Exists(d):

-      n = self._hashFile(d)

-      self.newfingers[target][d] = n

-      if not (target in self.fingers): return True

-      if not (d in self.fingers[target]): return True

-      return n != self.fingers[target][d]

-    else:

-      Warn("'%s' does not exist!" % d)

-      return True

-

-  def _makeAux(self, target, callstack={}):

-    # returns "uptodate", "updated", "failed"

-    UPTODATE = 1

-    UPDATED = 2

-    FAILED = 3

-

-    if target in callstack: return callstack[target]

-

-    def explain(msg):

-      if 'explain' in self.options: _Info(msg)

-

-    if not (target in self.rules): return UPTODATE # target is up to date

-    callstack[target] = UPTODATE # assume uptodate until proven otherwise

-    result = UPTODATE

-

-    # retrieve the dependencies:

-    deps = self._getDeps(target)

-    for d in deps:

-      if d[0] == '#':

-        t = d[1:]

-        if not (t in self.rules):

-          Error("reference to unknown target '%s'" % t)

-        # it is a target!

-        #callstack[t] = # XXX: prevend endless recursion!

-        res = self._makeAux(t, callstack)

-        result = max(result, res)

-        if res == UPDATED:

-          explain("will build '%s' because '%s' modified since last build" %

-                  (target, d))

-        elif res == FAILED:

-          explain("cannot build '%s' because '%s' failed" %

-                  (target, d))

-      elif self._hasChanged(target, d):

-        explain("will build '%s' because '%s' modified since last build" %

-                (target, d))

-        result = max(result, UPDATED)

-    if self.rules[target][2]: # check if output file exists:

-      if not Exists(self.rules[target][2]):

-        explain("will build '%s' because output file '%s' does not exist" %

-               (target, self.rules[target][2]))

-        result = max(result, UPDATED)

-

-    if result == UPTODATE and 'force' in self.options:

-      explain("will build '%s' because forced" % target)

-      result = max(result, UPDATED)

-

-    if result == UPDATED:

-      _Info("building target '%s'" % target)

-      buildRes = self._doRebuild(self.rules[target][1])

-      if buildRes is None:

-        Error("builder for target '%s' did not return an int" % target)

-        result = FAILED

-      elif buildRes != 0:

-        result = FAILED

-    elif result == UPTODATE:

-      _Info("'%s' is up to date" % target)

-    callstack[target] = result

-    if result == UPDATED: # building was successful, so update fingerprints:

-      if not (target in self.newfingers):

-      # for phony targets this check is needed

-        self.newfingers[target] = {}

-      for m in self.rules[target][3]: # look for changed files

-        self._hasChanged(target, m) # call for its side-effects

-      self.fingers[target] = self.newfingers[target]

-    return result

-

-  def make(self, target):

-    self._makeAux(target)

-    self._saveFingerprints(_FINGERPRINTS_FILE)

-

-# -----------------------------------------------------------------------------

-

-def SplitArg(s):

-  if ':' in s: c = ':'

-  elif '=' in s: c = '='

-  else: return (s, '')

-  i = s.find(c)

-  return (s[:i], s[i+1:])

-

-# -----------------------------------------------------------------------------

-

-def _writeUsage():

-  print("Usage: koch.py [options] command/target [command/target...]\n"

-        "Options:\n"

-        "  --force, -b, -f        forces rebuilding\n"

-        "  --help, -h             shows this help\n"

-        "  --explain, -e          explain why a target is built\n"

-        "Available targets:")

-  for t in _importantTargets:

-    print("  " + t[0] + " " * (23-len(t[0])) + t[1])

-  if len(_commands) > 0:

-    print("Available commands:")

-    for k, v in _commands.iteritems():

-      print("  " + k + " " * (23-len(k)) + v[0])

-  sys.exit(2)

-

-def Koch(defaultTarget):

-  argv = sys.argv[1:]

-

-  options = {}

-  i = 0

-  # process general options:

-  while i < len(argv):

-    if argv[i][0] == '-':

-      if argv[i] in ("-h", "--help"): _writeUsage()

-      elif argv[i] in ("-b", "-B", "--force", "-f"): options['force'] = True

-      elif argv[i] in ("--explain", "-e"): options['explain'] = True

-      else: Error("invalid option: '%s'" % argv[i])

-    else: break # BUGFIX

-    i += 1

-

-  k = _Koch(options)

-

-  # process commands:

-  i = 0

-  while i < len(argv):

-    if argv[i][0] != '-': # process target/command

-      if argv[i] in _rules:

-        k.make(argv[i])

-      elif argv[i] in _commands:

-        cmd = argv[i]

-        n = _commands[cmd][2]

-        args = []

-        if n < 0: upperBound = len(argv)-1

-        else: upperBound = i+n

-        while i+1 <= upperBound:

-          if i+1 >= len(argv):

-            Error("command '%s' expects %d arguments" % (cmd, n))

-          args.append(argv[i+1])

-          i += 1

-        if n < 0: _commands[cmd][1](args)

-        else: _commands[cmd][1](*args)

-      else:

-        Error("Invalid target/command: " + argv[i])

-

-    i += 1

-  if len(argv) == 0:

-    k.make(defaultTarget)

-

-if __name__ == "__main__":

-  Error("You should execute the file 'koch.py' or consult\n"

-        "the documentation to see how to build this software.")

-

-

+# This is kochmod, a simple module for make-like functionality.
+# For further documentation see koch.txt or koch.html.
+# (c) 2007 Andreas Rumpf
+
+VERSION = "1.0.4"
+
+import os, os.path, inspect, re, shutil, glob, cPickle, zlib, string, \
+  getopt, sys
+from types import *
+
+def Error(msg): sys.exit("[Koch] *** ERROR: " + msg)
+def Warn(msg): print "[Koch] *** WARNING: " + msg
+def Echo(msg): print "[Koch] " + msg
+def _Info(msg): print "[Koch] " + msg
+
+_FINGERPRINTS_FILE = "koch.dat"
+  # in this file all the fingerprints are kept to allow recognizing when a file
+  # has changed. This works reliably, which cannot be said from just taking
+  # filetime-stamps.
+
+# -----------------------------------------------------------------------------
+
+def FileCmp(filenameA, filenameB):
+  SIZE = 4096*2
+  result = True
+  a = file(filenameA, "rb")
+  b = file(filenameB, "rb")
+  while True:
+    x = a.read(SIZE)
+    y = b.read(SIZE)
+    if x != y:
+      result = False
+      break
+    elif len(x) < SIZE: # EOF?
+      break
+  a.close()
+  b.close()
+  return result
+
+# ---------------- C Compilers ------------------------------------------------
+
+# We support the following C compilers:
+C_Compilers = ["gcc", "lcc", "bcc", "dmc", "wcc", "tcc", "pcc", "ucc", "llvm"]
+
+_CC_Info = [
+  dict(
+    name = "gcc",
+    objExt = "o",
+    optSpeed = " -O3 -ffast-math ",
+    optSize = " -Os -ffast-math ",
+    comp = "gcc -c $options $include -o $objfile $file",
+    buildGui = " -mwindows",
+    buildDll = " -mdll",
+    link = "gcc $options $buildgui $builddll -o $exefile $objfiles",
+    includeCmd = " -I",
+    debug = "",
+    defineValue = " -D$name=$value",
+    define = " -D$name",
+    undef = " -U$name",
+    pic = "-fPIC"
+  ), dict(
+    name = "lcc",
+    objExt = "obj",
+    optSpeed = " -O -p6 ",
+    optSize = " -O -p6 ",
+    comp = "lcc -e1 $options $include -Fo$objfile $file",
+    buildGui = " -subsystem windows",
+    buildDll = " -dll",
+    link = "lcclnk $options $buildgui $builddll -O $exefile $objfiles",
+    includeCmd = " -I",
+    debug = " -g5 ",
+    defineValue = " -D$name=$value",
+    define = " -D$name",
+    undef = " -U$name",
+    pic = ""
+  ), dict(
+    name = "bcc",
+    objExt = "obj",
+    optSpeed = " -O2 -6 ",
+    optSize = " -O1 -6 ",
+    comp = "bcc32 -c -H- -q -RT- -a8 $options $include -o$objfile $file",
+    buildGui = " -tW",
+    buildDll = " -tWD",
+    link = "bcc32 $options $buildgui $builddll -e$exefile $objfiles",
+    includeCmd = " -I",
+    debug = "",
+    defineValue = " -D$name=$value",
+    define = " -D$name",
+    undef = " -U$name",
+    pic = ""
+  ), dict(
+    name = "dmc",
+    objExt = "obj",
+    optSpeed = " -ff -o -6 ",
+    optSize = " -ff -o -6 ",
+    comp = "dmc -c -Jm $options $include -o$objfile $file",
+    buildGui = " -L/exet:nt/su:windows",
+    buildDll = " -WD",
+    link = "dmc $options $buildgui $builddll -o$exefile $objfiles",
+    includeCmd = " -I",
+    debug = " -g ",
+    defineValue = " -D$name=$value",
+    define = " -D$name",
+    undef = " -U$name", # XXX: dmc does not have -U ?
+    pic = ""
+  ), dict(
+    name = "wcc",
+    objExt = "obj",
+    optSpeed = " -ox -on -6 -d0 -fp6 -zW ",
+    optSize = "",
+    comp = "wcl386 -c -6 -zw $options $include -fo=$objfile $file",
+    buildGui = " -bw",
+    buildDll = " -bd",
+    link = "wcl386 $options $buildgui $builddll -fe=$exefile $objfiles ",
+    includeCmd = " -i=",
+    debug = " -d2 ",
+    defineValue = " -d$name=$value",
+    define = " -d$name",
+    undef = " -u$name",
+    pic = ""
+  ), dict(
+    name = "vcc",
+    objExt = "obj",
+    optSpeed = " /Ogityb2 /G7 /arch:SSE2 ",
+    optSize = " /O1 /G7 ",
+    comp = "cl /c $options $include /Fo$objfile $file",
+    buildGui = " /link /SUBSYSTEM:WINDOWS ",
+    buildDll = " /LD",
+    link = "cl $options $builddll /Fe$exefile $objfiles $buildgui",
+    includeCmd = " /I",
+    debug = " /GZ /Zi ",
+    defineValue = " /D$name=$value",
+    define = " /D$name",
+    undef = " /U$name",
+    pic = ""
+  ), dict(
+    name = "tcc",
+    objExt = "o",
+    optSpeed = "", # Tiny C has no optimizer
+    optSize = "",
+    comp = "tcc -c $options $include -o $objfile $file",
+    buildGui = "UNAVAILABLE!",
+    buildDll = " -shared",
+    link = "tcc -o $exefile $options $buildgui $builddll $objfiles",
+    includeCmd = " -I",
+    debug = " -b ",
+    defineValue = " -D$name=$value",
+    define = " -D$name",
+    undef = " -U$name",
+    pic = ""
+  ), dict(
+    name = "pcc", # Pelles C
+    objExt = "obj",
+    optSpeed = " -Ox ",
+    optSize = " -Os ",
+    comp = "cc -c $options $include -Fo$objfile $file",
+    buildGui = " -SUBSYSTEM:WINDOWS",
+    buildDll = " -DLL",
+    link = "cc $options $buildgui $builddll -OUT:$exefile $objfiles",
+    includeCmd = " -I",
+    debug = " -Zi ",
+    defineValue = " -D$name=$value",
+    define = " -D$name",
+    undef = " -U$name",
+    pic = ""
+  ), dict(
+    name = "ucc",
+    objExt = "o",
+    optSpeed = " -O3 ",
+    optSize = " -O1 ",
+    comp = "cc -c $options $include -o $objfile $file",
+    buildGui = "",
+    buildDll = " -shared ",
+    link = "cc -o $exefile $options $buildgui $builddll $objfiles",
+    includeCmd = " -I",
+    debug = "",
+    defineValue = " -D$name=$value",
+    define = " -D$name",
+    undef = " -U$name",
+    pic = ""
+  ), dict(
+    name = "llvm_gcc", # its options are the same as GCC's
+    objExt = "o",
+    optSpeed = " -O3 -ffast-math ",
+    optSize = " -Os -ffast-math ",
+    comp = "llvm-gcc -c $options $include -o $objfile $file",
+    buildGui = " -mwindows",
+    buildDll = " -mdll",
+    link = "llvm-gcc $options $buildgui $builddll -o $exefile $objfiles",
+    includeCmd = " -I",
+    debug = "",
+    defineValue = " -D$name=$value",
+    define = " -D$name",
+    undef = " -U$name",
+    pic = "-fPIC"
+  )
+]
+
+#  --------------- little helpers ---------------------------------------------
+
+def Subs(frmt, **substitution):
+  if isinstance(frmt, basestring):
+    return string.Template(frmt).substitute(substitution)
+  else:
+    return tuple([string.Template(x).substitute(substitution) for x in frmt])
+
+def SafeSubs(frmt, **substitution):
+  return string.Template(frmt).safe_substitute(substitution)
+
+_baseDir = os.getcwd()
+BaseDir = _baseDir
+
+def Path(a):
+  # Gets a UNIX like path and converts it to a path on this platform.
+  # With UNIX like, I mean: slashes, not backslashes, only relative
+  # paths ('../etc' can be used)
+  result = a
+  if os.sep != "/": result = result.replace("/", os.sep)
+  if os.pardir != "..": result = result.replace("..", os.pardir)
+  return result
+
+def Join(*args):
+  result = ""
+  for a in args[:-1]:
+    result += a
+    if result[-1] != "/":
+      result += "/"
+  result += args[-1]
+  return result.replace("//", "/")
+
+def Exec(command):
+  c = Path(command)
+  Echo(c)
+  result = os.system(c)
+  if result != 0: Error("execution of an external program failed")
+  return result
+
+def TryExec(command):
+  c = Path(command)
+  Echo(c)
+  result = os.system(c)
+  return result
+
+def RawExec(command):
+  Echo(command)
+  result = os.system(command)
+  if result != 0: Error("execution of an external program failed")
+  return result
+
+def Move(src, dest):
+  s = Path(src)
+  d = Path(dest)
+  try:
+    shutil.move(s, d)
+  except IOError, OSError:
+    Warn("could not move %s to %s" % (s, d))
+
+def Copy(src, dest):
+  s = Path(src)
+  d = Path(dest)
+  try:
+    shutil.copyfile(s, d)
+  except IOError, OSError:
+    Warn("could not copy %s to %s" % (s, d))
+
+def Remove(f):
+  try:
+    os.remove(Path(f))
+  except OSError:
+    Warn("could not remove: %s" % f)
+
+def RemoveDir(f):
+  try:
+    shutil.rmtree(Path(f))
+  except OSError:
+    Warn("could not remove: %s" % f)
+
+def Exists(f): return os.path.exists(Path(f))
+
+def Chdir(dest):
+  d = Path(dest)
+  try:
+    os.chdir(d)
+  except OSError:
+    Warn("could not switch to directory: " + d)
+
+def Mkdir(dest):
+  d = Path(dest)
+  try:
+    os.mkdir(d)
+  except OSError:
+    Warn("could not create directory: " + d)
+
+def Glob(pattern): # needed because glob.glob() is buggy on Windows 95:
+  # things like tests/t*.mor won't work
+  global _baseDir
+  (head, tail) = os.path.split(Path(pattern))
+  try:
+    os.chdir(os.path.join(_baseDir, head))
+    result = []
+    for f in glob.glob(tail):
+      result.append(os.path.join(head, f))
+  except OSError:
+    result = []
+  finally:
+    os.chdir(_baseDir)
+  return result
+
+def FilenameNoExt(f):
+  return os.path.splitext(os.path.basename(f))[0]
+
+def _Ext(trunc, posixFormat, winFormat):
+  (head, tail) = os.path.split(Path(trunc))
+  if os.name == "posix": frmt = posixFormat
+  else:                  frmt = winFormat
+  return os.path.join(head, Subs(frmt, trunc=tail))
+
+def DynExt(trunc):
+  """Makes a dynamic library out of a trunc. This means it either
+     does '${trunc}.dll' or 'lib${trunc}.so'.
+  """
+  return _Ext(trunc, 'lib${trunc}.so', '${trunc}.dll')
+
+def LibExt(trunc):
+  """Makes a static library out of a trunc. This means it either
+     does '${trunc}.lib' or '${trunc}.a'.
+  """
+  return _Ext(trunc, '${trunc}.a', '${trunc}.lib')
+
+def ScriptExt(trunc):
+  """Makes a script out of a trunc. This means it either
+     does '${trunc}.bat' or '${trunc}.sh'.
+  """
+  return _Ext(trunc, '${trunc}.sh', '${trunc}.bat')
+
+def ExeExt(trunc):
+  """Makes an executable out of a trunc. This means it either
+     does '${trunc}.exe' or '${trunc}'.
+  """
+  return _Ext(trunc, '${trunc}', '${trunc}.exe')
+
+def MakeExecutable(file):
+  os.chmod(file, 493)
+
+# ----------------- Dependency Analyser Core ---------------------------------
+# We simply store the rules in a list until building the things. Checking is
+# also delayed.
+_rules = {}
+_importantTargets = [] # used for command line switches
+_commands = {} # other commands
+# a command is a tuple: (name, description, function, number of arguments)
+
+def Command(name, desc, func, args=0):
+  """if args == -1, a variable number of arguments is given to the ``func``
+     as a list"""
+  _commands[name] = (desc, func, args)
+
+def _applyPath(x):
+  if type(x) == ListType:
+    return map(Path, x)
+  else:
+    return Path(x)
+
+def Rule(name = None, desc = "", prereqs = [], cmds = None, outputfile = None,
+         modifies = []):
+  """Defines a rule. Name must be a single word, not a file!"""
+  if not name:
+    t = "#" + str(len(_rules.keys()))
+  else:
+    t = name
+  if t in _rules: Error("target '%s' already exists!" % t)
+  _rules[t] = (_applyPath(prereqs), cmds, outputfile, _applyPath(modifies))
+  if desc:
+    _importantTargets.append((t, desc))
+
+
+class Changed(object):
+  """ Returns a Changed object. This object evals to true if one of the
+      given files has changed, false otherwise in a boolean context. You have
+      to call the object's success() method if the building has been a success.
+
+      Example:
+
+      c = Changed("unique_name", "file1.pas file2.pas file3.pas")
+      if c:
+        Exec("fpc file1.pas")
+        # Exec raises an exception if it fails, thus if we get to here, it was
+        # a success:
+        c.success()
+  """
+  def __init__(self, id, files, explain=False,
+              fingerprintsfile=_FINGERPRINTS_FILE):
+    # load the fingerprints file:
+    # fingerprints is a dict[target, files] where files is a dict[filename, hash]
+    self.fingers = {} # default value
+    if Exists(fingerprintsfile):
+      try:
+        self.fingers = cPickle.load(file(fingerprintsfile))
+      except OSError:
+        Error("Cannot read from " + fingerprintsfile)
+    self.filename = fingerprintsfile
+    self.id = id
+    self.files = files
+    self._hashStr = zlib.adler32 # our hash function
+    self.explain = explain
+
+  def _hashFile(self, f):
+    x = file(f)
+    result = self._hashStr(x.read())
+    x.close() # for other Python implementations
+    return result
+
+  def __nonzero__(self):
+    if type(self.files) == type(""):
+      self.files = self.files.split()
+    result = False
+    target = self.id
+    if not (target in self.fingers):
+      self.fingers[target] = {}
+      if self.explain: _Info("no entries for target '%s'" % target)
+      result = True
+    for d in self.files:
+      if Exists(d):
+        n = self._hashFile(d)
+        if d not in self.fingers[target] or n != self.fingers[target][d]:
+          result = True
+          if self.explain: _Info("'%s' modified since last build" % d)
+          self.fingers[target][d] = n
+      else:
+        Warn("'%s' does not exist!" % d)
+        result = True
+    return result
+
+  def update(self, filename):
+    self.fingers[self.id][filename] = self._hashFile(filename)
+
+  def success(self):
+    cPickle.dump(self.fingers, file(self.filename, "w+"))
+
+
+class _Koch(object):
+  def _loadFingerprints(self, filename):
+  # fingerprints is a dict[target, files] where files is a dict[filename, hash]
+    if Exists(filename):
+      try:
+        self.fingers = cPickle.load(file(filename))
+      except OSError:
+        Error("Cannot read from " + filename)
+    else:
+      self.fingers = {} # we have no fingerprints :-(
+
+  def _saveFingerprints(self, filename):
+    cPickle.dump(self.fingers, file(filename, "w+"))
+
+  def __init__(self, options):
+    self._loadFingerprints(_FINGERPRINTS_FILE)
+    self.newfingers = {}
+    self.rules = _rules
+    self._hashStr = zlib.adler32 # our hash function
+    self.options = options
+
+  def _doRebuild(self, cmd):
+    if cmd is None: return 0
+    if type(cmd) is StringType:
+      if cmd:
+        c = Path(cmd)
+        _Info(c)
+        return os.system(c)
+      else:
+        return 0
+    elif type(cmd) is FunctionType:
+      return cmd()
+    elif type(cmd) is ListType:
+      for c in cmd:
+        res = self._doRebuild(c)
+        if res != 0: break
+      return res
+    else:
+      Error("invalid rule: command must be a string or a function")
+
+  def _hashFile(self, f):
+    x = file(f)
+    result = self._hashStr(x.read())
+    x.close() # for other Python implementations
+    return result
+
+  def _getDeps(self, target):
+    depslist = self.rules[target][0]
+    if type(depslist) is StringType:
+      result = depslist.split()
+    elif type(depslist) is FunctionType:
+      result = depslist()
+    elif type(depslist) is ListType:
+      result = []
+      for d in depslist:
+        if type(d) is StringType:
+          result.append(d)
+        elif type(d) is FunctionType:
+          result.append(d())
+        else:
+          Error("invalid rule: prereqs must be a string, list, or a function")
+    for i in range(0, len(result)):
+      result[i] = Path(result[i])
+    return result
+
+  def _hasChanged(self, target, d):
+    if not (target in self.newfingers):
+      self.newfingers[target] = {}
+    if Exists(d):
+      n = self._hashFile(d)
+      self.newfingers[target][d] = n
+      if not (target in self.fingers): return True
+      if not (d in self.fingers[target]): return True
+      return n != self.fingers[target][d]
+    else:
+      Warn("'%s' does not exist!" % d)
+      return True
+
+  def _makeAux(self, target, callstack={}):
+    # returns "uptodate", "updated", "failed"
+    UPTODATE = 1
+    UPDATED = 2
+    FAILED = 3
+
+    if target in callstack: return callstack[target]
+
+    def explain(msg):
+      if 'explain' in self.options: _Info(msg)
+
+    if not (target in self.rules): return UPTODATE # target is up to date
+    callstack[target] = UPTODATE # assume uptodate until proven otherwise
+    result = UPTODATE
+
+    # retrieve the dependencies:
+    deps = self._getDeps(target)
+    for d in deps:
+      if d[0] == '#':
+        t = d[1:]
+        if not (t in self.rules):
+          Error("reference to unknown target '%s'" % t)
+        # it is a target!
+        #callstack[t] = # XXX: prevend endless recursion!
+        res = self._makeAux(t, callstack)
+        result = max(result, res)
+        if res == UPDATED:
+          explain("will build '%s' because '%s' modified since last build" %
+                  (target, d))
+        elif res == FAILED:
+          explain("cannot build '%s' because '%s' failed" %
+                  (target, d))
+      elif self._hasChanged(target, d):
+        explain("will build '%s' because '%s' modified since last build" %
+                (target, d))
+        result = max(result, UPDATED)
+    if self.rules[target][2]: # check if output file exists:
+      if not Exists(self.rules[target][2]):
+        explain("will build '%s' because output file '%s' does not exist" %
+               (target, self.rules[target][2]))
+        result = max(result, UPDATED)
+
+    if result == UPTODATE and 'force' in self.options:
+      explain("will build '%s' because forced" % target)
+      result = max(result, UPDATED)
+
+    if result == UPDATED:
+      _Info("building target '%s'" % target)
+      buildRes = self._doRebuild(self.rules[target][1])
+      if buildRes is None:
+        Error("builder for target '%s' did not return an int" % target)
+        result = FAILED
+      elif buildRes != 0:
+        result = FAILED
+    elif result == UPTODATE:
+      _Info("'%s' is up to date" % target)
+    callstack[target] = result
+    if result == UPDATED: # building was successful, so update fingerprints:
+      if not (target in self.newfingers):
+      # for phony targets this check is needed
+        self.newfingers[target] = {}
+      for m in self.rules[target][3]: # look for changed files
+        self._hasChanged(target, m) # call for its side-effects
+      self.fingers[target] = self.newfingers[target]
+    return result
+
+  def make(self, target):
+    self._makeAux(target)
+    self._saveFingerprints(_FINGERPRINTS_FILE)
+
+# -----------------------------------------------------------------------------
+
+def SplitArg(s):
+  if ':' in s: c = ':'
+  elif '=' in s: c = '='
+  else: return (s, '')
+  i = s.find(c)
+  return (s[:i], s[i+1:])
+
+# -----------------------------------------------------------------------------
+
+def _writeUsage():
+  print("Usage: koch.py [options] command/target [command/target...]\n"
+        "Options:\n"
+        "  --force, -b, -f        forces rebuilding\n"
+        "  --help, -h             shows this help\n"
+        "  --explain, -e          explain why a target is built\n"
+        "Available targets:")
+  for t in _importantTargets:
+    print("  " + t[0] + " " * (23-len(t[0])) + t[1])
+  if len(_commands) > 0:
+    print("Available commands:")
+    for k, v in _commands.iteritems():
+      print("  " + k + " " * (23-len(k)) + v[0])
+  sys.exit(2)
+
+def Koch(defaultTarget):
+  argv = sys.argv[1:]
+
+  options = {}
+  i = 0
+  # process general options:
+  while i < len(argv):
+    if argv[i][0] == '-':
+      if argv[i] in ("-h", "--help"): _writeUsage()
+      elif argv[i] in ("-b", "-B", "--force", "-f"): options['force'] = True
+      elif argv[i] in ("--explain", "-e"): options['explain'] = True
+      else: Error("invalid option: '%s'" % argv[i])
+    else: break # BUGFIX
+    i += 1
+
+  k = _Koch(options)
+
+  # process commands:
+  i = 0
+  while i < len(argv):
+    if argv[i][0] != '-': # process target/command
+      if argv[i] in _rules:
+        k.make(argv[i])
+      elif argv[i] in _commands:
+        cmd = argv[i]
+        n = _commands[cmd][2]
+        args = []
+        if n < 0: upperBound = len(argv)-1
+        else: upperBound = i+n
+        while i+1 <= upperBound:
+          if i+1 >= len(argv):
+            Error("command '%s' expects %d arguments" % (cmd, n))
+          args.append(argv[i+1])
+          i += 1
+        if n < 0: _commands[cmd][1](args)
+        else: _commands[cmd][1](*args)
+      else:
+        Error("Invalid target/command: " + argv[i])
+
+    i += 1
+  if len(argv) == 0:
+    k.make(defaultTarget)
+
+if __name__ == "__main__":
+  Error("You should execute the file 'koch.py' or consult\n"
+        "the documentation to see how to build this software.")
+
+
diff --git a/lib/ansi_c.nim b/lib/ansi_c.nim
index e667822a9..6691ca4cc 100644
--- a/lib/ansi_c.nim
+++ b/lib/ansi_c.nim
@@ -17,9 +17,9 @@ proc c_memcpy(a, b: CString, size: cint) {.nodecl, importc: "memcpy".}
 proc c_strlen(a: CString): cint {.nodecl, importc: "strlen".}
 
 type
-  C_TextFile {.importc: "FILE", nodecl.} = record   # empty record for
-                                                   # data hiding
-  C_BinaryFile {.importc: "FILE", nodecl.} = record
+  C_TextFile {.importc: "FILE", nodecl, final.} = object   # empty record for
+                                                           # data hiding
+  C_BinaryFile {.importc: "FILE", nodecl, final.} = object
   C_TextFileStar = ptr CTextFile
   C_BinaryFileStar = ptr CBinaryFile
 
diff --git a/lib/arithm.nim b/lib/arithm.nim
index 5510d2f30..c8abded91 100644
--- a/lib/arithm.nim
+++ b/lib/arithm.nim
@@ -18,13 +18,13 @@ proc raiseDivByZero {.exportc: "raiseDivByZero".} =
   raise newException(EDivByZero, "divison by zero")
 
 proc addInt64(a, b: int64): int64 {.compilerProc, inline.} =
-  result = a + b
+  result = a +% b
   if (result xor a) >= int64(0) or (result xor b) >= int64(0):
     return result
   raiseOverflow()
 
 proc subInt64(a, b: int64): int64 {.compilerProc, inline.} =
-  result = a - b
+  result = a -% b
   if (result xor a) >= int64(0) or (result xor not b) >= int64(0):
     return result
   raiseOverflow()
@@ -74,7 +74,7 @@ proc modInt64(a, b: int64): int64 {.compilerProc, inline.} =
 proc mulInt64(a, b: int64): int64 {.compilerproc.} =
   var
     resAsFloat, floatProd: float64
-  result = a * b
+  result = a *% b
   floatProd = float64(a) # conversion
   floatProd = floatProd * float64(b)
   resAsFloat = float64(result)
@@ -211,7 +211,7 @@ when defined(asmVersion) and not defined(gcc):
     """
 
 elif defined(asmVersion) and defined(gcc):
-  proc addInt(a, b: int): int = 
+  proc addInt(a, b: int): int =
     asm """ "addl %1,%%eax\n"
              "jno 1\n"
              "call _raiseOverflow\n"
@@ -219,7 +219,7 @@ elif defined(asmVersion) and defined(gcc):
             :"=a"(`a`)
             :"a"(`a`), "r"(`b`)
     """
-    
+
   proc subInt(a, b: int): int =
     asm """ "subl %1,%%eax\n"
              "jno 1\n"
@@ -228,7 +228,7 @@ elif defined(asmVersion) and defined(gcc):
             :"=a"(`a`)
             :"a"(`a`), "r"(`b`)
     """
-    
+
   proc negInt(a: int): int =
     asm """  "negl %%eax\n"
              "jno 1\n"
@@ -237,7 +237,7 @@ elif defined(asmVersion) and defined(gcc):
             :"=a"(`a`)
             :"a"(`a`)
     """
-  
+
   proc divInt(a, b: int): int =
     asm """  "xorl %%edx, %%edx\n"
              "idivl %%ecx\n"
@@ -276,13 +276,13 @@ else:
   # Platform independant versions of the above (slower!)
 
   proc addInt(a, b: int): int =
-    result = a + b
+    result = a +% b
     if (result xor a) >= 0 or (result xor b) >= 0:
       return result
     raiseOverflow()
 
   proc subInt(a, b: int): int =
-    result = a - b
+    result = a -% b
     if (result xor a) >= 0 or (result xor not b) >= 0:
       return result
     raiseOverflow()
@@ -327,7 +327,7 @@ else:
     var
       resAsFloat, floatProd: float
 
-    result = a * b
+    result = a *% b
     floatProd = toFloat(a) * toFloat(b)
     resAsFloat = toFloat(result)
 
diff --git a/lib/assign.nim b/lib/assign.nim
index c8592b970..5ac475ef0 100644
--- a/lib/assign.nim
+++ b/lib/assign.nim
@@ -55,7 +55,8 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) =
     var dstseq = cast[PGenericSeq](dst)

     dstseq.len = seq.len

     dstseq.space = seq.len

-  of tyRecord, tyObject, tyTuple:

+  of tyObject, tyTuple, tyPureObject: 

+    # we don't need to copy m_type field for tyObject, as they are equal anyway

     genericAssignAux(dest, src, mt.node)

   of tyArray, tyArrayConstr:

     for i in 0..(mt.size div mt.base.size)-1:

@@ -75,6 +76,7 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) =
     copyMem(dest, src, mt.size) # copy raw bits

 

 proc genericSeqAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} =

+  var src = src # ugly, but I like to stress the parser sometimes :-)

   genericAssign(dest, addr(src), mt)

 

 proc genericAssignOpenArray(dest, src: pointer, len: int,

@@ -110,7 +112,7 @@ proc objectInit(dest: Pointer, typ: PNimType) =
     var pint = cast[ptr PNimType](dest)

     pint^ = typ

     objectInitAux(dest, typ.node)

-  of tyRecord:

+  of tyTuple, tyPureObject:

     objectInitAux(dest, typ.node)

   of tyArray, tyArrayConstr:

     for i in 0..(typ.size div typ.base.size)-1:

diff --git a/lib/base/cairo/cairo.nim b/lib/base/cairo/cairo.nim
index c999590a2..d2a99f355 100644
--- a/lib/base/cairo/cairo.nim
+++ b/lib/base/cairo/cairo.nim
@@ -149,13 +149,13 @@ type
       cdecl.}
   cairo_read_func_t* = proc (closure: Pointer, data: PByte, len: int32): cairo_status_t{.
       cdecl.}
-  cairo_t* = record           #OPAQUE
-  cairo_surface_t* = record   #OPAQUE
-  cairo_pattern_t* = record   #OPAQUE
-  cairo_scaled_font_t* = record #OPAQUE
-  cairo_font_face_t* = record #OPAQUE
-  cairo_font_options_t* = record #OPAQUE
-  cairo_matrix_t* = record
+  cairo_t* {.final.} = object           #OPAQUE
+  cairo_surface_t* {.final.} = object   #OPAQUE
+  cairo_pattern_t* {.final.} = object   #OPAQUE
+  cairo_scaled_font_t* {.final.} = object #OPAQUE
+  cairo_font_face_t* {.final.} = object #OPAQUE
+  cairo_font_options_t* {.final.} = object #OPAQUE
+  cairo_matrix_t* {.final.} = object
     xx: float64
     yx: float64
     xy: float64
@@ -163,15 +163,15 @@ type
     x0: float64
     y0: float64
 
-  cairo_user_data_key_t* = record
+  cairo_user_data_key_t* {.final.} = object
     unused: int32
 
-  cairo_glyph_t* = record
+  cairo_glyph_t* {.final.} = object
     index: int32
     x: float64
     y: float64
 
-  cairo_text_extents_t* = record
+  cairo_text_extents_t* {.final.} = object
     x_bearing: float64
     y_bearing: float64
     width: float64
@@ -179,28 +179,28 @@ type
     x_advance: float64
     y_advance: float64
 
-  cairo_font_extents_t* = record
+  cairo_font_extents_t* {.final.} = object
     ascent: float64
     descent: float64
     height: float64
     max_x_advance: float64
     max_y_advance: float64
 
-  cairo_path_data_t* = record #* _type : cairo_path_data_type_t;
-                              #       length : LongInt;
-                              #    end
+  cairo_path_data_t* {.final.} = object #* _type : cairo_path_data_type_t;
+                                        #       length : LongInt;
+                                        #    end
     x: float64
     y: float64
 
-  cairo_path_t* = record
+  cairo_path_t* {.final.} = object
     status: cairo_status_t
     data: Pcairo_path_data_t
     num_data: int32
 
-  cairo_rectangle_t* = record
+  cairo_rectangle_t* {.final.} = object
     x, y, width, height: float64
 
-  cairo_rectangle_list_t* = record
+  cairo_rectangle_list_t* {.final.} = object
     status: cairo_status_t
     rectangles: Pcairo_rectangle_t
     num_rectangles: int32
diff --git a/lib/base/gtk/atk.nim b/lib/base/gtk/atk.nim
index 69eb7c7cc..96fde8af6 100644
--- a/lib/base/gtk/atk.nim
+++ b/lib/base/gtk/atk.nim
@@ -56,7 +56,7 @@ type
     ATK_LAYER_INVALID, ATK_LAYER_BACKGROUND, ATK_LAYER_CANVAS, ATK_LAYER_WIDGET,
     ATK_LAYER_MDI, ATK_LAYER_POPUP, ATK_LAYER_OVERLAY
   PAtkPropertyValues* = ptr TAtkPropertyValues
-  TAtkPropertyValues* = record
+  TAtkPropertyValues* {.final.} = object
     property_name*: cstring
     old_value*: TGValue
     new_value*: TGValue
@@ -379,7 +379,7 @@ type
 
   TAtkAttributeSet* = TGSList
   PAtkAttribute* = ptr TAtkAttribute
-  TAtkAttribute* = record
+  TAtkAttribute* {.final.} = object
     name*: cstring
     value*: cstring
 
@@ -453,7 +453,7 @@ type
   TAtkEventListenerInitProc* = proc ()
   TAtkEventListenerInit* = proc (para1: TAtkEventListenerInitProc){.cdecl.}
   PAtkKeyEventStruct* = ptr TAtkKeyEventStruct
-  TAtkKeyEventStruct* = record
+  TAtkKeyEventStruct* {.final.} = object
     `type`*: gint
     state*: guint
     keyval*: guint
diff --git a/lib/base/gtk/gdk2.nim b/lib/base/gtk/gdk2.nim
index 11179525a..621a64bca 100644
--- a/lib/base/gtk/gdk2.nim
+++ b/lib/base/gtk/gdk2.nim
@@ -32,7 +32,7 @@ type
   TGdkVisualClass* = object of TGObjectClass
 
   PGdkColor* = ptr TGdkColor
-  TGdkColor* = record 
+  TGdkColor* {.final.} = object 
     pixel*: guint32
     red*: guint16
     green*: guint16
@@ -52,7 +52,7 @@ type
   TGdkFontType* = enum 
     GDK_FONT_FONT, GDK_FONT_FONTSET
   PGdkFont* = ptr TGdkFont
-  TGdkFont* = record 
+  TGdkFont* {.final.} = object 
     `type`*: TGdkFontType
     ascent*: gint
     descent*: gint
@@ -79,7 +79,7 @@ type
   PGdkGCValuesMask* = ptr TGdkGCValuesMask
   TGdkGCValuesMask* = int32
   PGdkGCValues* = ptr TGdkGCValues
-  TGdkGCValues* = record 
+  TGdkGCValues* {.final.} = object 
     foreground*: TGdkColor
     background*: TGdkColor
     font*: PGdkFont
@@ -125,7 +125,7 @@ type
   TGdkInputCondition* = int32
   PGdkStatus* = ptr TGdkStatus
   TGdkStatus* = int32
-  TGdkPoint* = record 
+  TGdkPoint* {.final.} = object 
     x*: gint
     y*: gint
 
@@ -135,14 +135,14 @@ type
   PGdkWChar* = ptr TGdkWChar
   TGdkWChar* = guint32
   PGdkSegment* = ptr TGdkSegment
-  TGdkSegment* = record 
+  TGdkSegment* {.final.} = object 
     x1*: gint
     y1*: gint
     x2*: gint
     y2*: gint
 
   PGdkRectangle* = ptr TGdkRectangle
-  TGdkRectangle* = record 
+  TGdkRectangle* {.final.} = object 
     x*: gint
     y*: gint
     width*: gint
@@ -190,7 +190,7 @@ type
   PGdkCursorType* = ptr TGdkCursorType
   TGdkCursorType* = gint
   PGdkCursor* = ptr TGdkCursor
-  TGdkCursor* = record 
+  TGdkCursor* {.final.} = object 
     `type`*: TGdkCursorType
     ref_count*: guint
 
@@ -220,14 +220,14 @@ type
   PGdkRegionBox* = ptr TGdkRegionBox
   TGdkRegionBox* = TGdkSegment
   PGdkRegion* = ptr TGdkRegion
-  TGdkRegion* = record 
+  TGdkRegion* {.final.} = object 
     size*: int32
     numRects*: int32
     rects*: PGdkRegionBox
     extents*: TGdkRegionBox
 
   PPOINTBLOCK* = ptr TPOINTBLOCK
-  TPOINTBLOCK* = record 
+  TPOINTBLOCK* {.final.} = object 
     pts*: array[0..(NUMPTSTOBUFFER) - 1, TGdkPoint]
     next*: PPOINTBLOCK
 
@@ -336,13 +336,13 @@ type
     GDK_SETTING_ACTION_NEW, GDK_SETTING_ACTION_CHANGED, 
     GDK_SETTING_ACTION_DELETED
   PGdkEventAny* = ptr TGdkEventAny
-  TGdkEventAny* = record 
+  TGdkEventAny* {.final.} = object 
     `type`*: TGdkEventType
     window*: PGdkWindow
     send_event*: gint8
 
   PGdkEventExpose* = ptr TGdkEventExpose
-  TGdkEventExpose* = record 
+  TGdkEventExpose* {.final.} = object 
     `type`*: TGdkEventType
     window*: PGdkWindow
     send_event*: gint8
@@ -351,20 +351,20 @@ type
     count*: gint
 
   PGdkEventNoExpose* = ptr TGdkEventNoExpose
-  TGdkEventNoExpose* = record 
+  TGdkEventNoExpose* {.final.} = object 
     `type`*: TGdkEventType
     window*: PGdkWindow
     send_event*: gint8
 
   PGdkEventVisibility* = ptr TGdkEventVisibility
-  TGdkEventVisibility* = record 
+  TGdkEventVisibility* {.final.} = object 
     `type`*: TGdkEventType
     window*: PGdkWindow
     send_event*: gint8
     state*: TGdkVisibilityState
 
   PGdkEventMotion* = ptr TGdkEventMotion
-  TGdkEventMotion* = record 
+  TGdkEventMotion* {.final.} = object 
     `type`*: TGdkEventType
     window*: PGdkWindow
     send_event*: gint8
@@ -379,7 +379,7 @@ type
     y_root*: gdouble
 
   PGdkEventButton* = ptr TGdkEventButton
-  TGdkEventButton* = record 
+  TGdkEventButton* {.final.} = object 
     `type`*: TGdkEventType
     window*: PGdkWindow
     send_event*: gint8
@@ -394,7 +394,7 @@ type
     y_root*: gdouble
 
   PGdkEventScroll* = ptr TGdkEventScroll
-  TGdkEventScroll* = record 
+  TGdkEventScroll* {.final.} = object 
     `type`*: TGdkEventType
     window*: PGdkWindow
     send_event*: gint8
@@ -408,7 +408,7 @@ type
     y_root*: gdouble
 
   PGdkEventKey* = ptr TGdkEventKey
-  TGdkEventKey* = record 
+  TGdkEventKey* {.final.} = object 
     `type`*: TGdkEventType
     window*: PGdkWindow
     send_event*: gint8
@@ -421,7 +421,7 @@ type
     group*: guint8
 
   PGdkEventCrossing* = ptr TGdkEventCrossing
-  TGdkEventCrossing* = record 
+  TGdkEventCrossing* {.final.} = object 
     `type`*: TGdkEventType
     window*: PGdkWindow
     send_event*: gint8
@@ -437,14 +437,14 @@ type
     state*: guint
 
   PGdkEventFocus* = ptr TGdkEventFocus
-  TGdkEventFocus* = record 
+  TGdkEventFocus* {.final.} = object 
     `type`*: TGdkEventType
     window*: PGdkWindow
     send_event*: gint8
     `in`*: gint16
 
   PGdkEventConfigure* = ptr TGdkEventConfigure
-  TGdkEventConfigure* = record 
+  TGdkEventConfigure* {.final.} = object 
     `type`*: TGdkEventType
     window*: PGdkWindow
     send_event*: gint8
@@ -454,7 +454,7 @@ type
     height*: gint
 
   PGdkEventProperty* = ptr TGdkEventProperty
-  TGdkEventProperty* = record 
+  TGdkEventProperty* {.final.} = object 
     `type`*: TGdkEventType
     window*: PGdkWindow
     send_event*: gint8
@@ -464,7 +464,7 @@ type
 
   TGdkNativeWindow* = pointer
   PGdkEventSelection* = ptr TGdkEventSelection
-  TGdkEventSelection* = record 
+  TGdkEventSelection* {.final.} = object 
     `type`*: TGdkEventType
     window*: PGdkWindow
     send_event*: gint8
@@ -475,7 +475,7 @@ type
     requestor*: TGdkNativeWindow
 
   PGdkEventProximity* = ptr TGdkEventProximity
-  TGdkEventProximity* = record 
+  TGdkEventProximity* {.final.} = object 
     `type`*: TGdkEventType
     window*: PGdkWindow
     send_event*: gint8
@@ -483,11 +483,11 @@ type
     device*: PGdkDevice
 
   PmatDUMMY* = ptr TmatDUMMY
-  TmatDUMMY* = record 
+  TmatDUMMY* {.final.} = object 
     b*: array[0..19, char]
 
   PGdkEventClient* = ptr TGdkEventClient
-  TGdkEventClient* = record 
+  TGdkEventClient* {.final.} = object 
     `type`*: TGdkEventType
     window*: PGdkWindow
     send_event*: gint8
@@ -496,7 +496,7 @@ type
     b*: array[0..19, char]
 
   PGdkEventSetting* = ptr TGdkEventSetting
-  TGdkEventSetting* = record 
+  TGdkEventSetting* {.final.} = object 
     `type`*: TGdkEventType
     window*: PGdkWindow
     send_event*: gint8
@@ -504,7 +504,7 @@ type
     name*: cstring
 
   PGdkEventWindowState* = ptr TGdkEventWindowState
-  TGdkEventWindowState* = record 
+  TGdkEventWindowState* {.final.} = object 
     `type`*: TGdkEventType
     window*: PGdkWindow
     send_event*: gint8
@@ -512,7 +512,7 @@ type
     new_window_state*: TGdkWindowState
 
   PGdkEventDND* = ptr TGdkEventDND
-  TGdkEventDND* = record 
+  TGdkEventDND* {.final.} = object 
     `type`*: TGdkEventType
     window*: PGdkWindow
     send_event*: gint8
@@ -521,7 +521,7 @@ type
     x_root*: gshort
     y_root*: gshort
 
-  TGdkEvent* = record 
+  TGdkEvent* {.final.} = object 
     data*: array[0..255, char] # union of
                                # `type`: TGdkEventType
                                #  any: TGdkEventAny
@@ -585,12 +585,12 @@ type
   PGdkAxisUse* = ptr TGdkAxisUse
   TGdkAxisUse* = int32
   PGdkDeviceKey* = ptr TGdkDeviceKey
-  TGdkDeviceKey* = record 
+  TGdkDeviceKey* {.final.} = object 
     keyval*: guint
     modifiers*: TGdkModifierType
 
   PGdkDeviceAxis* = ptr TGdkDeviceAxis
-  TGdkDeviceAxis* = record 
+  TGdkDeviceAxis* {.final.} = object 
     use*: TGdkAxisUse
     min*: gdouble
     max*: gdouble
@@ -605,12 +605,12 @@ type
     num_keys*: gint
     keys*: PGdkDeviceKey
 
-  TGdkTimeCoord* = record 
+  TGdkTimeCoord* {.final.} = object 
     time*: guint32
     axes*: array[0..(GDK_MAX_TIMECOORD_AXES) - 1, gdouble]
 
   PGdkKeymapKey* = ptr TGdkKeymapKey
-  TGdkKeymapKey* = record 
+  TGdkKeymapKey* {.final.} = object 
     keycode*: guint
     group*: gint
     level*: gint
@@ -624,12 +624,12 @@ type
     direction_changed*: proc (keymap: PGdkKeymap){.cdecl.}
 
   PGdkPangoAttrStipple* = ptr TGdkPangoAttrStipple
-  TGdkPangoAttrStipple* = record 
+  TGdkPangoAttrStipple* {.final.} = object 
     attr*: TPangoAttribute
     stipple*: PGdkBitmap
 
   PGdkPangoAttrEmbossed* = ptr TGdkPangoAttrEmbossed
-  TGdkPangoAttrEmbossed* = record 
+  TGdkPangoAttrEmbossed* {.final.} = object 
     attr*: TPangoAttribute
     embossed*: gboolean
 
@@ -653,7 +653,7 @@ type
     GDK_OVERLAP_RECTANGLE_PART
   TGdkSpanFunc* = proc (span: PGdkSpan, data: gpointer){.cdecl.}
   PGdkRgbCmap* = ptr TGdkRgbCmap
-  TGdkRgbCmap* = record 
+  TGdkRgbCmap* {.final.} = object 
     colors*: array[0..255, guint32]
     n_colors*: gint
     info_list*: PGSList
@@ -698,7 +698,7 @@ type
   TGdkInputFunction* = proc (data: gpointer, source: gint, 
                              condition: TGdkInputCondition){.cdecl.}
   TGdkDestroyNotify* = proc (data: gpointer){.cdecl.}
-  TGdkSpan* = record 
+  TGdkSpan* {.final.} = object 
     x*: gint
     y*: gint
     width*: gint
@@ -731,7 +731,7 @@ type
     GDK_WINDOW_EDGE_SOUTH_WEST, GDK_WINDOW_EDGE_SOUTH, 
     GDK_WINDOW_EDGE_SOUTH_EAST
   PGdkWindowAttr* = ptr TGdkWindowAttr
-  TGdkWindowAttr* = record 
+  TGdkWindowAttr* {.final.} = object 
     title*: cstring
     event_mask*: gint
     x*: gint
@@ -748,7 +748,7 @@ type
     override_redirect*: gboolean
 
   PGdkGeometry* = ptr TGdkGeometry
-  TGdkGeometry* = record 
+  TGdkGeometry* {.final.} = object 
     min_width*: gint
     min_height*: gint
     max_width*: gint
@@ -762,7 +762,7 @@ type
     win_gravity*: TGdkGravity
 
   PGdkPointerHooks* = ptr TGdkPointerHooks
-  TGdkPointerHooks* = record 
+  TGdkPointerHooks* {.final.} = object 
     get_pointer*: proc (window: PGdkWindow, x: Pgint, y: Pgint, 
                         mask: PGdkModifierType): PGdkWindow{.cdecl.}
     window_at_pointer*: proc (screen: PGdkScreen, win_x: Pgint, win_y: Pgint): PGdkWindow{.
diff --git a/lib/base/gtk/gdk2pixbuf.nim b/lib/base/gtk/gdk2pixbuf.nim
index 1dcc020d1..b9ab472c2 100644
--- a/lib/base/gtk/gdk2pixbuf.nim
+++ b/lib/base/gtk/gdk2pixbuf.nim
@@ -191,12 +191,12 @@ proc gdk_pixbuf_get_option*(pixbuf: PGdkPixbuf, key: cstring): cstring{.cdecl,
     dynlib: gdkpixbuflib, importc: "gdk_pixbuf_get_option".}
 type 
   PGdkPixbufLoader* = ptr TGdkPixbufLoader
-  TGdkPixbufLoader* = record 
+  TGdkPixbufLoader* {.final.} = object 
     parent_instance*: TGObject
     priv*: gpointer
 
   PGdkPixbufLoaderClass* = ptr TGdkPixbufLoaderClass
-  TGdkPixbufLoaderClass* = record 
+  TGdkPixbufLoaderClass* {.final.} = object 
     parent_class*: TGObjectClass
     area_prepared*: proc (loader: PGdkPixbufLoader){.cdecl.}
     area_updated*: proc (loader: PGdkPixbufLoader, x: int32, y: int32, 
diff --git a/lib/base/gtk/glib2.nim b/lib/base/gtk/glib2.nim
index 4b4724c70..c84bc26eb 100644
--- a/lib/base/gtk/glib2.nim
+++ b/lib/base/gtk/glib2.nim
@@ -61,7 +61,7 @@ type
   TGHFunc* = proc (key, value, user_data: gpointer){.cdecl.}
   PGFreeFunc* = proc (data: gpointer){.cdecl.}
   PGTimeVal* = ptr TGTimeVal
-  TGTimeVal* = record
+  TGTimeVal* {.final.} = object
     tv_sec*: glong
     tv_usec*: glong
 
@@ -88,17 +88,17 @@ type
   TGQuark* = guint32
   PGQuark* = ptr TGQuark
   PGTypeCValue* = ptr TGTypeCValue
-  TGTypeCValue* = record
+  TGTypeCValue* {.final.} = object
     v_double*: gdouble
 
   GType* = gulong
   PGType* = ptr GType
   PGTypeClass* = ptr TGTypeClass
-  TGTypeClass* = record
+  TGTypeClass* {.final.} = object
     g_type*: GType
 
   PGTypeInstance* = ptr TGTypeInstance
-  TGTypeInstance* = record
+  TGTypeInstance* {.final.} = object
     g_class*: PGTypeClass
 
   PGTypeInterface* = ptr TGTypeInterface
@@ -107,14 +107,14 @@ type
     g_instance_type*: GType
 
   PGTypeQuery* = ptr TGTypeQuery
-  TGTypeQuery* = record
+  TGTypeQuery* {.final.} = object
     theType*: GType
     type_name*: cstring
     class_size*: guint
     instance_size*: guint
 
   PGValue* = ptr TGValue
-  TGValue* = record
+  TGValue* {.final.} = object
     g_type*: GType
     data*: array[0..1, gdouble]
 
@@ -122,12 +122,12 @@ type
   PGData* = pointer
   PGSList* = ptr TGSList
   PPGSList* = ptr PGSList
-  TGSList* = record
+  TGSList* {.final.} = object
     data*: gpointer
     next*: PGSList
 
   PGList* = ptr TGList
-  TGList* = record
+  TGList* {.final.} = object
     data*: gpointer
     next*: PGList
     prev*: PGList
@@ -136,7 +136,7 @@ type
   TGParamFlags* = int32
   PGParamSpec* = ptr TGParamSpec
   PPGParamSpec* = ptr PGParamSpec
-  TGParamSpec* = record
+  TGParamSpec* {.final.} = object
     g_type_instance*: TGTypeInstance
     name*: cstring
     flags*: TGParamFlags
@@ -149,7 +149,7 @@ type
     param_id*: guint
 
   PGParamSpecClass* = ptr TGParamSpecClass
-  TGParamSpecClass* = record
+  TGParamSpecClass* {.final.} = object
     g_type_class*: TGTypeClass
     value_type*: GType
     finalize*: proc (pspec: PGParamSpec){.cdecl.}
@@ -160,7 +160,7 @@ type
     dummy*: array[0..3, gpointer]
 
   PGParameter* = ptr TGParameter
-  TGParameter* = record
+  TGParameter* {.final.} = object
     name*: cstring
     value*: TGValue
 
@@ -305,7 +305,7 @@ const
 
 type
   PGTypeValueTable* = ptr TGTypeValueTable
-  TGTypeValueTable* = record
+  TGTypeValueTable* {.final.} = object
     value_init*: proc (value: PGValue){.cdecl.}
     value_free*: proc (value: PGValue){.cdecl.}
     value_copy*: proc (src_value: PGValue, dest_value: PGValue){.cdecl.}
@@ -320,7 +320,7 @@ type
         cdecl.}
 
   PGTypeInfo* = ptr TGTypeInfo
-  TGTypeInfo* = record
+  TGTypeInfo* {.final.} = object
     class_size*: guint16
     base_init*: TGBaseInitFunc
     base_finalize*: TGBaseFinalizeFunc
@@ -333,11 +333,11 @@ type
     value_table*: PGTypeValueTable
 
   PGTypeFundamentalInfo* = ptr TGTypeFundamentalInfo
-  TGTypeFundamentalInfo* = record
+  TGTypeFundamentalInfo* {.final.} = object
     type_flags*: TGTypeFundamentalFlags
 
   PGInterfaceInfo* = ptr TGInterfaceInfo
-  TGInterfaceInfo* = record
+  TGInterfaceInfo* {.final.} = object
     interface_init*: TGInterfaceInitFunc
     interface_finalize*: TGInterfaceFinalizeFunc
     interface_data*: gpointer
@@ -449,7 +449,7 @@ const
 
 type
   PGValueArray* = ptr TGValueArray
-  TGValueArray* = record
+  TGValueArray* {.final.} = object
     n_values*: guint
     values*: PGValue
     n_prealloced*: guint
@@ -628,7 +628,7 @@ proc g_value_set_param_take_ownership*(value: PGValue, param: PGParamSpec){.
     cdecl, dynlib: gliblib, importc: "g_value_set_param_take_ownership".}
 type
   PGParamSpecTypeInfo* = ptr TGParamSpecTypeInfo
-  TGParamSpecTypeInfo* = record
+  TGParamSpecTypeInfo* {.final.} = object
     instance_size*: guint16
     n_preallocs*: guint16
     instance_init*: proc (pspec: PGParamSpec){.cdecl.}
@@ -668,7 +668,7 @@ type
   PGClosure* = ptr TGClosure
   PGClosureNotifyData* = ptr TGClosureNotifyData
   TGClosureNotify* = proc (data: gpointer, closure: PGClosure){.cdecl.}
-  TGClosure* = record
+  TGClosure* {.final.} = object
     flag0*: int32
     marshal*: proc (closure: PGClosure, return_value: PGValue,
                     n_param_values: guint, param_values: PGValue,
@@ -682,7 +682,7 @@ type
                             n_param_values: guint, param_values: PGValue,
                             invocation_hint: gpointer, marshal_data: gpointer){.
       cdecl.}
-  TGClosureNotifyData* = record
+  TGClosureNotifyData* {.final.} = object
     data*: gpointer
     notify*: TGClosureNotify
 
@@ -734,7 +734,7 @@ proc is_invalid*(a: var TGClosure): guint
 proc set_is_invalid*(a: var TGClosure, is_invalid: guint)
 type
   PGCClosure* = ptr TGCClosure
-  TGCClosure* = record
+  TGCClosure* {.final.} = object
     closure*: TGClosure
     callback*: gpointer
 
@@ -797,13 +797,13 @@ type
                                data: gpointer): gboolean{.cdecl.}
   PGSignalFlags* = ptr TGSignalFlags
   TGSignalFlags* = int32
-  TGSignalInvocationHint* = record
+  TGSignalInvocationHint* {.final.} = object
     signal_id*: guint
     detail*: TGQuark
     run_type*: TGSignalFlags
 
   PGSignalQuery* = ptr TGSignalQuery
-  TGSignalQuery* = record
+  TGSignalQuery* {.final.} = object
     signal_id*: guint
     signal_name*: cstring
     itype*: GType
@@ -952,7 +952,7 @@ type
   TGTypePluginCompleteInterfaceInfo* = proc (plugin: PGTypePlugin,
       instance_type: GType, interface_type: GType, info: PGInterfaceInfo){.cdecl.}
   PGTypePluginClass* = ptr TGTypePluginClass
-  TGTypePluginClass* = record
+  TGTypePluginClass* {.final.} = object
     base_iface*: TGTypeInterface
     use_plugin*: TGTypePluginUse
     unuse_plugin*: TGTypePluginUnuse
@@ -1011,7 +1011,7 @@ type
     notify*: proc (anObject: PGObject, pspec: PGParamSpec){.cdecl.}
     pdummy*: array[0..7, gpointer]
 
-  TGObjectConstructParam* = record
+  TGObjectConstructParam* {.final.} = object
     pspec*: PGParamSpec
     value*: PGValue
 
@@ -1125,27 +1125,27 @@ proc GUINT32_SWAP_LE_BE_CONSTANT*(val: guint32): guint32
 type
   PGEnumClass* = ptr TGEnumClass
   PGEnumValue* = ptr TGEnumValue
-  TGEnumClass* = record
+  TGEnumClass* {.final.} = object
     g_type_class*: TGTypeClass
     minimum*: gint
     maximum*: gint
     n_values*: guint
     values*: PGEnumValue
 
-  TGEnumValue* = record
+  TGEnumValue* {.final.} = object
     value*: gint
     value_name*: cstring
     value_nick*: cstring
 
   PGFlagsClass* = ptr TGFlagsClass
   PGFlagsValue* = ptr TGFlagsValue
-  TGFlagsClass* = record
+  TGFlagsClass* {.final.} = object
     g_type_class*: TGTypeClass
     mask*: guint
     n_values*: guint
     values*: PGFlagsValue
 
-  TGFlagsValue* = record
+  TGFlagsValue* {.final.} = object
     value*: guint
     value_name*: cstring
     value_nick*: cstring
@@ -1203,7 +1203,7 @@ const
   G_MAXUSHORT* = 2 * G_MAXSHORT + 1
   G_MAXINT* = 2147483647
   G_MININT* = - G_MAXINT - 1
-  G_MAXUINT* = 4294967295
+  G_MAXUINT* = -1
   G_MINLONG* = G_MININT
   G_MAXLONG* = G_MAXINT
   G_MAXULONG* = G_MAXUINT
@@ -1224,7 +1224,7 @@ const
 
 type
   PGSystemThread* = ptr TGSystemThread
-  TGSystemThread* = record
+  TGSystemThread* {.final.} = object
     data*: array[0..3, char]
     dummy_double*: float64
     dummy_pointer*: pointer
@@ -1350,7 +1350,7 @@ proc g_set_prgname*(prgname: cstring){.cdecl, dynlib: gliblib,
                                        importc: "g_set_prgname".}
 type
   PGDebugKey* = ptr TGDebugKey
-  TGDebugKey* = record
+  TGDebugKey* {.final.} = object
     key*: cstring
     value*: guint
 
@@ -1390,7 +1390,7 @@ proc g_bit_storage*(number: gulong): guint{.cdecl, dynlib: gliblib,
 type
   PPGTrashStack* = ptr PGTrashStack
   PGTrashStack* = ptr TGTrashStack
-  TGTrashStack* = record
+  TGTrashStack* {.final.} = object
     next*: PGTrashStack
 
 
@@ -1466,7 +1466,7 @@ const
 
 type
   PGMemVTable* = ptr TGMemVTable
-  TGMemVTable* = record
+  TGMemVTable* {.final.} = object
     malloc*: proc (n_bytes: gsize): gpointer{.cdecl.}
     realloc*: proc (mem: gpointer, n_bytes: gsize): gpointer{.cdecl.}
     free*: proc (mem: gpointer){.cdecl.}
@@ -1679,7 +1679,7 @@ type
   TGCompletionStrncmpFunc* = proc (s1: cstring, s2: cstring, n: gsize): gint{.
       cdecl.}
   PGCompletion* = ptr TGCompletion
-  TGCompletion* = record
+  TGCompletion* {.final.} = object
     items*: PGList
     func*: TGCompletionFunc
     prefix*: cstring
@@ -1809,7 +1809,7 @@ type
   PGDateDay* = ptr TGDateDay
   TGDateDay* = guint8
   Ptm* = ptr Ttm
-  Ttm* = record
+  Ttm* {.final.} = object
     tm_sec*: gint
     tm_min*: gint
     tm_hour*: gint
@@ -1872,7 +1872,7 @@ const
 
 type
   PGDate* = ptr TGDate
-  TGDate* = record
+  TGDate* {.final.} = object
     flag0*: int32
     flag1*: int32
 
@@ -2028,7 +2028,7 @@ proc g_file_open_tmp*(tmpl: cstring, name_used: PPchar, error: pointer): int32{.
     cdecl, dynlib: gliblib, importc: "g_file_open_tmp".}
 type
   PGHook* = ptr TGHook
-  TGHook* = record
+  TGHook* {.final.} = object
     data*: gpointer
     next*: PGHook
     prev*: PGHook
@@ -2047,7 +2047,7 @@ type
   TGHookFunc* = proc (data: gpointer){.cdecl.}
   TGHookCheckFunc* = proc (data: gpointer): gboolean{.cdecl.}
   TGHookFinalizeFunc* = proc (hook_list: PGHookList, hook: PGHook){.cdecl.}
-  TGHookList* = record
+  TGHookList* {.final.} = object
     seq_id*: gulong
     flag0*: int32
     hooks*: PGHook
@@ -2138,7 +2138,7 @@ proc g_hook_list_marshal_check*(hook_list: PGHookList, may_recurse: gboolean,
     importc: "g_hook_list_marshal_check".}
 type
   PGThreadPool* = ptr TGThreadPool
-  TGThreadPool* = record
+  TGThreadPool* {.final.} = object
     func*: TGFunc
     user_data*: gpointer
     exclusive*: gboolean
@@ -2352,7 +2352,7 @@ proc g_utf8_collate_key*(str: cstring, len: gssize): cstring{.cdecl,
     dynlib: gliblib, importc: "g_utf8_collate_key".}
 type
   PGString* = ptr TGString
-  TGString* = record
+  TGString* {.final.} = object
     str*: cstring
     len*: gsize
     allocated_len*: gsize
@@ -2468,7 +2468,7 @@ type
   TGIOFunc* = proc (source: PGIOChannel, condition: TGIOCondition,
                     data: gpointer): gboolean{.cdecl.}
   PGIOFuncs* = ptr TGIOFuncs
-  TGIOFuncs* = record
+  TGIOFuncs* {.final.} = object
     io_read*: proc (channel: PGIOChannel, buf: cstring, count: gsize,
                     bytes_read: Pgsize, err: pointer): TGIOStatus{.cdecl.}
     io_write*: proc (channel: PGIOChannel, buf: cstring, count: gsize,
@@ -2483,7 +2483,7 @@ type
         cdecl.}
     io_get_flags*: proc (channel: PGIOChannel): TGIOFlags{.cdecl.}
 
-  TGIOChannel* = record
+  TGIOChannel* {.final.} = object
     ref_count*: guint
     funcs*: PGIOFuncs
     encoding*: cstring
@@ -2699,7 +2699,7 @@ type
   PGMarkupParseContext* = ptr TGMarkupParseContext
   TGMarkupParseContext* = pointer
   PGMarkupParser* = ptr TGMarkupParser
-  TGMarkupParser* = record
+  TGMarkupParser* {.final.} = object
     start_element*: proc (context: PGMarkupParseContext, element_name: cstring,
                           attribute_names: PPgchar, attribute_values: PPgchar,
                           user_data: gpointer, error: pointer){.cdecl.}
@@ -2733,7 +2733,7 @@ proc g_markup_escape_text*(text: cstring, length: gssize): cstring{.cdecl,
     dynlib: gliblib, importc: "g_markup_escape_text".}
 type
   PGNode* = ptr TGNode
-  TGNode* = record
+  TGNode* {.final.} = object
     data*: gpointer
     next*: PGNode
     prev*: PGNode
@@ -2886,7 +2886,7 @@ proc g_qsort_with_data*(pbase: gconstpointer, total_elems: gint, size: gsize,
     cdecl, dynlib: gliblib, importc: "g_qsort_with_data".}
 type
   PGQueue* = ptr TGQueue
-  TGQueue* = record
+  TGQueue* {.final.} = object
     head*: PGList
     tail*: PGList
     length*: guint
@@ -2947,7 +2947,7 @@ proc g_random_double_range*(`begin`: gdouble, `end`: gdouble): gdouble{.cdecl,
     dynlib: gliblib, importc: "g_random_double_range".}
 type
   PGTuples* = ptr TGTuples
-  TGTuples* = record
+  TGTuples* {.final.} = object
     len*: guint
 
   PGRelation* = pointer
@@ -3003,12 +3003,12 @@ type
   PGScanner* = ptr TGScanner
   PGScannerConfig* = ptr TGScannerConfig
   PGTokenValue* = ptr TGTokenValue
-  TGTokenValue* = record
+  TGTokenValue* {.final.} = object
     v_float*: gdouble
 
   TGScannerMsgFunc* = proc (scanner: PGScanner, message: cstring,
                             error: gboolean){.cdecl.}
-  TGScanner* = record
+  TGScanner* {.final.} = object
     user_data*: gpointer
     max_parse_errors*: guint
     parse_errors*: guint
@@ -3031,7 +3031,7 @@ type
     scope_id*: guint
     msg_handler*: TGScannerMsgFunc
 
-  TGScannerConfig* = record
+  TGScannerConfig* {.final.} = object
     cset_skip_characters*: cstring
     cset_identifier_first*: cstring
     cset_identifier_nth*: cstring
diff --git a/lib/base/gtk/gtk2.nim b/lib/base/gtk/gtk2.nim
index 6c7a2ce9f..b7cf6e64f 100644
--- a/lib/base/gtk/gtk2.nim
+++ b/lib/base/gtk/gtk2.nim
@@ -155,17 +155,17 @@ type
   TGtkSignalFunc* = proc (para1: TGtkSignalFuncProc){.cdecl.}
   PGtkSignalMarshaller* = ptr TGtkSignalMarshaller
   TGtkSignalMarshaller* = TGSignalCMarshaller
-  TGtkArgSignalData* = record
+  TGtkArgSignalData* {.final.} = object
     f*: TGtkSignalFunc
     d*: gpointer
 
-  TGtkArg* = record
+  TGtkArg* {.final.} = object
     `type`*: TGtkType
     name*: cstring
     d*: gdouble               # was a union type
 
   PGtkTypeInfo* = ptr TGtkTypeInfo
-  TGtkTypeInfo* = record
+  TGtkTypeInfo* {.final.} = object
     type_name*: cstring
     object_size*: guint
     class_size*: guint
@@ -188,7 +188,7 @@ type
   TGtkAllocation* = TGdkRectangle
   TGtkCallback* = proc (widget: PGtkWidget, data: gpointer){.cdecl.}
   PGtkRequisition* = ptr TGtkRequisition
-  TGtkRequisition* = record
+  TGtkRequisition* {.final.} = object
     width*: gint
     height*: gint
 
@@ -323,7 +323,7 @@ type
     gtk_reserved8*: proc (){.cdecl.}
 
   PGtkWidgetAuxInfo* = ptr TGtkWidgetAuxInfo
-  TGtkWidgetAuxInfo* = record
+  TGtkWidgetAuxInfo* {.final.} = object
     x*: gint
     y*: gint
     width*: gint
@@ -331,7 +331,7 @@ type
     flag0*: guint16
 
   PGtkWidgetShapeInfo* = ptr TGtkWidgetShapeInfo
-  TGtkWidgetShapeInfo* = record
+  TGtkWidgetShapeInfo* {.final.} = object
     offset_x*: gint16
     offset_y*: gint16
     shape_mask*: PGdkBitmap
@@ -370,12 +370,12 @@ type
     gtk_reserved4: proc (){.cdecl.}
 
   PGtkAccelKey* = ptr TGtkAccelKey
-  TGtkAccelKey* = record
+  TGtkAccelKey* {.final.} = object
     accel_key*: guint
     accel_mods*: TGdkModifierType
     flag0*: guint16
 
-  TGtkAccelGroupEntry* = record
+  TGtkAccelGroupEntry* {.final.} = object
     key*: TGtkAccelKey
     closure*: PGClosure
     accel_path_quark*: TGQuark
@@ -595,7 +595,7 @@ type
   PGtkBindingSignal* = ptr TGtkBindingSignal
   PGtkBindingArg* = ptr TGtkBindingArg
   PGtkBindingSet* = ptr TGtkBindingSet
-  TGtkBindingSet* = record
+  TGtkBindingSet* {.final.} = object
     set_name*: cstring
     priority*: gint
     widget_path_pspecs*: PGSList
@@ -605,7 +605,7 @@ type
     current*: PGtkBindingEntry
     flag0*: guint16
 
-  TGtkBindingEntry* = record
+  TGtkBindingEntry* {.final.} = object
     keyval*: guint
     modifiers*: TGdkModifierType
     binding_set*: PGtkBindingSet
@@ -614,13 +614,13 @@ type
     hash_next*: PGtkBindingEntry
     signals*: PGtkBindingSignal
 
-  TGtkBindingSignal* = record
+  TGtkBindingSignal* {.final.} = object
     next*: PGtkBindingSignal
     signal_name*: cstring
     n_args*: guint
     args*: PGtkBindingArg
 
-  TGtkBindingArg* = record
+  TGtkBindingArg* {.final.} = object
     arg_type*: TGtkType
     d*: gdouble
 
@@ -634,7 +634,7 @@ type
   TGtkBoxClass* = object of TGtkContainerClass
 
   PGtkBoxChild* = ptr TGtkBoxChild
-  TGtkBoxChild* = record
+  TGtkBoxChild* {.final.} = object
     widget*: PGtkWidget
     padding*: guint16
     flag0*: guint16
@@ -906,12 +906,12 @@ type
   TGtkCListCompareFunc* = proc (clist: PGtkCList, ptr1: gconstpointer,
                                 ptr2: gconstpointer): gint{.cdecl.}
   PGtkCListCellInfo* = ptr TGtkCListCellInfo
-  TGtkCListCellInfo* = record
+  TGtkCListCellInfo* {.final.} = object
     row*: gint
     column*: gint
 
   PGtkCListDestInfo* = ptr TGtkCListDestInfo
-  TGtkCListDestInfo* = record
+  TGtkCListDestInfo* {.final.} = object
     cell*: TGtkCListCellInfo
     insert_pos*: TGtkCListDragPos
 
@@ -1014,7 +1014,7 @@ type
 
   PGPtrArray = pointer
   PGArray = pointer
-  TGtkCListColumn* = record
+  TGtkCListColumn* {.final.} = object
     title*: cstring
     area*: TGdkRectangle
     button*: PGtkWidget
@@ -1025,7 +1025,7 @@ type
     justification*: TGtkJustification
     flag0*: guint16
 
-  TGtkCListRow* = record
+  TGtkCListRow* {.final.} = object
     cell*: PGtkCell
     state*: TGtkStateType
     foreground*: TGdkColor
@@ -1036,7 +1036,7 @@ type
     flag0*: guint16
 
   PGtkCellText* = ptr TGtkCellText
-  TGtkCellText* = record
+  TGtkCellText* {.final.} = object
     `type`*: TGtkCellType
     vertical*: gint16
     horizontal*: gint16
@@ -1044,7 +1044,7 @@ type
     text*: cstring
 
   PGtkCellPixmap* = ptr TGtkCellPixmap
-  TGtkCellPixmap* = record
+  TGtkCellPixmap* {.final.} = object
     `type`*: TGtkCellType
     vertical*: gint16
     horizontal*: gint16
@@ -1053,7 +1053,7 @@ type
     mask*: PGdkBitmap
 
   PGtkCellPixText* = ptr TGtkCellPixText
-  TGtkCellPixText* = record
+  TGtkCellPixText* {.final.} = object
     `type`*: TGtkCellType
     vertical*: gint16
     horizontal*: gint16
@@ -1064,14 +1064,14 @@ type
     mask*: PGdkBitmap
 
   PGtkCellWidget* = ptr TGtkCellWidget
-  TGtkCellWidget* = record
+  TGtkCellWidget* {.final.} = object
     `type`*: TGtkCellType
     vertical*: gint16
     horizontal*: gint16
     style*: PGtkStyle
     widget*: PGtkWidget
 
-  TGtkCell* = record
+  TGtkCell* {.final.} = object
     `type`*: TGtkCellType
     vertical*: gint16
     horizontal*: gint16
@@ -1212,7 +1212,7 @@ type
                                        action: TGtkCTreeExpansionType){.cdecl.}
 
   PGtkCTreeRow* = ptr TGtkCTreeRow
-  TGtkCTreeRow* = record
+  TGtkCTreeRow* {.final.} = object
     row*: TGtkCListRow
     parent*: PGtkCTreeNode
     sibling*: PGtkCTreeNode
@@ -1224,7 +1224,7 @@ type
     level*: guint16
     GtkCTreeRow_flag0*: guint16
 
-  TGtkCTreeNode* = record
+  TGtkCTreeNode* {.final.} = object
     list*: TGList
 
   PGtkDrawingArea* = ptr TGtkDrawingArea
@@ -1479,7 +1479,7 @@ type
   TGtkFixedClass* = object of TGtkContainerClass
 
   PGtkFixedChild* = ptr TGtkFixedChild
-  TGtkFixedChild* = record
+  TGtkFixedChild* {.final.} = object
     widget*: PGtkWidget
     x*: gint
     y*: gint
@@ -1632,7 +1632,7 @@ type
     gtk_reserved363: proc (){.cdecl.}
     gtk_reserved364: proc (){.cdecl.}
 
-  TGtkRulerMetric* = record
+  TGtkRulerMetric* {.final.} = object
     metric_name*: cstring
     abbrev*: cstring
     pixels_per_unit*: gdouble
@@ -1657,7 +1657,7 @@ type
   TGtkSettingsClass* = object of TGObjectClass
 
   PGtkSettingsValue* = ptr TGtkSettingsValue
-  TGtkSettingsValue* = record
+  TGtkSettingsValue* {.final.} = object
     origin*: cstring
     value*: TGValue
 
@@ -1708,7 +1708,7 @@ type
     GTK_RC_TOKEN_IM_MODULE_FILE, GTK_RC_TOKEN_STOCK, GTK_RC_TOKEN_LTR,
     GTK_RC_TOKEN_RTL, GTK_RC_TOKEN_LAST
   PGtkRcProperty* = ptr TGtkRcProperty
-  TGtkRcProperty* = record
+  TGtkRcProperty* {.final.} = object
     type_name*: TGQuark
     property_name*: TGQuark
     origin*: cstring
@@ -1877,7 +1877,7 @@ type
     gtk_reserved3812: proc (){.cdecl.}
 
   PGtkBorder* = ptr TGtkBorder
-  TGtkBorder* = record
+  TGtkBorder* {.final.} = object
     left*: gint
     right*: gint
     top*: gint
@@ -1978,27 +1978,27 @@ type
 
   PGtkIconSet* = pointer
   PGtkImagePixmapData* = ptr TGtkImagePixmapData
-  TGtkImagePixmapData* = record
+  TGtkImagePixmapData* {.final.} = object
     pixmap*: PGdkPixmap
 
   PGtkImageImageData* = ptr TGtkImageImageData
-  TGtkImageImageData* = record
+  TGtkImageImageData* {.final.} = object
     image*: PGdkImage
 
   PGtkImagePixbufData* = ptr TGtkImagePixbufData
-  TGtkImagePixbufData* = record
+  TGtkImagePixbufData* {.final.} = object
     pixbuf*: PGdkPixbuf
 
   PGtkImageStockData* = ptr TGtkImageStockData
-  TGtkImageStockData* = record
+  TGtkImageStockData* {.final.} = object
     stock_id*: cstring
 
   PGtkImageIconSetData* = ptr TGtkImageIconSetData
-  TGtkImageIconSetData* = record
+  TGtkImageIconSetData* {.final.} = object
     icon_set*: PGtkIconSet
 
   PGtkImageAnimationData* = ptr TGtkImageAnimationData
-  TGtkImageAnimationData* = record
+  TGtkImageAnimationData* {.final.} = object
     anim*: PGdkPixbufAnimation
     iter*: PGdkPixbufAnimationIter
     frame_timeout*: guint
@@ -2111,7 +2111,7 @@ type
     gtk_reserved474: proc (){.cdecl.}
 
   PGtkItemFactoryEntry* = ptr TGtkItemFactoryEntry
-  TGtkItemFactoryEntry* = record
+  TGtkItemFactoryEntry* {.final.} = object
     path*: cstring
     accelerator*: cstring
     callback*: TGtkItemFactoryCallback
@@ -2120,7 +2120,7 @@ type
     extra_data*: gconstpointer
 
   PGtkItemFactoryItem* = ptr TGtkItemFactoryItem
-  TGtkItemFactoryItem* = record
+  TGtkItemFactoryItem* {.final.} = object
     path*: cstring
     widgets*: PGSList
 
@@ -2173,7 +2173,7 @@ type
       cdecl.}
   PGtkTreeModelFlags* = ptr TGtkTreeModelFlags
   TGtkTreeModelFlags* = int32
-  TGtkTreeIter* = record
+  TGtkTreeIter* {.final.} = object
     stamp*: gint
     user_data*: gpointer
     user_data2*: gpointer
@@ -2435,12 +2435,12 @@ type
     GtkPreview_flag0*: guint16
 
   PGtkPreviewInfo* = ptr TGtkPreviewInfo
-  TGtkPreviewInfo* = record
+  TGtkPreviewInfo* {.final.} = object
     lookup*: Pguchar
     gamma*: gdouble
 
   PGtkDitherInfo* = ptr TGtkDitherInfo
-  TGtkDitherInfo* = record
+  TGtkDitherInfo* {.final.} = object
     c*: array[0..3, guchar]
 
   PGtkPreviewClass* = ptr TGtkPreviewClass
@@ -2533,7 +2533,7 @@ type
     gtk_reserved603: proc (){.cdecl.}
     gtk_reserved604: proc (){.cdecl.}
 
-  TGtkSelectionData* = record
+  TGtkSelectionData* {.final.} = object
     selection*: TGdkAtom
     target*: TGdkAtom
     thetype*: TGdkAtom
@@ -2543,18 +2543,18 @@ type
     display*: PGdkDisplay
 
   PGtkTargetEntry* = ptr TGtkTargetEntry
-  TGtkTargetEntry* = record
+  TGtkTargetEntry* {.final.} = object
     target*: cstring
     flags*: guint
     info*: guint
 
   PGtkTargetList* = ptr TGtkTargetList
-  TGtkTargetList* = record
+  TGtkTargetList* {.final.} = object
     list*: PGList
     ref_count*: guint
 
   PGtkTargetPair* = ptr TGtkTargetPair
-  TGtkTargetPair* = record
+  TGtkTargetPair* {.final.} = object
     target*: TGdkAtom
     flags*: guint
     info*: guint
@@ -2635,7 +2635,7 @@ type
     gtk_reserved634: proc (){.cdecl.}
 
   PGtkStockItem* = ptr TGtkStockItem
-  TGtkStockItem* = record
+  TGtkStockItem* {.final.} = object
     stock_id*: cstring
     label*: cstring
     modifier*: TGdkModifierType
@@ -2681,7 +2681,7 @@ type
   TGtkTableClass* = object of TGtkContainerClass
 
   PGtkTableChild* = ptr TGtkTableChild
-  TGtkTableChild* = record
+  TGtkTableChild* {.final.} = object
     widget*: PGtkWidget
     left_attach*: guint16
     right_attach*: guint16
@@ -2691,7 +2691,7 @@ type
     ypadding*: guint16
     GtkTableChild_flag0*: guint16
 
-  TGtkTableRowCol* = record
+  TGtkTableRowCol* {.final.} = object
     requisition*: guint16
     allocation*: guint16
     spacing*: guint16
@@ -2710,7 +2710,7 @@ type
 
   PGtkTextFont* = pointer
   PGtkPropertyMark* = ptr TGtkPropertyMark
-  TGtkPropertyMark* = record
+  TGtkPropertyMark* {.final.} = object
     `property`*: PGList
     offset*: guint
     index*: guint
@@ -2764,7 +2764,7 @@ type
   PGtkTextSearchFlags* = ptr TGtkTextSearchFlags
   TGtkTextSearchFlags* = int32
   PGtkTextIter* = ptr TGtkTextIter
-  TGtkTextIter* = record
+  TGtkTextIter* {.final.} = object
     dummy1*: gpointer
     dummy2*: gpointer
     dummy3*: gint
@@ -2802,7 +2802,7 @@ type
     gtk_reserved664: proc (){.cdecl.}
 
   PGtkTextAppearance* = ptr TGtkTextAppearance
-  TGtkTextAppearance* = record
+  TGtkTextAppearance* {.final.} = object
     bg_color*: TGdkColor
     fg_color*: TGdkColor
     bg_stipple*: PGdkBitmap
@@ -2811,7 +2811,7 @@ type
     padding1*: gpointer
     flag0*: guint16
 
-  TGtkTextAttributes* = record
+  TGtkTextAttributes* {.final.} = object
     refcount*: guint
     appearance*: TGtkTextAppearance
     justification*: TGtkJustification
@@ -2860,7 +2860,7 @@ type
     gtk_reserved4: proc (){.cdecl.}
 
   PGtkTextMarkBody* = ptr TGtkTextMarkBody
-  TGtkTextMarkBody* = record
+  TGtkTextMarkBody* {.final.} = object
     obj*: PGtkTextMark
     name*: cstring
     tree*: PGtkTextBTree
@@ -2879,11 +2879,11 @@ type
     gtk_reserved4: proc (){.cdecl.}
 
   PGtkTextPixbuf* = ptr TGtkTextPixbuf
-  TGtkTextPixbuf* = record
+  TGtkTextPixbuf* {.final.} = object
     pixbuf*: PGdkPixbuf
 
   PGtkTextChildBody* = ptr TGtkTextChildBody
-  TGtkTextChildBody* = record
+  TGtkTextChildBody* {.final.} = object
     obj*: PGtkTextChildAnchor
     widgets*: PGSList
     tree*: PGtkTextBTree
@@ -2892,17 +2892,17 @@ type
   PGtkTextLineSegment* = ptr TGtkTextLineSegment
   PGtkTextLineSegmentClass* = ptr TGtkTextLineSegmentClass
   PGtkTextTagInfo* = ptr TGtkTextTagInfo
-  TGtkTextTagInfo* = record
+  TGtkTextTagInfo* {.final.} = object
     tag*: PGtkTextTag
     tag_root*: PGtkTextBTreeNode
     toggle_count*: gint
 
   PGtkTextToggleBody* = ptr TGtkTextToggleBody
-  TGtkTextToggleBody* = record
+  TGtkTextToggleBody* {.final.} = object
     info*: PGtkTextTagInfo
     inNodeCounts*: gboolean
 
-  TGtkTextLineSegment* = record
+  TGtkTextLineSegment* {.final.} = object
     `type`*: PGtkTextLineSegmentClass
     next*: PGtkTextLineSegment
     char_count*: int32
@@ -2919,7 +2919,7 @@ type
                                      line: PGtkTextLine){.cdecl.}
   TGtkTextSegCheckFunc* = proc (seg: PGtkTextLineSegment, line: PGtkTextLine){.
       cdecl.}
-  TGtkTextLineSegmentClass* = record
+  TGtkTextLineSegmentClass* {.final.} = object
     name*: cstring
     leftGravity*: gboolean
     splitFunc*: TGtkTextSegSplitFunc
@@ -2929,13 +2929,13 @@ type
     checkFunc*: TGtkTextSegCheckFunc
 
   PGtkTextLineData* = ptr TGtkTextLineData
-  TGtkTextLineData* = record
+  TGtkTextLineData* {.final.} = object
     view_id*: gpointer
     next*: PGtkTextLineData
     height*: gint
     flag0*: int32
 
-  TGtkTextLine* = record
+  TGtkTextLine* {.final.} = object
     parent*: PGtkTextBTreeNode
     next*: PGtkTextLine
     segments*: PGtkTextLineSegment
@@ -3020,18 +3020,18 @@ type
     gtk_reserved4: proc (){.cdecl.}
 
   PGtkTextAttrAppearance* = ptr TGtkTextAttrAppearance
-  TGtkTextAttrAppearance* = record
+  TGtkTextAttrAppearance* {.final.} = object
     attr*: TPangoAttribute
     appearance*: TGtkTextAppearance
 
   PGtkTextCursorDisplay* = ptr TGtkTextCursorDisplay
-  TGtkTextCursorDisplay* = record
+  TGtkTextCursorDisplay* {.final.} = object
     x*: gint
     y*: gint
     height*: gint
     flag0*: guint16
 
-  TGtkTextLineDisplay* = record
+  TGtkTextLineDisplay* {.final.} = object
     layout*: PPangoLayout
     cursors*: PGSList
     shaped_objects*: PGSList
@@ -3152,7 +3152,7 @@ type
 
   PGtkTooltips* = ptr TGtkTooltips
   PGtkTooltipsData* = ptr TGtkTooltipsData
-  TGtkTooltipsData* = record
+  TGtkTooltipsData* {.final.} = object
     tooltips*: PGtkTooltips
     widget*: PGtkWidget
     tip_text*: cstring
@@ -3184,7 +3184,7 @@ type
   TGtkToolbarSpaceStyle* = enum
     GTK_TOOLBAR_SPACE_EMPTY, GTK_TOOLBAR_SPACE_LINE
   PGtkToolbarChild* = ptr TGtkToolbarChild
-  TGtkToolbarChild* = record
+  TGtkToolbarChild* {.final.} = object
     `type`*: TGtkToolbarChildType
     widget*: PGtkWidget
     icon*: PGtkWidget
@@ -3365,13 +3365,13 @@ type
   PGtkRBNode* = ptr TGtkRBNode
   TGtkRBTreeTraverseFunc* = proc (tree: PGtkRBTree, node: PGtkRBNode,
                                   data: gpointer){.cdecl.}
-  TGtkRBTree* = record
+  TGtkRBTree* {.final.} = object
     root*: PGtkRBNode
     `nil`*: PGtkRBNode
     parent_tree*: PGtkRBTree
     parent_node*: PGtkRBNode
 
-  TGtkRBNode* = record
+  TGtkRBNode* {.final.} = object
     flag0*: guint16
     left*: PGtkRBNode
     right*: PGtkRBNode
@@ -3386,14 +3386,14 @@ type
   TGtkTreeViewSearchDialogPositionFunc* = proc (tree_view: PGtkTreeView,
       search_dialog: PGtkWidget){.cdecl.}
   PGtkTreeViewColumnReorder* = ptr TGtkTreeViewColumnReorder
-  TGtkTreeViewColumnReorder* = record
+  TGtkTreeViewColumnReorder* {.final.} = object
     left_align*: gint
     right_align*: gint
     left_column*: PGtkTreeViewColumn
     right_column*: PGtkTreeViewColumn
 
   PGtkTreeViewPrivate* = ptr TGtkTreeViewPrivate
-  TGtkTreeViewPrivate* = record
+  TGtkTreeViewPrivate* {.final.} = object
     model*: PGtkTreeModel
     flags*: guint
     tree*: PGtkRBTree
@@ -11304,96 +11304,127 @@ proc GTK_FUNDAMENTAL_TYPE*(thetype: GType): GType =
   result = G_TYPE_FUNDAMENTAL(thetype)
 
 proc GTK_VALUE_CHAR*(a: TGtkArg): gchar =
+  var a = a
   Result = cast[ptr gchar](addr(a.d))^
 
 proc GTK_VALUE_UCHAR*(a: TGtkArg): guchar =
+  var a = a
   Result = cast[ptr guchar](addr(a.d))^
 
 proc GTK_VALUE_BOOL*(a: TGtkArg): gboolean =
+  var a = a
   Result = cast[ptr gboolean](addr(a.d))^
 
 proc GTK_VALUE_INT*(a: TGtkArg): gint =
+  var a = a
   Result = cast[ptr gint](addr(a.d))^
 
 proc GTK_VALUE_UINT*(a: TGtkArg): guint =
+  var a = a
   Result = cast[ptr guint](addr(a.d))^
 
 proc GTK_VALUE_LONG*(a: TGtkArg): glong =
+  var a = a
   Result = cast[ptr glong](addr(a.d))^
 
 proc GTK_VALUE_ULONG*(a: TGtkArg): gulong =
+  var a = a
   Result = cast[ptr gulong](addr(a.d))^
 
 proc GTK_VALUE_FLOAT*(a: TGtkArg): gfloat =
+  var a = a
   Result = cast[ptr gfloat](addr(a.d))^
 
 proc GTK_VALUE_DOUBLE*(a: TGtkArg): gdouble =
+  var a = a
   Result = cast[ptr gdouble](addr(a.d))^
 
 proc GTK_VALUE_STRING*(a: TGtkArg): cstring =
+  var a = a
   Result = cast[ptr cstring](addr(a.d))^
 
 proc GTK_VALUE_ENUM*(a: TGtkArg): gint =
+  var a = a
   Result = cast[ptr gint](addr(a.d))^
 
 proc GTK_VALUE_FLAGS*(a: TGtkArg): guint =
+  var a = a
   Result = cast[ptr guint](addr(a.d))^
 
 proc GTK_VALUE_BOXED*(a: TGtkArg): gpointer =
+  var a = a
   Result = cast[ptr gpointer](addr(a.d))^
 
 proc GTK_VALUE_OBJECT*(a: TGtkArg): PGtkObject =
+  var a = a
   Result = cast[ptr PGtkObject](addr(a.d))^
 
 proc GTK_VALUE_POINTER*(a: TGtkArg): GPointer =
+  var a = a
   Result = cast[ptr gpointer](addr(a.d))^
 
 proc GTK_VALUE_SIGNAL*(a: TGtkArg): TGtkArgSignalData =
+  var a = a
   Result = cast[ptr TGtkArgSignalData](addr(a.d))^
 
 proc GTK_RETLOC_CHAR*(a: TGtkArg): cstring =
+  var a = a
   Result = cast[ptr cstring](addr(a.d))^
 
 proc GTK_RETLOC_UCHAR*(a: TGtkArg): Pguchar =
+  var a = a
   Result = cast[ptr pguchar](addr(a.d))^
 
 proc GTK_RETLOC_BOOL*(a: TGtkArg): Pgboolean =
+  var a = a
   Result = cast[ptr pgboolean](addr(a.d))^
 
 proc GTK_RETLOC_INT*(a: TGtkArg): Pgint =
+  var a = a
   Result = cast[ptr pgint](addr(a.d))^
 
 proc GTK_RETLOC_UINT*(a: TGtkArg): Pguint =
+  var a = a
   Result = cast[ptr pguint](addr(a.d))^
 
 proc GTK_RETLOC_LONG*(a: TGtkArg): Pglong =
+  var a = a
   Result = cast[ptr pglong](addr(a.d))^
 
 proc GTK_RETLOC_ULONG*(a: TGtkArg): Pgulong =
+  var a = a
   Result = cast[ptr pgulong](addr(a.d))^
 
 proc GTK_RETLOC_FLOAT*(a: TGtkArg): Pgfloat =
+  var a = a
   Result = cast[ptr pgfloat](addr(a.d))^
 
 proc GTK_RETLOC_DOUBLE*(a: TGtkArg): Pgdouble =
+  var a = a
   Result = cast[ptr pgdouble](addr(a.d))^
 
 proc GTK_RETLOC_STRING*(a: TGtkArg): Ppgchar =
+  var a = a
   Result = cast[ptr Ppgchar](addr(a.d))^
 
 proc GTK_RETLOC_ENUM*(a: TGtkArg): Pgint =
+  var a = a
   Result = cast[ptr Pgint](addr(a.d))^
 
 proc GTK_RETLOC_FLAGS*(a: TGtkArg): Pguint =
+  var a = a
   Result = cast[ptr pguint](addr(a.d))^
 
 proc GTK_RETLOC_BOXED*(a: TGtkArg): Pgpointer =
+  var a = a
   Result = cast[ptr pgpointer](addr(a.d))^
 
 proc GTK_RETLOC_OBJECT*(a: TGtkArg): PPGtkObject =
+  var a = a
   Result = cast[ptr ppgtkobject](addr(a.d))^
 
 proc GTK_RETLOC_POINTER*(a: TGtkArg): Pgpointer =
+  var a = a
   Result = cast[ptr pgpointer](addr(a.d))^
 
 proc GTK_TYPE_WIDGET*(): GType =
@@ -15108,7 +15139,7 @@ proc gtk_signal_handler_pending_by_func*(anObject: PGtkObject, signal_id: guint,
       G_SIGNAL_MATCH_DATA)
   if not may_be_blocked:
     t = t or cast[int](G_SIGNAL_MATCH_UNBLOCKED)
-  Result = g_signal_handler_find(anObject, t, signal_id, 0, nil, addr(func_),
+  Result = g_signal_handler_find(anObject, t, signal_id, 0, nil, func_,
                                  data) != 0
 
 proc GTK_TYPE_SIZE_GROUP*(): GType =
@@ -17045,7 +17076,7 @@ type
     GTK_FILE_FILTER_FILENAME = 1 shl 0, GTK_FILE_FILTER_URI = 1 shl 1, 
     GTK_FILE_FILTER_DISPLAY_NAME = 1 shl 2, GTK_FILE_FILTER_MIME_TYPE = 1 shl 3
   PGtkFileFilterInfo* = ref TGtkFileFilterInfo
-  TGtkFileFilterInfo* = record 
+  TGtkFileFilterInfo* {.final.} = object 
     contains*: TGtkFileFilterFlags
     filename*: cstring
     uri*: cstring
diff --git a/lib/base/gtk/gtkhtml.nim b/lib/base/gtk/gtkhtml.nim
index 5599eec2b..ca1ce883d 100644
--- a/lib/base/gtk/gtkhtml.nim
+++ b/lib/base/gtk/gtkhtml.nim
@@ -68,12 +68,12 @@ type
                             exc: PDomException): PDomString{.cdecl.}
 
   PDomDocument* = ptr TDomDocument
-  TDomDocument* = record 
+  TDomDocument* {.final.} = object 
     parent*: PDomNode
     iterators*: PGSList
 
   PDomDocumentClass* = ptr TDomDocumentClass
-  TDomDocumentClass* = record 
+  TDomDocumentClass* {.final.} = object 
     parent_class*: PDomNodeClass
 
   PHtmlFocusIterator* = ptr THtmlFocusIterator
diff --git a/lib/base/gtk/pango.nim b/lib/base/gtk/pango.nim
index 4c6c48bf8..142ab4aa2 100644
--- a/lib/base/gtk/pango.nim
+++ b/lib/base/gtk/pango.nim
@@ -50,7 +50,7 @@ type
   PPangoGlyph* = ptr TPangoGlyph
   TPangoGlyph* = guint32
   PPangoRectangle* = ptr TPangoRectangle
-  TPangoRectangle* = record 
+  TPangoRectangle* {.final.} = object 
     x*: int32
     y*: int32
     width*: int32
@@ -61,7 +61,7 @@ type
     PANGO_DIRECTION_LTR, PANGO_DIRECTION_RTL, PANGO_DIRECTION_TTB_LTR, 
     PANGO_DIRECTION_TTB_RTL
   PPangoColor* = ptr TPangoColor
-  TPangoColor* = record 
+  TPangoColor* {.final.} = object 
     red*: guint16
     green*: guint16
     blue*: guint16
@@ -72,12 +72,12 @@ type
   TPangoUnderline* = int32
   PPangoAttribute* = ptr TPangoAttribute
   PPangoAttrClass* = ptr TPangoAttrClass
-  TPangoAttribute* = record 
+  TPangoAttribute* {.final.} = object 
     klass*: PPangoAttrClass
     start_index*: int
     end_index*: int
 
-  TPangoAttrClass* = record 
+  TPangoAttrClass* {.final.} = object 
     `type`*: TPangoAttrType
     copy*: proc (attr: PPangoAttribute): PPangoAttribute{.cdecl.}
     destroy*: proc (attr: PPangoAttribute){.cdecl.}
@@ -85,43 +85,43 @@ type
         cdecl.}
 
   PPangoAttrString* = ptr TPangoAttrString
-  TPangoAttrString* = record 
+  TPangoAttrString* {.final.} = object 
     attr*: TPangoAttribute
     value*: cstring
 
   PPangoAttrLanguage* = ptr TPangoAttrLanguage
-  TPangoAttrLanguage* = record 
+  TPangoAttrLanguage* {.final.} = object 
     attr*: TPangoAttribute
     value*: PPangoLanguage
 
   PPangoAttrInt* = ptr TPangoAttrInt
-  TPangoAttrInt* = record 
+  TPangoAttrInt* {.final.} = object 
     attr*: TPangoAttribute
     value*: int32
 
   PPangoAttrFloat* = ptr TPangoAttrFloat
-  TPangoAttrFloat* = record 
+  TPangoAttrFloat* {.final.} = object 
     attr*: TPangoAttribute
     value*: gdouble
 
   PPangoAttrColor* = ptr TPangoAttrColor
-  TPangoAttrColor* = record 
+  TPangoAttrColor* {.final.} = object 
     attr*: TPangoAttribute
     color*: TPangoColor
 
   PPangoAttrShape* = ptr TPangoAttrShape
-  TPangoAttrShape* = record 
+  TPangoAttrShape* {.final.} = object 
     attr*: TPangoAttribute
     ink_rect*: TPangoRectangle
     logical_rect*: TPangoRectangle
 
   PPangoAttrFontDesc* = ptr TPangoAttrFontDesc
-  TPangoAttrFontDesc* = record 
+  TPangoAttrFontDesc* {.final.} = object 
     attr*: TPangoAttribute
     desc*: PPangoFontDescription
 
   PPangoLogAttr* = ptr TPangoLogAttr
-  TPangoLogAttr* = record 
+  TPangoLogAttr* {.final.} = object 
     flag0*: guint16
 
   PPangoCoverageLevel* = ptr TPangoCoverageLevel
@@ -129,25 +129,25 @@ type
     PANGO_COVERAGE_NONE, PANGO_COVERAGE_FALLBACK, PANGO_COVERAGE_APPROXIMATE, 
     PANGO_COVERAGE_EXACT
   PPangoBlockInfo* = ptr TPangoBlockInfo
-  TPangoBlockInfo* = record 
+  TPangoBlockInfo* {.final.} = object 
     data*: Pguchar
     level*: TPangoCoverageLevel
 
   PPangoCoverage* = ptr TPangoCoverage
-  TPangoCoverage* = record 
+  TPangoCoverage* {.final.} = object 
     ref_count*: int
     n_blocks*: int32
     data_size*: int32
     blocks*: PPangoBlockInfo
 
   PPangoEngineRange* = ptr TPangoEngineRange
-  TPangoEngineRange* = record 
+  TPangoEngineRange* {.final.} = object 
     start*: int32
     theEnd*: int32
     langs*: cstring
 
   PPangoEngineInfo* = ptr TPangoEngineInfo
-  TPangoEngineInfo* = record 
+  TPangoEngineInfo* {.final.} = object 
     id*: cstring
     engine_type*: cstring
     render_type*: cstring
@@ -155,7 +155,7 @@ type
     n_ranges*: gint
 
   PPangoEngine* = ptr TPangoEngine
-  TPangoEngine* = record 
+  TPangoEngine* {.final.} = object 
     id*: cstring
     `type`*: cstring
     length*: gint
@@ -165,7 +165,7 @@ type
                                        attrs: PPangoLogAttr, attrs_len: int32){.
       cdecl.}
   PPangoEngineLang* = ptr TPangoEngineLang
-  TPangoEngineLang* = record 
+  TPangoEngineLang* {.final.} = object 
     engine*: TPangoEngine
     script_break*: TPangoEngineLangScriptBreak
 
@@ -176,7 +176,7 @@ type
                                         language: PPangoLanguage): PPangoCoverage{.
       cdecl.}
   PPangoEngineShape* = ptr TPangoEngineShape
-  TPangoEngineShape* = record 
+  TPangoEngineShape* {.final.} = object 
     engine*: TPangoEngine
     script_shape*: TPangoEngineShapeScript
     get_coverage*: TPangoEngineShapeGetCoverage
@@ -194,28 +194,28 @@ type
   PPangoGlyphUnit* = ptr TPangoGlyphUnit
   TPangoGlyphUnit* = gint32
   PPangoGlyphGeometry* = ptr TPangoGlyphGeometry
-  TPangoGlyphGeometry* = record 
+  TPangoGlyphGeometry* {.final.} = object 
     width*: TPangoGlyphUnit
     x_offset*: TPangoGlyphUnit
     y_offset*: TPangoGlyphUnit
 
   PPangoGlyphVisAttr* = ptr TPangoGlyphVisAttr
-  TPangoGlyphVisAttr* = record 
+  TPangoGlyphVisAttr* {.final.} = object 
     flag0*: int16
 
   PPangoGlyphInfo* = ptr TPangoGlyphInfo
-  TPangoGlyphInfo* = record 
+  TPangoGlyphInfo* {.final.} = object 
     glyph*: TPangoGlyph
     geometry*: TPangoGlyphGeometry
     attr*: TPangoGlyphVisAttr
 
-  TPangoGlyphString* = record 
+  TPangoGlyphString* {.final.} = object 
     num_glyphs*: gint
     glyphs*: PPangoGlyphInfo
     log_clusters*: Pgint
     space*: gint
 
-  TPangoAnalysis* = record 
+  TPangoAnalysis* {.final.} = object 
     shape_engine*: PPangoEngineShape
     lang_engine*: PPangoEngineLang
     font*: PPangoFont
@@ -223,7 +223,7 @@ type
     language*: PPangoLanguage
     extra_attrs*: PGSList
 
-  TPangoItem* = record 
+  TPangoItem* {.final.} = object 
     offset*: gint
     length*: gint
     num_chars*: gint
@@ -236,14 +236,14 @@ type
   TPangoWrapMode* = enum 
     PANGO_WRAP_WORD, PANGO_WRAP_CHAR
   PPangoLayoutLine* = ptr TPangoLayoutLine
-  TPangoLayoutLine* = record 
+  TPangoLayoutLine* {.final.} = object 
     layout*: PPangoLayout
     start_index*: gint
     length*: gint
     runs*: PGSList
 
   PPangoLayoutRun* = ptr TPangoLayoutRun
-  TPangoLayoutRun* = record 
+  TPangoLayoutRun* {.final.} = object 
     item*: PPangoItem
     glyphs*: PPangoGlyphString
 
diff --git a/lib/base/nregex.nim b/lib/base/nregex.nim
index 509f77f1b..77afb8421 100644
--- a/lib/base/nregex.nim
+++ b/lib/base/nregex.nim
@@ -12,7 +12,7 @@ type
     regMN,
     regNewline
   
-  TRegex = record
+  TRegex = object of TObject
     case kind: TRegexKind
     of regChar: c: char
     of regSet: s: ref set[char]
diff --git a/lib/base/pcre.nim b/lib/base/pcre.nim
index 6a9f14123..1023f86f3 100644
--- a/lib/base/pcre.nim
+++ b/lib/base/pcre.nim
@@ -162,7 +162,7 @@ type
   # Data passed back in callouts  

   # Const before type ignored 

   # Pointer to character tables  

-  Tpcre_extra* = record

+  Tpcre_extra* {.final.} = object

     flags: cuint

     study_data: pointer

     match_limit: cuint

@@ -189,7 +189,7 @@ type
   # Offset to next item in the pattern  

   # Length of next item in the pattern  

   # ------------------------------------------------------------------  

-  TPcre_callout_block* = record

+  TPcre_callout_block* {.final.} = object

     version: cint

     callout_number: cint

     offset_vector: ptr cint

diff --git a/lib/complex.nim b/lib/complex.nim
index b5724e48f..6f0f568a3 100644
--- a/lib/complex.nim
+++ b/lib/complex.nim
@@ -19,10 +19,8 @@ import
   math

 

 type

-  TComplex* = record ## a complex number, consisting of a real and an

-                     ## imaginary part

-    re*: float       ## real part of the complex number

-    im*: float       ## imarginary part of the complex number

+  TComplex* = tuple[re, im: float] 

+    ## a complex number, consisting of a real and an imaginary part

 

 proc `==` *(x, y: TComplex): bool =

   ## Compare two complex numbers `x` and `y` for equality.

diff --git a/lib/debugger.nim b/lib/debugger.nim
index dca346fe0..03cbb6c0b 100644
--- a/lib/debugger.nim
+++ b/lib/debugger.nim
@@ -25,23 +25,24 @@ type
     dbQuiting,    # debugger wants to quit

     dbBreakpoints # debugger is only interested in breakpoints

 

-  TDbgBreakpoint = record

+  TDbgBreakpoint {.final.} = object

     low, high: int   # range from low to high; if disabled

                      # both low and high are set to their negative values

                      # this makes the check faster and safes memory

     filename: string

     name: string     # name of breakpoint

 

-  TVarSlot {.compilerproc.} = record # variable slots used for debugger:

+  TVarSlot {.compilerproc, final.} = object # variable slots used for debugger:

     address: pointer

     typ: PNimType

     name: cstring   # for globals this is "module.name"

 

   PExtendedFrame = ptr TExtendedFrame

-  TExtendedFrame = record  # If the debugger is enabled the compiler provides 

-                           # an extended frame. Of course only slots that are

-                           # needed are allocated and not 10_000, except for

-                           # the global data description.

+  TExtendedFrame {.final.} = object  # If the debugger is enabled the compiler

+                                     # provides an extended frame. Of course

+                                     # only slots that are

+                                     # needed are allocated and not 10_000,

+                                     # except for the global data description.

     f: TFrame

     slots: array[0..10_000, TVarSlot]

 

@@ -69,7 +70,7 @@ proc findBreakpoint(name: string): int =
   return -1

 

 proc ListBreakPoints() =

-  write(stdout, "*** emdb| Breakpoints:\n")

+  write(stdout, "*** endb| Breakpoints:\n")

   for i in 0 .. dbgBPlen-1:

     write(stdout, dbgBP[i].name & ": " & $abs(dbgBP[i].low) & ".." &

                   $abs(dbgBP[i].high) & dbgBP[i].filename)

@@ -101,13 +102,13 @@ proc writeVariable(stream: TFile, slot: TVarSlot) =
   writeln(stream, dbgRepr(slot.address, slot.typ))

 

 proc ListFrame(stream: TFile, f: PExtendedFrame) =

-  write(stream, "*** emdb| Frame (" & $f.f.len &  " slots):\n")

+  write(stream, "*** endb| Frame (" & $f.f.len &  " slots):\n")

   for i in 0 .. f.f.len-1:

     writeVariable(stream, f.slots[i])

   write(stream, "***\n")

 

 proc ListVariables(stream: TFile, f: PExtendedFrame) =

-  write(stream, "*** emdb| Frame (" & $f.f.len & " slots):\n")

+  write(stream, "*** endb| Frame (" & $f.f.len & " slots):\n")

   for i in 0 .. f.f.len-1:

     writeln(stream, f.slots[i].name)

   write(stream, "***\n")

@@ -115,7 +116,7 @@ proc ListVariables(stream: TFile, f: PExtendedFrame) =
 proc debugOut(msg: cstring) =

   # the *** *** markers are for easy recognition of debugger

   # output for external frontends.

-  write(stdout, "*** emdb| ")

+  write(stdout, "*** endb| ")

   write(stdout, msg)

   write(stdout, "***\n")

 

@@ -131,14 +132,14 @@ proc findVariable(frame: PExtendedFrame, varname: cstring): int =
 

 proc dbgShowCurrentProc(dbgFramePointer: PFrame) =

   if dbgFramePointer != nil:

-    write(stdout, "*** emdb| now in proc: ")

+    write(stdout, "*** endb| now in proc: ")

     write(stdout, dbgFramePointer.procname)

     write(stdout, " ***\n")

   else:

-    write(stdout, "*** emdb| (procedure name not available) ***\n")

+    write(stdout, "*** endb| (procedure name not available) ***\n")

 

 proc dbgShowExecutionPoint() =

-  write(stdout, "*** emdb| " & $framePtr.filename & "(" & $framePtr.line &

+  write(stdout, "*** endb| " & $framePtr.filename & "(" & $framePtr.line &

                 ") " & $framePtr.procname & " ***\n")

 

 when defined(windows) or defined(dos) or defined(os2):

@@ -219,26 +220,26 @@ h, help                 display this help message
 q, quit                 quit the debugger and the program

 <ENTER>                 repeat the previous debugger command

               EXECUTING

-s, stepinto             single step, stepping into routine calls

-n, stepover             single step, without stepping into routine calls

+s, step                 single step, stepping into routine calls

+n, next                 single step, without stepping into routine calls

 f, skipcurrent          continue execution until the current routine finishes

 c, continue             continue execution until the next breakpoint

 i, ignore               continue execution, ignore all breakpoints

               BREAKPOINTS

-b, setbreak  <name> [fromline [toline]] [file]

+b, break <name> [fromline [toline]] [file]

                         set a new breakpoint named 'name' for line and file

                         if line or file are omitted the current one is used

 breakpoints             display the entire breakpoint list

 disable <name>          disable a breakpoint

 enable  <name>          enable a breakpoint

               DATA DISPLAY

-e, eval <exp>           evaluate the expression <exp>

-o, out <file> <exp>     evaluate <exp> and write it to <file>

+e, eval <expr>          evaluate the expression <expr>

+o, out <file> <expr>    evaluate <expr> and write it to <file>

 w, where                display the current execution point

 stackframe [file]       display current stack frame [and write it to file]

 u, up                   go up in the call stack

 d, down                 go down in the call stack

-callstack               display the entire call stack

+bt, backtrace           display the entire call stack

 l, locals               display available local variables

 g, globals              display available global variables

 maxdisplay <integer>    set the display's recursion maximum

@@ -352,7 +353,7 @@ proc CommandPrompt() =
     dbgDown: int = 0 # how often we did go down

 

   while again:

-    write(stdout, "*** emdb| >>")

+    write(stdout, "*** endb| >>")

     var tmp = readLine(stdin)

     if tmp.len > 0: dbgUser = tmp

     # now look what we have to do:

@@ -360,10 +361,10 @@ proc CommandPrompt() =
     var i = scanWord(dbgUser, dbgTemp, 0)

     case dbgTemp

     of "": InvalidCommand()

-    of "s", "stepinto":

+    of "s", "step":

       dbgState = dbStepInto

       again = false

-    of "n", "stepover":

+    of "n", "next":

       dbgState = dbStepOver

       dbgSkipToFrame = framePtr

       again = false

@@ -412,9 +413,9 @@ proc CommandPrompt() =
         dbgShowCurrentProc(dbgFramePtr)

       else:

         debugOut("[Warning] cannot go down any further ")

-    of "callstack":

+    of "bt", "backtrace":

       WriteStackTrace()

-    of "b", "setbreak":

+    of "b", "break":

       setBreakPoint(dbgUser, i)

     of "breakpoints":

       ListBreakPoints()

@@ -443,7 +444,7 @@ proc endbStep() =
 proc checkForBreakpoint() =

   var i = dbgBreakpointReached(framePtr.line)

   if i >= 0:

-    write(stdout, "*** emdb| reached ")

+    write(stdout, "*** endb| reached ")

     write(stdout, dbgBP[i].name)

     write(stdout, " in ")

     write(stdout, framePtr.filename)

diff --git a/lib/dlmalloc.c b/lib/dlmalloc.c
index 79fb5801b..c907da830 100644
--- a/lib/dlmalloc.c
+++ b/lib/dlmalloc.c
@@ -1,5071 +1,5073 @@
-#define USE_DL_PREFIX

-

-#define FOOTERS 1

-#define DEBUG 1

-/*

-#define ABORT_ON_ASSERT_FAILURE 0

-*/

-

-/*

-  This is a version (aka dlmalloc) of malloc/free/realloc written by

-  Doug Lea and released to the public domain, as explained at

-  http://creativecommons.org/licenses/publicdomain.  Send questions,

-  comments, complaints, performance data, etc to dl@cs.oswego.edu

-

-* Version 2.8.3 Thu Sep 22 11:16:15 2005  Doug Lea  (dl at gee)

-

-   Note: There may be an updated version of this malloc obtainable at

-           ftp://gee.cs.oswego.edu/pub/misc/malloc.c

-         Check before installing!

-

-* Quickstart

-

-  This library is all in one file to simplify the most common usage:

-  ftp it, compile it (-O3), and link it into another program. All of

-  the compile-time options default to reasonable values for use on

-  most platforms.  You might later want to step through various

-  compile-time and dynamic tuning options.

-

-  For convenience, an include file for code using this malloc is at:

-     ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.3.h

-  You don't really need this .h file unless you call functions not

-  defined in your system include files.  The .h file contains only the

-  excerpts from this file needed for using this malloc on ANSI C/C++

-  systems, so long as you haven't changed compile-time options about

-  naming and tuning parameters.  If you do, then you can create your

-  own malloc.h that does include all settings by cutting at the point

-  indicated below. Note that you may already by default be using a C

-  library containing a malloc that is based on some version of this

-  malloc (for example in linux). You might still want to use the one

-  in this file to customize settings or to avoid overheads associated

-  with library versions.

-

-* Vital statistics:

-

-  Supported pointer/size_t representation:       4 or 8 bytes

-       size_t MUST be an unsigned type of the same width as

-       pointers. (If you are using an ancient system that declares

-       size_t as a signed type, or need it to be a different width

-       than pointers, you can use a previous release of this malloc

-       (e.g. 2.7.2) supporting these.)

-

-  Alignment:                                     8 bytes (default)

-       This suffices for nearly all current machines and C compilers.

-       However, you can define MALLOC_ALIGNMENT to be wider than this

-       if necessary (up to 128bytes), at the expense of using more space.

-

-  Minimum overhead per allocated chunk:   4 or  8 bytes (if 4byte sizes)

-                                          8 or 16 bytes (if 8byte sizes)

-       Each malloced chunk has a hidden word of overhead holding size

-       and status information, and additional cross-check word

-       if FOOTERS is defined.

-

-  Minimum allocated size: 4-byte ptrs:  16 bytes    (including overhead)

-                          8-byte ptrs:  32 bytes    (including overhead)

-

-       Even a request for zero bytes (i.e., malloc(0)) returns a

-       pointer to something of the minimum allocatable size.

-       The maximum overhead wastage (i.e., number of extra bytes

-       allocated than were requested in malloc) is less than or equal

-       to the minimum size, except for requests >= mmap_threshold that

-       are serviced via mmap(), where the worst case wastage is about

-       32 bytes plus the remainder from a system page (the minimal

-       mmap unit); typically 4096 or 8192 bytes.

-

-  Security: static-safe; optionally more or less

-       The "security" of malloc refers to the ability of malicious

-       code to accentuate the effects of errors (for example, freeing

-       space that is not currently malloc'ed or overwriting past the

-       ends of chunks) in code that calls malloc.  This malloc

-       guarantees not to modify any memory locations below the base of

-       heap, i.e., static variables, even in the presence of usage

-       errors.  The routines additionally detect most improper frees

-       and reallocs.  All this holds as long as the static bookkeeping

-       for malloc itself is not corrupted by some other means.  This

-       is only one aspect of security -- these checks do not, and

-       cannot, detect all possible programming errors.

-

-       If FOOTERS is defined nonzero, then each allocated chunk

-       carries an additional check word to verify that it was malloced

-       from its space.  These check words are the same within each

-       execution of a program using malloc, but differ across

-       executions, so externally crafted fake chunks cannot be

-       freed. This improves security by rejecting frees/reallocs that

-       could corrupt heap memory, in addition to the checks preventing

-       writes to statics that are always on.  This may further improve

-       security at the expense of time and space overhead.  (Note that

-       FOOTERS may also be worth using with MSPACES.)

-

-       By default detected errors cause the program to abort (calling

-       "abort()"). You can override this to instead proceed past

-       errors by defining PROCEED_ON_ERROR.  In this case, a bad free

-       has no effect, and a malloc that encounters a bad address

-       caused by user overwrites will ignore the bad address by

-       dropping pointers and indices to all known memory. This may

-       be appropriate for programs that should continue if at all

-       possible in the face of programming errors, although they may

-       run out of memory because dropped memory is never reclaimed.

-

-       If you don't like either of these options, you can define

-       CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything

-       else. And if if you are sure that your program using malloc has

-       no errors or vulnerabilities, you can define INSECURE to 1,

-       which might (or might not) provide a small performance improvement.

-

-  Thread-safety: NOT thread-safe unless USE_LOCKS defined

-       When USE_LOCKS is defined, each public call to malloc, free,

-       etc is surrounded with either a pthread mutex or a win32

-       spinlock (depending on WIN32). This is not especially fast, and

-       can be a major bottleneck.  It is designed only to provide

-       minimal protection in concurrent environments, and to provide a

-       basis for extensions.  If you are using malloc in a concurrent

-       program, consider instead using ptmalloc, which is derived from

-       a version of this malloc. (See http://www.malloc.de).

-

-  System requirements: Any combination of MORECORE and/or MMAP/MUNMAP

-       This malloc can use unix sbrk or any emulation (invoked using

-       the CALL_MORECORE macro) and/or mmap/munmap or any emulation

-       (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system

-       memory.  On most unix systems, it tends to work best if both

-       MORECORE and MMAP are enabled.  On Win32, it uses emulations

-       based on VirtualAlloc. It also uses common C library functions

-       like memset.

-

-  Compliance: I believe it is compliant with the Single Unix Specification

-       (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably

-       others as well.

-

-* Overview of algorithms

-

-  This is not the fastest, most space-conserving, most portable, or

-  most tunable malloc ever written. However it is among the fastest

-  while also being among the most space-conserving, portable and

-  tunable.  Consistent balance across these factors results in a good

-  general-purpose allocator for malloc-intensive programs.

-

-  In most ways, this malloc is a best-fit allocator. Generally, it

-  chooses the best-fitting existing chunk for a request, with ties

-  broken in approximately least-recently-used order. (This strategy

-  normally maintains low fragmentation.) However, for requests less

-  than 256bytes, it deviates from best-fit when there is not an

-  exactly fitting available chunk by preferring to use space adjacent

-  to that used for the previous small request, as well as by breaking

-  ties in approximately most-recently-used order. (These enhance

-  locality of series of small allocations.)  And for very large requests

-  (>= 256Kb by default), it relies on system memory mapping

-  facilities, if supported.  (This helps avoid carrying around and

-  possibly fragmenting memory used only for large chunks.)

-

-  All operations (except malloc_stats and mallinfo) have execution

-  times that are bounded by a constant factor of the number of bits in

-  a size_t, not counting any clearing in calloc or copying in realloc,

-  or actions surrounding MORECORE and MMAP that have times

-  proportional to the number of non-contiguous regions returned by

-  system allocation routines, which is often just 1.

-

-  The implementation is not very modular and seriously overuses

-  macros. Perhaps someday all C compilers will do as good a job

-  inlining modular code as can now be done by brute-force expansion,

-  but now, enough of them seem not to.

-

-  Some compilers issue a lot of warnings about code that is

-  dead/unreachable only on some platforms, and also about intentional

-  uses of negation on unsigned types. All known cases of each can be

-  ignored.

-

-  For a longer but out of date high-level description, see

-     http://gee.cs.oswego.edu/dl/html/malloc.html

-

-* MSPACES

-  If MSPACES is defined, then in addition to malloc, free, etc.,

-  this file also defines mspace_malloc, mspace_free, etc. These

-  are versions of malloc routines that take an "mspace" argument

-  obtained using create_mspace, to control all internal bookkeeping.

-  If ONLY_MSPACES is defined, only these versions are compiled.

-  So if you would like to use this allocator for only some allocations,

-  and your system malloc for others, you can compile with

-  ONLY_MSPACES and then do something like...

-    static mspace mymspace = create_mspace(0,0); // for example

-    #define mymalloc(bytes)  mspace_malloc(mymspace, bytes)

-

-  (Note: If you only need one instance of an mspace, you can instead

-  use "USE_DL_PREFIX" to relabel the global malloc.)

-

-  You can similarly create thread-local allocators by storing

-  mspaces as thread-locals. For example:

-    static __thread mspace tlms = 0;

-    void*  tlmalloc(size_t bytes) {

-      if (tlms == 0) tlms = create_mspace(0, 0);

-      return mspace_malloc(tlms, bytes);

-    }

-    void  tlfree(void* mem) { mspace_free(tlms, mem); }

-

-  Unless FOOTERS is defined, each mspace is completely independent.

-  You cannot allocate from one and free to another (although

-  conformance is only weakly checked, so usage errors are not always

-  caught). If FOOTERS is defined, then each chunk carries around a tag

-  indicating its originating mspace, and frees are directed to their

-  originating spaces.

-

- -------------------------  Compile-time options ---------------------------

-

-Be careful in setting #define values for numerical constants of type

-size_t. On some systems, literal values are not automatically extended

-to size_t precision unless they are explicitly casted.

-

-WIN32                    default: defined if _WIN32 defined

-  Defining WIN32 sets up defaults for MS environment and compilers.

-  Otherwise defaults are for unix.

-

-MALLOC_ALIGNMENT         default: (size_t)8

-  Controls the minimum alignment for malloc'ed chunks.  It must be a

-  power of two and at least 8, even on machines for which smaller

-  alignments would suffice. It may be defined as larger than this

-  though. Note however that code and data structures are optimized for

-  the case of 8-byte alignment.

-

-MSPACES                  default: 0 (false)

-  If true, compile in support for independent allocation spaces.

-  This is only supported if HAVE_MMAP is true.

-

-ONLY_MSPACES             default: 0 (false)

-  If true, only compile in mspace versions, not regular versions.

-

-USE_LOCKS                default: 0 (false)

-  Causes each call to each public routine to be surrounded with

-  pthread or WIN32 mutex lock/unlock. (If set true, this can be

-  overridden on a per-mspace basis for mspace versions.)

-

-FOOTERS                  default: 0

-  If true, provide extra checking and dispatching by placing

-  information in the footers of allocated chunks. This adds

-  space and time overhead.

-

-INSECURE                 default: 0

-  If true, omit checks for usage errors and heap space overwrites.

-

-USE_DL_PREFIX            default: NOT defined

-  Causes compiler to prefix all public routines with the string 'dl'.

-  This can be useful when you only want to use this malloc in one part

-  of a program, using your regular system malloc elsewhere.

-

-ABORT                    default: defined as abort()

-  Defines how to abort on failed checks.  On most systems, a failed

-  check cannot die with an "assert" or even print an informative

-  message, because the underlying print routines in turn call malloc,

-  which will fail again.  Generally, the best policy is to simply call

-  abort(). It's not very useful to do more than this because many

-  errors due to overwriting will show up as address faults (null, odd

-  addresses etc) rather than malloc-triggered checks, so will also

-  abort.  Also, most compilers know that abort() does not return, so

-  can better optimize code conditionally calling it.

-

-PROCEED_ON_ERROR           default: defined as 0 (false)

-  Controls whether detected bad addresses cause them to bypassed

-  rather than aborting. If set, detected bad arguments to free and

-  realloc are ignored. And all bookkeeping information is zeroed out

-  upon a detected overwrite of freed heap space, thus losing the

-  ability to ever return it from malloc again, but enabling the

-  application to proceed. If PROCEED_ON_ERROR is defined, the

-  static variable malloc_corruption_error_count is compiled in

-  and can be examined to see if errors have occurred. This option

-  generates slower code than the default abort policy.

-

-DEBUG                    default: NOT defined

-  The DEBUG setting is mainly intended for people trying to modify

-  this code or diagnose problems when porting to new platforms.

-  However, it may also be able to better isolate user errors than just

-  using runtime checks.  The assertions in the check routines spell

-  out in more detail the assumptions and invariants underlying the

-  algorithms.  The checking is fairly extensive, and will slow down

-  execution noticeably. Calling malloc_stats or mallinfo with DEBUG

-  set will attempt to check every non-mmapped allocated and free chunk

-  in the course of computing the summaries.

-

-ABORT_ON_ASSERT_FAILURE   default: defined as 1 (true)

-  Debugging assertion failures can be nearly impossible if your

-  version of the assert macro causes malloc to be called, which will

-  lead to a cascade of further failures, blowing the runtime stack.

-  ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(),

-  which will usually make debugging easier.

-

-MALLOC_FAILURE_ACTION     default: sets errno to ENOMEM, or no-op on win32

-  The action to take before "return 0" when malloc fails to be able to

-  return memory because there is none available.

-

-HAVE_MORECORE             default: 1 (true) unless win32 or ONLY_MSPACES

-  True if this system supports sbrk or an emulation of it.

-

-MORECORE                  default: sbrk

-  The name of the sbrk-style system routine to call to obtain more

-  memory.  See below for guidance on writing custom MORECORE

-  functions. The type of the argument to sbrk/MORECORE varies across

-  systems.  It cannot be size_t, because it supports negative

-  arguments, so it is normally the signed type of the same width as

-  size_t (sometimes declared as "intptr_t").  It doesn't much matter

-  though. Internally, we only call it with arguments less than half

-  the max value of a size_t, which should work across all reasonable

-  possibilities, although sometimes generating compiler warnings.  See

-  near the end of this file for guidelines for creating a custom

-  version of MORECORE.

-

-MORECORE_CONTIGUOUS       default: 1 (true)

-  If true, take advantage of fact that consecutive calls to MORECORE

-  with positive arguments always return contiguous increasing

-  addresses.  This is true of unix sbrk. It does not hurt too much to

-  set it true anyway, since malloc copes with non-contiguities.

-  Setting it false when definitely non-contiguous saves time

-  and possibly wasted space it would take to discover this though.

-

-MORECORE_CANNOT_TRIM      default: NOT defined

-  True if MORECORE cannot release space back to the system when given

-  negative arguments. This is generally necessary only if you are

-  using a hand-crafted MORECORE function that cannot handle negative

-  arguments.

-

-HAVE_MMAP                 default: 1 (true)

-  True if this system supports mmap or an emulation of it.  If so, and

-  HAVE_MORECORE is not true, MMAP is used for all system

-  allocation. If set and HAVE_MORECORE is true as well, MMAP is

-  primarily used to directly allocate very large blocks. It is also

-  used as a backup strategy in cases where MORECORE fails to provide

-  space from system. Note: A single call to MUNMAP is assumed to be

-  able to unmap memory that may have be allocated using multiple calls

-  to MMAP, so long as they are adjacent.

-

-HAVE_MREMAP               default: 1 on linux, else 0

-  If true realloc() uses mremap() to re-allocate large blocks and

-  extend or shrink allocation spaces.

-

-MMAP_CLEARS               default: 1 on unix

-  True if mmap clears memory so calloc doesn't need to. This is true

-  for standard unix mmap using /dev/zero.

-

-USE_BUILTIN_FFS            default: 0 (i.e., not used)

-  Causes malloc to use the builtin ffs() function to compute indices.

-  Some compilers may recognize and intrinsify ffs to be faster than the

-  supplied C version. Also, the case of x86 using gcc is special-cased

-  to an asm instruction, so is already as fast as it can be, and so

-  this setting has no effect. (On most x86s, the asm version is only

-  slightly faster than the C version.)

-

-malloc_getpagesize         default: derive from system includes, or 4096.

-  The system page size. To the extent possible, this malloc manages

-  memory from the system in page-size units.  This may be (and

-  usually is) a function rather than a constant. This is ignored

-  if WIN32, where page size is determined using getSystemInfo during

-  initialization.

-

-USE_DEV_RANDOM             default: 0 (i.e., not used)

-  Causes malloc to use /dev/random to initialize secure magic seed for

-  stamping footers. Otherwise, the current time is used.

-

-NO_MALLINFO                default: 0

-  If defined, don't compile "mallinfo". This can be a simple way

-  of dealing with mismatches between system declarations and

-  those in this file.

-

-MALLINFO_FIELD_TYPE        default: size_t

-  The type of the fields in the mallinfo struct. This was originally

-  defined as "int" in SVID etc, but is more usefully defined as

-  size_t. The value is used only if  HAVE_USR_INCLUDE_MALLOC_H is not set

-

-REALLOC_ZERO_BYTES_FREES    default: not defined

-  This should be set if a call to realloc with zero bytes should

-  be the same as a call to free. Some people think it should. Otherwise,

-  since this malloc returns a unique pointer for malloc(0), so does

-  realloc(p, 0).

-

-LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H

-LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H,  LACKS_ERRNO_H

-LACKS_STDLIB_H                default: NOT defined unless on WIN32

-  Define these if your system does not have these header files.

-  You might need to manually insert some of the declarations they provide.

-

-DEFAULT_GRANULARITY        default: page size if MORECORE_CONTIGUOUS,

-                                system_info.dwAllocationGranularity in WIN32,

-                                otherwise 64K.

-      Also settable using mallopt(M_GRANULARITY, x)

-  The unit for allocating and deallocating memory from the system.  On

-  most systems with contiguous MORECORE, there is no reason to

-  make this more than a page. However, systems with MMAP tend to

-  either require or encourage larger granularities.  You can increase

-  this value to prevent system allocation functions to be called so

-  often, especially if they are slow.  The value must be at least one

-  page and must be a power of two.  Setting to 0 causes initialization

-  to either page size or win32 region size.  (Note: In previous

-  versions of malloc, the equivalent of this option was called

-  "TOP_PAD")

-

-DEFAULT_TRIM_THRESHOLD    default: 2MB

-      Also settable using mallopt(M_TRIM_THRESHOLD, x)

-  The maximum amount of unused top-most memory to keep before

-  releasing via malloc_trim in free().  Automatic trimming is mainly

-  useful in long-lived programs using contiguous MORECORE.  Because

-  trimming via sbrk can be slow on some systems, and can sometimes be

-  wasteful (in cases where programs immediately afterward allocate

-  more large chunks) the value should be high enough so that your

-  overall system performance would improve by releasing this much

-  memory.  As a rough guide, you might set to a value close to the

-  average size of a process (program) running on your system.

-  Releasing this much memory would allow such a process to run in

-  memory.  Generally, it is worth tuning trim thresholds when a

-  program undergoes phases where several large chunks are allocated

-  and released in ways that can reuse each other's storage, perhaps

-  mixed with phases where there are no such chunks at all. The trim

-  value must be greater than page size to have any useful effect.  To

-  disable trimming completely, you can set to MAX_SIZE_T. Note that the trick

-  some people use of mallocing a huge space and then freeing it at

-  program startup, in an attempt to reserve system memory, doesn't

-  have the intended effect under automatic trimming, since that memory

-  will immediately be returned to the system.

-

-DEFAULT_MMAP_THRESHOLD       default: 256K

-      Also settable using mallopt(M_MMAP_THRESHOLD, x)

-  The request size threshold for using MMAP to directly service a

-  request. Requests of at least this size that cannot be allocated

-  using already-existing space will be serviced via mmap.  (If enough

-  normal freed space already exists it is used instead.)  Using mmap

-  segregates relatively large chunks of memory so that they can be

-  individually obtained and released from the host system. A request

-  serviced through mmap is never reused by any other request (at least

-  not directly; the system may just so happen to remap successive

-  requests to the same locations).  Segregating space in this way has

-  the benefits that: Mmapped space can always be individually released

-  back to the system, which helps keep the system level memory demands

-  of a long-lived program low.  Also, mapped memory doesn't become

-  `locked' between other chunks, as can happen with normally allocated

-  chunks, which means that even trimming via malloc_trim would not

-  release them.  However, it has the disadvantage that the space

-  cannot be reclaimed, consolidated, and then used to service later

-  requests, as happens with normal chunks.  The advantages of mmap

-  nearly always outweigh disadvantages for "large" chunks, but the

-  value of "large" may vary across systems.  The default is an

-  empirically derived value that works well in most systems. You can

-  disable mmap by setting to MAX_SIZE_T.

-

-*/

-#if defined(__WATCOMC__) || defined(_MSC_VER)

-#define WIN32 1

-#endif

-

-#ifndef WIN32

-#ifdef _WIN32

-#define WIN32 1

-#endif  /* _WIN32 */

-#endif  /* WIN32 */

-#ifdef WIN32

-#define WIN32_LEAN_AND_MEAN

-#include <windows.h>

-#define HAVE_MORECORE 0

-#define LACKS_UNISTD_H

-#define LACKS_SYS_PARAM_H

-#define LACKS_SYS_MMAN_H

-#define LACKS_STRING_H

-#define LACKS_STRINGS_H

-#define LACKS_SYS_TYPES_H

-#define LACKS_ERRNO_H

-#define MALLOC_FAILURE_ACTION

-#define MMAP_CLEARS 0 /* WINCE and some others apparently don't clear */

-#endif  /* WIN32 */

-

-#if defined(DARWIN) || defined(_DARWIN)

-/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */

-#ifndef HAVE_MORECORE

-#define HAVE_MORECORE 0

-#define HAVE_MMAP 1

-#endif  /* HAVE_MORECORE */

-#endif  /* DARWIN */

-

-#ifndef LACKS_SYS_TYPES_H

-#include <sys/types.h>  /* For size_t */

-#endif  /* LACKS_SYS_TYPES_H */

-

-/* The maximum possible size_t value has all bits set */

-#define MAX_SIZE_T           (~(size_t)0)

-

-#ifndef ONLY_MSPACES

-#define ONLY_MSPACES 0

-#endif  /* ONLY_MSPACES */

-#ifndef MSPACES

-#if ONLY_MSPACES

-#define MSPACES 1

-#else   /* ONLY_MSPACES */

-#define MSPACES 0

-#endif  /* ONLY_MSPACES */

-#endif  /* MSPACES */

-#ifndef MALLOC_ALIGNMENT

-#define MALLOC_ALIGNMENT ((size_t)8U)

-#endif  /* MALLOC_ALIGNMENT */

-#ifndef FOOTERS

-#define FOOTERS 0

-#endif  /* FOOTERS */

-#ifndef ABORT

-#define ABORT  abort()

-#endif  /* ABORT */

-#ifndef ABORT_ON_ASSERT_FAILURE

-#define ABORT_ON_ASSERT_FAILURE 1

-#endif  /* ABORT_ON_ASSERT_FAILURE */

-#ifndef PROCEED_ON_ERROR

-#define PROCEED_ON_ERROR 0

-#endif  /* PROCEED_ON_ERROR */

-#ifndef USE_LOCKS

-#define USE_LOCKS 0

-#endif  /* USE_LOCKS */

-#ifndef INSECURE

-#define INSECURE 0

-#endif  /* INSECURE */

-#ifndef HAVE_MMAP

-#define HAVE_MMAP 1

-#endif  /* HAVE_MMAP */

-#ifndef MMAP_CLEARS

-#define MMAP_CLEARS 1

-#endif  /* MMAP_CLEARS */

-#ifndef HAVE_MREMAP

-#ifdef linux

-#define HAVE_MREMAP 1

-#else   /* linux */

-#define HAVE_MREMAP 0

-#endif  /* linux */

-#endif  /* HAVE_MREMAP */

-#ifndef MALLOC_FAILURE_ACTION

-#define MALLOC_FAILURE_ACTION  errno = ENOMEM;

-#endif  /* MALLOC_FAILURE_ACTION */

-#ifndef HAVE_MORECORE

-#if ONLY_MSPACES

-#define HAVE_MORECORE 0

-#else   /* ONLY_MSPACES */

-#define HAVE_MORECORE 1

-#endif  /* ONLY_MSPACES */

-#endif  /* HAVE_MORECORE */

-#if !HAVE_MORECORE

-#define MORECORE_CONTIGUOUS 0

-#else   /* !HAVE_MORECORE */

-#ifndef MORECORE

-#define MORECORE sbrk

-#endif  /* MORECORE */

-#ifndef MORECORE_CONTIGUOUS

-#define MORECORE_CONTIGUOUS 1

-#endif  /* MORECORE_CONTIGUOUS */

-#endif  /* HAVE_MORECORE */

-#ifndef DEFAULT_GRANULARITY

-#if MORECORE_CONTIGUOUS

-#define DEFAULT_GRANULARITY (0)  /* 0 means to compute in init_mparams */

-#else   /* MORECORE_CONTIGUOUS */

-#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U)

-#endif  /* MORECORE_CONTIGUOUS */

-#endif  /* DEFAULT_GRANULARITY */

-#ifndef DEFAULT_TRIM_THRESHOLD

-#ifndef MORECORE_CANNOT_TRIM

-#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U)

-#else   /* MORECORE_CANNOT_TRIM */

-#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T

-#endif  /* MORECORE_CANNOT_TRIM */

-#endif  /* DEFAULT_TRIM_THRESHOLD */

-#ifndef DEFAULT_MMAP_THRESHOLD

-#if HAVE_MMAP

-#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U)

-#else   /* HAVE_MMAP */

-#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T

-#endif  /* HAVE_MMAP */

-#endif  /* DEFAULT_MMAP_THRESHOLD */

-#ifndef USE_BUILTIN_FFS

-#define USE_BUILTIN_FFS 0

-#endif  /* USE_BUILTIN_FFS */

-#ifndef USE_DEV_RANDOM

-#define USE_DEV_RANDOM 0

-#endif  /* USE_DEV_RANDOM */

-#ifndef NO_MALLINFO

-#define NO_MALLINFO 0

-#endif  /* NO_MALLINFO */

-#ifndef MALLINFO_FIELD_TYPE

-#define MALLINFO_FIELD_TYPE size_t

-#endif  /* MALLINFO_FIELD_TYPE */

-

-/*

-  mallopt tuning options.  SVID/XPG defines four standard parameter

-  numbers for mallopt, normally defined in malloc.h.  None of these

-  are used in this malloc, so setting them has no effect. But this

-  malloc does support the following options.

-*/

-

-#define M_TRIM_THRESHOLD     (-1)

-#define M_GRANULARITY        (-2)

-#define M_MMAP_THRESHOLD     (-3)

-

-/* ------------------------ Mallinfo declarations ------------------------ */

-

-#if !NO_MALLINFO

-/*

-  This version of malloc supports the standard SVID/XPG mallinfo

-  routine that returns a struct containing usage properties and

-  statistics. It should work on any system that has a

-  /usr/include/malloc.h defining struct mallinfo.  The main

-  declaration needed is the mallinfo struct that is returned (by-copy)

-  by mallinfo().  The malloinfo struct contains a bunch of fields that

-  are not even meaningful in this version of malloc.  These fields are

-  are instead filled by mallinfo() with other numbers that might be of

-  interest.

-

-  HAVE_USR_INCLUDE_MALLOC_H should be set if you have a

-  /usr/include/malloc.h file that includes a declaration of struct

-  mallinfo.  If so, it is included; else a compliant version is

-  declared below.  These must be precisely the same for mallinfo() to

-  work.  The original SVID version of this struct, defined on most

-  systems with mallinfo, declares all fields as ints. But some others

-  define as unsigned long. If your system defines the fields using a

-  type of different width than listed here, you MUST #include your

-  system version and #define HAVE_USR_INCLUDE_MALLOC_H.

-*/

-

-/* #define HAVE_USR_INCLUDE_MALLOC_H */

-

-#ifdef HAVE_USR_INCLUDE_MALLOC_H

-#include "/usr/include/malloc.h"

-#else /* HAVE_USR_INCLUDE_MALLOC_H */

-

-struct mallinfo {

-  MALLINFO_FIELD_TYPE arena;    /* non-mmapped space allocated from system */

-  MALLINFO_FIELD_TYPE ordblks;  /* number of free chunks */

-  MALLINFO_FIELD_TYPE smblks;   /* always 0 */

-  MALLINFO_FIELD_TYPE hblks;    /* always 0 */

-  MALLINFO_FIELD_TYPE hblkhd;   /* space in mmapped regions */

-  MALLINFO_FIELD_TYPE usmblks;  /* maximum total allocated space */

-  MALLINFO_FIELD_TYPE fsmblks;  /* always 0 */

-  MALLINFO_FIELD_TYPE uordblks; /* total allocated space */

-  MALLINFO_FIELD_TYPE fordblks; /* total free space */

-  MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */

-};

-

-#endif /* HAVE_USR_INCLUDE_MALLOC_H */

-#endif /* NO_MALLINFO */

-

-#ifdef __cplusplus

-extern "C" {

-#endif /* __cplusplus */

-

-#if !ONLY_MSPACES

-

-/* ------------------- Declarations of public routines ------------------- */

-

-#ifndef USE_DL_PREFIX

-#define dlcalloc               calloc

-#define dlfree                 free

-#define dlmalloc               malloc

-#define dlmemalign             memalign

-#define dlrealloc              realloc

-#define dlvalloc               valloc

-#define dlpvalloc              pvalloc

-#define dlmallinfo             mallinfo

-#define dlmallopt              mallopt

-#define dlmalloc_trim          malloc_trim

-#define dlmalloc_stats         malloc_stats

-#define dlmalloc_usable_size   malloc_usable_size

-#define dlmalloc_footprint     malloc_footprint

-#define dlmalloc_max_footprint malloc_max_footprint

-#define dlindependent_calloc   independent_calloc

-#define dlindependent_comalloc independent_comalloc

-#endif /* USE_DL_PREFIX */

-

-

-/*

-  malloc(size_t n)

-  Returns a pointer to a newly allocated chunk of at least n bytes, or

-  null if no space is available, in which case errno is set to ENOMEM

-  on ANSI C systems.

-

-  If n is zero, malloc returns a minimum-sized chunk. (The minimum

-  size is 16 bytes on most 32bit systems, and 32 bytes on 64bit

-  systems.)  Note that size_t is an unsigned type, so calls with

-  arguments that would be negative if signed are interpreted as

-  requests for huge amounts of space, which will often fail. The

-  maximum supported value of n differs across systems, but is in all

-  cases less than the maximum representable value of a size_t.

-*/

-void* dlmalloc(size_t);

-

-/*

-  free(void* p)

-  Releases the chunk of memory pointed to by p, that had been previously

-  allocated using malloc or a related routine such as realloc.

-  It has no effect if p is null. If p was not malloced or already

-  freed, free(p) will by default cause the current program to abort.

-*/

-void  dlfree(void*);

-

-/*

-  calloc(size_t n_elements, size_t element_size);

-  Returns a pointer to n_elements * element_size bytes, with all locations

-  set to zero.

-*/

-void* dlcalloc(size_t, size_t);

-

-/*

-  realloc(void* p, size_t n)

-  Returns a pointer to a chunk of size n that contains the same data

-  as does chunk p up to the minimum of (n, p's size) bytes, or null

-  if no space is available.

-

-  The returned pointer may or may not be the same as p. The algorithm

-  prefers extending p in most cases when possible, otherwise it

-  employs the equivalent of a malloc-copy-free sequence.

-

-  If p is null, realloc is equivalent to malloc.

-

-  If space is not available, realloc returns null, errno is set (if on

-  ANSI) and p is NOT freed.

-

-  if n is for fewer bytes than already held by p, the newly unused

-  space is lopped off and freed if possible.  realloc with a size

-  argument of zero (re)allocates a minimum-sized chunk.

-

-  The old unix realloc convention of allowing the last-free'd chunk

-  to be used as an argument to realloc is not supported.

-*/

-

-void* dlrealloc(void*, size_t);

-

-/*

-  memalign(size_t alignment, size_t n);

-  Returns a pointer to a newly allocated chunk of n bytes, aligned

-  in accord with the alignment argument.

-

-  The alignment argument should be a power of two. If the argument is

-  not a power of two, the nearest greater power is used.

-  8-byte alignment is guaranteed by normal malloc calls, so don't

-  bother calling memalign with an argument of 8 or less.

-

-  Overreliance on memalign is a sure way to fragment space.

-*/

-void* dlmemalign(size_t, size_t);

-

-/*

-  valloc(size_t n);

-  Equivalent to memalign(pagesize, n), where pagesize is the page

-  size of the system. If the pagesize is unknown, 4096 is used.

-*/

-void* dlvalloc(size_t);

-

-/*

-  mallopt(int parameter_number, int parameter_value)

-  Sets tunable parameters The format is to provide a

-  (parameter-number, parameter-value) pair.  mallopt then sets the

-  corresponding parameter to the argument value if it can (i.e., so

-  long as the value is meaningful), and returns 1 if successful else

-  0.  SVID/XPG/ANSI defines four standard param numbers for mallopt,

-  normally defined in malloc.h.  None of these are use in this malloc,

-  so setting them has no effect. But this malloc also supports other

-  options in mallopt. See below for details.  Briefly, supported

-  parameters are as follows (listed defaults are for "typical"

-  configurations).

-

-  Symbol            param #  default    allowed param values

-  M_TRIM_THRESHOLD     -1   2*1024*1024   any   (MAX_SIZE_T disables)

-  M_GRANULARITY        -2     page size   any power of 2 >= page size

-  M_MMAP_THRESHOLD     -3      256*1024   any   (or 0 if no MMAP support)

-*/

-int dlmallopt(int, int);

-

-/*

-  malloc_footprint();

-  Returns the number of bytes obtained from the system.  The total

-  number of bytes allocated by malloc, realloc etc., is less than this

-  value. Unlike mallinfo, this function returns only a precomputed

-  result, so can be called frequently to monitor memory consumption.

-  Even if locks are otherwise defined, this function does not use them,

-  so results might not be up to date.

-*/

-size_t dlmalloc_footprint(void);

-

-/*

-  malloc_max_footprint();

-  Returns the maximum number of bytes obtained from the system. This

-  value will be greater than current footprint if deallocated space

-  has been reclaimed by the system. The peak number of bytes allocated

-  by malloc, realloc etc., is less than this value. Unlike mallinfo,

-  this function returns only a precomputed result, so can be called

-  frequently to monitor memory consumption.  Even if locks are

-  otherwise defined, this function does not use them, so results might

-  not be up to date.

-*/

-size_t dlmalloc_max_footprint(void);

-

-#if !NO_MALLINFO

-/*

-  mallinfo()

-  Returns (by copy) a struct containing various summary statistics:

-

-  arena:     current total non-mmapped bytes allocated from system

-  ordblks:   the number of free chunks

-  smblks:    always zero.

-  hblks:     current number of mmapped regions

-  hblkhd:    total bytes held in mmapped regions

-  usmblks:   the maximum total allocated space. This will be greater

-                than current total if trimming has occurred.

-  fsmblks:   always zero

-  uordblks:  current total allocated space (normal or mmapped)

-  fordblks:  total free space

-  keepcost:  the maximum number of bytes that could ideally be released

-               back to system via malloc_trim. ("ideally" means that

-               it ignores page restrictions etc.)

-

-  Because these fields are ints, but internal bookkeeping may

-  be kept as longs, the reported values may wrap around zero and

-  thus be inaccurate.

-*/

-struct mallinfo dlmallinfo(void);

-#endif /* NO_MALLINFO */

-

-/*

-  independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);

-

-  independent_calloc is similar to calloc, but instead of returning a

-  single cleared space, it returns an array of pointers to n_elements

-  independent elements that can hold contents of size elem_size, each

-  of which starts out cleared, and can be independently freed,

-  realloc'ed etc. The elements are guaranteed to be adjacently

-  allocated (this is not guaranteed to occur with multiple callocs or

-  mallocs), which may also improve cache locality in some

-  applications.

-

-  The "chunks" argument is optional (i.e., may be null, which is

-  probably the most typical usage). If it is null, the returned array

-  is itself dynamically allocated and should also be freed when it is

-  no longer needed. Otherwise, the chunks array must be of at least

-  n_elements in length. It is filled in with the pointers to the

-  chunks.

-

-  In either case, independent_calloc returns this pointer array, or

-  null if the allocation failed.  If n_elements is zero and "chunks"

-  is null, it returns a chunk representing an array with zero elements

-  (which should be freed if not wanted).

-

-  Each element must be individually freed when it is no longer

-  needed. If you'd like to instead be able to free all at once, you

-  should instead use regular calloc and assign pointers into this

-  space to represent elements.  (In this case though, you cannot

-  independently free elements.)

-

-  independent_calloc simplifies and speeds up implementations of many

-  kinds of pools.  It may also be useful when constructing large data

-  structures that initially have a fixed number of fixed-sized nodes,

-  but the number is not known at compile time, and some of the nodes

-  may later need to be freed. For example:

-

-  struct Node { int item; struct Node* next; };

-

-  struct Node* build_list() {

-    struct Node** pool;

-    int n = read_number_of_nodes_needed();

-    if (n <= 0) return 0;

-    pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);

-    if (pool == 0) die();

-    // organize into a linked list...

-    struct Node* first = pool[0];

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

-      pool[i]->next = pool[i+1];

-    free(pool);     // Can now free the array (or not, if it is needed later)

-    return first;

-  }

-*/

-void** dlindependent_calloc(size_t, size_t, void**);

-

-/*

-  independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);

-

-  independent_comalloc allocates, all at once, a set of n_elements

-  chunks with sizes indicated in the "sizes" array.    It returns

-  an array of pointers to these elements, each of which can be

-  independently freed, realloc'ed etc. The elements are guaranteed to

-  be adjacently allocated (this is not guaranteed to occur with

-  multiple callocs or mallocs), which may also improve cache locality

-  in some applications.

-

-  The "chunks" argument is optional (i.e., may be null). If it is null

-  the returned array is itself dynamically allocated and should also

-  be freed when it is no longer needed. Otherwise, the chunks array

-  must be of at least n_elements in length. It is filled in with the

-  pointers to the chunks.

-

-  In either case, independent_comalloc returns this pointer array, or

-  null if the allocation failed.  If n_elements is zero and chunks is

-  null, it returns a chunk representing an array with zero elements

-  (which should be freed if not wanted).

-

-  Each element must be individually freed when it is no longer

-  needed. If you'd like to instead be able to free all at once, you

-  should instead use a single regular malloc, and assign pointers at

-  particular offsets in the aggregate space. (In this case though, you

-  cannot independently free elements.)

-

-  independent_comallac differs from independent_calloc in that each

-  element may have a different size, and also that it does not

-  automatically clear elements.

-

-  independent_comalloc can be used to speed up allocation in cases

-  where several structs or objects must always be allocated at the

-  same time.  For example:

-

-  struct Head { ... }

-  struct Foot { ... }

-

-  void send_message(char* msg) {

-    int msglen = strlen(msg);

-    size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };

-    void* chunks[3];

-    if (independent_comalloc(3, sizes, chunks) == 0)

-      die();

-    struct Head* head = (struct Head*)(chunks[0]);

-    char*        body = (char*)(chunks[1]);

-    struct Foot* foot = (struct Foot*)(chunks[2]);

-    // ...

-  }

-

-  In general though, independent_comalloc is worth using only for

-  larger values of n_elements. For small values, you probably won't

-  detect enough difference from series of malloc calls to bother.

-

-  Overuse of independent_comalloc can increase overall memory usage,

-  since it cannot reuse existing noncontiguous small chunks that

-  might be available for some of the elements.

-*/

-void** dlindependent_comalloc(size_t, size_t*, void**);

-

-

-/*

-  pvalloc(size_t n);

-  Equivalent to valloc(minimum-page-that-holds(n)), that is,

-  round up n to nearest pagesize.

- */

-void*  dlpvalloc(size_t);

-

-/*

-  malloc_trim(size_t pad);

-

-  If possible, gives memory back to the system (via negative arguments

-  to sbrk) if there is unused memory at the `high' end of the malloc

-  pool or in unused MMAP segments. You can call this after freeing

-  large blocks of memory to potentially reduce the system-level memory

-  requirements of a program. However, it cannot guarantee to reduce

-  memory. Under some allocation patterns, some large free blocks of

-  memory will be locked between two used chunks, so they cannot be

-  given back to the system.

-

-  The `pad' argument to malloc_trim represents the amount of free

-  trailing space to leave untrimmed. If this argument is zero, only

-  the minimum amount of memory to maintain internal data structures

-  will be left. Non-zero arguments can be supplied to maintain enough

-  trailing space to service future expected allocations without having

-  to re-obtain memory from the system.

-

-  Malloc_trim returns 1 if it actually released any memory, else 0.

-*/

-int  dlmalloc_trim(size_t);

-

-/*

-  malloc_usable_size(void* p);

-

-  Returns the number of bytes you can actually use in

-  an allocated chunk, which may be more than you requested (although

-  often not) due to alignment and minimum size constraints.

-  You can use this many bytes without worrying about

-  overwriting other allocated objects. This is not a particularly great

-  programming practice. malloc_usable_size can be more useful in

-  debugging and assertions, for example:

-

-  p = malloc(n);

-  assert(malloc_usable_size(p) >= 256);

-*/

-size_t dlmalloc_usable_size(void*);

-

-/*

-  malloc_stats();

-  Prints on stderr the amount of space obtained from the system (both

-  via sbrk and mmap), the maximum amount (which may be more than

-  current if malloc_trim and/or munmap got called), and the current

-  number of bytes allocated via malloc (or realloc, etc) but not yet

-  freed. Note that this is the number of bytes allocated, not the

-  number requested. It will be larger than the number requested

-  because of alignment and bookkeeping overhead. Because it includes

-  alignment wastage as being in use, this figure may be greater than

-  zero even when no user-level chunks are allocated.

-

-  The reported current and maximum system memory can be inaccurate if

-  a program makes other calls to system memory allocation functions

-  (normally sbrk) outside of malloc.

-

-  malloc_stats prints only the most commonly interesting statistics.

-  More information can be obtained by calling mallinfo.

-*/

-void  dlmalloc_stats(void);

-

-#endif /* ONLY_MSPACES */

-

-#if MSPACES

-

-/*

-  mspace is an opaque type representing an independent

-  region of space that supports mspace_malloc, etc.

-*/

-typedef void* mspace;

-

-/*

-  create_mspace creates and returns a new independent space with the

-  given initial capacity, or, if 0, the default granularity size.  It

-  returns null if there is no system memory available to create the

-  space.  If argument locked is non-zero, the space uses a separate

-  lock to control access. The capacity of the space will grow

-  dynamically as needed to service mspace_malloc requests.  You can

-  control the sizes of incremental increases of this space by

-  compiling with a different DEFAULT_GRANULARITY or dynamically

-  setting with mallopt(M_GRANULARITY, value).

-*/

-mspace create_mspace(size_t capacity, int locked);

-

-/*

-  destroy_mspace destroys the given space, and attempts to return all

-  of its memory back to the system, returning the total number of

-  bytes freed. After destruction, the results of access to all memory

-  used by the space become undefined.

-*/

-size_t destroy_mspace(mspace msp);

-

-/*

-  create_mspace_with_base uses the memory supplied as the initial base

-  of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this

-  space is used for bookkeeping, so the capacity must be at least this

-  large. (Otherwise 0 is returned.) When this initial space is

-  exhausted, additional memory will be obtained from the system.

-  Destroying this space will deallocate all additionally allocated

-  space (if possible) but not the initial base.

-*/

-mspace create_mspace_with_base(void* base, size_t capacity, int locked);

-

-/*

-  mspace_malloc behaves as malloc, but operates within

-  the given space.

-*/

-void* mspace_malloc(mspace msp, size_t bytes);

-

-/*

-  mspace_free behaves as free, but operates within

-  the given space.

-

-  If compiled with FOOTERS==1, mspace_free is not actually needed.

-  free may be called instead of mspace_free because freed chunks from

-  any space are handled by their originating spaces.

-*/

-void mspace_free(mspace msp, void* mem);

-

-/*

-  mspace_realloc behaves as realloc, but operates within

-  the given space.

-

-  If compiled with FOOTERS==1, mspace_realloc is not actually

-  needed.  realloc may be called instead of mspace_realloc because

-  realloced chunks from any space are handled by their originating

-  spaces.

-*/

-void* mspace_realloc(mspace msp, void* mem, size_t newsize);

-

-/*

-  mspace_calloc behaves as calloc, but operates within

-  the given space.

-*/

-void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);

-

-/*

-  mspace_memalign behaves as memalign, but operates within

-  the given space.

-*/

-void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);

-

-/*

-  mspace_independent_calloc behaves as independent_calloc, but

-  operates within the given space.

-*/

-void** mspace_independent_calloc(mspace msp, size_t n_elements,

-                                 size_t elem_size, void* chunks[]);

-

-/*

-  mspace_independent_comalloc behaves as independent_comalloc, but

-  operates within the given space.

-*/

-void** mspace_independent_comalloc(mspace msp, size_t n_elements,

-                                   size_t sizes[], void* chunks[]);

-

-/*

-  mspace_footprint() returns the number of bytes obtained from the

-  system for this space.

-*/

-size_t mspace_footprint(mspace msp);

-

-/*

-  mspace_max_footprint() returns the peak number of bytes obtained from the

-  system for this space.

-*/

-size_t mspace_max_footprint(mspace msp);

-

-

-#if !NO_MALLINFO

-/*

-  mspace_mallinfo behaves as mallinfo, but reports properties of

-  the given space.

-*/

-struct mallinfo mspace_mallinfo(mspace msp);

-#endif /* NO_MALLINFO */

-

-/*

-  mspace_malloc_stats behaves as malloc_stats, but reports

-  properties of the given space.

-*/

-void mspace_malloc_stats(mspace msp);

-

-/*

-  mspace_trim behaves as malloc_trim, but

-  operates within the given space.

-*/

-int mspace_trim(mspace msp, size_t pad);

-

-/*

-  An alias for mallopt.

-*/

-int mspace_mallopt(int, int);

-

-#endif /* MSPACES */

-

-#ifdef __cplusplus

-};  /* end of extern "C" */

-#endif /* __cplusplus */

-

-/*

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

-  To make a fully customizable malloc.h header file, cut everything

-  above this line, put into file malloc.h, edit to suit, and #include it

-  on the next line, as well as in programs that use this malloc.

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

-*/

-

-/* #include "malloc.h" */

-

-/*------------------------------ internal #includes ---------------------- */

-

-#ifdef WIN32

-#pragma warning( disable : 4146 ) /* no "unsigned" warnings */

-#endif /* WIN32 */

-

-#include <stdio.h>       /* for printing in malloc_stats */

-

-#ifndef LACKS_ERRNO_H

-#include <errno.h>       /* for MALLOC_FAILURE_ACTION */

-#endif /* LACKS_ERRNO_H */

-#if FOOTERS

-#include <time.h>        /* for magic initialization */

-#endif /* FOOTERS */

-#ifndef LACKS_STDLIB_H

-#include <stdlib.h>      /* for abort() */

-#endif /* LACKS_STDLIB_H */

-#ifdef DEBUG

-#if ABORT_ON_ASSERT_FAILURE

-#define assert(x) if(!(x)) ABORT

-#else /* ABORT_ON_ASSERT_FAILURE */

-#include <assert.h>

-#endif /* ABORT_ON_ASSERT_FAILURE */

-#else  /* DEBUG */

-#define assert(x)

-#endif /* DEBUG */

-#ifndef LACKS_STRING_H

-#include <string.h>      /* for memset etc */

-#endif  /* LACKS_STRING_H */

-#if USE_BUILTIN_FFS

-#ifndef LACKS_STRINGS_H

-#include <strings.h>     /* for ffs */

-#endif /* LACKS_STRINGS_H */

-#endif /* USE_BUILTIN_FFS */

-#if HAVE_MMAP

-#ifndef LACKS_SYS_MMAN_H

-#include <sys/mman.h>    /* for mmap */

-#endif /* LACKS_SYS_MMAN_H */

-#ifndef LACKS_FCNTL_H

-#include <fcntl.h>

-#endif /* LACKS_FCNTL_H */

-#endif /* HAVE_MMAP */

-#if HAVE_MORECORE

-#ifndef LACKS_UNISTD_H

-#include <unistd.h>     /* for sbrk */

-#else /* LACKS_UNISTD_H */

-#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)

-extern void*     sbrk(ptrdiff_t);

-#endif /* FreeBSD etc */

-#endif /* LACKS_UNISTD_H */

-#endif /* HAVE_MMAP */

-

-#ifndef WIN32

-#ifndef malloc_getpagesize

-#  ifdef _SC_PAGESIZE         /* some SVR4 systems omit an underscore */

-#    ifndef _SC_PAGE_SIZE

-#      define _SC_PAGE_SIZE _SC_PAGESIZE

-#    endif

-#  endif

-#  ifdef _SC_PAGE_SIZE

-#    define malloc_getpagesize sysconf(_SC_PAGE_SIZE)

-#  else

-#    if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)

-       extern size_t getpagesize();

-#      define malloc_getpagesize getpagesize()

-#    else

-#      ifdef WIN32 /* use supplied emulation of getpagesize */

-#        define malloc_getpagesize getpagesize()

-#      else

-#        ifndef LACKS_SYS_PARAM_H

-#          include <sys/param.h>

-#        endif

-#        ifdef EXEC_PAGESIZE

-#          define malloc_getpagesize EXEC_PAGESIZE

-#        else

-#          ifdef NBPG

-#            ifndef CLSIZE

-#              define malloc_getpagesize NBPG

-#            else

-#              define malloc_getpagesize (NBPG * CLSIZE)

-#            endif

-#          else

-#            ifdef NBPC

-#              define malloc_getpagesize NBPC

-#            else

-#              ifdef PAGESIZE

-#                define malloc_getpagesize PAGESIZE

-#              else /* just guess */

-#                define malloc_getpagesize ((size_t)4096U)

-#              endif

-#            endif

-#          endif

-#        endif

-#      endif

-#    endif

-#  endif

-#endif

-#endif

-

-/* ------------------- size_t and alignment properties -------------------- */

-

-/* The byte and bit size of a size_t */

-#define SIZE_T_SIZE         (sizeof(size_t))

-#define SIZE_T_BITSIZE      (sizeof(size_t) << 3)

-

-/* Some constants coerced to size_t */

-/* Annoying but necessary to avoid errors on some plaftorms */

-#define SIZE_T_ZERO         ((size_t)0)

-#define SIZE_T_ONE          ((size_t)1)

-#define SIZE_T_TWO          ((size_t)2)

-#define TWO_SIZE_T_SIZES    (SIZE_T_SIZE<<1)

-#define FOUR_SIZE_T_SIZES   (SIZE_T_SIZE<<2)

-#define SIX_SIZE_T_SIZES    (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES)

-#define HALF_MAX_SIZE_T     (MAX_SIZE_T / 2U)

-

-/* The bit mask value corresponding to MALLOC_ALIGNMENT */

-#define CHUNK_ALIGN_MASK    (MALLOC_ALIGNMENT - SIZE_T_ONE)

-

-/* True if address a has acceptable alignment */

-#define is_aligned(A)       (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0)

-

-/* the number of bytes to offset an address to align it */

-#define align_offset(A)\

- ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\

-  ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK))

-

-/* -------------------------- MMAP preliminaries ------------------------- */

-

-/*

-   If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and

-   checks to fail so compiler optimizer can delete code rather than

-   using so many "#if"s.

-*/

-

-

-/* MORECORE and MMAP must return MFAIL on failure */

-#define MFAIL                ((void*)(MAX_SIZE_T))

-#define CMFAIL               ((char*)(MFAIL)) /* defined for convenience */

-

-#if !HAVE_MMAP

-#define IS_MMAPPED_BIT       (SIZE_T_ZERO)

-#define USE_MMAP_BIT         (SIZE_T_ZERO)

-#define CALL_MMAP(s)         MFAIL

-#define CALL_MUNMAP(a, s)    (-1)

-#define DIRECT_MMAP(s)       MFAIL

-

-#else /* HAVE_MMAP */

-#define IS_MMAPPED_BIT       (SIZE_T_ONE)

-#define USE_MMAP_BIT         (SIZE_T_ONE)

-

-#ifndef WIN32

-#define CALL_MUNMAP(a, s)    munmap((a), (s))

-#define MMAP_PROT            (PROT_READ|PROT_WRITE)

-#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)

-#define MAP_ANONYMOUS        MAP_ANON

-#endif /* MAP_ANON */

-#ifdef MAP_ANONYMOUS

-#define MMAP_FLAGS           (MAP_PRIVATE|MAP_ANONYMOUS)

-#define CALL_MMAP(s)         mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0)

-#else /* MAP_ANONYMOUS */

-/*

-   Nearly all versions of mmap support MAP_ANONYMOUS, so the following

-   is unlikely to be needed, but is supplied just in case.

-*/

-#define MMAP_FLAGS           (MAP_PRIVATE)

-static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */

-#define CALL_MMAP(s) ((dev_zero_fd < 0) ? \

-           (dev_zero_fd = open("/dev/zero", O_RDWR), \

-            mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \

-            mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0))

-#endif /* MAP_ANONYMOUS */

-

-#define DIRECT_MMAP(s)       CALL_MMAP(s)

-#else /* WIN32 */

-

-/* Win32 MMAP via VirtualAlloc */

-static void* win32mmap(size_t size) {

-  void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);

-  return (ptr != 0)? ptr: MFAIL;

-}

-

-/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */

-static void* win32direct_mmap(size_t size) {

-  void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN,

-                           PAGE_READWRITE);

-  return (ptr != 0)? ptr: MFAIL;

-}

-

-/* This function supports releasing coalesed segments */

-static int win32munmap(void* ptr, size_t size) {

-  MEMORY_BASIC_INFORMATION minfo;

-  char* cptr = ptr;

-  while (size) {

-    if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0)

-      return -1;

-    if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr ||

-        minfo.State != MEM_COMMIT || minfo.RegionSize > size)

-      return -1;

-    if (VirtualFree(cptr, 0, MEM_RELEASE) == 0)

-      return -1;

-    cptr += minfo.RegionSize;

-    size -= minfo.RegionSize;

-  }

-  return 0;

-}

-

-#define CALL_MMAP(s)         win32mmap(s)

-#define CALL_MUNMAP(a, s)    win32munmap((a), (s))

-#define DIRECT_MMAP(s)       win32direct_mmap(s)

-#endif /* WIN32 */

-#endif /* HAVE_MMAP */

-

-#if HAVE_MMAP && HAVE_MREMAP

-#define CALL_MREMAP(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv))

-#else  /* HAVE_MMAP && HAVE_MREMAP */

-#define CALL_MREMAP(addr, osz, nsz, mv) MFAIL

-#endif /* HAVE_MMAP && HAVE_MREMAP */

-

-#if HAVE_MORECORE

-#define CALL_MORECORE(S)     MORECORE(S)

-#else  /* HAVE_MORECORE */

-#define CALL_MORECORE(S)     MFAIL

-#endif /* HAVE_MORECORE */

-

-/* mstate bit set if continguous morecore disabled or failed */

-#define USE_NONCONTIGUOUS_BIT (4U)

-

-/* segment bit set in create_mspace_with_base */

-#define EXTERN_BIT            (8U)

-

-

-/* --------------------------- Lock preliminaries ------------------------ */

-

-#if USE_LOCKS

-

-/*

-  When locks are defined, there are up to two global locks:

-

-  * If HAVE_MORECORE, morecore_mutex protects sequences of calls to

-    MORECORE.  In many cases sys_alloc requires two calls, that should

-    not be interleaved with calls by other threads.  This does not

-    protect against direct calls to MORECORE by other threads not

-    using this lock, so there is still code to cope the best we can on

-    interference.

-

-  * magic_init_mutex ensures that mparams.magic and other

-    unique mparams values are initialized only once.

-*/

-

-#ifndef WIN32

-/* By default use posix locks */

-#include <pthread.h>

-#define MLOCK_T pthread_mutex_t

-#define INITIAL_LOCK(l)      pthread_mutex_init(l, NULL)

-#define ACQUIRE_LOCK(l)      pthread_mutex_lock(l)

-#define RELEASE_LOCK(l)      pthread_mutex_unlock(l)

-

-#if HAVE_MORECORE

-static MLOCK_T morecore_mutex = PTHREAD_MUTEX_INITIALIZER;

-#endif /* HAVE_MORECORE */

-

-static MLOCK_T magic_init_mutex = PTHREAD_MUTEX_INITIALIZER;

-

-#else /* WIN32 */

-/*

-   Because lock-protected regions have bounded times, and there

-   are no recursive lock calls, we can use simple spinlocks.

-*/

-

-#define MLOCK_T long

-static int win32_acquire_lock (MLOCK_T *sl) {

-  for (;;) {

-#ifdef InterlockedCompareExchangePointer

-    if (!InterlockedCompareExchange(sl, 1, 0))

-      return 0;

-#else  /* Use older void* version */

-    if (!InterlockedCompareExchange((void**)sl, (void*)1, (void*)0))

-      return 0;

-#endif /* InterlockedCompareExchangePointer */

-    Sleep (0);

-  }

-}

-

-static void win32_release_lock (MLOCK_T *sl) {

-  InterlockedExchange (sl, 0);

-}

-

-#define INITIAL_LOCK(l)      *(l)=0

-#define ACQUIRE_LOCK(l)      win32_acquire_lock(l)

-#define RELEASE_LOCK(l)      win32_release_lock(l)

-#if HAVE_MORECORE

-static MLOCK_T morecore_mutex;

-#endif /* HAVE_MORECORE */

-static MLOCK_T magic_init_mutex;

-#endif /* WIN32 */

-

-#define USE_LOCK_BIT               (2U)

-#else  /* USE_LOCKS */

-#define USE_LOCK_BIT               (0U)

-#define INITIAL_LOCK(l)

-#endif /* USE_LOCKS */

-

-#if USE_LOCKS && HAVE_MORECORE

-#define ACQUIRE_MORECORE_LOCK()    ACQUIRE_LOCK(&morecore_mutex);

-#define RELEASE_MORECORE_LOCK()    RELEASE_LOCK(&morecore_mutex);

-#else /* USE_LOCKS && HAVE_MORECORE */

-#define ACQUIRE_MORECORE_LOCK()

-#define RELEASE_MORECORE_LOCK()

-#endif /* USE_LOCKS && HAVE_MORECORE */

-

-#if USE_LOCKS

-#define ACQUIRE_MAGIC_INIT_LOCK()  ACQUIRE_LOCK(&magic_init_mutex);

-#define RELEASE_MAGIC_INIT_LOCK()  RELEASE_LOCK(&magic_init_mutex);

-#else  /* USE_LOCKS */

-#define ACQUIRE_MAGIC_INIT_LOCK()

-#define RELEASE_MAGIC_INIT_LOCK()

-#endif /* USE_LOCKS */

-

-

-/* -----------------------  Chunk representations ------------------------ */

-

-/*

-  (The following includes lightly edited explanations by Colin Plumb.)

-

-  The malloc_chunk declaration below is misleading (but accurate and

-  necessary).  It declares a "view" into memory allowing access to

-  necessary fields at known offsets from a given base.

-

-  Chunks of memory are maintained using a `boundary tag' method as

-  originally described by Knuth.  (See the paper by Paul Wilson

-  ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such

-  techniques.)  Sizes of free chunks are stored both in the front of

-  each chunk and at the end.  This makes consolidating fragmented

-  chunks into bigger chunks fast.  The head fields also hold bits

-  representing whether chunks are free or in use.

-

-  Here are some pictures to make it clearer.  They are "exploded" to

-  show that the state of a chunk can be thought of as extending from

-  the high 31 bits of the head field of its header through the

-  prev_foot and PINUSE_BIT bit of the following chunk header.

-

-  A chunk that's in use looks like:

-

-   chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-           | Size of previous chunk (if P = 1)                             |

-           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|

-         | Size of this chunk                                         1| +-+

-   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-         |                                                               |

-         +-                                                             -+

-         |                                                               |

-         +-                                                             -+

-         |                                                               :

-         +-      size - sizeof(size_t) available payload bytes          -+

-         :                                                               |

- chunk-> +-                                                             -+

-         |                                                               |

-         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|

-       | Size of next chunk (may or may not be in use)               | +-+

- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-

-    And if it's free, it looks like this:

-

-   chunk-> +-                                                             -+

-           | User payload (must be in use, or we would have merged!)       |

-           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|

-         | Size of this chunk                                         0| +-+

-   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-         | Next pointer                                                  |

-         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-         | Prev pointer                                                  |

-         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-         |                                                               :

-         +-      size - sizeof(struct chunk) unused bytes               -+

-         :                                                               |

- chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-         | Size of this chunk                                            |

-         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|

-       | Size of next chunk (must be in use, or we would have merged)| +-+

- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-       |                                                               :

-       +- User payload                                                -+

-       :                                                               |

-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-                                                                     |0|

-                                                                     +-+

-  Note that since we always merge adjacent free chunks, the chunks

-  adjacent to a free chunk must be in use.

-

-  Given a pointer to a chunk (which can be derived trivially from the

-  payload pointer) we can, in O(1) time, find out whether the adjacent

-  chunks are free, and if so, unlink them from the lists that they

-  are on and merge them with the current chunk.

-

-  Chunks always begin on even word boundaries, so the mem portion

-  (which is returned to the user) is also on an even word boundary, and

-  thus at least double-word aligned.

-

-  The P (PINUSE_BIT) bit, stored in the unused low-order bit of the

-  chunk size (which is always a multiple of two words), is an in-use

-  bit for the *previous* chunk.  If that bit is *clear*, then the

-  word before the current chunk size contains the previous chunk

-  size, and can be used to find the front of the previous chunk.

-  The very first chunk allocated always has this bit set, preventing

-  access to non-existent (or non-owned) memory. If pinuse is set for

-  any given chunk, then you CANNOT determine the size of the

-  previous chunk, and might even get a memory addressing fault when

-  trying to do so.

-

-  The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of

-  the chunk size redundantly records whether the current chunk is

-  inuse. This redundancy enables usage checks within free and realloc,

-  and reduces indirection when freeing and consolidating chunks.

-

-  Each freshly allocated chunk must have both cinuse and pinuse set.

-  That is, each allocated chunk borders either a previously allocated

-  and still in-use chunk, or the base of its memory arena. This is

-  ensured by making all allocations from the the `lowest' part of any

-  found chunk.  Further, no free chunk physically borders another one,

-  so each free chunk is known to be preceded and followed by either

-  inuse chunks or the ends of memory.

-

-  Note that the `foot' of the current chunk is actually represented

-  as the prev_foot of the NEXT chunk. This makes it easier to

-  deal with alignments etc but can be very confusing when trying

-  to extend or adapt this code.

-

-  The exceptions to all this are

-

-     1. The special chunk `top' is the top-most available chunk (i.e.,

-        the one bordering the end of available memory). It is treated

-        specially.  Top is never included in any bin, is used only if

-        no other chunk is available, and is released back to the

-        system if it is very large (see M_TRIM_THRESHOLD).  In effect,

-        the top chunk is treated as larger (and thus less well

-        fitting) than any other available chunk.  The top chunk

-        doesn't update its trailing size field since there is no next

-        contiguous chunk that would have to index off it. However,

-        space is still allocated for it (TOP_FOOT_SIZE) to enable

-        separation or merging when space is extended.

-

-     3. Chunks allocated via mmap, which have the lowest-order bit

-        (IS_MMAPPED_BIT) set in their prev_foot fields, and do not set

-        PINUSE_BIT in their head fields.  Because they are allocated

-        one-by-one, each must carry its own prev_foot field, which is

-        also used to hold the offset this chunk has within its mmapped

-        region, which is needed to preserve alignment. Each mmapped

-        chunk is trailed by the first two fields of a fake next-chunk

-        for sake of usage checks.

-

-*/

-

-struct malloc_chunk {

-  size_t               prev_foot;  /* Size of previous chunk (if free).  */

-  size_t               head;       /* Size and inuse bits. */

-  struct malloc_chunk* fd;         /* double links -- used only if free. */

-  struct malloc_chunk* bk;

-};

-

-typedef struct malloc_chunk  mchunk;

-typedef struct malloc_chunk* mchunkptr;

-typedef struct malloc_chunk* sbinptr;  /* The type of bins of chunks */

-typedef unsigned int bindex_t;         /* Described below */

-typedef unsigned int binmap_t;         /* Described below */

-typedef unsigned int flag_t;           /* The type of various bit flag sets */

-

-/* ------------------- Chunks sizes and alignments ----------------------- */

-

-#define MCHUNK_SIZE         (sizeof(mchunk))

-

-#if FOOTERS

-#define CHUNK_OVERHEAD      (TWO_SIZE_T_SIZES)

-#else /* FOOTERS */

-#define CHUNK_OVERHEAD      (SIZE_T_SIZE)

-#endif /* FOOTERS */

-

-/* MMapped chunks need a second word of overhead ... */

-#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)

-/* ... and additional padding for fake next-chunk at foot */

-#define MMAP_FOOT_PAD       (FOUR_SIZE_T_SIZES)

-

-/* The smallest size we can malloc is an aligned minimal chunk */

-#define MIN_CHUNK_SIZE\

-  ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)

-

-/* conversion from malloc headers to user pointers, and back */

-#define chunk2mem(p)        ((void*)((char*)(p)       + TWO_SIZE_T_SIZES))

-#define mem2chunk(mem)      ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES))

-/* chunk associated with aligned address A */

-#define align_as_chunk(A)   (mchunkptr)((A) + align_offset(chunk2mem(A)))

-

-/* Bounds on request (not chunk) sizes. */

-#define MAX_REQUEST         ((-MIN_CHUNK_SIZE) << 2)

-#define MIN_REQUEST         (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE)

-

-/* pad request bytes into a usable size */

-#define pad_request(req) \

-   (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)

-

-/* pad request, checking for minimum (but not maximum) */

-#define request2size(req) \

-  (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req))

-

-

-/* ------------------ Operations on head and foot fields ----------------- */

-

-/*

-  The head field of a chunk is or'ed with PINUSE_BIT when previous

-  adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in

-  use. If the chunk was obtained with mmap, the prev_foot field has

-  IS_MMAPPED_BIT set, otherwise holding the offset of the base of the

-  mmapped region to the base of the chunk.

-*/

-

-#define PINUSE_BIT          (SIZE_T_ONE)

-#define CINUSE_BIT          (SIZE_T_TWO)

-#define INUSE_BITS          (PINUSE_BIT|CINUSE_BIT)

-

-/* Head value for fenceposts */

-#define FENCEPOST_HEAD      (INUSE_BITS|SIZE_T_SIZE)

-

-/* extraction of fields from head words */

-#define cinuse(p)           ((p)->head & CINUSE_BIT)

-#define pinuse(p)           ((p)->head & PINUSE_BIT)

-#define chunksize(p)        ((p)->head & ~(INUSE_BITS))

-

-#define clear_pinuse(p)     ((p)->head &= ~PINUSE_BIT)

-#define clear_cinuse(p)     ((p)->head &= ~CINUSE_BIT)

-

-/* Treat space at ptr +/- offset as a chunk */

-#define chunk_plus_offset(p, s)  ((mchunkptr)(((char*)(p)) + (s)))

-#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s)))

-

-/* Ptr to next or previous physical malloc_chunk. */

-#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~INUSE_BITS)))

-#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) ))

-

-/* extract next chunk's pinuse bit */

-#define next_pinuse(p)  ((next_chunk(p)->head) & PINUSE_BIT)

-

-/* Get/set size at footer */

-#define get_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot)

-#define set_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s))

-

-/* Set size, pinuse bit, and foot */

-#define set_size_and_pinuse_of_free_chunk(p, s)\

-  ((p)->head = (s|PINUSE_BIT), set_foot(p, s))

-

-/* Set size, pinuse bit, foot, and clear next pinuse */

-#define set_free_with_pinuse(p, s, n)\

-  (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s))

-

-#define is_mmapped(p)\

-  (!((p)->head & PINUSE_BIT) && ((p)->prev_foot & IS_MMAPPED_BIT))

-

-/* Get the internal overhead associated with chunk p */

-#define overhead_for(p)\

- (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD)

-

-/* Return true if malloced space is not necessarily cleared */

-#if MMAP_CLEARS

-#define calloc_must_clear(p) (!is_mmapped(p))

-#else /* MMAP_CLEARS */

-#define calloc_must_clear(p) (1)

-#endif /* MMAP_CLEARS */

-

-/* ---------------------- Overlaid data structures ----------------------- */

-

-/*

-  When chunks are not in use, they are treated as nodes of either

-  lists or trees.

-

-  "Small"  chunks are stored in circular doubly-linked lists, and look

-  like this:

-

-    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-            |             Size of previous chunk                            |

-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-    `head:' |             Size of chunk, in bytes                         |P|

-      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-            |             Forward pointer to next chunk in list             |

-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-            |             Back pointer to previous chunk in list            |

-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-            |             Unused space (may be 0 bytes long)                .

-            .                                                               .

-            .                                                               |

-nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-    `foot:' |             Size of chunk, in bytes                           |

-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-

-  Larger chunks are kept in a form of bitwise digital trees (aka

-  tries) keyed on chunksizes.  Because malloc_tree_chunks are only for

-  free chunks greater than 256 bytes, their size doesn't impose any

-  constraints on user chunk sizes.  Each node looks like:

-

-    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-            |             Size of previous chunk                            |

-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-    `head:' |             Size of chunk, in bytes                         |P|

-      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-            |             Forward pointer to next chunk of same size        |

-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-            |             Back pointer to previous chunk of same size       |

-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-            |             Pointer to left child (child[0])                  |

-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-            |             Pointer to right child (child[1])                 |

-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-            |             Pointer to parent                                 |

-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-            |             bin index of this chunk                           |

-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-            |             Unused space                                      .

-            .                                                               |

-nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-    `foot:' |             Size of chunk, in bytes                           |

-            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

-

-  Each tree holding treenodes is a tree of unique chunk sizes.  Chunks

-  of the same size are arranged in a circularly-linked list, with only

-  the oldest chunk (the next to be used, in our FIFO ordering)

-  actually in the tree.  (Tree members are distinguished by a non-null

-  parent pointer.)  If a chunk with the same size an an existing node

-  is inserted, it is linked off the existing node using pointers that

-  work in the same way as fd/bk pointers of small chunks.

-

-  Each tree contains a power of 2 sized range of chunk sizes (the

-  smallest is 0x100 <= x < 0x180), which is is divided in half at each

-  tree level, with the chunks in the smaller half of the range (0x100

-  <= x < 0x140 for the top nose) in the left subtree and the larger

-  half (0x140 <= x < 0x180) in the right subtree.  This is, of course,

-  done by inspecting individual bits.

-

-  Using these rules, each node's left subtree contains all smaller

-  sizes than its right subtree.  However, the node at the root of each

-  subtree has no particular ordering relationship to either.  (The

-  dividing line between the subtree sizes is based on trie relation.)

-  If we remove the last chunk of a given size from the interior of the

-  tree, we need to replace it with a leaf node.  The tree ordering

-  rules permit a node to be replaced by any leaf below it.

-

-  The smallest chunk in a tree (a common operation in a best-fit

-  allocator) can be found by walking a path to the leftmost leaf in

-  the tree.  Unlike a usual binary tree, where we follow left child

-  pointers until we reach a null, here we follow the right child

-  pointer any time the left one is null, until we reach a leaf with

-  both child pointers null. The smallest chunk in the tree will be

-  somewhere along that path.

-

-  The worst case number of steps to add, find, or remove a node is

-  bounded by the number of bits differentiating chunks within

-  bins. Under current bin calculations, this ranges from 6 up to 21

-  (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case

-  is of course much better.

-*/

-

-struct malloc_tree_chunk {

-  /* The first four fields must be compatible with malloc_chunk */

-  size_t                    prev_foot;

-  size_t                    head;

-  struct malloc_tree_chunk* fd;

-  struct malloc_tree_chunk* bk;

-

-  struct malloc_tree_chunk* child[2];

-  struct malloc_tree_chunk* parent;

-  bindex_t                  index;

-};

-

-typedef struct malloc_tree_chunk  tchunk;

-typedef struct malloc_tree_chunk* tchunkptr;

-typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */

-

-/* A little helper macro for trees */

-#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1])

-

-/* ----------------------------- Segments -------------------------------- */

-

-/*

-  Each malloc space may include non-contiguous segments, held in a

-  list headed by an embedded malloc_segment record representing the

-  top-most space. Segments also include flags holding properties of

-  the space. Large chunks that are directly allocated by mmap are not

-  included in this list. They are instead independently created and

-  destroyed without otherwise keeping track of them.

-

-  Segment management mainly comes into play for spaces allocated by

-  MMAP.  Any call to MMAP might or might not return memory that is

-  adjacent to an existing segment.  MORECORE normally contiguously

-  extends the current space, so this space is almost always adjacent,

-  which is simpler and faster to deal with. (This is why MORECORE is

-  used preferentially to MMAP when both are available -- see

-  sys_alloc.)  When allocating using MMAP, we don't use any of the

-  hinting mechanisms (inconsistently) supported in various

-  implementations of unix mmap, or distinguish reserving from

-  committing memory. Instead, we just ask for space, and exploit

-  contiguity when we get it.  It is probably possible to do

-  better than this on some systems, but no general scheme seems

-  to be significantly better.

-

-  Management entails a simpler variant of the consolidation scheme

-  used for chunks to reduce fragmentation -- new adjacent memory is

-  normally prepended or appended to an existing segment. However,

-  there are limitations compared to chunk consolidation that mostly

-  reflect the fact that segment processing is relatively infrequent

-  (occurring only when getting memory from system) and that we

-  don't expect to have huge numbers of segments:

-

-  * Segments are not indexed, so traversal requires linear scans.  (It

-    would be possible to index these, but is not worth the extra

-    overhead and complexity for most programs on most platforms.)

-  * New segments are only appended to old ones when holding top-most

-    memory; if they cannot be prepended to others, they are held in

-    different segments.

-

-  Except for the top-most segment of an mstate, each segment record

-  is kept at the tail of its segment. Segments are added by pushing

-  segment records onto the list headed by &mstate.seg for the

-  containing mstate.

-

-  Segment flags control allocation/merge/deallocation policies:

-  * If EXTERN_BIT set, then we did not allocate this segment,

-    and so should not try to deallocate or merge with others.

-    (This currently holds only for the initial segment passed

-    into create_mspace_with_base.)

-  * If IS_MMAPPED_BIT set, the segment may be merged with

-    other surrounding mmapped segments and trimmed/de-allocated

-    using munmap.

-  * If neither bit is set, then the segment was obtained using

-    MORECORE so can be merged with surrounding MORECORE'd segments

-    and deallocated/trimmed using MORECORE with negative arguments.

-*/

-

-struct malloc_segment {

-  char*        base;             /* base address */

-  size_t       size;             /* allocated size */

-  struct malloc_segment* next;   /* ptr to next segment */

-  flag_t       sflags;           /* mmap and extern flag */

-};

-

-#define is_mmapped_segment(S)  ((S)->sflags & IS_MMAPPED_BIT)

-#define is_extern_segment(S)   ((S)->sflags & EXTERN_BIT)

-

-typedef struct malloc_segment  msegment;

-typedef struct malloc_segment* msegmentptr;

-

-/* ---------------------------- malloc_state ----------------------------- */

-

-/*

-   A malloc_state holds all of the bookkeeping for a space.

-   The main fields are:

-

-  Top

-    The topmost chunk of the currently active segment. Its size is

-    cached in topsize.  The actual size of topmost space is

-    topsize+TOP_FOOT_SIZE, which includes space reserved for adding

-    fenceposts and segment records if necessary when getting more

-    space from the system.  The size at which to autotrim top is

-    cached from mparams in trim_check, except that it is disabled if

-    an autotrim fails.

-

-  Designated victim (dv)

-    This is the preferred chunk for servicing small requests that

-    don't have exact fits.  It is normally the chunk split off most

-    recently to service another small request.  Its size is cached in

-    dvsize. The link fields of this chunk are not maintained since it

-    is not kept in a bin.

-

-  SmallBins

-    An array of bin headers for free chunks.  These bins hold chunks

-    with sizes less than MIN_LARGE_SIZE bytes. Each bin contains

-    chunks of all the same size, spaced 8 bytes apart.  To simplify

-    use in double-linked lists, each bin header acts as a malloc_chunk

-    pointing to the real first node, if it exists (else pointing to

-    itself).  This avoids special-casing for headers.  But to avoid

-    waste, we allocate only the fd/bk pointers of bins, and then use

-    repositioning tricks to treat these as the fields of a chunk.

-

-  TreeBins

-    Treebins are pointers to the roots of trees holding a range of

-    sizes. There are 2 equally spaced treebins for each power of two

-    from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything

-    larger.

-

-  Bin maps

-    There is one bit map for small bins ("smallmap") and one for

-    treebins ("treemap).  Each bin sets its bit when non-empty, and

-    clears the bit when empty.  Bit operations are then used to avoid

-    bin-by-bin searching -- nearly all "search" is done without ever

-    looking at bins that won't be selected.  The bit maps

-    conservatively use 32 bits per map word, even if on 64bit system.

-    For a good description of some of the bit-based techniques used

-    here, see Henry S. Warren Jr's book "Hacker's Delight" (and

-    supplement at http://hackersdelight.org/). Many of these are

-    intended to reduce the branchiness of paths through malloc etc, as

-    well as to reduce the number of memory locations read or written.

-

-  Segments

-    A list of segments headed by an embedded malloc_segment record

-    representing the initial space.

-

-  Address check support

-    The least_addr field is the least address ever obtained from

-    MORECORE or MMAP. Attempted frees and reallocs of any address less

-    than this are trapped (unless INSECURE is defined).

-

-  Magic tag

-    A cross-check field that should always hold same value as mparams.magic.

-

-  Flags

-    Bits recording whether to use MMAP, locks, or contiguous MORECORE

-

-  Statistics

-    Each space keeps track of current and maximum system memory

-    obtained via MORECORE or MMAP.

-

-  Locking

-    If USE_LOCKS is defined, the "mutex" lock is acquired and released

-    around every public call using this mspace.

-*/

-

-/* Bin types, widths and sizes */

-#define NSMALLBINS        (32U)

-#define NTREEBINS         (32U)

-#define SMALLBIN_SHIFT    (3U)

-#define SMALLBIN_WIDTH    (SIZE_T_ONE << SMALLBIN_SHIFT)

-#define TREEBIN_SHIFT     (8U)

-#define MIN_LARGE_SIZE    (SIZE_T_ONE << TREEBIN_SHIFT)

-#define MAX_SMALL_SIZE    (MIN_LARGE_SIZE - SIZE_T_ONE)

-#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD)

-

-struct malloc_state {

-  binmap_t   smallmap;

-  binmap_t   treemap;

-  size_t     dvsize;

-  size_t     topsize;

-  char*      least_addr;

-  mchunkptr  dv;

-  mchunkptr  top;

-  size_t     trim_check;

-  size_t     magic;

-  mchunkptr  smallbins[(NSMALLBINS+1)*2];

-  tbinptr    treebins[NTREEBINS];

-  size_t     footprint;

-  size_t     max_footprint;

-  flag_t     mflags;

-#if USE_LOCKS

-  MLOCK_T    mutex;     /* locate lock among fields that rarely change */

-#endif /* USE_LOCKS */

-  msegment   seg;

-};

-

-typedef struct malloc_state*    mstate;

-

-/* ------------- Global malloc_state and malloc_params ------------------- */

-

-/*

-  malloc_params holds global properties, including those that can be

-  dynamically set using mallopt. There is a single instance, mparams,

-  initialized in init_mparams.

-*/

-

-struct malloc_params {

-  size_t magic;

-  size_t page_size;

-  size_t granularity;

-  size_t mmap_threshold;

-  size_t trim_threshold;

-  flag_t default_mflags;

-};

-

-static struct malloc_params mparams;

-

-/* The global malloc_state used for all non-"mspace" calls */

-static struct malloc_state _gm_;

-#define gm                 (&_gm_)

-#define is_global(M)       ((M) == &_gm_)

-#define is_initialized(M)  ((M)->top != 0)

-

-/* -------------------------- system alloc setup ------------------------- */

-

-/* Operations on mflags */

-

-#define use_lock(M)           ((M)->mflags &   USE_LOCK_BIT)

-#define enable_lock(M)        ((M)->mflags |=  USE_LOCK_BIT)

-#define disable_lock(M)       ((M)->mflags &= ~USE_LOCK_BIT)

-

-#define use_mmap(M)           ((M)->mflags &   USE_MMAP_BIT)

-#define enable_mmap(M)        ((M)->mflags |=  USE_MMAP_BIT)

-#define disable_mmap(M)       ((M)->mflags &= ~USE_MMAP_BIT)

-

-#define use_noncontiguous(M)  ((M)->mflags &   USE_NONCONTIGUOUS_BIT)

-#define disable_contiguous(M) ((M)->mflags |=  USE_NONCONTIGUOUS_BIT)

-

-#define set_lock(M,L)\

- ((M)->mflags = (L)?\

-  ((M)->mflags | USE_LOCK_BIT) :\

-  ((M)->mflags & ~USE_LOCK_BIT))

-

-/* page-align a size */

-#define page_align(S)\

- (((S) + (mparams.page_size)) & ~(mparams.page_size - SIZE_T_ONE))

-

-/* granularity-align a size */

-#define granularity_align(S)\

-  (((S) + (mparams.granularity)) & ~(mparams.granularity - SIZE_T_ONE))

-

-#define is_page_aligned(S)\

-   (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0)

-#define is_granularity_aligned(S)\

-   (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0)

-

-/*  True if segment S holds address A */

-#define segment_holds(S, A)\

-  ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)

-

-/* Return segment holding given address */

-static msegmentptr segment_holding(mstate m, char* addr) {

-  msegmentptr sp = &m->seg;

-  for (;;) {

-    if (addr >= sp->base && addr < sp->base + sp->size)

-      return sp;

-    if ((sp = sp->next) == 0)

-      return 0;

-  }

-}

-

-/* Return true if segment contains a segment link */

-static int has_segment_link(mstate m, msegmentptr ss) {

-  msegmentptr sp = &m->seg;

-  for (;;) {

-    if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size)

-      return 1;

-    if ((sp = sp->next) == 0)

-      return 0;

-  }

-}

-

-#ifndef MORECORE_CANNOT_TRIM

-#define should_trim(M,s)  ((s) > (M)->trim_check)

-#else  /* MORECORE_CANNOT_TRIM */

-#define should_trim(M,s)  (0)

-#endif /* MORECORE_CANNOT_TRIM */

-

-/*

-  TOP_FOOT_SIZE is padding at the end of a segment, including space

-  that may be needed to place segment records and fenceposts when new

-  noncontiguous segments are added.

-*/

-#define TOP_FOOT_SIZE\

-  (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE)

-

-

-/* -------------------------------  Hooks -------------------------------- */

-

-/*

-  PREACTION should be defined to return 0 on success, and nonzero on

-  failure. If you are not using locking, you can redefine these to do

-  anything you like.

-*/

-

-#if USE_LOCKS

-

-/* Ensure locks are initialized */

-#define GLOBALLY_INITIALIZE() (mparams.page_size == 0 && init_mparams())

-

-#define PREACTION(M)  ((GLOBALLY_INITIALIZE() || use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0)

-#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); }

-#else /* USE_LOCKS */

-

-#ifndef PREACTION

-#define PREACTION(M) (0)

-#endif  /* PREACTION */

-

-#ifndef POSTACTION

-#define POSTACTION(M)

-#endif  /* POSTACTION */

-

-#endif /* USE_LOCKS */

-

-/*

-  CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses.

-  USAGE_ERROR_ACTION is triggered on detected bad frees and

-  reallocs. The argument p is an address that might have triggered the

-  fault. It is ignored by the two predefined actions, but might be

-  useful in custom actions that try to help diagnose errors.

-*/

-

-#if PROCEED_ON_ERROR

-

-/* A count of the number of corruption errors causing resets */

-int malloc_corruption_error_count;

-

-/* default corruption action */

-static void reset_on_error(mstate m);

-

-#define CORRUPTION_ERROR_ACTION(m)  reset_on_error(m)

-#define USAGE_ERROR_ACTION(m, p)

-

-#else /* PROCEED_ON_ERROR */

-

-#ifndef CORRUPTION_ERROR_ACTION

-#define CORRUPTION_ERROR_ACTION(m) ABORT

-#endif /* CORRUPTION_ERROR_ACTION */

-

-#ifndef USAGE_ERROR_ACTION

-#define USAGE_ERROR_ACTION(m,p) ABORT

-#endif /* USAGE_ERROR_ACTION */

-

-#endif /* PROCEED_ON_ERROR */

-

-/* -------------------------- Debugging setup ---------------------------- */

-

-#if ! DEBUG

-

-#define check_free_chunk(M,P)

-#define check_inuse_chunk(M,P)

-#define check_malloced_chunk(M,P,N)

-#define check_mmapped_chunk(M,P)

-#define check_malloc_state(M)

-#define check_top_chunk(M,P)

-

-#else /* DEBUG */

-#define check_free_chunk(M,P)       do_check_free_chunk(M,P)

-#define check_inuse_chunk(M,P)      do_check_inuse_chunk(M,P)

-#define check_top_chunk(M,P)        do_check_top_chunk(M,P)

-#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N)

-#define check_mmapped_chunk(M,P)    do_check_mmapped_chunk(M,P)

-#define check_malloc_state(M)       do_check_malloc_state(M)

-

-static void   do_check_any_chunk(mstate m, mchunkptr p);

-static void   do_check_top_chunk(mstate m, mchunkptr p);

-static void   do_check_mmapped_chunk(mstate m, mchunkptr p);

-static void   do_check_inuse_chunk(mstate m, mchunkptr p);

-static void   do_check_free_chunk(mstate m, mchunkptr p);

-static void   do_check_malloced_chunk(mstate m, void* mem, size_t s);

-static void   do_check_tree(mstate m, tchunkptr t);

-static void   do_check_treebin(mstate m, bindex_t i);

-static void   do_check_smallbin(mstate m, bindex_t i);

-static void   do_check_malloc_state(mstate m);

-static int    bin_find(mstate m, mchunkptr x);

-static size_t traverse_and_check(mstate m);

-#endif /* DEBUG */

-

-/* ---------------------------- Indexing Bins ---------------------------- */

-

-#define is_small(s)         (((s) >> SMALLBIN_SHIFT) < NSMALLBINS)

-#define small_index(s)      ((s)  >> SMALLBIN_SHIFT)

-#define small_index2size(i) ((i)  << SMALLBIN_SHIFT)

-#define MIN_SMALL_INDEX     (small_index(MIN_CHUNK_SIZE))

-

-/* addressing by index. See above about smallbin repositioning */

-#define smallbin_at(M, i)   ((sbinptr)((char*)&((M)->smallbins[(i)<<1])))

-#define treebin_at(M,i)     (&((M)->treebins[i]))

-

-/* assign tree index for size S to variable I */

-#if defined(__GNUC__) && defined(i386)

-#define compute_tree_index(S, I)\

-{\

-  size_t X = S >> TREEBIN_SHIFT;\

-  if (X == 0)\

-    I = 0;\

-  else if (X > 0xFFFF)\

-    I = NTREEBINS-1;\

-  else {\

-    unsigned int K;\

-    __asm__("bsrl %1,%0\n\t" : "=r" (K) : "rm"  (X));\

-    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\

-  }\

-}

-#else /* GNUC */

-#define compute_tree_index(S, I)\

-{\

-  size_t X = S >> TREEBIN_SHIFT;\

-  if (X == 0)\

-    I = 0;\

-  else if (X > 0xFFFF)\

-    I = NTREEBINS-1;\

-  else {\

-    unsigned int Y = (unsigned int)X;\

-    unsigned int N = ((Y - 0x100) >> 16) & 8;\

-    unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\

-    N += K;\

-    N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\

-    K = 14 - N + ((Y <<= K) >> 15);\

-    I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\

-  }\

-}

-#endif /* GNUC */

-

-/* Bit representing maximum resolved size in a treebin at i */

-#define bit_for_tree_index(i) \

-   (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2)

-

-/* Shift placing maximum resolved bit in a treebin at i as sign bit */

-#define leftshift_for_tree_index(i) \

-   ((i == NTREEBINS-1)? 0 : \

-    ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2)))

-

-/* The size of the smallest chunk held in bin with index i */

-#define minsize_for_tree_index(i) \

-   ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) |  \

-   (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1)))

-

-

-/* ------------------------ Operations on bin maps ----------------------- */

-

-/* bit corresponding to given index */

-#define idx2bit(i)              ((binmap_t)(1) << (i))

-

-/* Mark/Clear bits with given index */

-#define mark_smallmap(M,i)      ((M)->smallmap |=  idx2bit(i))

-#define clear_smallmap(M,i)     ((M)->smallmap &= ~idx2bit(i))

-#define smallmap_is_marked(M,i) ((M)->smallmap &   idx2bit(i))

-

-#define mark_treemap(M,i)       ((M)->treemap  |=  idx2bit(i))

-#define clear_treemap(M,i)      ((M)->treemap  &= ~idx2bit(i))

-#define treemap_is_marked(M,i)  ((M)->treemap  &   idx2bit(i))

-

-/* index corresponding to given bit */

-

-#if defined(__GNUC__) && defined(i386)

-#define compute_bit2idx(X, I)\

-{\

-  unsigned int J;\

-  __asm__("bsfl %1,%0\n\t" : "=r" (J) : "rm" (X));\

-  I = (bindex_t)J;\

-}

-

-#else /* GNUC */

-#if  USE_BUILTIN_FFS

-#define compute_bit2idx(X, I) I = ffs(X)-1

-

-#else /* USE_BUILTIN_FFS */

-#define compute_bit2idx(X, I)\

-{\

-  unsigned int Y = X - 1;\

-  unsigned int K = Y >> (16-4) & 16;\

-  unsigned int N = K;        Y >>= K;\

-  N += K = Y >> (8-3) &  8;  Y >>= K;\

-  N += K = Y >> (4-2) &  4;  Y >>= K;\

-  N += K = Y >> (2-1) &  2;  Y >>= K;\

-  N += K = Y >> (1-0) &  1;  Y >>= K;\

-  I = (bindex_t)(N + Y);\

-}

-#endif /* USE_BUILTIN_FFS */

-#endif /* GNUC */

-

-/* isolate the least set bit of a bitmap */

-#define least_bit(x)         ((x) & -(x))

-

-/* mask with all bits to left of least bit of x on */

-#define left_bits(x)         ((x<<1) | -(x<<1))

-

-/* mask with all bits to left of or equal to least bit of x on */

-#define same_or_left_bits(x) ((x) | -(x))

-

-

-/* ----------------------- Runtime Check Support ------------------------- */

-

-/*

-  For security, the main invariant is that malloc/free/etc never

-  writes to a static address other than malloc_state, unless static

-  malloc_state itself has been corrupted, which cannot occur via

-  malloc (because of these checks). In essence this means that we

-  believe all pointers, sizes, maps etc held in malloc_state, but

-  check all of those linked or offsetted from other embedded data

-  structures.  These checks are interspersed with main code in a way

-  that tends to minimize their run-time cost.

-

-  When FOOTERS is defined, in addition to range checking, we also

-  verify footer fields of inuse chunks, which can be used guarantee

-  that the mstate controlling malloc/free is intact.  This is a

-  streamlined version of the approach described by William Robertson

-  et al in "Run-time Detection of Heap-based Overflows" LISA'03

-  http://www.usenix.org/events/lisa03/tech/robertson.html The footer

-  of an inuse chunk holds the xor of its mstate and a random seed,

-  that is checked upon calls to free() and realloc().  This is

-  (probablistically) unguessable from outside the program, but can be

-  computed by any code successfully malloc'ing any chunk, so does not

-  itself provide protection against code that has already broken

-  security through some other means.  Unlike Robertson et al, we

-  always dynamically check addresses of all offset chunks (previous,

-  next, etc). This turns out to be cheaper than relying on hashes.

-*/

-

-#if !INSECURE

-/* Check if address a is at least as high as any from MORECORE or MMAP */

-#define ok_address(M, a) ((char*)(a) >= (M)->least_addr)

-/* Check if address of next chunk n is higher than base chunk p */

-#define ok_next(p, n)    ((char*)(p) < (char*)(n))

-/* Check if p has its cinuse bit on */

-#define ok_cinuse(p)     cinuse(p)

-/* Check if p has its pinuse bit on */

-#define ok_pinuse(p)     pinuse(p)

-

-#else /* !INSECURE */

-#define ok_address(M, a) (1)

-#define ok_next(b, n)    (1)

-#define ok_cinuse(p)     (1)

-#define ok_pinuse(p)     (1)

-#endif /* !INSECURE */

-

-#if (FOOTERS && !INSECURE)

-/* Check if (alleged) mstate m has expected magic field */

-#define ok_magic(M)      ((M)->magic == mparams.magic)

-#else  /* (FOOTERS && !INSECURE) */

-#define ok_magic(M)      (1)

-#endif /* (FOOTERS && !INSECURE) */

-

-

-/* In gcc, use __builtin_expect to minimize impact of checks */

-#if !INSECURE

-#if defined(__GNUC__) && __GNUC__ >= 3

-#define RTCHECK(e)  __builtin_expect(e, 1)

-#else /* GNUC */

-#define RTCHECK(e)  (e)

-#endif /* GNUC */

-#else /* !INSECURE */

-#define RTCHECK(e)  (1)

-#endif /* !INSECURE */

-

-/* macros to set up inuse chunks with or without footers */

-

-#if !FOOTERS

-

-#define mark_inuse_foot(M,p,s)

-

-/* Set cinuse bit and pinuse bit of next chunk */

-#define set_inuse(M,p,s)\

-  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\

-  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)

-

-/* Set cinuse and pinuse of this chunk and pinuse of next chunk */

-#define set_inuse_and_pinuse(M,p,s)\

-  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\

-  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)

-

-/* Set size, cinuse and pinuse bit of this chunk */

-#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\

-  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT))

-

-#else /* FOOTERS */

-

-/* Set foot of inuse chunk to be xor of mstate and seed */

-#define mark_inuse_foot(M,p,s)\

-  (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic))

-

-#define get_mstate_for(p)\

-  ((mstate)(((mchunkptr)((char*)(p) +\

-    (chunksize(p))))->prev_foot ^ mparams.magic))

-

-#define set_inuse(M,p,s)\

-  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\

-  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \

-  mark_inuse_foot(M,p,s))

-

-#define set_inuse_and_pinuse(M,p,s)\

-  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\

-  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\

- mark_inuse_foot(M,p,s))

-

-#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\

-  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\

-  mark_inuse_foot(M, p, s))

-

-#endif /* !FOOTERS */

-

-/* ---------------------------- setting mparams -------------------------- */

-

-/* Initialize mparams */

-static int init_mparams(void) {

-  if (mparams.page_size == 0) {

-    size_t s;

-

-    mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD;

-    mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD;

-#if MORECORE_CONTIGUOUS

-    mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT;

-#else  /* MORECORE_CONTIGUOUS */

-    mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT;

-#endif /* MORECORE_CONTIGUOUS */

-

-#if (FOOTERS && !INSECURE)

-    {

-#if USE_DEV_RANDOM

-      int fd;

-      unsigned char buf[sizeof(size_t)];

-      /* Try to use /dev/urandom, else fall back on using time */

-      if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 &&

-          read(fd, buf, sizeof(buf)) == sizeof(buf)) {

-        s = *((size_t *) buf);

-        close(fd);

-      }

-      else

-#endif /* USE_DEV_RANDOM */

-        s = (size_t)(time(0) ^ (size_t)0x55555555U);

-

-      s |= (size_t)8U;    /* ensure nonzero */

-      s &= ~(size_t)7U;   /* improve chances of fault for bad values */

-

-    }

-#else /* (FOOTERS && !INSECURE) */

-    s = (size_t)0x58585858U;

-#endif /* (FOOTERS && !INSECURE) */

-    ACQUIRE_MAGIC_INIT_LOCK();

-    if (mparams.magic == 0) {

-      mparams.magic = s;

-      /* Set up lock for main malloc area */

-      INITIAL_LOCK(&gm->mutex);

-      gm->mflags = mparams.default_mflags;

-    }

-    RELEASE_MAGIC_INIT_LOCK();

-

-#ifndef WIN32

-    mparams.page_size = malloc_getpagesize;

-    mparams.granularity = ((DEFAULT_GRANULARITY != 0)?

-                           DEFAULT_GRANULARITY : mparams.page_size);

-#else /* WIN32 */

-    {

-      SYSTEM_INFO system_info;

-      GetSystemInfo(&system_info);

-      mparams.page_size = system_info.dwPageSize;

-      mparams.granularity = system_info.dwAllocationGranularity;

-    }

-#endif /* WIN32 */

-

-    /* Sanity-check configuration:

-       size_t must be unsigned and as wide as pointer type.

-       ints must be at least 4 bytes.

-       alignment must be at least 8.

-       Alignment, min chunk size, and page size must all be powers of 2.

-    */

-    if ((sizeof(size_t) != sizeof(char*)) ||

-        (MAX_SIZE_T < MIN_CHUNK_SIZE)  ||

-        (sizeof(int) < 4)  ||

-        (MALLOC_ALIGNMENT < (size_t)8U) ||

-        ((MALLOC_ALIGNMENT    & (MALLOC_ALIGNMENT-SIZE_T_ONE))    != 0) ||

-        ((MCHUNK_SIZE         & (MCHUNK_SIZE-SIZE_T_ONE))         != 0) ||

-        ((mparams.granularity & (mparams.granularity-SIZE_T_ONE)) != 0) ||

-        ((mparams.page_size   & (mparams.page_size-SIZE_T_ONE))   != 0))

-      ABORT;

-  }

-  return 0;

-}

-

-/* support for mallopt */

-static int change_mparam(int param_number, int value) {

-  size_t val = (size_t)value;

-  init_mparams();

-  switch(param_number) {

-  case M_TRIM_THRESHOLD:

-    mparams.trim_threshold = val;

-    return 1;

-  case M_GRANULARITY:

-    if (val >= mparams.page_size && ((val & (val-1)) == 0)) {

-      mparams.granularity = val;

-      return 1;

-    }

-    else

-      return 0;

-  case M_MMAP_THRESHOLD:

-    mparams.mmap_threshold = val;

-    return 1;

-  default:

-    return 0;

-  }

-}

-

-#if DEBUG

-/* ------------------------- Debugging Support --------------------------- */

-

-/* Check properties of any chunk, whether free, inuse, mmapped etc  */

-static void do_check_any_chunk(mstate m, mchunkptr p) {

-  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));

-  assert(ok_address(m, p));

-}

-

-/* Check properties of top chunk */

-static void do_check_top_chunk(mstate m, mchunkptr p) {

-  msegmentptr sp = segment_holding(m, (char*)p);

-  size_t  sz = chunksize(p);

-  assert(sp != 0);

-  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));

-  assert(ok_address(m, p));

-  assert(sz == m->topsize);

-  assert(sz > 0);

-  assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE);

-  assert(pinuse(p));

-  assert(!next_pinuse(p));

-}

-

-/* Check properties of (inuse) mmapped chunks */

-static void do_check_mmapped_chunk(mstate m, mchunkptr p) {

-  size_t  sz = chunksize(p);

-  size_t len = (sz + (p->prev_foot & ~IS_MMAPPED_BIT) + MMAP_FOOT_PAD);

-  assert(is_mmapped(p));

-  assert(use_mmap(m));

-  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));

-  assert(ok_address(m, p));

-  assert(!is_small(sz));

-  assert((len & (mparams.page_size-SIZE_T_ONE)) == 0);

-  assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD);

-  assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0);

-}

-

-/* Check properties of inuse chunks */

-static void do_check_inuse_chunk(mstate m, mchunkptr p) {

-  do_check_any_chunk(m, p);

-  assert(cinuse(p));

-  assert(next_pinuse(p));

-  /* If not pinuse and not mmapped, previous chunk has OK offset */

-  assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p);

-  if (is_mmapped(p))

-    do_check_mmapped_chunk(m, p);

-}

-

-/* Check properties of free chunks */

-static void do_check_free_chunk(mstate m, mchunkptr p) {

-  size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT);

-  mchunkptr next = chunk_plus_offset(p, sz);

-  do_check_any_chunk(m, p);

-  assert(!cinuse(p));

-  assert(!next_pinuse(p));

-  assert (!is_mmapped(p));

-  if (p != m->dv && p != m->top) {

-    if (sz >= MIN_CHUNK_SIZE) {

-      assert((sz & CHUNK_ALIGN_MASK) == 0);

-      assert(is_aligned(chunk2mem(p)));

-      assert(next->prev_foot == sz);

-      assert(pinuse(p));

-      assert (next == m->top || cinuse(next));

-      assert(p->fd->bk == p);

-      assert(p->bk->fd == p);

-    }

-    else  /* markers are always of size SIZE_T_SIZE */

-      assert(sz == SIZE_T_SIZE);

-  }

-}

-

-/* Check properties of malloced chunks at the point they are malloced */

-static void do_check_malloced_chunk(mstate m, void* mem, size_t s) {

-  if (mem != 0) {

-    mchunkptr p = mem2chunk(mem);

-    size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT);

-    do_check_inuse_chunk(m, p);

-    assert((sz & CHUNK_ALIGN_MASK) == 0);

-    assert(sz >= MIN_CHUNK_SIZE);

-    assert(sz >= s);

-    /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */

-    assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE));

-  }

-}

-

-/* Check a tree and its subtrees.  */

-static void do_check_tree(mstate m, tchunkptr t) {

-  tchunkptr head = 0;

-  tchunkptr u = t;

-  bindex_t tindex = t->index;

-  size_t tsize = chunksize(t);

-  bindex_t idx;

-  compute_tree_index(tsize, idx);

-  assert(tindex == idx);

-  assert(tsize >= MIN_LARGE_SIZE);

-  assert(tsize >= minsize_for_tree_index(idx));

-  assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1))));

-

-  do { /* traverse through chain of same-sized nodes */

-    do_check_any_chunk(m, ((mchunkptr)u));

-    assert(u->index == tindex);

-    assert(chunksize(u) == tsize);

-    assert(!cinuse(u));

-    assert(!next_pinuse(u));

-    assert(u->fd->bk == u);

-    assert(u->bk->fd == u);

-    if (u->parent == 0) {

-      assert(u->child[0] == 0);

-      assert(u->child[1] == 0);

-    }

-    else {

-      assert(head == 0); /* only one node on chain has parent */

-      head = u;

-      assert(u->parent != u);

-      assert (u->parent->child[0] == u ||

-              u->parent->child[1] == u ||

-              *((tbinptr*)(u->parent)) == u);

-      if (u->child[0] != 0) {

-        assert(u->child[0]->parent == u);

-        assert(u->child[0] != u);

-        do_check_tree(m, u->child[0]);

-      }

-      if (u->child[1] != 0) {

-        assert(u->child[1]->parent == u);

-        assert(u->child[1] != u);

-        do_check_tree(m, u->child[1]);

-      }

-      if (u->child[0] != 0 && u->child[1] != 0) {

-        assert(chunksize(u->child[0]) < chunksize(u->child[1]));

-      }

-    }

-    u = u->fd;

-  } while (u != t);

-  assert(head != 0);

-}

-

-/*  Check all the chunks in a treebin.  */

-static void do_check_treebin(mstate m, bindex_t i) {

-  tbinptr* tb = treebin_at(m, i);

-  tchunkptr t = *tb;

-  int empty = (m->treemap & (1U << i)) == 0;

-  if (t == 0)

-    assert(empty);

-  if (!empty)

-    do_check_tree(m, t);

-}

-

-/*  Check all the chunks in a smallbin.  */

-static void do_check_smallbin(mstate m, bindex_t i) {

-  sbinptr b = smallbin_at(m, i);

-  mchunkptr p = b->bk;

-  unsigned int empty = (m->smallmap & (1U << i)) == 0;

-  if (p == b)

-    assert(empty);

-  if (!empty) {

-    for (; p != b; p = p->bk) {

-      size_t size = chunksize(p);

-      mchunkptr q;

-      /* each chunk claims to be free */

-      do_check_free_chunk(m, p);

-      /* chunk belongs in bin */

-      assert(small_index(size) == i);

-      assert(p->bk == b || chunksize(p->bk) == chunksize(p));

-      /* chunk is followed by an inuse chunk */

-      q = next_chunk(p);

-      if (q->head != FENCEPOST_HEAD)

-        do_check_inuse_chunk(m, q);

-    }

-  }

-}

-

-/* Find x in a bin. Used in other check functions. */

-static int bin_find(mstate m, mchunkptr x) {

-  size_t size = chunksize(x);

-  if (is_small(size)) {

-    bindex_t sidx = small_index(size);

-    sbinptr b = smallbin_at(m, sidx);

-    if (smallmap_is_marked(m, sidx)) {

-      mchunkptr p = b;

-      do {

-        if (p == x)

-          return 1;

-      } while ((p = p->fd) != b);

-    }

-  }

-  else {

-    bindex_t tidx;

-    compute_tree_index(size, tidx);

-    if (treemap_is_marked(m, tidx)) {

-      tchunkptr t = *treebin_at(m, tidx);

-      size_t sizebits = size << leftshift_for_tree_index(tidx);

-      while (t != 0 && chunksize(t) != size) {

-        t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];

-        sizebits <<= 1;

-      }

-      if (t != 0) {

-        tchunkptr u = t;

-        do {

-          if (u == (tchunkptr)x)

-            return 1;

-        } while ((u = u->fd) != t);

-      }

-    }

-  }

-  return 0;

-}

-

-/* Traverse each chunk and check it; return total */

-static size_t traverse_and_check(mstate m) {

-  size_t sum = 0;

-  if (is_initialized(m)) {

-    msegmentptr s = &m->seg;

-    sum += m->topsize + TOP_FOOT_SIZE;

-    while (s != 0) {

-      mchunkptr q = align_as_chunk(s->base);

-      mchunkptr lastq = 0;

-      assert(pinuse(q));

-      while (segment_holds(s, q) &&

-             q != m->top && q->head != FENCEPOST_HEAD) {

-        sum += chunksize(q);

-        if (cinuse(q)) {

-          assert(!bin_find(m, q));

-          do_check_inuse_chunk(m, q);

-        }

-        else {

-          assert(q == m->dv || bin_find(m, q));

-          assert(lastq == 0 || cinuse(lastq)); /* Not 2 consecutive free */

-          do_check_free_chunk(m, q);

-        }

-        lastq = q;

-        q = next_chunk(q);

-      }

-      s = s->next;

-    }

-  }

-  return sum;

-}

-

-/* Check all properties of malloc_state. */

-static void do_check_malloc_state(mstate m) {

-  bindex_t i;

-  size_t total;

-  /* check bins */

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

-    do_check_smallbin(m, i);

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

-    do_check_treebin(m, i);

-

-  if (m->dvsize != 0) { /* check dv chunk */

-    do_check_any_chunk(m, m->dv);

-    assert(m->dvsize == chunksize(m->dv));

-    assert(m->dvsize >= MIN_CHUNK_SIZE);

-    assert(bin_find(m, m->dv) == 0);

-  }

-

-  if (m->top != 0) {   /* check top chunk */

-    do_check_top_chunk(m, m->top);

-    assert(m->topsize == chunksize(m->top));

-    assert(m->topsize > 0);

-    assert(bin_find(m, m->top) == 0);

-  }

-

-  total = traverse_and_check(m);

-  assert(total <= m->footprint);

-  assert(m->footprint <= m->max_footprint);

-}

-#endif /* DEBUG */

-

-/* ----------------------------- statistics ------------------------------ */

-

-#if !NO_MALLINFO

-static struct mallinfo internal_mallinfo(mstate m) {

-  struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

-  if (!PREACTION(m)) {

-    check_malloc_state(m);

-    if (is_initialized(m)) {

-      size_t nfree = SIZE_T_ONE; /* top always free */

-      size_t mfree = m->topsize + TOP_FOOT_SIZE;

-      size_t sum = mfree;

-      msegmentptr s = &m->seg;

-      while (s != 0) {

-        mchunkptr q = align_as_chunk(s->base);

-        while (segment_holds(s, q) &&

-               q != m->top && q->head != FENCEPOST_HEAD) {

-          size_t sz = chunksize(q);

-          sum += sz;

-          if (!cinuse(q)) {

-            mfree += sz;

-            ++nfree;

-          }

-          q = next_chunk(q);

-        }

-        s = s->next;

-      }

-

-      nm.arena    = sum;

-      nm.ordblks  = nfree;

-      nm.hblkhd   = m->footprint - sum;

-      nm.usmblks  = m->max_footprint;

-      nm.uordblks = m->footprint - mfree;

-      nm.fordblks = mfree;

-      nm.keepcost = m->topsize;

-    }

-

-    POSTACTION(m);

-  }

-  return nm;

-}

-#endif /* !NO_MALLINFO */

-

-static void internal_malloc_stats(mstate m) {

-  if (!PREACTION(m)) {

-    size_t maxfp = 0;

-    size_t fp = 0;

-    size_t used = 0;

-    check_malloc_state(m);

-    if (is_initialized(m)) {

-      msegmentptr s = &m->seg;

-      maxfp = m->max_footprint;

-      fp = m->footprint;

-      used = fp - (m->topsize + TOP_FOOT_SIZE);

-

-      while (s != 0) {

-        mchunkptr q = align_as_chunk(s->base);

-        while (segment_holds(s, q) &&

-               q != m->top && q->head != FENCEPOST_HEAD) {

-          if (!cinuse(q))

-            used -= chunksize(q);

-          q = next_chunk(q);

-        }

-        s = s->next;

-      }

-    }

-

-    fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp));

-    fprintf(stderr, "system bytes     = %10lu\n", (unsigned long)(fp));

-    fprintf(stderr, "in use bytes     = %10lu\n", (unsigned long)(used));

-

-    POSTACTION(m);

-  }

-}

-

-/* ----------------------- Operations on smallbins ----------------------- */

-

-/*

-  Various forms of linking and unlinking are defined as macros.  Even

-  the ones for trees, which are very long but have very short typical

-  paths.  This is ugly but reduces reliance on inlining support of

-  compilers.

-*/

-

-/* Link a free chunk into a smallbin  */

-#define insert_small_chunk(M, P, S) {\

-  bindex_t I  = small_index(S);\

-  mchunkptr B = smallbin_at(M, I);\

-  mchunkptr F = B;\

-  assert(S >= MIN_CHUNK_SIZE);\

-  if (!smallmap_is_marked(M, I))\

-    mark_smallmap(M, I);\

-  else if (RTCHECK(ok_address(M, B->fd)))\

-    F = B->fd;\

-  else {\

-    CORRUPTION_ERROR_ACTION(M);\

-  }\

-  B->fd = P;\

-  F->bk = P;\

-  P->fd = F;\

-  P->bk = B;\

-}

-

-/* Unlink a chunk from a smallbin  */

-#define unlink_small_chunk(M, P, S) {\

-  mchunkptr F = P->fd;\

-  mchunkptr B = P->bk;\

-  bindex_t I = small_index(S);\

-  assert(P != B);\

-  assert(P != F);\

-  assert(chunksize(P) == small_index2size(I));\

-  if (F == B)\

-    clear_smallmap(M, I);\

-  else if (RTCHECK((F == smallbin_at(M,I) || ok_address(M, F)) &&\

-                   (B == smallbin_at(M,I) || ok_address(M, B)))) {\

-    F->bk = B;\

-    B->fd = F;\

-  }\

-  else {\

-    CORRUPTION_ERROR_ACTION(M);\

-  }\

-}

-

-/* Unlink the first chunk from a smallbin */

-#define unlink_first_small_chunk(M, B, P, I) {\

-  mchunkptr F = P->fd;\

-  assert(P != B);\

-  assert(P != F);\

-  assert(chunksize(P) == small_index2size(I));\

-  if (B == F)\

-    clear_smallmap(M, I);\

-  else if (RTCHECK(ok_address(M, F))) {\

-    B->fd = F;\

-    F->bk = B;\

-  }\

-  else {\

-    CORRUPTION_ERROR_ACTION(M);\

-  }\

-}

-

-/* Replace dv node, binning the old one */

-/* Used only when dvsize known to be small */

-#define replace_dv(M, P, S) {\

-  size_t DVS = M->dvsize;\

-  if (DVS != 0) {\

-    mchunkptr DV = M->dv;\

-    assert(is_small(DVS));\

-    insert_small_chunk(M, DV, DVS);\

-  }\

-  M->dvsize = S;\

-  M->dv = P;\

-}

-

-/* ------------------------- Operations on trees ------------------------- */

-

-/* Insert chunk into tree */

-#define insert_large_chunk(M, X, S) {\

-  tbinptr* H;\

-  bindex_t I;\

-  compute_tree_index(S, I);\

-  H = treebin_at(M, I);\

-  X->index = I;\

-  X->child[0] = X->child[1] = 0;\

-  if (!treemap_is_marked(M, I)) {\

-    mark_treemap(M, I);\

-    *H = X;\

-    X->parent = (tchunkptr)H;\

-    X->fd = X->bk = X;\

-  }\

-  else {\

-    tchunkptr T = *H;\

-    size_t K = S << leftshift_for_tree_index(I);\

-    for (;;) {\

-      if (chunksize(T) != S) {\

-        tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\

-        K <<= 1;\

-        if (*C != 0)\

-          T = *C;\

-        else if (RTCHECK(ok_address(M, C))) {\

-          *C = X;\

-          X->parent = T;\

-          X->fd = X->bk = X;\

-          break;\

-        }\

-        else {\

-          CORRUPTION_ERROR_ACTION(M);\

-          break;\

-        }\

-      }\

-      else {\

-        tchunkptr F = T->fd;\

-        if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\

-          T->fd = F->bk = X;\

-          X->fd = F;\

-          X->bk = T;\

-          X->parent = 0;\

-          break;\

-        }\

-        else {\

-          CORRUPTION_ERROR_ACTION(M);\

-          break;\

-        }\

-      }\

-    }\

-  }\

-}

-

-/*

-  Unlink steps:

-

-  1. If x is a chained node, unlink it from its same-sized fd/bk links

-     and choose its bk node as its replacement.

-  2. If x was the last node of its size, but not a leaf node, it must

-     be replaced with a leaf node (not merely one with an open left or

-     right), to make sure that lefts and rights of descendents

-     correspond properly to bit masks.  We use the rightmost descendent

-     of x.  We could use any other leaf, but this is easy to locate and

-     tends to counteract removal of leftmosts elsewhere, and so keeps

-     paths shorter than minimally guaranteed.  This doesn't loop much

-     because on average a node in a tree is near the bottom.

-  3. If x is the base of a chain (i.e., has parent links) relink

-     x's parent and children to x's replacement (or null if none).

-*/

-

-#define unlink_large_chunk(M, X) {\

-  tchunkptr XP = X->parent;\

-  tchunkptr R;\

-  if (X->bk != X) {\

-    tchunkptr F = X->fd;\

-    R = X->bk;\

-    if (RTCHECK(ok_address(M, F))) {\

-      F->bk = R;\

-      R->fd = F;\

-    }\

-    else {\

-      CORRUPTION_ERROR_ACTION(M);\

-    }\

-  }\

-  else {\

-    tchunkptr* RP;\

-    if (((R = *(RP = &(X->child[1]))) != 0) ||\

-        ((R = *(RP = &(X->child[0]))) != 0)) {\

-      tchunkptr* CP;\

-      while ((*(CP = &(R->child[1])) != 0) ||\

-             (*(CP = &(R->child[0])) != 0)) {\

-        R = *(RP = CP);\

-      }\

-      if (RTCHECK(ok_address(M, RP)))\

-        *RP = 0;\

-      else {\

-        CORRUPTION_ERROR_ACTION(M);\

-      }\

-    }\

-  }\

-  if (XP != 0) {\

-    tbinptr* H = treebin_at(M, X->index);\

-    if (X == *H) {\

-      if ((*H = R) == 0) \

-        clear_treemap(M, X->index);\

-    }\

-    else if (RTCHECK(ok_address(M, XP))) {\

-      if (XP->child[0] == X) \

-        XP->child[0] = R;\

-      else \

-        XP->child[1] = R;\

-    }\

-    else\

-      CORRUPTION_ERROR_ACTION(M);\

-    if (R != 0) {\

-      if (RTCHECK(ok_address(M, R))) {\

-        tchunkptr C0, C1;\

-        R->parent = XP;\

-        if ((C0 = X->child[0]) != 0) {\

-          if (RTCHECK(ok_address(M, C0))) {\

-            R->child[0] = C0;\

-            C0->parent = R;\

-          }\

-          else\

-            CORRUPTION_ERROR_ACTION(M);\

-        }\

-        if ((C1 = X->child[1]) != 0) {\

-          if (RTCHECK(ok_address(M, C1))) {\

-            R->child[1] = C1;\

-            C1->parent = R;\

-          }\

-          else\

-            CORRUPTION_ERROR_ACTION(M);\

-        }\

-      }\

-      else\

-        CORRUPTION_ERROR_ACTION(M);\

-    }\

-  }\

-}

-

-/* Relays to large vs small bin operations */

-

-#define insert_chunk(M, P, S)\

-  if (is_small(S)) insert_small_chunk(M, P, S)\

-  else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); }

-

-#define unlink_chunk(M, P, S)\

-  if (is_small(S)) unlink_small_chunk(M, P, S)\

-  else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); }

-

-

-/* Relays to internal calls to malloc/free from realloc, memalign etc */

-

-#if ONLY_MSPACES

-#define internal_malloc(m, b) mspace_malloc(m, b)

-#define internal_free(m, mem) mspace_free(m,mem);

-#else /* ONLY_MSPACES */

-#if MSPACES

-#define internal_malloc(m, b)\

-   (m == gm)? dlmalloc(b) : mspace_malloc(m, b)

-#define internal_free(m, mem)\

-   if (m == gm) dlfree(mem); else mspace_free(m,mem);

-#else /* MSPACES */

-#define internal_malloc(m, b) dlmalloc(b)

-#define internal_free(m, mem) dlfree(mem)

-#endif /* MSPACES */

-#endif /* ONLY_MSPACES */

-

-/* -----------------------  Direct-mmapping chunks ----------------------- */

-

-/*

-  Directly mmapped chunks are set up with an offset to the start of

-  the mmapped region stored in the prev_foot field of the chunk. This

-  allows reconstruction of the required argument to MUNMAP when freed,

-  and also allows adjustment of the returned chunk to meet alignment

-  requirements (especially in memalign).  There is also enough space

-  allocated to hold a fake next chunk of size SIZE_T_SIZE to maintain

-  the PINUSE bit so frees can be checked.

-*/

-

-/* Malloc using mmap */

-static void* mmap_alloc(mstate m, size_t nb) {

-  size_t mmsize = granularity_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);

-  if (mmsize > nb) {     /* Check for wrap around 0 */

-    char* mm = (char*)(DIRECT_MMAP(mmsize));

-    if (mm != CMFAIL) {

-      size_t offset = align_offset(chunk2mem(mm));

-      size_t psize = mmsize - offset - MMAP_FOOT_PAD;

-      mchunkptr p = (mchunkptr)(mm + offset);

-      p->prev_foot = offset | IS_MMAPPED_BIT;

-      (p)->head = (psize|CINUSE_BIT);

-      mark_inuse_foot(m, p, psize);

-      chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD;

-      chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0;

-

-      if (mm < m->least_addr)

-        m->least_addr = mm;

-      if ((m->footprint += mmsize) > m->max_footprint)

-        m->max_footprint = m->footprint;

-      assert(is_aligned(chunk2mem(p)));

-      check_mmapped_chunk(m, p);

-      return chunk2mem(p);

-    }

-  }

-  return 0;

-}

-

-/* Realloc using mmap */

-static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb) {

-  size_t oldsize = chunksize(oldp);

-  if (is_small(nb)) /* Can't shrink mmap regions below small size */

-    return 0;

-  /* Keep old chunk if big enough but not too big */

-  if (oldsize >= nb + SIZE_T_SIZE &&

-      (oldsize - nb) <= (mparams.granularity << 1))

-    return oldp;

-  else {

-    size_t offset = oldp->prev_foot & ~IS_MMAPPED_BIT;

-    size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD;

-    size_t newmmsize = granularity_align(nb + SIX_SIZE_T_SIZES +

-                                         CHUNK_ALIGN_MASK);

-    char* cp = (char*)CALL_MREMAP((char*)oldp - offset,

-                                  oldmmsize, newmmsize, 1);

-    if (cp != CMFAIL) {

-      mchunkptr newp = (mchunkptr)(cp + offset);

-      size_t psize = newmmsize - offset - MMAP_FOOT_PAD;

-      newp->head = (psize|CINUSE_BIT);

-      mark_inuse_foot(m, newp, psize);

-      chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD;

-      chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0;

-

-      if (cp < m->least_addr)

-        m->least_addr = cp;

-      if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint)

-        m->max_footprint = m->footprint;

-      check_mmapped_chunk(m, newp);

-      return newp;

-    }

-  }

-  return 0;

-}

-

-/* -------------------------- mspace management -------------------------- */

-

-/* Initialize top chunk and its size */

-static void init_top(mstate m, mchunkptr p, size_t psize) {

-  /* Ensure alignment */

-  size_t offset = align_offset(chunk2mem(p));

-  p = (mchunkptr)((char*)p + offset);

-  psize -= offset;

-

-  m->top = p;

-  m->topsize = psize;

-  p->head = psize | PINUSE_BIT;

-  /* set size of fake trailing chunk holding overhead space only once */

-  chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE;

-  m->trim_check = mparams.trim_threshold; /* reset on each update */

-}

-

-/* Initialize bins for a new mstate that is otherwise zeroed out */

-static void init_bins(mstate m) {

-  /* Establish circular links for smallbins */

-  bindex_t i;

-  for (i = 0; i < NSMALLBINS; ++i) {

-    sbinptr bin = smallbin_at(m,i);

-    bin->fd = bin->bk = bin;

-  }

-}

-

-#if PROCEED_ON_ERROR

-

-/* default corruption action */

-static void reset_on_error(mstate m) {

-  int i;

-  ++malloc_corruption_error_count;

-  /* Reinitialize fields to forget about all memory */

-  m->smallbins = m->treebins = 0;

-  m->dvsize = m->topsize = 0;

-  m->seg.base = 0;

-  m->seg.size = 0;

-  m->seg.next = 0;

-  m->top = m->dv = 0;

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

-    *treebin_at(m, i) = 0;

-  init_bins(m);

-}

-#endif /* PROCEED_ON_ERROR */

-

-/* Allocate chunk and prepend remainder with chunk in successor base. */

-static void* prepend_alloc(mstate m, char* newbase, char* oldbase,

-                           size_t nb) {

-  mchunkptr p = align_as_chunk(newbase);

-  mchunkptr oldfirst = align_as_chunk(oldbase);

-  size_t psize = (char*)oldfirst - (char*)p;

-  mchunkptr q = chunk_plus_offset(p, nb);

-  size_t qsize = psize - nb;

-  set_size_and_pinuse_of_inuse_chunk(m, p, nb);

-

-  assert((char*)oldfirst > (char*)q);

-  assert(pinuse(oldfirst));

-  assert(qsize >= MIN_CHUNK_SIZE);

-

-  /* consolidate remainder with first chunk of old base */

-  if (oldfirst == m->top) {

-    size_t tsize = m->topsize += qsize;

-    m->top = q;

-    q->head = tsize | PINUSE_BIT;

-    check_top_chunk(m, q);

-  }

-  else if (oldfirst == m->dv) {

-    size_t dsize = m->dvsize += qsize;

-    m->dv = q;

-    set_size_and_pinuse_of_free_chunk(q, dsize);

-  }

-  else {

-    if (!cinuse(oldfirst)) {

-      size_t nsize = chunksize(oldfirst);

-      unlink_chunk(m, oldfirst, nsize);

-      oldfirst = chunk_plus_offset(oldfirst, nsize);

-      qsize += nsize;

-    }

-    set_free_with_pinuse(q, qsize, oldfirst);

-    insert_chunk(m, q, qsize);

-    check_free_chunk(m, q);

-  }

-

-  check_malloced_chunk(m, chunk2mem(p), nb);

-  return chunk2mem(p);

-}

-

-

-/* Add a segment to hold a new noncontiguous region */

-static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) {

-  /* Determine locations and sizes of segment, fenceposts, old top */

-  char* old_top = (char*)m->top;

-  msegmentptr oldsp = segment_holding(m, old_top);

-  char* old_end = oldsp->base + oldsp->size;

-  size_t ssize = pad_request(sizeof(struct malloc_segment));

-  char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK);

-  size_t offset = align_offset(chunk2mem(rawsp));

-  char* asp = rawsp + offset;

-  char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp;

-  mchunkptr sp = (mchunkptr)csp;

-  msegmentptr ss = (msegmentptr)(chunk2mem(sp));

-  mchunkptr tnext = chunk_plus_offset(sp, ssize);

-  mchunkptr p = tnext;

-  int nfences = 0;

-

-  /* reset top to new space */

-  init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);

-

-  /* Set up segment record */

-  assert(is_aligned(ss));

-  set_size_and_pinuse_of_inuse_chunk(m, sp, ssize);

-  *ss = m->seg; /* Push current record */

-  m->seg.base = tbase;

-  m->seg.size = tsize;

-  m->seg.sflags = mmapped;

-  m->seg.next = ss;

-

-  /* Insert trailing fenceposts */

-  for (;;) {

-    mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE);

-    p->head = FENCEPOST_HEAD;

-    ++nfences;

-    if ((char*)(&(nextp->head)) < old_end)

-      p = nextp;

-    else

-      break;

-  }

-  assert(nfences >= 2);

-

-  /* Insert the rest of old top into a bin as an ordinary free chunk */

-  if (csp != old_top) {

-    mchunkptr q = (mchunkptr)old_top;

-    size_t psize = csp - old_top;

-    mchunkptr tn = chunk_plus_offset(q, psize);

-    set_free_with_pinuse(q, psize, tn);

-    insert_chunk(m, q, psize);

-  }

-

-  check_top_chunk(m, m->top);

-}

-

-/* -------------------------- System allocation -------------------------- */

-

-/* Get memory from system using MORECORE or MMAP */

-static void* sys_alloc(mstate m, size_t nb) {

-  char* tbase = CMFAIL;

-  size_t tsize = 0;

-  flag_t mmap_flag = 0;

-

-  init_mparams();

-

-  /* Directly map large chunks */

-  if (use_mmap(m) && nb >= mparams.mmap_threshold) {

-    void* mem = mmap_alloc(m, nb);

-    if (mem != 0)

-      return mem;

-  }

-

-  /*

-    Try getting memory in any of three ways (in most-preferred to

-    least-preferred order):

-    1. A call to MORECORE that can normally contiguously extend memory.

-       (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or

-       or main space is mmapped or a previous contiguous call failed)

-    2. A call to MMAP new space (disabled if not HAVE_MMAP).

-       Note that under the default settings, if MORECORE is unable to

-       fulfill a request, and HAVE_MMAP is true, then mmap is

-       used as a noncontiguous system allocator. This is a useful backup

-       strategy for systems with holes in address spaces -- in this case

-       sbrk cannot contiguously expand the heap, but mmap may be able to

-       find space.

-    3. A call to MORECORE that cannot usually contiguously extend memory.

-       (disabled if not HAVE_MORECORE)

-  */

-

-  if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) {

-    char* br = CMFAIL;

-    msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top);

-    size_t asize = 0;

-    ACQUIRE_MORECORE_LOCK();

-

-    if (ss == 0) {  /* First time through or recovery */

-      char* base = (char*)CALL_MORECORE(0);

-      if (base != CMFAIL) {

-        asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE);

-        /* Adjust to end on a page boundary */

-        if (!is_page_aligned(base))

-          asize += (page_align((size_t)base) - (size_t)base);

-        /* Can't call MORECORE if size is negative when treated as signed */

-        if (asize < HALF_MAX_SIZE_T &&

-            (br = (char*)(CALL_MORECORE(asize))) == base) {

-          tbase = base;

-          tsize = asize;

-        }

-      }

-    }

-    else {

-      /* Subtract out existing available top space from MORECORE request. */

-      asize = granularity_align(nb - m->topsize + TOP_FOOT_SIZE + SIZE_T_ONE);

-      /* Use mem here only if it did continuously extend old space */

-      if (asize < HALF_MAX_SIZE_T &&

-          (br = (char*)(CALL_MORECORE(asize))) == ss->base+ss->size) {

-        tbase = br;

-        tsize = asize;

-      }

-    }

-

-    if (tbase == CMFAIL) {    /* Cope with partial failure */

-      if (br != CMFAIL) {    /* Try to use/extend the space we did get */

-        if (asize < HALF_MAX_SIZE_T &&

-            asize < nb + TOP_FOOT_SIZE + SIZE_T_ONE) {

-          size_t esize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE - asize);

-          if (esize < HALF_MAX_SIZE_T) {

-            char* end = (char*)CALL_MORECORE(esize);

-            if (end != CMFAIL)

-              asize += esize;

-            else {            /* Can't use; try to release */

-              CALL_MORECORE(-asize);

-              br = CMFAIL;

-            }

-          }

-        }

-      }

-      if (br != CMFAIL) {    /* Use the space we did get */

-        tbase = br;

-        tsize = asize;

-      }

-      else

-        disable_contiguous(m); /* Don't try contiguous path in the future */

-    }

-

-    RELEASE_MORECORE_LOCK();

-  }

-

-  if (HAVE_MMAP && tbase == CMFAIL) {  /* Try MMAP */

-    size_t req = nb + TOP_FOOT_SIZE + SIZE_T_ONE;

-    size_t rsize = granularity_align(req);

-    if (rsize > nb) { /* Fail if wraps around zero */

-      char* mp = (char*)(CALL_MMAP(rsize));

-      if (mp != CMFAIL) {

-        tbase = mp;

-        tsize = rsize;

-        mmap_flag = IS_MMAPPED_BIT;

-      }

-    }

-  }

-

-  if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */

-    size_t asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE);

-    if (asize < HALF_MAX_SIZE_T) {

-      char* br = CMFAIL;

-      char* end = CMFAIL;

-      ACQUIRE_MORECORE_LOCK();

-      br = (char*)(CALL_MORECORE(asize));

-      end = (char*)(CALL_MORECORE(0));

-      RELEASE_MORECORE_LOCK();

-      if (br != CMFAIL && end != CMFAIL && br < end) {

-        size_t ssize = end - br;

-        if (ssize > nb + TOP_FOOT_SIZE) {

-          tbase = br;

-          tsize = ssize;

-        }

-      }

-    }

-  }

-

-  if (tbase != CMFAIL) {

-

-    if ((m->footprint += tsize) > m->max_footprint)

-      m->max_footprint = m->footprint;

-

-    if (!is_initialized(m)) { /* first-time initialization */

-      m->seg.base = m->least_addr = tbase;

-      m->seg.size = tsize;

-      m->seg.sflags = mmap_flag;

-      m->magic = mparams.magic;

-      init_bins(m);

-      if (is_global(m))

-        init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);

-      else {

-        /* Offset top by embedded malloc_state */

-        mchunkptr mn = next_chunk(mem2chunk(m));

-        init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE);

-      }

-    }

-

-    else {

-      /* Try to merge with an existing segment */

-      msegmentptr sp = &m->seg;

-      while (sp != 0 && tbase != sp->base + sp->size)

-        sp = sp->next;

-      if (sp != 0 &&

-          !is_extern_segment(sp) &&

-          (sp->sflags & IS_MMAPPED_BIT) == mmap_flag &&

-          segment_holds(sp, m->top)) { /* append */

-        sp->size += tsize;

-        init_top(m, m->top, m->topsize + tsize);

-      }

-      else {

-        if (tbase < m->least_addr)

-          m->least_addr = tbase;

-        sp = &m->seg;

-        while (sp != 0 && sp->base != tbase + tsize)

-          sp = sp->next;

-        if (sp != 0 &&

-            !is_extern_segment(sp) &&

-            (sp->sflags & IS_MMAPPED_BIT) == mmap_flag) {

-          char* oldbase = sp->base;

-          sp->base = tbase;

-          sp->size += tsize;

-          return prepend_alloc(m, tbase, oldbase, nb);

-        }

-        else

-          add_segment(m, tbase, tsize, mmap_flag);

-      }

-    }

-

-    if (nb < m->topsize) { /* Allocate from new or extended top space */

-      size_t rsize = m->topsize -= nb;

-      mchunkptr p = m->top;

-      mchunkptr r = m->top = chunk_plus_offset(p, nb);

-      r->head = rsize | PINUSE_BIT;

-      set_size_and_pinuse_of_inuse_chunk(m, p, nb);

-      check_top_chunk(m, m->top);

-      check_malloced_chunk(m, chunk2mem(p), nb);

-      return chunk2mem(p);

-    }

-  }

-

-  MALLOC_FAILURE_ACTION;

-  return 0;

-}

-

-/* -----------------------  system deallocation -------------------------- */

-

-/* Unmap and unlink any mmapped segments that don't contain used chunks */

-static size_t release_unused_segments(mstate m) {

-  size_t released = 0;

-  msegmentptr pred = &m->seg;

-  msegmentptr sp = pred->next;

-  while (sp != 0) {

-    char* base = sp->base;

-    size_t size = sp->size;

-    msegmentptr next = sp->next;

-    if (is_mmapped_segment(sp) && !is_extern_segment(sp)) {

-      mchunkptr p = align_as_chunk(base);

-      size_t psize = chunksize(p);

-      /* Can unmap if first chunk holds entire segment and not pinned */

-      if (!cinuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) {

-        tchunkptr tp = (tchunkptr)p;

-        assert(segment_holds(sp, (char*)sp));

-        if (p == m->dv) {

-          m->dv = 0;

-          m->dvsize = 0;

-        }

-        else {

-          unlink_large_chunk(m, tp);

-        }

-        if (CALL_MUNMAP(base, size) == 0) {

-          released += size;

-          m->footprint -= size;

-          /* unlink obsoleted record */

-          sp = pred;

-          sp->next = next;

-        }

-        else { /* back out if cannot unmap */

-          insert_large_chunk(m, tp, psize);

-        }

-      }

-    }

-    pred = sp;

-    sp = next;

-  }

-  return released;

-}

-

-static int sys_trim(mstate m, size_t pad) {

-  size_t released = 0;

-  if (pad < MAX_REQUEST && is_initialized(m)) {

-    pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */

-

-    if (m->topsize > pad) {

-      /* Shrink top space in granularity-size units, keeping at least one */

-      size_t unit = mparams.granularity;

-      size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit -

-                      SIZE_T_ONE) * unit;

-      msegmentptr sp = segment_holding(m, (char*)m->top);

-

-      if (!is_extern_segment(sp)) {

-        if (is_mmapped_segment(sp)) {

-          if (HAVE_MMAP &&

-              sp->size >= extra &&

-              !has_segment_link(m, sp)) { /* can't shrink if pinned */

-            size_t newsize = sp->size - extra;

-            /* Prefer mremap, fall back to munmap */

-            if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) ||

-                (CALL_MUNMAP(sp->base + newsize, extra) == 0)) {

-              released = extra;

-            }

-          }

-        }

-        else if (HAVE_MORECORE) {

-          if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */

-            extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit;

-          ACQUIRE_MORECORE_LOCK();

-          {

-            /* Make sure end of memory is where we last set it. */

-            char* old_br = (char*)(CALL_MORECORE(0));

-            if (old_br == sp->base + sp->size) {

-              char* rel_br = (char*)(CALL_MORECORE(-extra));

-              char* new_br = (char*)(CALL_MORECORE(0));

-              if (rel_br != CMFAIL && new_br < old_br)

-                released = old_br - new_br;

-            }

-          }

-          RELEASE_MORECORE_LOCK();

-        }

-      }

-

-      if (released != 0) {

-        sp->size -= released;

-        m->footprint -= released;

-        init_top(m, m->top, m->topsize - released);

-        check_top_chunk(m, m->top);

-      }

-    }

-

-    /* Unmap any unused mmapped segments */

-    if (HAVE_MMAP)

-      released += release_unused_segments(m);

-

-    /* On failure, disable autotrim to avoid repeated failed future calls */

-    if (released == 0)

-      m->trim_check = MAX_SIZE_T;

-  }

-

-  return (released != 0)? 1 : 0;

-}

-

-/* ---------------------------- malloc support --------------------------- */

-

-/* allocate a large request from the best fitting chunk in a treebin */

-static void* tmalloc_large(mstate m, size_t nb) {

-  tchunkptr v = 0;

-  size_t rsize = -nb; /* Unsigned negation */

-  tchunkptr t;

-  bindex_t idx;

-  compute_tree_index(nb, idx);

-

-  if ((t = *treebin_at(m, idx)) != 0) {

-    /* Traverse tree for this bin looking for node with size == nb */

-    size_t sizebits = nb << leftshift_for_tree_index(idx);

-    tchunkptr rst = 0;  /* The deepest untaken right subtree */

-    for (;;) {

-      tchunkptr rt;

-      size_t trem = chunksize(t) - nb;

-      if (trem < rsize) {

-        v = t;

-        if ((rsize = trem) == 0)

-          break;

-      }

-      rt = t->child[1];

-      t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];

-      if (rt != 0 && rt != t)

-        rst = rt;

-      if (t == 0) {

-        t = rst; /* set t to least subtree holding sizes > nb */

-        break;

-      }

-      sizebits <<= 1;

-    }

-  }

-

-  if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */

-    binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;

-    if (leftbits != 0) {

-      bindex_t i;

-      binmap_t leastbit = least_bit(leftbits);

-      compute_bit2idx(leastbit, i);

-      t = *treebin_at(m, i);

-    }

-  }

-

-  while (t != 0) { /* find smallest of tree or subtree */

-    size_t trem = chunksize(t) - nb;

-    if (trem < rsize) {

-      rsize = trem;

-      v = t;

-    }

-    t = leftmost_child(t);

-  }

-

-  /*  If dv is a better fit, return 0 so malloc will use it */

-  if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {

-    if (RTCHECK(ok_address(m, v))) { /* split */

-      mchunkptr r = chunk_plus_offset(v, nb);

-      assert(chunksize(v) == rsize + nb);

-      if (RTCHECK(ok_next(v, r))) {

-        unlink_large_chunk(m, v);

-        if (rsize < MIN_CHUNK_SIZE)

-          set_inuse_and_pinuse(m, v, (rsize + nb));

-        else {

-          set_size_and_pinuse_of_inuse_chunk(m, v, nb);

-          set_size_and_pinuse_of_free_chunk(r, rsize);

-          insert_chunk(m, r, rsize);

-        }

-        return chunk2mem(v);

-      }

-    }

-    CORRUPTION_ERROR_ACTION(m);

-  }

-  return 0;

-}

-

-/* allocate a small request from the best fitting chunk in a treebin */

-static void* tmalloc_small(mstate m, size_t nb) {

-  tchunkptr t, v;

-  size_t rsize;

-  bindex_t i;

-  binmap_t leastbit = least_bit(m->treemap);

-  compute_bit2idx(leastbit, i);

-

-  v = t = *treebin_at(m, i);

-  rsize = chunksize(t) - nb;

-

-  while ((t = leftmost_child(t)) != 0) {

-    size_t trem = chunksize(t) - nb;

-    if (trem < rsize) {

-      rsize = trem;

-      v = t;

-    }

-  }

-

-  if (RTCHECK(ok_address(m, v))) {

-    mchunkptr r = chunk_plus_offset(v, nb);

-    assert(chunksize(v) == rsize + nb);

-    if (RTCHECK(ok_next(v, r))) {

-      unlink_large_chunk(m, v);

-      if (rsize < MIN_CHUNK_SIZE)

-        set_inuse_and_pinuse(m, v, (rsize + nb));

-      else {

-        set_size_and_pinuse_of_inuse_chunk(m, v, nb);

-        set_size_and_pinuse_of_free_chunk(r, rsize);

-        replace_dv(m, r, rsize);

-      }

-      return chunk2mem(v);

-    }

-  }

-

-  CORRUPTION_ERROR_ACTION(m);

-  return 0;

-}

-

-/* --------------------------- realloc support --------------------------- */

-

-static void* internal_realloc(mstate m, void* oldmem, size_t bytes) {

-  if (bytes >= MAX_REQUEST) {

-    MALLOC_FAILURE_ACTION;

-    return 0;

-  }

-  if (!PREACTION(m)) {

-    mchunkptr oldp = mem2chunk(oldmem);

-    size_t oldsize = chunksize(oldp);

-    mchunkptr next = chunk_plus_offset(oldp, oldsize);

-    mchunkptr newp = 0;

-    void* extra = 0;

-

-    /* Try to either shrink or extend into top. Else malloc-copy-free */

-

-    if (RTCHECK(ok_address(m, oldp) && ok_cinuse(oldp) &&

-                ok_next(oldp, next) && ok_pinuse(next))) {

-      size_t nb = request2size(bytes);

-      if (is_mmapped(oldp))

-        newp = mmap_resize(m, oldp, nb);

-      else if (oldsize >= nb) { /* already big enough */

-        size_t rsize = oldsize - nb;

-        newp = oldp;

-        if (rsize >= MIN_CHUNK_SIZE) {

-          mchunkptr remainder = chunk_plus_offset(newp, nb);

-          set_inuse(m, newp, nb);

-          set_inuse(m, remainder, rsize);

-          extra = chunk2mem(remainder);

-        }

-      }

-      else if (next == m->top && oldsize + m->topsize > nb) {

-        /* Expand into top */

-        size_t newsize = oldsize + m->topsize;

-        size_t newtopsize = newsize - nb;

-        mchunkptr newtop = chunk_plus_offset(oldp, nb);

-        set_inuse(m, oldp, nb);

-        newtop->head = newtopsize |PINUSE_BIT;

-        m->top = newtop;

-        m->topsize = newtopsize;

-        newp = oldp;

-      }

-    }

-    else {

-      USAGE_ERROR_ACTION(m, oldmem);

-      POSTACTION(m);

-      return 0;

-    }

-

-    POSTACTION(m);

-

-    if (newp != 0) {

-      if (extra != 0) {

-        internal_free(m, extra);

-      }

-      check_inuse_chunk(m, newp);

-      return chunk2mem(newp);

-    }

-    else {

-      void* newmem = internal_malloc(m, bytes);

-      if (newmem != 0) {

-        size_t oc = oldsize - overhead_for(oldp);

-        memcpy(newmem, oldmem, (oc < bytes)? oc : bytes);

-        internal_free(m, oldmem);

-      }

-      return newmem;

-    }

-  }

-  return 0;

-}

-

-/* --------------------------- memalign support -------------------------- */

-

-static void* internal_memalign(mstate m, size_t alignment, size_t bytes) {

-  if (alignment <= MALLOC_ALIGNMENT)    /* Can just use malloc */

-    return internal_malloc(m, bytes);

-  if (alignment <  MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */

-    alignment = MIN_CHUNK_SIZE;

-  if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */

-    size_t a = MALLOC_ALIGNMENT << 1;

-    while (a < alignment) a <<= 1;

-    alignment = a;

-  }

-

-  if (bytes >= MAX_REQUEST - alignment) {

-    if (m != 0)  { /* Test isn't needed but avoids compiler warning */

-      MALLOC_FAILURE_ACTION;

-    }

-  }

-  else {

-    size_t nb = request2size(bytes);

-    size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;

-    char* mem = (char*)internal_malloc(m, req);

-    if (mem != 0) {

-      void* leader = 0;

-      void* trailer = 0;

-      mchunkptr p = mem2chunk(mem);

-

-      if (PREACTION(m)) return 0;

-      if ((((size_t)(mem)) % alignment) != 0) { /* misaligned */

-        /*

-          Find an aligned spot inside chunk.  Since we need to give

-          back leading space in a chunk of at least MIN_CHUNK_SIZE, if

-          the first calculation places us at a spot with less than

-          MIN_CHUNK_SIZE leader, we can move to the next aligned spot.

-          We've allocated enough total room so that this is always

-          possible.

-        */

-        char* br = (char*)mem2chunk((size_t)(((size_t)(mem +

-                                                       alignment -

-                                                       SIZE_T_ONE)) &

-                                             -alignment));

-        char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)?

-          br : br+alignment;

-        mchunkptr newp = (mchunkptr)pos;

-        size_t leadsize = pos - (char*)(p);

-        size_t newsize = chunksize(p) - leadsize;

-

-        if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */

-          newp->prev_foot = p->prev_foot + leadsize;

-          newp->head = (newsize|CINUSE_BIT);

-        }

-        else { /* Otherwise, give back leader, use the rest */

-          set_inuse(m, newp, newsize);

-          set_inuse(m, p, leadsize);

-          leader = chunk2mem(p);

-        }

-        p = newp;

-      }

-

-      /* Give back spare room at the end */

-      if (!is_mmapped(p)) {

-        size_t size = chunksize(p);

-        if (size > nb + MIN_CHUNK_SIZE) {

-          size_t remainder_size = size - nb;

-          mchunkptr remainder = chunk_plus_offset(p, nb);

-          set_inuse(m, p, nb);

-          set_inuse(m, remainder, remainder_size);

-          trailer = chunk2mem(remainder);

-        }

-      }

-

-      assert (chunksize(p) >= nb);

-      assert((((size_t)(chunk2mem(p))) % alignment) == 0);

-      check_inuse_chunk(m, p);

-      POSTACTION(m);

-      if (leader != 0) {

-        internal_free(m, leader);

-      }

-      if (trailer != 0) {

-        internal_free(m, trailer);

-      }

-      return chunk2mem(p);

-    }

-  }

-  return 0;

-}

-

-/* ------------------------ comalloc/coalloc support --------------------- */

-

-static void** ialloc(mstate m,

-                     size_t n_elements,

-                     size_t* sizes,

-                     int opts,

-                     void* chunks[]) {

-  /*

-    This provides common support for independent_X routines, handling

-    all of the combinations that can result.

-

-    The opts arg has:

-    bit 0 set if all elements are same size (using sizes[0])

-    bit 1 set if elements should be zeroed

-  */

-

-  size_t    element_size;   /* chunksize of each element, if all same */

-  size_t    contents_size;  /* total size of elements */

-  size_t    array_size;     /* request size of pointer array */

-  void*     mem;            /* malloced aggregate space */

-  mchunkptr p;              /* corresponding chunk */

-  size_t    remainder_size; /* remaining bytes while splitting */

-  void**    marray;         /* either "chunks" or malloced ptr array */

-  mchunkptr array_chunk;    /* chunk for malloced ptr array */

-  flag_t    was_enabled;    /* to disable mmap */

-  size_t    size;

-  size_t    i;

-

-  /* compute array length, if needed */

-  if (chunks != 0) {

-    if (n_elements == 0)

-      return chunks; /* nothing to do */

-    marray = chunks;

-    array_size = 0;

-  }

-  else {

-    /* if empty req, must still return chunk representing empty array */

-    if (n_elements == 0)

-      return (void**)internal_malloc(m, 0);

-    marray = 0;

-    array_size = request2size(n_elements * (sizeof(void*)));

-  }

-

-  /* compute total element size */

-  if (opts & 0x1) { /* all-same-size */

-    element_size = request2size(*sizes);

-    contents_size = n_elements * element_size;

-  }

-  else { /* add up all the sizes */

-    element_size = 0;

-    contents_size = 0;

-    for (i = 0; i != n_elements; ++i)

-      contents_size += request2size(sizes[i]);

-  }

-

-  size = contents_size + array_size;

-

-  /*

-     Allocate the aggregate chunk.  First disable direct-mmapping so

-     malloc won't use it, since we would not be able to later

-     free/realloc space internal to a segregated mmap region.

-  */

-  was_enabled = use_mmap(m);

-  disable_mmap(m);

-  mem = internal_malloc(m, size - CHUNK_OVERHEAD);

-  if (was_enabled)

-    enable_mmap(m);

-  if (mem == 0)

-    return 0;

-

-  if (PREACTION(m)) return 0;

-  p = mem2chunk(mem);

-  remainder_size = chunksize(p);

-

-  assert(!is_mmapped(p));

-

-  if (opts & 0x2) {       /* optionally clear the elements */

-    memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size);

-  }

-

-  /* If not provided, allocate the pointer array as final part of chunk */

-  if (marray == 0) {

-    size_t  array_chunk_size;

-    array_chunk = chunk_plus_offset(p, contents_size);

-    array_chunk_size = remainder_size - contents_size;

-    marray = (void**) (chunk2mem(array_chunk));

-    set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size);

-    remainder_size = contents_size;

-  }

-

-  /* split out elements */

-  for (i = 0; ; ++i) {

-    marray[i] = chunk2mem(p);

-    if (i != n_elements-1) {

-      if (element_size != 0)

-        size = element_size;

-      else

-        size = request2size(sizes[i]);

-      remainder_size -= size;

-      set_size_and_pinuse_of_inuse_chunk(m, p, size);

-      p = chunk_plus_offset(p, size);

-    }

-    else { /* the final element absorbs any overallocation slop */

-      set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size);

-      break;

-    }

-  }

-

-#if DEBUG

-  if (marray != chunks) {

-    /* final element must have exactly exhausted chunk */

-    if (element_size != 0) {

-      assert(remainder_size == element_size);

-    }

-    else {

-      assert(remainder_size == request2size(sizes[i]));

-    }

-    check_inuse_chunk(m, mem2chunk(marray));

-  }

-  for (i = 0; i != n_elements; ++i)

-    check_inuse_chunk(m, mem2chunk(marray[i]));

-

-#endif /* DEBUG */

-

-  POSTACTION(m);

-  return marray;

-}

-

-

-/* -------------------------- public routines ---------------------------- */

-

-#if !ONLY_MSPACES

-

-void* dlmalloc(size_t bytes) {

-  /*

-     Basic algorithm:

-     If a small request (< 256 bytes minus per-chunk overhead):

-       1. If one exists, use a remainderless chunk in associated smallbin.

-          (Remainderless means that there are too few excess bytes to

-          represent as a chunk.)

-       2. If it is big enough, use the dv chunk, which is normally the

-          chunk adjacent to the one used for the most recent small request.

-       3. If one exists, split the smallest available chunk in a bin,

-          saving remainder in dv.

-       4. If it is big enough, use the top chunk.

-       5. If available, get memory from system and use it

-     Otherwise, for a large request:

-       1. Find the smallest available binned chunk that fits, and use it

-          if it is better fitting than dv chunk, splitting if necessary.

-       2. If better fitting than any binned chunk, use the dv chunk.

-       3. If it is big enough, use the top chunk.

-       4. If request size >= mmap threshold, try to directly mmap this chunk.

-       5. If available, get memory from system and use it

-

-     The ugly goto's here ensure that postaction occurs along all paths.

-  */

-

-  if (!PREACTION(gm)) {

-    void* mem;

-    size_t nb;

-    if (bytes <= MAX_SMALL_REQUEST) {

-      bindex_t idx;

-      binmap_t smallbits;

-      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);

-      idx = small_index(nb);

-      smallbits = gm->smallmap >> idx;

-

-      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */

-        mchunkptr b, p;

-        idx += ~smallbits & 1;       /* Uses next bin if idx empty */

-        b = smallbin_at(gm, idx);

-        p = b->fd;

-        assert(chunksize(p) == small_index2size(idx));

-        unlink_first_small_chunk(gm, b, p, idx);

-        set_inuse_and_pinuse(gm, p, small_index2size(idx));

-        mem = chunk2mem(p);

-        check_malloced_chunk(gm, mem, nb);

-        goto postaction;

-      }

-

-      else if (nb > gm->dvsize) {

-        if (smallbits != 0) { /* Use chunk in next nonempty smallbin */

-          mchunkptr b, p, r;

-          size_t rsize;

-          bindex_t i;

-          binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));

-          binmap_t leastbit = least_bit(leftbits);

-          compute_bit2idx(leastbit, i);

-          b = smallbin_at(gm, i);

-          p = b->fd;

-          assert(chunksize(p) == small_index2size(i));

-          unlink_first_small_chunk(gm, b, p, i);

-          rsize = small_index2size(i) - nb;

-          /* Fit here cannot be remainderless if 4byte sizes */

-          if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)

-            set_inuse_and_pinuse(gm, p, small_index2size(i));

-          else {

-            set_size_and_pinuse_of_inuse_chunk(gm, p, nb);

-            r = chunk_plus_offset(p, nb);

-            set_size_and_pinuse_of_free_chunk(r, rsize);

-            replace_dv(gm, r, rsize);

-          }

-          mem = chunk2mem(p);

-          check_malloced_chunk(gm, mem, nb);

-          goto postaction;

-        }

-

-        else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) {

-          check_malloced_chunk(gm, mem, nb);

-          goto postaction;

-        }

-      }

-    }

-    else if (bytes >= MAX_REQUEST)

-      nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */

-    else {

-      nb = pad_request(bytes);

-      if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) {

-        check_malloced_chunk(gm, mem, nb);

-        goto postaction;

-      }

-    }

-

-    if (nb <= gm->dvsize) {

-      size_t rsize = gm->dvsize - nb;

-      mchunkptr p = gm->dv;

-      if (rsize >= MIN_CHUNK_SIZE) { /* split dv */

-        mchunkptr r = gm->dv = chunk_plus_offset(p, nb);

-        gm->dvsize = rsize;

-        set_size_and_pinuse_of_free_chunk(r, rsize);

-        set_size_and_pinuse_of_inuse_chunk(gm, p, nb);

-      }

-      else { /* exhaust dv */

-        size_t dvs = gm->dvsize;

-        gm->dvsize = 0;

-        gm->dv = 0;

-        set_inuse_and_pinuse(gm, p, dvs);

-      }

-      mem = chunk2mem(p);

-      check_malloced_chunk(gm, mem, nb);

-      goto postaction;

-    }

-

-    else if (nb < gm->topsize) { /* Split top */

-      size_t rsize = gm->topsize -= nb;

-      mchunkptr p = gm->top;

-      mchunkptr r = gm->top = chunk_plus_offset(p, nb);

-      r->head = rsize | PINUSE_BIT;

-      set_size_and_pinuse_of_inuse_chunk(gm, p, nb);

-      mem = chunk2mem(p);

-      check_top_chunk(gm, gm->top);

-      check_malloced_chunk(gm, mem, nb);

-      goto postaction;

-    }

-

-    mem = sys_alloc(gm, nb);

-

-  postaction:

-    POSTACTION(gm);

-    return mem;

-  }

-

-  return 0;

-}

-

-void dlfree(void* mem) {

-  /*

-     Consolidate freed chunks with preceeding or succeeding bordering

-     free chunks, if they exist, and then place in a bin.  Intermixed

-     with special cases for top, dv, mmapped chunks, and usage errors.

-  */

-

-  if (mem != 0) {

-    mchunkptr p  = mem2chunk(mem);

-#if FOOTERS

-    mstate fm = get_mstate_for(p);

-    if (!ok_magic(fm)) {

-      USAGE_ERROR_ACTION(fm, p);

-      return;

-    }

-#else /* FOOTERS */

-#define fm gm

-#endif /* FOOTERS */

-    if (!PREACTION(fm)) {

-      check_inuse_chunk(fm, p);

-      if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) {

-        size_t psize = chunksize(p);

-        mchunkptr next = chunk_plus_offset(p, psize);

-        if (!pinuse(p)) {

-          size_t prevsize = p->prev_foot;

-          if ((prevsize & IS_MMAPPED_BIT) != 0) {

-            prevsize &= ~IS_MMAPPED_BIT;

-            psize += prevsize + MMAP_FOOT_PAD;

-            if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)

-              fm->footprint -= psize;

-            goto postaction;

-          }

-          else {

-            mchunkptr prev = chunk_minus_offset(p, prevsize);

-            psize += prevsize;

-            p = prev;

-            if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */

-              if (p != fm->dv) {

-                unlink_chunk(fm, p, prevsize);

-              }

-              else if ((next->head & INUSE_BITS) == INUSE_BITS) {

-                fm->dvsize = psize;

-                set_free_with_pinuse(p, psize, next);

-                goto postaction;

-              }

-            }

-            else

-              goto erroraction;

-          }

-        }

-

-        if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {

-          if (!cinuse(next)) {  /* consolidate forward */

-            if (next == fm->top) {

-              size_t tsize = fm->topsize += psize;

-              fm->top = p;

-              p->head = tsize | PINUSE_BIT;

-              if (p == fm->dv) {

-                fm->dv = 0;

-                fm->dvsize = 0;

-              }

-              if (should_trim(fm, tsize))

-                sys_trim(fm, 0);

-              goto postaction;

-            }

-            else if (next == fm->dv) {

-              size_t dsize = fm->dvsize += psize;

-              fm->dv = p;

-              set_size_and_pinuse_of_free_chunk(p, dsize);

-              goto postaction;

-            }

-            else {

-              size_t nsize = chunksize(next);

-              psize += nsize;

-              unlink_chunk(fm, next, nsize);

-              set_size_and_pinuse_of_free_chunk(p, psize);

-              if (p == fm->dv) {

-                fm->dvsize = psize;

-                goto postaction;

-              }

-            }

-          }

-          else

-            set_free_with_pinuse(p, psize, next);

-          insert_chunk(fm, p, psize);

-          check_free_chunk(fm, p);

-          goto postaction;

-        }

-      }

-    erroraction:

-      USAGE_ERROR_ACTION(fm, p);

-    postaction:

-      POSTACTION(fm);

-    }

-  }

-#if !FOOTERS

-#undef fm

-#endif /* FOOTERS */

-}

-

-void* dlcalloc(size_t n_elements, size_t elem_size) {

-  void* mem;

-  size_t req = 0;

-  if (n_elements != 0) {

-    req = n_elements * elem_size;

-    if (((n_elements | elem_size) & ~(size_t)0xffff) &&

-        (req / n_elements != elem_size))

-      req = MAX_SIZE_T; /* force downstream failure on overflow */

-  }

-  mem = dlmalloc(req);

-  if (mem != 0 && calloc_must_clear(mem2chunk(mem)))

-    memset(mem, 0, req);

-  return mem;

-}

-

-void* dlrealloc(void* oldmem, size_t bytes) {

-  if (oldmem == 0)

-    return dlmalloc(bytes);

-#ifdef REALLOC_ZERO_BYTES_FREES

-  if (bytes == 0) {

-    dlfree(oldmem);

-    return 0;

-  }

-#endif /* REALLOC_ZERO_BYTES_FREES */

-  else {

-#if ! FOOTERS

-    mstate m = gm;

-#else /* FOOTERS */

-    mstate m = get_mstate_for(mem2chunk(oldmem));

-    if (!ok_magic(m)) {

-      USAGE_ERROR_ACTION(m, oldmem);

-      return 0;

-    }

-#endif /* FOOTERS */

-    return internal_realloc(m, oldmem, bytes);

-  }

-}

-

-void* dlmemalign(size_t alignment, size_t bytes) {

-  return internal_memalign(gm, alignment, bytes);

-}

-

-void** dlindependent_calloc(size_t n_elements, size_t elem_size,

-                                 void* chunks[]) {

-  size_t sz = elem_size; /* serves as 1-element array */

-  return ialloc(gm, n_elements, &sz, 3, chunks);

-}

-

-void** dlindependent_comalloc(size_t n_elements, size_t sizes[],

-                                   void* chunks[]) {

-  return ialloc(gm, n_elements, sizes, 0, chunks);

-}

-

-void* dlvalloc(size_t bytes) {

-  size_t pagesz;

-  init_mparams();

-  pagesz = mparams.page_size;

-  return dlmemalign(pagesz, bytes);

-}

-

-void* dlpvalloc(size_t bytes) {

-  size_t pagesz;

-  init_mparams();

-  pagesz = mparams.page_size;

-  return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE));

-}

-

-int dlmalloc_trim(size_t pad) {

-  int result = 0;

-  if (!PREACTION(gm)) {

-    result = sys_trim(gm, pad);

-    POSTACTION(gm);

-  }

-  return result;

-}

-

-size_t dlmalloc_footprint(void) {

-  return gm->footprint;

-}

-

-size_t dlmalloc_max_footprint(void) {

-  return gm->max_footprint;

-}

-

-#if !NO_MALLINFO

-struct mallinfo dlmallinfo(void) {

-  return internal_mallinfo(gm);

-}

-#endif /* NO_MALLINFO */

-

-void dlmalloc_stats() {

-  internal_malloc_stats(gm);

-}

-

-size_t dlmalloc_usable_size(void* mem) {

-  if (mem != 0) {

-    mchunkptr p = mem2chunk(mem);

-    if (cinuse(p))

-      return chunksize(p) - overhead_for(p);

-  }

-  return 0;

-}

-

-int dlmallopt(int param_number, int value) {

-  return change_mparam(param_number, value);

-}

-

-#endif /* !ONLY_MSPACES */

-

-/* ----------------------------- user mspaces ---------------------------- */

-

-#if MSPACES

-

-static mstate init_user_mstate(char* tbase, size_t tsize) {

-  size_t msize = pad_request(sizeof(struct malloc_state));

-  mchunkptr mn;

-  mchunkptr msp = align_as_chunk(tbase);

-  mstate m = (mstate)(chunk2mem(msp));

-  memset(m, 0, msize);

-  INITIAL_LOCK(&m->mutex);

-  msp->head = (msize|PINUSE_BIT|CINUSE_BIT);

-  m->seg.base = m->least_addr = tbase;

-  m->seg.size = m->footprint = m->max_footprint = tsize;

-  m->magic = mparams.magic;

-  m->mflags = mparams.default_mflags;

-  disable_contiguous(m);

-  init_bins(m);

-  mn = next_chunk(mem2chunk(m));

-  init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE);

-  check_top_chunk(m, m->top);

-  return m;

-}

-

-mspace create_mspace(size_t capacity, int locked) {

-  mstate m = 0;

-  size_t msize = pad_request(sizeof(struct malloc_state));

-  init_mparams(); /* Ensure pagesize etc initialized */

-

-  if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {

-    size_t rs = ((capacity == 0)? mparams.granularity :

-                 (capacity + TOP_FOOT_SIZE + msize));

-    size_t tsize = granularity_align(rs);

-    char* tbase = (char*)(CALL_MMAP(tsize));

-    if (tbase != CMFAIL) {

-      m = init_user_mstate(tbase, tsize);

-      m->seg.sflags = IS_MMAPPED_BIT;

-      set_lock(m, locked);

-    }

-  }

-  return (mspace)m;

-}

-

-mspace create_mspace_with_base(void* base, size_t capacity, int locked) {

-  mstate m = 0;

-  size_t msize = pad_request(sizeof(struct malloc_state));

-  init_mparams(); /* Ensure pagesize etc initialized */

-

-  if (capacity > msize + TOP_FOOT_SIZE &&

-      capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {

-    m = init_user_mstate((char*)base, capacity);

-    m->seg.sflags = EXTERN_BIT;

-    set_lock(m, locked);

-  }

-  return (mspace)m;

-}

-

-size_t destroy_mspace(mspace msp) {

-  size_t freed = 0;

-  mstate ms = (mstate)msp;

-  if (ok_magic(ms)) {

-    msegmentptr sp = &ms->seg;

-    while (sp != 0) {

-      char* base = sp->base;

-      size_t size = sp->size;

-      flag_t flag = sp->sflags;

-      sp = sp->next;

-      if ((flag & IS_MMAPPED_BIT) && !(flag & EXTERN_BIT) &&

-          CALL_MUNMAP(base, size) == 0)

-        freed += size;

-    }

-  }

-  else {

-    USAGE_ERROR_ACTION(ms,ms);

-  }

-  return freed;

-}

-

-/*

-  mspace versions of routines are near-clones of the global

-  versions. This is not so nice but better than the alternatives.

-*/

-

-

-void* mspace_malloc(mspace msp, size_t bytes) {

-  mstate ms = (mstate)msp;

-  if (!ok_magic(ms)) {

-    USAGE_ERROR_ACTION(ms,ms);

-    return 0;

-  }

-  if (!PREACTION(ms)) {

-    void* mem;

-    size_t nb;

-    if (bytes <= MAX_SMALL_REQUEST) {

-      bindex_t idx;

-      binmap_t smallbits;

-      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);

-      idx = small_index(nb);

-      smallbits = ms->smallmap >> idx;

-

-      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */

-        mchunkptr b, p;

-        idx += ~smallbits & 1;       /* Uses next bin if idx empty */

-        b = smallbin_at(ms, idx);

-        p = b->fd;

-        assert(chunksize(p) == small_index2size(idx));

-        unlink_first_small_chunk(ms, b, p, idx);

-        set_inuse_and_pinuse(ms, p, small_index2size(idx));

-        mem = chunk2mem(p);

-        check_malloced_chunk(ms, mem, nb);

-        goto postaction;

-      }

-

-      else if (nb > ms->dvsize) {

-        if (smallbits != 0) { /* Use chunk in next nonempty smallbin */

-          mchunkptr b, p, r;

-          size_t rsize;

-          bindex_t i;

-          binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));

-          binmap_t leastbit = least_bit(leftbits);

-          compute_bit2idx(leastbit, i);

-          b = smallbin_at(ms, i);

-          p = b->fd;

-          assert(chunksize(p) == small_index2size(i));

-          unlink_first_small_chunk(ms, b, p, i);

-          rsize = small_index2size(i) - nb;

-          /* Fit here cannot be remainderless if 4byte sizes */

-          if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)

-            set_inuse_and_pinuse(ms, p, small_index2size(i));

-          else {

-            set_size_and_pinuse_of_inuse_chunk(ms, p, nb);

-            r = chunk_plus_offset(p, nb);

-            set_size_and_pinuse_of_free_chunk(r, rsize);

-            replace_dv(ms, r, rsize);

-          }

-          mem = chunk2mem(p);

-          check_malloced_chunk(ms, mem, nb);

-          goto postaction;

-        }

-

-        else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) {

-          check_malloced_chunk(ms, mem, nb);

-          goto postaction;

-        }

-      }

-    }

-    else if (bytes >= MAX_REQUEST)

-      nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */

-    else {

-      nb = pad_request(bytes);

-      if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) {

-        check_malloced_chunk(ms, mem, nb);

-        goto postaction;

-      }

-    }

-

-    if (nb <= ms->dvsize) {

-      size_t rsize = ms->dvsize - nb;

-      mchunkptr p = ms->dv;

-      if (rsize >= MIN_CHUNK_SIZE) { /* split dv */

-        mchunkptr r = ms->dv = chunk_plus_offset(p, nb);

-        ms->dvsize = rsize;

-        set_size_and_pinuse_of_free_chunk(r, rsize);

-        set_size_and_pinuse_of_inuse_chunk(ms, p, nb);

-      }

-      else { /* exhaust dv */

-        size_t dvs = ms->dvsize;

-        ms->dvsize = 0;

-        ms->dv = 0;

-        set_inuse_and_pinuse(ms, p, dvs);

-      }

-      mem = chunk2mem(p);

-      check_malloced_chunk(ms, mem, nb);

-      goto postaction;

-    }

-

-    else if (nb < ms->topsize) { /* Split top */

-      size_t rsize = ms->topsize -= nb;

-      mchunkptr p = ms->top;

-      mchunkptr r = ms->top = chunk_plus_offset(p, nb);

-      r->head = rsize | PINUSE_BIT;

-      set_size_and_pinuse_of_inuse_chunk(ms, p, nb);

-      mem = chunk2mem(p);

-      check_top_chunk(ms, ms->top);

-      check_malloced_chunk(ms, mem, nb);

-      goto postaction;

-    }

-

-    mem = sys_alloc(ms, nb);

-

-  postaction:

-    POSTACTION(ms);

-    return mem;

-  }

-

-  return 0;

-}

-

-void mspace_free(mspace msp, void* mem) {

-  if (mem != 0) {

-    mchunkptr p  = mem2chunk(mem);

-#if FOOTERS

-    mstate fm = get_mstate_for(p);

-#else /* FOOTERS */

-    mstate fm = (mstate)msp;

-#endif /* FOOTERS */

-    if (!ok_magic(fm)) {

-      USAGE_ERROR_ACTION(fm, p);

-      return;

-    }

-    if (!PREACTION(fm)) {

-      check_inuse_chunk(fm, p);

-      if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) {

-        size_t psize = chunksize(p);

-        mchunkptr next = chunk_plus_offset(p, psize);

-        if (!pinuse(p)) {

-          size_t prevsize = p->prev_foot;

-          if ((prevsize & IS_MMAPPED_BIT) != 0) {

-            prevsize &= ~IS_MMAPPED_BIT;

-            psize += prevsize + MMAP_FOOT_PAD;

-            if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)

-              fm->footprint -= psize;

-            goto postaction;

-          }

-          else {

-            mchunkptr prev = chunk_minus_offset(p, prevsize);

-            psize += prevsize;

-            p = prev;

-            if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */

-              if (p != fm->dv) {

-                unlink_chunk(fm, p, prevsize);

-              }

-              else if ((next->head & INUSE_BITS) == INUSE_BITS) {

-                fm->dvsize = psize;

-                set_free_with_pinuse(p, psize, next);

-                goto postaction;

-              }

-            }

-            else

-              goto erroraction;

-          }

-        }

-

-        if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {

-          if (!cinuse(next)) {  /* consolidate forward */

-            if (next == fm->top) {

-              size_t tsize = fm->topsize += psize;

-              fm->top = p;

-              p->head = tsize | PINUSE_BIT;

-              if (p == fm->dv) {

-                fm->dv = 0;

-                fm->dvsize = 0;

-              }

-              if (should_trim(fm, tsize))

-                sys_trim(fm, 0);

-              goto postaction;

-            }

-            else if (next == fm->dv) {

-              size_t dsize = fm->dvsize += psize;

-              fm->dv = p;

-              set_size_and_pinuse_of_free_chunk(p, dsize);

-              goto postaction;

-            }

-            else {

-              size_t nsize = chunksize(next);

-              psize += nsize;

-              unlink_chunk(fm, next, nsize);

-              set_size_and_pinuse_of_free_chunk(p, psize);

-              if (p == fm->dv) {

-                fm->dvsize = psize;

-                goto postaction;

-              }

-            }

-          }

-          else

-            set_free_with_pinuse(p, psize, next);

-          insert_chunk(fm, p, psize);

-          check_free_chunk(fm, p);

-          goto postaction;

-        }

-      }

-    erroraction:

-      USAGE_ERROR_ACTION(fm, p);

-    postaction:

-      POSTACTION(fm);

-    }

-  }

-}

-

-void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) {

-  void* mem;

-  size_t req = 0;

-  mstate ms = (mstate)msp;

-  if (!ok_magic(ms)) {

-    USAGE_ERROR_ACTION(ms,ms);

-    return 0;

-  }

-  if (n_elements != 0) {

-    req = n_elements * elem_size;

-    if (((n_elements | elem_size) & ~(size_t)0xffff) &&

-        (req / n_elements != elem_size))

-      req = MAX_SIZE_T; /* force downstream failure on overflow */

-  }

-  mem = internal_malloc(ms, req);

-  if (mem != 0 && calloc_must_clear(mem2chunk(mem)))

-    memset(mem, 0, req);

-  return mem;

-}

-

-void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) {

-  if (oldmem == 0)

-    return mspace_malloc(msp, bytes);

-#ifdef REALLOC_ZERO_BYTES_FREES

-  if (bytes == 0) {

-    mspace_free(msp, oldmem);

-    return 0;

-  }

-#endif /* REALLOC_ZERO_BYTES_FREES */

-  else {

-#if FOOTERS

-    mchunkptr p  = mem2chunk(oldmem);

-    mstate ms = get_mstate_for(p);

-#else /* FOOTERS */

-    mstate ms = (mstate)msp;

-#endif /* FOOTERS */

-    if (!ok_magic(ms)) {

-      USAGE_ERROR_ACTION(ms,ms);

-      return 0;

-    }

-    return internal_realloc(ms, oldmem, bytes);

-  }

-}

-

-void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) {

-  mstate ms = (mstate)msp;

-  if (!ok_magic(ms)) {

-    USAGE_ERROR_ACTION(ms,ms);

-    return 0;

-  }

-  return internal_memalign(ms, alignment, bytes);

-}

-

-void** mspace_independent_calloc(mspace msp, size_t n_elements,

-                                 size_t elem_size, void* chunks[]) {

-  size_t sz = elem_size; /* serves as 1-element array */

-  mstate ms = (mstate)msp;

-  if (!ok_magic(ms)) {

-    USAGE_ERROR_ACTION(ms,ms);

-    return 0;

-  }

-  return ialloc(ms, n_elements, &sz, 3, chunks);

-}

-

-void** mspace_independent_comalloc(mspace msp, size_t n_elements,

-                                   size_t sizes[], void* chunks[]) {

-  mstate ms = (mstate)msp;

-  if (!ok_magic(ms)) {

-    USAGE_ERROR_ACTION(ms,ms);

-    return 0;

-  }

-  return ialloc(ms, n_elements, sizes, 0, chunks);

-}

-

-int mspace_trim(mspace msp, size_t pad) {

-  int result = 0;

-  mstate ms = (mstate)msp;

-  if (ok_magic(ms)) {

-    if (!PREACTION(ms)) {

-      result = sys_trim(ms, pad);

-      POSTACTION(ms);

-    }

-  }

-  else {

-    USAGE_ERROR_ACTION(ms,ms);

-  }

-  return result;

-}

-

-void mspace_malloc_stats(mspace msp) {

-  mstate ms = (mstate)msp;

-  if (ok_magic(ms)) {

-    internal_malloc_stats(ms);

-  }

-  else {

-    USAGE_ERROR_ACTION(ms,ms);

-  }

-}

-

-size_t mspace_footprint(mspace msp) {

-  size_t result;

-  mstate ms = (mstate)msp;

-  if (ok_magic(ms)) {

-    result = ms->footprint;

-  }

-  USAGE_ERROR_ACTION(ms,ms);

-  return result;

-}

-

-

-size_t mspace_max_footprint(mspace msp) {

-  size_t result;

-  mstate ms = (mstate)msp;

-  if (ok_magic(ms)) {

-    result = ms->max_footprint;

-  }

-  USAGE_ERROR_ACTION(ms,ms);

-  return result;

-}

-

-

-#if !NO_MALLINFO

-struct mallinfo mspace_mallinfo(mspace msp) {

-  mstate ms = (mstate)msp;

-  if (!ok_magic(ms)) {

-    USAGE_ERROR_ACTION(ms,ms);

-  }

-  return internal_mallinfo(ms);

-}

-#endif /* NO_MALLINFO */

-

-int mspace_mallopt(int param_number, int value) {

-  return change_mparam(param_number, value);

-}

-

-#endif /* MSPACES */

-

-/* -------------------- Alternative MORECORE functions ------------------- */

-

-/*

-  Guidelines for creating a custom version of MORECORE:

-

-  * For best performance, MORECORE should allocate in multiples of pagesize.

-  * MORECORE may allocate more memory than requested. (Or even less,

-      but this will usually result in a malloc failure.)

-  * MORECORE must not allocate memory when given argument zero, but

-      instead return one past the end address of memory from previous

-      nonzero call.

-  * For best performance, consecutive calls to MORECORE with positive

-      arguments should return increasing addresses, indicating that

-      space has been contiguously extended.

-  * Even though consecutive calls to MORECORE need not return contiguous

-      addresses, it must be OK for malloc'ed chunks to span multiple

-      regions in those cases where they do happen to be contiguous.

-  * MORECORE need not handle negative arguments -- it may instead

-      just return MFAIL when given negative arguments.

-      Negative arguments are always multiples of pagesize. MORECORE

-      must not misinterpret negative args as large positive unsigned

-      args. You can suppress all such calls from even occurring by defining

-      MORECORE_CANNOT_TRIM,

-

-  As an example alternative MORECORE, here is a custom allocator

-  kindly contributed for pre-OSX macOS.  It uses virtually but not

-  necessarily physically contiguous non-paged memory (locked in,

-  present and won't get swapped out).  You can use it by uncommenting

-  this section, adding some #includes, and setting up the appropriate

-  defines above:

-

-      #define MORECORE osMoreCore

-

-  There is also a shutdown routine that should somehow be called for

-  cleanup upon program exit.

-

-  #define MAX_POOL_ENTRIES 100

-  #define MINIMUM_MORECORE_SIZE  (64 * 1024U)

-  static int next_os_pool;

-  void *our_os_pools[MAX_POOL_ENTRIES];

-

-  void *osMoreCore(int size)

-  {

-    void *ptr = 0;

-    static void *sbrk_top = 0;

-

-    if (size > 0)

-    {

-      if (size < MINIMUM_MORECORE_SIZE)

-         size = MINIMUM_MORECORE_SIZE;

-      if (CurrentExecutionLevel() == kTaskLevel)

-         ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0);

-      if (ptr == 0)

-      {

-        return (void *) MFAIL;

-      }

-      // save ptrs so they can be freed during cleanup

-      our_os_pools[next_os_pool] = ptr;

-      next_os_pool++;

-      ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK);

-      sbrk_top = (char *) ptr + size;

-      return ptr;

-    }

-    else if (size < 0)

-    {

-      // we don't currently support shrink behavior

-      return (void *) MFAIL;

-    }

-    else

-    {

-      return sbrk_top;

-    }

-  }

-

-  // cleanup any allocated memory pools

-  // called as last thing before shutting down driver

-

-  void osCleanupMem(void)

-  {

-    void **ptr;

-

-    for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++)

-      if (*ptr)

-      {

-         PoolDeallocate(*ptr);

-         *ptr = 0;

-      }

-  }

-

-*/

-

-

-/* -----------------------------------------------------------------------

-History:

-    V2.8.3 Thu Sep 22 11:16:32 2005  Doug Lea  (dl at gee)

-      * Add max_footprint functions

-      * Ensure all appropriate literals are size_t

-      * Fix conditional compilation problem for some #define settings

-      * Avoid concatenating segments with the one provided

-        in create_mspace_with_base

-      * Rename some variables to avoid compiler shadowing warnings

-      * Use explicit lock initialization.

-      * Better handling of sbrk interference.

-      * Simplify and fix segment insertion, trimming and mspace_destroy

-      * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x

-      * Thanks especially to Dennis Flanagan for help on these.

-

-    V2.8.2 Sun Jun 12 16:01:10 2005  Doug Lea  (dl at gee)

-      * Fix memalign brace error.

-

-    V2.8.1 Wed Jun  8 16:11:46 2005  Doug Lea  (dl at gee)

-      * Fix improper #endif nesting in C++

-      * Add explicit casts needed for C++

-

-    V2.8.0 Mon May 30 14:09:02 2005  Doug Lea  (dl at gee)

-      * Use trees for large bins

-      * Support mspaces

-      * Use segments to unify sbrk-based and mmap-based system allocation,

-        removing need for emulation on most platforms without sbrk.

-      * Default safety checks

-      * Optional footer checks. Thanks to William Robertson for the idea.

-      * Internal code refactoring

-      * Incorporate suggestions and platform-specific changes.

-        Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas,

-        Aaron Bachmann,  Emery Berger, and others.

-      * Speed up non-fastbin processing enough to remove fastbins.

-      * Remove useless cfree() to avoid conflicts with other apps.

-      * Remove internal memcpy, memset. Compilers handle builtins better.

-      * Remove some options that no one ever used and rename others.

-

-    V2.7.2 Sat Aug 17 09:07:30 2002  Doug Lea  (dl at gee)

-      * Fix malloc_state bitmap array misdeclaration

-

-    V2.7.1 Thu Jul 25 10:58:03 2002  Doug Lea  (dl at gee)

-      * Allow tuning of FIRST_SORTED_BIN_SIZE

-      * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte.

-      * Better detection and support for non-contiguousness of MORECORE.

-        Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger

-      * Bypass most of malloc if no frees. Thanks To Emery Berger.

-      * Fix freeing of old top non-contiguous chunk im sysmalloc.

-      * Raised default trim and map thresholds to 256K.

-      * Fix mmap-related #defines. Thanks to Lubos Lunak.

-      * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield.

-      * Branch-free bin calculation

-      * Default trim and mmap thresholds now 256K.

-

-    V2.7.0 Sun Mar 11 14:14:06 2001  Doug Lea  (dl at gee)

-      * Introduce independent_comalloc and independent_calloc.

-        Thanks to Michael Pachos for motivation and help.

-      * Make optional .h file available

-      * Allow > 2GB requests on 32bit systems.

-      * new WIN32 sbrk, mmap, munmap, lock code from <Walter@GeNeSys-e.de>.

-        Thanks also to Andreas Mueller <a.mueller at paradatec.de>,

-        and Anonymous.

-      * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for

-        helping test this.)

-      * memalign: check alignment arg

-      * realloc: don't try to shift chunks backwards, since this

-        leads to  more fragmentation in some programs and doesn't

-        seem to help in any others.

-      * Collect all cases in malloc requiring system memory into sysmalloc

-      * Use mmap as backup to sbrk

-      * Place all internal state in malloc_state

-      * Introduce fastbins (although similar to 2.5.1)

-      * Many minor tunings and cosmetic improvements

-      * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK

-      * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS

-        Thanks to Tony E. Bennett <tbennett@nvidia.com> and others.

-      * Include errno.h to support default failure action.

-

-    V2.6.6 Sun Dec  5 07:42:19 1999  Doug Lea  (dl at gee)

-      * return null for negative arguments

-      * Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com>

-         * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'

-          (e.g. WIN32 platforms)

-         * Cleanup header file inclusion for WIN32 platforms

-         * Cleanup code to avoid Microsoft Visual C++ compiler complaints

-         * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing

-           memory allocation routines

-         * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)

-         * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to

-           usage of 'assert' in non-WIN32 code

-         * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to

-           avoid infinite loop

-      * Always call 'fREe()' rather than 'free()'

-

-    V2.6.5 Wed Jun 17 15:57:31 1998  Doug Lea  (dl at gee)

-      * Fixed ordering problem with boundary-stamping

-

-    V2.6.3 Sun May 19 08:17:58 1996  Doug Lea  (dl at gee)

-      * Added pvalloc, as recommended by H.J. Liu

-      * Added 64bit pointer support mainly from Wolfram Gloger

-      * Added anonymously donated WIN32 sbrk emulation

-      * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen

-      * malloc_extend_top: fix mask error that caused wastage after

-        foreign sbrks

-      * Add linux mremap support code from HJ Liu

-

-    V2.6.2 Tue Dec  5 06:52:55 1995  Doug Lea  (dl at gee)

-      * Integrated most documentation with the code.

-      * Add support for mmap, with help from

-        Wolfram Gloger (Gloger@lrz.uni-muenchen.de).

-      * Use last_remainder in more cases.

-      * Pack bins using idea from  colin@nyx10.cs.du.edu

-      * Use ordered bins instead of best-fit threshhold

-      * Eliminate block-local decls to simplify tracing and debugging.

-      * Support another case of realloc via move into top

-      * Fix error occuring when initial sbrk_base not word-aligned.

-      * Rely on page size for units instead of SBRK_UNIT to

-        avoid surprises about sbrk alignment conventions.

-      * Add mallinfo, mallopt. Thanks to Raymond Nijssen

-        (raymond@es.ele.tue.nl) for the suggestion.

-      * Add `pad' argument to malloc_trim and top_pad mallopt parameter.

-      * More precautions for cases where other routines call sbrk,

-        courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).

-      * Added macros etc., allowing use in linux libc from

-        H.J. Lu (hjl@gnu.ai.mit.edu)

-      * Inverted this history list

-

-    V2.6.1 Sat Dec  2 14:10:57 1995  Doug Lea  (dl at gee)

-      * Re-tuned and fixed to behave more nicely with V2.6.0 changes.

-      * Removed all preallocation code since under current scheme

-        the work required to undo bad preallocations exceeds

-        the work saved in good cases for most test programs.

-      * No longer use return list or unconsolidated bins since

-        no scheme using them consistently outperforms those that don't

-        given above changes.

-      * Use best fit for very large chunks to prevent some worst-cases.

-      * Added some support for debugging

-

-    V2.6.0 Sat Nov  4 07:05:23 1995  Doug Lea  (dl at gee)

-      * Removed footers when chunks are in use. Thanks to

-        Paul Wilson (wilson@cs.texas.edu) for the suggestion.

-

-    V2.5.4 Wed Nov  1 07:54:51 1995  Doug Lea  (dl at gee)

-      * Added malloc_trim, with help from Wolfram Gloger

-        (wmglo@Dent.MED.Uni-Muenchen.DE).

-

-    V2.5.3 Tue Apr 26 10:16:01 1994  Doug Lea  (dl at g)

-

-    V2.5.2 Tue Apr  5 16:20:40 1994  Doug Lea  (dl at g)

-      * realloc: try to expand in both directions

-      * malloc: swap order of clean-bin strategy;

-      * realloc: only conditionally expand backwards

-      * Try not to scavenge used bins

-      * Use bin counts as a guide to preallocation

-      * Occasionally bin return list chunks in first scan

-      * Add a few optimizations from colin@nyx10.cs.du.edu

-

-    V2.5.1 Sat Aug 14 15:40:43 1993  Doug Lea  (dl at g)

-      * faster bin computation & slightly different binning

-      * merged all consolidations to one part of malloc proper

-         (eliminating old malloc_find_space & malloc_clean_bin)

-      * Scan 2 returns chunks (not just 1)

-      * Propagate failure in realloc if malloc returns 0

-      * Add stuff to allow compilation on non-ANSI compilers

-          from kpv@research.att.com

-

-    V2.5 Sat Aug  7 07:41:59 1993  Doug Lea  (dl at g.oswego.edu)

-      * removed potential for odd address access in prev_chunk

-      * removed dependency on getpagesize.h

-      * misc cosmetics and a bit more internal documentation

-      * anticosmetics: mangled names in macros to evade debugger strangeness

-      * tested on sparc, hp-700, dec-mips, rs6000

-          with gcc & native cc (hp, dec only) allowing

-          Detlefs & Zorn comparison study (in SIGPLAN Notices.)

-

-    Trial version Fri Aug 28 13:14:29 1992  Doug Lea  (dl at g.oswego.edu)

-      * Based loosely on libg++-1.2X malloc. (It retains some of the overall

-         structure of old version,  but most details differ.)

-

-*/

+#define USE_DL_PREFIX
+
+#define FOOTERS 1
+#define DEBUG 1
+/*
+#define ABORT_ON_ASSERT_FAILURE 0
+*/
+
+#define ABORT do { printf("abort was called\n"); abort(); } while (0)
+
+/*
+  This is a version (aka dlmalloc) of malloc/free/realloc written by
+  Doug Lea and released to the public domain, as explained at
+  http://creativecommons.org/licenses/publicdomain.  Send questions,
+  comments, complaints, performance data, etc to dl@cs.oswego.edu
+
+* Version 2.8.3 Thu Sep 22 11:16:15 2005  Doug Lea  (dl at gee)
+
+   Note: There may be an updated version of this malloc obtainable at
+           ftp://gee.cs.oswego.edu/pub/misc/malloc.c
+         Check before installing!
+
+* Quickstart
+
+  This library is all in one file to simplify the most common usage:
+  ftp it, compile it (-O3), and link it into another program. All of
+  the compile-time options default to reasonable values for use on
+  most platforms.  You might later want to step through various
+  compile-time and dynamic tuning options.
+
+  For convenience, an include file for code using this malloc is at:
+     ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.3.h
+  You don't really need this .h file unless you call functions not
+  defined in your system include files.  The .h file contains only the
+  excerpts from this file needed for using this malloc on ANSI C/C++
+  systems, so long as you haven't changed compile-time options about
+  naming and tuning parameters.  If you do, then you can create your
+  own malloc.h that does include all settings by cutting at the point
+  indicated below. Note that you may already by default be using a C
+  library containing a malloc that is based on some version of this
+  malloc (for example in linux). You might still want to use the one
+  in this file to customize settings or to avoid overheads associated
+  with library versions.
+
+* Vital statistics:
+
+  Supported pointer/size_t representation:       4 or 8 bytes
+       size_t MUST be an unsigned type of the same width as
+       pointers. (If you are using an ancient system that declares
+       size_t as a signed type, or need it to be a different width
+       than pointers, you can use a previous release of this malloc
+       (e.g. 2.7.2) supporting these.)
+
+  Alignment:                                     8 bytes (default)
+       This suffices for nearly all current machines and C compilers.
+       However, you can define MALLOC_ALIGNMENT to be wider than this
+       if necessary (up to 128bytes), at the expense of using more space.
+
+  Minimum overhead per allocated chunk:   4 or  8 bytes (if 4byte sizes)
+                                          8 or 16 bytes (if 8byte sizes)
+       Each malloced chunk has a hidden word of overhead holding size
+       and status information, and additional cross-check word
+       if FOOTERS is defined.
+
+  Minimum allocated size: 4-byte ptrs:  16 bytes    (including overhead)
+                          8-byte ptrs:  32 bytes    (including overhead)
+
+       Even a request for zero bytes (i.e., malloc(0)) returns a
+       pointer to something of the minimum allocatable size.
+       The maximum overhead wastage (i.e., number of extra bytes
+       allocated than were requested in malloc) is less than or equal
+       to the minimum size, except for requests >= mmap_threshold that
+       are serviced via mmap(), where the worst case wastage is about
+       32 bytes plus the remainder from a system page (the minimal
+       mmap unit); typically 4096 or 8192 bytes.
+
+  Security: static-safe; optionally more or less
+       The "security" of malloc refers to the ability of malicious
+       code to accentuate the effects of errors (for example, freeing
+       space that is not currently malloc'ed or overwriting past the
+       ends of chunks) in code that calls malloc.  This malloc
+       guarantees not to modify any memory locations below the base of
+       heap, i.e., static variables, even in the presence of usage
+       errors.  The routines additionally detect most improper frees
+       and reallocs.  All this holds as long as the static bookkeeping
+       for malloc itself is not corrupted by some other means.  This
+       is only one aspect of security -- these checks do not, and
+       cannot, detect all possible programming errors.
+
+       If FOOTERS is defined nonzero, then each allocated chunk
+       carries an additional check word to verify that it was malloced
+       from its space.  These check words are the same within each
+       execution of a program using malloc, but differ across
+       executions, so externally crafted fake chunks cannot be
+       freed. This improves security by rejecting frees/reallocs that
+       could corrupt heap memory, in addition to the checks preventing
+       writes to statics that are always on.  This may further improve
+       security at the expense of time and space overhead.  (Note that
+       FOOTERS may also be worth using with MSPACES.)
+
+       By default detected errors cause the program to abort (calling
+       "abort()"). You can override this to instead proceed past
+       errors by defining PROCEED_ON_ERROR.  In this case, a bad free
+       has no effect, and a malloc that encounters a bad address
+       caused by user overwrites will ignore the bad address by
+       dropping pointers and indices to all known memory. This may
+       be appropriate for programs that should continue if at all
+       possible in the face of programming errors, although they may
+       run out of memory because dropped memory is never reclaimed.
+
+       If you don't like either of these options, you can define
+       CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything
+       else. And if if you are sure that your program using malloc has
+       no errors or vulnerabilities, you can define INSECURE to 1,
+       which might (or might not) provide a small performance improvement.
+
+  Thread-safety: NOT thread-safe unless USE_LOCKS defined
+       When USE_LOCKS is defined, each public call to malloc, free,
+       etc is surrounded with either a pthread mutex or a win32
+       spinlock (depending on WIN32). This is not especially fast, and
+       can be a major bottleneck.  It is designed only to provide
+       minimal protection in concurrent environments, and to provide a
+       basis for extensions.  If you are using malloc in a concurrent
+       program, consider instead using ptmalloc, which is derived from
+       a version of this malloc. (See http://www.malloc.de).
+
+  System requirements: Any combination of MORECORE and/or MMAP/MUNMAP
+       This malloc can use unix sbrk or any emulation (invoked using
+       the CALL_MORECORE macro) and/or mmap/munmap or any emulation
+       (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system
+       memory.  On most unix systems, it tends to work best if both
+       MORECORE and MMAP are enabled.  On Win32, it uses emulations
+       based on VirtualAlloc. It also uses common C library functions
+       like memset.
+
+  Compliance: I believe it is compliant with the Single Unix Specification
+       (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably
+       others as well.
+
+* Overview of algorithms
+
+  This is not the fastest, most space-conserving, most portable, or
+  most tunable malloc ever written. However it is among the fastest
+  while also being among the most space-conserving, portable and
+  tunable.  Consistent balance across these factors results in a good
+  general-purpose allocator for malloc-intensive programs.
+
+  In most ways, this malloc is a best-fit allocator. Generally, it
+  chooses the best-fitting existing chunk for a request, with ties
+  broken in approximately least-recently-used order. (This strategy
+  normally maintains low fragmentation.) However, for requests less
+  than 256bytes, it deviates from best-fit when there is not an
+  exactly fitting available chunk by preferring to use space adjacent
+  to that used for the previous small request, as well as by breaking
+  ties in approximately most-recently-used order. (These enhance
+  locality of series of small allocations.)  And for very large requests
+  (>= 256Kb by default), it relies on system memory mapping
+  facilities, if supported.  (This helps avoid carrying around and
+  possibly fragmenting memory used only for large chunks.)
+
+  All operations (except malloc_stats and mallinfo) have execution
+  times that are bounded by a constant factor of the number of bits in
+  a size_t, not counting any clearing in calloc or copying in realloc,
+  or actions surrounding MORECORE and MMAP that have times
+  proportional to the number of non-contiguous regions returned by
+  system allocation routines, which is often just 1.
+
+  The implementation is not very modular and seriously overuses
+  macros. Perhaps someday all C compilers will do as good a job
+  inlining modular code as can now be done by brute-force expansion,
+  but now, enough of them seem not to.
+
+  Some compilers issue a lot of warnings about code that is
+  dead/unreachable only on some platforms, and also about intentional
+  uses of negation on unsigned types. All known cases of each can be
+  ignored.
+
+  For a longer but out of date high-level description, see
+     http://gee.cs.oswego.edu/dl/html/malloc.html
+
+* MSPACES
+  If MSPACES is defined, then in addition to malloc, free, etc.,
+  this file also defines mspace_malloc, mspace_free, etc. These
+  are versions of malloc routines that take an "mspace" argument
+  obtained using create_mspace, to control all internal bookkeeping.
+  If ONLY_MSPACES is defined, only these versions are compiled.
+  So if you would like to use this allocator for only some allocations,
+  and your system malloc for others, you can compile with
+  ONLY_MSPACES and then do something like...
+    static mspace mymspace = create_mspace(0,0); // for example
+    #define mymalloc(bytes)  mspace_malloc(mymspace, bytes)
+
+  (Note: If you only need one instance of an mspace, you can instead
+  use "USE_DL_PREFIX" to relabel the global malloc.)
+
+  You can similarly create thread-local allocators by storing
+  mspaces as thread-locals. For example:
+    static __thread mspace tlms = 0;
+    void*  tlmalloc(size_t bytes) {
+      if (tlms == 0) tlms = create_mspace(0, 0);
+      return mspace_malloc(tlms, bytes);
+    }
+    void  tlfree(void* mem) { mspace_free(tlms, mem); }
+
+  Unless FOOTERS is defined, each mspace is completely independent.
+  You cannot allocate from one and free to another (although
+  conformance is only weakly checked, so usage errors are not always
+  caught). If FOOTERS is defined, then each chunk carries around a tag
+  indicating its originating mspace, and frees are directed to their
+  originating spaces.
+
+ -------------------------  Compile-time options ---------------------------
+
+Be careful in setting #define values for numerical constants of type
+size_t. On some systems, literal values are not automatically extended
+to size_t precision unless they are explicitly casted.
+
+WIN32                    default: defined if _WIN32 defined
+  Defining WIN32 sets up defaults for MS environment and compilers.
+  Otherwise defaults are for unix.
+
+MALLOC_ALIGNMENT         default: (size_t)8
+  Controls the minimum alignment for malloc'ed chunks.  It must be a
+  power of two and at least 8, even on machines for which smaller
+  alignments would suffice. It may be defined as larger than this
+  though. Note however that code and data structures are optimized for
+  the case of 8-byte alignment.
+
+MSPACES                  default: 0 (false)
+  If true, compile in support for independent allocation spaces.
+  This is only supported if HAVE_MMAP is true.
+
+ONLY_MSPACES             default: 0 (false)
+  If true, only compile in mspace versions, not regular versions.
+
+USE_LOCKS                default: 0 (false)
+  Causes each call to each public routine to be surrounded with
+  pthread or WIN32 mutex lock/unlock. (If set true, this can be
+  overridden on a per-mspace basis for mspace versions.)
+
+FOOTERS                  default: 0
+  If true, provide extra checking and dispatching by placing
+  information in the footers of allocated chunks. This adds
+  space and time overhead.
+
+INSECURE                 default: 0
+  If true, omit checks for usage errors and heap space overwrites.
+
+USE_DL_PREFIX            default: NOT defined
+  Causes compiler to prefix all public routines with the string 'dl'.
+  This can be useful when you only want to use this malloc in one part
+  of a program, using your regular system malloc elsewhere.
+
+ABORT                    default: defined as abort()
+  Defines how to abort on failed checks.  On most systems, a failed
+  check cannot die with an "assert" or even print an informative
+  message, because the underlying print routines in turn call malloc,
+  which will fail again.  Generally, the best policy is to simply call
+  abort(). It's not very useful to do more than this because many
+  errors due to overwriting will show up as address faults (null, odd
+  addresses etc) rather than malloc-triggered checks, so will also
+  abort.  Also, most compilers know that abort() does not return, so
+  can better optimize code conditionally calling it.
+
+PROCEED_ON_ERROR           default: defined as 0 (false)
+  Controls whether detected bad addresses cause them to bypassed
+  rather than aborting. If set, detected bad arguments to free and
+  realloc are ignored. And all bookkeeping information is zeroed out
+  upon a detected overwrite of freed heap space, thus losing the
+  ability to ever return it from malloc again, but enabling the
+  application to proceed. If PROCEED_ON_ERROR is defined, the
+  static variable malloc_corruption_error_count is compiled in
+  and can be examined to see if errors have occurred. This option
+  generates slower code than the default abort policy.
+
+DEBUG                    default: NOT defined
+  The DEBUG setting is mainly intended for people trying to modify
+  this code or diagnose problems when porting to new platforms.
+  However, it may also be able to better isolate user errors than just
+  using runtime checks.  The assertions in the check routines spell
+  out in more detail the assumptions and invariants underlying the
+  algorithms.  The checking is fairly extensive, and will slow down
+  execution noticeably. Calling malloc_stats or mallinfo with DEBUG
+  set will attempt to check every non-mmapped allocated and free chunk
+  in the course of computing the summaries.
+
+ABORT_ON_ASSERT_FAILURE   default: defined as 1 (true)
+  Debugging assertion failures can be nearly impossible if your
+  version of the assert macro causes malloc to be called, which will
+  lead to a cascade of further failures, blowing the runtime stack.
+  ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(),
+  which will usually make debugging easier.
+
+MALLOC_FAILURE_ACTION     default: sets errno to ENOMEM, or no-op on win32
+  The action to take before "return 0" when malloc fails to be able to
+  return memory because there is none available.
+
+HAVE_MORECORE             default: 1 (true) unless win32 or ONLY_MSPACES
+  True if this system supports sbrk or an emulation of it.
+
+MORECORE                  default: sbrk
+  The name of the sbrk-style system routine to call to obtain more
+  memory.  See below for guidance on writing custom MORECORE
+  functions. The type of the argument to sbrk/MORECORE varies across
+  systems.  It cannot be size_t, because it supports negative
+  arguments, so it is normally the signed type of the same width as
+  size_t (sometimes declared as "intptr_t").  It doesn't much matter
+  though. Internally, we only call it with arguments less than half
+  the max value of a size_t, which should work across all reasonable
+  possibilities, although sometimes generating compiler warnings.  See
+  near the end of this file for guidelines for creating a custom
+  version of MORECORE.
+
+MORECORE_CONTIGUOUS       default: 1 (true)
+  If true, take advantage of fact that consecutive calls to MORECORE
+  with positive arguments always return contiguous increasing
+  addresses.  This is true of unix sbrk. It does not hurt too much to
+  set it true anyway, since malloc copes with non-contiguities.
+  Setting it false when definitely non-contiguous saves time
+  and possibly wasted space it would take to discover this though.
+
+MORECORE_CANNOT_TRIM      default: NOT defined
+  True if MORECORE cannot release space back to the system when given
+  negative arguments. This is generally necessary only if you are
+  using a hand-crafted MORECORE function that cannot handle negative
+  arguments.
+
+HAVE_MMAP                 default: 1 (true)
+  True if this system supports mmap or an emulation of it.  If so, and
+  HAVE_MORECORE is not true, MMAP is used for all system
+  allocation. If set and HAVE_MORECORE is true as well, MMAP is
+  primarily used to directly allocate very large blocks. It is also
+  used as a backup strategy in cases where MORECORE fails to provide
+  space from system. Note: A single call to MUNMAP is assumed to be
+  able to unmap memory that may have be allocated using multiple calls
+  to MMAP, so long as they are adjacent.
+
+HAVE_MREMAP               default: 1 on linux, else 0
+  If true realloc() uses mremap() to re-allocate large blocks and
+  extend or shrink allocation spaces.
+
+MMAP_CLEARS               default: 1 on unix
+  True if mmap clears memory so calloc doesn't need to. This is true
+  for standard unix mmap using /dev/zero.
+
+USE_BUILTIN_FFS            default: 0 (i.e., not used)
+  Causes malloc to use the builtin ffs() function to compute indices.
+  Some compilers may recognize and intrinsify ffs to be faster than the
+  supplied C version. Also, the case of x86 using gcc is special-cased
+  to an asm instruction, so is already as fast as it can be, and so
+  this setting has no effect. (On most x86s, the asm version is only
+  slightly faster than the C version.)
+
+malloc_getpagesize         default: derive from system includes, or 4096.
+  The system page size. To the extent possible, this malloc manages
+  memory from the system in page-size units.  This may be (and
+  usually is) a function rather than a constant. This is ignored
+  if WIN32, where page size is determined using getSystemInfo during
+  initialization.
+
+USE_DEV_RANDOM             default: 0 (i.e., not used)
+  Causes malloc to use /dev/random to initialize secure magic seed for
+  stamping footers. Otherwise, the current time is used.
+
+NO_MALLINFO                default: 0
+  If defined, don't compile "mallinfo". This can be a simple way
+  of dealing with mismatches between system declarations and
+  those in this file.
+
+MALLINFO_FIELD_TYPE        default: size_t
+  The type of the fields in the mallinfo struct. This was originally
+  defined as "int" in SVID etc, but is more usefully defined as
+  size_t. The value is used only if  HAVE_USR_INCLUDE_MALLOC_H is not set
+
+REALLOC_ZERO_BYTES_FREES    default: not defined
+  This should be set if a call to realloc with zero bytes should
+  be the same as a call to free. Some people think it should. Otherwise,
+  since this malloc returns a unique pointer for malloc(0), so does
+  realloc(p, 0).
+
+LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H
+LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H,  LACKS_ERRNO_H
+LACKS_STDLIB_H                default: NOT defined unless on WIN32
+  Define these if your system does not have these header files.
+  You might need to manually insert some of the declarations they provide.
+
+DEFAULT_GRANULARITY        default: page size if MORECORE_CONTIGUOUS,
+                                system_info.dwAllocationGranularity in WIN32,
+                                otherwise 64K.
+      Also settable using mallopt(M_GRANULARITY, x)
+  The unit for allocating and deallocating memory from the system.  On
+  most systems with contiguous MORECORE, there is no reason to
+  make this more than a page. However, systems with MMAP tend to
+  either require or encourage larger granularities.  You can increase
+  this value to prevent system allocation functions to be called so
+  often, especially if they are slow.  The value must be at least one
+  page and must be a power of two.  Setting to 0 causes initialization
+  to either page size or win32 region size.  (Note: In previous
+  versions of malloc, the equivalent of this option was called
+  "TOP_PAD")
+
+DEFAULT_TRIM_THRESHOLD    default: 2MB
+      Also settable using mallopt(M_TRIM_THRESHOLD, x)
+  The maximum amount of unused top-most memory to keep before
+  releasing via malloc_trim in free().  Automatic trimming is mainly
+  useful in long-lived programs using contiguous MORECORE.  Because
+  trimming via sbrk can be slow on some systems, and can sometimes be
+  wasteful (in cases where programs immediately afterward allocate
+  more large chunks) the value should be high enough so that your
+  overall system performance would improve by releasing this much
+  memory.  As a rough guide, you might set to a value close to the
+  average size of a process (program) running on your system.
+  Releasing this much memory would allow such a process to run in
+  memory.  Generally, it is worth tuning trim thresholds when a
+  program undergoes phases where several large chunks are allocated
+  and released in ways that can reuse each other's storage, perhaps
+  mixed with phases where there are no such chunks at all. The trim
+  value must be greater than page size to have any useful effect.  To
+  disable trimming completely, you can set to MAX_SIZE_T. Note that the trick
+  some people use of mallocing a huge space and then freeing it at
+  program startup, in an attempt to reserve system memory, doesn't
+  have the intended effect under automatic trimming, since that memory
+  will immediately be returned to the system.
+
+DEFAULT_MMAP_THRESHOLD       default: 256K
+      Also settable using mallopt(M_MMAP_THRESHOLD, x)
+  The request size threshold for using MMAP to directly service a
+  request. Requests of at least this size that cannot be allocated
+  using already-existing space will be serviced via mmap.  (If enough
+  normal freed space already exists it is used instead.)  Using mmap
+  segregates relatively large chunks of memory so that they can be
+  individually obtained and released from the host system. A request
+  serviced through mmap is never reused by any other request (at least
+  not directly; the system may just so happen to remap successive
+  requests to the same locations).  Segregating space in this way has
+  the benefits that: Mmapped space can always be individually released
+  back to the system, which helps keep the system level memory demands
+  of a long-lived program low.  Also, mapped memory doesn't become
+  `locked' between other chunks, as can happen with normally allocated
+  chunks, which means that even trimming via malloc_trim would not
+  release them.  However, it has the disadvantage that the space
+  cannot be reclaimed, consolidated, and then used to service later
+  requests, as happens with normal chunks.  The advantages of mmap
+  nearly always outweigh disadvantages for "large" chunks, but the
+  value of "large" may vary across systems.  The default is an
+  empirically derived value that works well in most systems. You can
+  disable mmap by setting to MAX_SIZE_T.
+
+*/
+#if defined(__WATCOMC__) || defined(_MSC_VER)
+#define WIN32 1
+#endif
+
+#ifndef WIN32
+#ifdef _WIN32
+#define WIN32 1
+#endif  /* _WIN32 */
+#endif  /* WIN32 */
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#define HAVE_MORECORE 0
+#define LACKS_UNISTD_H
+#define LACKS_SYS_PARAM_H
+#define LACKS_SYS_MMAN_H
+#define LACKS_STRING_H
+#define LACKS_STRINGS_H
+#define LACKS_SYS_TYPES_H
+#define LACKS_ERRNO_H
+#define MALLOC_FAILURE_ACTION
+#define MMAP_CLEARS 0 /* WINCE and some others apparently don't clear */
+#endif  /* WIN32 */
+
+#if defined(DARWIN) || defined(_DARWIN)
+/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */
+#ifndef HAVE_MORECORE
+#define HAVE_MORECORE 0
+#define HAVE_MMAP 1
+#endif  /* HAVE_MORECORE */
+#endif  /* DARWIN */
+
+#ifndef LACKS_SYS_TYPES_H
+#include <sys/types.h>  /* For size_t */
+#endif  /* LACKS_SYS_TYPES_H */
+
+/* The maximum possible size_t value has all bits set */
+#define MAX_SIZE_T           (~(size_t)0)
+
+#ifndef ONLY_MSPACES
+#define ONLY_MSPACES 0
+#endif  /* ONLY_MSPACES */
+#ifndef MSPACES
+#if ONLY_MSPACES
+#define MSPACES 1
+#else   /* ONLY_MSPACES */
+#define MSPACES 0
+#endif  /* ONLY_MSPACES */
+#endif  /* MSPACES */
+#ifndef MALLOC_ALIGNMENT
+#define MALLOC_ALIGNMENT ((size_t)8U)
+#endif  /* MALLOC_ALIGNMENT */
+#ifndef FOOTERS
+#define FOOTERS 0
+#endif  /* FOOTERS */
+#ifndef ABORT
+#define ABORT  abort()
+#endif  /* ABORT */
+#ifndef ABORT_ON_ASSERT_FAILURE
+#define ABORT_ON_ASSERT_FAILURE 1
+#endif  /* ABORT_ON_ASSERT_FAILURE */
+#ifndef PROCEED_ON_ERROR
+#define PROCEED_ON_ERROR 0
+#endif  /* PROCEED_ON_ERROR */
+#ifndef USE_LOCKS
+#define USE_LOCKS 0
+#endif  /* USE_LOCKS */
+#ifndef INSECURE
+#define INSECURE 0
+#endif  /* INSECURE */
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 1
+#endif  /* HAVE_MMAP */
+#ifndef MMAP_CLEARS
+#define MMAP_CLEARS 1
+#endif  /* MMAP_CLEARS */
+#ifndef HAVE_MREMAP
+#ifdef linux
+#define HAVE_MREMAP 1
+#else   /* linux */
+#define HAVE_MREMAP 0
+#endif  /* linux */
+#endif  /* HAVE_MREMAP */
+#ifndef MALLOC_FAILURE_ACTION
+#define MALLOC_FAILURE_ACTION  errno = ENOMEM;
+#endif  /* MALLOC_FAILURE_ACTION */
+#ifndef HAVE_MORECORE
+#if ONLY_MSPACES
+#define HAVE_MORECORE 0
+#else   /* ONLY_MSPACES */
+#define HAVE_MORECORE 1
+#endif  /* ONLY_MSPACES */
+#endif  /* HAVE_MORECORE */
+#if !HAVE_MORECORE
+#define MORECORE_CONTIGUOUS 0
+#else   /* !HAVE_MORECORE */
+#ifndef MORECORE
+#define MORECORE sbrk
+#endif  /* MORECORE */
+#ifndef MORECORE_CONTIGUOUS
+#define MORECORE_CONTIGUOUS 1
+#endif  /* MORECORE_CONTIGUOUS */
+#endif  /* HAVE_MORECORE */
+#ifndef DEFAULT_GRANULARITY
+#if MORECORE_CONTIGUOUS
+#define DEFAULT_GRANULARITY (0)  /* 0 means to compute in init_mparams */
+#else   /* MORECORE_CONTIGUOUS */
+#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U)
+#endif  /* MORECORE_CONTIGUOUS */
+#endif  /* DEFAULT_GRANULARITY */
+#ifndef DEFAULT_TRIM_THRESHOLD
+#ifndef MORECORE_CANNOT_TRIM
+#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U)
+#else   /* MORECORE_CANNOT_TRIM */
+#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T
+#endif  /* MORECORE_CANNOT_TRIM */
+#endif  /* DEFAULT_TRIM_THRESHOLD */
+#ifndef DEFAULT_MMAP_THRESHOLD
+#if HAVE_MMAP
+#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U)
+#else   /* HAVE_MMAP */
+#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
+#endif  /* HAVE_MMAP */
+#endif  /* DEFAULT_MMAP_THRESHOLD */
+#ifndef USE_BUILTIN_FFS
+#define USE_BUILTIN_FFS 0
+#endif  /* USE_BUILTIN_FFS */
+#ifndef USE_DEV_RANDOM
+#define USE_DEV_RANDOM 0
+#endif  /* USE_DEV_RANDOM */
+#ifndef NO_MALLINFO
+#define NO_MALLINFO 0
+#endif  /* NO_MALLINFO */
+#ifndef MALLINFO_FIELD_TYPE
+#define MALLINFO_FIELD_TYPE size_t
+#endif  /* MALLINFO_FIELD_TYPE */
+
+/*
+  mallopt tuning options.  SVID/XPG defines four standard parameter
+  numbers for mallopt, normally defined in malloc.h.  None of these
+  are used in this malloc, so setting them has no effect. But this
+  malloc does support the following options.
+*/
+
+#define M_TRIM_THRESHOLD     (-1)
+#define M_GRANULARITY        (-2)
+#define M_MMAP_THRESHOLD     (-3)
+
+/* ------------------------ Mallinfo declarations ------------------------ */
+
+#if !NO_MALLINFO
+/*
+  This version of malloc supports the standard SVID/XPG mallinfo
+  routine that returns a struct containing usage properties and
+  statistics. It should work on any system that has a
+  /usr/include/malloc.h defining struct mallinfo.  The main
+  declaration needed is the mallinfo struct that is returned (by-copy)
+  by mallinfo().  The malloinfo struct contains a bunch of fields that
+  are not even meaningful in this version of malloc.  These fields are
+  are instead filled by mallinfo() with other numbers that might be of
+  interest.
+
+  HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+  /usr/include/malloc.h file that includes a declaration of struct
+  mallinfo.  If so, it is included; else a compliant version is
+  declared below.  These must be precisely the same for mallinfo() to
+  work.  The original SVID version of this struct, defined on most
+  systems with mallinfo, declares all fields as ints. But some others
+  define as unsigned long. If your system defines the fields using a
+  type of different width than listed here, you MUST #include your
+  system version and #define HAVE_USR_INCLUDE_MALLOC_H.
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+#ifdef HAVE_USR_INCLUDE_MALLOC_H
+#include "/usr/include/malloc.h"
+#else /* HAVE_USR_INCLUDE_MALLOC_H */
+
+struct mallinfo {
+  MALLINFO_FIELD_TYPE arena;    /* non-mmapped space allocated from system */
+  MALLINFO_FIELD_TYPE ordblks;  /* number of free chunks */
+  MALLINFO_FIELD_TYPE smblks;   /* always 0 */
+  MALLINFO_FIELD_TYPE hblks;    /* always 0 */
+  MALLINFO_FIELD_TYPE hblkhd;   /* space in mmapped regions */
+  MALLINFO_FIELD_TYPE usmblks;  /* maximum total allocated space */
+  MALLINFO_FIELD_TYPE fsmblks;  /* always 0 */
+  MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
+  MALLINFO_FIELD_TYPE fordblks; /* total free space */
+  MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
+};
+
+#endif /* HAVE_USR_INCLUDE_MALLOC_H */
+#endif /* NO_MALLINFO */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#if !ONLY_MSPACES
+
+/* ------------------- Declarations of public routines ------------------- */
+
+#ifndef USE_DL_PREFIX
+#define dlcalloc               calloc
+#define dlfree                 free
+#define dlmalloc               malloc
+#define dlmemalign             memalign
+#define dlrealloc              realloc
+#define dlvalloc               valloc
+#define dlpvalloc              pvalloc
+#define dlmallinfo             mallinfo
+#define dlmallopt              mallopt
+#define dlmalloc_trim          malloc_trim
+#define dlmalloc_stats         malloc_stats
+#define dlmalloc_usable_size   malloc_usable_size
+#define dlmalloc_footprint     malloc_footprint
+#define dlmalloc_max_footprint malloc_max_footprint
+#define dlindependent_calloc   independent_calloc
+#define dlindependent_comalloc independent_comalloc
+#endif /* USE_DL_PREFIX */
+
+
+/*
+  malloc(size_t n)
+  Returns a pointer to a newly allocated chunk of at least n bytes, or
+  null if no space is available, in which case errno is set to ENOMEM
+  on ANSI C systems.
+
+  If n is zero, malloc returns a minimum-sized chunk. (The minimum
+  size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
+  systems.)  Note that size_t is an unsigned type, so calls with
+  arguments that would be negative if signed are interpreted as
+  requests for huge amounts of space, which will often fail. The
+  maximum supported value of n differs across systems, but is in all
+  cases less than the maximum representable value of a size_t.
+*/
+void* dlmalloc(size_t);
+
+/*
+  free(void* p)
+  Releases the chunk of memory pointed to by p, that had been previously
+  allocated using malloc or a related routine such as realloc.
+  It has no effect if p is null. If p was not malloced or already
+  freed, free(p) will by default cause the current program to abort.
+*/
+void  dlfree(void*);
+
+/*
+  calloc(size_t n_elements, size_t element_size);
+  Returns a pointer to n_elements * element_size bytes, with all locations
+  set to zero.
+*/
+void* dlcalloc(size_t, size_t);
+
+/*
+  realloc(void* p, size_t n)
+  Returns a pointer to a chunk of size n that contains the same data
+  as does chunk p up to the minimum of (n, p's size) bytes, or null
+  if no space is available.
+
+  The returned pointer may or may not be the same as p. The algorithm
+  prefers extending p in most cases when possible, otherwise it
+  employs the equivalent of a malloc-copy-free sequence.
+
+  If p is null, realloc is equivalent to malloc.
+
+  If space is not available, realloc returns null, errno is set (if on
+  ANSI) and p is NOT freed.
+
+  if n is for fewer bytes than already held by p, the newly unused
+  space is lopped off and freed if possible.  realloc with a size
+  argument of zero (re)allocates a minimum-sized chunk.
+
+  The old unix realloc convention of allowing the last-free'd chunk
+  to be used as an argument to realloc is not supported.
+*/
+
+void* dlrealloc(void*, size_t);
+
+/*
+  memalign(size_t alignment, size_t n);
+  Returns a pointer to a newly allocated chunk of n bytes, aligned
+  in accord with the alignment argument.
+
+  The alignment argument should be a power of two. If the argument is
+  not a power of two, the nearest greater power is used.
+  8-byte alignment is guaranteed by normal malloc calls, so don't
+  bother calling memalign with an argument of 8 or less.
+
+  Overreliance on memalign is a sure way to fragment space.
+*/
+void* dlmemalign(size_t, size_t);
+
+/*
+  valloc(size_t n);
+  Equivalent to memalign(pagesize, n), where pagesize is the page
+  size of the system. If the pagesize is unknown, 4096 is used.
+*/
+void* dlvalloc(size_t);
+
+/*
+  mallopt(int parameter_number, int parameter_value)
+  Sets tunable parameters The format is to provide a
+  (parameter-number, parameter-value) pair.  mallopt then sets the
+  corresponding parameter to the argument value if it can (i.e., so
+  long as the value is meaningful), and returns 1 if successful else
+  0.  SVID/XPG/ANSI defines four standard param numbers for mallopt,
+  normally defined in malloc.h.  None of these are use in this malloc,
+  so setting them has no effect. But this malloc also supports other
+  options in mallopt. See below for details.  Briefly, supported
+  parameters are as follows (listed defaults are for "typical"
+  configurations).
+
+  Symbol            param #  default    allowed param values
+  M_TRIM_THRESHOLD     -1   2*1024*1024   any   (MAX_SIZE_T disables)
+  M_GRANULARITY        -2     page size   any power of 2 >= page size
+  M_MMAP_THRESHOLD     -3      256*1024   any   (or 0 if no MMAP support)
+*/
+int dlmallopt(int, int);
+
+/*
+  malloc_footprint();
+  Returns the number of bytes obtained from the system.  The total
+  number of bytes allocated by malloc, realloc etc., is less than this
+  value. Unlike mallinfo, this function returns only a precomputed
+  result, so can be called frequently to monitor memory consumption.
+  Even if locks are otherwise defined, this function does not use them,
+  so results might not be up to date.
+*/
+size_t dlmalloc_footprint(void);
+
+/*
+  malloc_max_footprint();
+  Returns the maximum number of bytes obtained from the system. This
+  value will be greater than current footprint if deallocated space
+  has been reclaimed by the system. The peak number of bytes allocated
+  by malloc, realloc etc., is less than this value. Unlike mallinfo,
+  this function returns only a precomputed result, so can be called
+  frequently to monitor memory consumption.  Even if locks are
+  otherwise defined, this function does not use them, so results might
+  not be up to date.
+*/
+size_t dlmalloc_max_footprint(void);
+
+#if !NO_MALLINFO
+/*
+  mallinfo()
+  Returns (by copy) a struct containing various summary statistics:
+
+  arena:     current total non-mmapped bytes allocated from system
+  ordblks:   the number of free chunks
+  smblks:    always zero.
+  hblks:     current number of mmapped regions
+  hblkhd:    total bytes held in mmapped regions
+  usmblks:   the maximum total allocated space. This will be greater
+                than current total if trimming has occurred.
+  fsmblks:   always zero
+  uordblks:  current total allocated space (normal or mmapped)
+  fordblks:  total free space
+  keepcost:  the maximum number of bytes that could ideally be released
+               back to system via malloc_trim. ("ideally" means that
+               it ignores page restrictions etc.)
+
+  Because these fields are ints, but internal bookkeeping may
+  be kept as longs, the reported values may wrap around zero and
+  thus be inaccurate.
+*/
+struct mallinfo dlmallinfo(void);
+#endif /* NO_MALLINFO */
+
+/*
+  independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
+
+  independent_calloc is similar to calloc, but instead of returning a
+  single cleared space, it returns an array of pointers to n_elements
+  independent elements that can hold contents of size elem_size, each
+  of which starts out cleared, and can be independently freed,
+  realloc'ed etc. The elements are guaranteed to be adjacently
+  allocated (this is not guaranteed to occur with multiple callocs or
+  mallocs), which may also improve cache locality in some
+  applications.
+
+  The "chunks" argument is optional (i.e., may be null, which is
+  probably the most typical usage). If it is null, the returned array
+  is itself dynamically allocated and should also be freed when it is
+  no longer needed. Otherwise, the chunks array must be of at least
+  n_elements in length. It is filled in with the pointers to the
+  chunks.
+
+  In either case, independent_calloc returns this pointer array, or
+  null if the allocation failed.  If n_elements is zero and "chunks"
+  is null, it returns a chunk representing an array with zero elements
+  (which should be freed if not wanted).
+
+  Each element must be individually freed when it is no longer
+  needed. If you'd like to instead be able to free all at once, you
+  should instead use regular calloc and assign pointers into this
+  space to represent elements.  (In this case though, you cannot
+  independently free elements.)
+
+  independent_calloc simplifies and speeds up implementations of many
+  kinds of pools.  It may also be useful when constructing large data
+  structures that initially have a fixed number of fixed-sized nodes,
+  but the number is not known at compile time, and some of the nodes
+  may later need to be freed. For example:
+
+  struct Node { int item; struct Node* next; };
+
+  struct Node* build_list() {
+    struct Node** pool;
+    int n = read_number_of_nodes_needed();
+    if (n <= 0) return 0;
+    pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
+    if (pool == 0) die();
+    // organize into a linked list...
+    struct Node* first = pool[0];
+    for (i = 0; i < n-1; ++i)
+      pool[i]->next = pool[i+1];
+    free(pool);     // Can now free the array (or not, if it is needed later)
+    return first;
+  }
+*/
+void** dlindependent_calloc(size_t, size_t, void**);
+
+/*
+  independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
+
+  independent_comalloc allocates, all at once, a set of n_elements
+  chunks with sizes indicated in the "sizes" array.    It returns
+  an array of pointers to these elements, each of which can be
+  independently freed, realloc'ed etc. The elements are guaranteed to
+  be adjacently allocated (this is not guaranteed to occur with
+  multiple callocs or mallocs), which may also improve cache locality
+  in some applications.
+
+  The "chunks" argument is optional (i.e., may be null). If it is null
+  the returned array is itself dynamically allocated and should also
+  be freed when it is no longer needed. Otherwise, the chunks array
+  must be of at least n_elements in length. It is filled in with the
+  pointers to the chunks.
+
+  In either case, independent_comalloc returns this pointer array, or
+  null if the allocation failed.  If n_elements is zero and chunks is
+  null, it returns a chunk representing an array with zero elements
+  (which should be freed if not wanted).
+
+  Each element must be individually freed when it is no longer
+  needed. If you'd like to instead be able to free all at once, you
+  should instead use a single regular malloc, and assign pointers at
+  particular offsets in the aggregate space. (In this case though, you
+  cannot independently free elements.)
+
+  independent_comallac differs from independent_calloc in that each
+  element may have a different size, and also that it does not
+  automatically clear elements.
+
+  independent_comalloc can be used to speed up allocation in cases
+  where several structs or objects must always be allocated at the
+  same time.  For example:
+
+  struct Head { ... }
+  struct Foot { ... }
+
+  void send_message(char* msg) {
+    int msglen = strlen(msg);
+    size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
+    void* chunks[3];
+    if (independent_comalloc(3, sizes, chunks) == 0)
+      die();
+    struct Head* head = (struct Head*)(chunks[0]);
+    char*        body = (char*)(chunks[1]);
+    struct Foot* foot = (struct Foot*)(chunks[2]);
+    // ...
+  }
+
+  In general though, independent_comalloc is worth using only for
+  larger values of n_elements. For small values, you probably won't
+  detect enough difference from series of malloc calls to bother.
+
+  Overuse of independent_comalloc can increase overall memory usage,
+  since it cannot reuse existing noncontiguous small chunks that
+  might be available for some of the elements.
+*/
+void** dlindependent_comalloc(size_t, size_t*, void**);
+
+
+/*
+  pvalloc(size_t n);
+  Equivalent to valloc(minimum-page-that-holds(n)), that is,
+  round up n to nearest pagesize.
+ */
+void*  dlpvalloc(size_t);
+
+/*
+  malloc_trim(size_t pad);
+
+  If possible, gives memory back to the system (via negative arguments
+  to sbrk) if there is unused memory at the `high' end of the malloc
+  pool or in unused MMAP segments. You can call this after freeing
+  large blocks of memory to potentially reduce the system-level memory
+  requirements of a program. However, it cannot guarantee to reduce
+  memory. Under some allocation patterns, some large free blocks of
+  memory will be locked between two used chunks, so they cannot be
+  given back to the system.
+
+  The `pad' argument to malloc_trim represents the amount of free
+  trailing space to leave untrimmed. If this argument is zero, only
+  the minimum amount of memory to maintain internal data structures
+  will be left. Non-zero arguments can be supplied to maintain enough
+  trailing space to service future expected allocations without having
+  to re-obtain memory from the system.
+
+  Malloc_trim returns 1 if it actually released any memory, else 0.
+*/
+int  dlmalloc_trim(size_t);
+
+/*
+  malloc_usable_size(void* p);
+
+  Returns the number of bytes you can actually use in
+  an allocated chunk, which may be more than you requested (although
+  often not) due to alignment and minimum size constraints.
+  You can use this many bytes without worrying about
+  overwriting other allocated objects. This is not a particularly great
+  programming practice. malloc_usable_size can be more useful in
+  debugging and assertions, for example:
+
+  p = malloc(n);
+  assert(malloc_usable_size(p) >= 256);
+*/
+size_t dlmalloc_usable_size(void*);
+
+/*
+  malloc_stats();
+  Prints on stderr the amount of space obtained from the system (both
+  via sbrk and mmap), the maximum amount (which may be more than
+  current if malloc_trim and/or munmap got called), and the current
+  number of bytes allocated via malloc (or realloc, etc) but not yet
+  freed. Note that this is the number of bytes allocated, not the
+  number requested. It will be larger than the number requested
+  because of alignment and bookkeeping overhead. Because it includes
+  alignment wastage as being in use, this figure may be greater than
+  zero even when no user-level chunks are allocated.
+
+  The reported current and maximum system memory can be inaccurate if
+  a program makes other calls to system memory allocation functions
+  (normally sbrk) outside of malloc.
+
+  malloc_stats prints only the most commonly interesting statistics.
+  More information can be obtained by calling mallinfo.
+*/
+void  dlmalloc_stats(void);
+
+#endif /* ONLY_MSPACES */
+
+#if MSPACES
+
+/*
+  mspace is an opaque type representing an independent
+  region of space that supports mspace_malloc, etc.
+*/
+typedef void* mspace;
+
+/*
+  create_mspace creates and returns a new independent space with the
+  given initial capacity, or, if 0, the default granularity size.  It
+  returns null if there is no system memory available to create the
+  space.  If argument locked is non-zero, the space uses a separate
+  lock to control access. The capacity of the space will grow
+  dynamically as needed to service mspace_malloc requests.  You can
+  control the sizes of incremental increases of this space by
+  compiling with a different DEFAULT_GRANULARITY or dynamically
+  setting with mallopt(M_GRANULARITY, value).
+*/
+mspace create_mspace(size_t capacity, int locked);
+
+/*
+  destroy_mspace destroys the given space, and attempts to return all
+  of its memory back to the system, returning the total number of
+  bytes freed. After destruction, the results of access to all memory
+  used by the space become undefined.
+*/
+size_t destroy_mspace(mspace msp);
+
+/*
+  create_mspace_with_base uses the memory supplied as the initial base
+  of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
+  space is used for bookkeeping, so the capacity must be at least this
+  large. (Otherwise 0 is returned.) When this initial space is
+  exhausted, additional memory will be obtained from the system.
+  Destroying this space will deallocate all additionally allocated
+  space (if possible) but not the initial base.
+*/
+mspace create_mspace_with_base(void* base, size_t capacity, int locked);
+
+/*
+  mspace_malloc behaves as malloc, but operates within
+  the given space.
+*/
+void* mspace_malloc(mspace msp, size_t bytes);
+
+/*
+  mspace_free behaves as free, but operates within
+  the given space.
+
+  If compiled with FOOTERS==1, mspace_free is not actually needed.
+  free may be called instead of mspace_free because freed chunks from
+  any space are handled by their originating spaces.
+*/
+void mspace_free(mspace msp, void* mem);
+
+/*
+  mspace_realloc behaves as realloc, but operates within
+  the given space.
+
+  If compiled with FOOTERS==1, mspace_realloc is not actually
+  needed.  realloc may be called instead of mspace_realloc because
+  realloced chunks from any space are handled by their originating
+  spaces.
+*/
+void* mspace_realloc(mspace msp, void* mem, size_t newsize);
+
+/*
+  mspace_calloc behaves as calloc, but operates within
+  the given space.
+*/
+void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
+
+/*
+  mspace_memalign behaves as memalign, but operates within
+  the given space.
+*/
+void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
+
+/*
+  mspace_independent_calloc behaves as independent_calloc, but
+  operates within the given space.
+*/
+void** mspace_independent_calloc(mspace msp, size_t n_elements,
+                                 size_t elem_size, void* chunks[]);
+
+/*
+  mspace_independent_comalloc behaves as independent_comalloc, but
+  operates within the given space.
+*/
+void** mspace_independent_comalloc(mspace msp, size_t n_elements,
+                                   size_t sizes[], void* chunks[]);
+
+/*
+  mspace_footprint() returns the number of bytes obtained from the
+  system for this space.
+*/
+size_t mspace_footprint(mspace msp);
+
+/*
+  mspace_max_footprint() returns the peak number of bytes obtained from the
+  system for this space.
+*/
+size_t mspace_max_footprint(mspace msp);
+
+
+#if !NO_MALLINFO
+/*
+  mspace_mallinfo behaves as mallinfo, but reports properties of
+  the given space.
+*/
+struct mallinfo mspace_mallinfo(mspace msp);
+#endif /* NO_MALLINFO */
+
+/*
+  mspace_malloc_stats behaves as malloc_stats, but reports
+  properties of the given space.
+*/
+void mspace_malloc_stats(mspace msp);
+
+/*
+  mspace_trim behaves as malloc_trim, but
+  operates within the given space.
+*/
+int mspace_trim(mspace msp, size_t pad);
+
+/*
+  An alias for mallopt.
+*/
+int mspace_mallopt(int, int);
+
+#endif /* MSPACES */
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif /* __cplusplus */
+
+/*
+  ========================================================================
+  To make a fully customizable malloc.h header file, cut everything
+  above this line, put into file malloc.h, edit to suit, and #include it
+  on the next line, as well as in programs that use this malloc.
+  ========================================================================
+*/
+
+/* #include "malloc.h" */
+
+/*------------------------------ internal #includes ---------------------- */
+
+#ifdef WIN32
+#pragma warning( disable : 4146 ) /* no "unsigned" warnings */
+#endif /* WIN32 */
+
+#include <stdio.h>       /* for printing in malloc_stats */
+
+#ifndef LACKS_ERRNO_H
+#include <errno.h>       /* for MALLOC_FAILURE_ACTION */
+#endif /* LACKS_ERRNO_H */
+#if FOOTERS
+#include <time.h>        /* for magic initialization */
+#endif /* FOOTERS */
+#ifndef LACKS_STDLIB_H
+#include <stdlib.h>      /* for abort() */
+#endif /* LACKS_STDLIB_H */
+#ifdef DEBUG
+#if ABORT_ON_ASSERT_FAILURE
+#define assert(x) if(!(x)) ABORT
+#else /* ABORT_ON_ASSERT_FAILURE */
+#include <assert.h>
+#endif /* ABORT_ON_ASSERT_FAILURE */
+#else  /* DEBUG */
+#define assert(x)
+#endif /* DEBUG */
+#ifndef LACKS_STRING_H
+#include <string.h>      /* for memset etc */
+#endif  /* LACKS_STRING_H */
+#if USE_BUILTIN_FFS
+#ifndef LACKS_STRINGS_H
+#include <strings.h>     /* for ffs */
+#endif /* LACKS_STRINGS_H */
+#endif /* USE_BUILTIN_FFS */
+#if HAVE_MMAP
+#ifndef LACKS_SYS_MMAN_H
+#include <sys/mman.h>    /* for mmap */
+#endif /* LACKS_SYS_MMAN_H */
+#ifndef LACKS_FCNTL_H
+#include <fcntl.h>
+#endif /* LACKS_FCNTL_H */
+#endif /* HAVE_MMAP */
+#if HAVE_MORECORE
+#ifndef LACKS_UNISTD_H
+#include <unistd.h>     /* for sbrk */
+#else /* LACKS_UNISTD_H */
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
+extern void*     sbrk(ptrdiff_t);
+#endif /* FreeBSD etc */
+#endif /* LACKS_UNISTD_H */
+#endif /* HAVE_MMAP */
+
+#ifndef WIN32
+#ifndef malloc_getpagesize
+#  ifdef _SC_PAGESIZE         /* some SVR4 systems omit an underscore */
+#    ifndef _SC_PAGE_SIZE
+#      define _SC_PAGE_SIZE _SC_PAGESIZE
+#    endif
+#  endif
+#  ifdef _SC_PAGE_SIZE
+#    define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+#  else
+#    if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+       extern size_t getpagesize();
+#      define malloc_getpagesize getpagesize()
+#    else
+#      ifdef WIN32 /* use supplied emulation of getpagesize */
+#        define malloc_getpagesize getpagesize()
+#      else
+#        ifndef LACKS_SYS_PARAM_H
+#          include <sys/param.h>
+#        endif
+#        ifdef EXEC_PAGESIZE
+#          define malloc_getpagesize EXEC_PAGESIZE
+#        else
+#          ifdef NBPG
+#            ifndef CLSIZE
+#              define malloc_getpagesize NBPG
+#            else
+#              define malloc_getpagesize (NBPG * CLSIZE)
+#            endif
+#          else
+#            ifdef NBPC
+#              define malloc_getpagesize NBPC
+#            else
+#              ifdef PAGESIZE
+#                define malloc_getpagesize PAGESIZE
+#              else /* just guess */
+#                define malloc_getpagesize ((size_t)4096U)
+#              endif
+#            endif
+#          endif
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+#endif
+
+/* ------------------- size_t and alignment properties -------------------- */
+
+/* The byte and bit size of a size_t */
+#define SIZE_T_SIZE         (sizeof(size_t))
+#define SIZE_T_BITSIZE      (sizeof(size_t) << 3)
+
+/* Some constants coerced to size_t */
+/* Annoying but necessary to avoid errors on some plaftorms */
+#define SIZE_T_ZERO         ((size_t)0)
+#define SIZE_T_ONE          ((size_t)1)
+#define SIZE_T_TWO          ((size_t)2)
+#define TWO_SIZE_T_SIZES    (SIZE_T_SIZE<<1)
+#define FOUR_SIZE_T_SIZES   (SIZE_T_SIZE<<2)
+#define SIX_SIZE_T_SIZES    (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES)
+#define HALF_MAX_SIZE_T     (MAX_SIZE_T / 2U)
+
+/* The bit mask value corresponding to MALLOC_ALIGNMENT */
+#define CHUNK_ALIGN_MASK    (MALLOC_ALIGNMENT - SIZE_T_ONE)
+
+/* True if address a has acceptable alignment */
+#define is_aligned(A)       (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0)
+
+/* the number of bytes to offset an address to align it */
+#define align_offset(A)\
+ ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\
+  ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK))
+
+/* -------------------------- MMAP preliminaries ------------------------- */
+
+/*
+   If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and
+   checks to fail so compiler optimizer can delete code rather than
+   using so many "#if"s.
+*/
+
+
+/* MORECORE and MMAP must return MFAIL on failure */
+#define MFAIL                ((void*)(MAX_SIZE_T))
+#define CMFAIL               ((char*)(MFAIL)) /* defined for convenience */
+
+#if !HAVE_MMAP
+#define IS_MMAPPED_BIT       (SIZE_T_ZERO)
+#define USE_MMAP_BIT         (SIZE_T_ZERO)
+#define CALL_MMAP(s)         MFAIL
+#define CALL_MUNMAP(a, s)    (-1)
+#define DIRECT_MMAP(s)       MFAIL
+
+#else /* HAVE_MMAP */
+#define IS_MMAPPED_BIT       (SIZE_T_ONE)
+#define USE_MMAP_BIT         (SIZE_T_ONE)
+
+#ifndef WIN32
+#define CALL_MUNMAP(a, s)    munmap((a), (s))
+#define MMAP_PROT            (PROT_READ|PROT_WRITE)
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS        MAP_ANON
+#endif /* MAP_ANON */
+#ifdef MAP_ANONYMOUS
+#define MMAP_FLAGS           (MAP_PRIVATE|MAP_ANONYMOUS)
+#define CALL_MMAP(s)         mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0)
+#else /* MAP_ANONYMOUS */
+/*
+   Nearly all versions of mmap support MAP_ANONYMOUS, so the following
+   is unlikely to be needed, but is supplied just in case.
+*/
+#define MMAP_FLAGS           (MAP_PRIVATE)
+static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */
+#define CALL_MMAP(s) ((dev_zero_fd < 0) ? \
+           (dev_zero_fd = open("/dev/zero", O_RDWR), \
+            mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \
+            mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0))
+#endif /* MAP_ANONYMOUS */
+
+#define DIRECT_MMAP(s)       CALL_MMAP(s)
+#else /* WIN32 */
+
+/* Win32 MMAP via VirtualAlloc */
+static void* win32mmap(size_t size) {
+  void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
+  return (ptr != 0)? ptr: MFAIL;
+}
+
+/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */
+static void* win32direct_mmap(size_t size) {
+  void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN,
+                           PAGE_READWRITE);
+  return (ptr != 0)? ptr: MFAIL;
+}
+
+/* This function supports releasing coalesed segments */
+static int win32munmap(void* ptr, size_t size) {
+  MEMORY_BASIC_INFORMATION minfo;
+  char* cptr = ptr;
+  while (size) {
+    if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0)
+      return -1;
+    if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr ||
+        minfo.State != MEM_COMMIT || minfo.RegionSize > size)
+      return -1;
+    if (VirtualFree(cptr, 0, MEM_RELEASE) == 0)
+      return -1;
+    cptr += minfo.RegionSize;
+    size -= minfo.RegionSize;
+  }
+  return 0;
+}
+
+#define CALL_MMAP(s)         win32mmap(s)
+#define CALL_MUNMAP(a, s)    win32munmap((a), (s))
+#define DIRECT_MMAP(s)       win32direct_mmap(s)
+#endif /* WIN32 */
+#endif /* HAVE_MMAP */
+
+#if HAVE_MMAP && HAVE_MREMAP
+#define CALL_MREMAP(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv))
+#else  /* HAVE_MMAP && HAVE_MREMAP */
+#define CALL_MREMAP(addr, osz, nsz, mv) MFAIL
+#endif /* HAVE_MMAP && HAVE_MREMAP */
+
+#if HAVE_MORECORE
+#define CALL_MORECORE(S)     MORECORE(S)
+#else  /* HAVE_MORECORE */
+#define CALL_MORECORE(S)     MFAIL
+#endif /* HAVE_MORECORE */
+
+/* mstate bit set if continguous morecore disabled or failed */
+#define USE_NONCONTIGUOUS_BIT (4U)
+
+/* segment bit set in create_mspace_with_base */
+#define EXTERN_BIT            (8U)
+
+
+/* --------------------------- Lock preliminaries ------------------------ */
+
+#if USE_LOCKS
+
+/*
+  When locks are defined, there are up to two global locks:
+
+  * If HAVE_MORECORE, morecore_mutex protects sequences of calls to
+    MORECORE.  In many cases sys_alloc requires two calls, that should
+    not be interleaved with calls by other threads.  This does not
+    protect against direct calls to MORECORE by other threads not
+    using this lock, so there is still code to cope the best we can on
+    interference.
+
+  * magic_init_mutex ensures that mparams.magic and other
+    unique mparams values are initialized only once.
+*/
+
+#ifndef WIN32
+/* By default use posix locks */
+#include <pthread.h>
+#define MLOCK_T pthread_mutex_t
+#define INITIAL_LOCK(l)      pthread_mutex_init(l, NULL)
+#define ACQUIRE_LOCK(l)      pthread_mutex_lock(l)
+#define RELEASE_LOCK(l)      pthread_mutex_unlock(l)
+
+#if HAVE_MORECORE
+static MLOCK_T morecore_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif /* HAVE_MORECORE */
+
+static MLOCK_T magic_init_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#else /* WIN32 */
+/*
+   Because lock-protected regions have bounded times, and there
+   are no recursive lock calls, we can use simple spinlocks.
+*/
+
+#define MLOCK_T long
+static int win32_acquire_lock (MLOCK_T *sl) {
+  for (;;) {
+#ifdef InterlockedCompareExchangePointer
+    if (!InterlockedCompareExchange(sl, 1, 0))
+      return 0;
+#else  /* Use older void* version */
+    if (!InterlockedCompareExchange((void**)sl, (void*)1, (void*)0))
+      return 0;
+#endif /* InterlockedCompareExchangePointer */
+    Sleep (0);
+  }
+}
+
+static void win32_release_lock (MLOCK_T *sl) {
+  InterlockedExchange (sl, 0);
+}
+
+#define INITIAL_LOCK(l)      *(l)=0
+#define ACQUIRE_LOCK(l)      win32_acquire_lock(l)
+#define RELEASE_LOCK(l)      win32_release_lock(l)
+#if HAVE_MORECORE
+static MLOCK_T morecore_mutex;
+#endif /* HAVE_MORECORE */
+static MLOCK_T magic_init_mutex;
+#endif /* WIN32 */
+
+#define USE_LOCK_BIT               (2U)
+#else  /* USE_LOCKS */
+#define USE_LOCK_BIT               (0U)
+#define INITIAL_LOCK(l)
+#endif /* USE_LOCKS */
+
+#if USE_LOCKS && HAVE_MORECORE
+#define ACQUIRE_MORECORE_LOCK()    ACQUIRE_LOCK(&morecore_mutex);
+#define RELEASE_MORECORE_LOCK()    RELEASE_LOCK(&morecore_mutex);
+#else /* USE_LOCKS && HAVE_MORECORE */
+#define ACQUIRE_MORECORE_LOCK()
+#define RELEASE_MORECORE_LOCK()
+#endif /* USE_LOCKS && HAVE_MORECORE */
+
+#if USE_LOCKS
+#define ACQUIRE_MAGIC_INIT_LOCK()  ACQUIRE_LOCK(&magic_init_mutex);
+#define RELEASE_MAGIC_INIT_LOCK()  RELEASE_LOCK(&magic_init_mutex);
+#else  /* USE_LOCKS */
+#define ACQUIRE_MAGIC_INIT_LOCK()
+#define RELEASE_MAGIC_INIT_LOCK()
+#endif /* USE_LOCKS */
+
+
+/* -----------------------  Chunk representations ------------------------ */
+
+/*
+  (The following includes lightly edited explanations by Colin Plumb.)
+
+  The malloc_chunk declaration below is misleading (but accurate and
+  necessary).  It declares a "view" into memory allowing access to
+  necessary fields at known offsets from a given base.
+
+  Chunks of memory are maintained using a `boundary tag' method as
+  originally described by Knuth.  (See the paper by Paul Wilson
+  ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such
+  techniques.)  Sizes of free chunks are stored both in the front of
+  each chunk and at the end.  This makes consolidating fragmented
+  chunks into bigger chunks fast.  The head fields also hold bits
+  representing whether chunks are free or in use.
+
+  Here are some pictures to make it clearer.  They are "exploded" to
+  show that the state of a chunk can be thought of as extending from
+  the high 31 bits of the head field of its header through the
+  prev_foot and PINUSE_BIT bit of the following chunk header.
+
+  A chunk that's in use looks like:
+
+   chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+           | Size of previous chunk (if P = 1)                             |
+           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
+         | Size of this chunk                                         1| +-+
+   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         |                                                               |
+         +-                                                             -+
+         |                                                               |
+         +-                                                             -+
+         |                                                               :
+         +-      size - sizeof(size_t) available payload bytes          -+
+         :                                                               |
+ chunk-> +-                                                             -+
+         |                                                               |
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|
+       | Size of next chunk (may or may not be in use)               | +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+    And if it's free, it looks like this:
+
+   chunk-> +-                                                             -+
+           | User payload (must be in use, or we would have merged!)       |
+           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
+         | Size of this chunk                                         0| +-+
+   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         | Next pointer                                                  |
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         | Prev pointer                                                  |
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         |                                                               :
+         +-      size - sizeof(struct chunk) unused bytes               -+
+         :                                                               |
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         | Size of this chunk                                            |
+         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|
+       | Size of next chunk (must be in use, or we would have merged)| +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                                                               :
+       +- User payload                                                -+
+       :                                                               |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                                                                     |0|
+                                                                     +-+
+  Note that since we always merge adjacent free chunks, the chunks
+  adjacent to a free chunk must be in use.
+
+  Given a pointer to a chunk (which can be derived trivially from the
+  payload pointer) we can, in O(1) time, find out whether the adjacent
+  chunks are free, and if so, unlink them from the lists that they
+  are on and merge them with the current chunk.
+
+  Chunks always begin on even word boundaries, so the mem portion
+  (which is returned to the user) is also on an even word boundary, and
+  thus at least double-word aligned.
+
+  The P (PINUSE_BIT) bit, stored in the unused low-order bit of the
+  chunk size (which is always a multiple of two words), is an in-use
+  bit for the *previous* chunk.  If that bit is *clear*, then the
+  word before the current chunk size contains the previous chunk
+  size, and can be used to find the front of the previous chunk.
+  The very first chunk allocated always has this bit set, preventing
+  access to non-existent (or non-owned) memory. If pinuse is set for
+  any given chunk, then you CANNOT determine the size of the
+  previous chunk, and might even get a memory addressing fault when
+  trying to do so.
+
+  The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of
+  the chunk size redundantly records whether the current chunk is
+  inuse. This redundancy enables usage checks within free and realloc,
+  and reduces indirection when freeing and consolidating chunks.
+
+  Each freshly allocated chunk must have both cinuse and pinuse set.
+  That is, each allocated chunk borders either a previously allocated
+  and still in-use chunk, or the base of its memory arena. This is
+  ensured by making all allocations from the the `lowest' part of any
+  found chunk.  Further, no free chunk physically borders another one,
+  so each free chunk is known to be preceded and followed by either
+  inuse chunks or the ends of memory.
+
+  Note that the `foot' of the current chunk is actually represented
+  as the prev_foot of the NEXT chunk. This makes it easier to
+  deal with alignments etc but can be very confusing when trying
+  to extend or adapt this code.
+
+  The exceptions to all this are
+
+     1. The special chunk `top' is the top-most available chunk (i.e.,
+        the one bordering the end of available memory). It is treated
+        specially.  Top is never included in any bin, is used only if
+        no other chunk is available, and is released back to the
+        system if it is very large (see M_TRIM_THRESHOLD).  In effect,
+        the top chunk is treated as larger (and thus less well
+        fitting) than any other available chunk.  The top chunk
+        doesn't update its trailing size field since there is no next
+        contiguous chunk that would have to index off it. However,
+        space is still allocated for it (TOP_FOOT_SIZE) to enable
+        separation or merging when space is extended.
+
+     3. Chunks allocated via mmap, which have the lowest-order bit
+        (IS_MMAPPED_BIT) set in their prev_foot fields, and do not set
+        PINUSE_BIT in their head fields.  Because they are allocated
+        one-by-one, each must carry its own prev_foot field, which is
+        also used to hold the offset this chunk has within its mmapped
+        region, which is needed to preserve alignment. Each mmapped
+        chunk is trailed by the first two fields of a fake next-chunk
+        for sake of usage checks.
+
+*/
+
+struct malloc_chunk {
+  size_t               prev_foot;  /* Size of previous chunk (if free).  */
+  size_t               head;       /* Size and inuse bits. */
+  struct malloc_chunk* fd;         /* double links -- used only if free. */
+  struct malloc_chunk* bk;
+};
+
+typedef struct malloc_chunk  mchunk;
+typedef struct malloc_chunk* mchunkptr;
+typedef struct malloc_chunk* sbinptr;  /* The type of bins of chunks */
+typedef unsigned int bindex_t;         /* Described below */
+typedef unsigned int binmap_t;         /* Described below */
+typedef unsigned int flag_t;           /* The type of various bit flag sets */
+
+/* ------------------- Chunks sizes and alignments ----------------------- */
+
+#define MCHUNK_SIZE         (sizeof(mchunk))
+
+#if FOOTERS
+#define CHUNK_OVERHEAD      (TWO_SIZE_T_SIZES)
+#else /* FOOTERS */
+#define CHUNK_OVERHEAD      (SIZE_T_SIZE)
+#endif /* FOOTERS */
+
+/* MMapped chunks need a second word of overhead ... */
+#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)
+/* ... and additional padding for fake next-chunk at foot */
+#define MMAP_FOOT_PAD       (FOUR_SIZE_T_SIZES)
+
+/* The smallest size we can malloc is an aligned minimal chunk */
+#define MIN_CHUNK_SIZE\
+  ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
+
+/* conversion from malloc headers to user pointers, and back */
+#define chunk2mem(p)        ((void*)((char*)(p)       + TWO_SIZE_T_SIZES))
+#define mem2chunk(mem)      ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES))
+/* chunk associated with aligned address A */
+#define align_as_chunk(A)   (mchunkptr)((A) + align_offset(chunk2mem(A)))
+
+/* Bounds on request (not chunk) sizes. */
+#define MAX_REQUEST         ((-MIN_CHUNK_SIZE) << 2)
+#define MIN_REQUEST         (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE)
+
+/* pad request bytes into a usable size */
+#define pad_request(req) \
+   (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
+
+/* pad request, checking for minimum (but not maximum) */
+#define request2size(req) \
+  (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req))
+
+
+/* ------------------ Operations on head and foot fields ----------------- */
+
+/*
+  The head field of a chunk is or'ed with PINUSE_BIT when previous
+  adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in
+  use. If the chunk was obtained with mmap, the prev_foot field has
+  IS_MMAPPED_BIT set, otherwise holding the offset of the base of the
+  mmapped region to the base of the chunk.
+*/
+
+#define PINUSE_BIT          (SIZE_T_ONE)
+#define CINUSE_BIT          (SIZE_T_TWO)
+#define INUSE_BITS          (PINUSE_BIT|CINUSE_BIT)
+
+/* Head value for fenceposts */
+#define FENCEPOST_HEAD      (INUSE_BITS|SIZE_T_SIZE)
+
+/* extraction of fields from head words */
+#define cinuse(p)           ((p)->head & CINUSE_BIT)
+#define pinuse(p)           ((p)->head & PINUSE_BIT)
+#define chunksize(p)        ((p)->head & ~(INUSE_BITS))
+
+#define clear_pinuse(p)     ((p)->head &= ~PINUSE_BIT)
+#define clear_cinuse(p)     ((p)->head &= ~CINUSE_BIT)
+
+/* Treat space at ptr +/- offset as a chunk */
+#define chunk_plus_offset(p, s)  ((mchunkptr)(((char*)(p)) + (s)))
+#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s)))
+
+/* Ptr to next or previous physical malloc_chunk. */
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~INUSE_BITS)))
+#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) ))
+
+/* extract next chunk's pinuse bit */
+#define next_pinuse(p)  ((next_chunk(p)->head) & PINUSE_BIT)
+
+/* Get/set size at footer */
+#define get_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot)
+#define set_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s))
+
+/* Set size, pinuse bit, and foot */
+#define set_size_and_pinuse_of_free_chunk(p, s)\
+  ((p)->head = (s|PINUSE_BIT), set_foot(p, s))
+
+/* Set size, pinuse bit, foot, and clear next pinuse */
+#define set_free_with_pinuse(p, s, n)\
+  (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s))
+
+#define is_mmapped(p)\
+  (!((p)->head & PINUSE_BIT) && ((p)->prev_foot & IS_MMAPPED_BIT))
+
+/* Get the internal overhead associated with chunk p */
+#define overhead_for(p)\
+ (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD)
+
+/* Return true if malloced space is not necessarily cleared */
+#if MMAP_CLEARS
+#define calloc_must_clear(p) (!is_mmapped(p))
+#else /* MMAP_CLEARS */
+#define calloc_must_clear(p) (1)
+#endif /* MMAP_CLEARS */
+
+/* ---------------------- Overlaid data structures ----------------------- */
+
+/*
+  When chunks are not in use, they are treated as nodes of either
+  lists or trees.
+
+  "Small"  chunks are stored in circular doubly-linked lists, and look
+  like this:
+
+    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Size of previous chunk                            |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `head:' |             Size of chunk, in bytes                         |P|
+      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Forward pointer to next chunk in list             |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Back pointer to previous chunk in list            |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Unused space (may be 0 bytes long)                .
+            .                                                               .
+            .                                                               |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `foot:' |             Size of chunk, in bytes                           |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+  Larger chunks are kept in a form of bitwise digital trees (aka
+  tries) keyed on chunksizes.  Because malloc_tree_chunks are only for
+  free chunks greater than 256 bytes, their size doesn't impose any
+  constraints on user chunk sizes.  Each node looks like:
+
+    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Size of previous chunk                            |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `head:' |             Size of chunk, in bytes                         |P|
+      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Forward pointer to next chunk of same size        |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Back pointer to previous chunk of same size       |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Pointer to left child (child[0])                  |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Pointer to right child (child[1])                 |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Pointer to parent                                 |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             bin index of this chunk                           |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+            |             Unused space                                      .
+            .                                                               |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `foot:' |             Size of chunk, in bytes                           |
+            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+  Each tree holding treenodes is a tree of unique chunk sizes.  Chunks
+  of the same size are arranged in a circularly-linked list, with only
+  the oldest chunk (the next to be used, in our FIFO ordering)
+  actually in the tree.  (Tree members are distinguished by a non-null
+  parent pointer.)  If a chunk with the same size an an existing node
+  is inserted, it is linked off the existing node using pointers that
+  work in the same way as fd/bk pointers of small chunks.
+
+  Each tree contains a power of 2 sized range of chunk sizes (the
+  smallest is 0x100 <= x < 0x180), which is is divided in half at each
+  tree level, with the chunks in the smaller half of the range (0x100
+  <= x < 0x140 for the top nose) in the left subtree and the larger
+  half (0x140 <= x < 0x180) in the right subtree.  This is, of course,
+  done by inspecting individual bits.
+
+  Using these rules, each node's left subtree contains all smaller
+  sizes than its right subtree.  However, the node at the root of each
+  subtree has no particular ordering relationship to either.  (The
+  dividing line between the subtree sizes is based on trie relation.)
+  If we remove the last chunk of a given size from the interior of the
+  tree, we need to replace it with a leaf node.  The tree ordering
+  rules permit a node to be replaced by any leaf below it.
+
+  The smallest chunk in a tree (a common operation in a best-fit
+  allocator) can be found by walking a path to the leftmost leaf in
+  the tree.  Unlike a usual binary tree, where we follow left child
+  pointers until we reach a null, here we follow the right child
+  pointer any time the left one is null, until we reach a leaf with
+  both child pointers null. The smallest chunk in the tree will be
+  somewhere along that path.
+
+  The worst case number of steps to add, find, or remove a node is
+  bounded by the number of bits differentiating chunks within
+  bins. Under current bin calculations, this ranges from 6 up to 21
+  (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case
+  is of course much better.
+*/
+
+struct malloc_tree_chunk {
+  /* The first four fields must be compatible with malloc_chunk */
+  size_t                    prev_foot;
+  size_t                    head;
+  struct malloc_tree_chunk* fd;
+  struct malloc_tree_chunk* bk;
+
+  struct malloc_tree_chunk* child[2];
+  struct malloc_tree_chunk* parent;
+  bindex_t                  index;
+};
+
+typedef struct malloc_tree_chunk  tchunk;
+typedef struct malloc_tree_chunk* tchunkptr;
+typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */
+
+/* A little helper macro for trees */
+#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1])
+
+/* ----------------------------- Segments -------------------------------- */
+
+/*
+  Each malloc space may include non-contiguous segments, held in a
+  list headed by an embedded malloc_segment record representing the
+  top-most space. Segments also include flags holding properties of
+  the space. Large chunks that are directly allocated by mmap are not
+  included in this list. They are instead independently created and
+  destroyed without otherwise keeping track of them.
+
+  Segment management mainly comes into play for spaces allocated by
+  MMAP.  Any call to MMAP might or might not return memory that is
+  adjacent to an existing segment.  MORECORE normally contiguously
+  extends the current space, so this space is almost always adjacent,
+  which is simpler and faster to deal with. (This is why MORECORE is
+  used preferentially to MMAP when both are available -- see
+  sys_alloc.)  When allocating using MMAP, we don't use any of the
+  hinting mechanisms (inconsistently) supported in various
+  implementations of unix mmap, or distinguish reserving from
+  committing memory. Instead, we just ask for space, and exploit
+  contiguity when we get it.  It is probably possible to do
+  better than this on some systems, but no general scheme seems
+  to be significantly better.
+
+  Management entails a simpler variant of the consolidation scheme
+  used for chunks to reduce fragmentation -- new adjacent memory is
+  normally prepended or appended to an existing segment. However,
+  there are limitations compared to chunk consolidation that mostly
+  reflect the fact that segment processing is relatively infrequent
+  (occurring only when getting memory from system) and that we
+  don't expect to have huge numbers of segments:
+
+  * Segments are not indexed, so traversal requires linear scans.  (It
+    would be possible to index these, but is not worth the extra
+    overhead and complexity for most programs on most platforms.)
+  * New segments are only appended to old ones when holding top-most
+    memory; if they cannot be prepended to others, they are held in
+    different segments.
+
+  Except for the top-most segment of an mstate, each segment record
+  is kept at the tail of its segment. Segments are added by pushing
+  segment records onto the list headed by &mstate.seg for the
+  containing mstate.
+
+  Segment flags control allocation/merge/deallocation policies:
+  * If EXTERN_BIT set, then we did not allocate this segment,
+    and so should not try to deallocate or merge with others.
+    (This currently holds only for the initial segment passed
+    into create_mspace_with_base.)
+  * If IS_MMAPPED_BIT set, the segment may be merged with
+    other surrounding mmapped segments and trimmed/de-allocated
+    using munmap.
+  * If neither bit is set, then the segment was obtained using
+    MORECORE so can be merged with surrounding MORECORE'd segments
+    and deallocated/trimmed using MORECORE with negative arguments.
+*/
+
+struct malloc_segment {
+  char*        base;             /* base address */
+  size_t       size;             /* allocated size */
+  struct malloc_segment* next;   /* ptr to next segment */
+  flag_t       sflags;           /* mmap and extern flag */
+};
+
+#define is_mmapped_segment(S)  ((S)->sflags & IS_MMAPPED_BIT)
+#define is_extern_segment(S)   ((S)->sflags & EXTERN_BIT)
+
+typedef struct malloc_segment  msegment;
+typedef struct malloc_segment* msegmentptr;
+
+/* ---------------------------- malloc_state ----------------------------- */
+
+/*
+   A malloc_state holds all of the bookkeeping for a space.
+   The main fields are:
+
+  Top
+    The topmost chunk of the currently active segment. Its size is
+    cached in topsize.  The actual size of topmost space is
+    topsize+TOP_FOOT_SIZE, which includes space reserved for adding
+    fenceposts and segment records if necessary when getting more
+    space from the system.  The size at which to autotrim top is
+    cached from mparams in trim_check, except that it is disabled if
+    an autotrim fails.
+
+  Designated victim (dv)
+    This is the preferred chunk for servicing small requests that
+    don't have exact fits.  It is normally the chunk split off most
+    recently to service another small request.  Its size is cached in
+    dvsize. The link fields of this chunk are not maintained since it
+    is not kept in a bin.
+
+  SmallBins
+    An array of bin headers for free chunks.  These bins hold chunks
+    with sizes less than MIN_LARGE_SIZE bytes. Each bin contains
+    chunks of all the same size, spaced 8 bytes apart.  To simplify
+    use in double-linked lists, each bin header acts as a malloc_chunk
+    pointing to the real first node, if it exists (else pointing to
+    itself).  This avoids special-casing for headers.  But to avoid
+    waste, we allocate only the fd/bk pointers of bins, and then use
+    repositioning tricks to treat these as the fields of a chunk.
+
+  TreeBins
+    Treebins are pointers to the roots of trees holding a range of
+    sizes. There are 2 equally spaced treebins for each power of two
+    from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything
+    larger.
+
+  Bin maps
+    There is one bit map for small bins ("smallmap") and one for
+    treebins ("treemap).  Each bin sets its bit when non-empty, and
+    clears the bit when empty.  Bit operations are then used to avoid
+    bin-by-bin searching -- nearly all "search" is done without ever
+    looking at bins that won't be selected.  The bit maps
+    conservatively use 32 bits per map word, even if on 64bit system.
+    For a good description of some of the bit-based techniques used
+    here, see Henry S. Warren Jr's book "Hacker's Delight" (and
+    supplement at http://hackersdelight.org/). Many of these are
+    intended to reduce the branchiness of paths through malloc etc, as
+    well as to reduce the number of memory locations read or written.
+
+  Segments
+    A list of segments headed by an embedded malloc_segment record
+    representing the initial space.
+
+  Address check support
+    The least_addr field is the least address ever obtained from
+    MORECORE or MMAP. Attempted frees and reallocs of any address less
+    than this are trapped (unless INSECURE is defined).
+
+  Magic tag
+    A cross-check field that should always hold same value as mparams.magic.
+
+  Flags
+    Bits recording whether to use MMAP, locks, or contiguous MORECORE
+
+  Statistics
+    Each space keeps track of current and maximum system memory
+    obtained via MORECORE or MMAP.
+
+  Locking
+    If USE_LOCKS is defined, the "mutex" lock is acquired and released
+    around every public call using this mspace.
+*/
+
+/* Bin types, widths and sizes */
+#define NSMALLBINS        (32U)
+#define NTREEBINS         (32U)
+#define SMALLBIN_SHIFT    (3U)
+#define SMALLBIN_WIDTH    (SIZE_T_ONE << SMALLBIN_SHIFT)
+#define TREEBIN_SHIFT     (8U)
+#define MIN_LARGE_SIZE    (SIZE_T_ONE << TREEBIN_SHIFT)
+#define MAX_SMALL_SIZE    (MIN_LARGE_SIZE - SIZE_T_ONE)
+#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD)
+
+struct malloc_state {
+  binmap_t   smallmap;
+  binmap_t   treemap;
+  size_t     dvsize;
+  size_t     topsize;
+  char*      least_addr;
+  mchunkptr  dv;
+  mchunkptr  top;
+  size_t     trim_check;
+  size_t     magic;
+  mchunkptr  smallbins[(NSMALLBINS+1)*2];
+  tbinptr    treebins[NTREEBINS];
+  size_t     footprint;
+  size_t     max_footprint;
+  flag_t     mflags;
+#if USE_LOCKS
+  MLOCK_T    mutex;     /* locate lock among fields that rarely change */
+#endif /* USE_LOCKS */
+  msegment   seg;
+};
+
+typedef struct malloc_state*    mstate;
+
+/* ------------- Global malloc_state and malloc_params ------------------- */
+
+/*
+  malloc_params holds global properties, including those that can be
+  dynamically set using mallopt. There is a single instance, mparams,
+  initialized in init_mparams.
+*/
+
+struct malloc_params {
+  size_t magic;
+  size_t page_size;
+  size_t granularity;
+  size_t mmap_threshold;
+  size_t trim_threshold;
+  flag_t default_mflags;
+};
+
+static struct malloc_params mparams;
+
+/* The global malloc_state used for all non-"mspace" calls */
+static struct malloc_state _gm_;
+#define gm                 (&_gm_)
+#define is_global(M)       ((M) == &_gm_)
+#define is_initialized(M)  ((M)->top != 0)
+
+/* -------------------------- system alloc setup ------------------------- */
+
+/* Operations on mflags */
+
+#define use_lock(M)           ((M)->mflags &   USE_LOCK_BIT)
+#define enable_lock(M)        ((M)->mflags |=  USE_LOCK_BIT)
+#define disable_lock(M)       ((M)->mflags &= ~USE_LOCK_BIT)
+
+#define use_mmap(M)           ((M)->mflags &   USE_MMAP_BIT)
+#define enable_mmap(M)        ((M)->mflags |=  USE_MMAP_BIT)
+#define disable_mmap(M)       ((M)->mflags &= ~USE_MMAP_BIT)
+
+#define use_noncontiguous(M)  ((M)->mflags &   USE_NONCONTIGUOUS_BIT)
+#define disable_contiguous(M) ((M)->mflags |=  USE_NONCONTIGUOUS_BIT)
+
+#define set_lock(M,L)\
+ ((M)->mflags = (L)?\
+  ((M)->mflags | USE_LOCK_BIT) :\
+  ((M)->mflags & ~USE_LOCK_BIT))
+
+/* page-align a size */
+#define page_align(S)\
+ (((S) + (mparams.page_size)) & ~(mparams.page_size - SIZE_T_ONE))
+
+/* granularity-align a size */
+#define granularity_align(S)\
+  (((S) + (mparams.granularity)) & ~(mparams.granularity - SIZE_T_ONE))
+
+#define is_page_aligned(S)\
+   (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0)
+#define is_granularity_aligned(S)\
+   (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0)
+
+/*  True if segment S holds address A */
+#define segment_holds(S, A)\
+  ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)
+
+/* Return segment holding given address */
+static msegmentptr segment_holding(mstate m, char* addr) {
+  msegmentptr sp = &m->seg;
+  for (;;) {
+    if (addr >= sp->base && addr < sp->base + sp->size)
+      return sp;
+    if ((sp = sp->next) == 0)
+      return 0;
+  }
+}
+
+/* Return true if segment contains a segment link */
+static int has_segment_link(mstate m, msegmentptr ss) {
+  msegmentptr sp = &m->seg;
+  for (;;) {
+    if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size)
+      return 1;
+    if ((sp = sp->next) == 0)
+      return 0;
+  }
+}
+
+#ifndef MORECORE_CANNOT_TRIM
+#define should_trim(M,s)  ((s) > (M)->trim_check)
+#else  /* MORECORE_CANNOT_TRIM */
+#define should_trim(M,s)  (0)
+#endif /* MORECORE_CANNOT_TRIM */
+
+/*
+  TOP_FOOT_SIZE is padding at the end of a segment, including space
+  that may be needed to place segment records and fenceposts when new
+  noncontiguous segments are added.
+*/
+#define TOP_FOOT_SIZE\
+  (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE)
+
+
+/* -------------------------------  Hooks -------------------------------- */
+
+/*
+  PREACTION should be defined to return 0 on success, and nonzero on
+  failure. If you are not using locking, you can redefine these to do
+  anything you like.
+*/
+
+#if USE_LOCKS
+
+/* Ensure locks are initialized */
+#define GLOBALLY_INITIALIZE() (mparams.page_size == 0 && init_mparams())
+
+#define PREACTION(M)  ((GLOBALLY_INITIALIZE() || use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0)
+#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); }
+#else /* USE_LOCKS */
+
+#ifndef PREACTION
+#define PREACTION(M) (0)
+#endif  /* PREACTION */
+
+#ifndef POSTACTION
+#define POSTACTION(M)
+#endif  /* POSTACTION */
+
+#endif /* USE_LOCKS */
+
+/*
+  CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses.
+  USAGE_ERROR_ACTION is triggered on detected bad frees and
+  reallocs. The argument p is an address that might have triggered the
+  fault. It is ignored by the two predefined actions, but might be
+  useful in custom actions that try to help diagnose errors.
+*/
+
+#if PROCEED_ON_ERROR
+
+/* A count of the number of corruption errors causing resets */
+int malloc_corruption_error_count;
+
+/* default corruption action */
+static void reset_on_error(mstate m);
+
+#define CORRUPTION_ERROR_ACTION(m)  reset_on_error(m)
+#define USAGE_ERROR_ACTION(m, p)
+
+#else /* PROCEED_ON_ERROR */
+
+#ifndef CORRUPTION_ERROR_ACTION
+#define CORRUPTION_ERROR_ACTION(m) ABORT
+#endif /* CORRUPTION_ERROR_ACTION */
+
+#ifndef USAGE_ERROR_ACTION
+#define USAGE_ERROR_ACTION(m,p) ABORT
+#endif /* USAGE_ERROR_ACTION */
+
+#endif /* PROCEED_ON_ERROR */
+
+/* -------------------------- Debugging setup ---------------------------- */
+
+#if ! DEBUG
+
+#define check_free_chunk(M,P)
+#define check_inuse_chunk(M,P)
+#define check_malloced_chunk(M,P,N)
+#define check_mmapped_chunk(M,P)
+#define check_malloc_state(M)
+#define check_top_chunk(M,P)
+
+#else /* DEBUG */
+#define check_free_chunk(M,P)       do_check_free_chunk(M,P)
+#define check_inuse_chunk(M,P)      do_check_inuse_chunk(M,P)
+#define check_top_chunk(M,P)        do_check_top_chunk(M,P)
+#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N)
+#define check_mmapped_chunk(M,P)    do_check_mmapped_chunk(M,P)
+#define check_malloc_state(M)       do_check_malloc_state(M)
+
+static void   do_check_any_chunk(mstate m, mchunkptr p);
+static void   do_check_top_chunk(mstate m, mchunkptr p);
+static void   do_check_mmapped_chunk(mstate m, mchunkptr p);
+static void   do_check_inuse_chunk(mstate m, mchunkptr p);
+static void   do_check_free_chunk(mstate m, mchunkptr p);
+static void   do_check_malloced_chunk(mstate m, void* mem, size_t s);
+static void   do_check_tree(mstate m, tchunkptr t);
+static void   do_check_treebin(mstate m, bindex_t i);
+static void   do_check_smallbin(mstate m, bindex_t i);
+static void   do_check_malloc_state(mstate m);
+static int    bin_find(mstate m, mchunkptr x);
+static size_t traverse_and_check(mstate m);
+#endif /* DEBUG */
+
+/* ---------------------------- Indexing Bins ---------------------------- */
+
+#define is_small(s)         (((s) >> SMALLBIN_SHIFT) < NSMALLBINS)
+#define small_index(s)      ((s)  >> SMALLBIN_SHIFT)
+#define small_index2size(i) ((i)  << SMALLBIN_SHIFT)
+#define MIN_SMALL_INDEX     (small_index(MIN_CHUNK_SIZE))
+
+/* addressing by index. See above about smallbin repositioning */
+#define smallbin_at(M, i)   ((sbinptr)((char*)&((M)->smallbins[(i)<<1])))
+#define treebin_at(M,i)     (&((M)->treebins[i]))
+
+/* assign tree index for size S to variable I */
+#if defined(__GNUC__) && defined(i386)
+#define compute_tree_index(S, I)\
+{\
+  size_t X = S >> TREEBIN_SHIFT;\
+  if (X == 0)\
+    I = 0;\
+  else if (X > 0xFFFF)\
+    I = NTREEBINS-1;\
+  else {\
+    unsigned int K;\
+    __asm__("bsrl %1,%0\n\t" : "=r" (K) : "rm"  (X));\
+    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
+  }\
+}
+#else /* GNUC */
+#define compute_tree_index(S, I)\
+{\
+  size_t X = S >> TREEBIN_SHIFT;\
+  if (X == 0)\
+    I = 0;\
+  else if (X > 0xFFFF)\
+    I = NTREEBINS-1;\
+  else {\
+    unsigned int Y = (unsigned int)X;\
+    unsigned int N = ((Y - 0x100) >> 16) & 8;\
+    unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\
+    N += K;\
+    N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\
+    K = 14 - N + ((Y <<= K) >> 15);\
+    I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\
+  }\
+}
+#endif /* GNUC */
+
+/* Bit representing maximum resolved size in a treebin at i */
+#define bit_for_tree_index(i) \
+   (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2)
+
+/* Shift placing maximum resolved bit in a treebin at i as sign bit */
+#define leftshift_for_tree_index(i) \
+   ((i == NTREEBINS-1)? 0 : \
+    ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2)))
+
+/* The size of the smallest chunk held in bin with index i */
+#define minsize_for_tree_index(i) \
+   ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) |  \
+   (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1)))
+
+
+/* ------------------------ Operations on bin maps ----------------------- */
+
+/* bit corresponding to given index */
+#define idx2bit(i)              ((binmap_t)(1) << (i))
+
+/* Mark/Clear bits with given index */
+#define mark_smallmap(M,i)      ((M)->smallmap |=  idx2bit(i))
+#define clear_smallmap(M,i)     ((M)->smallmap &= ~idx2bit(i))
+#define smallmap_is_marked(M,i) ((M)->smallmap &   idx2bit(i))
+
+#define mark_treemap(M,i)       ((M)->treemap  |=  idx2bit(i))
+#define clear_treemap(M,i)      ((M)->treemap  &= ~idx2bit(i))
+#define treemap_is_marked(M,i)  ((M)->treemap  &   idx2bit(i))
+
+/* index corresponding to given bit */
+
+#if defined(__GNUC__) && defined(i386)
+#define compute_bit2idx(X, I)\
+{\
+  unsigned int J;\
+  __asm__("bsfl %1,%0\n\t" : "=r" (J) : "rm" (X));\
+  I = (bindex_t)J;\
+}
+
+#else /* GNUC */
+#if  USE_BUILTIN_FFS
+#define compute_bit2idx(X, I) I = ffs(X)-1
+
+#else /* USE_BUILTIN_FFS */
+#define compute_bit2idx(X, I)\
+{\
+  unsigned int Y = X - 1;\
+  unsigned int K = Y >> (16-4) & 16;\
+  unsigned int N = K;        Y >>= K;\
+  N += K = Y >> (8-3) &  8;  Y >>= K;\
+  N += K = Y >> (4-2) &  4;  Y >>= K;\
+  N += K = Y >> (2-1) &  2;  Y >>= K;\
+  N += K = Y >> (1-0) &  1;  Y >>= K;\
+  I = (bindex_t)(N + Y);\
+}
+#endif /* USE_BUILTIN_FFS */
+#endif /* GNUC */
+
+/* isolate the least set bit of a bitmap */
+#define least_bit(x)         ((x) & -(x))
+
+/* mask with all bits to left of least bit of x on */
+#define left_bits(x)         ((x<<1) | -(x<<1))
+
+/* mask with all bits to left of or equal to least bit of x on */
+#define same_or_left_bits(x) ((x) | -(x))
+
+
+/* ----------------------- Runtime Check Support ------------------------- */
+
+/*
+  For security, the main invariant is that malloc/free/etc never
+  writes to a static address other than malloc_state, unless static
+  malloc_state itself has been corrupted, which cannot occur via
+  malloc (because of these checks). In essence this means that we
+  believe all pointers, sizes, maps etc held in malloc_state, but
+  check all of those linked or offsetted from other embedded data
+  structures.  These checks are interspersed with main code in a way
+  that tends to minimize their run-time cost.
+
+  When FOOTERS is defined, in addition to range checking, we also
+  verify footer fields of inuse chunks, which can be used guarantee
+  that the mstate controlling malloc/free is intact.  This is a
+  streamlined version of the approach described by William Robertson
+  et al in "Run-time Detection of Heap-based Overflows" LISA'03
+  http://www.usenix.org/events/lisa03/tech/robertson.html The footer
+  of an inuse chunk holds the xor of its mstate and a random seed,
+  that is checked upon calls to free() and realloc().  This is
+  (probablistically) unguessable from outside the program, but can be
+  computed by any code successfully malloc'ing any chunk, so does not
+  itself provide protection against code that has already broken
+  security through some other means.  Unlike Robertson et al, we
+  always dynamically check addresses of all offset chunks (previous,
+  next, etc). This turns out to be cheaper than relying on hashes.
+*/
+
+#if !INSECURE
+/* Check if address a is at least as high as any from MORECORE or MMAP */
+#define ok_address(M, a) ((char*)(a) >= (M)->least_addr)
+/* Check if address of next chunk n is higher than base chunk p */
+#define ok_next(p, n)    ((char*)(p) < (char*)(n))
+/* Check if p has its cinuse bit on */
+#define ok_cinuse(p)     cinuse(p)
+/* Check if p has its pinuse bit on */
+#define ok_pinuse(p)     pinuse(p)
+
+#else /* !INSECURE */
+#define ok_address(M, a) (1)
+#define ok_next(b, n)    (1)
+#define ok_cinuse(p)     (1)
+#define ok_pinuse(p)     (1)
+#endif /* !INSECURE */
+
+#if (FOOTERS && !INSECURE)
+/* Check if (alleged) mstate m has expected magic field */
+#define ok_magic(M)      ((M)->magic == mparams.magic)
+#else  /* (FOOTERS && !INSECURE) */
+#define ok_magic(M)      (1)
+#endif /* (FOOTERS && !INSECURE) */
+
+
+/* In gcc, use __builtin_expect to minimize impact of checks */
+#if !INSECURE
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define RTCHECK(e)  __builtin_expect(e, 1)
+#else /* GNUC */
+#define RTCHECK(e)  (e)
+#endif /* GNUC */
+#else /* !INSECURE */
+#define RTCHECK(e)  (1)
+#endif /* !INSECURE */
+
+/* macros to set up inuse chunks with or without footers */
+
+#if !FOOTERS
+
+#define mark_inuse_foot(M,p,s)
+
+/* Set cinuse bit and pinuse bit of next chunk */
+#define set_inuse(M,p,s)\
+  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
+  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
+
+/* Set cinuse and pinuse of this chunk and pinuse of next chunk */
+#define set_inuse_and_pinuse(M,p,s)\
+  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
+
+/* Set size, cinuse and pinuse bit of this chunk */
+#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
+  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT))
+
+#else /* FOOTERS */
+
+/* Set foot of inuse chunk to be xor of mstate and seed */
+#define mark_inuse_foot(M,p,s)\
+  (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic))
+
+#define get_mstate_for(p)\
+  ((mstate)(((mchunkptr)((char*)(p) +\
+    (chunksize(p))))->prev_foot ^ mparams.magic))
+
+#define set_inuse(M,p,s)\
+  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
+  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \
+  mark_inuse_foot(M,p,s))
+
+#define set_inuse_and_pinuse(M,p,s)\
+  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\
+ mark_inuse_foot(M,p,s))
+
+#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
+  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+  mark_inuse_foot(M, p, s))
+
+#endif /* !FOOTERS */
+
+/* ---------------------------- setting mparams -------------------------- */
+
+/* Initialize mparams */
+static int init_mparams(void) {
+  if (mparams.page_size == 0) {
+    size_t s;
+
+    mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD;
+    mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD;
+#if MORECORE_CONTIGUOUS
+    mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT;
+#else  /* MORECORE_CONTIGUOUS */
+    mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT;
+#endif /* MORECORE_CONTIGUOUS */
+
+#if (FOOTERS && !INSECURE)
+    {
+#if USE_DEV_RANDOM
+      int fd;
+      unsigned char buf[sizeof(size_t)];
+      /* Try to use /dev/urandom, else fall back on using time */
+      if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 &&
+          read(fd, buf, sizeof(buf)) == sizeof(buf)) {
+        s = *((size_t *) buf);
+        close(fd);
+      }
+      else
+#endif /* USE_DEV_RANDOM */
+        s = (size_t)(time(0) ^ (size_t)0x55555555U);
+
+      s |= (size_t)8U;    /* ensure nonzero */
+      s &= ~(size_t)7U;   /* improve chances of fault for bad values */
+
+    }
+#else /* (FOOTERS && !INSECURE) */
+    s = (size_t)0x58585858U;
+#endif /* (FOOTERS && !INSECURE) */
+    ACQUIRE_MAGIC_INIT_LOCK();
+    if (mparams.magic == 0) {
+      mparams.magic = s;
+      /* Set up lock for main malloc area */
+      INITIAL_LOCK(&gm->mutex);
+      gm->mflags = mparams.default_mflags;
+    }
+    RELEASE_MAGIC_INIT_LOCK();
+
+#ifndef WIN32
+    mparams.page_size = malloc_getpagesize;
+    mparams.granularity = ((DEFAULT_GRANULARITY != 0)?
+                           DEFAULT_GRANULARITY : mparams.page_size);
+#else /* WIN32 */
+    {
+      SYSTEM_INFO system_info;
+      GetSystemInfo(&system_info);
+      mparams.page_size = system_info.dwPageSize;
+      mparams.granularity = system_info.dwAllocationGranularity;
+    }
+#endif /* WIN32 */
+
+    /* Sanity-check configuration:
+       size_t must be unsigned and as wide as pointer type.
+       ints must be at least 4 bytes.
+       alignment must be at least 8.
+       Alignment, min chunk size, and page size must all be powers of 2.
+    */
+    if ((sizeof(size_t) != sizeof(char*)) ||
+        (MAX_SIZE_T < MIN_CHUNK_SIZE)  ||
+        (sizeof(int) < 4)  ||
+        (MALLOC_ALIGNMENT < (size_t)8U) ||
+        ((MALLOC_ALIGNMENT    & (MALLOC_ALIGNMENT-SIZE_T_ONE))    != 0) ||
+        ((MCHUNK_SIZE         & (MCHUNK_SIZE-SIZE_T_ONE))         != 0) ||
+        ((mparams.granularity & (mparams.granularity-SIZE_T_ONE)) != 0) ||
+        ((mparams.page_size   & (mparams.page_size-SIZE_T_ONE))   != 0))
+      ABORT;
+  }
+  return 0;
+}
+
+/* support for mallopt */
+static int change_mparam(int param_number, int value) {
+  size_t val = (size_t)value;
+  init_mparams();
+  switch(param_number) {
+  case M_TRIM_THRESHOLD:
+    mparams.trim_threshold = val;
+    return 1;
+  case M_GRANULARITY:
+    if (val >= mparams.page_size && ((val & (val-1)) == 0)) {
+      mparams.granularity = val;
+      return 1;
+    }
+    else
+      return 0;
+  case M_MMAP_THRESHOLD:
+    mparams.mmap_threshold = val;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+#if DEBUG
+/* ------------------------- Debugging Support --------------------------- */
+
+/* Check properties of any chunk, whether free, inuse, mmapped etc  */
+static void do_check_any_chunk(mstate m, mchunkptr p) {
+  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+  assert(ok_address(m, p));
+}
+
+/* Check properties of top chunk */
+static void do_check_top_chunk(mstate m, mchunkptr p) {
+  msegmentptr sp = segment_holding(m, (char*)p);
+  size_t  sz = chunksize(p);
+  assert(sp != 0);
+  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+  assert(ok_address(m, p));
+  assert(sz == m->topsize);
+  assert(sz > 0);
+  assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE);
+  assert(pinuse(p));
+  assert(!next_pinuse(p));
+}
+
+/* Check properties of (inuse) mmapped chunks */
+static void do_check_mmapped_chunk(mstate m, mchunkptr p) {
+  size_t  sz = chunksize(p);
+  size_t len = (sz + (p->prev_foot & ~IS_MMAPPED_BIT) + MMAP_FOOT_PAD);
+  assert(is_mmapped(p));
+  assert(use_mmap(m));
+  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+  assert(ok_address(m, p));
+  assert(!is_small(sz));
+  assert((len & (mparams.page_size-SIZE_T_ONE)) == 0);
+  assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD);
+  assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0);
+}
+
+/* Check properties of inuse chunks */
+static void do_check_inuse_chunk(mstate m, mchunkptr p) {
+  do_check_any_chunk(m, p);
+  assert(cinuse(p));
+  assert(next_pinuse(p));
+  /* If not pinuse and not mmapped, previous chunk has OK offset */
+  assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p);
+  if (is_mmapped(p))
+    do_check_mmapped_chunk(m, p);
+}
+
+/* Check properties of free chunks */
+static void do_check_free_chunk(mstate m, mchunkptr p) {
+  size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT);
+  mchunkptr next = chunk_plus_offset(p, sz);
+  do_check_any_chunk(m, p);
+  assert(!cinuse(p));
+  assert(!next_pinuse(p));
+  assert (!is_mmapped(p));
+  if (p != m->dv && p != m->top) {
+    if (sz >= MIN_CHUNK_SIZE) {
+      assert((sz & CHUNK_ALIGN_MASK) == 0);
+      assert(is_aligned(chunk2mem(p)));
+      assert(next->prev_foot == sz);
+      assert(pinuse(p));
+      assert (next == m->top || cinuse(next));
+      assert(p->fd->bk == p);
+      assert(p->bk->fd == p);
+    }
+    else  /* markers are always of size SIZE_T_SIZE */
+      assert(sz == SIZE_T_SIZE);
+  }
+}
+
+/* Check properties of malloced chunks at the point they are malloced */
+static void do_check_malloced_chunk(mstate m, void* mem, size_t s) {
+  if (mem != 0) {
+    mchunkptr p = mem2chunk(mem);
+    size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT);
+    do_check_inuse_chunk(m, p);
+    assert((sz & CHUNK_ALIGN_MASK) == 0);
+    assert(sz >= MIN_CHUNK_SIZE);
+    assert(sz >= s);
+    /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */
+    assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE));
+  }
+}
+
+/* Check a tree and its subtrees.  */
+static void do_check_tree(mstate m, tchunkptr t) {
+  tchunkptr head = 0;
+  tchunkptr u = t;
+  bindex_t tindex = t->index;
+  size_t tsize = chunksize(t);
+  bindex_t idx;
+  compute_tree_index(tsize, idx);
+  assert(tindex == idx);
+  assert(tsize >= MIN_LARGE_SIZE);
+  assert(tsize >= minsize_for_tree_index(idx));
+  assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1))));
+
+  do { /* traverse through chain of same-sized nodes */
+    do_check_any_chunk(m, ((mchunkptr)u));
+    assert(u->index == tindex);
+    assert(chunksize(u) == tsize);
+    assert(!cinuse(u));
+    assert(!next_pinuse(u));
+    assert(u->fd->bk == u);
+    assert(u->bk->fd == u);
+    if (u->parent == 0) {
+      assert(u->child[0] == 0);
+      assert(u->child[1] == 0);
+    }
+    else {
+      assert(head == 0); /* only one node on chain has parent */
+      head = u;
+      assert(u->parent != u);
+      assert (u->parent->child[0] == u ||
+              u->parent->child[1] == u ||
+              *((tbinptr*)(u->parent)) == u);
+      if (u->child[0] != 0) {
+        assert(u->child[0]->parent == u);
+        assert(u->child[0] != u);
+        do_check_tree(m, u->child[0]);
+      }
+      if (u->child[1] != 0) {
+        assert(u->child[1]->parent == u);
+        assert(u->child[1] != u);
+        do_check_tree(m, u->child[1]);
+      }
+      if (u->child[0] != 0 && u->child[1] != 0) {
+        assert(chunksize(u->child[0]) < chunksize(u->child[1]));
+      }
+    }
+    u = u->fd;
+  } while (u != t);
+  assert(head != 0);
+}
+
+/*  Check all the chunks in a treebin.  */
+static void do_check_treebin(mstate m, bindex_t i) {
+  tbinptr* tb = treebin_at(m, i);
+  tchunkptr t = *tb;
+  int empty = (m->treemap & (1U << i)) == 0;
+  if (t == 0)
+    assert(empty);
+  if (!empty)
+    do_check_tree(m, t);
+}
+
+/*  Check all the chunks in a smallbin.  */
+static void do_check_smallbin(mstate m, bindex_t i) {
+  sbinptr b = smallbin_at(m, i);
+  mchunkptr p = b->bk;
+  unsigned int empty = (m->smallmap & (1U << i)) == 0;
+  if (p == b)
+    assert(empty);
+  if (!empty) {
+    for (; p != b; p = p->bk) {
+      size_t size = chunksize(p);
+      mchunkptr q;
+      /* each chunk claims to be free */
+      do_check_free_chunk(m, p);
+      /* chunk belongs in bin */
+      assert(small_index(size) == i);
+      assert(p->bk == b || chunksize(p->bk) == chunksize(p));
+      /* chunk is followed by an inuse chunk */
+      q = next_chunk(p);
+      if (q->head != FENCEPOST_HEAD)
+        do_check_inuse_chunk(m, q);
+    }
+  }
+}
+
+/* Find x in a bin. Used in other check functions. */
+static int bin_find(mstate m, mchunkptr x) {
+  size_t size = chunksize(x);
+  if (is_small(size)) {
+    bindex_t sidx = small_index(size);
+    sbinptr b = smallbin_at(m, sidx);
+    if (smallmap_is_marked(m, sidx)) {
+      mchunkptr p = b;
+      do {
+        if (p == x)
+          return 1;
+      } while ((p = p->fd) != b);
+    }
+  }
+  else {
+    bindex_t tidx;
+    compute_tree_index(size, tidx);
+    if (treemap_is_marked(m, tidx)) {
+      tchunkptr t = *treebin_at(m, tidx);
+      size_t sizebits = size << leftshift_for_tree_index(tidx);
+      while (t != 0 && chunksize(t) != size) {
+        t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
+        sizebits <<= 1;
+      }
+      if (t != 0) {
+        tchunkptr u = t;
+        do {
+          if (u == (tchunkptr)x)
+            return 1;
+        } while ((u = u->fd) != t);
+      }
+    }
+  }
+  return 0;
+}
+
+/* Traverse each chunk and check it; return total */
+static size_t traverse_and_check(mstate m) {
+  size_t sum = 0;
+  if (is_initialized(m)) {
+    msegmentptr s = &m->seg;
+    sum += m->topsize + TOP_FOOT_SIZE;
+    while (s != 0) {
+      mchunkptr q = align_as_chunk(s->base);
+      mchunkptr lastq = 0;
+      assert(pinuse(q));
+      while (segment_holds(s, q) &&
+             q != m->top && q->head != FENCEPOST_HEAD) {
+        sum += chunksize(q);
+        if (cinuse(q)) {
+          assert(!bin_find(m, q));
+          do_check_inuse_chunk(m, q);
+        }
+        else {
+          assert(q == m->dv || bin_find(m, q));
+          assert(lastq == 0 || cinuse(lastq)); /* Not 2 consecutive free */
+          do_check_free_chunk(m, q);
+        }
+        lastq = q;
+        q = next_chunk(q);
+      }
+      s = s->next;
+    }
+  }
+  return sum;
+}
+
+/* Check all properties of malloc_state. */
+static void do_check_malloc_state(mstate m) {
+  bindex_t i;
+  size_t total;
+  /* check bins */
+  for (i = 0; i < NSMALLBINS; ++i)
+    do_check_smallbin(m, i);
+  for (i = 0; i < NTREEBINS; ++i)
+    do_check_treebin(m, i);
+
+  if (m->dvsize != 0) { /* check dv chunk */
+    do_check_any_chunk(m, m->dv);
+    assert(m->dvsize == chunksize(m->dv));
+    assert(m->dvsize >= MIN_CHUNK_SIZE);
+    assert(bin_find(m, m->dv) == 0);
+  }
+
+  if (m->top != 0) {   /* check top chunk */
+    do_check_top_chunk(m, m->top);
+    assert(m->topsize == chunksize(m->top));
+    assert(m->topsize > 0);
+    assert(bin_find(m, m->top) == 0);
+  }
+
+  total = traverse_and_check(m);
+  assert(total <= m->footprint);
+  assert(m->footprint <= m->max_footprint);
+}
+#endif /* DEBUG */
+
+/* ----------------------------- statistics ------------------------------ */
+
+#if !NO_MALLINFO
+static struct mallinfo internal_mallinfo(mstate m) {
+  struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+  if (!PREACTION(m)) {
+    check_malloc_state(m);
+    if (is_initialized(m)) {
+      size_t nfree = SIZE_T_ONE; /* top always free */
+      size_t mfree = m->topsize + TOP_FOOT_SIZE;
+      size_t sum = mfree;
+      msegmentptr s = &m->seg;
+      while (s != 0) {
+        mchunkptr q = align_as_chunk(s->base);
+        while (segment_holds(s, q) &&
+               q != m->top && q->head != FENCEPOST_HEAD) {
+          size_t sz = chunksize(q);
+          sum += sz;
+          if (!cinuse(q)) {
+            mfree += sz;
+            ++nfree;
+          }
+          q = next_chunk(q);
+        }
+        s = s->next;
+      }
+
+      nm.arena    = sum;
+      nm.ordblks  = nfree;
+      nm.hblkhd   = m->footprint - sum;
+      nm.usmblks  = m->max_footprint;
+      nm.uordblks = m->footprint - mfree;
+      nm.fordblks = mfree;
+      nm.keepcost = m->topsize;
+    }
+
+    POSTACTION(m);
+  }
+  return nm;
+}
+#endif /* !NO_MALLINFO */
+
+static void internal_malloc_stats(mstate m) {
+  if (!PREACTION(m)) {
+    size_t maxfp = 0;
+    size_t fp = 0;
+    size_t used = 0;
+    check_malloc_state(m);
+    if (is_initialized(m)) {
+      msegmentptr s = &m->seg;
+      maxfp = m->max_footprint;
+      fp = m->footprint;
+      used = fp - (m->topsize + TOP_FOOT_SIZE);
+
+      while (s != 0) {
+        mchunkptr q = align_as_chunk(s->base);
+        while (segment_holds(s, q) &&
+               q != m->top && q->head != FENCEPOST_HEAD) {
+          if (!cinuse(q))
+            used -= chunksize(q);
+          q = next_chunk(q);
+        }
+        s = s->next;
+      }
+    }
+
+    fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp));
+    fprintf(stderr, "system bytes     = %10lu\n", (unsigned long)(fp));
+    fprintf(stderr, "in use bytes     = %10lu\n", (unsigned long)(used));
+
+    POSTACTION(m);
+  }
+}
+
+/* ----------------------- Operations on smallbins ----------------------- */
+
+/*
+  Various forms of linking and unlinking are defined as macros.  Even
+  the ones for trees, which are very long but have very short typical
+  paths.  This is ugly but reduces reliance on inlining support of
+  compilers.
+*/
+
+/* Link a free chunk into a smallbin  */
+#define insert_small_chunk(M, P, S) {\
+  bindex_t I  = small_index(S);\
+  mchunkptr B = smallbin_at(M, I);\
+  mchunkptr F = B;\
+  assert(S >= MIN_CHUNK_SIZE);\
+  if (!smallmap_is_marked(M, I))\
+    mark_smallmap(M, I);\
+  else if (RTCHECK(ok_address(M, B->fd)))\
+    F = B->fd;\
+  else {\
+    CORRUPTION_ERROR_ACTION(M);\
+  }\
+  B->fd = P;\
+  F->bk = P;\
+  P->fd = F;\
+  P->bk = B;\
+}
+
+/* Unlink a chunk from a smallbin  */
+#define unlink_small_chunk(M, P, S) {\
+  mchunkptr F = P->fd;\
+  mchunkptr B = P->bk;\
+  bindex_t I = small_index(S);\
+  assert(P != B);\
+  assert(P != F);\
+  assert(chunksize(P) == small_index2size(I));\
+  if (F == B)\
+    clear_smallmap(M, I);\
+  else if (RTCHECK((F == smallbin_at(M,I) || ok_address(M, F)) &&\
+                   (B == smallbin_at(M,I) || ok_address(M, B)))) {\
+    F->bk = B;\
+    B->fd = F;\
+  }\
+  else {\
+    CORRUPTION_ERROR_ACTION(M);\
+  }\
+}
+
+/* Unlink the first chunk from a smallbin */
+#define unlink_first_small_chunk(M, B, P, I) {\
+  mchunkptr F = P->fd;\
+  assert(P != B);\
+  assert(P != F);\
+  assert(chunksize(P) == small_index2size(I));\
+  if (B == F)\
+    clear_smallmap(M, I);\
+  else if (RTCHECK(ok_address(M, F))) {\
+    B->fd = F;\
+    F->bk = B;\
+  }\
+  else {\
+    CORRUPTION_ERROR_ACTION(M);\
+  }\
+}
+
+/* Replace dv node, binning the old one */
+/* Used only when dvsize known to be small */
+#define replace_dv(M, P, S) {\
+  size_t DVS = M->dvsize;\
+  if (DVS != 0) {\
+    mchunkptr DV = M->dv;\
+    assert(is_small(DVS));\
+    insert_small_chunk(M, DV, DVS);\
+  }\
+  M->dvsize = S;\
+  M->dv = P;\
+}
+
+/* ------------------------- Operations on trees ------------------------- */
+
+/* Insert chunk into tree */
+#define insert_large_chunk(M, X, S) {\
+  tbinptr* H;\
+  bindex_t I;\
+  compute_tree_index(S, I);\
+  H = treebin_at(M, I);\
+  X->index = I;\
+  X->child[0] = X->child[1] = 0;\
+  if (!treemap_is_marked(M, I)) {\
+    mark_treemap(M, I);\
+    *H = X;\
+    X->parent = (tchunkptr)H;\
+    X->fd = X->bk = X;\
+  }\
+  else {\
+    tchunkptr T = *H;\
+    size_t K = S << leftshift_for_tree_index(I);\
+    for (;;) {\
+      if (chunksize(T) != S) {\
+        tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\
+        K <<= 1;\
+        if (*C != 0)\
+          T = *C;\
+        else if (RTCHECK(ok_address(M, C))) {\
+          *C = X;\
+          X->parent = T;\
+          X->fd = X->bk = X;\
+          break;\
+        }\
+        else {\
+          CORRUPTION_ERROR_ACTION(M);\
+          break;\
+        }\
+      }\
+      else {\
+        tchunkptr F = T->fd;\
+        if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\
+          T->fd = F->bk = X;\
+          X->fd = F;\
+          X->bk = T;\
+          X->parent = 0;\
+          break;\
+        }\
+        else {\
+          CORRUPTION_ERROR_ACTION(M);\
+          break;\
+        }\
+      }\
+    }\
+  }\
+}
+
+/*
+  Unlink steps:
+
+  1. If x is a chained node, unlink it from its same-sized fd/bk links
+     and choose its bk node as its replacement.
+  2. If x was the last node of its size, but not a leaf node, it must
+     be replaced with a leaf node (not merely one with an open left or
+     right), to make sure that lefts and rights of descendents
+     correspond properly to bit masks.  We use the rightmost descendent
+     of x.  We could use any other leaf, but this is easy to locate and
+     tends to counteract removal of leftmosts elsewhere, and so keeps
+     paths shorter than minimally guaranteed.  This doesn't loop much
+     because on average a node in a tree is near the bottom.
+  3. If x is the base of a chain (i.e., has parent links) relink
+     x's parent and children to x's replacement (or null if none).
+*/
+
+#define unlink_large_chunk(M, X) {\
+  tchunkptr XP = X->parent;\
+  tchunkptr R;\
+  if (X->bk != X) {\
+    tchunkptr F = X->fd;\
+    R = X->bk;\
+    if (RTCHECK(ok_address(M, F))) {\
+      F->bk = R;\
+      R->fd = F;\
+    }\
+    else {\
+      CORRUPTION_ERROR_ACTION(M);\
+    }\
+  }\
+  else {\
+    tchunkptr* RP;\
+    if (((R = *(RP = &(X->child[1]))) != 0) ||\
+        ((R = *(RP = &(X->child[0]))) != 0)) {\
+      tchunkptr* CP;\
+      while ((*(CP = &(R->child[1])) != 0) ||\
+             (*(CP = &(R->child[0])) != 0)) {\
+        R = *(RP = CP);\
+      }\
+      if (RTCHECK(ok_address(M, RP)))\
+        *RP = 0;\
+      else {\
+        CORRUPTION_ERROR_ACTION(M);\
+      }\
+    }\
+  }\
+  if (XP != 0) {\
+    tbinptr* H = treebin_at(M, X->index);\
+    if (X == *H) {\
+      if ((*H = R) == 0) \
+        clear_treemap(M, X->index);\
+    }\
+    else if (RTCHECK(ok_address(M, XP))) {\
+      if (XP->child[0] == X) \
+        XP->child[0] = R;\
+      else \
+        XP->child[1] = R;\
+    }\
+    else\
+      CORRUPTION_ERROR_ACTION(M);\
+    if (R != 0) {\
+      if (RTCHECK(ok_address(M, R))) {\
+        tchunkptr C0, C1;\
+        R->parent = XP;\
+        if ((C0 = X->child[0]) != 0) {\
+          if (RTCHECK(ok_address(M, C0))) {\
+            R->child[0] = C0;\
+            C0->parent = R;\
+          }\
+          else\
+            CORRUPTION_ERROR_ACTION(M);\
+        }\
+        if ((C1 = X->child[1]) != 0) {\
+          if (RTCHECK(ok_address(M, C1))) {\
+            R->child[1] = C1;\
+            C1->parent = R;\
+          }\
+          else\
+            CORRUPTION_ERROR_ACTION(M);\
+        }\
+      }\
+      else\
+        CORRUPTION_ERROR_ACTION(M);\
+    }\
+  }\
+}
+
+/* Relays to large vs small bin operations */
+
+#define insert_chunk(M, P, S)\
+  if (is_small(S)) insert_small_chunk(M, P, S)\
+  else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); }
+
+#define unlink_chunk(M, P, S)\
+  if (is_small(S)) unlink_small_chunk(M, P, S)\
+  else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); }
+
+
+/* Relays to internal calls to malloc/free from realloc, memalign etc */
+
+#if ONLY_MSPACES
+#define internal_malloc(m, b) mspace_malloc(m, b)
+#define internal_free(m, mem) mspace_free(m,mem);
+#else /* ONLY_MSPACES */
+#if MSPACES
+#define internal_malloc(m, b)\
+   (m == gm)? dlmalloc(b) : mspace_malloc(m, b)
+#define internal_free(m, mem)\
+   if (m == gm) dlfree(mem); else mspace_free(m,mem);
+#else /* MSPACES */
+#define internal_malloc(m, b) dlmalloc(b)
+#define internal_free(m, mem) dlfree(mem)
+#endif /* MSPACES */
+#endif /* ONLY_MSPACES */
+
+/* -----------------------  Direct-mmapping chunks ----------------------- */
+
+/*
+  Directly mmapped chunks are set up with an offset to the start of
+  the mmapped region stored in the prev_foot field of the chunk. This
+  allows reconstruction of the required argument to MUNMAP when freed,
+  and also allows adjustment of the returned chunk to meet alignment
+  requirements (especially in memalign).  There is also enough space
+  allocated to hold a fake next chunk of size SIZE_T_SIZE to maintain
+  the PINUSE bit so frees can be checked.
+*/
+
+/* Malloc using mmap */
+static void* mmap_alloc(mstate m, size_t nb) {
+  size_t mmsize = granularity_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
+  if (mmsize > nb) {     /* Check for wrap around 0 */
+    char* mm = (char*)(DIRECT_MMAP(mmsize));
+    if (mm != CMFAIL) {
+      size_t offset = align_offset(chunk2mem(mm));
+      size_t psize = mmsize - offset - MMAP_FOOT_PAD;
+      mchunkptr p = (mchunkptr)(mm + offset);
+      p->prev_foot = offset | IS_MMAPPED_BIT;
+      (p)->head = (psize|CINUSE_BIT);
+      mark_inuse_foot(m, p, psize);
+      chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD;
+      chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0;
+
+      if (mm < m->least_addr)
+        m->least_addr = mm;
+      if ((m->footprint += mmsize) > m->max_footprint)
+        m->max_footprint = m->footprint;
+      assert(is_aligned(chunk2mem(p)));
+      check_mmapped_chunk(m, p);
+      return chunk2mem(p);
+    }
+  }
+  return 0;
+}
+
+/* Realloc using mmap */
+static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb) {
+  size_t oldsize = chunksize(oldp);
+  if (is_small(nb)) /* Can't shrink mmap regions below small size */
+    return 0;
+  /* Keep old chunk if big enough but not too big */
+  if (oldsize >= nb + SIZE_T_SIZE &&
+      (oldsize - nb) <= (mparams.granularity << 1))
+    return oldp;
+  else {
+    size_t offset = oldp->prev_foot & ~IS_MMAPPED_BIT;
+    size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD;
+    size_t newmmsize = granularity_align(nb + SIX_SIZE_T_SIZES +
+                                         CHUNK_ALIGN_MASK);
+    char* cp = (char*)CALL_MREMAP((char*)oldp - offset,
+                                  oldmmsize, newmmsize, 1);
+    if (cp != CMFAIL) {
+      mchunkptr newp = (mchunkptr)(cp + offset);
+      size_t psize = newmmsize - offset - MMAP_FOOT_PAD;
+      newp->head = (psize|CINUSE_BIT);
+      mark_inuse_foot(m, newp, psize);
+      chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD;
+      chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0;
+
+      if (cp < m->least_addr)
+        m->least_addr = cp;
+      if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint)
+        m->max_footprint = m->footprint;
+      check_mmapped_chunk(m, newp);
+      return newp;
+    }
+  }
+  return 0;
+}
+
+/* -------------------------- mspace management -------------------------- */
+
+/* Initialize top chunk and its size */
+static void init_top(mstate m, mchunkptr p, size_t psize) {
+  /* Ensure alignment */
+  size_t offset = align_offset(chunk2mem(p));
+  p = (mchunkptr)((char*)p + offset);
+  psize -= offset;
+
+  m->top = p;
+  m->topsize = psize;
+  p->head = psize | PINUSE_BIT;
+  /* set size of fake trailing chunk holding overhead space only once */
+  chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE;
+  m->trim_check = mparams.trim_threshold; /* reset on each update */
+}
+
+/* Initialize bins for a new mstate that is otherwise zeroed out */
+static void init_bins(mstate m) {
+  /* Establish circular links for smallbins */
+  bindex_t i;
+  for (i = 0; i < NSMALLBINS; ++i) {
+    sbinptr bin = smallbin_at(m,i);
+    bin->fd = bin->bk = bin;
+  }
+}
+
+#if PROCEED_ON_ERROR
+
+/* default corruption action */
+static void reset_on_error(mstate m) {
+  int i;
+  ++malloc_corruption_error_count;
+  /* Reinitialize fields to forget about all memory */
+  m->smallbins = m->treebins = 0;
+  m->dvsize = m->topsize = 0;
+  m->seg.base = 0;
+  m->seg.size = 0;
+  m->seg.next = 0;
+  m->top = m->dv = 0;
+  for (i = 0; i < NTREEBINS; ++i)
+    *treebin_at(m, i) = 0;
+  init_bins(m);
+}
+#endif /* PROCEED_ON_ERROR */
+
+/* Allocate chunk and prepend remainder with chunk in successor base. */
+static void* prepend_alloc(mstate m, char* newbase, char* oldbase,
+                           size_t nb) {
+  mchunkptr p = align_as_chunk(newbase);
+  mchunkptr oldfirst = align_as_chunk(oldbase);
+  size_t psize = (char*)oldfirst - (char*)p;
+  mchunkptr q = chunk_plus_offset(p, nb);
+  size_t qsize = psize - nb;
+  set_size_and_pinuse_of_inuse_chunk(m, p, nb);
+
+  assert((char*)oldfirst > (char*)q);
+  assert(pinuse(oldfirst));
+  assert(qsize >= MIN_CHUNK_SIZE);
+
+  /* consolidate remainder with first chunk of old base */
+  if (oldfirst == m->top) {
+    size_t tsize = m->topsize += qsize;
+    m->top = q;
+    q->head = tsize | PINUSE_BIT;
+    check_top_chunk(m, q);
+  }
+  else if (oldfirst == m->dv) {
+    size_t dsize = m->dvsize += qsize;
+    m->dv = q;
+    set_size_and_pinuse_of_free_chunk(q, dsize);
+  }
+  else {
+    if (!cinuse(oldfirst)) {
+      size_t nsize = chunksize(oldfirst);
+      unlink_chunk(m, oldfirst, nsize);
+      oldfirst = chunk_plus_offset(oldfirst, nsize);
+      qsize += nsize;
+    }
+    set_free_with_pinuse(q, qsize, oldfirst);
+    insert_chunk(m, q, qsize);
+    check_free_chunk(m, q);
+  }
+
+  check_malloced_chunk(m, chunk2mem(p), nb);
+  return chunk2mem(p);
+}
+
+
+/* Add a segment to hold a new noncontiguous region */
+static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) {
+  /* Determine locations and sizes of segment, fenceposts, old top */
+  char* old_top = (char*)m->top;
+  msegmentptr oldsp = segment_holding(m, old_top);
+  char* old_end = oldsp->base + oldsp->size;
+  size_t ssize = pad_request(sizeof(struct malloc_segment));
+  char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
+  size_t offset = align_offset(chunk2mem(rawsp));
+  char* asp = rawsp + offset;
+  char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp;
+  mchunkptr sp = (mchunkptr)csp;
+  msegmentptr ss = (msegmentptr)(chunk2mem(sp));
+  mchunkptr tnext = chunk_plus_offset(sp, ssize);
+  mchunkptr p = tnext;
+  int nfences = 0;
+
+  /* reset top to new space */
+  init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
+
+  /* Set up segment record */
+  assert(is_aligned(ss));
+  set_size_and_pinuse_of_inuse_chunk(m, sp, ssize);
+  *ss = m->seg; /* Push current record */
+  m->seg.base = tbase;
+  m->seg.size = tsize;
+  m->seg.sflags = mmapped;
+  m->seg.next = ss;
+
+  /* Insert trailing fenceposts */
+  for (;;) {
+    mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE);
+    p->head = FENCEPOST_HEAD;
+    ++nfences;
+    if ((char*)(&(nextp->head)) < old_end)
+      p = nextp;
+    else
+      break;
+  }
+  assert(nfences >= 2);
+
+  /* Insert the rest of old top into a bin as an ordinary free chunk */
+  if (csp != old_top) {
+    mchunkptr q = (mchunkptr)old_top;
+    size_t psize = csp - old_top;
+    mchunkptr tn = chunk_plus_offset(q, psize);
+    set_free_with_pinuse(q, psize, tn);
+    insert_chunk(m, q, psize);
+  }
+
+  check_top_chunk(m, m->top);
+}
+
+/* -------------------------- System allocation -------------------------- */
+
+/* Get memory from system using MORECORE or MMAP */
+static void* sys_alloc(mstate m, size_t nb) {
+  char* tbase = CMFAIL;
+  size_t tsize = 0;
+  flag_t mmap_flag = 0;
+
+  init_mparams();
+
+  /* Directly map large chunks */
+  if (use_mmap(m) && nb >= mparams.mmap_threshold) {
+    void* mem = mmap_alloc(m, nb);
+    if (mem != 0)
+      return mem;
+  }
+
+  /*
+    Try getting memory in any of three ways (in most-preferred to
+    least-preferred order):
+    1. A call to MORECORE that can normally contiguously extend memory.
+       (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or
+       or main space is mmapped or a previous contiguous call failed)
+    2. A call to MMAP new space (disabled if not HAVE_MMAP).
+       Note that under the default settings, if MORECORE is unable to
+       fulfill a request, and HAVE_MMAP is true, then mmap is
+       used as a noncontiguous system allocator. This is a useful backup
+       strategy for systems with holes in address spaces -- in this case
+       sbrk cannot contiguously expand the heap, but mmap may be able to
+       find space.
+    3. A call to MORECORE that cannot usually contiguously extend memory.
+       (disabled if not HAVE_MORECORE)
+  */
+
+  if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) {
+    char* br = CMFAIL;
+    msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top);
+    size_t asize = 0;
+    ACQUIRE_MORECORE_LOCK();
+
+    if (ss == 0) {  /* First time through or recovery */
+      char* base = (char*)CALL_MORECORE(0);
+      if (base != CMFAIL) {
+        asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE);
+        /* Adjust to end on a page boundary */
+        if (!is_page_aligned(base))
+          asize += (page_align((size_t)base) - (size_t)base);
+        /* Can't call MORECORE if size is negative when treated as signed */
+        if (asize < HALF_MAX_SIZE_T &&
+            (br = (char*)(CALL_MORECORE(asize))) == base) {
+          tbase = base;
+          tsize = asize;
+        }
+      }
+    }
+    else {
+      /* Subtract out existing available top space from MORECORE request. */
+      asize = granularity_align(nb - m->topsize + TOP_FOOT_SIZE + SIZE_T_ONE);
+      /* Use mem here only if it did continuously extend old space */
+      if (asize < HALF_MAX_SIZE_T &&
+          (br = (char*)(CALL_MORECORE(asize))) == ss->base+ss->size) {
+        tbase = br;
+        tsize = asize;
+      }
+    }
+
+    if (tbase == CMFAIL) {    /* Cope with partial failure */
+      if (br != CMFAIL) {    /* Try to use/extend the space we did get */
+        if (asize < HALF_MAX_SIZE_T &&
+            asize < nb + TOP_FOOT_SIZE + SIZE_T_ONE) {
+          size_t esize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE - asize);
+          if (esize < HALF_MAX_SIZE_T) {
+            char* end = (char*)CALL_MORECORE(esize);
+            if (end != CMFAIL)
+              asize += esize;
+            else {            /* Can't use; try to release */
+              CALL_MORECORE(-asize);
+              br = CMFAIL;
+            }
+          }
+        }
+      }
+      if (br != CMFAIL) {    /* Use the space we did get */
+        tbase = br;
+        tsize = asize;
+      }
+      else
+        disable_contiguous(m); /* Don't try contiguous path in the future */
+    }
+
+    RELEASE_MORECORE_LOCK();
+  }
+
+  if (HAVE_MMAP && tbase == CMFAIL) {  /* Try MMAP */
+    size_t req = nb + TOP_FOOT_SIZE + SIZE_T_ONE;
+    size_t rsize = granularity_align(req);
+    if (rsize > nb) { /* Fail if wraps around zero */
+      char* mp = (char*)(CALL_MMAP(rsize));
+      if (mp != CMFAIL) {
+        tbase = mp;
+        tsize = rsize;
+        mmap_flag = IS_MMAPPED_BIT;
+      }
+    }
+  }
+
+  if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */
+    size_t asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE);
+    if (asize < HALF_MAX_SIZE_T) {
+      char* br = CMFAIL;
+      char* end = CMFAIL;
+      ACQUIRE_MORECORE_LOCK();
+      br = (char*)(CALL_MORECORE(asize));
+      end = (char*)(CALL_MORECORE(0));
+      RELEASE_MORECORE_LOCK();
+      if (br != CMFAIL && end != CMFAIL && br < end) {
+        size_t ssize = end - br;
+        if (ssize > nb + TOP_FOOT_SIZE) {
+          tbase = br;
+          tsize = ssize;
+        }
+      }
+    }
+  }
+
+  if (tbase != CMFAIL) {
+
+    if ((m->footprint += tsize) > m->max_footprint)
+      m->max_footprint = m->footprint;
+
+    if (!is_initialized(m)) { /* first-time initialization */
+      m->seg.base = m->least_addr = tbase;
+      m->seg.size = tsize;
+      m->seg.sflags = mmap_flag;
+      m->magic = mparams.magic;
+      init_bins(m);
+      if (is_global(m))
+        init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
+      else {
+        /* Offset top by embedded malloc_state */
+        mchunkptr mn = next_chunk(mem2chunk(m));
+        init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE);
+      }
+    }
+
+    else {
+      /* Try to merge with an existing segment */
+      msegmentptr sp = &m->seg;
+      while (sp != 0 && tbase != sp->base + sp->size)
+        sp = sp->next;
+      if (sp != 0 &&
+          !is_extern_segment(sp) &&
+          (sp->sflags & IS_MMAPPED_BIT) == mmap_flag &&
+          segment_holds(sp, m->top)) { /* append */
+        sp->size += tsize;
+        init_top(m, m->top, m->topsize + tsize);
+      }
+      else {
+        if (tbase < m->least_addr)
+          m->least_addr = tbase;
+        sp = &m->seg;
+        while (sp != 0 && sp->base != tbase + tsize)
+          sp = sp->next;
+        if (sp != 0 &&
+            !is_extern_segment(sp) &&
+            (sp->sflags & IS_MMAPPED_BIT) == mmap_flag) {
+          char* oldbase = sp->base;
+          sp->base = tbase;
+          sp->size += tsize;
+          return prepend_alloc(m, tbase, oldbase, nb);
+        }
+        else
+          add_segment(m, tbase, tsize, mmap_flag);
+      }
+    }
+
+    if (nb < m->topsize) { /* Allocate from new or extended top space */
+      size_t rsize = m->topsize -= nb;
+      mchunkptr p = m->top;
+      mchunkptr r = m->top = chunk_plus_offset(p, nb);
+      r->head = rsize | PINUSE_BIT;
+      set_size_and_pinuse_of_inuse_chunk(m, p, nb);
+      check_top_chunk(m, m->top);
+      check_malloced_chunk(m, chunk2mem(p), nb);
+      return chunk2mem(p);
+    }
+  }
+
+  MALLOC_FAILURE_ACTION;
+  return 0;
+}
+
+/* -----------------------  system deallocation -------------------------- */
+
+/* Unmap and unlink any mmapped segments that don't contain used chunks */
+static size_t release_unused_segments(mstate m) {
+  size_t released = 0;
+  msegmentptr pred = &m->seg;
+  msegmentptr sp = pred->next;
+  while (sp != 0) {
+    char* base = sp->base;
+    size_t size = sp->size;
+    msegmentptr next = sp->next;
+    if (is_mmapped_segment(sp) && !is_extern_segment(sp)) {
+      mchunkptr p = align_as_chunk(base);
+      size_t psize = chunksize(p);
+      /* Can unmap if first chunk holds entire segment and not pinned */
+      if (!cinuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) {
+        tchunkptr tp = (tchunkptr)p;
+        assert(segment_holds(sp, (char*)sp));
+        if (p == m->dv) {
+          m->dv = 0;
+          m->dvsize = 0;
+        }
+        else {
+          unlink_large_chunk(m, tp);
+        }
+        if (CALL_MUNMAP(base, size) == 0) {
+          released += size;
+          m->footprint -= size;
+          /* unlink obsoleted record */
+          sp = pred;
+          sp->next = next;
+        }
+        else { /* back out if cannot unmap */
+          insert_large_chunk(m, tp, psize);
+        }
+      }
+    }
+    pred = sp;
+    sp = next;
+  }
+  return released;
+}
+
+static int sys_trim(mstate m, size_t pad) {
+  size_t released = 0;
+  if (pad < MAX_REQUEST && is_initialized(m)) {
+    pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */
+
+    if (m->topsize > pad) {
+      /* Shrink top space in granularity-size units, keeping at least one */
+      size_t unit = mparams.granularity;
+      size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit -
+                      SIZE_T_ONE) * unit;
+      msegmentptr sp = segment_holding(m, (char*)m->top);
+
+      if (!is_extern_segment(sp)) {
+        if (is_mmapped_segment(sp)) {
+          if (HAVE_MMAP &&
+              sp->size >= extra &&
+              !has_segment_link(m, sp)) { /* can't shrink if pinned */
+            size_t newsize = sp->size - extra;
+            /* Prefer mremap, fall back to munmap */
+            if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) ||
+                (CALL_MUNMAP(sp->base + newsize, extra) == 0)) {
+              released = extra;
+            }
+          }
+        }
+        else if (HAVE_MORECORE) {
+          if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */
+            extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit;
+          ACQUIRE_MORECORE_LOCK();
+          {
+            /* Make sure end of memory is where we last set it. */
+            char* old_br = (char*)(CALL_MORECORE(0));
+            if (old_br == sp->base + sp->size) {
+              char* rel_br = (char*)(CALL_MORECORE(-extra));
+              char* new_br = (char*)(CALL_MORECORE(0));
+              if (rel_br != CMFAIL && new_br < old_br)
+                released = old_br - new_br;
+            }
+          }
+          RELEASE_MORECORE_LOCK();
+        }
+      }
+
+      if (released != 0) {
+        sp->size -= released;
+        m->footprint -= released;
+        init_top(m, m->top, m->topsize - released);
+        check_top_chunk(m, m->top);
+      }
+    }
+
+    /* Unmap any unused mmapped segments */
+    if (HAVE_MMAP)
+      released += release_unused_segments(m);
+
+    /* On failure, disable autotrim to avoid repeated failed future calls */
+    if (released == 0)
+      m->trim_check = MAX_SIZE_T;
+  }
+
+  return (released != 0)? 1 : 0;
+}
+
+/* ---------------------------- malloc support --------------------------- */
+
+/* allocate a large request from the best fitting chunk in a treebin */
+static void* tmalloc_large(mstate m, size_t nb) {
+  tchunkptr v = 0;
+  size_t rsize = -nb; /* Unsigned negation */
+  tchunkptr t;
+  bindex_t idx;
+  compute_tree_index(nb, idx);
+
+  if ((t = *treebin_at(m, idx)) != 0) {
+    /* Traverse tree for this bin looking for node with size == nb */
+    size_t sizebits = nb << leftshift_for_tree_index(idx);
+    tchunkptr rst = 0;  /* The deepest untaken right subtree */
+    for (;;) {
+      tchunkptr rt;
+      size_t trem = chunksize(t) - nb;
+      if (trem < rsize) {
+        v = t;
+        if ((rsize = trem) == 0)
+          break;
+      }
+      rt = t->child[1];
+      t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
+      if (rt != 0 && rt != t)
+        rst = rt;
+      if (t == 0) {
+        t = rst; /* set t to least subtree holding sizes > nb */
+        break;
+      }
+      sizebits <<= 1;
+    }
+  }
+
+  if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */
+    binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;
+    if (leftbits != 0) {
+      bindex_t i;
+      binmap_t leastbit = least_bit(leftbits);
+      compute_bit2idx(leastbit, i);
+      t = *treebin_at(m, i);
+    }
+  }
+
+  while (t != 0) { /* find smallest of tree or subtree */
+    size_t trem = chunksize(t) - nb;
+    if (trem < rsize) {
+      rsize = trem;
+      v = t;
+    }
+    t = leftmost_child(t);
+  }
+
+  /*  If dv is a better fit, return 0 so malloc will use it */
+  if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {
+    if (RTCHECK(ok_address(m, v))) { /* split */
+      mchunkptr r = chunk_plus_offset(v, nb);
+      assert(chunksize(v) == rsize + nb);
+      if (RTCHECK(ok_next(v, r))) {
+        unlink_large_chunk(m, v);
+        if (rsize < MIN_CHUNK_SIZE)
+          set_inuse_and_pinuse(m, v, (rsize + nb));
+        else {
+          set_size_and_pinuse_of_inuse_chunk(m, v, nb);
+          set_size_and_pinuse_of_free_chunk(r, rsize);
+          insert_chunk(m, r, rsize);
+        }
+        return chunk2mem(v);
+      }
+    }
+    CORRUPTION_ERROR_ACTION(m);
+  }
+  return 0;
+}
+
+/* allocate a small request from the best fitting chunk in a treebin */
+static void* tmalloc_small(mstate m, size_t nb) {
+  tchunkptr t, v;
+  size_t rsize;
+  bindex_t i;
+  binmap_t leastbit = least_bit(m->treemap);
+  compute_bit2idx(leastbit, i);
+
+  v = t = *treebin_at(m, i);
+  rsize = chunksize(t) - nb;
+
+  while ((t = leftmost_child(t)) != 0) {
+    size_t trem = chunksize(t) - nb;
+    if (trem < rsize) {
+      rsize = trem;
+      v = t;
+    }
+  }
+
+  if (RTCHECK(ok_address(m, v))) {
+    mchunkptr r = chunk_plus_offset(v, nb);
+    assert(chunksize(v) == rsize + nb);
+    if (RTCHECK(ok_next(v, r))) {
+      unlink_large_chunk(m, v);
+      if (rsize < MIN_CHUNK_SIZE)
+        set_inuse_and_pinuse(m, v, (rsize + nb));
+      else {
+        set_size_and_pinuse_of_inuse_chunk(m, v, nb);
+        set_size_and_pinuse_of_free_chunk(r, rsize);
+        replace_dv(m, r, rsize);
+      }
+      return chunk2mem(v);
+    }
+  }
+
+  CORRUPTION_ERROR_ACTION(m);
+  return 0;
+}
+
+/* --------------------------- realloc support --------------------------- */
+
+static void* internal_realloc(mstate m, void* oldmem, size_t bytes) {
+  if (bytes >= MAX_REQUEST) {
+    MALLOC_FAILURE_ACTION;
+    return 0;
+  }
+  if (!PREACTION(m)) {
+    mchunkptr oldp = mem2chunk(oldmem);
+    size_t oldsize = chunksize(oldp);
+    mchunkptr next = chunk_plus_offset(oldp, oldsize);
+    mchunkptr newp = 0;
+    void* extra = 0;
+
+    /* Try to either shrink or extend into top. Else malloc-copy-free */
+
+    if (RTCHECK(ok_address(m, oldp) && ok_cinuse(oldp) &&
+                ok_next(oldp, next) && ok_pinuse(next))) {
+      size_t nb = request2size(bytes);
+      if (is_mmapped(oldp))
+        newp = mmap_resize(m, oldp, nb);
+      else if (oldsize >= nb) { /* already big enough */
+        size_t rsize = oldsize - nb;
+        newp = oldp;
+        if (rsize >= MIN_CHUNK_SIZE) {
+          mchunkptr remainder = chunk_plus_offset(newp, nb);
+          set_inuse(m, newp, nb);
+          set_inuse(m, remainder, rsize);
+          extra = chunk2mem(remainder);
+        }
+      }
+      else if (next == m->top && oldsize + m->topsize > nb) {
+        /* Expand into top */
+        size_t newsize = oldsize + m->topsize;
+        size_t newtopsize = newsize - nb;
+        mchunkptr newtop = chunk_plus_offset(oldp, nb);
+        set_inuse(m, oldp, nb);
+        newtop->head = newtopsize |PINUSE_BIT;
+        m->top = newtop;
+        m->topsize = newtopsize;
+        newp = oldp;
+      }
+    }
+    else {
+      USAGE_ERROR_ACTION(m, oldmem);
+      POSTACTION(m);
+      return 0;
+    }
+
+    POSTACTION(m);
+
+    if (newp != 0) {
+      if (extra != 0) {
+        internal_free(m, extra);
+      }
+      check_inuse_chunk(m, newp);
+      return chunk2mem(newp);
+    }
+    else {
+      void* newmem = internal_malloc(m, bytes);
+      if (newmem != 0) {
+        size_t oc = oldsize - overhead_for(oldp);
+        memcpy(newmem, oldmem, (oc < bytes)? oc : bytes);
+        internal_free(m, oldmem);
+      }
+      return newmem;
+    }
+  }
+  return 0;
+}
+
+/* --------------------------- memalign support -------------------------- */
+
+static void* internal_memalign(mstate m, size_t alignment, size_t bytes) {
+  if (alignment <= MALLOC_ALIGNMENT)    /* Can just use malloc */
+    return internal_malloc(m, bytes);
+  if (alignment <  MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */
+    alignment = MIN_CHUNK_SIZE;
+  if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */
+    size_t a = MALLOC_ALIGNMENT << 1;
+    while (a < alignment) a <<= 1;
+    alignment = a;
+  }
+
+  if (bytes >= MAX_REQUEST - alignment) {
+    if (m != 0)  { /* Test isn't needed but avoids compiler warning */
+      MALLOC_FAILURE_ACTION;
+    }
+  }
+  else {
+    size_t nb = request2size(bytes);
+    size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;
+    char* mem = (char*)internal_malloc(m, req);
+    if (mem != 0) {
+      void* leader = 0;
+      void* trailer = 0;
+      mchunkptr p = mem2chunk(mem);
+
+      if (PREACTION(m)) return 0;
+      if ((((size_t)(mem)) % alignment) != 0) { /* misaligned */
+        /*
+          Find an aligned spot inside chunk.  Since we need to give
+          back leading space in a chunk of at least MIN_CHUNK_SIZE, if
+          the first calculation places us at a spot with less than
+          MIN_CHUNK_SIZE leader, we can move to the next aligned spot.
+          We've allocated enough total room so that this is always
+          possible.
+        */
+        char* br = (char*)mem2chunk((size_t)(((size_t)(mem +
+                                                       alignment -
+                                                       SIZE_T_ONE)) &
+                                             -alignment));
+        char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)?
+          br : br+alignment;
+        mchunkptr newp = (mchunkptr)pos;
+        size_t leadsize = pos - (char*)(p);
+        size_t newsize = chunksize(p) - leadsize;
+
+        if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */
+          newp->prev_foot = p->prev_foot + leadsize;
+          newp->head = (newsize|CINUSE_BIT);
+        }
+        else { /* Otherwise, give back leader, use the rest */
+          set_inuse(m, newp, newsize);
+          set_inuse(m, p, leadsize);
+          leader = chunk2mem(p);
+        }
+        p = newp;
+      }
+
+      /* Give back spare room at the end */
+      if (!is_mmapped(p)) {
+        size_t size = chunksize(p);
+        if (size > nb + MIN_CHUNK_SIZE) {
+          size_t remainder_size = size - nb;
+          mchunkptr remainder = chunk_plus_offset(p, nb);
+          set_inuse(m, p, nb);
+          set_inuse(m, remainder, remainder_size);
+          trailer = chunk2mem(remainder);
+        }
+      }
+
+      assert (chunksize(p) >= nb);
+      assert((((size_t)(chunk2mem(p))) % alignment) == 0);
+      check_inuse_chunk(m, p);
+      POSTACTION(m);
+      if (leader != 0) {
+        internal_free(m, leader);
+      }
+      if (trailer != 0) {
+        internal_free(m, trailer);
+      }
+      return chunk2mem(p);
+    }
+  }
+  return 0;
+}
+
+/* ------------------------ comalloc/coalloc support --------------------- */
+
+static void** ialloc(mstate m,
+                     size_t n_elements,
+                     size_t* sizes,
+                     int opts,
+                     void* chunks[]) {
+  /*
+    This provides common support for independent_X routines, handling
+    all of the combinations that can result.
+
+    The opts arg has:
+    bit 0 set if all elements are same size (using sizes[0])
+    bit 1 set if elements should be zeroed
+  */
+
+  size_t    element_size;   /* chunksize of each element, if all same */
+  size_t    contents_size;  /* total size of elements */
+  size_t    array_size;     /* request size of pointer array */
+  void*     mem;            /* malloced aggregate space */
+  mchunkptr p;              /* corresponding chunk */
+  size_t    remainder_size; /* remaining bytes while splitting */
+  void**    marray;         /* either "chunks" or malloced ptr array */
+  mchunkptr array_chunk;    /* chunk for malloced ptr array */
+  flag_t    was_enabled;    /* to disable mmap */
+  size_t    size;
+  size_t    i;
+
+  /* compute array length, if needed */
+  if (chunks != 0) {
+    if (n_elements == 0)
+      return chunks; /* nothing to do */
+    marray = chunks;
+    array_size = 0;
+  }
+  else {
+    /* if empty req, must still return chunk representing empty array */
+    if (n_elements == 0)
+      return (void**)internal_malloc(m, 0);
+    marray = 0;
+    array_size = request2size(n_elements * (sizeof(void*)));
+  }
+
+  /* compute total element size */
+  if (opts & 0x1) { /* all-same-size */
+    element_size = request2size(*sizes);
+    contents_size = n_elements * element_size;
+  }
+  else { /* add up all the sizes */
+    element_size = 0;
+    contents_size = 0;
+    for (i = 0; i != n_elements; ++i)
+      contents_size += request2size(sizes[i]);
+  }
+
+  size = contents_size + array_size;
+
+  /*
+     Allocate the aggregate chunk.  First disable direct-mmapping so
+     malloc won't use it, since we would not be able to later
+     free/realloc space internal to a segregated mmap region.
+  */
+  was_enabled = use_mmap(m);
+  disable_mmap(m);
+  mem = internal_malloc(m, size - CHUNK_OVERHEAD);
+  if (was_enabled)
+    enable_mmap(m);
+  if (mem == 0)
+    return 0;
+
+  if (PREACTION(m)) return 0;
+  p = mem2chunk(mem);
+  remainder_size = chunksize(p);
+
+  assert(!is_mmapped(p));
+
+  if (opts & 0x2) {       /* optionally clear the elements */
+    memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size);
+  }
+
+  /* If not provided, allocate the pointer array as final part of chunk */
+  if (marray == 0) {
+    size_t  array_chunk_size;
+    array_chunk = chunk_plus_offset(p, contents_size);
+    array_chunk_size = remainder_size - contents_size;
+    marray = (void**) (chunk2mem(array_chunk));
+    set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size);
+    remainder_size = contents_size;
+  }
+
+  /* split out elements */
+  for (i = 0; ; ++i) {
+    marray[i] = chunk2mem(p);
+    if (i != n_elements-1) {
+      if (element_size != 0)
+        size = element_size;
+      else
+        size = request2size(sizes[i]);
+      remainder_size -= size;
+      set_size_and_pinuse_of_inuse_chunk(m, p, size);
+      p = chunk_plus_offset(p, size);
+    }
+    else { /* the final element absorbs any overallocation slop */
+      set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size);
+      break;
+    }
+  }
+
+#if DEBUG
+  if (marray != chunks) {
+    /* final element must have exactly exhausted chunk */
+    if (element_size != 0) {
+      assert(remainder_size == element_size);
+    }
+    else {
+      assert(remainder_size == request2size(sizes[i]));
+    }
+    check_inuse_chunk(m, mem2chunk(marray));
+  }
+  for (i = 0; i != n_elements; ++i)
+    check_inuse_chunk(m, mem2chunk(marray[i]));
+
+#endif /* DEBUG */
+
+  POSTACTION(m);
+  return marray;
+}
+
+
+/* -------------------------- public routines ---------------------------- */
+
+#if !ONLY_MSPACES
+
+void* dlmalloc(size_t bytes) {
+  /*
+     Basic algorithm:
+     If a small request (< 256 bytes minus per-chunk overhead):
+       1. If one exists, use a remainderless chunk in associated smallbin.
+          (Remainderless means that there are too few excess bytes to
+          represent as a chunk.)
+       2. If it is big enough, use the dv chunk, which is normally the
+          chunk adjacent to the one used for the most recent small request.
+       3. If one exists, split the smallest available chunk in a bin,
+          saving remainder in dv.
+       4. If it is big enough, use the top chunk.
+       5. If available, get memory from system and use it
+     Otherwise, for a large request:
+       1. Find the smallest available binned chunk that fits, and use it
+          if it is better fitting than dv chunk, splitting if necessary.
+       2. If better fitting than any binned chunk, use the dv chunk.
+       3. If it is big enough, use the top chunk.
+       4. If request size >= mmap threshold, try to directly mmap this chunk.
+       5. If available, get memory from system and use it
+
+     The ugly goto's here ensure that postaction occurs along all paths.
+  */
+
+  if (!PREACTION(gm)) {
+    void* mem;
+    size_t nb;
+    if (bytes <= MAX_SMALL_REQUEST) {
+      bindex_t idx;
+      binmap_t smallbits;
+      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
+      idx = small_index(nb);
+      smallbits = gm->smallmap >> idx;
+
+      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
+        mchunkptr b, p;
+        idx += ~smallbits & 1;       /* Uses next bin if idx empty */
+        b = smallbin_at(gm, idx);
+        p = b->fd;
+        assert(chunksize(p) == small_index2size(idx));
+        unlink_first_small_chunk(gm, b, p, idx);
+        set_inuse_and_pinuse(gm, p, small_index2size(idx));
+        mem = chunk2mem(p);
+        check_malloced_chunk(gm, mem, nb);
+        goto postaction;
+      }
+
+      else if (nb > gm->dvsize) {
+        if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
+          mchunkptr b, p, r;
+          size_t rsize;
+          bindex_t i;
+          binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
+          binmap_t leastbit = least_bit(leftbits);
+          compute_bit2idx(leastbit, i);
+          b = smallbin_at(gm, i);
+          p = b->fd;
+          assert(chunksize(p) == small_index2size(i));
+          unlink_first_small_chunk(gm, b, p, i);
+          rsize = small_index2size(i) - nb;
+          /* Fit here cannot be remainderless if 4byte sizes */
+          if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
+            set_inuse_and_pinuse(gm, p, small_index2size(i));
+          else {
+            set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
+            r = chunk_plus_offset(p, nb);
+            set_size_and_pinuse_of_free_chunk(r, rsize);
+            replace_dv(gm, r, rsize);
+          }
+          mem = chunk2mem(p);
+          check_malloced_chunk(gm, mem, nb);
+          goto postaction;
+        }
+
+        else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) {
+          check_malloced_chunk(gm, mem, nb);
+          goto postaction;
+        }
+      }
+    }
+    else if (bytes >= MAX_REQUEST)
+      nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
+    else {
+      nb = pad_request(bytes);
+      if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) {
+        check_malloced_chunk(gm, mem, nb);
+        goto postaction;
+      }
+    }
+
+    if (nb <= gm->dvsize) {
+      size_t rsize = gm->dvsize - nb;
+      mchunkptr p = gm->dv;
+      if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
+        mchunkptr r = gm->dv = chunk_plus_offset(p, nb);
+        gm->dvsize = rsize;
+        set_size_and_pinuse_of_free_chunk(r, rsize);
+        set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
+      }
+      else { /* exhaust dv */
+        size_t dvs = gm->dvsize;
+        gm->dvsize = 0;
+        gm->dv = 0;
+        set_inuse_and_pinuse(gm, p, dvs);
+      }
+      mem = chunk2mem(p);
+      check_malloced_chunk(gm, mem, nb);
+      goto postaction;
+    }
+
+    else if (nb < gm->topsize) { /* Split top */
+      size_t rsize = gm->topsize -= nb;
+      mchunkptr p = gm->top;
+      mchunkptr r = gm->top = chunk_plus_offset(p, nb);
+      r->head = rsize | PINUSE_BIT;
+      set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
+      mem = chunk2mem(p);
+      check_top_chunk(gm, gm->top);
+      check_malloced_chunk(gm, mem, nb);
+      goto postaction;
+    }
+
+    mem = sys_alloc(gm, nb);
+
+  postaction:
+    POSTACTION(gm);
+    return mem;
+  }
+
+  return 0;
+}
+
+void dlfree(void* mem) {
+  /*
+     Consolidate freed chunks with preceeding or succeeding bordering
+     free chunks, if they exist, and then place in a bin.  Intermixed
+     with special cases for top, dv, mmapped chunks, and usage errors.
+  */
+
+  if (mem != 0) {
+    mchunkptr p  = mem2chunk(mem);
+#if FOOTERS
+    mstate fm = get_mstate_for(p);
+    if (!ok_magic(fm)) {
+      USAGE_ERROR_ACTION(fm, p);
+      return;
+    }
+#else /* FOOTERS */
+#define fm gm
+#endif /* FOOTERS */
+    if (!PREACTION(fm)) {
+      check_inuse_chunk(fm, p);
+      if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) {
+        size_t psize = chunksize(p);
+        mchunkptr next = chunk_plus_offset(p, psize);
+        if (!pinuse(p)) {
+          size_t prevsize = p->prev_foot;
+          if ((prevsize & IS_MMAPPED_BIT) != 0) {
+            prevsize &= ~IS_MMAPPED_BIT;
+            psize += prevsize + MMAP_FOOT_PAD;
+            if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
+              fm->footprint -= psize;
+            goto postaction;
+          }
+          else {
+            mchunkptr prev = chunk_minus_offset(p, prevsize);
+            psize += prevsize;
+            p = prev;
+            if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
+              if (p != fm->dv) {
+                unlink_chunk(fm, p, prevsize);
+              }
+              else if ((next->head & INUSE_BITS) == INUSE_BITS) {
+                fm->dvsize = psize;
+                set_free_with_pinuse(p, psize, next);
+                goto postaction;
+              }
+            }
+            else
+              goto erroraction;
+          }
+        }
+
+        if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
+          if (!cinuse(next)) {  /* consolidate forward */
+            if (next == fm->top) {
+              size_t tsize = fm->topsize += psize;
+              fm->top = p;
+              p->head = tsize | PINUSE_BIT;
+              if (p == fm->dv) {
+                fm->dv = 0;
+                fm->dvsize = 0;
+              }
+              if (should_trim(fm, tsize))
+                sys_trim(fm, 0);
+              goto postaction;
+            }
+            else if (next == fm->dv) {
+              size_t dsize = fm->dvsize += psize;
+              fm->dv = p;
+              set_size_and_pinuse_of_free_chunk(p, dsize);
+              goto postaction;
+            }
+            else {
+              size_t nsize = chunksize(next);
+              psize += nsize;
+              unlink_chunk(fm, next, nsize);
+              set_size_and_pinuse_of_free_chunk(p, psize);
+              if (p == fm->dv) {
+                fm->dvsize = psize;
+                goto postaction;
+              }
+            }
+          }
+          else
+            set_free_with_pinuse(p, psize, next);
+          insert_chunk(fm, p, psize);
+          check_free_chunk(fm, p);
+          goto postaction;
+        }
+      }
+    erroraction:
+      USAGE_ERROR_ACTION(fm, p);
+    postaction:
+      POSTACTION(fm);
+    }
+  }
+#if !FOOTERS
+#undef fm
+#endif /* FOOTERS */
+}
+
+void* dlcalloc(size_t n_elements, size_t elem_size) {
+  void* mem;
+  size_t req = 0;
+  if (n_elements != 0) {
+    req = n_elements * elem_size;
+    if (((n_elements | elem_size) & ~(size_t)0xffff) &&
+        (req / n_elements != elem_size))
+      req = MAX_SIZE_T; /* force downstream failure on overflow */
+  }
+  mem = dlmalloc(req);
+  if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
+    memset(mem, 0, req);
+  return mem;
+}
+
+void* dlrealloc(void* oldmem, size_t bytes) {
+  if (oldmem == 0)
+    return dlmalloc(bytes);
+#ifdef REALLOC_ZERO_BYTES_FREES
+  if (bytes == 0) {
+    dlfree(oldmem);
+    return 0;
+  }
+#endif /* REALLOC_ZERO_BYTES_FREES */
+  else {
+#if ! FOOTERS
+    mstate m = gm;
+#else /* FOOTERS */
+    mstate m = get_mstate_for(mem2chunk(oldmem));
+    if (!ok_magic(m)) {
+      USAGE_ERROR_ACTION(m, oldmem);
+      return 0;
+    }
+#endif /* FOOTERS */
+    return internal_realloc(m, oldmem, bytes);
+  }
+}
+
+void* dlmemalign(size_t alignment, size_t bytes) {
+  return internal_memalign(gm, alignment, bytes);
+}
+
+void** dlindependent_calloc(size_t n_elements, size_t elem_size,
+                                 void* chunks[]) {
+  size_t sz = elem_size; /* serves as 1-element array */
+  return ialloc(gm, n_elements, &sz, 3, chunks);
+}
+
+void** dlindependent_comalloc(size_t n_elements, size_t sizes[],
+                                   void* chunks[]) {
+  return ialloc(gm, n_elements, sizes, 0, chunks);
+}
+
+void* dlvalloc(size_t bytes) {
+  size_t pagesz;
+  init_mparams();
+  pagesz = mparams.page_size;
+  return dlmemalign(pagesz, bytes);
+}
+
+void* dlpvalloc(size_t bytes) {
+  size_t pagesz;
+  init_mparams();
+  pagesz = mparams.page_size;
+  return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE));
+}
+
+int dlmalloc_trim(size_t pad) {
+  int result = 0;
+  if (!PREACTION(gm)) {
+    result = sys_trim(gm, pad);
+    POSTACTION(gm);
+  }
+  return result;
+}
+
+size_t dlmalloc_footprint(void) {
+  return gm->footprint;
+}
+
+size_t dlmalloc_max_footprint(void) {
+  return gm->max_footprint;
+}
+
+#if !NO_MALLINFO
+struct mallinfo dlmallinfo(void) {
+  return internal_mallinfo(gm);
+}
+#endif /* NO_MALLINFO */
+
+void dlmalloc_stats() {
+  internal_malloc_stats(gm);
+}
+
+size_t dlmalloc_usable_size(void* mem) {
+  if (mem != 0) {
+    mchunkptr p = mem2chunk(mem);
+    if (cinuse(p))
+      return chunksize(p) - overhead_for(p);
+  }
+  return 0;
+}
+
+int dlmallopt(int param_number, int value) {
+  return change_mparam(param_number, value);
+}
+
+#endif /* !ONLY_MSPACES */
+
+/* ----------------------------- user mspaces ---------------------------- */
+
+#if MSPACES
+
+static mstate init_user_mstate(char* tbase, size_t tsize) {
+  size_t msize = pad_request(sizeof(struct malloc_state));
+  mchunkptr mn;
+  mchunkptr msp = align_as_chunk(tbase);
+  mstate m = (mstate)(chunk2mem(msp));
+  memset(m, 0, msize);
+  INITIAL_LOCK(&m->mutex);
+  msp->head = (msize|PINUSE_BIT|CINUSE_BIT);
+  m->seg.base = m->least_addr = tbase;
+  m->seg.size = m->footprint = m->max_footprint = tsize;
+  m->magic = mparams.magic;
+  m->mflags = mparams.default_mflags;
+  disable_contiguous(m);
+  init_bins(m);
+  mn = next_chunk(mem2chunk(m));
+  init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE);
+  check_top_chunk(m, m->top);
+  return m;
+}
+
+mspace create_mspace(size_t capacity, int locked) {
+  mstate m = 0;
+  size_t msize = pad_request(sizeof(struct malloc_state));
+  init_mparams(); /* Ensure pagesize etc initialized */
+
+  if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
+    size_t rs = ((capacity == 0)? mparams.granularity :
+                 (capacity + TOP_FOOT_SIZE + msize));
+    size_t tsize = granularity_align(rs);
+    char* tbase = (char*)(CALL_MMAP(tsize));
+    if (tbase != CMFAIL) {
+      m = init_user_mstate(tbase, tsize);
+      m->seg.sflags = IS_MMAPPED_BIT;
+      set_lock(m, locked);
+    }
+  }
+  return (mspace)m;
+}
+
+mspace create_mspace_with_base(void* base, size_t capacity, int locked) {
+  mstate m = 0;
+  size_t msize = pad_request(sizeof(struct malloc_state));
+  init_mparams(); /* Ensure pagesize etc initialized */
+
+  if (capacity > msize + TOP_FOOT_SIZE &&
+      capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
+    m = init_user_mstate((char*)base, capacity);
+    m->seg.sflags = EXTERN_BIT;
+    set_lock(m, locked);
+  }
+  return (mspace)m;
+}
+
+size_t destroy_mspace(mspace msp) {
+  size_t freed = 0;
+  mstate ms = (mstate)msp;
+  if (ok_magic(ms)) {
+    msegmentptr sp = &ms->seg;
+    while (sp != 0) {
+      char* base = sp->base;
+      size_t size = sp->size;
+      flag_t flag = sp->sflags;
+      sp = sp->next;
+      if ((flag & IS_MMAPPED_BIT) && !(flag & EXTERN_BIT) &&
+          CALL_MUNMAP(base, size) == 0)
+        freed += size;
+    }
+  }
+  else {
+    USAGE_ERROR_ACTION(ms,ms);
+  }
+  return freed;
+}
+
+/*
+  mspace versions of routines are near-clones of the global
+  versions. This is not so nice but better than the alternatives.
+*/
+
+
+void* mspace_malloc(mspace msp, size_t bytes) {
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+    return 0;
+  }
+  if (!PREACTION(ms)) {
+    void* mem;
+    size_t nb;
+    if (bytes <= MAX_SMALL_REQUEST) {
+      bindex_t idx;
+      binmap_t smallbits;
+      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
+      idx = small_index(nb);
+      smallbits = ms->smallmap >> idx;
+
+      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
+        mchunkptr b, p;
+        idx += ~smallbits & 1;       /* Uses next bin if idx empty */
+        b = smallbin_at(ms, idx);
+        p = b->fd;
+        assert(chunksize(p) == small_index2size(idx));
+        unlink_first_small_chunk(ms, b, p, idx);
+        set_inuse_and_pinuse(ms, p, small_index2size(idx));
+        mem = chunk2mem(p);
+        check_malloced_chunk(ms, mem, nb);
+        goto postaction;
+      }
+
+      else if (nb > ms->dvsize) {
+        if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
+          mchunkptr b, p, r;
+          size_t rsize;
+          bindex_t i;
+          binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
+          binmap_t leastbit = least_bit(leftbits);
+          compute_bit2idx(leastbit, i);
+          b = smallbin_at(ms, i);
+          p = b->fd;
+          assert(chunksize(p) == small_index2size(i));
+          unlink_first_small_chunk(ms, b, p, i);
+          rsize = small_index2size(i) - nb;
+          /* Fit here cannot be remainderless if 4byte sizes */
+          if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
+            set_inuse_and_pinuse(ms, p, small_index2size(i));
+          else {
+            set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+            r = chunk_plus_offset(p, nb);
+            set_size_and_pinuse_of_free_chunk(r, rsize);
+            replace_dv(ms, r, rsize);
+          }
+          mem = chunk2mem(p);
+          check_malloced_chunk(ms, mem, nb);
+          goto postaction;
+        }
+
+        else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) {
+          check_malloced_chunk(ms, mem, nb);
+          goto postaction;
+        }
+      }
+    }
+    else if (bytes >= MAX_REQUEST)
+      nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
+    else {
+      nb = pad_request(bytes);
+      if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) {
+        check_malloced_chunk(ms, mem, nb);
+        goto postaction;
+      }
+    }
+
+    if (nb <= ms->dvsize) {
+      size_t rsize = ms->dvsize - nb;
+      mchunkptr p = ms->dv;
+      if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
+        mchunkptr r = ms->dv = chunk_plus_offset(p, nb);
+        ms->dvsize = rsize;
+        set_size_and_pinuse_of_free_chunk(r, rsize);
+        set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+      }
+      else { /* exhaust dv */
+        size_t dvs = ms->dvsize;
+        ms->dvsize = 0;
+        ms->dv = 0;
+        set_inuse_and_pinuse(ms, p, dvs);
+      }
+      mem = chunk2mem(p);
+      check_malloced_chunk(ms, mem, nb);
+      goto postaction;
+    }
+
+    else if (nb < ms->topsize) { /* Split top */
+      size_t rsize = ms->topsize -= nb;
+      mchunkptr p = ms->top;
+      mchunkptr r = ms->top = chunk_plus_offset(p, nb);
+      r->head = rsize | PINUSE_BIT;
+      set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+      mem = chunk2mem(p);
+      check_top_chunk(ms, ms->top);
+      check_malloced_chunk(ms, mem, nb);
+      goto postaction;
+    }
+
+    mem = sys_alloc(ms, nb);
+
+  postaction:
+    POSTACTION(ms);
+    return mem;
+  }
+
+  return 0;
+}
+
+void mspace_free(mspace msp, void* mem) {
+  if (mem != 0) {
+    mchunkptr p  = mem2chunk(mem);
+#if FOOTERS
+    mstate fm = get_mstate_for(p);
+#else /* FOOTERS */
+    mstate fm = (mstate)msp;
+#endif /* FOOTERS */
+    if (!ok_magic(fm)) {
+      USAGE_ERROR_ACTION(fm, p);
+      return;
+    }
+    if (!PREACTION(fm)) {
+      check_inuse_chunk(fm, p);
+      if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) {
+        size_t psize = chunksize(p);
+        mchunkptr next = chunk_plus_offset(p, psize);
+        if (!pinuse(p)) {
+          size_t prevsize = p->prev_foot;
+          if ((prevsize & IS_MMAPPED_BIT) != 0) {
+            prevsize &= ~IS_MMAPPED_BIT;
+            psize += prevsize + MMAP_FOOT_PAD;
+            if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
+              fm->footprint -= psize;
+            goto postaction;
+          }
+          else {
+            mchunkptr prev = chunk_minus_offset(p, prevsize);
+            psize += prevsize;
+            p = prev;
+            if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
+              if (p != fm->dv) {
+                unlink_chunk(fm, p, prevsize);
+              }
+              else if ((next->head & INUSE_BITS) == INUSE_BITS) {
+                fm->dvsize = psize;
+                set_free_with_pinuse(p, psize, next);
+                goto postaction;
+              }
+            }
+            else
+              goto erroraction;
+          }
+        }
+
+        if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
+          if (!cinuse(next)) {  /* consolidate forward */
+            if (next == fm->top) {
+              size_t tsize = fm->topsize += psize;
+              fm->top = p;
+              p->head = tsize | PINUSE_BIT;
+              if (p == fm->dv) {
+                fm->dv = 0;
+                fm->dvsize = 0;
+              }
+              if (should_trim(fm, tsize))
+                sys_trim(fm, 0);
+              goto postaction;
+            }
+            else if (next == fm->dv) {
+              size_t dsize = fm->dvsize += psize;
+              fm->dv = p;
+              set_size_and_pinuse_of_free_chunk(p, dsize);
+              goto postaction;
+            }
+            else {
+              size_t nsize = chunksize(next);
+              psize += nsize;
+              unlink_chunk(fm, next, nsize);
+              set_size_and_pinuse_of_free_chunk(p, psize);
+              if (p == fm->dv) {
+                fm->dvsize = psize;
+                goto postaction;
+              }
+            }
+          }
+          else
+            set_free_with_pinuse(p, psize, next);
+          insert_chunk(fm, p, psize);
+          check_free_chunk(fm, p);
+          goto postaction;
+        }
+      }
+    erroraction:
+      USAGE_ERROR_ACTION(fm, p);
+    postaction:
+      POSTACTION(fm);
+    }
+  }
+}
+
+void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) {
+  void* mem;
+  size_t req = 0;
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+    return 0;
+  }
+  if (n_elements != 0) {
+    req = n_elements * elem_size;
+    if (((n_elements | elem_size) & ~(size_t)0xffff) &&
+        (req / n_elements != elem_size))
+      req = MAX_SIZE_T; /* force downstream failure on overflow */
+  }
+  mem = internal_malloc(ms, req);
+  if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
+    memset(mem, 0, req);
+  return mem;
+}
+
+void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) {
+  if (oldmem == 0)
+    return mspace_malloc(msp, bytes);
+#ifdef REALLOC_ZERO_BYTES_FREES
+  if (bytes == 0) {
+    mspace_free(msp, oldmem);
+    return 0;
+  }
+#endif /* REALLOC_ZERO_BYTES_FREES */
+  else {
+#if FOOTERS
+    mchunkptr p  = mem2chunk(oldmem);
+    mstate ms = get_mstate_for(p);
+#else /* FOOTERS */
+    mstate ms = (mstate)msp;
+#endif /* FOOTERS */
+    if (!ok_magic(ms)) {
+      USAGE_ERROR_ACTION(ms,ms);
+      return 0;
+    }
+    return internal_realloc(ms, oldmem, bytes);
+  }
+}
+
+void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) {
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+    return 0;
+  }
+  return internal_memalign(ms, alignment, bytes);
+}
+
+void** mspace_independent_calloc(mspace msp, size_t n_elements,
+                                 size_t elem_size, void* chunks[]) {
+  size_t sz = elem_size; /* serves as 1-element array */
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+    return 0;
+  }
+  return ialloc(ms, n_elements, &sz, 3, chunks);
+}
+
+void** mspace_independent_comalloc(mspace msp, size_t n_elements,
+                                   size_t sizes[], void* chunks[]) {
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+    return 0;
+  }
+  return ialloc(ms, n_elements, sizes, 0, chunks);
+}
+
+int mspace_trim(mspace msp, size_t pad) {
+  int result = 0;
+  mstate ms = (mstate)msp;
+  if (ok_magic(ms)) {
+    if (!PREACTION(ms)) {
+      result = sys_trim(ms, pad);
+      POSTACTION(ms);
+    }
+  }
+  else {
+    USAGE_ERROR_ACTION(ms,ms);
+  }
+  return result;
+}
+
+void mspace_malloc_stats(mspace msp) {
+  mstate ms = (mstate)msp;
+  if (ok_magic(ms)) {
+    internal_malloc_stats(ms);
+  }
+  else {
+    USAGE_ERROR_ACTION(ms,ms);
+  }
+}
+
+size_t mspace_footprint(mspace msp) {
+  size_t result;
+  mstate ms = (mstate)msp;
+  if (ok_magic(ms)) {
+    result = ms->footprint;
+  }
+  USAGE_ERROR_ACTION(ms,ms);
+  return result;
+}
+
+
+size_t mspace_max_footprint(mspace msp) {
+  size_t result;
+  mstate ms = (mstate)msp;
+  if (ok_magic(ms)) {
+    result = ms->max_footprint;
+  }
+  USAGE_ERROR_ACTION(ms,ms);
+  return result;
+}
+
+
+#if !NO_MALLINFO
+struct mallinfo mspace_mallinfo(mspace msp) {
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+  }
+  return internal_mallinfo(ms);
+}
+#endif /* NO_MALLINFO */
+
+int mspace_mallopt(int param_number, int value) {
+  return change_mparam(param_number, value);
+}
+
+#endif /* MSPACES */
+
+/* -------------------- Alternative MORECORE functions ------------------- */
+
+/*
+  Guidelines for creating a custom version of MORECORE:
+
+  * For best performance, MORECORE should allocate in multiples of pagesize.
+  * MORECORE may allocate more memory than requested. (Or even less,
+      but this will usually result in a malloc failure.)
+  * MORECORE must not allocate memory when given argument zero, but
+      instead return one past the end address of memory from previous
+      nonzero call.
+  * For best performance, consecutive calls to MORECORE with positive
+      arguments should return increasing addresses, indicating that
+      space has been contiguously extended.
+  * Even though consecutive calls to MORECORE need not return contiguous
+      addresses, it must be OK for malloc'ed chunks to span multiple
+      regions in those cases where they do happen to be contiguous.
+  * MORECORE need not handle negative arguments -- it may instead
+      just return MFAIL when given negative arguments.
+      Negative arguments are always multiples of pagesize. MORECORE
+      must not misinterpret negative args as large positive unsigned
+      args. You can suppress all such calls from even occurring by defining
+      MORECORE_CANNOT_TRIM,
+
+  As an example alternative MORECORE, here is a custom allocator
+  kindly contributed for pre-OSX macOS.  It uses virtually but not
+  necessarily physically contiguous non-paged memory (locked in,
+  present and won't get swapped out).  You can use it by uncommenting
+  this section, adding some #includes, and setting up the appropriate
+  defines above:
+
+      #define MORECORE osMoreCore
+
+  There is also a shutdown routine that should somehow be called for
+  cleanup upon program exit.
+
+  #define MAX_POOL_ENTRIES 100
+  #define MINIMUM_MORECORE_SIZE  (64 * 1024U)
+  static int next_os_pool;
+  void *our_os_pools[MAX_POOL_ENTRIES];
+
+  void *osMoreCore(int size)
+  {
+    void *ptr = 0;
+    static void *sbrk_top = 0;
+
+    if (size > 0)
+    {
+      if (size < MINIMUM_MORECORE_SIZE)
+         size = MINIMUM_MORECORE_SIZE;
+      if (CurrentExecutionLevel() == kTaskLevel)
+         ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0);
+      if (ptr == 0)
+      {
+        return (void *) MFAIL;
+      }
+      // save ptrs so they can be freed during cleanup
+      our_os_pools[next_os_pool] = ptr;
+      next_os_pool++;
+      ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK);
+      sbrk_top = (char *) ptr + size;
+      return ptr;
+    }
+    else if (size < 0)
+    {
+      // we don't currently support shrink behavior
+      return (void *) MFAIL;
+    }
+    else
+    {
+      return sbrk_top;
+    }
+  }
+
+  // cleanup any allocated memory pools
+  // called as last thing before shutting down driver
+
+  void osCleanupMem(void)
+  {
+    void **ptr;
+
+    for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++)
+      if (*ptr)
+      {
+         PoolDeallocate(*ptr);
+         *ptr = 0;
+      }
+  }
+
+*/
+
+
+/* -----------------------------------------------------------------------
+History:
+    V2.8.3 Thu Sep 22 11:16:32 2005  Doug Lea  (dl at gee)
+      * Add max_footprint functions
+      * Ensure all appropriate literals are size_t
+      * Fix conditional compilation problem for some #define settings
+      * Avoid concatenating segments with the one provided
+        in create_mspace_with_base
+      * Rename some variables to avoid compiler shadowing warnings
+      * Use explicit lock initialization.
+      * Better handling of sbrk interference.
+      * Simplify and fix segment insertion, trimming and mspace_destroy
+      * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x
+      * Thanks especially to Dennis Flanagan for help on these.
+
+    V2.8.2 Sun Jun 12 16:01:10 2005  Doug Lea  (dl at gee)
+      * Fix memalign brace error.
+
+    V2.8.1 Wed Jun  8 16:11:46 2005  Doug Lea  (dl at gee)
+      * Fix improper #endif nesting in C++
+      * Add explicit casts needed for C++
+
+    V2.8.0 Mon May 30 14:09:02 2005  Doug Lea  (dl at gee)
+      * Use trees for large bins
+      * Support mspaces
+      * Use segments to unify sbrk-based and mmap-based system allocation,
+        removing need for emulation on most platforms without sbrk.
+      * Default safety checks
+      * Optional footer checks. Thanks to William Robertson for the idea.
+      * Internal code refactoring
+      * Incorporate suggestions and platform-specific changes.
+        Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas,
+        Aaron Bachmann,  Emery Berger, and others.
+      * Speed up non-fastbin processing enough to remove fastbins.
+      * Remove useless cfree() to avoid conflicts with other apps.
+      * Remove internal memcpy, memset. Compilers handle builtins better.
+      * Remove some options that no one ever used and rename others.
+
+    V2.7.2 Sat Aug 17 09:07:30 2002  Doug Lea  (dl at gee)
+      * Fix malloc_state bitmap array misdeclaration
+
+    V2.7.1 Thu Jul 25 10:58:03 2002  Doug Lea  (dl at gee)
+      * Allow tuning of FIRST_SORTED_BIN_SIZE
+      * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte.
+      * Better detection and support for non-contiguousness of MORECORE.
+        Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger
+      * Bypass most of malloc if no frees. Thanks To Emery Berger.
+      * Fix freeing of old top non-contiguous chunk im sysmalloc.
+      * Raised default trim and map thresholds to 256K.
+      * Fix mmap-related #defines. Thanks to Lubos Lunak.
+      * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield.
+      * Branch-free bin calculation
+      * Default trim and mmap thresholds now 256K.
+
+    V2.7.0 Sun Mar 11 14:14:06 2001  Doug Lea  (dl at gee)
+      * Introduce independent_comalloc and independent_calloc.
+        Thanks to Michael Pachos for motivation and help.
+      * Make optional .h file available
+      * Allow > 2GB requests on 32bit systems.
+      * new WIN32 sbrk, mmap, munmap, lock code from <Walter@GeNeSys-e.de>.
+        Thanks also to Andreas Mueller <a.mueller at paradatec.de>,
+        and Anonymous.
+      * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for
+        helping test this.)
+      * memalign: check alignment arg
+      * realloc: don't try to shift chunks backwards, since this
+        leads to  more fragmentation in some programs and doesn't
+        seem to help in any others.
+      * Collect all cases in malloc requiring system memory into sysmalloc
+      * Use mmap as backup to sbrk
+      * Place all internal state in malloc_state
+      * Introduce fastbins (although similar to 2.5.1)
+      * Many minor tunings and cosmetic improvements
+      * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK
+      * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS
+        Thanks to Tony E. Bennett <tbennett@nvidia.com> and others.
+      * Include errno.h to support default failure action.
+
+    V2.6.6 Sun Dec  5 07:42:19 1999  Doug Lea  (dl at gee)
+      * return null for negative arguments
+      * Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com>
+         * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
+          (e.g. WIN32 platforms)
+         * Cleanup header file inclusion for WIN32 platforms
+         * Cleanup code to avoid Microsoft Visual C++ compiler complaints
+         * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
+           memory allocation routines
+         * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
+         * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
+           usage of 'assert' in non-WIN32 code
+         * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
+           avoid infinite loop
+      * Always call 'fREe()' rather than 'free()'
+
+    V2.6.5 Wed Jun 17 15:57:31 1998  Doug Lea  (dl at gee)
+      * Fixed ordering problem with boundary-stamping
+
+    V2.6.3 Sun May 19 08:17:58 1996  Doug Lea  (dl at gee)
+      * Added pvalloc, as recommended by H.J. Liu
+      * Added 64bit pointer support mainly from Wolfram Gloger
+      * Added anonymously donated WIN32 sbrk emulation
+      * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
+      * malloc_extend_top: fix mask error that caused wastage after
+        foreign sbrks
+      * Add linux mremap support code from HJ Liu
+
+    V2.6.2 Tue Dec  5 06:52:55 1995  Doug Lea  (dl at gee)
+      * Integrated most documentation with the code.
+      * Add support for mmap, with help from
+        Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+      * Use last_remainder in more cases.
+      * Pack bins using idea from  colin@nyx10.cs.du.edu
+      * Use ordered bins instead of best-fit threshhold
+      * Eliminate block-local decls to simplify tracing and debugging.
+      * Support another case of realloc via move into top
+      * Fix error occuring when initial sbrk_base not word-aligned.
+      * Rely on page size for units instead of SBRK_UNIT to
+        avoid surprises about sbrk alignment conventions.
+      * Add mallinfo, mallopt. Thanks to Raymond Nijssen
+        (raymond@es.ele.tue.nl) for the suggestion.
+      * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
+      * More precautions for cases where other routines call sbrk,
+        courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+      * Added macros etc., allowing use in linux libc from
+        H.J. Lu (hjl@gnu.ai.mit.edu)
+      * Inverted this history list
+
+    V2.6.1 Sat Dec  2 14:10:57 1995  Doug Lea  (dl at gee)
+      * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
+      * Removed all preallocation code since under current scheme
+        the work required to undo bad preallocations exceeds
+        the work saved in good cases for most test programs.
+      * No longer use return list or unconsolidated bins since
+        no scheme using them consistently outperforms those that don't
+        given above changes.
+      * Use best fit for very large chunks to prevent some worst-cases.
+      * Added some support for debugging
+
+    V2.6.0 Sat Nov  4 07:05:23 1995  Doug Lea  (dl at gee)
+      * Removed footers when chunks are in use. Thanks to
+        Paul Wilson (wilson@cs.texas.edu) for the suggestion.
+
+    V2.5.4 Wed Nov  1 07:54:51 1995  Doug Lea  (dl at gee)
+      * Added malloc_trim, with help from Wolfram Gloger
+        (wmglo@Dent.MED.Uni-Muenchen.DE).
+
+    V2.5.3 Tue Apr 26 10:16:01 1994  Doug Lea  (dl at g)
+
+    V2.5.2 Tue Apr  5 16:20:40 1994  Doug Lea  (dl at g)
+      * realloc: try to expand in both directions
+      * malloc: swap order of clean-bin strategy;
+      * realloc: only conditionally expand backwards
+      * Try not to scavenge used bins
+      * Use bin counts as a guide to preallocation
+      * Occasionally bin return list chunks in first scan
+      * Add a few optimizations from colin@nyx10.cs.du.edu
+
+    V2.5.1 Sat Aug 14 15:40:43 1993  Doug Lea  (dl at g)
+      * faster bin computation & slightly different binning
+      * merged all consolidations to one part of malloc proper
+         (eliminating old malloc_find_space & malloc_clean_bin)
+      * Scan 2 returns chunks (not just 1)
+      * Propagate failure in realloc if malloc returns 0
+      * Add stuff to allow compilation on non-ANSI compilers
+          from kpv@research.att.com
+
+    V2.5 Sat Aug  7 07:41:59 1993  Doug Lea  (dl at g.oswego.edu)
+      * removed potential for odd address access in prev_chunk
+      * removed dependency on getpagesize.h
+      * misc cosmetics and a bit more internal documentation
+      * anticosmetics: mangled names in macros to evade debugger strangeness
+      * tested on sparc, hp-700, dec-mips, rs6000
+          with gcc & native cc (hp, dec only) allowing
+          Detlefs & Zorn comparison study (in SIGPLAN Notices.)
+
+    Trial version Fri Aug 28 13:14:29 1992  Doug Lea  (dl at g.oswego.edu)
+      * Based loosely on libg++-1.2X malloc. (It retains some of the overall
+         structure of old version,  but most details differ.)
+
+*/
diff --git a/lib/excpt.nim b/lib/excpt.nim
index ae057cc97..8adb3d5a9 100644
--- a/lib/excpt.nim
+++ b/lib/excpt.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2006 Andreas Rumpf
+#        (c) Copyright 2008 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -35,35 +35,34 @@ proc chckNil(p: pointer) {.inline, compilerproc.}
 
 type
   PSafePoint = ptr TSafePoint
-  TSafePoint {.compilerproc.} = record
+  TSafePoint {.compilerproc, final.} = object
     prev: PSafePoint # points to next safe point ON THE STACK
     exc: ref E_Base
     status: int
     context: C_JmpBuf
 
 var
-  excHandler {.compilerproc, volatile.}: PSafePoint = nil
+  excHandler {.compilerproc.}: PSafePoint = nil
     # list of exception handlers
     # a global variable for the root of all try blocks
 
 proc reraiseException() =
-  if excHandler != nil:
+  if excHandler == nil:
     raise newException(ENoExceptionToReraise, "no exception to reraise")
   else:
     c_longjmp(excHandler.context, 1)
 
 type
   PFrame = ptr TFrame
-  TFrame {.importc, nodecl.} = record
+  TFrame {.importc, nodecl, final.} = object
     prev: PFrame
     procname: CString
     line: int # current line number
     filename: CString
     len: int  # length of slots (when not debugging always zero)
 
-  TTempFrame = record # used for recursion elimination in WriteStackTrace
-    procname: CString
-    line: int
+  TTempFrame = tuple[ # used for recursion elimination in WriteStackTrace
+    procname: CString, line: int]
 
 var
   buf: string       # cannot be allocated on the stack!
@@ -71,7 +70,7 @@ var
                     # assert, as it raises an exception and
                     # exception handler needs the buffer too
 
-  framePtr {.exportc, volatile.}: PFrame
+  framePtr {.exportc.}: PFrame
 
   tempFrames: array [0..255, TTempFrame] # cannot be allocated
                                          # on the stack!
@@ -82,8 +81,7 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
     i = 0
     total = 0
   while it != nil and i <= high(tempFrames):
-    tempFrames[i].procname = it.procname
-    tempFrames[i].line = it.line
+    tempFrames[i] = (it.procname, it.line)
     inc(i)
     inc(total)
     it = it.prev
@@ -110,10 +108,10 @@ proc rawWriteStackTrace(s: var string) =
     auxWriteStackTrace(framePtr, s)
 
 proc quitOrDebug() {.inline.} =
-  when not defined(emdb):
+  when not defined(endb):
     quit(1)
   else:
-    emdbStep() # call the debugger
+    endbStep() # call the debugger
 
 proc raiseException(e: ref E_Base, ename: CString) =
   GC_disable() # a bad thing is an error in the GC while raising an exception
@@ -122,7 +120,7 @@ proc raiseException(e: ref E_Base, ename: CString) =
     excHandler.exc = e
     c_longjmp(excHandler.context, 1)
   else:
-    if cast[pointer](buf) != nil:
+    if not isNil(buf):
       setLen(buf, 0)
       rawWriteStackTrace(buf)
       if e.msg != nil and e.msg[0] != '\0':
@@ -135,9 +133,7 @@ proc raiseException(e: ref E_Base, ename: CString) =
       add(buf, "]\n")
       writeToStdErr(buf)
     else:
-      writeToStdErr("*** FATAL ERROR *** ")
       writeToStdErr(ename)
-      writeToStdErr("\n")
     quitOrDebug()
   GC_enable()
 
@@ -147,7 +143,8 @@ var
 proc internalAssert(file: cstring, line: int, cond: bool) {.compilerproc.} =
   if not cond:
     GC_disable() # BUGFIX: `$` allocates a new string object!
-    if cast[pointer](assertBuf) != nil: # BUGFIX: when debugging the GC, assertBuf may be nil
+    if not isNil(assertBuf):
+      # BUGFIX: when debugging the GC, assertBuf may be nil
       setLen(assertBuf, 0)
       add(assertBuf, "[Assertion failure] file: ")
       add(assertBuf, file)
@@ -164,6 +161,11 @@ proc WriteStackTrace() =
   rawWriteStackTrace(s)
   writeToStdErr(s)
 
+#proc stackTraceWrapper {.noconv.} =
+#  writeStackTrace()
+
+#addQuitProc(stackTraceWrapper)
+
 var
   dbgAborting: bool # whether the debugger wants to abort
 
@@ -171,6 +173,7 @@ proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} =
   # print stack trace and quit
   var
     s = int(sig)
+  GC_disable()
   setLen(buf, 0)
   rawWriteStackTrace(buf)
 
@@ -185,6 +188,7 @@ proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} =
   else: add(buf, "unknown signal\n")
   writeToStdErr(buf)
   dbgAborting = True # play safe here...
+  GC_enable()
   quit(1) # always quit when SIGABRT
 
 proc registerSignalHandler() =
@@ -195,8 +199,8 @@ proc registerSignalHandler() =
   c_signal(SIGILL, signalHandler)
   c_signal(SIGBUS, signalHandler)
 
-registerSignalHandler() # call it in initialization section 
-# for easier debugging of the GC, this memory is only allocated after the 
+registerSignalHandler() # call it in initialization section
+# for easier debugging of the GC, this memory is only allocated after the
 # signal handlers have been registered
 new(gAssertionFailed)
 buf = newString(2048)
@@ -204,12 +208,15 @@ assertBuf = newString(2048)
 setLen(buf, 0)
 setLen(assertBuf, 0)
 
-proc raiseRangeError() {.compilerproc, noreturn.} =
-  raise newException(EOutOfRange, "value out of range")
+proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn.} =
+  raise newException(EOutOfRange, "value " & $val & " out of range")
 
 proc raiseIndexError() {.compilerproc, noreturn.} =
   raise newException(EInvalidIndex, "index out of bounds")
 
+proc raiseFieldError(f: string) {.compilerproc, noreturn.} =
+  raise newException(EInvalidField, f & " is not accessible")
+
 proc chckIndx(i, a, b: int): int =
   if i >= a and i <= b:
     return i
@@ -220,19 +227,19 @@ proc chckRange(i, a, b: int): int =
   if i >= a and i <= b:
     return i
   else:
-    raiseRangeError()
+    raiseRangeError(i)
 
 proc chckRange64(i, a, b: int64): int64 {.compilerproc.} =
   if i >= a and i <= b:
     return i
   else:
-    raiseRangeError()
+    raiseRangeError(i)
 
 proc chckRangeF(x, a, b: float): float =
   if x >= a and x <= b:
     return x
   else:
-    raiseRangeError()
+    raise newException(EOutOfRange, "value " & $x & " out of range")
 
 proc chckNil(p: pointer) =
   if p == nil: c_raise(SIGSEGV)
diff --git a/lib/gc.nim b/lib/gc.nim
index 570c484e6..72a287064 100644
--- a/lib/gc.nim
+++ b/lib/gc.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2006 Andreas Rumpf
+#        (c) Copyright 2008 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -13,33 +13,39 @@
 # For a description of the algorithms used here see:
 # intern.html
 
-#{.define: debugGC.}   # we wish to debug the GC...
+{.define: debugGC.}   # we wish to debug the GC...
 
 #when defined(debugGC):
 #  {.define: logGC.} # define if the GC should log some of its activities
 
 {.define: cycleGC.}
 
+const
+  traceGC = false # extensive debugging
+  reallyDealloc = true # for debugging purposes this can be set to false
+
 # 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!
 const
-  PageSize = 1024 * sizeof(int)
-  RC_Increase = 7 * PageSize # is an additive increase
+  PageShift = if sizeof(pointer) == 4: 12 else: 13
+  PageSize = 1 shl PageShift # on 32 bit systems 4096
   CycleIncrease = 2 # is a multiplicative increase
 
+  InitialCycleThreshold = 8*1024*1024 # X MB because cycle checking is slow
+  ZctThreshold = 512  # we collect garbage if the ZCT's size
+                      # reaches this threshold
+                      # this needs benchmarking...
+
 when defined(debugGC):
-  const InitialThreshold = 64*1024
-  const stressGC = True    # GC is debugged; no need to stress it
+  const stressGC = False
 else:
   const stressGC = False
-  const InitialThreshold = RC_Increase
-  # this may need benchmarking...
 
 # things the System module thinks should be available:
 when defined(useDL) or defined(nativeDL):
   type
-    TMallocInfo {.importc: "struct mallinfo", nodecl.} = record
+    TMallocInfo {.importc: "struct mallinfo", nodecl, final.} = object
       arena: cint    # non-mmapped space allocated from system
       ordblks: cint  # number of free chunks
       smblks: cint   # number of fastbin blocks
@@ -68,8 +74,7 @@ else: # not available:
   proc getTotalMem(): int = return -1
 
 var
-  rcThreshold: int = InitialThreshold
-  cycleThreshold: int = InitialThreshold
+  cycleThreshold: int = InitialCycleThreshold
 
   memUsed: int = 0 # we have to keep track how much we have allocated
 
@@ -113,11 +118,12 @@ type
     waNone, waRelease, waZctDecRef, waCycleDecRef, waCycleIncRef, waDebugIncRef
 
   TCollectorData = int
-  TCell = record
+  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
+    when stressGC:
+      stackcount: int           # stack counter for debugging
+      drefc: int                # real reference counter for debugging
 
   PCell = ptr TCell
 
@@ -145,6 +151,7 @@ proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
 
 proc internRefcount(p: pointer): int {.exportc: "getRefcount".} =
   result = int(usrToCell(p).refcount)
+  if result < 0: result = 0
 
 proc gcAlloc(size: int): pointer =
   result = alloc0(size)
@@ -162,7 +169,7 @@ proc GC_setStrategy(strategy: TGC_Strategy) =
   of gcOptimizeTime: nil
 
 proc GC_enableMarkAndSweep() =
-  cycleThreshold = InitialThreshold
+  cycleThreshold = InitialCycleThreshold
 
 proc GC_disableMarkAndSweep() =
   cycleThreshold = high(cycleThreshold)-1
@@ -174,7 +181,7 @@ proc nextTry(h, maxHash: int): int {.inline.} =
   # generates each int in range(maxHash) exactly once (see any text on
   # random-number generation for proof).
 
-# ------------------ Zero count table (ZCT) and any table (AT) -------------
+# ------------------ Any table (AT) -------------
 
 # these values are for DL-malloc known for sure (and other allocators
 # can only be worse):
@@ -200,8 +207,7 @@ when BitsPerPage mod BitsPerUnit != 0:
 
 # ------------------- 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.
+# 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
@@ -217,17 +223,59 @@ type
 
   TBitIndex = range[0..UnitsPerPage-1]
 
-  TPageDesc = record
+  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 = record
+  TCellSet {.final.} = object
     counter, max: int
     head: PPageDesc
     data: PPageDescArray
 
+  PCellArray = ptr array[0..100_000_000, PCell]
+  TCellSeq {.final.} = object
+    len, cap: int
+    d: PCellArray
+
+  TSlowSet {.final.} = object  # used for debugging purposes only
+    L: int # current length
+    cap: int # capacity
+    d: PCellArray
+
+  TGcHeap {.final.} = object # this contains the zero count and
+                             # non-zero count table
+    mask: TAddress           # mask for fast pointer detection
+    zct: TCellSeq            # the zero count table
+    at: TCellSet             # a table that contains all references
+    newAT: TCellSet
+    stackCells: TCellSeq     # cells that need to be decremented because they
+                             # are in the hardware stack; a cell may occur
+                             # several times in this data structure
+
+var
+  stackBottom: pointer
+  gch: TGcHeap
+
+proc add(s: var TCellSeq, c: PCell) {.inline.} =
+  if s.len >= s.cap:
+    s.cap = s.cap * 3 div 2
+    s.d = cast[PCellArray](realloc(s.d, s.cap * sizeof(PCell)))
+    if s.d == nil: raiseOutOfMem()
+  s.d[s.len] = c
+  inc(s.len)
+
+proc inOperator(s: TCellSeq, c: PCell): bool {.inline.} =
+  for i in 0 .. s.len-1:
+    if s.d[i] == c: return True
+  return False
+
+proc init(s: var TCellSeq, cap: int = 1024) =
+  s.len = 0
+  s.cap = cap
+  s.d = cast[PCellArray](gcAlloc(cap * sizeof(PCell)))
+
 const
   InitCellSetSize = 1024 # must be a power of two!
 
@@ -284,7 +332,8 @@ proc CellSetPut(t: var TCellSet, key: TAddress): PPageDesc =
     if x.key == key: return x
     h = nextTry(h, t.max)
 
-  if (t.max+1) * 2 < t.counter * 3: CellSetEnlarge(t)
+  if ((t.max+1)*2 < t.counter*3) or ((t.max+1)-t.counter < 4):
+    CellSetEnlarge(t)
   inc(t.counter)
   h = cast[int](key) and t.max
   while t.data[h] != nil: h = nextTry(h, t.max)
@@ -303,7 +352,7 @@ proc in_Operator(s: TCellSet, cell: PCell): bool =
     u: TAddress
     t: PPageDesc
   u = cast[TAddress](cell)
-  t = CellSetGet(s, u /% PageSize)
+  t = CellSetGet(s, u shr PageShift)
   if t != nil:
     u = (u %% PageSize) /% MemAlignment
     result = (t.bits[u /% BitsPerUnit] and (1 shl (u %% BitsPerUnit))) != 0
@@ -315,7 +364,7 @@ proc incl(s: var TCellSet, cell: PCell) =
     u: TAddress
     t: PPageDesc
   u = cast[TAddress](cell)
-  t = CellSetPut(s, u /% PageSize)
+  t = CellSetPut(s, u shr PageShift)
   u = (u %% PageSize) /% MemAlignment
   t.bits[u /% BitsPerUnit] = t.bits[u /% BitsPerUnit] or
     (1 shl (u %% BitsPerUnit))
@@ -325,7 +374,7 @@ proc excl(s: var TCellSet, cell: PCell) =
     u: TAddress
     t: PPageDesc
   u = cast[TAddress](cell)
-  t = CellSetGet(s, u /% PageSize)
+  t = CellSetGet(s, u shr PageShift)
   if t != nil:
     u = (u %% PageSize) /% MemAlignment
     t.bits[u /% BitsPerUnit] = (t.bits[u /% BitsPerUnit] and
@@ -342,7 +391,7 @@ iterator elements(t: TCellSet): PCell {.inline.} =
       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) +%
+          yield cast[PCell]((r.key shl PageShift) or # +%
                               (i*%BitsPerUnit+%j) *% MemAlignment)
         inc(j)
         w = w shr 1
@@ -354,68 +403,121 @@ iterator elements(t: TCellSet): PCell {.inline.} =
 proc testPageDescs() =
   var root: TCellSet
   CellSetInit(root)
-  var u = 10_000
-  while u <= 20_000:
-    incl(root, cast[PCell](u))
-    inc(u, 8)
+  #var u = 10_000
+  #while u <= 20_000:
+  #  incl(root, cast[PCell](u))
+  #  inc(u, 8)
+
+  incl(root, cast[PCell](0x81cdfb8))
   for cell in elements(root):
-    c_fprintf(c_stdout, "%ld\n", cast[int](cell))
+    c_fprintf(c_stdout, "%p\n", cast[int](cell))
 
-# testPageDescs()
+#testPageDescs()
 
 when defined(debugGC):
   proc writeCell(msg: CString, c: PCell) =
-    c_fprintf(c_stdout, "%s: %p\n", msg, c)
+    if c.typ != nil:
+      if c.typ.kind == tyString:
+        c_fprintf(c_stdout, "%s\n", cast[TAddress](cellToUsr(c)) + sizeof(int)*2)
+      c_fprintf(c_stdout, "%s: %p %d\n", msg, c, c.typ.kind)
+    else: c_fprintf(c_stdout, "%s: %p (nil type)\n", msg, c)
   proc writePtr(msg: CString, p: Pointer) =
     c_fprintf(c_stdout, "%s: %p\n", msg, p)
 
-# -------------------------------------------------------------------------
 
-type
-  PStackCells = ptr array[0..1000_0000, PCell]
-  TCountTables = record     # this contains the zero count and
-                            # non-zero count table
-    mask: TAddress          # mask for fast pointer detection
-    zct: TCellSet           # the zero count table
-    at: TCellSet            # a table that contains all references
-    newAT: TCellSet
-    newZCT: TCellSet
-    stackCells: PStackCells # cells that need to be decremented because they
-                            # are in the hardware stack; a cell may occur
-                            # several times in this data structure
-    stackLen, stackMax: int # for managing the stack cells
-
-proc addStackCell(ct: var TCountTables, cell: PCell) =
-  if ct.stackLen >= ct.stackMax:
-    ct.stackMax = ct.stackMax * 3 div 2
-    ct.stackCells = cast[PStackCells](realloc(ct.stackCells, ct.stackMax *
-                                      sizeof(PCell)))
-    if ct.stackCells == nil: raiseOutOfMem()
-  ct.stackCells[ct.stackLen] = cell
-  inc(ct.stackLen)
+when traceGC:
+  # traceGC is a special switch to enable extensive debugging
+  type
+    TCellState = enum
+      csAllocated, csZctFreed, csCycFreed
+
+  proc cellSetInit(s: var TSlowSet) =
+    s.L = 0
+    s.cap = 4096
+    s.d = cast[PCellArray](gcAlloc(s.cap * sizeof(PCell)))
+
+  proc cellSetDeinit(s: var TSlowSet) =
+    s.L = 0
+    s.cap = 0
+    dealloc(s.d)
+
+  proc incl(s: var TSlowSet, c: PCell) =
+    if s.L >= s.cap:
+      s.cap = s.cap * 3 div 2
+      s.d = cast[PCellArray](realloc(s.d, s.cap * sizeof(PCell)))
+      if s.d == nil: raiseOutOfMem()
+    s.d[s.L] = c
+    inc(s.L)
+
+  proc excl(s: var TSlowSet, c: PCell) =
+    var i = 0
+    while i < s.L:
+      if s.d[i] == c:
+        s.d[i] = s.d[s.L-1]
+        dec(s.L)
+        break
+      inc(i)
 
-var
-  stackBottom: pointer
-  ct: TCountTables
+  proc inOperator(s: TSlowSet, c: PCell): bool =
+    var i = 0
+    while i < s.L:
+      if s.d[i] == c: return true
+      inc(i)
 
-proc GC_invariant(): bool =
-  result = True
-  when stressGC:
-    if recGcLock == 0:
-      GC_disable()
-      for cell in elements(ct.at):
-        var t = cell.typ # getCellType(cell)
-        if t == nil or t.kind notin {tySequence, tyString, tyRef}:
-          writeCell("corrupt cell?", cell)
-          result = false
-      GC_enable()
+  iterator elements(s: TSlowSet): PCell =
+    var i = 0
+    while i < s.L:
+      yield s.d[i]
+      inc(i)
 
-when stressGC:
-  proc GCdebugHook() =
-    if not GC_invariant():
-      assert(false)
+  var
+    states: array[TCellState, TSlowSet] # TCellSet]
+
+  proc traceCell(c: PCell, state: TCellState) =
+    case state
+    of csAllocated:
+      if c in states[csAllocated]:
+        writeCell("attempt to alloc a already allocated cell", c)
+        assert(false)
+      excl(states[csCycFreed], c)
+      excl(states[csZctFreed], c)
+    of csZctFreed:
+      if c notin states[csAllocated]:
+        writeCell("attempt to free a not allocated cell", c)
+        assert(false)
+      if c in states[csZctFreed]:
+        writeCell("attempt to free zct cell twice", c)
+        assert(false)
+      if c in states[csCycFreed]:
+        writeCell("attempt to free with zct, but already freed with cyc", c)
+        assert(false)
+      excl(states[csAllocated], c)
+    of csCycFreed:
+      if c notin states[csAllocated]:
+        writeCell("attempt to free a not allocated cell", c)
+        assert(false)
+      if c in states[csCycFreed]:
+        writeCell("attempt to free cyc cell twice", c)
+        assert(false)
+      if c in states[csZctFreed]:
+        writeCell("attempt to free with cyc, but already freed with zct", c)
+        assert(false)
+      excl(states[csAllocated], c)
+    incl(states[state], c)
+
+template gcTrace(cell, state: expr): stmt =
+  when traceGC: traceCell(cell, state)
 
-  dbgLineHook = GCdebugHook
+# -------------------------------------------------------------------------
+
+# forward declarations:
+proc collectCT(gch: var TGcHeap)
+proc IsOnStack(p: pointer): bool
+proc forAllChildren(cell: PCell, op: TWalkOp)
+proc collectCycles(gch: var TGcHeap)
+
+proc reprAny(p: pointer, typ: PNimType): string {.compilerproc.}
+# we need the prototype here for debugging purposes
 
 proc prepareDealloc(cell: PCell) =
   if cell.typ.finalizer != nil:
@@ -433,79 +535,95 @@ proc prepareDealloc(cell: PCell) =
   else:
     memUsed = memUsed - cell.typ.size
 
-proc setStackBottom(theStackBottom: pointer) {.compilerproc.} =
-  stackBottom = theStackBottom
-
-proc initGC() =
-  # init the rt
-  CellSetInit(ct.zct)
-  CellSetInit(ct.at)
-  ct.stackLen = 0
-  ct.stackMax = 255
-  ct.stackCells = cast[PStackCells](gcAlloc((ct.stackMax+1) * sizeof(PCell)))
-  ct.mask = 0
-  new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
-  assert(GC_invariant())
-
-# forward declarations:
-proc collectCT(ct: var TCountTables)
-proc IsOnStack(p: pointer): bool
-proc forAllChildren(cell: PCell, op: TWalkOp)
-proc collectCycles()
-
-proc reprAny(p: pointer, typ: PNimType): string {.compilerproc.}
-# we need the prototype here for debugging purposes
-
-proc outputCell(c: PCell) =
+proc checkZCT(): bool =
+  if recGcLock >= 1: return true # prevent endless recursion
   inc(recGcLock)
-  write(stdout, reprAny(cellToUsr(c), c.typ))
+  result = true
+  for i in 0..gch.zct.len-1:
+    var c = gch.zct.d[i]
+    if c.refcount > 0: # should be in the ZCT!
+      writeCell("wrong ZCT entry", c)
+      result = false
+    elif gch.zct.d[-c.refcount] != c:
+      writeCell("wrong ZCT position", c)
+      result = false
   dec(recGcLock)
 
-proc writeGraph() =
-  {.checkpoint.}
-  block:
-    inc(recGcLock)
-    for c in elements(ct.AT): outputCell(c)
-    dec(recGcLock)
-
-proc checkRefc(): bool =
+proc GC_invariant(): bool =
   if recGcLock >= 1: return true # prevent endless recursion
   inc(recGcLock)
   result = True
-  # set counters back to zero:
-  for c in elements(ct.AT):
-    c.drefc = 0
-  for c in elements(ct.AT):
-    forAllChildren(c, waDebugIncRef)
-  for c in elements(ct.AT):
-    if c.drefc > c.refcount - c.stackcount:
-      result = false # failed
-      c_fprintf(c_stdout,
-         "broken cell: %p, refc: %ld, stack: %ld, real: %ld\n",
-         c, c.refcount, c.stackcount, c.drefc)
+  block checks:
+    if not checkZCT():
+      result = false
+      break checks
+    # set counters back to zero:
+    for c in elements(gch.AT):
+      var t = c.typ
+      if t == nil or t.kind notin {tySequence, tyString, tyRef}:
+        writeCell("corrupt cell?", c)
+        result = false
+        break checks
+      when stressGC: c.drefc = 0
+    for c in elements(gch.AT):
+      forAllChildren(c, waDebugIncRef)
+    when stressGC:
+      for c in elements(gch.AT):
+        var rc = c.refcount
+        if rc < 0: rc = 0
+        if c.drefc > rc + c.stackcount:
+          result = false # failed
+          c_fprintf(c_stdout,
+             "broken cell: %p, refc: %ld, stack: %ld, real: %ld\n",
+             c, c.refcount, c.stackcount, c.drefc)
+          break checks
   dec(recGcLock)
 
-proc seqCheck(cell: PCell): bool =
-  assert(cell.typ != nil)
-  if cell.typ.kind in {tySequence, tyString}:
-    result = cell.refcount - cell.stackcount <= 1
-  else:
-    result = true
+when stressGC:
+  proc GCdebugHook() =
+    if not GC_invariant():
+      assert(false)
+
+  dbgLineHook = GCdebugHook
+
+proc setStackBottom(theStackBottom: pointer) {.compilerproc.} =
+  stackBottom = theStackBottom
+
+proc initGC() =
+  when traceGC:
+    for i in low(TCellState)..high(TCellState): CellSetInit(states[i])
+  # init the rt
+  init(gch.zct)
+  CellSetInit(gch.at)
+  init(gch.stackCells)
+  gch.mask = 0
+  new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
+  assert(GC_invariant())
 
 proc decRef(cell: PCell) {.inline.} =
-  assert(cell in ct.AT)
-  when defined(debugGC):
-    if cell.refcount == 0:
-      writePtr("decref broken", cellToUsr(cell))
   assert(cell.refcount > 0) # this should be the case!
-  assert(seqCheck(cell))
+  when stressGC: assert(cell in gch.AT)
   dec(cell.refcount)
   if cell.refcount == 0:
-    incl(ct.zct, cell)
+    cell.refcount = -gch.zct.len
+    when stressGC: assert(cell notin gch.zct)
+    add(gch.zct, cell)
+  when stressGC: assert(checkZCT())
 
 proc incRef(cell: PCell) {.inline.} =
-  assert(seqCheck(cell))
-  inc(cell.refcount)
+  var rc = cell.refcount
+  if rc <= 0:
+    # remove from zero count table:
+    when stressGC: assert(gch.zct.len > -rc)
+    when stressGC: assert(gch.zct.d[-rc] == cell)
+    gch.zct.d[-rc] = gch.zct.d[gch.zct.len-1]
+    gch.zct.d[-rc].refcount = rc
+    dec(gch.zct.len)
+    cell.refcount = 1
+    when stressGC: assert(checkZCT())
+  else:
+    inc(cell.refcount)
+    when stressGC: assert(checkZCT())
 
 proc asgnRef(dest: ppointer, src: pointer) =
   # the code generator calls this proc!
@@ -514,18 +632,18 @@ proc asgnRef(dest: ppointer, src: pointer) =
   if src != nil: incRef(usrToCell(src))
   if dest^ != nil: decRef(usrToCell(dest^))
   dest^ = src
-  #assert(checkRefc())
+  when stressGC: assert(GC_invariant())
 
 proc unsureAsgnRef(dest: ppointer, src: pointer) =
   if not IsOnStack(dest):
     if src != nil: incRef(usrToCell(src))
     if dest^ != nil: decRef(usrToCell(dest^))
   dest^ = src
-  #assert(checkRefc())
+  when stressGC: assert(GC_invariant())
 
 proc restore(cell: PCell) =
-  if cell notin ct.newAT:
-    incl(ct.newAT, Cell)
+  if cell notin gch.newAT:
+    incl(gch.newAT, Cell)
     forAllChildren(cell, waCycleIncRef)
 
 proc doOperation(p: pointer, op: TWalkOp) =
@@ -536,19 +654,15 @@ proc doOperation(p: pointer, op: TWalkOp) =
   of waNone: assert(false)
   of waRelease: decRef(cell) # DEAD CODE!
   of waZctDecRef:
-    assert(cell.refcount > 0)
-    assert(seqCheck(cell))
-    dec(cell.refcount)
-    if cell.refcount == 0:
-      incl(ct.newZCT, cell)
+    decRef(cell)
   of waCycleDecRef:
-    assert(cell.refcount != 0)
+    assert(cell.refcount > 0)
     dec(cell.refcount)
   of waCycleIncRef:
     inc(cell.refcount) # restore proper reference counts!
     restore(cell)
   of waDebugIncRef:
-    inc(cell.drefc)
+    when stressGC: inc(cell.drefc)
 
 type
   TByteArray = array[0..1000_0000, byte]
@@ -590,16 +704,20 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
     if m != nil: forAllSlotsAux(dest, m, op)
 
 proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp) =
+  const
+    handledTypes = {tyArray, tyArrayConstr, tyOpenArray, tyRef,
+                    tyString, tySequence, tyObject, tyPureObject, tyTuple}
   var
     d = cast[TAddress](dest)
   if dest == nil: return # nothing to do
   case mt.Kind
   of tyArray, tyArrayConstr, tyOpenArray:
-    for i in 0..(mt.size div mt.base.size)-1:
-      forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
+    if mt.base.kind in handledTypes:
+      for i in 0..(mt.size div mt.base.size)-1:
+        forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
   of tyRef, tyString, tySequence: # leaf:
     doOperation(cast[ppointer](d)^, op)
-  of tyRecord, tyObject, tyTuple:
+  of tyObject, tyTuple, tyPureObject:
     forAllSlotsAux(dest, mt.node, op)
   else: nil
 
@@ -608,6 +726,13 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
   when defined(debugGC):
     if cell.typ == nil:
       writeCell("cell has no type descriptor", cell)
+      when traceGC:
+        if cell notin states[csAllocated]:
+          writeCell("cell has never been allocated!", cell)
+        if cell in states[csCycFreed]:
+          writeCell("cell has been freed by Cyc", cell)
+        if cell in states[csZctFreed]:
+          writeCell("cell has been freed by Zct", cell)
   assert(cell.typ != nil)
   case cell.typ.Kind
   of tyRef: # common case
@@ -625,36 +750,36 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
 proc checkCollection() {.inline.} =
   # checks if a collection should be done
   if recGcLock == 0:
-    if memUsed >= rcThreshold or stressGC:
-      collectCT(ct)
-      when defined(debugGC):
-        write(stdout, "threshold is now: ")
-        writeln(stdout, rcThreshold)
+    collectCT(gch)
 
 proc newObj(typ: PNimType, size: int): pointer =
   # generates a new object and sets its reference counter to 0
   var
     res: PCell
+  when stressGC: assert(checkZCT())
   assert(typ.kind in {tyRef, tyString, tySequence})
   # check if we have to collect:
   checkCollection()
   res = cast[PCell](Alloc0(size + sizeof(TCell)))
+  when stressGC: assert((cast[TAddress](res) and (MemAlignment-1)) == 0)
   if res == nil: raiseOutOfMem()
   when defined(nimSize):
     memUsed = memUsed + nimSize(res)
   else:
     memUsed = memUsed + size
 
-  res.refcount = 0
   # now it is buffered in the ZCT
   res.typ = typ
-  incl(ct.zct, res) # its refcount is zero, so add it to the ZCT
-  incl(ct.at, res)  # add it to the any table too
-  ct.mask = ct.mask or cast[TAddress](res)
+  res.refcount = -gch.zct.len
+  add(gch.zct, res)  # its refcount is zero, so add it to the ZCT
+  incl(gch.at, res)  # add it to the any table too
+  gch.mask = gch.mask or cast[TAddress](res)
   when defined(debugGC):
-    writeCell("new cell", res)
-    assert(gcInvariant())
+    when defined(logGC): writeCell("new cell", res)
+  gcTrace(res, csAllocated)
   result = cellToUsr(res)
+  assert(res.typ == typ)
+  when stressGC: assert(checkZCT())
 
 proc newSeq(typ: PNimType, len: int): pointer =
   # XXX: overflow checks!
@@ -665,16 +790,19 @@ proc newSeq(typ: PNimType, len: int): pointer =
 proc growObj(old: pointer, newsize: int): pointer =
   var
     res, ol: PCell
+  when stressGC: assert(checkZCT())
   checkCollection()
   ol = usrToCell(old)
   assert(ol.typ.kind in {tyString, tySequence})
-  assert(seqCheck(ol))
   when defined(nimSize):
     memUsed = memUsed - nimSize(ol)
   else:
     memUsed = memUsed - ol.size # this is not exact
-  # pity that we don't know the old size
+                                # pity that we don't know the old size
   res = cast[PCell](realloc(ol, newsize + sizeof(TCell)))
+  #res = cast[PCell](gcAlloc(newsize + sizeof(TCell)))
+  #copyMem(res, ol, nimSize(ol))
+  assert((cast[TAddress](res) and (MemAlignment-1)) == 0)
   when defined(nimSize):
     memUsed = memUsed + nimSize(res)
   else:
@@ -682,74 +810,69 @@ proc growObj(old: pointer, newsize: int): pointer =
 
   if res != ol:
     if res == nil: raiseOutOfMem()
-    excl(ct.zct, ol) # remove old pointer in any case:
-    # It may have a refcount > 0 and is still in the ZCT.
-    # So do it safe here and remove it anyway.
-    excl(ct.at, ol)
-    if res.refcount == 0:
-      # store new pointer in ZCT, if refcount == 0:
-      incl(ct.zct, res)
-    incl(ct.at, res)
-    ct.mask = ct.mask or cast[TAddress](res)
-    when defined(debugGC):
+    if res.refcount <= 0:
+      assert(gch.zct.d[-res.refcount] == ol)
+      gch.zct.d[-res.refcount] = res
+    excl(gch.at, ol)
+    incl(gch.at, res)
+    gch.mask = gch.mask or cast[TAddress](res)
+    when defined(logGC):
       writeCell("growObj old cell", ol)
       writeCell("growObj new cell", res)
+    gcTrace(ol, csZctFreed)
+    gcTrace(res, csAllocated)
   result = cellToUsr(res)
-  #assert(checkRefc())
+  when stressGC: assert(checkZCT())
 
-proc collectCycles() =
-  when defined(debugGC):
-    echo("collecting cycles!\n")
+proc collectCycles(gch: var TGcHeap) =
+  when defined(logGC):
+    c_fprintf(c_stdout, "collecting cycles!\n")
 
   # step 1: pretend that any node is dead
-  for c in elements(ct.at):
+  for c in elements(gch.at):
     forallChildren(c, waCycleDecRef)
-  CellSetInit(ct.newAt)
+  CellSetInit(gch.newAt)
   # step 2: restore life cells
-  for c in elements(ct.at):
+  for c in elements(gch.at):
     if c.refcount > 0: restore(c)
   # step 3: free dead cells:
-  for cell in elements(ct.at):
+  for cell in elements(gch.at):
     if cell.refcount == 0:
-      assert(cell notin ct.zct)
       # We free an object that is part of a cycle here. Its children
       # may have been freed already. Thus the finalizer could access
       # garbage. To handle this case properly we need two passes for
       # freeing here which is too expensive. We just don't call the
       # finalizer for now. YYY: Any better ideas?
       prepareDealloc(cell)
-      dealloc(cell)
-      when defined(debugGC):
+      gcTrace(cell, csCycFreed)
+      when defined(logGC):
         writeCell("cycle collector dealloc cell", cell)
-  CellSetDeinit(ct.at)
-  ct.at = ct.newAt
-  #ct.newAt = nil
+      when reallyDealloc: dealloc(cell)
+  CellSetDeinit(gch.at)
+  gch.at = gch.newAt
 
-proc gcMark(p: pointer) =
+proc gcMark(gch: var TGcHeap, p: pointer) =
   # 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 ct.mask) == c) and cell in ct.at:
+  if ((c and gch.mask) == c) and cell in gch.at:
     # is the page that p "points to" in the AT? (All allocated pages are
     # always in the AT)
-    inc(cell.refcount)
-    inc(cell.stackcount)
-    addStackCell(ct, cell)
-
-proc unmarkStackAndRegisters() =
-  for i in 0 .. ct.stackLen-1:
-    var cell = ct.stackCells[i]
+    incRef(cell)
+    when stressGC: inc(cell.stackcount)
+    add(gch.stackCells, cell)
+
+proc unmarkStackAndRegisters(gch: var TGcHeap) =
+  when stressGC: assert(checkZCT())
+  for i in 0 .. gch.stackCells.len-1:
+    var cell = gch.stackCells.d[i]
     assert(cell.refcount > 0)
-    when defined(debugGC):
-      if cell.stackcount == 0:
-        writeGraph()
-        writePtr("broken stackcount", cellToUsr(cell))
-    assert(cell.stackcount > 0)
-    dec(cell.refcount)
-    dec(cell.stackcount)
-    if cell.refcount == 0:
-      incl(ct.zct, cell)
-  ct.stackLen = 0 # reset to zero
+    when stressGC:
+      assert(cell.stackcount > 0)
+      dec(cell.stackcount)
+    decRef(cell)
+  gch.stackCells.len = 0 # reset to zero
+  when stressGC: assert(checkZCT())
 
 # ----------------- stack management --------------------------------------
 #  inspired from Smart Eiffel (c)
@@ -765,7 +888,7 @@ when defined(sparc): # For SPARC architecture.
       stackTop: array[0..1, pointer]
     result = p >= addr(stackTop[0]) and p <= stackBottom
 
-  proc markStackAndRegisters() =
+  proc markStackAndRegisters(gch: var TGcHeap) =
     when defined(sparcv9):
       asm  " flushw"
     else:
@@ -780,7 +903,7 @@ when defined(sparc): # For SPARC architecture.
     sp = addr(stackTop[0])
     # Addresses decrease as the stack grows.
     while sp <= max:
-      gcMark(sp^)
+      gcMark(gch, sp^)
       sp = cast[ppointer](cast[TAddress](sp) +% sizeof(pointer))
 
 elif defined(ELATE):
@@ -802,7 +925,7 @@ elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or
       # a little hack to get the size of a TJmpBuf in the generated C code
       # in a platform independant way
 
-  proc markStackAndRegisters() =
+  proc markStackAndRegisters(gch: var TGcHeap) =
     var
       max = stackBottom
       registers: C_JmpBuf # The jmp_buf buffer is in the C stack.
@@ -814,7 +937,7 @@ elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or
     # sp will traverse the JMP_BUF as well (jmp_buf size is added,
     # otherwise sp would be below the registers structure).
     while sp >= max:
-      gcMark(sp^)
+      gcMark(gch, sp^)
       sp = cast[ppointer](cast[TAddress](sp) -% sizeof(pointer))
 
 else:
@@ -826,7 +949,7 @@ else:
       stackTop: array [0..1, pointer]
     result = p >= addr(stackTop[0]) and p <= stackBottom
 
-  proc markStackAndRegisters() =
+  proc markStackAndRegisters(gch: var TGcHeap) =
     var
       max = stackBottom
       registers: C_JmpBuf # The jmp_buf buffer is in the C stack.
@@ -835,63 +958,58 @@ else:
     c_setjmp(registers)   # To fill the C stack with registers.
     sp = cast[ppointer](addr(registers))
     while sp <= max:
-      gcMark(sp^)
+      gcMark(gch, sp^)
       sp = cast[ppointer](cast[TAddress](sp) +% sizeof(pointer))
 
 # ----------------------------------------------------------------------------
 # end of non-portable code
 # ----------------------------------------------------------------------------
 
-proc CollectZCT =
-  CellSetInit(ct.newZCT)
-  for c in elements(ct.zct):
-    if c.refcount == 0:
-      # if != 0 the reference count has been increased, so this does not
-      # belong to the ZCT. We simply do nothing - it won't appear in the newZCT
-      # anyway.
-      # We are about to free the object, call the finalizer BEFORE its
-      # children are deleted as well, because otherwise the finalizer may
-      # access invalid memory. This is done by prepareDealloc():
-      prepareDealloc(c)
-      forAllChildren(c, waZctDecRef)
-      assert(c.refcount == 0) # should still be zero
-      excl(ct.at, c)
-      excl(ct.newZCT, c) # BUGFIX
-      when defined(debugGC):
-        writeCell("zct dealloc cell", c)
-      dealloc(c)
-  CellSetDeinit(ct.zct)
-  ct.zct = ct.newZCT
-  #ct.newZCT = nil
-
-proc collectCT(ct: var TCountTables) =
-  when defined(debugGC):
+proc CollectZCT(gch: var TGcHeap) =
+  while gch.zct.len > 0:
+    var c = gch.zct.d[0]
+    assert(c.refcount <= 0)
+    # remove from ZCT:
+    gch.zct.d[0] = gch.zct.d[gch.zct.len-1]
+    gch.zct.d[0].refcount = 0
+    dec(gch.zct.len)
+    # We are about to free the object, call the finalizer BEFORE its
+    # children are deleted as well, because otherwise the finalizer may
+    # access invalid memory. This is done by prepareDealloc():
+    gcTrace(c, csZctFreed)
+    prepareDealloc(c)
+    forAllChildren(c, waZctDecRef)
+    excl(gch.at, c)
+    when defined(logGC):
+      writeCell("zct dealloc cell", c)
+    #when defined(debugGC) and defined(nimSize): zeroMem(c, nimSize(c))
+    when reallyDealloc: dealloc(c)
+
+proc collectCT(gch: var TGcHeap) =
+  when defined(logGC):
     c_fprintf(c_stdout, "collecting zero count table; stack size: %ld\n",
               stackSize())
-  markStackAndRegisters()
-  assert(GC_invariant())
-  while True:
-    collectZCT()
-    if ct.zct.counter == 0: break
-    # ``counter`` counts the pages, but zero pages means zero cells
-
-  when defined(cycleGC):
-    # still over the cycle threshold?
-    if memUsed >= cycleThreshold or stressGC:
-      # collect the cyclic things:
-      assert(ct.zct.counter == 0)
-      assert(GC_invariant())
-      collectCycles()
-
-  # recompute the thresholds:
-  rcThreshold = (memUsed div RC_increase + 1) * RC_Increase
-  cycleThreshold = memUsed * cycleIncrease
-
-  assert(GC_invariant())
-  unmarkStackAndRegisters()
+  when stressGC: assert(checkZCT())
+  if gch.zct.len >= ZctThreshold or memUsed >= cycleThreshold or stressGC:
+    markStackAndRegisters(gch)
+    when stressGC: assert(GC_invariant())
+    collectZCT(gch)
+    when stressGC: assert(GC_invariant())
+    assert(gch.zct.len == 0)
+    when defined(cycleGC):
+      if memUsed >= cycleThreshold or stressGC:
+        when defined(logGC):
+          c_fprintf(c_stdout, "collecting cycles; memory used: %ld\n", memUsed)
+        collectCycles(gch)
+        cycleThreshold = max(InitialCycleThreshold, memUsed * cycleIncrease)
+        when defined(logGC):
+          c_fprintf(c_stdout, "now used: %ld; threshold: %ld\n",
+                    memUsed, cycleThreshold)
+    unmarkStackAndRegisters(gch)
+  when stressGC: assert(GC_invariant())
 
 proc GC_fullCollect() =
   var oldThreshold = cycleThreshold
   cycleThreshold = 0 # forces cycle collection
-  collectCT(ct)
+  collectCT(gch)
   cycleThreshold = oldThreshold
diff --git a/lib/hti.nim b/lib/hti.nim
index 8fc46cdd7..563414b26 100644
--- a/lib/hti.nim
+++ b/lib/hti.nim
@@ -10,29 +10,38 @@
 type # This should be he same as ast.TTypeKind
      # some enum fields are not used at runtime
   TNimKind = enum
-    tyNone, tyBool, tyChar,
-    tyEmptySet, tyArrayConstr, tyNil, tyRecordConstr,
-    tyGeneric,
-    tyGenericInst,
-    tyGenericParam,
-    tyEnum, tyAnyEnum,
-    tyArray,
-    tyRecord,
-    tyObject,
-    tyTuple,
-    tySet,
-    tyRange,
-    tyPtr, tyRef,
-    tyVar,
-    tySequence,
-    tyProc,
-    tyPointer, tyOpenArray,
-    tyString, tyCString, tyForward,
+    tyNone, # 0 
+    tyBool, # 1 
+    tyChar, # 2
+    tyEmptySet, # 3
+    tyArrayConstr, # 4
+    tyNil, # 5
+    tyGeneric, # 6
+    tyGenericInst, # 7
+    tyGenericParam, # 8
+    tyEnum, # 9
+    tyAnyEnum, # 10
+    tyArray, # 11
+    tyObject, # 12 
+    tyTuple, # 13
+    tySet, # 14
+    tyRange, # 15
+    tyPtr, # 16
+    tyRef, # 17
+    tyVar, # 18
+    tySequence, # 19
+    tyProc, # 20
+    tyPointer, # 21
+    tyOpenArray, # 22
+    tyString, # 23
+    tyCString, # 24
+    tyForward, # 25
     tyInt, tyInt8, tyInt16, tyInt32, tyInt64,
-    tyFloat, tyFloat32, tyFloat64, tyFloat128
+    tyFloat, tyFloat32, tyFloat64, tyFloat128,
+    tyPureObject # 35: signals that object has no `n_type` field
 
   TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
-  TNimNode {.compilerproc.} = record
+  TNimNode {.compilerproc, final.} = object
     kind: TNimNodeKind
     offset: int
     typ: ptr TNimType
@@ -40,7 +49,7 @@ type # This should be he same as ast.TTypeKind
     len: int
     sons: ptr array [0..0x7fff, ptr TNimNode]
 
-  TNimType {.compilerproc.} = record
+  TNimType {.compilerproc, final.} = object
     size: int
     kind: TNimKind
     base: ptr TNimType
diff --git a/lib/int64s.nim b/lib/int64s.nim
index bac6b9ccd..430514ce3 100644
--- a/lib/int64s.nim
+++ b/lib/int64s.nim
@@ -10,8 +10,7 @@
 # 64 bit integers for platforms that don't have those

 

 type

-  IInt64 = record # "internal" int64

-    lo, hi: int32

+  IInt64 = tuple[lo, hi: int32]

 

 proc cmpI64(x, y: IInt64): int32 {.compilerproc.} =

   result = x.hi -% y.hi

diff --git a/lib/math.nim b/lib/math.nim
index 84cba9894..aff5815ce 100644
--- a/lib/math.nim
+++ b/lib/math.nim
@@ -1,75 +1,22 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2006 Andreas Rumpf
+#        (c) Copyright 2008 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
-
-
-# math routines
-
-# interface
+## Basic math routines for Nimrod.
+## This module is available for the ECMAScript target.
 
 {.push debugger:off .} # the user does not want to trace a part
                        # of the standard library!
 
 {.push checks:off, line_dir:off, stack_trace:off.}
 
-proc nextPowerOfTwo*(x: int): int
-  ## returns the nearest power of two, so that
-  ## result**2 >= x > (result-1)**2.
-proc isPowerOfTwo*(x: int): bool {.noSideEffect.}
-  ## returns true, if x is a power of two, false otherwise.
-  ## Negative numbers are not a power of two.
-proc countBits*(n: int32): int {.noSideEffect.}
-  ## counts the set bits in `n`.
-
-proc random*(max: int): int
-  ## returns a random number in the range 0..max-1. The sequence of
-  ## random number is always the same, unless `randomize` is called
-  ## which initializes the random number generator with a "random"
-  ## number, i.e. a tickcount.
-proc randomize*()
-  ## initializes the random number generator with a "random"
-  ## number, i.e. a tickcount.
-
-proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".}
-  ## computes the square root of `x`.
-
-proc ln*(x: float): float {.importc: "log", header: "<math.h>".}
-  ## computes ln(x).
-proc exp*(x: float): float {.importc: "exp", header: "<math.h>".}
-  ## computes e**x.
-
-proc frexp*(x: float, exponent: var int): float {.
-  importc: "frexp", header: "<math.h>".}
-  ## Split a number into mantissa and exponent.
-  ## `frexp` calculates the mantissa m (a float greater than or equal to 0.5
-  ## and less than 1) and the integer value n such that `x` (the original
-  ## float value) equals m * 2**n. frexp stores n in `exponent` and returns
-  ## m.
-
-proc arccos*(x: float): float {.importc: "acos", header: "<math.h>".}
-proc arcsin*(x: float): float {.importc: "asin", header: "<math.h>".}
-proc arctan*(x: float): float {.importc: "atan", header: "<math.h>".}
-proc arctan2*(y, x: float): float {.importc: "atan2", header: "<math.h>".}
-  ## Calculate the arc tangent of `y` / `x`.
-  ## `atan2` returns the arc tangent of `y` / `x`; it produces correct
-  ## results even when the resulting angle is near pi/2 or -pi/2
-  ## (`x` near 0).
-
-proc cos*(x: float): float {.importc: "cos", header: "<math.h>".}
-proc cosh*(x: float): float {.importc: "cosh", header: "<math.h>".}
-proc hypot*(x: float): float {.importc: "hypot", header: "<math.h>".}
-proc log10*(x: float): float {.importc: "log10", header: "<math.h>".}
-proc sinh*(x: float): float {.importc: "sinh", header: "<math.h>".}
-proc tan*(x: float): float {.importc: "tan", header: "<math.h>".}
-proc tanh*(x: float): float {.importc: "tanh", header: "<math.h>".}
-proc pow*(x, y: float): float {.importc: "pos", header: "<math.h>".}
-  ## computes x to power raised of y.
+when defined(Posix): 
+  {.passl: "-lm".}
 
 type
   TFloatClass* = enum ## describes the class a floating point value belongs to.
@@ -82,15 +29,32 @@ type
     fcInf,       ## value is positive infinity
     fcNegInf     ## value is negative infinity
 
-proc classify*(x: float): TFloatClass
+proc classify*(x: float): TFloatClass = 
   ## classifies a floating point value. Returns `x`'s class as specified by
-  ## `TFloatClass`
+  ## `TFloatClass`.
+    
+  # ECMAScript and most C compilers have no classify:
+  if x == 0.0:
+    if 1.0/x == 1.0/0.0:
+      return fcZero
+    else:
+      return fcNegZero
+  if x*0.5 == x:
+    if x > 0.0: return fcInf
+    else: return fcNegInf
+  if x != x: return fcNan
+  return fcNormal
+  # XXX: fcSubnormal is not detected!
 
-# implementation
 
-include cntbits
+proc isPowerOfTwo*(x: int): bool {.noSideEffect.} =
+  ## returns true, if x is a power of two, false otherwise.
+  ## Negative numbers are not a power of two.
+  return (x and -x) == x
 
-proc nextPowerOfTwo(x: int): int =
+proc nextPowerOfTwo*(x: int): int =
+  ## returns the nearest power of two, so that
+  ## result**2 >= x > (result-1)**2.
   result = x - 1
   when defined(cpu64):
     result = result or (result shr 32)
@@ -101,31 +65,111 @@ proc nextPowerOfTwo(x: int): int =
   result = result or (result shr 1)
   Inc(result)
 
-# C procs:
-proc gettime(dummy: ptr cint): cint {.
-  importc: "time", header: "<time.h>".}
-proc srand(seed: cint) {.
-  importc: "srand", nodecl.}
-proc rand(): cint {.importc: "rand", nodecl.}
+proc countBits*(n: int32): int {.noSideEffect.}
+  ## counts the set bits in `n`.
 
-# most C compilers have no classify:
-proc classify(x: float): TFloatClass =
-  if x == 0.0:
-    if 1.0/x == 1.0/0.0:
-      return fcZero
-    else:
-      return fcNegZero
-  if x*0.5 == x:
-    if x > 0.0: return fcInf
-    else: return fcNegInf
-  if x != x: return fcNan
-  return fcNormal
-  # XXX: fcSubnormal is not detected!
+include cntbits
 
-proc randomize() = srand(gettime(nil))
-proc random(max: int): int = return rand() mod max
 
-proc isPowerOfTwo(x: int): bool = return (x and -x) == x
+when not defined(ECMAScript):
+  proc random*(max: int): int
+    ## returns a random number in the range 0..max-1. The sequence of
+    ## random number is always the same, unless `randomize` is called
+    ## which initializes the random number generator with a "random"
+    ## number, i.e. a tickcount.
+  proc randomize*()
+    ## initializes the random number generator with a "random"
+    ## number, i.e. a tickcount. Note: Does nothing for the ECMAScript target,
+    ## as ECMAScript does not support this.
+  
+  proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".}
+    ## computes the square root of `x`.
+  
+  proc ln*(x: float): float {.importc: "log", header: "<math.h>".}
+    ## computes ln(x).
+  proc log10*(x: float): float {.importc: "log10", header: "<math.h>".}
+  proc log2*(x: float): float = return ln(x) / ln(2.0)
+  proc exp*(x: float): float {.importc: "exp", header: "<math.h>".}
+    ## computes e**x.
+  
+  proc frexp*(x: float, exponent: var int): float {.
+    importc: "frexp", header: "<math.h>".}
+    ## Split a number into mantissa and exponent.
+    ## `frexp` calculates the mantissa m (a float greater than or equal to 0.5
+    ## and less than 1) and the integer value n such that `x` (the original
+    ## float value) equals m * 2**n. frexp stores n in `exponent` and returns
+    ## m.
+  
+  proc round*(x: float): int {.importc: "lrint", nodecl.}
+    ## converts a float to an int by rounding.  
+  
+  proc arccos*(x: float): float {.importc: "acos", header: "<math.h>".}
+  proc arcsin*(x: float): float {.importc: "asin", header: "<math.h>".}
+  proc arctan*(x: float): float {.importc: "atan", header: "<math.h>".}
+  proc arctan2*(y, x: float): float {.importc: "atan2", header: "<math.h>".}
+    ## Calculate the arc tangent of `y` / `x`.
+    ## `atan2` returns the arc tangent of `y` / `x`; it produces correct
+    ## results even when the resulting angle is near pi/2 or -pi/2
+    ## (`x` near 0).
+  
+  proc cos*(x: float): float {.importc: "cos", header: "<math.h>".}
+  proc cosh*(x: float): float {.importc: "cosh", header: "<math.h>".}
+  proc hypot*(x, y: float): float {.importc: "hypot", header: "<math.h>".}
+    ## same as ``sqrt(x*x + y*y)``.
+  
+  proc sinh*(x: float): float {.importc: "sinh", header: "<math.h>".}
+  proc tan*(x: float): float {.importc: "tan", header: "<math.h>".}
+  proc tanh*(x: float): float {.importc: "tanh", header: "<math.h>".}
+  proc pow*(x, y: float): float {.importc: "pow", header: "<math.h>".}
+    ## computes x to power raised of y.
+    
+  # C procs:
+  proc gettime(dummy: ptr cint): cint {.importc: "time", header: "<time.h>".}
+  proc srand(seed: cint) {.importc: "srand", nodecl.}
+  proc rand(): cint {.importc: "rand", nodecl.}
+    
+  proc randomize() = srand(gettime(nil))
+  proc random(max: int): int = return rand() mod max
+
+else:  
+  proc mathrandom(): float {.importc: "Math.random", nodecl.}
+  proc mathfloor(x: float): float {.importc: "Math.floor", nodecl.}
+  proc random*(max: int): int = return mathfloor(mathrandom() * max)
+  proc randomize*() = nil
+  
+  proc sqrt*(x: float): float {.importc: "Math.sqrt", nodecl.}
+  proc ln*(x: float): float {.importc: "Math.log", nodecl.}
+  proc log10*(x: float): float = return ln(x) / ln(10.0)
+  proc log2*(x: float): float = return ln(x) / ln(2.0)
+
+  proc exp*(x: float): float {.importc: "Math.exp", nodecl.}
+  proc round*(x: float): int {.importc: "Math.round", nodecl.}
+  proc pow*(x, y: float): float {.importc: "Math.pow", nodecl.}
+  
+  proc frexp*(x: float, exponent: var int): float =
+    if x == 0.0:
+      exponent = 0.0
+      result = 0.0
+    elif x < 0.0:
+      result = -frexp(-x, exponent)
+    else:
+      var ex = mathfloor(log2(x))
+      exponent = round(ex)
+      result = x / pow(2.0, ex)
+
+  proc arccos*(x: float): float {.importc: "Math.acos", nodecl.}
+  proc arcsin*(x: float): float {.importc: "Math.asin", nodecl.}
+  proc arctan*(x: float): float {.importc: "Math.atan", nodecl.}
+  proc arctan2*(y, x: float): float {.importc: "Math.atan2", nodecl.}
+  
+  proc cos*(x: float): float {.importc: "Math.cos", nodecl.}
+  proc cosh*(x: float): float = return (exp(x)+exp(-x))*0.5
+  proc hypot*(x, y: float): float = return sqrt(x*x + y*y)
+  proc sinh*(x: float): float = return (exp(x)-exp(-x))*0.5
+  proc tan*(x: float): float {.importc: "Math.tan", nodecl.}
+  proc tanh*(x: float): float =
+    var y = exp(2.0*x)
+    return (y-1.0)/(y+1.0)
 
 {.pop.}
 {.pop.}
diff --git a/lib/memman.nim b/lib/memman.nim
index f0ca078f7..81919389b 100644
--- a/lib/memman.nim
+++ b/lib/memman.nim
@@ -37,24 +37,24 @@ const
   realFli = MaxFli - fliOffset
   
 type
-  TFreePtr = record
+  TFreePtr {.final.} = object
     prev, next: PBhdr
   Pbhdr = ptr Tbhdr
-  Tbhdr = record
+  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 = record  # This structure is embedded at the beginning of each
-                      # area, giving us enough information to cope with a set
-                      # of areas
+  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 = record    
+  TLSF {.final.} = object
     tlsf_signature: int32 # the TLSF's structure signature
     usedSize, maxSize: int
     areaHead: PAreaInfo # A linked list holding all the existing areas
@@ -147,6 +147,7 @@ elif defined(windows):
     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.}
   
@@ -155,6 +156,124 @@ else:
     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
+# boundry. 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]
+    pages: TPageManager
+    usedPages: TPageList
+    freePages: TPageList
+
+# small blocks: 
+proc allocSmall(var h: TGcHeap, size: int): pointer = 
+  var s = align(size)
+  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
 
@@ -261,7 +380,7 @@ proc extractBlock(b: Pbhdr, t: var TLSF, fl, sl: int) {.inline.} =
 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] != 0:
+  if t.matrix[fl][sl] != nil:
     t.matrix[fl][sl].freePtr.prev = b		
   t.matrix[fl][sl] = b
   set_bit(sl, t.slBitmap[fl])
@@ -295,9 +414,6 @@ proc processArea(area: pointer, size: int): Pbhdr =
 # ----------------------------------------------------------------------------
 #                  Begin of the allocator code
 
-var
-  mp: pointer # default memory pool.
-
 proc initMemoryPool(memPoolSize: int, memPool: pointer): int = 
   var
     t: PLSF
@@ -307,16 +423,14 @@ proc initMemoryPool(memPoolSize: int, memPool: pointer): int =
     writeToStdErr("initMemoryPool(): memory_pool invalid\n")
     return -1
 
-  if (memPool and ptrMask) != 0:
+  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:
-    mp = memPool
-    b = getNextBlock(mp, roundupSize(sizeof(TLSF)))
+    b = getNextBlock(memPool, roundupSize(sizeof(TLSF)))
     return b.size and blockSize
-  mp = memPool
   zeroMem(memPool, sizeof(TLSF))
 
   t.signature = tlsfSignature
@@ -456,7 +570,7 @@ proc freeEx(p: pointer, t: var TLSF) =
   b.freePtr.prev = nil
   b.freePtr.next = nil
   tmpB = getNextBlock(getBuffer(b), b.size and blockSize)
-  if tmpB.size and freeBlock != 0:
+  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)
@@ -549,51 +663,30 @@ proc ansiCrealloc(p: pointer, newSize: int, t: var TLSF): pointer =
   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
 
-void *tlsf_malloc(size_t size)
-{
-  void *ret
-
-#if USE_MMAP || USE_SBRK
-  if (!mp) {
-    size_t areaSize
-    void *area
-
-    areaSize = sizeof(tlsf_t) + BHDR_OVERHEAD * 8 # Just a safety constant
-    areaSize = (areaSize > DEFAULT_areaSize) ? areaSize : DEFAULT_areaSize
-    area = get_new_area(&areaSize)
-    if (area == ((void *) ~0))
-      return NULL        # Not enough system memory 
-    initMemoryPool(areaSize, area)
-  }
-#endif
-
-  TLSF_ACQUIRE_LOCK(&((tlsf_t *)mp)->lock)
-
-  ret = malloc_ex(size, mp)
-
-  TLSF_RELEASE_LOCK(&((tlsf_t *)mp)->lock)
-
-  return ret
-}
-
-void tlsf_free(void *p)
-{
-  TLSF_ACQUIRE_LOCK(&((tlsf_t *)mp)->lock)
-  free_ex(p, mp)
-  TLSF_RELEASE_LOCK(&((tlsf_t *)mp)->lock)
-}
-
-void *tlsf_realloc(void *p, size_t size)
-{
-  void *ret
-#if USE_MMAP || USE_SBRK
-  if (!mp) {
-    return tlsf_malloc(size)
-  }
-#endif
-  TLSF_ACQUIRE_LOCK(&((tlsf_t *)mp)->lock)
-  ret = realloc_ex(p, size, mp)
-  TLSF_RELEASE_LOCK(&((tlsf_t *)mp)->lock)
-  return ret
-}
+  # XXX
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 99ee2f20c..8d7c287e0 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -1,7 +1,7 @@
 /*
 
             Nimrod's Runtime Library
-        (c) Copyright 2006 Andreas Rumpf
+        (c) Copyright 2008 Andreas Rumpf
 
     See the file "copying.txt", included in this
     distribution, for details about the copyright.
@@ -11,7 +11,8 @@
 #define NIMBASE_H
 
 /* calling convention mess ----------------------------------------------- */
-#if defined(__GNUC__) || defined(__LCC__) || defined(__POCC__)
+#if defined(__GNUC__) || defined(__LCC__) || defined(__POCC__) \
+                      || defined(__TINYC__)
   /* these should support C99's inline */
   /* the test for __POCC__ has to come before the test for _MSC_VER,
      because PellesC defines _MSC_VER too. This is brain-dead. */
@@ -30,10 +31,18 @@
 #  define N_INLINE(rettype, name) rettype __inline name
 #endif
 
-#if defined(_MSC_VER)
+#if defined(__POCC__) || defined(_MSC_VER)
 #  define HAVE_LRINT 1
 #endif
 
+#if defined(__POCC__)
+#  define NIM_CONST /* PCC is really picky with const modifiers */
+#elif defined(__cplusplus)
+#  define NIM_CONST /* C++ is picky with const modifiers */
+#else
+#  define NIM_CONST  const
+#endif
+
 /* --------------- how int64 constants should be declared: ----------- */
 #if defined(__GNUC__) || defined(__LCC__) || \
     defined(__POCC__) || defined(__DMC__)
@@ -136,8 +145,7 @@
 **		long int lrint  (double x);
 */
 
-#if defined(__LCC__) || defined(__POCC__) \
-                     || (defined(__GNUC__) && defined(WIN32))
+#if defined(__LCC__) || (defined(__GNUC__) && defined(WIN32))
 /* Linux' GCC does not seem to have these. Why? */
 #  define HAVE_LRINT
 #  define HAVE_LRINTF
@@ -159,7 +167,7 @@
 #  include  <math.h>
 
 #elif (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \
-   && !defined(__BORLANDC__)
+   && !defined(__BORLANDC__) && !defined(__POCC__)
 
 #  include  <math.h>
 
@@ -206,6 +214,17 @@ static N_INLINE(long int, lrintf)(float flt) {
 #include <signal.h>
 #include <setjmp.h>
 
+#ifndef NAN
+static unsigned long nimNaN[2]={0xffffffff, 0x7fffffff};
+#  define NAN (*(double*) nimNaN)
+#endif
+
+/*
+#ifndef INF
+static unsigned long nimInf[2]={0xffffffff, 0x7fffffff};
+#  define INF (*(double*) nimInf)
+#endif */
+
 /* compiler symbols:
 __BORLANDC__
 _MSC_VER
@@ -214,6 +233,7 @@ __LCC__
 __GNUC__
 __DMC__
 __POCC__
+__TINYC__
 */
 
 /* C99 compiler? */
@@ -250,50 +270,41 @@ __POCC__
 #endif
 
 #define NIM_NIL ((void*)0) /* C's NULL is fucked up in some C compilers, so
-  the generated code does not rely on it anymore */
+                              the generated code does not rely on it anymore */
 
 #if defined(HAVE_STDINT_H)
 #  include <stdint.h>
-typedef int8_t NS8;
-typedef int16_t NS16;
-typedef int32_t NS32;
-typedef int64_t NS64;
+typedef int8_t NI8;
+typedef int16_t NI16;
+typedef int32_t NI32;
+typedef int64_t NI64;
 typedef uint64_t NU64;
 typedef uint8_t NU8;
 typedef uint16_t NU16;
 typedef uint32_t NU32;
 #elif defined(__BORLANDC__) || defined(__DMC__) \
    || defined(__WATCOMC__) || defined(_MSC_VER)
-typedef signed char NS8;
-typedef signed short int NS16;
-typedef signed int NS32;
+typedef signed char NI8;
+typedef signed short int NI16;
+typedef signed int NI32;
 /* XXX: Float128? */
 typedef unsigned char NU8;
 typedef unsigned short int NU16;
 typedef unsigned __int64 NU64;
-typedef __int64 NS64;
+typedef __int64 NI64;
 typedef unsigned int NU32;
 #else
-typedef signed char NS8;
-typedef signed short int NS16;
-typedef signed int NS32;
+typedef signed char NI8;
+typedef signed short int NI16;
+typedef signed int NI32;
 /* XXX: Float128? */
 typedef unsigned char NU8;
 typedef unsigned short int NU16;
 typedef unsigned long long int NU64;
-typedef long long int NS64;
+typedef long long int NI64;
 typedef unsigned int NU32;
 #endif
 
-#if defined(_MSC_VER) && (defined(AMD64) || defined(_M_AMD64))
-/* Microsoft C is brain-dead in this case; long is still not an int64 */
-typedef unsigned long long int NU;
-typedef signed long long int NS;
-#else
-typedef unsigned long int NU; /* note: int would be wrong for AMD64 */
-typedef signed long int NS;
-#endif
-
 typedef float NF32;
 typedef double NF64;
 typedef double NF;
@@ -307,13 +318,13 @@ typedef char* NCSTRING;
 #  define NIM_IMAN 0
 #endif
 
-static N_INLINE(NS32, float64ToInt32)(double val) {
+static N_INLINE(NI32, float64ToInt32)(double val) {
   val = val + 68719476736.0*1.5;
   /* 2^36 * 1.5,  (52-_shiftamt=36) uses limited precisicion to floor */
-  return ((NS32*)&val)[NIM_IMAN] >> 16; /* 16.16 fixed point representation */
+  return ((NI32*)&val)[NIM_IMAN] >> 16; /* 16.16 fixed point representation */
 }
 
-static N_INLINE(NS32, float32ToInt32)(float val) {
+static N_INLINE(NI32, float32ToInt32)(float val) {
   return float64ToInt32((double)val);
 }
 
@@ -322,7 +333,7 @@ static N_INLINE(NS32, float32ToInt32)(float val) {
 
 #define STRING_LITERAL(name, str, length) \
   static const struct {                   \
-    NS len, space;                        \
+    NI len, space;                        \
     NIM_CHAR data[length + 1];            \
   } name = {length, length, str}
 
@@ -357,7 +368,7 @@ typedef struct TStringDesc* string;
 /*
 typedef struct TSafePoint TSafePoint;
 struct TSafePoint {
-  NS exc;
+  NI exc;
   NCSTRING excname;
   NCSTRING msg;
   TSafePoint* prev;
@@ -368,19 +379,19 @@ typedef struct TFrame TFrame;
 struct TFrame {
   TFrame* prev;
   NCSTRING procname;
-  NS line;
+  NI line;
   NCSTRING filename;
-  NS len;
+  NI len;
 };
 
-extern TFrame* volatile framePtr;
-/*extern TSafePoint* volatile excHandler; */
+extern TFrame* framePtr;
+/*extern TSafePoint* excHandler; */
 
 #if defined(__cplusplus)
 struct NimException {
   TSafePoint sp;
 
-  NimException(NS aExc, NCSTRING aExcname, NCSTRING aMsg) {
+  NimException(NI aExc, NCSTRING aExcname, NCSTRING aMsg) {
     sp.exc = aExc; sp.excname = aExcname; sp.msg = aMsg;
     sp.prev = excHandler;
     excHandler = &sp;
@@ -389,13 +400,13 @@ struct NimException {
 #endif
 
 typedef struct TStringDesc {
-  NS len;
-  NS space;
+  NI len;
+  NI space;
   NIM_CHAR data[1]; /* SEQ_DECL_SIZE]; */
 } TStringDesc;
 
 typedef struct {
-  NS len, space;
+  NI len, space;
 } TGenericSeq;
 
 typedef TGenericSeq* PGenericSeq;
diff --git a/lib/optparse.nim b/lib/optparse.nim
deleted file mode 100644
index 58007b5a9..000000000
--- a/lib/optparse.nim
+++ /dev/null
@@ -1,39 +0,0 @@
-#

-#

-#            Nimrod's Runtime Library

-#        (c) Copyright 2006 Andreas Rumpf

-#

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

-#    distribution, for details about the copyright.

-#

-

-

-## This module provides a command line parser.

-## It supports one iterator over all command line options.

-

-#interface

-

-{.push debugger: off.}

-

-import

-  os

-

-proc findSep(s: string): int {.nostatic.} =

-  for i in 0 .. high(s)-1:

-    if s[i] in {'=', ':'}: return i

-  return high(s)+1

-

-iterator getopt*(): tuple[string, string] =

-  # returns a (cmd, arg) tuple.

-  for k in 1 .. ParamCount():

-    var param = paramStr(k)

-    if param[0] == '-':

-      var j = findSep(param)

-      cmd = copy(param, 0, j-1)

-      arg = copy(param, j+1)

-    else:

-      cmd = ""

-      arg = param

-    yield cmd, arg

-

-{.pop.}

diff --git a/lib/os.nim b/lib/os.nim
index cd835c480..f07045143 100644
--- a/lib/os.nim
+++ b/lib/os.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2006 Andreas Rumpf
+#        (c) Copyright 2008 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -10,7 +10,9 @@
 ## Basic operating system facilities like retrieving environment variables,
 ## reading command line arguments, working with directories, running shell
 ## commands, etc. This module is -- like any other basic library --
-## platform independant.
+## platform independant. However, the ECMAScript target is not supported,
+## as there is no way to perform these operations in ECMAScript portably
+## or at all.
 
 {.push debugger:off.}
 
@@ -18,7 +20,7 @@ import
   strutils, times
 
 # copied from excpt.nim, because I don't want to make this template public
-template newException(exceptn, message: expr): expr = 
+template newException(exceptn, message: expr): expr =
   block: # open a new scope
     var
       e: ref exceptn
@@ -294,7 +296,7 @@ proc existsDir*(dir: string): bool
 proc getLastModificationTime*(file: string): TTime
   ## Gets the time of the `file`'s last modification.
 
-proc fileNewer*(a, b: string): bool 
+proc fileNewer*(a, b: string): bool
   ## returns true if the file `a` is newer than file `b`, i.e. if `a`'s
   ## modification time is later than `b`'s.
 
@@ -371,8 +373,11 @@ proc UnixToNativePath(path: string): string =
 
 # interface to C library:
 
+const
+  cunder = if defined(pcc): "_" else: ""
+
 type
-  TStat {.importc: "struct stat".} = record
+  TStat {.importc: "struct " & cunder & "stat", final.} = object
     st_dev: int16
     st_ino: int16
     st_mode: int16
@@ -397,7 +402,8 @@ else:
   {.error: "os library not ported to your OS. Please help!".}
 
 
-proc chdir(path: CString): cint {.importc: "chdir", header: dirHeader.}
+proc chdir(path: CString): cint {.
+  importc: cunder & "chdir", header: dirHeader.}
 
 when defined(unix):
   proc mkdir(dir: CString, theAccess: cint): cint {.
@@ -412,7 +418,7 @@ elif defined(windows):
   proc fullpath(buffer, file: CString, size: int): CString {.
     importc: "_fullpath", header: "<stdlib.h>".}
   proc getcwd(buf: CString, buflen: cint): CString {.
-    importc: "getcwd", header: "<direct.h>".}
+    importc: cunder & "getcwd", header: "<direct.h>".}
 
   proc CreateDirectory(pathName: cstring, security: Pointer): cint {.
     importc: "CreateDirectory", header: "<windows.h>".}
@@ -421,7 +427,8 @@ else:
   {.error: "os library not ported to your OS. Please help!".}
 
 
-proc rmdir(dir: CString): cint {.importc: "rmdir", header: "<time.h>".}
+proc rmdir(dir: CString): cint {.
+  importc: cunder & "rmdir", header: "<time.h>".}
   # rmdir is of course in ``dirHeader``, but we check here to include
   # time.h which is needed for stat(). stat() needs time.h and
   # sys/stat.h; we workaround a C library issue here.
@@ -432,17 +439,7 @@ proc free(c: cstring) {.importc: "free", nodecl.}
 proc strlen(str: CString): int {.importc: "strlen", nodecl.}
 
 proc stat(f: CString, res: var TStat): cint {.
-  importc: "stat", header: "<sys/stat.h>".}
-
-proc sameFile*(path1, path2: string): bool =
-  ## Returns True if both pathname arguments refer to the same file or
-  ## directory (as indicated by device number and i-node number).
-  ## Raises an exception if an os.stat() call on either pathname fails.
-  var
-    a, b: TStat
-  if stat(path1, a) < 0 or stat(path2, b) < 0:
-    raise newException(EOS, "stat() call failed")
-  return int(a.st_dev) == b.st_dev and int(a.st_ino) == b.st_ino
+  importc: cunder & "stat", header: "<sys/stat.h>".}
 
 when defined(windows):
   proc getModuleFilename(handle: int32, buf: CString, size: int32): int32 {.
@@ -456,13 +453,13 @@ proc getLastModificationTime(file: string): TTime =
 
 proc setCurrentDir(newDir: string) =
   if chdir(newDir) != 0:
-    raise newException(EOS, "cannot change the working directory to '$1'" % 
+    raise newException(EOS, "cannot change the working directory to '$1'" %
       newDir)
 
 when defined(linux) or defined(solaris) or defined(bsd):
   proc readlink(link, buf: cstring, size: int): int {.
     header: "<unistd.h>", cdecl.}
-  
+
   proc getApplAux(procPath: string): string =
     result = newString(256)
     var len = readlink(procPath, result, 256)
@@ -473,6 +470,13 @@ when defined(linux) or defined(solaris) or defined(bsd):
 
 when defined(solaris) or defined(bsd):
   proc getpid(): int {.importc, header: "<unistd.h>", cdecl.}
+elif defined(macosx):
+  # a really hacky solution: since we like to include 2 headers we have to
+  # define two procs which in reality are the same
+  proc getExecPath1(c: cstring, size: var int32) {.
+    importc: "_NSGetExecutablePath", header: "<sys/param.h>".}
+  proc getExecPath2(c: cstring, size: var int32): bool {.
+    importc: "_NSGetExecutablePath", header: "<mach-o/dyld.h>".}
 
 proc getApplicationFilename(): string =
   # Linux: /proc/<pid>/exe
@@ -491,6 +495,12 @@ proc getApplicationFilename(): string =
     result = getApplAux("/proc/" & $getpid() & "/path/a.out")
   elif defined(bsd):
     result = getApplAux("/proc/" & $getpid() & "file")
+  elif defined(macosx):
+    var size: int32
+    getExecPath1(nil, size)
+    result = newString(int(size))
+    if getExecPath2(result, size):
+      result = "" # error!
   else:
     # little heuristic that may work on other POSIX-like systems:
     result = getEnv("_")
@@ -612,7 +622,7 @@ when defined(wcc):
   proc cputenv(env: CString): cint {.importc: "putenv", header: "<process.h>".}
 
 else: # is in <stdlib.h>
-  proc cputenv(env: CString): cint {.importc: "putenv", noDecl.} 
+  proc cputenv(env: CString): cint {.importc: cunder & "putenv", noDecl.}
 
 proc cgetenv(env: CString): CString {.importc: "getenv", noDecl.}
 
@@ -621,7 +631,7 @@ proc cgetenv(env: CString): CString {.importc: "getenv", noDecl.}
 #int  _findclose(long);
 when defined(windows):
   type
-    TFindData {.importc: "struct _finddata_t".} = record
+    TFindData {.importc: "struct _finddata_t", final.} = object
       attrib {.importc: "attrib".}: cint
       time_create {.importc: "time_create".}: cint
       time_access {.importc: "time_access".}: cint
@@ -636,7 +646,7 @@ when defined(windows):
   proc findclose(handle: cint) {.importc: "_findclose", header: "<io.h>".}
 else:
   type
-    TFindData {.importc: "glob_t".} = record
+    TFindData {.importc: "glob_t", final.} = object
       gl_pathc: int     # count of paths matched by pattern
       gl_pathv: ptr array[0..1000_000, CString] # list of matched path names
       gl_offs: int      # slots to reserve at beginning of gl_pathv
@@ -649,6 +659,30 @@ else:
   proc globfree(pglob: PFindData) {.
     importc: "globfree", header: "<glob.h>".}
 
+proc sameFile*(path1, path2: string): bool =
+  ## Returns True if both pathname arguments refer to the same file or
+  ## directory (as indicated by device number and i-node number).
+  ## Raises an exception if an os.stat() call on either pathname fails.
+  when defined(Windows):
+    var
+      a, b: TFindData
+    var resA = findfirst(path1, addr(a))
+    var resB = findfirst(path2, addr(b))
+    if resA != -1 and resB != -1:
+      result = $a.name == $b.name
+    else:
+      # work around some ``findfirst`` bugs
+      result = cmpPaths(path1, path2) == 0
+    if resA != -1: findclose(resA)
+    if resB != -1: findclose(resB)
+  else:
+    var
+      a, b: TStat
+    if stat(path1, a) < 0 or stat(path2, b) < 0:
+      result = cmpPaths(path1, path2) == 0 # be consistent with Windows
+    else:
+      result = int(a.st_dev) == b.st_dev and int(a.st_ino) == b.st_ino
+
 proc cremove(filename: CString): cint {.importc: "remove", noDecl.}
 proc crename(oldname, newname: CString): cint {.importc: "rename", noDecl.}
 
@@ -776,9 +810,9 @@ proc findEnvVar(key: string): int =
 
 proc getEnv(key: string): string =
   var i = findEnvVar(key)
-  if i >= 0: 
+  if i >= 0:
     return copy(environment[i], findSubStr("=", environment[i])+1)
-  else: 
+  else:
     var env = cgetenv(key)
     if env == nil: return ""
     result = $env
@@ -787,7 +821,7 @@ proc existsEnv(key: string): bool =
   if cgetenv(key) != nil: return true
   else: return findEnvVar(key) >= 0
 
-iterator iterOverEnvironment*(): tuple[string, string] =
+iterator iterOverEnvironment*(): tuple[key, value: string] =
   ## Iterate over all environments varialbes. In the first component of the
   ## tuple is the name of the current variable stored, in the second its value.
   getEnvVarsC()
@@ -798,7 +832,7 @@ iterator iterOverEnvironment*(): tuple[string, string] =
 proc putEnv(key, val: string) =
   # Note: by storing the string in the environment sequence,
   # we gurantee that we don't free the memory before the program
-  # ends (this is needed for POSIX compliance). It is also needed so that 
+  # ends (this is needed for POSIX compliance). It is also needed so that
   # the process itself may access its modified environment variables!
   var indx = findEnvVar(key)
   if indx >= 0:
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index 9a18d0e17..35fe0a0df 100644
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -14,7 +14,7 @@
 ## This is a raw POSIX interface module. It does not not provide any

 ## convenience: cstrings are used instead of proper Nimrod strings and

 ## return codes indicate errors. If you want exceptions 

-## and a proper Nimrod-like interface, use the OS module.

+## and a proper Nimrod-like interface, use the OS module or write a wrapper.

 

 ## Coding conventions:

 ## ALL types are named the same as in the POSIX standard except that they start

@@ -60,7 +60,7 @@ const
   STDOUT_FILENO = 1 ## File number of stdout; 

 

 type

-  Taiocb* {.importc: "struct aiocb", header: "<aio.h>".} = record

+  Taiocb* {.importc: "struct aiocb", header: "<aio.h>", final.} = object

     aio_fildes*: cint ##    File descriptor. 

     aio_offset*: TOff ##    File offset. 

     aio_buf*: pointer ##    Location of buffer. 

@@ -69,14 +69,14 @@ type
     aio_sigevent*: TSigEvent  ## Signal number and value. 

     aio_lio_opcode: cint ## Operation to be performed. 

 

-  TDIR* {.importc: "DIR", header: "<dirent.h>".} = record

+  TDIR* {.importc: "DIR", header: "<dirent.h>", final.} = object

     ## A type representing a directory stream. 

 

-  Tdirent* {.importc: "struct dirent", header: "<dirent.h>".} = record

+  Tdirent* {.importc: "struct dirent", header: "<dirent.h>", final.} = object

     d_ino*: TIno  ## File serial number.

     d_name*: array [0..255, char] ## Name of entry.

 

-  Tflock* {.importc: "flock", header: "<fcntl>".} = record

+  Tflock* {.importc: "flock", header: "<fcntl>", final.} = object

     l_type*: cshort  ## Type of lock; F_RDLCK, F_WRLCK, F_UNLCK. 

     l_whence*: cshort ## Flag for starting offset. 

     l_start*: Toff ## Relative offset in bytes. 

@@ -84,13 +84,13 @@ type
     l_pid*: TPid   ## Process ID of the process holding the lock; 

                    ## returned with F_GETLK. 

   

-  Tfenv* {.importc: "fenv_t", header: "<fenv.h>".} = 

-    record ## Represents the entire floating-point environment. The

+  Tfenv* {.importc: "fenv_t", header: "<fenv.h>", final.} = 

+    object ## Represents the entire floating-point environment. The

            ## floating-point environment refers collectively to any

            ## floating-point status flags and control modes supported

            ## by the implementation.

-  Tfexcept* {.importc: "fexcept_t", header: "<fenv.h>".} = 

-    record ## Represents the floating-point status flags collectively, 

+  Tfexcept* {.importc: "fexcept_t", header: "<fenv.h>", final.} = 

+    object ## Represents the floating-point status flags collectively, 

            ## including any status the implementation associates with the 

            ## flags. A floating-point status flag is a system variable 

            ## whose value is set (but never cleared) when a floating-point

@@ -100,25 +100,25 @@ type
            ## whose value may be set by the user to affect the subsequent 

            ## behavior of floating-point arithmetic.

 

-  TFTW* {.importc: "struct FTW", header: "<ftw.h>".} = record

+  TFTW* {.importc: "struct FTW", header: "<ftw.h>", final.} = object

     base*: cint

     level*: cint

     

-  TGlob* {.importc: "glob_t", header: "<glob.h>".} = record

+  TGlob* {.importc: "glob_t", header: "<glob.h>", final.} = object

     gl_pathc*: int ## Count of paths matched by pattern. 

     gl_pathv*: ptr cstring ## Pointer to a list of matched pathnames. 

     gl_offs*: int ##  Slots to reserve at the beginning of gl_pathv. 

   

-  TGroup* {.importc: "struct group", header: "<grp.h>".} = record

+  TGroup* {.importc: "struct group", header: "<grp.h>", final.} = object

     gr_name*: cstring ## The name of the group. 

     gr_gid*: TGid  ## Numerical group ID. 

     gr_mem*: cstringArray ## Pointer to a null-terminated array of character 

                           ## pointers to member names. 

 

-  Ticonv* {.importc: "iconv_t", header: "<iconv.h>".} = 

-    record ## Identifies the conversion from one codeset to another.

+  Ticonv* {.importc: "iconv_t", header: "<iconv.h>", final.} = 

+    object ## Identifies the conversion from one codeset to another.

 

-  Tlconv* {.importc: "struct lconv", header: "<locale.h>".} = record

+  Tlconv* {.importc: "struct lconv", header: "<locale.h>", final.} = object

     currency_symbol*: cstring

     decimal_point*: cstring

     frac_digits*: char

@@ -144,14 +144,14 @@ type
     p_sign_posn*: char

     thousands_sep*: cstring

 

-  TMqd* {.importc: "mqd_t", header: "<mqueue.h>".} = record

-  TMqAttr* {.importc: "struct mq_attr", header: "<mqueue.h>".} = record

+  TMqd* {.importc: "mqd_t", header: "<mqueue.h>", final.} = object

+  TMqAttr* {.importc: "struct mq_attr", header: "<mqueue.h>", final.} = object

     mq_flags*: int ##    Message queue flags. 

     mq_maxmsg*: int ##   Maximum number of messages. 

     mq_msgsize*: int ##  Maximum message size. 

     mq_curmsgs*: int ##  Number of messages currently queued. 

 

-  TPasswd* {.importc: "struct passwd", header: "<pwd.h>".} = record

+  TPasswd* {.importc: "struct passwd", header: "<pwd.h>", final.} = object

     pw_name*: cstring ##   User's login name. 

     pw_uid*: TUid ##    Numerical user ID. 

     pw_gid*: TGid ##    Numerical group ID. 

@@ -198,7 +198,7 @@ type
   Tuid* {.importc: "uid_t", header: "<sys/types.h>".} = int

   Tuseconds* {.importc: "useconds_t", header: "<sys/types.h>".} = int

   

-  Tutsname* {.importc: "struct utsname", header: "<sys/utsname.h>".} = record

+  Tutsname* {.importc: "struct utsname", header: "<sys/utsname.h>", final.} = object

     sysname*,    ## Name of this implementation of the operating system. 

       nodename*,   ## Name of this node within the communications 

                    ## network to which this node is attached, if any. 

@@ -207,15 +207,15 @@ type
       machine*: array [0..255, char] ## Name of the hardware type on which the

                                      ## system is running. 

 

-  TSem* {.importc: "sem_t", header: "<semaphore.h>".} = record

-  Tipc_perm* {.importc: "struct ipc_perm", header: "<sys/ipc.h>".} = record

+  TSem* {.importc: "sem_t", header: "<semaphore.h>", final.} = object

+  Tipc_perm* {.importc: "struct ipc_perm", header: "<sys/ipc.h>", final.} = object

     uid*: tuid    ## Owner's user ID. 

     gid*: tgid    ## Owner's group ID. 

     cuid*: Tuid   ## Creator's user ID. 

     cgid*: Tgid   ## Creator's group ID. 

     mode*: TMode   ## Read/write permission. 

   

-  TStat* {.importc: "struct stat", header: "<sys/stat.h>".} = record

+  TStat* {.importc: "struct stat", header: "<sys/stat.h>", final.} = object

     st_dev*: TDev  ##   Device ID of device containing file. 

     st_ino*: TIno  ##   File serial number. 

     st_mode*: TMode ##   Mode of file (see below). 

@@ -239,7 +239,7 @@ type
     st_blocks*: Tblkcnt ## Number of blocks allocated for this object. 

 

   

-  TStatvfs* {.importc: "struct statvfs", header: "<sys/statvfs.h>".} = record  

+  TStatvfs* {.importc: "struct statvfs", header: "<sys/statvfs.h>", final.} = object  

     f_bsize*: int   ## File system block size. 

     f_frsize*: int  ## Fundamental file system block size. 

     f_blocks*: Tfsblkcnt  ## Total number of blocks on file system in units of f_frsize. 

@@ -255,10 +255,10 @@ type
     f_namemax*: int ##  Maximum filename length. 

 

   Tposix_typed_mem_info* {.importc: "struct posix_typed_mem_info", 

-                           header: "<sys/mman.h>".} = record

+                           header: "<sys/mman.h>", final.} = object

     posix_tmi_length*: int

   

-  Ttm* {.importc: "struct tm", header: "<time.h>".} = record

+  Ttm* {.importc: "struct tm", header: "<time.h>", final.} = object

     tm_sec*: cint ## Seconds [0,60]. 

     tm_min*: cint   ## Minutes [0,59]. 

     tm_hour*: cint  ## Hour [0,23]. 

@@ -268,10 +268,10 @@ type
     tm_wday*: cint  ## Day of week [0,6] (Sunday =0). 

     tm_yday*: cint  ## Day of year [0,365]. 

     tm_isdst*: cint ## Daylight Savings flag. 

-  Ttimespec* {.importc: "struct timespec", header: "<time.h>".} = record

+  Ttimespec* {.importc: "struct timespec", header: "<time.h>", final.} = object

     tv_sec*: Ttime ## Seconds. 

     tv_nsec*: int ## Nanoseconds. 

-  titimerspec* {.importc: "struct itimerspec", header: "<time.h>".} = record

+  titimerspec* {.importc: "struct itimerspec", header: "<time.h>", final.} = object

     it_interval*: ttimespec ## Timer period. 

     it_value*: ttimespec    ## Timer expiration. 

   

@@ -279,19 +279,19 @@ type
     ## Possibly volatile-qualified integer type of an object that can be 

     ## accessed as an atomic entity, even in the presence of asynchronous

     ## interrupts.

-  Tsigset* {.importc: "sigset_t", header: "<signal.h>".} = record

+  Tsigset* {.importc: "sigset_t", header: "<signal.h>", final.} = object

   

-  TsigEvent* {.importc: "struct sigevent", header: "<signal.h>".} = record

+  TsigEvent* {.importc: "struct sigevent", header: "<signal.h>", final.} = object

     sigev_notify*: cint           ## Notification type. 

     sigev_signo*: cint            ## Signal number. 

     sigev_value*: Tsigval        ##     Signal value. 

     sigev_notify_function*: proc (x: TSigval) {.noconv.} ##  Notification function. 

     sigev_notify_attributes*: ptr Tpthreadattr ## Notification attributes.

 

-  TsigVal* {.importc: "union sigval", header: "<signal.h>".} = record

+  TsigVal* {.importc: "union sigval", header: "<signal.h>", final.} = object

     sival_ptr*: pointer ## pointer signal value; 

                         ## integer signal value not defined!

-  TSigaction* {.importc: "struct sigaction", header: "<signal.h>".} = record

+  TSigaction* {.importc: "struct sigaction", header: "<signal.h>", final.} = object

     sa_handler*: proc (x: cint) {.noconv.}  ## Pointer to a signal-catching

                                             ## function or one of the macros 

                                             ## SIG_IGN or SIG_DFL. 

@@ -300,16 +300,16 @@ type
     sa_flags*: cint   ## Special flags. 

     sa_sigaction*: proc (x: cint, y: var TSigInfo, z: pointer) {.noconv.}

 

-  TStack* {.importc: "stack_t", header: "<signal.h>".} = record

+  TStack* {.importc: "stack_t", header: "<signal.h>", final.} = object

     ss_sp*: pointer ##       Stack base or pointer. 

     ss_size*: int ##     Stack size. 

     ss_flags*: cint ##    Flags. 

 

-  TSigStack* {.importc: "struct sigstack", header: "<signal.h>".} = record

+  TSigStack* {.importc: "struct sigstack", header: "<signal.h>", final.} = object

     ss_onstack*: cint ##  Non-zero when signal stack is in use. 

     ss_sp*: pointer ## Signal stack pointer. 

 

-  TsigInfo* {.importc: "siginfo_t", header: "<signal.h>".} = record

+  TsigInfo* {.importc: "siginfo_t", header: "<signal.h>", final.} = object

     si_signo*: cint ##  Signal number. 

     si_code*: cint ##   Signal code. 

     si_errno*: cint ##  If non-zero, an errno value associated with 

@@ -324,7 +324,7 @@ type
   Tnl_item* {.importc: "nl_item", header: "<nl_types.h>".} = cint

   Tnl_catd* {.importc: "nl_catd", header: "<nl_types.h>".} = cint

 

-  Tsched_param* {.importc: "struct sched_param", header: "<sched.h>".} = record

+  Tsched_param* {.importc: "struct sched_param", header: "<sched.h>", final.} = object

     sched_priority*: cint

     sched_ss_low_priority*: cint ## Low scheduling priority for 

                                  ## sporadic server. 

@@ -334,15 +334,15 @@ type
     sched_ss_max_repl*: cint    ## Maximum pending replenishments for 

                                 ## sporadic server. 

 

-  Ttimeval* {.importc: "struct timeval", header: "<sys/select.h>".} = record

+  Ttimeval* {.importc: "struct timeval", header: "<sys/select.h>", final.} = object

     tv_sec*: ttime ##      Seconds. 

     tv_usec*: tsuseconds ##     Microseconds. 

-  Tfd_set* {.importc: "struct fd_set", header: "<sys/select.h>".} = record

+  Tfd_set* {.importc: "struct fd_set", header: "<sys/select.h>", final.} = object

  

   Tposix_spawnattr* {.importc: "posix_spawnattr_t", header: "<spawn.h>".} = cint

   Tposix_spawn_file_actions* {.importc: "posix_spawn_file_actions_t", header: "<spawn.h>".} = cint 

-  Tmcontext* {.importc: "mcontext_t", header: "<ucontext.h>".} = record

-  Tucontext* {.importc: "ucontext_t", header: "<ucontext.h>".} = record

+  Tmcontext* {.importc: "mcontext_t", header: "<ucontext.h>", final.} = object

+  Tucontext* {.importc: "ucontext_t", header: "<ucontext.h>", final.} = object

     uc_link*: ptr Tucontext ## Pointer to the context that is resumed 

                             ## when this context returns. 

     uc_sigmask*: Tsigset ## The set of signals that are blocked when this 

@@ -729,7 +729,7 @@ var
   GLOB_NOSORT* {.importc, header: "<glob.h>".}: cint

     ## Do not sort the pathnames returned.

   GLOB_ABORTED* {.importc, header: "<glob.h>".}: cint

-    ## The scan was stopped because GLOB_ERR was set or (*errfunc)() 

+    ## The scan was stopped because GLOB_ERR was set or errfunc() 

     ## returned non-zero.

   GLOB_NOMATCH* {.importc, header: "<glob.h>".}: cint

     ## The pattern does not match any existing pathname, and GLOB_NOCHECK 

diff --git a/lib/process.nim b/lib/process.nim
index ebeeb3f47..8806264b9 100644
--- a/lib/process.nim
+++ b/lib/process.nim
@@ -1,7 +1,7 @@
 #

 #

 #            Nimrod's Runtime Library

-#        (c) Copyright 2006 Andreas Rumpf

+#        (c) Copyright 2008 Andreas Rumpf

 #

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

 #    distribution, for details about the copyright.

diff --git a/lib/ptrset.nim b/lib/ptrset.nim
index f1b9e58e5..95f01b16f 100644
--- a/lib/ptrset.nim
+++ b/lib/ptrset.nim
@@ -18,7 +18,7 @@ type
   PPointer = ptr pointer
 
   TCollectorData = int
-  TCell = record
+  TCell {.final.} = object
     refcount: TCollectorData  # the refcount and bit flags
     typ: PNimType                  
     stackcount: int           # stack counter for debugging
@@ -67,18 +67,18 @@ type
 
   TBitIndex = range[0..UnitsPerPage-1]
 
-  TPageDesc = record
+  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 = record
+  TCellSet {.final.} = object
     counter, max: int
     head: PPageDesc
     data: PPageDescArray
     
-  TSetNode = record
+  TSetNode {.final.} = object
     n: array[0.. (1 shl bitsPerNode)-1, PSetNode]
   PSetNode = ptr TSetNode
 
diff --git a/lib/repr.nim b/lib/repr.nim
index e5106c38d..34a2ce2fb 100644
--- a/lib/repr.nim
+++ b/lib/repr.nim
@@ -1,233 +1,247 @@
-#

-#

-#            Nimrod's Runtime Library

-#        (c) Copyright 2006 Andreas Rumpf

-#

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

-#    distribution, for details about the copyright.

-#

-

-# The generic ``repr`` procedure. It is an invaluable debugging tool.

-

-#proc cstrToNimStrDummy(s: cstring): string {.inline.} =

-#  result = cast[string](cstrToNimStr(s))

-

-proc reprInt(x: int64): string {.compilerproc.} = return $x

-proc reprFloat(x: float): string {.compilerproc.} = return $x

-

-proc reprPointer(x: pointer): string {.compilerproc.} =

-  var buf: array [0..59, char] 

-  c_sprintf(buf, "%p", x)

-  return $buf

-

-proc reprStrAux(result: var string, s: string) =

-  if cast[pointer](s) == nil:

-    add result "nil"

-    return

-  add result, reprPointer(cast[pointer](s)) & "\""

-  for c in items(s):

-    case c

-    of '"': add result "\\\""

-    of '\\': add result, "\\\\" # BUGFIX: forgotten

-    of '\10': add result, "\\10\"\n\"" # " \n " # better readability

-    of '\128' .. '\255', '\0'..'\9', '\11'..'\31':

-      add result, "\\" & reprInt(ord(c))

-    else: result.add(c)

-  add result, "\""

-

-proc reprStr(s: string): string {.compilerproc.} =

-  result = ""

-  reprStrAux(result, s)

-

-proc reprBool(x: bool): string {.compilerproc.} =

-  if x: result = "true"

-  else: result = "false"

-

-proc reprChar(x: char): string {.compilerproc.} =

-  result = "\'"

-  case x

-  of '"': add result, "\\\""

-  of '\\': add result, "\\\\"

-  of '\128' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x))

-  else: add result, x

-  add result, "\'"

-

-proc reprEnum(e: int, typ: PNimType): string {.compilerproc.} =

-  if e <% typ.node.len: # BUGFIX

-    result = $typ.node.sons[e].name

-  else:

-    result = $e & " (invalid data!)"

-

-type

-  pbyteArray = ptr array[0.. 0xffff, byte]

-

-proc addSetElem(result: var string, elem: int, typ: PNimType) =

-  case typ.kind

-  of tyEnum: add result, reprEnum(elem, typ)

-  of tyBool: add result, reprBool(bool(elem))

-  of tyChar: add result, reprChar(chr(elem))

-  of tyRange: addSetElem(result, elem, typ.base)

-  of tyInt..tyInt64: add result, reprInt(elem)

-  else: # data corrupt --> inform the user

-    add result, " (invalid data!)"

-

-proc reprSetAux(result: var string, p: pointer, typ: PNimType) =

-  # "typ.slots.len" field is for sets the "first" field

-  var elemCounter = 0  # we need this flag for adding the comma at

-                       # the right places

-  add result, "{"

-  var u: int64

-  case typ.size

-  of 1: u = ze64(cast[ptr int8](p)^)

-  of 2: u = ze64(cast[ptr int16](p)^)

-  of 4: u = ze64(cast[ptr int32](p)^)

-  of 8: u = ze64(cast[ptr int64](p)^)

-  else:

-    var a = cast[pbyteArray](p)^

-    for i in 0 .. typ.size*8-1:

-      if (a[i div 8] and (1 shl (i mod 8))) != 0:

-        if elemCounter > 0: add result, ", "

-        addSetElem(result, i+typ.node.len, typ.base)

-        inc(elemCounter)

-  if typ.size <= 8:

-    for i in 0..sizeof(int64)*8-1:

-      if (u and (1 shl i)) != 0:

-        if elemCounter > 0: add result, ", "

-        addSetElem(result, i+typ.node.len, typ.base)

-        inc(elemCounter)

-  add result, "}"

-

-proc reprSet(p: pointer, typ: PNimType): string {.compilerproc.} =

-  result = ""

-  reprSetAux(result, p, typ)

-

-type

-  TReprClosure = record # we cannot use a global variable here

-                        # as this wouldn't be thread-safe

-    marked: TCellSet

-    recdepth: int       # do not recurse endless

-    indent: int         # indentation

-

-proc initReprClosure(cl: var TReprClosure) =

-  CellSetInit(cl.marked)

-  cl.recdepth = -1      # default is to display everything!

-  cl.indent = 0

-

-proc deinitReprClosure(cl: var TReprClosure) =

-  CellSetDeinit(cl.marked)

-

-proc reprBreak(result: var string, cl: TReprClosure) =

-  add result, "\n"

-  for i in 0..cl.indent-1: add result, ' '

-

-proc reprAux(result: var string, p: pointer, typ: PNimType,

-             cl: var TReprClosure)

-

-proc reprArray(result: var string, p: pointer, typ: PNimType,

-               cl: var TReprClosure) =

-  add result, "["

-  var bs = typ.base.size

-  for i in 0..typ.size div bs - 1:

-    if i > 0: add result, ", "

-    reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), typ.base, cl)

-  add result, "]"

-

-proc reprSequence(result: var string, p: pointer, typ: PNimType,

-                  cl: var TReprClosure) =

-  if p == nil:

-    add result, "nil"

-    return

-  result.add(reprPointer(p) & "[")

-  var bs = typ.base.size

-  for i in 0..cast[PGenericSeq](p).len-1:

-    if i > 0: add result, ", "

-    reprAux(result, cast[pointer](cast[TAddress](p) + GenericSeqSize + i*bs),

-            typ.Base, cl)

-  add result, "]"

-

-

-proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,

-                   cl: var TReprClosure) =

-  case n.kind

-  of nkNone: assert(false)

-  of nkSlot:

-    add result, $n.name 

-    add result, " = "

-    reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)

-  of nkList:

-    for i in 0..n.len-1: 

-      if i > 0: add result, ",\n"

-      reprRecordAux(result, p, n.sons[i], cl)

-  of nkCase: 

-    var m = selectBranch(p, n)

-    reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)

-    if m != nil: reprRecordAux(result, p, m, cl)

-    

-proc reprRecord(result: var string, p: pointer, typ: PNimType,

-                cl: var TReprClosure) =

-  add result, "["

-  reprRecordAux(result, p, typ.node, cl)

-  add result, "]"

-

-proc reprRef(result: var string, p: pointer, typ: PNimType,

-             cl: var TReprClosure) =

-  # we know that p is not nil here:

-  var cell = usrToCell(p)

-  add result, "ref " & reprPointer(p)

-  if cell notin cl.marked:

-    # only the address is shown:

-    incl(cl.marked, cell)

-    add result, " --> "

-    reprAux(result, p, typ.base, cl)

-

-proc reprAux(result: var string, p: pointer, typ: PNimType,

-             cl: var TReprClosure) =

-  if cl.recdepth == 0:

-    add result, "..."

-    return

-  dec(cl.recdepth)

-  case typ.kind

-  of tySet: reprSetAux(result, p, typ)

-  of tyArray: reprArray(result, p, typ, cl)

-  of tyRecord: reprRecord(result, p, typ, cl)

-  of tyObject: # result = reprRecord(p, typ, cl)

-    var t = cast[ptr PNimType](p)^

-    reprRecord(result, p, t, cl)

-  of tyRef, tyPtr:

-    assert(p != nil)

-    if cast[ppointer](p)^ == nil: add result, "nil"

-    else: reprRef(result, cast[ppointer](p)^, typ, cl)

-  of tySequence:

-    reprSequence(result, cast[ppointer](p)^, typ, cl)

-  of tyInt: add result, $(cast[ptr int](p)^)

-  of tyInt8: add result, $int(cast[ptr Int8](p)^)

-  of tyInt16: add result, $int(cast[ptr Int16](p)^)

-  of tyInt32: add result, $int(cast[ptr Int32](p)^)

-  of tyInt64: add result, $(cast[ptr Int64](p)^)

-  of tyFloat: add result, $(cast[ptr float](p)^)

-  of tyFloat32: add result, $(cast[ptr float32](p)^)

-  of tyFloat64: add result, $(cast[ptr float64](p)^)

-  of tyEnum: add result, reprEnum(cast[ptr int](p)^, typ)

-  of tyBool: add result, reprBool(cast[ptr bool](p)^)

-  of tyChar: add result, reprChar(cast[ptr char](p)^)

-  of tyString: reprStrAux(result, cast[ptr string](p)^)

-  of tyCString: reprStrAux(result, $(cast[ptr cstring](p)^))

-  of tyRange: reprAux(result, p, typ.base, cl)

-  of tyProc, tyPointer:

-    if cast[ppointer](p)^ == nil: add result, "nil"

-    else: add result, reprPointer(cast[ppointer](p)^)

-  else:

-    add result, "(invalid data!)"

-  inc(cl.recdepth)

-

-proc reprAny(p: pointer, typ: PNimType): string =

-  var

-    cl: TReprClosure

-  initReprClosure(cl)

-  result = ""

-  if typ.kind in {tyObject, tyRecord, tyArray, tySet}:

-    reprAux(result, p, typ, cl)

-  else:

-    reprAux(result, addr(p), typ, cl)

-  add result, "\n"

-  deinitReprClosure(cl)

+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2006 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# The generic ``repr`` procedure. It is an invaluable debugging tool.
+
+#proc cstrToNimStrDummy(s: cstring): string {.inline.} =
+#  result = cast[string](cstrToNimStr(s))
+
+proc reprInt(x: int64): string {.compilerproc.} = return $x
+proc reprFloat(x: float): string {.compilerproc.} = return $x
+
+proc reprPointer(x: pointer): string {.compilerproc.} =
+  var buf: array [0..59, char]
+  c_sprintf(buf, "%p", x)
+  return $buf
+
+proc reprStrAux(result: var string, s: string) =
+  if cast[pointer](s) == nil:
+    add result "nil"
+    return
+  add result, reprPointer(cast[pointer](s)) & "\""
+  for c in items(s):
+    case c
+    of '"': add result "\\\""
+    of '\\': add result, "\\\\" # BUGFIX: forgotten
+    of '\10': add result, "\\10\"\n\"" # " \n " # better readability
+    of '\128' .. '\255', '\0'..'\9', '\11'..'\31':
+      add result, "\\" & reprInt(ord(c))
+    else: result.add(c)
+  add result, "\""
+
+proc reprStr(s: string): string {.compilerproc.} =
+  result = ""
+  reprStrAux(result, s)
+
+proc reprBool(x: bool): string {.compilerproc.} =
+  if x: result = "true"
+  else: result = "false"
+
+proc reprChar(x: char): string {.compilerproc.} =
+  result = "\'"
+  case x
+  of '"': add result, "\\\""
+  of '\\': add result, "\\\\"
+  of '\128' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x))
+  else: add result, x
+  add result, "\'"
+
+proc reprEnum(e: int, typ: PNimType): string {.compilerproc.} =
+  if e <% typ.node.len: # BUGFIX
+    result = $typ.node.sons[e].name
+  else:
+    result = $e & " (invalid data!)"
+
+type
+  pbyteArray = ptr array[0.. 0xffff, byte]
+
+proc addSetElem(result: var string, elem: int, typ: PNimType) =
+  case typ.kind
+  of tyEnum: add result, reprEnum(elem, typ)
+  of tyBool: add result, reprBool(bool(elem))
+  of tyChar: add result, reprChar(chr(elem))
+  of tyRange: addSetElem(result, elem, typ.base)
+  of tyInt..tyInt64: add result, reprInt(elem)
+  else: # data corrupt --> inform the user
+    add result, " (invalid data!)"
+
+proc reprSetAux(result: var string, p: pointer, typ: PNimType) =
+  # "typ.slots.len" field is for sets the "first" field
+  var elemCounter = 0  # we need this flag for adding the comma at
+                       # the right places
+  add result, "{"
+  var u: int64
+  case typ.size
+  of 1: u = ze64(cast[ptr int8](p)^)
+  of 2: u = ze64(cast[ptr int16](p)^)
+  of 4: u = ze64(cast[ptr int32](p)^)
+  of 8: u = cast[ptr int64](p)^
+  else:
+    var a = cast[pbyteArray](p)
+    for i in 0 .. typ.size*8-1:
+      if (a[i div 8] and (1 shl (i mod 8))) != 0:
+        if elemCounter > 0: add result, ", "
+        addSetElem(result, i+typ.node.len, typ.base)
+        inc(elemCounter)
+  if typ.size <= 8:
+    for i in 0..sizeof(int64)*8-1:
+      if (u and (1 shl i)) != 0:
+        if elemCounter > 0: add result, ", "
+        addSetElem(result, i+typ.node.len, typ.base)
+        inc(elemCounter)
+  add result, "}"
+
+proc reprSet(p: pointer, typ: PNimType): string {.compilerproc.} =
+  result = ""
+  reprSetAux(result, p, typ)
+
+type
+  TReprClosure {.final.} = object # we cannot use a global variable here
+                                  # as this wouldn't be thread-safe
+    marked: TCellSet
+    recdepth: int       # do not recurse endless
+    indent: int         # indentation
+
+proc initReprClosure(cl: var TReprClosure) =
+  CellSetInit(cl.marked)
+  cl.recdepth = -1      # default is to display everything!
+  cl.indent = 0
+
+proc deinitReprClosure(cl: var TReprClosure) =
+  CellSetDeinit(cl.marked)
+
+proc reprBreak(result: var string, cl: TReprClosure) =
+  add result, "\n"
+  for i in 0..cl.indent-1: add result, ' '
+
+proc reprAux(result: var string, p: pointer, typ: PNimType,
+             cl: var TReprClosure)
+
+proc reprArray(result: var string, p: pointer, typ: PNimType,
+               cl: var TReprClosure) =
+  add result, "["
+  var bs = typ.base.size
+  for i in 0..typ.size div bs - 1:
+    if i > 0: add result, ", "
+    reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), typ.base, cl)
+  add result, "]"
+
+proc reprSequence(result: var string, p: pointer, typ: PNimType,
+                  cl: var TReprClosure) =
+  if p == nil:
+    add result, "nil"
+    return
+  result.add(reprPointer(p) & "[")
+  var bs = typ.base.size
+  for i in 0..cast[PGenericSeq](p).len-1:
+    if i > 0: add result, ", "
+    reprAux(result, cast[pointer](cast[TAddress](p) + GenericSeqSize + i*bs),
+            typ.Base, cl)
+  add result, "]"
+
+
+proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
+                   cl: var TReprClosure) =
+  case n.kind
+  of nkNone: assert(false)
+  of nkSlot:
+    add result, $n.name
+    add result, " = "
+    reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
+  of nkList:
+    for i in 0..n.len-1:
+      if i > 0: add result, ",\n"
+      reprRecordAux(result, p, n.sons[i], cl)
+  of nkCase:
+    var m = selectBranch(p, n)
+    reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
+    if m != nil: reprRecordAux(result, p, m, cl)
+
+proc reprRecord(result: var string, p: pointer, typ: PNimType,
+                cl: var TReprClosure) =
+  add result, "["
+  reprRecordAux(result, p, typ.node, cl)
+  add result, "]"
+
+proc reprRef(result: var string, p: pointer, typ: PNimType,
+             cl: var TReprClosure) =
+  # we know that p is not nil here:
+  var cell = usrToCell(p)
+  add result, "ref " & reprPointer(p)
+  if cell notin cl.marked:
+    # only the address is shown:
+    incl(cl.marked, cell)
+    add result, " --> "
+    reprAux(result, p, typ.base, cl)
+
+proc reprAux(result: var string, p: pointer, typ: PNimType,
+             cl: var TReprClosure) =
+  if cl.recdepth == 0:
+    add result, "..."
+    return
+  dec(cl.recdepth)
+  case typ.kind
+  of tySet: reprSetAux(result, p, typ)
+  of tyArray: reprArray(result, p, typ, cl)
+  of tyTuple, tyPureObject: reprRecord(result, p, typ, cl)
+  of tyObject: 
+    var t = cast[ptr PNimType](p)^
+    reprRecord(result, p, t, cl)
+  of tyRef, tyPtr:
+    assert(p != nil)
+    if cast[ppointer](p)^ == nil: add result, "nil"
+    else: reprRef(result, cast[ppointer](p)^, typ, cl)
+  of tySequence:
+    reprSequence(result, cast[ppointer](p)^, typ, cl)
+  of tyInt: add result, $(cast[ptr int](p)^)
+  of tyInt8: add result, $int(cast[ptr Int8](p)^)
+  of tyInt16: add result, $int(cast[ptr Int16](p)^)
+  of tyInt32: add result, $int(cast[ptr Int32](p)^)
+  of tyInt64: add result, $(cast[ptr Int64](p)^)
+  of tyFloat: add result, $(cast[ptr float](p)^)
+  of tyFloat32: add result, $(cast[ptr float32](p)^)
+  of tyFloat64: add result, $(cast[ptr float64](p)^)
+  of tyEnum: add result, reprEnum(cast[ptr int](p)^, typ)
+  of tyBool: add result, reprBool(cast[ptr bool](p)^)
+  of tyChar: add result, reprChar(cast[ptr char](p)^)
+  of tyString: reprStrAux(result, cast[ptr string](p)^)
+  of tyCString: reprStrAux(result, $(cast[ptr cstring](p)^))
+  of tyRange: reprAux(result, p, typ.base, cl)
+  of tyProc, tyPointer:
+    if cast[ppointer](p)^ == nil: add result, "nil"
+    else: add result, reprPointer(cast[ppointer](p)^)
+  else:
+    add result, "(invalid data!)"
+  inc(cl.recdepth)
+
+proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {.
+                   compilerproc.} =
+  var
+    cl: TReprClosure
+  initReprClosure(cl)
+  result = "["
+  var bs = elemtyp.size
+  for i in 0..length - 1:
+    if i > 0: add result, ", "
+    reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), elemtyp, cl)
+  add result, "]"
+  deinitReprClosure(cl)
+
+proc reprAny(p: pointer, typ: PNimType): string =
+  var
+    cl: TReprClosure
+  initReprClosure(cl)
+  result = ""
+  if typ.kind in {tyObject, tyPureObject, tyTuple, tyArray, tySet}:
+    reprAux(result, p, typ, cl)
+  else:
+    var p = p
+    reprAux(result, addr(p), typ, cl)
+  add result, "\n"
+  deinitReprClosure(cl)
diff --git a/lib/strutils.nim b/lib/strutils.nim
index e2aca01b4..039a06251 100644
--- a/lib/strutils.nim
+++ b/lib/strutils.nim
@@ -7,16 +7,16 @@
 #    distribution, for details about the copyright.
 #
 
-
-
 ## This module contains various string utility routines.
 ## See the module `regexprs` for regular expression support.
+## All the routines here are avaiable for the EMCAScript target
+## too!
 
 {.push debugger:off .} # the user does not want to trace a part
                        # of the standard library!
 
 # copied from excpt.nim, because I don't want to make this template public
-template newException(exceptn, message: expr): expr = 
+template newException(exceptn, message: expr): expr =
   block: # open a new scope
     var
       e: ref exceptn
@@ -153,6 +153,10 @@ proc ParseInt*(s: string): int {.noSideEffect.}
   ## a valid integer, `EInvalidValue` is raised.
   # XXX: make this biggestint!
 
+proc ParseBiggestInt*(s: string): biggestInt {.noSideEffect.}
+  ## Parses a decimal integer value contained in `s`. If `s` is not
+  ## a valid integer, `EInvalidValue` is raised.
+
 proc ParseFloat*(s: string): float {.noSideEffect.}
   ## Parses a decimal floating point value contained in `s`. If `s` is not
   ## a valid floating point number, `EInvalidValue` is raised.
@@ -187,7 +191,7 @@ proc `%` *(formatstr: string, a: openarray[string]): string {.noSideEffect.}
   ##
   ##   "The cat eats fish."
   ##
-  ## The variables are compared with `cmpIgnoreStyle`. `EInvalidValue` is 
+  ## The variables are compared with `cmpIgnoreStyle`. `EInvalidValue` is
   ## raised if an ill-formed format string has been passed to the `%` operator.
 
 proc `%` *(formatstr, a: string): string {.noSideEffect.}
@@ -213,7 +217,13 @@ proc allCharsInSet*(s: string, theSet: TCharSet): bool =
     if not (c in theSet): return false
   return true
 
-proc c_strcmp(a, b: CString): int {.importc: "strcmp", nodecl.}
+proc quoteIfSpaceExists*(s: string): string =
+  ## returns ``'"' & s & '"'`` if `s` contains a space and does not
+  ## start with a quote, else returns `s`
+  if findSubStr(' ', s) >= 0 and s[0] != '"':
+    result = '"' & s & '"'
+  else:
+    result = s
 
 proc startsWith(s, prefix: string): bool =
   var i = 0
@@ -262,7 +272,7 @@ proc findNormalized(x: string, inArray: openarray[string]): int =
   while i < high(inArray):
     if cmpIgnoreStyle(x, inArray[i]) == 0: return i
     inc(i, 2) # incrementing by 1 would probably result in a
-    # security whole ...
+              # security whole ...
   return -1
 
 proc `%`(formatstr: string, a: openarray[string]): string =
@@ -306,11 +316,9 @@ proc `%`(formatstr: string, a: openarray[string]): string =
 
 proc cmpIgnoreCase(a, b: string): int =
   # makes usage of the fact that strings are zero-terminated
-  var
-    aa, bb: char
   for i in 0..len(a)-1:
-    aa = toLower(a[i])
-    bb = toLower(b[i])
+    var aa = toLower(a[i])
+    var bb = toLower(b[i])
     result = ord(aa) - ord(bb)
     if result != 0: break
 
@@ -319,14 +327,13 @@ proc cmpIgnoreCase(a, b: string): int =
 
 proc cmpIgnoreStyle(a, b: string): int =
   var
-    aa, bb: char
     i = 0
     j = 0
   while True:
     while a[i] == '_': inc(i)
     while b[j] == '_': inc(j) # BUGFIX: typo
-    aa = toLower(a[i])
-    bb = toLower(b[j])
+    var aa = toLower(a[i])
+    var bb = toLower(b[j])
     result = ord(aa) - ord(bb)
     if result != 0 or aa == '\0': break
     inc(i)
@@ -475,15 +482,12 @@ proc deleteStr(s: var string, first, last: int) =
 
 # parsing numbers:
 
-proc sprintf(buf, frmt: CString) {.nodecl, importc: "sprintf", varargs.}
-
 proc toHex(x: BiggestInt, len: int): string =
   const
     HexChars = "0123456789ABCDEF"
   var
     shift: BiggestInt
   result = newString(len)
-  shift = 0
   for j in countdown(len-1, 0):
     result[j] = HexChars[toU32(x shr shift) and 0xF]
     shift = shift + 4
@@ -497,11 +501,8 @@ proc rawParseInt(s: string, index: var int): BiggestInt =
   # one more valid negative than prositive integer. Thus we perform the
   # computation as a negative number and then change the sign at the end.
   var
-    i: int
-    sign: BiggestInt
-  i = index
-  # a local i is more efficient than accessing an in out parameter
-  sign = -1
+    i: int = index # a local i is more efficient than accessing a var parameter
+    sign: BiggestInt = -1
   if s[i] == '+':
     inc(i)
   elif s[i] == '-':
@@ -523,10 +524,8 @@ proc rawParseInt(s: string, index: var int): BiggestInt =
 
 proc parseInt(s: string): int =
   var
-    index: int
-    res: BiggestInt
-  index = strStart
-  res = rawParseInt(s, index)
+    index: int = 0
+    res = rawParseInt(s, index)
   if index == -1:
     raise newException(EInvalidValue, "invalid integer: " & s)
   elif (sizeof(int) <= 4) and
@@ -535,17 +534,20 @@ proc parseInt(s: string): int =
   else:
     result = int(res) # convert to smaller integer type
 
+proc ParseBiggestInt(s: string): biggestInt =
+  var
+    index: int = 0
+  result = rawParseInt(s, index)
+  if index == -1:
+    raise newException(EInvalidValue, "invalid integer: " & s)
+
 proc ParseFloat(s: string): float =
   var
-    hd, esign, sign: float
+    esign = 1.0
+    sign = 1.0
     exponent, i: int
     flags: int
   result = 0.0
-  i = 0
-  exponent = 0
-  esign = 1.0
-  flags = 0
-  sign = 1.0
   if s[i] == '+': inc(i)
   elif s[i] == '-':
     sign = -1.0
@@ -558,7 +560,7 @@ proc ParseFloat(s: string): float =
     while s[i] == '_': inc(i)
   # Decimal?
   if s[i] == '.':
-    hd = 1.0
+    var hd = 1.0
     inc(i)
     while s[i] in {'0'..'9'}:
       # Read fractional part
@@ -579,14 +581,14 @@ proc ParseFloat(s: string): float =
     elif s[i] == '-':
       esign = -1.0
       inc(i)
-    if s[i] notin {'0'..'9'}: 
+    if s[i] notin {'0'..'9'}:
       raise newException(EInvalidValue, "invalid float: " & s)
     while s[i] in {'0'..'9'}:
       exponent = exponent * 10 + ord(s[i]) - ord('0')
       inc(i)
       while s[i] == '_': inc(i)
   # Calculate Exponent
-  hd = 1.0
+  var hd = 1.0
   for j in 1..exponent:
     hd = hd * 10.0
   if esign > 0.0: result = result * hd
@@ -600,11 +602,10 @@ proc toOct*(x: BiggestInt, len: int): string =
   ## converts `x` into its octal representation. The resulting string is
   ## always `len` characters long. No leading ``0c`` prefix is generated.
   var
-    mask, shift: BiggestInt
+    mask: BiggestInt = 7
+    shift: BiggestInt = 0
   assert(len > 0)
   result = newString(len)
-  mask = 7
-  shift = 0
   for j in countdown(len-1, 0):
     result[j] = chr(int((x and mask) shr shift) + ord('0'))
     shift = shift + 3
@@ -614,11 +615,10 @@ proc toBin*(x: BiggestInt, len: int): string =
   ## converts `x` into its binary representation. The resulting string is
   ## always `len` characters long. No leading ``0b`` prefix is generated.
   var
-    mask, shift: BiggestInt
+    mask: BiggestInt = 1
+    shift: BiggestInt = 0
   assert(len > 0)
   result = newString(len)
-  mask = 1
-  shift = 0
   for j in countdown(len-1, 0):
     result[j] = chr(int((x and mask) shr shift) + ord('0'))
     shift = shift + 1
diff --git a/lib/sysio.nim b/lib/sysio.nim
index bb028b0de..6da47eb20 100644
--- a/lib/sysio.nim
+++ b/lib/sysio.nim
@@ -33,10 +33,6 @@ var
   IOFBF {.importc: "_IOFBF", nodecl.}: cint
   IONBF {.importc: "_IONBF", nodecl.}: cint
 
-# copied here to remove dependancy on strutils:
-#proc toNimstr(x: Cstring, len: int): string {.
-#  noSideEffect, importc: "toNimStr".}
-
 proc rawReadLine(f: TFile, result: var string) {.noStatic.} =
   # of course this could be optimized a bit; but IO is slow anyway...
   # and it was difficult to get this CORRECT with Ansi C's methods
@@ -81,6 +77,8 @@ proc write(f: TFile, b: bool) =
   else: write(f, "false")
 proc write(f: TFile, r: float) = fprintf(f, "%g", r)
 proc write(f: TFile, c: Char) = putc(c, f)
+proc write(f: TFile, a: openArray[string]) =
+  for x in items(a): write(f, x)
 
 proc EndOfFile(f: TFile): bool =
   # do not blame me; blame the ANSI C standard this is so brain-damaged
@@ -93,6 +91,11 @@ proc EndOfFile(f: TFile): bool =
 proc writeln[Ty](f: TFile, x: Ty) =
   write(f, x)
   write(f, "\n")
+
+proc writeln[Ty](f: TFile, x: openArray[Ty]) =
+  write(f, x)
+  write(f, "\n")
+
 proc echo[Ty](x: Ty) = writeln(stdout, x)
 
 # interface to the C procs:
@@ -128,7 +131,6 @@ proc ftell(f: TFile): int {.importc: "ftell", noDecl.}
 
 proc fwrite(buf: Pointer, size, n: int, f: TFile): int {.
   importc: "fwrite", noDecl.}
-# size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);
 
 proc readBuffer(f: TFile, buffer: pointer, len: int): int =
   result = fread(buffer, 1, len, f)
@@ -140,9 +142,11 @@ proc ReadChars(f: TFile, a: var openarray[char], start, len: int): int =
   result = readBuffer(f, addr(a[start]), len)
 
 proc writeBytes(f: TFile, a: openarray[byte], start, len: int): int =
-  result = writeBuffer(f, addr(a[start]), len)
+  var x = cast[ptr array[0..1000_000_000, byte]](a)
+  result = writeBuffer(f, addr(x[start]), len)
 proc writeChars(f: TFile, a: openarray[char], start, len: int): int =
-  result = writeBuffer(f, addr(a[start]), len)
+  var x = cast[ptr array[0..1000_000_000, byte]](a)
+  result = writeBuffer(f, addr(x[start]), len)
 proc writeBuffer(f: TFile, buffer: pointer, len: int): int =
   result = fwrite(buffer, 1, len, f)
 
diff --git a/lib/sysstr.nim b/lib/sysstr.nim
index 0ff43216c..a3e5ab9f8 100644
--- a/lib/sysstr.nim
+++ b/lib/sysstr.nim
@@ -16,7 +16,7 @@
 # the programmer may not want
 
 type
-  TStringDesc {.importc, nodecl.} = record
+  TStringDesc {.importc, nodecl, final.} = object
     len, space: int # len and space without counting the terminating zero
     data: array[0..0, char] # for the '\0' character
 
@@ -25,7 +25,6 @@ type
 # implementation:
 
 proc resize(old: int): int {.inline.} =
-  assert(old < 65536 * 4)
   if old <= 0: return 1
   elif old < 65536: return old * 2
   else: return old * 3 div 2 # for large arrays * 3/2 is better
@@ -64,6 +63,7 @@ proc cstrToNimstr(str: CString): mstring {.compilerProc.} =
   return toNimstr(str, c_strlen(str))
 
 proc copyString(src: mstring): mstring {.compilerProc.} =
+  if src == nil: return nil
   result = rawNewString(src.space)
   result.len = src.len
   c_memcpy(result.data, src.data, (src.len + 1) * sizeof(Char))
@@ -220,7 +220,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
   result.len = newLen
 
 # --------------- other string routines ----------------------------------
-proc `$`(x: int): string =
+proc nimIntToStr(x: int): string {.compilerproc.} =
   result = newString(sizeof(x)*4)
   var i = 0
   var y = x
@@ -238,14 +238,12 @@ proc `$`(x: int): string =
   for j in 0..i div 2 - 1:
     swap(result[j], result[i-j-1])
 
-{.push warnings: off.}
-proc `$`(x: float): string =
+proc nimFloatToStr(x: float): string {.compilerproc.} =
   var buf: array [0..59, char]
   c_sprintf(buf, "%#g", x)
   return $buf
-{.pop.}
 
-proc `$`(x: int64): string =
+proc nimInt64ToStr(x: int64): string {.compilerproc.} =
   # we don't rely on C's runtime here as some C compiler's
   # int64 support is weak
   result = newString(sizeof(x)*4)
@@ -265,19 +263,13 @@ proc `$`(x: int64): string =
   for j in 0..i div 2 - 1:
     swap(result[j], result[i-j-1])
 
-proc `$`(x: bool): string =
-  if x: result = "true"
-  else: result = "false"
+proc nimBoolToStr(x: bool): string {.compilerproc.} =
+  return if x: "true" else: "false"
 
-proc `$`(x: char): string =
+proc nimCharToStr(x: char): string {.compilerproc.} =
   result = newString(1)
   result[0] = x
 
-proc `$`(x: string): string =
-  # this is useful for generic code!
-  return x
-
-
 proc binaryStrSearch(x: openarray[string], y: string): int {.compilerproc.} =
   var
     a = 0
diff --git a/lib/system.nim b/lib/system.nim
index 8e8fc5d6d..285b921f8 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -58,10 +58,10 @@ proc new*[T](a: var ref T) {.magic: "New".}
 proc new*[T](a: var ref T, finalizer: proc (x: ref T)) {.magic: "NewFinalize".}
   ## creates a new object of type ``T`` and returns a safe (traced)
   ## reference to it in ``a``. When the garbage collector frees the object,
-  ## `finalizer` is called. The `finalizer` may not keep a reference to the 
+  ## `finalizer` is called. The `finalizer` may not keep a reference to the
   ## object pointed to by `x`. The `finalizer` cannot prevent the GC from
   ## freeing the object. Note: The `finalizer` refers to the type `T`, not to
-  ## the object! This means that for each object of type `T` the finalizer 
+  ## the object! This means that for each object of type `T` the finalizer
   ## will be called!
 
 # for low and high the return type T may not be correct, but
@@ -86,7 +86,6 @@ type
                                        ## length field.
   seq*{.magic: "Seq".}[T]  ## Generic type to construct sequences.
   set*{.magic: "Set".}[T]  ## Generic type to construct bit sets.
-  tuple*{.magic: "Tuple".}[T]  ## Generic type to construct tuple types.
 
   Byte* = Int8 ## this is an alias for ``int8``, that is a signed
                ## int 8 bits wide.
@@ -104,14 +103,15 @@ type
                     ## objects that have no ancestor are allowed.
   PObject* = ref TObject ## reference to TObject
 
-  E_Base* {.compilerproc.} = object of TObject ## base exception class; 
+  E_Base* {.compilerproc.} = object of TObject ## base exception class;
                                                ## each exception has to
                                                ## inherit from `E_Base`.
     name*: cstring            ## The exception's name is its Nimrod identifier.
                               ## This field is filled automatically in the
                               ## ``raise`` statement.
-    msg*: cstring             ## the exception's message. Not providing an
-                              ## exception message is bad style.
+    msg* {.exportc: "message".}: cstring ## the exception's message. Not
+                                         ## providing an
+                                         ## exception message is bad style.
 
   EAsynch* = object of E_Base ## Abstract exception class for
                               ## *asynchronous exceptions* (interrupts).
@@ -129,18 +129,21 @@ type
                                            ## could not be fullfilled.
   EArithmetic* = object of ESynch       ## raised if any kind of arithmetic
                                         ## error occured.
-  EDivByZero* = object of EArithmetic   ## is the exception class for integer
-                                        ## divide-by-zero errors.
-  EOverflow* = object of EArithmetic    ## is the exception class for integer
-                                        ## calculations whose results are too
-                                        ## large to fit in the provided bits.
-
-  EAccessViolation* = object of ESynch  ## the exception class for
-                                        ## invalid memory access errors
-
-  EAssertionFailed* = object of ESynch  ## is the exception class for Assert
-                                        ## procedures that is raised if the
-                                        ## assertion proves wrong
+  EDivByZero* {.compilerproc.} =
+    object of EArithmetic ## is the exception class for integer divide-by-zero
+                          ## errors.
+  EOverflow* {.compilerproc.} =
+    object of EArithmetic  ## is the exception class for integer calculations
+                           ## whose results are too large to fit in the
+                           ## provided bits.
+
+  EAccessViolation* {.compilerproc.} =
+    object of ESynch ## the exception class for invalid memory access errors
+
+  EAssertionFailed* {.compilerproc.} =
+    object of ESynch  ## is the exception class for Assert
+                      ## procedures that is raised if the
+                      ## assertion proves wrong
 
   EControlC* = object of EAsynch        ## is the exception class for Ctrl+C
                                         ## key presses in console applications.
@@ -154,6 +157,9 @@ type
 
   EInvalidIndex* = object of ESynch     ## is raised if an array index is out
                                         ## of bounds.
+  EInvalidField* = object of ESynch     ## is raised if a record field is not
+                                        ## accessible because its dicriminant's
+                                        ## value does not fit.
 
   EOutOfRange* = object of ESynch       ## is raised if a range check error
                                         ## occured.
@@ -164,13 +170,13 @@ type
   ENoExceptionToReraise* = object of ESynch ## is raised if there is no
                                             ## exception to reraise.
 
-  EInvalidObjectAssignment* = object of ESynch ## is raised if an object
-                                               ## gets assigned to its
-                                               ## farther's object.
+  EInvalidObjectAssignment* =
+    object of ESynch ## is raised if an object gets assigned to its
+                     ## farther's object.
 
-  EInvalidObjectConversion* = object of ESynch ## is raised if an object is
-                                               ## converted to an incompatible
-                                               ## object type.
+  EInvalidObjectConversion* =
+    object of ESynch ## is raised if an object is converted to an incompatible
+                     ## object type.
 
   TResult* = enum Failure, Success
 
@@ -394,7 +400,7 @@ proc in_Operator*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.}
   ##   writeln(stdout, 'b' in s)
   ##
   ## If ``in`` had been declared as ``[T](elem: T, s: set[T])`` then ``T`` would
-  ## have been bound to ``char``. But ``s`` is not compatible with type
+  ## have been bound to ``char``. But ``s`` is not compatible to type
   ## ``set[char]``! The solution is to bind ``T`` to ``range['a'..'z']``. This
   ## is achieved by reversing the parameters for ``in_operator``; ``in`` then
   ## passes its arguments in reverse order.
@@ -418,25 +424,31 @@ proc cmp*(x, y: string): int {.noSideEffect.}
   ## Compare proc for strings. More efficient than the generic version.
 
 # concat operator:
-proc `&` * (x: string, y: char): string {.
-  magic: "ConStrStr", noSideEffect, returnsNew.}
-proc `&` * (x: char, y: char): string {.
-  magic: "ConStrStr", noSideEffect, returnsNew.}
-proc `&` * (x, y: string): string {.
-  magic: "ConStrStr", noSideEffect, returnsNew.}
-proc `&` * (x: char, y: string): string {.
-  magic: "ConStrStr", noSideEffect, returnsNew.}
-  ## is the `concatenation operator`. It
-  ## concatenates `x` and `y`.
+proc `&` * (x: string, y: char): string {.magic: "ConStrStr", noSideEffect.}
+proc `&` * (x: char, y: char): string {.magic: "ConStrStr", noSideEffect.}
+proc `&` * (x, y: string): string {.magic: "ConStrStr", noSideEffect.}
+proc `&` * (x: char, y: string): string {.magic: "ConStrStr", noSideEffect.}
+  ## is the `concatenation operator`. It concatenates `x` and `y`.
 
 proc add * (x: var string, y: char) {.magic: "AppendStrCh".}
 proc add * (x: var string, y: string) {.magic: "AppendStrStr".}
 
-proc add* (x: var string, y: cstring) =
-  var i = 0
-  while y[i] != '\0':
-    add(x, y[i])
-    inc(i)
+when not defined(ECMAScript):
+  proc add* (x: var string, y: cstring) =
+    var i = 0
+    while y[i] != '\0':
+      add(x, y[i])
+      inc(i)
+else:
+  proc add* (x: var string, y: cstring) {.pure.} =
+    asm """
+      var len = `x`[0].length-1;
+      for (var i = 0; i < `y`.length; ++i) {
+        `x`[0][len] = `y`.charCodeAt(i);
+        ++len;
+      }
+      `x`[0][len] = 0
+    """
 
 proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem".}
 proc add *[T](x: var seq[T], y: seq[T]) {.magic: "AppendSeqSeq".}
@@ -493,7 +505,7 @@ type # these work for most platforms:
 
   TEndian* = enum ## is a type describing the endianness of a processor.
     littleEndian, bigEndian
-    
+
   PFloat32* = ptr Float32 ## an alias for ``ptr float32``
   PFloat64* = ptr Float64 ## an alias for ``ptr float64``
   PInt64* = ptr Int64 ## an alias for ``ptr int64``
@@ -675,20 +687,27 @@ proc swap*[T](a, b: var T) {.magic: "Swap".}
   ## swaps the values `a` and `b`. This is often more efficient than
   ## ``tmp = a; a = b; b = tmp``. Particularly useful for sorting algorithms.
 
-proc ze*(x: int8): int {.magic: "Ze", noSideEffect.}
+proc ze*(x: int8): int {.magic: "Ze8ToI", noSideEffect.}
   ## zero extends a smaller integer type to ``int``. This treats `x` as
   ## unsigned.
-proc ze*(x: int16): int {.magic: "Ze", noSideEffect.}
+proc ze*(x: int16): int {.magic: "Ze16ToI", noSideEffect.}
   ## zero extends a smaller integer type to ``int``. This treats `x` as
   ## unsigned.
 
-proc ze64*(x: int32): int64 {.magic: "Ze64", noSideEffect.}
+proc ze64*(x: int8): int64 {.magic: "Ze8ToI64", noSideEffect.}
   ## zero extends a smaller integer type to ``int64``. This treats `x` as
   ## unsigned.
-proc ze*(x: int): int64 {.magic: "Ze", noDecl, noSideEffect.}
+proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect.}
+  ## zero extends a smaller integer type to ``int64``. This treats `x` as
+  ## unsigned.
+
+proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect.}
+  ## zero extends a smaller integer type to ``int64``. This treats `x` as
+  ## unsigned.
+proc ze64*(x: int): int64 {.magic: "ZeIToI64", noDecl, noSideEffect.}
   ## zero extends a smaller integer type to ``int64``. This treats `x` as
   ## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``.
-  ## (This is the case an 64 bit processors.)
+  ## (This is the case on 64 bit processors.)
 
 proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.}
   ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits
@@ -749,39 +768,39 @@ template `>%` *(x, y: expr): expr = y <% x
   ## treats `x` and `y` as unsigned and compares them.
   ## Returns true iff ``unsigned(x) > unsigned(y)``.
 
-proc `$` *(x: int): string {.noSideEffect.}
+proc `$` *(x: int): string {.magic: "IntToStr", noSideEffect.}
   ## The stingify operator for an integer argument. Returns `x`
   ## converted to a decimal string.
 
-proc `$` *(x: int64): string {.noSideEffect.}
+proc `$` *(x: int64): string {.magic: "Int64ToStr", noSideEffect.}
   ## The stingify operator for an integer argument. Returns `x`
   ## converted to a decimal string.
 
-proc `$` *(x: float): string {.noSideEffect.}
+proc `$` *(x: float): string {.magic: "FloatToStr", noSideEffect.}
   ## The stingify operator for a float argument. Returns `x`
   ## converted to a decimal string.
 
-proc `$` *(x: bool): string {.noSideEffect.}
+proc `$` *(x: bool): string {.magic: "BoolToStr", noSideEffect.}
   ## The stingify operator for a boolean argument. Returns `x`
   ## converted to the string "false" or "true".
 
-proc `$` *(x: char): string {.noSideEffect.}
+proc `$` *(x: char): string {.magic: "CharToStr", noSideEffect.}
   ## The stingify operator for a character argument. Returns `x`
   ## converted to a string.
 
-proc `$` *(x: Cstring): string {.noSideEffect, importc: "cstrToNimstr".}
+proc `$` *(x: Cstring): string {.magic: "CStrToStr", noSideEffect.}
   ## The stingify operator for a CString argument. Returns `x`
   ## converted to a string.
 
-proc `$` *(x: string): string {.noSideEffect.}
+proc `$` *(x: string): string {.magic: "StrToStr", noSideEffect.}
   ## The stingify operator for a string argument. Returns `x`
   ## as it is. This operator is useful for generic code, so
-  ## that ``$expr`` works if ``expr`` is already a string.
+  ## that ``$expr`` also works if ``expr`` is already a string.
 
 # undocumented:
 proc getRefcount*[T](x: ref T): int {.importc: "getRefcount".}
   ## retrieves the reference count of an heap-allocated object. The
-  ## value is implementation-dependant. 
+  ## value is implementation-dependant.
 
 #proc writeStackTrace() {.export: "writeStackTrace".}
 proc getCurrentExceptionMsg*(): string {.exportc.}
@@ -790,10 +809,12 @@ proc getCurrentExceptionMsg*(): string {.exportc.}
 
 # new constants:
 const
-  inf* = 1.0 / 0.0
+  inf* {.magic: "Inf".} = 0.0
     ## contains the IEEE floating point value of positive infinity.
-  nan* = 0.0 / 0.0
-    ## contains the IEEE floating point value of *Not A Number*. Note
+  neginf* {.magic: "NegInf".} = 0.0
+    ## contains the IEEE floating point value of negative infinity.
+  nan* {.magic: "NaN".} = 0.0
+    ## contains an IEEE floating point value of *Not A Number*. Note
     ## that you cannot compare a floating point value to this value
     ## and expect a reasonable result - use the `classify` procedure
     ## in the module ``math`` for checking for NaN.
@@ -805,18 +826,18 @@ var
     ## Only code compiled with the ``debugger:on`` switch calls this hook.
 
 # GC interface:
-when defined(Unix) and not defined(macosX) and not defined(linux): 
+when defined(Unix) and not defined(macosX) and not defined(linux):
   # BUGFIX for macosX
   {.define: nativeDL.}
 
 when defined(useDL) or defined(nativeDL):
   proc getOccupiedMem*(): int
     ## returns the number of bytes that are owned by the process and hold data.
-  
+
   proc getFreeMem*(): int
     ## returns the number of bytes that are owned by the process, but do not
     ## hold any meaningful data.
-  
+
   proc getTotalMem*(): int
     ## returns the number of bytes that are owned by the process.
 
@@ -885,11 +906,22 @@ iterator items*(a: cstring): char {.inline.} =
     yield a[i]
     inc(i)
 
+
+proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil".}
+proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".}
+proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil".}
+proc isNil*[T](x: ptr T): bool {.noSideEffect, magic: "IsNil".}
+proc isNil*(x: pointer): bool {.noSideEffect, magic: "IsNil".}
+proc isNil*(x: cstring): bool {.noSideEffect, magic: "IsNil".}
+  ## Fast check whether `x` is nil. This is sometimes more efficient than
+  ## ``== nil``.
+
+
 # Fixup some magic symbols here:
 {.fixup_system.} # This is an undocumented pragma that can only be used
                  # once in the system module.
 
-proc `&` *[T](x, y: seq[T]): seq[T] {.noSideEffect, returnsNew.} =
+proc `&` *[T](x, y: seq[T]): seq[T] {.noSideEffect.} =
   result = []
   setLen(result, x.len + y.len)
   for i in 0..x.len-1:
@@ -897,110 +929,74 @@ proc `&` *[T](x, y: seq[T]): seq[T] {.noSideEffect, returnsNew.} =
   for i in 0..y.len-1:
     result[i] = y[i]
 
-proc `&` *[T](x: seq[T], y: T): seq[T] {.noSideEffect, returnsNew.} =
+proc `&` *[T](x: seq[T], y: T): seq[T] {.noSideEffect.} =
   result = []
   setLen(x.len + 1)
   for i in 0..x.len-1:
     result[i] = x[i]
   result[x.len] = y
 
-proc `&` *[T](x: T, y: seq[T]): seq[T] {.noSideEffect, returnsNew.} =
+proc `&` *[T](x: T, y: seq[T]): seq[T] {.noSideEffect.} =
   result = []
   setLen(y.len + 1)
   for i in 0..y.len-1:
     result[i] = y[i]
   result[y.len] = x
 
-proc `&` *[T](x, y: T): seq[T] {.noSideEffect, returnsNew.} =
+proc `&` *[T](x, y: T): seq[T] {.noSideEffect.} =
   return [x, y]
 
+when not defined(ECMAScript): # XXX make this local procs
+  proc seqToPtr*[T](x: seq[T]): pointer {.inline, nosideeffect.} =
+    result = cast[pointer](x)
+else:
+  proc seqToPtr*[T](x: seq[T]): pointer {.pure, nosideeffect.} =
+    asm """return `x`"""
+
 proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} =
   ## Generic equals operator for sequences: relies on a equals operator for
   ## the element type `T`.
-  if cast[pointer](x) == cast[pointer](y):
+  if seqToPtr(x) == seqToPtr(y):
     result = true
-  elif cast[pointer](x) == nil or cast[pointer](y) == nil:
+  elif seqToPtr(x) == nil or seqToPtr(y) == nil:
     result = false
   elif x.len == y.len:
     for i in 0..x.len-1:
       if x[i] != y[i]: return false
     result = true
 
-{.push checks: off, line_dir: off, debugger: off,
-  assertions: on.}  # obviously we cannot generate checking operations here :-)
-                    # because it would yield into an endless recursion
-                    # however, stack-traces are available for most parts
-                    # of the code
-
-include hti
-
-proc initGC()
-
-var
-  strDesc: TNimType
-
-strDesc.size = sizeof(string)
-strDesc.kind = tyString
-initGC() # BUGFIX: need to be called here!
-
-{.push stack_trace: off.}
+# ----------------- FPU ------------------------------------------------------
 
-include ansi_c
+#proc disableFPUExceptions*()
+# disables all floating point unit exceptions
 
-proc cmp(x, y: string): int =
-  return c_strcmp(x, y)
+#proc enableFPUExceptions*()
+# enables all floating point unit exceptions
 
-when defined(windows):
-  # work-around C's sucking abstraction:
-  # BUGFIX: stdin and stdout should be binary files!
-  const pccHack = if defined(pcc): "_" else: "" # Hack for PCC
-  proc setmode(handle, mode: int) {.importc: pccHack & "setmode",
-                                    header: "<io.h>".}
-  proc fileno(f: C_TextFileStar): int {.importc: pccHack & "fileno",
-                                        header: "<fcntl.h>".}
-  var
-    O_BINARY {.importc: pccHack & "O_BINARY", nodecl.}: int
-
-  # we use binary mode in Windows:
-  setmode(fileno(c_stdin), O_BINARY)
-  setmode(fileno(c_stdout), O_BINARY)
-
-when defined(endb):
-  proc endbStep()
-
-
-template newException(exceptn, message: expr): expr =
-  block: # open a new scope
-    var
-      e: ref exceptn
-    new(e)
-    e.msg = message
-    e
-    
 # ----------------- GC interface ---------------------------------------------
 
-proc GC_disable*() 
+proc GC_disable*()
   ## disables the GC. If called n-times, n calls to `GC_enable` are needed to
   ## reactivate the GC. Note that in most circumstances one should only disable
-  ## the mark and sweep phase with `GC_disableMarkAndSweep`. 
+  ## the mark and sweep phase with `GC_disableMarkAndSweep`.
 
-proc GC_enable*() 
+proc GC_enable*()
   ## enables the GC again.
-  
+
 proc GC_fullCollect*()
-  ## forces a full garbage collection pass. 
+  ## forces a full garbage collection pass.
   ## Ordinary code does not need to call this.
 
 type
   TGC_Strategy* = enum ## the strategy the GC should use for the application
-    gcThroughput ,     ## optimize for throughput
+    gcThroughput,      ## optimize for throughput
     gcResponsiveness,  ## optimize for responsiveness (default)
     gcOptimizeTime,    ## optimize for speed
     gcOptimizeSpace    ## optimize for memory footprint
 
 proc GC_setStrategy*(strategy: TGC_Strategy)
   ## tells the GC the desired strategy for the application.
-  
+
 proc GC_enableMarkAndSweep*()
 proc GC_disableMarkAndSweep*()
   ## the current implementation uses a reference counting garbage collector
@@ -1009,176 +1005,242 @@ proc GC_disableMarkAndSweep*()
   ## does not create cycles. Thus the mark and sweep phase can be deactivated
   ## and activated separately from the rest of the GC.
 
-    
-# ----------------- IO Part --------------------------------------------------
 
-type
-  CFile {.importc: "FILE", nodecl.} = record  # empty record for
-                                              # data hiding
-  TFile* = ptr CFile ## The type representing a file handle.
-
-  TFileMode* = enum           ## The file mode when opening a file.
-    fmRead,                   ## Open the file for read access only.
-    fmWrite,                  ## Open the file for write access only.
-    fmReadWrite,              ## Open the file for read and write access.
-                              ## If the file does not exist, it will be
-                              ## created.
-    fmReadWriteExisting,      ## Open the file for read and write access.
-                              ## If the file does not exist, it will not be
-                              ## created.
-    fmAppend                  ## Open the file for writing only; append data
-                              ## at the end.
-
-# text file handling:
-var
-  stdin* {.importc: "stdin", noDecl.}: TFile   ## The standard input stream.
-  stdout* {.importc: "stdout", noDecl.}: TFile ## The standard output stream.
-  stderr* {.importc: "stderr", noDecl.}: TFile
-    ## The standard error stream.
-    ##
-    ## Note: In my opinion, this should not be used -- the concept of a
-    ## separate error stream is a design flaw of UNIX. A seperate *message
-    ## stream* is a good idea, but since it is named ``stderr`` there are few
-    ## programs out there that distinguish properly between ``stdout`` and
-    ## ``stderr``. So, that's what you get if you don't name your variables
-    ## appropriately. It also annoys people if redirection via ``>output.txt``
-    ## does not work because the program writes to ``stderr``.
-
-proc OpenFile*(f: var TFile, filename: string,
-               mode: TFileMode = fmRead, bufSize: int = -1): Bool
-  ## Opens a file named `filename` with given `mode`.
-  ##
-  ## Default mode is readonly. Returns true iff the file could be opened.
-  ## This throws no exception if the file could not be opened. The reason is
-  ## that the programmer needs to provide an appropriate error message anyway
-  ## (yes, even in scripts).
-
-proc CloseFile*(f: TFile) {.importc: "fclose", nodecl.}
-  ## Closes the file.
-proc EndOfFile*(f: TFile): Bool
-  ## Returns true iff `f` is at the end.
-proc readChar*(f: TFile): char {.importc: "fgetc", nodecl.}
-  ## Reads a single character from the stream `f`. If the stream
-  ## has no more characters, `EEndOfFile` is raised.
-proc FlushFile*(f: TFile) {.importc: "fflush", noDecl.}
-  ## Flushes `f`'s buffer.
-
-proc readFile*(filename: string): string
-  ## Opens a file name `filename` for reading. Then reads the
-  ## file's content completely into a string and
-  ## closes the file afterwards. Returns the string. Returns nil if there was
-  ## an error. Does not throw an IO exception.
-
-proc write*(f: TFile, r: float)
-proc write*(f: TFile, i: int)
-proc write*(f: TFile, s: string)
-proc write*(f: TFile, b: Bool)
-proc write*(f: TFile, c: char)
-proc write*(f: TFile, c: cstring)
-  ## Writes a value to the file `f`. May throw an IO exception.
-
-proc readLine*(f: TFile): string
-  ## reads a line of text from the file `f`. May throw an IO exception.
-  ## Reading from an empty file buffer, does not throw an exception, but
-  ## returns nil. A line of text may be delimited by ``CR``, ``LF`` or
-  ## ``CRLF``. The newline character(s) are not part of the returned string.
-
-proc writeln*[Ty](f: TFile, x: Ty) {.inline.}
-  ## writes a value `x` to `f` and then writes "\n". May throw an IO exception.
+{.push checks: off, line_dir: off, debugger: off,
+  assertions: on.}  # obviously we cannot generate checking operations here :-)
+                    # because it would yield into an endless recursion
+                    # however, stack-traces are available for most parts
+                    # of the code
+
 proc echo*[Ty](x: Ty) {.inline.}
-  ## equivalent to ``writeln(stdout, x); flush(stdout)``.
-
-proc getFileSize*(f: TFile): int64
-  ## retrieves the file size (in bytes) of `f`.
-
-proc ReadBytes*(f: TFile, a: var openarray[byte], start, len: int): int
-  ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
-  ## the actual number of bytes that have been read which may be less than
-  ## `len` (if not as many bytes are remaining), but not greater.
-
-proc ReadChars*(f: TFile, a: var openarray[char], start, len: int): int
-  ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
-  ## the actual number of bytes that have been read which may be less than
-  ## `len` (if not as many bytes are remaining), but not greater.
-
-proc readBuffer*(f: TFile, buffer: pointer, len: int): int
-  ## reads `len` bytes into the buffer pointed to by `buffer`. Returns
-  ## the actual number of bytes that have been read which may be less than
-  ## `len` (if not as many bytes are remaining), but not greater.
-
-proc writeBytes*(f: TFile, a: openarray[byte], start, len: int): int
-  ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
-  ## the number of actual written bytes, which may be less than `len` in case
-  ## of an error.
-
-proc writeChars*(f: tFile, a: openarray[char], start, len: int): int
-  ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
-  ## the number of actual written bytes, which may be less than `len` in case
-  ## of an error.
-
-proc writeBuffer*(f: TFile, buffer: pointer, len: int): int
-  ## writes the bytes of buffer pointed to by the parameter `buffer` to the
-  ## file `f`. Returns the number of actual written bytes, which may be less
-  ## than `len` in case of an error.
-
-proc setFilePos*(f: TFile, pos: int64)
-  ## sets the position of the file pointer that is used for read/write
-  ## operations. The file's first byte has the index zero.
-
-proc getFilePos*(f: TFile): int64
-  ## retrieves the current position of the file pointer that is used to
-  ## read from the file `f`. The file's first byte has the index zero.
-
-include sysio
-
-iterator lines*(filename: string): string =
-  ## Iterate over any line in the file named `filename`.
-  ## If the file does not exist `EIO` is raised.
-  var
-    f: TFile
-  if not openFile(f, filename):
-    raise newException(EIO, "cannot open: " & filename)
-  var res = ""
-  while not endOfFile(f):
-    rawReadLine(f, res)
-    yield res
-  CloseFile(f)
+  ## equivalent to ``writeln(stdout, x); flush(stdout)``. BUT: This is
+  ## available for the ECMAScript target too!
+
+
+template newException(exceptn, message: expr): expr =
+  block: # open a new scope
+    var
+      e: ref exceptn
+    new(e)
+    e.msg = message
+    e
 
-# ----------------------------------------------------------------------------
+when not defined(EcmaScript):
 
-include excpt
-# we cannot compile this with stack tracing on
-# as it would recurse endlessly!
-include arithm
-{.pop.} # stack trace
+  include hti
 
-# sequence type declarations here because the GC needs them too:
-type
-  TGenericSeq {.importc, nodecl.} = record
-    len, space: int
+  proc initGC()
 
-  PGenericSeq {.importc, nodecl.} = ptr TGenericSeq
+  var
+    strDesc: TNimType
 
-const
-  GenericSeqSize = (2 * sizeof(int))
+  strDesc.size = sizeof(string)
+  strDesc.kind = tyString
+  initGC() # BUGFIX: need to be called here!
 
-when not defined(boehmgc) and not defined(nogc):
-  include gc
+  {.push stack_trace: off.}
 
-include sysstr
-include assign
-include dyncalls
-include repr
+  include ansi_c
 
-# we have to implement it here after gentostr for the cstrToNimStrDummy proc
-proc getCurrentExceptionMsg(): string =
-  if excHandler == nil: return ""
-  return $excHandler.exc.msg
+  proc cmp(x, y: string): int =
+    return c_strcmp(x, y)
 
-{.push stack_trace: off.}
-when defined(endb):
-  include debugger
-{.pop.} # stacktrace
-{.pop.} # checks
+  when defined(windows):
+    # work-around C's sucking abstraction:
+    # BUGFIX: stdin and stdout should be binary files!
+    const pccHack = if defined(pcc): "_" else: "" # Hack for PCC
+    proc setmode(handle, mode: int) {.importc: pccHack & "setmode",
+                                      header: "<io.h>".}
+    proc fileno(f: C_TextFileStar): int {.importc: pccHack & "fileno",
+                                          header: "<fcntl.h>".}
+    var
+      O_BINARY {.importc: pccHack & "O_BINARY", nodecl.}: int
+
+    # we use binary mode in Windows:
+    setmode(fileno(c_stdin), O_BINARY)
+    setmode(fileno(c_stdout), O_BINARY)
+
+  when defined(endb):
+    proc endbStep()
+
+  # ----------------- IO Part --------------------------------------------------
+
+  type
+    CFile {.importc: "FILE", nodecl, final.} = object  # empty record for
+                                                       # data hiding
+    TFile* = ptr CFile ## The type representing a file handle.
+
+    TFileMode* = enum           ## The file mode when opening a file.
+      fmRead,                   ## Open the file for read access only.
+      fmWrite,                  ## Open the file for write access only.
+      fmReadWrite,              ## Open the file for read and write access.
+                                ## If the file does not exist, it will be
+                                ## created.
+      fmReadWriteExisting,      ## Open the file for read and write access.
+                                ## If the file does not exist, it will not be
+                                ## created.
+      fmAppend                  ## Open the file for writing only; append data
+                                ## at the end.
+
+  # text file handling:
+  var
+    stdin* {.importc: "stdin", noDecl.}: TFile   ## The standard input stream.
+    stdout* {.importc: "stdout", noDecl.}: TFile ## The standard output stream.
+    stderr* {.importc: "stderr", noDecl.}: TFile
+      ## The standard error stream.
+      ##
+      ## Note: In my opinion, this should not be used -- the concept of a
+      ## separate error stream is a design flaw of UNIX. A seperate *message
+      ## stream* is a good idea, but since it is named ``stderr`` there are few
+      ## programs out there that distinguish properly between ``stdout`` and
+      ## ``stderr``. So, that's what you get if you don't name your variables
+      ## appropriately. It also annoys people if redirection via ``>output.txt``
+      ## does not work because the program writes to ``stderr``.
+
+  proc OpenFile*(f: var TFile, filename: string,
+                 mode: TFileMode = fmRead, bufSize: int = -1): Bool
+    ## Opens a file named `filename` with given `mode`.
+    ##
+    ## Default mode is readonly. Returns true iff the file could be opened.
+    ## This throws no exception if the file could not be opened. The reason is
+    ## that the programmer needs to provide an appropriate error message anyway
+    ## (yes, even in scripts).
+
+  proc CloseFile*(f: TFile) {.importc: "fclose", nodecl.}
+    ## Closes the file.
+  proc EndOfFile*(f: TFile): Bool
+    ## Returns true iff `f` is at the end.
+  proc readChar*(f: TFile): char {.importc: "fgetc", nodecl.}
+    ## Reads a single character from the stream `f`. If the stream
+    ## has no more characters, `EEndOfFile` is raised.
+  proc FlushFile*(f: TFile) {.importc: "fflush", noDecl.}
+    ## Flushes `f`'s buffer.
+
+  proc readFile*(filename: string): string
+    ## Opens a file name `filename` for reading. Then reads the
+    ## file's content completely into a string and
+    ## closes the file afterwards. Returns the string. Returns nil if there was
+    ## an error. Does not throw an IO exception.
+
+  proc write*(f: TFile, r: float)
+  proc write*(f: TFile, i: int)
+  proc write*(f: TFile, s: string)
+  proc write*(f: TFile, b: Bool)
+  proc write*(f: TFile, c: char)
+  proc write*(f: TFile, c: cstring)
+  proc write*(f: TFile, a: openArray[string])
+    ## Writes a value to the file `f`. May throw an IO exception.
+
+  proc readLine*(f: TFile): string
+    ## reads a line of text from the file `f`. May throw an IO exception.
+    ## Reading from an empty file buffer, does not throw an exception, but
+    ## returns nil. A line of text may be delimited by ``CR``, ``LF`` or
+    ## ``CRLF``. The newline character(s) are not part of the returned string.
+
+  proc writeln*[Ty](f: TFile, x: Ty) {.inline.}
+    ## writes a value `x` to `f` and then writes "\n".
+    ## May throw an IO exception.
+
+  proc writeln*[Ty](f: TFile, x: openArray[Ty]) {.inline.}
+    ## writes a value `x` to `f` and then writes "\n".
+    ## May throw an IO exception.
+
+  proc getFileSize*(f: TFile): int64
+    ## retrieves the file size (in bytes) of `f`.
+
+  proc ReadBytes*(f: TFile, a: var openarray[byte], start, len: int): int
+    ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
+    ## the actual number of bytes that have been read which may be less than
+    ## `len` (if not as many bytes are remaining), but not greater.
+
+  proc ReadChars*(f: TFile, a: var openarray[char], start, len: int): int
+    ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
+    ## the actual number of bytes that have been read which may be less than
+    ## `len` (if not as many bytes are remaining), but not greater.
+
+  proc readBuffer*(f: TFile, buffer: pointer, len: int): int
+    ## reads `len` bytes into the buffer pointed to by `buffer`. Returns
+    ## the actual number of bytes that have been read which may be less than
+    ## `len` (if not as many bytes are remaining), but not greater.
+
+  proc writeBytes*(f: TFile, a: openarray[byte], start, len: int): int
+    ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
+    ## the number of actual written bytes, which may be less than `len` in case
+    ## of an error.
+
+  proc writeChars*(f: tFile, a: openarray[char], start, len: int): int
+    ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
+    ## the number of actual written bytes, which may be less than `len` in case
+    ## of an error.
+
+  proc writeBuffer*(f: TFile, buffer: pointer, len: int): int
+    ## writes the bytes of buffer pointed to by the parameter `buffer` to the
+    ## file `f`. Returns the number of actual written bytes, which may be less
+    ## than `len` in case of an error.
+
+  proc setFilePos*(f: TFile, pos: int64)
+    ## sets the position of the file pointer that is used for read/write
+    ## operations. The file's first byte has the index zero.
+
+  proc getFilePos*(f: TFile): int64
+    ## retrieves the current position of the file pointer that is used to
+    ## read from the file `f`. The file's first byte has the index zero.
+
+  include sysio
+
+  iterator lines*(filename: string): string =
+    ## Iterate over any line in the file named `filename`.
+    ## If the file does not exist `EIO` is raised.
+    var
+      f: TFile
+    if not openFile(f, filename):
+      raise newException(EIO, "cannot open: " & filename)
+    var res = ""
+    while not endOfFile(f):
+      rawReadLine(f, res)
+      yield res
+    CloseFile(f)
+
+  # ----------------------------------------------------------------------------
+
+  include excpt
+  # we cannot compile this with stack tracing on
+  # as it would recurse endlessly!
+  include arithm
+  {.pop.} # stack trace
+
+  # sequence type declarations here because the GC needs them too:
+  type
+    TGenericSeq {.importc, nodecl, final.} = object
+      len, space: int
+
+    PGenericSeq {.importc, nodecl.} = ptr TGenericSeq
+
+  const
+    GenericSeqSize = (2 * sizeof(int))
+
+  when not defined(boehmgc) and not defined(nogc):
+    include gc
+
+  include sysstr
+  include assign
+  include dyncalls
+  include repr
+
+  # we have to implement it here after gentostr for the cstrToNimStrDummy proc
+  proc getCurrentExceptionMsg(): string =
+    if excHandler == nil: return ""
+    return $excHandler.exc.msg
+
+  {.push stack_trace: off.}
+  when defined(endb):
+    include debugger
+  {.pop.} # stacktrace
 
+else:
+  include ecmasys
+
+include macros
+
+{.pop.} # checks
 {.pop.} # hints
diff --git a/lib/times.nim b/lib/times.nim
index e1b32e754..93524f568 100644
--- a/lib/times.nim
+++ b/lib/times.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2006 Andreas Rumpf
+#        (c) Copyright 2008 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -9,6 +9,7 @@
 
 
 ## This module contains routines and types for dealing with time.
+## This module is available for the ECMAScript target.
 
 {.push debugger:off .} # the user does not want to trace a part
                        # of the standard library!
@@ -22,9 +23,49 @@ type
   TWeekDay* = enum ## represents a weekday
     dMon, dTue, dWed, dThu, dFri, dSat, dSun
 
-  TTime* {.importc: "time_t".} = record ## abstract type that represents a time
+  TTime* {.importc: "time_t", final.} = object ## abstract type that 
+                                               ## represents a time
+    when defined(ECMAScript):
+      getDay: proc (): int
+      getFullYear: proc (): int
+      getHours: proc (): int
+      getMilliseconds: proc (): int
+      getMinutes: proc (): int
+      getMonth: proc (): int
+      getSeconds: proc (): int
+      getTime: proc (): int
+      getTimezoneOffset: proc (): int
+      getUTCDate: proc (): int
+      getUTCFullYear: proc (): int
+      getUTCHours: proc (): int
+      getUTCMilliseconds: proc (): int
+      getUTCMinutes: proc (): int
+      getUTCMonth: proc (): int
+      getUTCSeconds: proc (): int
+      getYear: proc (): int
+      parse: proc (s: cstring): TTime
+      setDate: proc (x: int)
+      setFullYear: proc (x: int)
+      setHours: proc (x: int)
+      setMilliseconds: proc (x: int)
+      setMinutes: proc (x: int)
+      setMonth: proc (x: int)
+      setSeconds: proc (x: int)
+      setTime: proc (x: int)
+      setUTCDate: proc (x: int)
+      setUTCFullYear: proc (x: int)
+      setUTCHours: proc (x: int)
+      setUTCMilliseconds: proc (x: int)
+      setUTCMinutes: proc (x: int)
+      setUTCMonth: proc (x: int)
+      setUTCSeconds: proc (x: int)
+      setYear: proc (x: int)
+      toGMTString: proc (): cstring
+      toLocaleString: proc (): cstring
+      UTC: proc (): int
 
-  TTimeInfo* = record         ## represents a time in different parts
+
+  TTimeInfo* = object of TObject ## represents a time in different parts
     second*: range[0..61]     ## The number of seconds after the minute,
                               ## normally in the range 0 to 59, but can
                               ## be up to 61 to allow for leap seconds.
@@ -38,6 +79,7 @@ type
     weekday*: TWeekDay        ## The current day of the week.
     yearday*: range[0..365]   ## The number of days since January 1,
                               ## in the range 0 to 365.
+                              ## Always 0 if the target is ECMAScript.
 
 proc getTime*(): TTime ## gets the current calendar time
 proc getLocalTime*(t: TTime): TTimeInfo
@@ -54,7 +96,7 @@ proc TimeInfoToTime*(timeInfo: TTimeInfo): TTime
   ## them from the other information in the broken-down time structure.
 
 proc `$` *(timeInfo: TTimeInfo): string
-  ## converts a `TTimeInfo` record to a
+  ## converts a `TTimeInfo` object to a
   ## string representation.
 proc `$` *(time: TTime): string
   ## converts a calendar time to a
@@ -72,92 +114,149 @@ proc `-` *(a, b: TTime): int64
 proc getStartMilsecs*(): int
   ## get the miliseconds from the start of the program
 
-#implementation
 
-# C wrapper:
-type
-  structTM {.importc: "struct tm".} = record
-    second {.importc: "tm_sec".},
-      minute {.importc: "tm_min".},
-      hour {.importc: "tm_hour".},
-      monthday {.importc: "tm_mday".},
-      month {.importc: "tm_mon".},
-      year {.importc: "tm_year".},
-      weekday {.importc: "tm_wday".},
-      yearday {.importc: "tm_yday".},
-      isdst {.importc: "tm_isdst".}: cint
-
-  PTimeInfo = ptr structTM
-  PTime = ptr TTime
-
-  TClock {.importc: "clock_t".} = range[low(int)..high(int)]
-
-proc localtime(timer: PTime): PTimeInfo {.
-  importc: "localtime", header: "<time.h>".}
-proc gmtime(timer: PTime): PTimeInfo {.importc: "gmtime", header: "<time.h>".}
-proc timec(timer: PTime): TTime      {.importc: "time", header: "<time.h>".}
-proc mktime(t: structTM): TTime      {.importc: "mktime", header: "<time.h>".}
-proc asctime(tblock: structTM): CString {.
-  importc: "asctime", header: "<time.h>".}
-proc ctime(time: PTime): CString     {.importc: "ctime", header: "<time.h>".}
-#  strftime(s: CString, maxsize: int, fmt: CString, t: tm): int {.
-#    importc: "strftime", header: "<time.h>".}
-proc clock(): TClock {.importc: "clock", header: "<time.h>".}
-proc difftime(a, b: TTime): float {.importc: "difftime", header: "<time.h>".}
-
-var
-  clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
-
-
-# our own procs on top of that:
-proc tmToTimeInfo(tm: structTM): TTimeInfo =
+when not defined(ECMAScript):
+  
+  # C wrapper:
+  type
+    structTM {.importc: "struct tm", final.} = object
+      second {.importc: "tm_sec".},
+        minute {.importc: "tm_min".},
+        hour {.importc: "tm_hour".},
+        monthday {.importc: "tm_mday".},
+        month {.importc: "tm_mon".},
+        year {.importc: "tm_year".},
+        weekday {.importc: "tm_wday".},
+        yearday {.importc: "tm_yday".},
+        isdst {.importc: "tm_isdst".}: cint
+  
+    PTimeInfo = ptr structTM
+    PTime = ptr TTime
+  
+    TClock {.importc: "clock_t".} = range[low(int)..high(int)]
+  
+  proc localtime(timer: PTime): PTimeInfo {.
+    importc: "localtime", header: "<time.h>".}
+  proc gmtime(timer: PTime): PTimeInfo {.importc: "gmtime", header: "<time.h>".}
+  proc timec(timer: PTime): TTime      {.importc: "time", header: "<time.h>".}
+  proc mktime(t: structTM): TTime      {.importc: "mktime", header: "<time.h>".}
+  proc asctime(tblock: structTM): CString {.
+    importc: "asctime", header: "<time.h>".}
+  proc ctime(time: PTime): CString     {.importc: "ctime", header: "<time.h>".}
+  #  strftime(s: CString, maxsize: int, fmt: CString, t: tm): int {.
+  #    importc: "strftime", header: "<time.h>".}
+  proc clock(): TClock {.importc: "clock", header: "<time.h>".}
+  proc difftime(a, b: TTime): float {.importc: "difftime", header: "<time.h>".}
+  
+  var
+    clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
+  
+  
+  # our own procs on top of that:
+  proc tmToTimeInfo(tm: structTM): TTimeInfo =
+    const
+      weekDays: array [0..6, TWeekDay] = [
+        dSun, dMon, dTue, dWed, dThu, dFri, dSat]
+    result.second = int(tm.second)
+    result.minute = int(tm.minute)
+    result.hour = int(tm.hour)
+    result.monthday = int(tm.monthday)
+    result.month = TMonth(tm.month)
+    result.year = tm.year + 1900
+    result.weekday = weekDays[int(tm.weekDay)]
+    result.yearday = int(tm.yearday)
+  
+  proc timeInfoToTM(t: TTimeInfo): structTM =
+    const
+      weekDays: array [TWeekDay, int] = [1, 2, 3, 4, 5, 6, 0]
+    result.second = t.second
+    result.minute = t.minute
+    result.hour = t.hour
+    result.monthday = t.monthday
+    result.month = ord(t.month)
+    result.year = t.year - 1900
+    result.weekday = weekDays[t.weekDay]
+    result.yearday = t.yearday
+    result.isdst = -1
+  
+  proc `-` (a, b: TTime): int64 =
+    return toInt(difftime(a, b)) # XXX: toBiggestInt is needed here, but
+                                 # Nim does not support it!
+  
+  proc getStartMilsecs(): int = return clock() div (clocksPerSec div 1000)
+  proc getTime(): TTime = return timec(nil)
+  proc getLocalTime(t: TTime): TTimeInfo =
+    var a = t
+    result = tmToTimeInfo(localtime(addr(a))^)
+    # copying is needed anyway to provide reentrancity; thus
+    # the convertion is not expensive
+  
+  proc getGMTime(t: TTime): TTimeInfo =
+    var a = t
+    result = tmToTimeInfo(gmtime(addr(a))^)
+    # copying is needed anyway to provide reentrancity; thus
+    # the convertion is not expensive
+  
+  proc TimeInfoToTime(timeInfo: TTimeInfo): TTime =
+    var cTimeInfo = timeInfo # for C++ we have to make a copy,
+    # because the header of mktime is broken in my version of libc
+    return mktime(timeInfoToTM(cTimeInfo))
+    
+  proc `$`(timeInfo: TTimeInfo): string =
+    return $asctime(timeInfoToTM(timeInfo))
+  
+  proc `$`(time: TTime): string =
+    var a = time
+    return $ctime(addr(a))
+
+else:
+  proc getTime(): TTime {.importc: "new Date", nodecl.}
+
   const
     weekDays: array [0..6, TWeekDay] = [
       dSun, dMon, dTue, dWed, dThu, dFri, dSat]
-  result.second = int(tm.second)
-  result.minute = int(tm.minute)
-  result.hour = int(tm.hour)
-  result.monthday = int(tm.monthday)
-  result.month = TMonth(tm.month)
-  result.year = tm.year + 1900
-  result.weekday = weekDays[int(tm.weekDay)]
-  result.yearday = int(tm.yearday)
-
-proc timeInfoToTM(t: TTimeInfo): structTM =
-  const
-    weekDays: array [TWeekDay, int] = [1, 2, 3, 4, 5, 6, 0]
-  result.second = t.second
-  result.minute = t.minute
-  result.hour = t.hour
-  result.monthday = t.monthday
-  result.month = ord(t.month)
-  result.year = t.year - 1900
-  result.weekday = weekDays[t.weekDay]
-  result.yearday = t.yearday
-  result.isdst = -1
-
-proc `-` (a, b: TTime): int64 =
-  return toInt(difftime(a, b)) # XXX: toBiggestInt is needed here, but
-                               # Nim does not support it!
-
-proc getStartMilsecs(): int = return clock() div (clocksPerSec div 1000)
-proc getTime(): TTime = return timec(nil)
-proc getLocalTime(t: TTime): TTimeInfo =
-  var a = t
-  result = tmToTimeInfo(localtime(addr(a))^)
-  # copying is needed anyway to provide reentrancity; thus
-  # the convertion is not expensive
-
-proc getGMTime(t: TTime): TTimeInfo =
-  var a = t
-  result = tmToTimeInfo(gmtime(addr(a))^)
-  # copying is needed anyway to provide reentrancity; thus
-  # the convertion is not expensive
-
-proc TimeInfoToTime(timeInfo: TTimeInfo): TTime =
-  var cTimeInfo = timeInfo # for C++ we have to make a copy,
-  # because the header of mktime is broken in my version of libc
-  return mktime(timeInfoToTM(cTimeInfo))
+  
+  proc getLocalTime(t: TTime): TTimeInfo =
+    result.second = t.getSeconds()
+    result.minute = t.getMinutes()
+    result.hour = t.getHours()
+    result.monthday = t.getDate()
+    result.month = TMonth(t.getMonth())
+    result.year = t.getFullYear()
+    result.weekday = weekDays[t.getDay()]
+    result.yearday = 0
+
+  proc getGMTime(t: TTime): TTimeInfo =
+    result.second = t.getUTCSeconds()
+    result.minute = t.getUTCMinutes()
+    result.hour = t.getUTCHours()
+    result.monthday = t.getUTCDate()
+    result.month = TMonth(t.getUTCMonth())
+    result.year = t.getUTCFullYear()
+    result.weekday = weekDays[t.getDay()]
+    result.yearday = 0
+  
+  proc TimeInfoToTime*(timeInfo: TTimeInfo): TTime =
+    result = getTime()
+    result.setSeconds(timeInfo.second)
+    result.setMinutes(timeInfo.minute)
+    result.setHours(timeInfo.hour)
+    result.setMonth(ord(timeInfo.month))
+    result.setFullYear(timeInfo.year)
+    result.setDate(timeInfo.monthday)
+  
+  proc `$`(timeInfo: TTimeInfo): string = return $(TimeInfoToTIme(timeInfo))
+  proc `$`(time: TTime): string = $time.toLocaleString()
+    
+  proc `-` (a, b: TTime): int64 = 
+    return a.getTime() - b.getTime()
+  
+  var
+    startMilsecs = getTime()
+  
+  proc getStartMilsecs(): int =
+    ## get the miliseconds from the start of the program
+    return int(getTime() - startMilsecs)
 
 proc getDateStr(): string =
   var ti = getLocalTime(getTime())
@@ -169,11 +268,4 @@ proc getClockStr(): string =
   result = intToStr(ti.hour, 2) & ':' & intToStr(ti.minute, 2) &
     ':' & intToStr(ti.second, 2)
 
-proc `$`(timeInfo: TTimeInfo): string =
-  return $asctime(timeInfoToTM(timeInfo))
-
-proc `$`(time: TTime): string =
-  var a = time
-  return $ctime(addr(a))
-
 {.pop.}
diff --git a/lib/typeinfo.nim b/lib/typeinfo.nim
deleted file mode 100644
index b4d8f8f3a..000000000
--- a/lib/typeinfo.nim
+++ /dev/null
@@ -1,221 +0,0 @@
-#
-#
-#            Nimrod's Runtime Library
-#        (c) Copyright 2006 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-# type-info module for Nimrod
-
-include hti
-
-proc typeid(x: any): PNimType
-
-type
-  Variant = opaque record
-    # contains the address and a typeinfo
-    a: pointer # an address
-    k: TNimTypeKind
-
-# conversions to any and from any are inserted by the compiler!
-# x.attr is supported, as well as x[]!
-# here is a special iterator for variants:
-iterator fields(x: variant): (fieldname: string, value: variant) =
-proc setField(structure: variant, fieldname: string, value: variant)
-proc getField(structure: variant, fieldname: string)
-
-# any is implemented as a pair (val: pointer, info: PTypeInfo)
-# val is for:
-# an array - its address
-# a record - its address
-# an object - its address
-# a string - the address of the pointer to the string data
-# a sequence - the address of the pointer to the sequence data
-# a float - the address of a memory location where the float is stored
-#           this is a given address; storage comes from compiler or is
-#           already there (in a container)
-# an int - the address of a memory location where the int is stored
-#         storage comes from compiler or is
-#         already there (in a container)
-# a cstring - the address of an address of an array of chars
-# a ref - the address of the ref! (not the ref itself!)
-
-# But this does not work too well...
-# Better: any is a ref to Object; than we define intObj, floatObj,
-#   etc.; for strings this not needed as they already fit into the
-#   scheme!
-#
-
-type
-  TAnyImpl {.exportc: "TAnyImpl".} = record
-    typ {.exportc: "info".}: PNimType
-    val {.exportc: "val".}: pointer
-
-proc
-  typeKind(p: PNimType): TTypeKind {.inline.}
-
-  getAnyLength(x: any): int
-
-  isContainer(x: any): bool
-
-  writeAny(container: any, index: int, val: any)
-  readAny(container: any, index: int): any
-
-  writeAny(container: any, name: string, val: any)
-  readAny(container: any, name: string): any
-
-  getAttr(container: any, index: int, out name: string, out val: any)
-
-  getEnumStrings(enumeration: any): sequence of string
-
-  anyToInt(x: any): biggestint
-  anyToFloat(x: any): biggestfloat
-  anyToString(x: any): string
-  anyToChar(x: any): char
-  anyToBool(x: any): bool
-  #anyToT{T}(x: any, out result: T)
-
-  # etc...
-
-  #write(a: array of any) # also possible!
-
-#generic proc
-#  deepCopy{T}(x: T): T
-
-import
-  strutils
-
-proc anyToImpl(a: any): TAnyImpl {.inline.} =
-  result = cast{TAnyImpl}(a)
-
-proc typeKind(p: PNimType): TTypeKind =
-  result = p.typeKind
-
-type
-  Pint = untraced ref int
-  Pint8 = untraced ref int8
-  Pint16 = untraced ref int16
-  Pint32 = untraced ref int32
-  Pint64 = untraced ref int64
-  Puint = untraced ref uint
-  Puint8 = untraced ref uint8
-  Puint16 = untraced ref uint16
-  Puint32 = untraced ref uint32
-  Puint64 = untraced ref uint64
-  Pfloat = untraced ref float
-  Pfloat32 = untraced ref float32
-  Pfloat64 = untraced ref float64
-  Pstring = untraced ref string
-  Pbool = untraced ref bool
-  Pchar = untraced ref char
-
-proc anyToInt(x: any): biggestint =
-  var impl = anyToImpl(x)
-  case impl.typ.typeKind
-    of tyInt, tyEnum: result = cast{pint}(x.val)^
-    of tySInt8:  result = cast{pint8}(x.val)^
-    of tySInt16: result = cast{pint16}(x.val)^
-    of tySInt32: result = cast{pint32}(x.val)^
-    of tySInt64: result = cast{pint64}(x.val)^
-    of tyUInt:   result = cast{puint}(x.val)^
-    of tyUInt8:  result = cast{puint8}(x.val)^
-    of tyUInt16: result = cast{puint16}(x.val)^
-    of tyUInt32: result = cast{puint32}(x.val)^
-    of tyUInt64: result = cast{puint64}(x.val)^
-    else: raise EConvertError
-
-proc anyToFloat(x: any): biggestfloat =
-  var impl = anyToImpl(x)
-  case impl.typ.typeKind
-    of tyReal:   result = cast{pfloat}(x.val)^
-    of tyReal32: result = cast{pfloat32}(x.val)^
-    of tyReal64: result = cast{pfloat64}(x.val)^
-    # of tyReal128:
-    else: raise EConvertError
-
-proc anyToString(x: any): string =
-  var impl = anyToImpl(x)
-  case impl.typ.typeKind
-    of tyString: result = cast{pstring}(x.val)^
-    else: raise EConvertError
-
-proc anyToChar(x: any): char =
-  var impl = anyToImpl(x)
-  case impl.typ.typeKind
-    of tyChar: result = cast{pchar}(x.val)^
-    else: raise EConvertError
-
-proc anyToBool(x: any): bool =
-  var impl = anyToImpl(x)
-  case impl.typ.typeKind
-    of tyBool: result = cast{pbool}(x.val)^
-    else: raise EConvertError
-
-proc getAnyLength(x: any): int =
-  result = anyToImpl(x).typ.len
-
-const
-  ContainerSet = {tyArray, tyRecord, tyObject, tyOpenArray, tySequence, tyTable}
-
-proc isContainer(x: any): bool =
-  result = anyToImpl(x).typ.typeKind in ContainerSet
-
-proc strcmp(a, b: cstring): int {.external: "strcmp", nodecl.}
-
-proc strToIndex(info: PTypeInfo, str: string): int =
-  for i in 0..typ.len-1:
-    if strcmp(info.slots[i].name, str) == 0:
-      return i
-  raise EConvertError
-
-proc writeAny(container: any, index: int, val: any) =
-  var x = anyToImpl(container)
-  if index >= 0 and index < container.len:
-    case x.typ.typeKind
-      of tySequence:
-        var u = cast{TAddress}(x.val)
-        genericAssignAux(cast{pointer}(u) +% x.typ.slots[index].offset +%
-                         GenericSeqSize,
-                         anyToImpl(val).val, u.typ.baseType)
-      of tyArray:
-      of tyRecord, tyObject:
-      else: raise EConvertError
-  else:
-    raise EIndexError
-
-
-proc readAny(container: any, index: int): any =
-  var x = anyToImpl(container)
-  if x.typ.typeKind in ContainerSet:
-    if index >= 0 and index < container.len:
-    # XXX
-
-    else:
-      raise EIndexError
-  else:
-    raise EConvertError
-
-proc writeAny(container: any, name: string, val: any) =
-  result = writeAny(container, strToIndex(anyToImpl(container).typ), val)
-
-proc readAny(container: any, name: string): any =
-  result = readAny(container, strToIndex(anyToImpl(container).typ))
-
-proc getAttr(container: any, index: int, out name: string, out val: any) =
-  var x = anyToImpl(container)
-  if x.typ.typeKind in ContainerSet:
-    val = readAny(container, index)
-    name = $x.typ.slots[index].name
-  else:
-    raise EConvertError
-
-proc getEnumStrings(enumeration: any): sequence of string =
-  result = []
-  var x = anyToImpl(enumeration)
-  if x.typ.typekind == tyEnum:
-    for i in 0 .. x.typ.len-1:
-      result &= $x.typ.slots[i].name
-  else:
-    raise EConvertError
diff --git a/lib/windows/mmsystem.nim b/lib/windows/mmsystem.nim
index b18ae2be4..a44e4dfca 100644
--- a/lib/windows/mmsystem.nim
+++ b/lib/windows/mmsystem.nim
@@ -980,7 +980,7 @@ const
                         #/////////////////////////////////////////////////////////
 
 type
-  mmtime* = record
+  mmtime* {.final.} = object
     wType*: UINT
     hour*, min*, sec*, frame*, fps*, dummy*: int8
     pad*: array[0..1, int8]
@@ -990,7 +990,7 @@ type
   LPMMTIME* = ptr mmtime
   PWAVEHDR* = ptr wavehdr
   TMMTime* = mmtime
-  wavehdr* = record
+  wavehdr* {.final.} = object
     lpData*: cstring
     dwBufferLength*: DWORD
     dwBytesRecorded*: DWORD
@@ -1003,7 +1003,7 @@ type
   TWAVEHDR* = WAVEHDR
   NPWAVEHDR* = ptr wavehdr
   LPWAVEHDR* = ptr wavehdr
-  WAVEOUTCAPSA* = record
+  WAVEOUTCAPSA* {.final.} = object
     wMid*: int16
     wPid*: int16
     vDriverVersion*: MMVERSION
@@ -1017,7 +1017,7 @@ type
   PWAVEOUTCAPSA* = ptr WAVEOUTCAPSA
   NPWAVEOUTCAPSA* = ptr WAVEOUTCAPSA
   LPWAVEOUTCAPSA* = ptr WAVEOUTCAPSA
-  WAVEOUTCAPSW* = record
+  WAVEOUTCAPSW* {.final.} = object
     wMid*: int16
     wPid*: int16
     vDriverVersion*: MMVERSION
@@ -1046,7 +1046,7 @@ else:
     LPWAVEOUTCAPS* = LPWAVEOUTCAPSA
 type
   TWAVEOUTCAPS* = WAVEOUTCAPS
-  WAVEINCAPSA* = record
+  WAVEINCAPSA* {.final.} = object
     wMid*: int16
     wPid*: int16
     vDriverVersion*: MMVERSION
@@ -1059,7 +1059,7 @@ type
   NPWAVEINCAPSA* = ptr WAVEINCAPSA
   LPWAVEINCAPSA* = ptr WAVEINCAPSA
   TWAVEINCAPSA* = WAVEINCAPSA
-  WAVEINCAPSW* = record
+  WAVEINCAPSW* {.final.} = object
     wMid*: int16
     wPid*: int16
     vDriverVersion*: MMVERSION
@@ -1087,7 +1087,7 @@ else:
     LPWAVEINCAPS* = LPWAVEINCAPSA
 type
   TWAVEINCAPS* = WAVEINCAPS
-  waveformat* = record
+  waveformat* {.final.} = object
     wFormatTag*: int16
     nChannels*: int16
     nSamplesPerSec*: DWORD
@@ -1103,7 +1103,7 @@ const
   WAVE_FORMAT_PCM* = 1
 
 type
-  pcmwaveformat* = record
+  pcmwaveformat* {.final.} = object
     wf*: WAVEFORMAT
     wBitsPerSample*: int16
 
@@ -1111,7 +1111,7 @@ type
   NPPCMWAVEFORMAT* = ptr pcmwaveformat
   LPPCMWAVEFORMAT* = ptr pcmwaveformat
   TPCMWAVEFORMAT* = PCMWAVEFORMAT
-  WAVEFORMATEX* = record
+  WAVEFORMATEX* {.final.} = object
     wFormatTag*: int16
     nChannels*: int16
     nSamplesPerSec*: DWORD
@@ -1143,7 +1143,7 @@ type
   LPPATCHARRAY* = ptr int16
   KEYARRAY* = array[0..Pred(MIDIPATCHSIZE), int16]
   LPKEYARRAY* = ptr int16
-  MIDIOUTCAPSA* = record
+  MIDIOUTCAPSA* {.final.} = object
     wMid*: int16
     wPid*: int16
     vDriverVersion*: MMVERSION
@@ -1158,7 +1158,7 @@ type
   NPMIDIOUTCAPSA* = ptr MIDIOUTCAPSA
   LPMIDIOUTCAPSA* = ptr MIDIOUTCAPSA
   TMIDIOUTCAPSA* = MIDIOUTCAPSA
-  MIDIOUTCAPSW* = record
+  MIDIOUTCAPSW* {.final.} = object
     wMid*: int16
     wPid*: int16
     vDriverVersion*: MMVERSION
@@ -1173,7 +1173,7 @@ type
   NPMIDIOUTCAPSW* = ptr MIDIOUTCAPSW
   LPMIDIOUTCAPSW* = ptr MIDIOUTCAPSW
   TMIDIOUTCAPSW* = MIDIOUTCAPSW
-  MIDIINCAPSA* = record
+  MIDIINCAPSA* {.final.} = object
     wMid*: int16
     wPid*: int16
     vDriverVersion*: MMVERSION
@@ -1184,7 +1184,7 @@ type
   NPMIDIINCAPSA* = ptr MIDIINCAPSA
   LPMIDIINCAPSA* = ptr MIDIINCAPSA
   TMIDIINCAPSA* = MIDIINCAPSA
-  MIDIINCAPSW* = record
+  MIDIINCAPSW* {.final.} = object
     wMid*: int16
     wPid*: int16
     vDriverVersion*: MMVERSION
@@ -1219,7 +1219,7 @@ else:
 type
   TMIDIINCAPS* = MIDIINCAPS
   PMIDIHDR* = ptr midihdr
-  midihdr* = record
+  midihdr* {.final.} = object
     lpData*: cstring
     dwBufferLength*: DWORD
     dwBytesRecorded*: DWORD
@@ -1233,30 +1233,30 @@ type
   NPMIDIHDR* = ptr midihdr
   LPMIDIHDR* = ptr midihdr
   TMIDIHDR* = MIDIHDR
-  midievent* = record
+  midievent* {.final.} = object
     dwDeltaTime*: DWORD
     dwStreamID*: DWORD
     dwEvent*: DWORD
     dwParms*: array[0..Pred(1), DWORD]
 
   TMIDIEVENT* = MIDIEVENT
-  midistrmbuffver* = record
+  midistrmbuffver* {.final.} = object
     dwVersion*: DWORD
     dwMid*: DWORD
     dwOEMVersion*: DWORD
 
   TMIDISTRMBUFFVER* = MIDISTRMBUFFVER
-  Tmidiproptimediv* = record
+  Tmidiproptimediv* {.final.} = object
     cbStruct*: DWORD
     dwTimeDiv*: DWORD
 
   LPMIDIPROPTIMEDIV* = ptr Tmidiproptimediv
-  Tmidiproptempo* = record
+  Tmidiproptempo* {.final.} = object
     cbStruct*: DWORD
     dwTempo*: DWORD
 
   LPMIDIPROPTEMPO* = ptr Tmidiproptempo
-  AUXCAPSA* = record
+  AUXCAPSA* {.final.} = object
     wMid*: int16
     wPid*: int16
     vDriverVersion*: MMVERSION
@@ -1269,7 +1269,7 @@ type
   NPAUXCAPSA* = ptr AUXCAPSA
   LPAUXCAPSA* = ptr AUXCAPSA
   TAUXCAPSA* = AUXCAPSA
-  AUXCAPSW* = record
+  AUXCAPSW* {.final.} = object
     wMid*: int16
     wPid*: int16
     vDriverVersion*: MMVERSION
@@ -1305,7 +1305,7 @@ type
 proc mixerGetNumDevs*(): UINT{.stdcall, dynlib: "winmm.dll",
                                importc: "mixerGetNumDevs".}
 type
-  MIXERCAPSA* = record
+  MIXERCAPSA* {.final.} = object
     wMid*: int16
     wPid*: int16
     vDriverVersion*: MMVERSION
@@ -1316,7 +1316,7 @@ type
   PMIXERCAPSA* = ptr MIXERCAPSA
   LPMIXERCAPSA* = ptr MIXERCAPSA
   TMIXERCAPSA* = MIXERCAPSA
-  MIXERCAPSW* = record
+  MIXERCAPSW* {.final.} = object
     wMid*: int16
     wPid*: int16
     vDriverVersion*: MMVERSION
@@ -1340,7 +1340,7 @@ else:
     LPMIXERCAPS* = LPMIXERCAPSA
 type
   TMIXERCAPS* = MIXERCAPS
-  MIXERLINEA* = record
+  MIXERLINEA* {.final.} = object
     cbStruct*: DWORD
     dwDestination*: DWORD
     dwSource*: DWORD
@@ -1361,7 +1361,7 @@ type
   PMIXERLINEA* = ptr MIXERLINEA
   LPMIXERLINEA* = ptr MIXERLINEA
   TMIXERLINEA* = MIXERLINEA
-  MIXERLINEW* = record
+  MIXERLINEW* {.final.} = object
     cbStruct*: DWORD
     dwDestination*: DWORD
     dwSource*: DWORD
@@ -1395,7 +1395,7 @@ else:
     LPMIXERLINE* = LPMIXERLINEA
 type
   TMIXERLINE* = MIXERLINE
-  MIXERCONTROLA* = record
+  MIXERCONTROLA* {.final.} = object
     cbStruct*: DWORD
     dwControlID*: DWORD
     dwControlType*: DWORD
@@ -1411,7 +1411,7 @@ type
   PMIXERCONTROLA* = ptr MIXERCONTROLA
   LPMIXERCONTROLA* = ptr MIXERCONTROLA
   TMIXERCONTROLA* = MIXERCONTROLA
-  MIXERCONTROLW* = record
+  MIXERCONTROLW* {.final.} = object
     cbStruct*: DWORD
     dwControlID*: DWORD
     dwControlType*: DWORD
@@ -1440,7 +1440,7 @@ else:
     LPMIXERCONTROL* = LPMIXERCONTROLA
 type
   TMIXERCONTROL* = MIXERCONTROL
-  MIXERLINECONTROLSA* = record
+  MIXERLINECONTROLSA* {.final.} = object
     cbStruct*: DWORD
     dwLineID*: DWORD
     dwControlType*, cControls*, cbmxctrl*: DWORD
@@ -1449,7 +1449,7 @@ type
   PMIXERLINECONTROLSA* = ptr MIXERLINECONTROLSA
   LPMIXERLINECONTROLSA* = ptr MIXERLINECONTROLSA
   TMIXERLINECONTROLSA* = MIXERLINECONTROLSA
-  MIXERLINECONTROLSW* = record
+  MIXERLINECONTROLSW* {.final.} = object
     cbStruct*: DWORD
     dwLineID*: DWORD
     dwControlType*, cControls*, cbmxctrl*: DWORD
@@ -1471,7 +1471,7 @@ else:
     LPMIXERLINECONTROLS* = LPMIXERLINECONTROLSA
 type
   TMIXERLINECONTROLS* = MIXERLINECONTROLS
-  TMIXERCONTROLDETAILS* = record
+  TMIXERCONTROLDETAILS* {.final.} = object
     cbStruct*: DWORD
     dwControlID*: DWORD
     cChannels*: DWORD
@@ -1481,7 +1481,7 @@ type
   MIXERCONTROLDETAILS* = tMIXERCONTROLDETAILS
   PMIXERCONTROLDETAILS* = ptr tMIXERCONTROLDETAILS
   LPMIXERCONTROLDETAILS* = ptr tMIXERCONTROLDETAILS
-  MIXERCONTROLDETAILS_LISTTEXTA* = record
+  MIXERCONTROLDETAILS_LISTTEXTA* {.final.} = object
     dwParam1*: DWORD
     dwParam2*: DWORD
     szName*: array[0..Pred(MIXER_LONG_NAME_CHARS), CHAR]
@@ -1489,7 +1489,7 @@ type
   PMIXERCONTROLDETAILS_LISTTEXTA* = ptr MIXERCONTROLDETAILS_LISTTEXTA
   LPMIXERCONTROLDETAILS_LISTTEXTA* = ptr MIXERCONTROLDETAILS_LISTTEXTA
   TMIXERCONTROLDETAILS_LISTTEXTA* = MIXERCONTROLDETAILS_LISTTEXTA
-  MIXERCONTROLDETAILS_LISTTEXTW* = record
+  MIXERCONTROLDETAILS_LISTTEXTW* {.final.} = object
     dwParam1*: DWORD
     dwParam2*: DWORD
     szName*: array[0..Pred(MIXER_LONG_NAME_CHARS), WCHAR]
@@ -1510,19 +1510,19 @@ else:
     LPMIXERCONTROLDETAILS_LISTTEXT* = LPMIXERCONTROLDETAILS_LISTTEXTA
 type
   TMIXERCONTROLDETAILS_LISTTEXT* = MIXERCONTROLDETAILS_LISTTEXT
-  MIXERCONTROLDETAILS_BOOLEAN* = record
+  MIXERCONTROLDETAILS_BOOLEAN* {.final.} = object
     fValue*: int32
 
   PMIXERCONTROLDETAILS_BOOLEAN* = ptr MIXERCONTROLDETAILS_BOOLEAN
   LPMIXERCONTROLDETAILS_BOOLEAN* = ptr MIXERCONTROLDETAILS_BOOLEAN
   TMIXERCONTROLDETAILS_BOOLEAN* = MIXERCONTROLDETAILS_BOOLEAN
-  MIXERCONTROLDETAILS_SIGNED* = record
+  MIXERCONTROLDETAILS_SIGNED* {.final.} = object
     lValue*: int32
 
   PMIXERCONTROLDETAILS_SIGNED* = ptr MIXERCONTROLDETAILS_SIGNED
   LPMIXERCONTROLDETAILS_SIGNED* = ptr MIXERCONTROLDETAILS_SIGNED
   TMIXERCONTROLDETAILS_SIGNED* = MIXERCONTROLDETAILS_SIGNED
-  MIXERCONTROLDETAILS_UNSIGNED* = record
+  MIXERCONTROLDETAILS_UNSIGNED* {.final.} = object
     dwValue*: DWORD
 
   PMIXERCONTROLDETAILS_UNSIGNED* = ptr MIXERCONTROLDETAILS_UNSIGNED
@@ -1531,7 +1531,7 @@ type
   LPTIMECALLBACK* = proc (uTimerID, uMsg: UINT, dwUser, dw1, dw2: DWORD){.
       stdcall.}
   TTIMECALLBACK* = LPTIMECALLBACK
-  timecaps* = record
+  timecaps* {.final.} = object
     wPeriodMin*: UINT
     wPeriodMax*: UINT
 
@@ -1539,7 +1539,7 @@ type
   NPTIMECAPS* = ptr timecaps
   LPTIMECAPS* = ptr timecaps
   TTIMECAS* = TIMECAPS
-  JOYCAPSA* = record
+  JOYCAPSA* {.final.} = object
     wMid*: int16
     wPid*: int16
     szPname*: array[0..Pred(MAXPNAMELEN), CHAR]
@@ -1569,7 +1569,7 @@ type
   NPJOYCAPSA* = ptr JOYCAPSA
   LPJOYCAPSA* = ptr JOYCAPSA
   TJOYCAPSA* = JOYCAPSA
-  JOYCAPSW* = record
+  JOYCAPSW* {.final.} = object
     wMid*: int16
     wPid*: int16
     szPname*: array[0..Pred(MAXPNAMELEN), WCHAR]
@@ -1614,7 +1614,7 @@ else:
     LPJOYCAPS* = LPJOYCAPSA
 type
   TJOYCAPS* = JOYCAPS
-  joyinfo* = record
+  joyinfo* {.final.} = object
     wXpos*: UINT
     wYpos*: UINT
     wZpos*: UINT
@@ -1624,7 +1624,7 @@ type
   NPJOYINFO* = ptr joyinfo
   LPJOYINFO* = ptr joyinfo
   TJOYINFO* = JOYINFO
-  joyinfoex* = record
+  joyinfoex* {.final.} = object
     dwSize*: DWORD
     dwFlags*: DWORD
     wXpos*: UINT
@@ -1648,7 +1648,7 @@ type
   HMMIO* = THandle
   LPMMIOPROC* = proc (x1: LPSTR, x2: UINT, x3, x4: LPARAM): LRESULT{.stdcall.}
   TMMIOPROC* = LPMMIOPROC
-  MMIOINFO* = record
+  MMIOINFO* {.final.} = object
     dwFlags*: DWORD
     fccIOProc*: FOURCC
     pIOProc*: LPMMIOPROC
@@ -1671,7 +1671,7 @@ type
   LPMMIOINFO* = ptr MMIOINFO
   LPCMMIOINFO* = ptr MMIOINFO
   TMMIOINFO* = MMIOINFO
-  MMCKINFO* = record
+  MMCKINFO* {.final.} = object
     ckid*: FOURCC
     cksize*: DWORD
     fccType*: FOURCC
@@ -1687,13 +1687,13 @@ type
   MCIDEVICEID* = UINT
   YIELDPROC* = proc (mciId: MCIDEVICEID, dwYieldData: DWORD): UINT{.stdcall.}
   TYIELDPROC* = YIELDPROC
-  MCI_GENERIC_PARMS* = record
+  MCI_GENERIC_PARMS* {.final.} = object
     dwCallback*: DWORD
 
   PMCI_GENERIC_PARMS* = ptr MCI_GENERIC_PARMS
   LPMCI_GENERIC_PARMS* = ptr MCI_GENERIC_PARMS
   TMCI_GENERIC_PARMS* = MCI_GENERIC_PARMS
-  MCI_OPEN_PARMSA* = record
+  MCI_OPEN_PARMSA* {.final.} = object
     dwCallback*: DWORD
     wDeviceID*: MCIDEVICEID
     lpstrDeviceType*: LPCSTR
@@ -1703,7 +1703,7 @@ type
   PMCI_OPEN_PARMSA* = ptr MCI_OPEN_PARMSA
   LPMCI_OPEN_PARMSA* = ptr MCI_OPEN_PARMSA
   TMCI_OPEN_PARMSA* = MCI_OPEN_PARMSA
-  MCI_OPEN_PARMSW* = record
+  MCI_OPEN_PARMSW* {.final.} = object
     dwCallback*: DWORD
     wDeviceID*: MCIDEVICEID
     lpstrDeviceType*: LPCWSTR
@@ -1726,7 +1726,7 @@ else:
     LPMCI_OPEN_PARMS* = LPMCI_OPEN_PARMSA
 type
   TMCI_OPEN_PARMS* = MCI_OPEN_PARMS
-  MCI_PLAY_PARMS* = record
+  MCI_PLAY_PARMS* {.final.} = object
     dwCallback*: DWORD
     dwFrom*: DWORD
     dwTo*: DWORD
@@ -1734,14 +1734,14 @@ type
   PMCI_PLAY_PARMS* = ptr MCI_PLAY_PARMS
   LPMCI_PLAY_PARMS* = ptr MCI_PLAY_PARMS
   TMCI_PLAY_PARMS* = MCI_PLAY_PARMS
-  MCI_SEEK_PARMS* = record
+  MCI_SEEK_PARMS* {.final.} = object
     dwCallback*: DWORD
     dwTo*: DWORD
 
   PMCI_SEEK_PARMS* = ptr MCI_SEEK_PARMS
   LPMCI_SEEK_PARMS* = ptr MCI_SEEK_PARMS
   TMCI_SEEK_PARMS* = MCI_SEEK_PARMS
-  MCI_STATUS_PARMS* = record
+  MCI_STATUS_PARMS* {.final.} = object
     dwCallback*: DWORD
     dwReturn*: DWORD
     dwItem*: DWORD
@@ -1750,14 +1750,14 @@ type
   PMCI_STATUS_PARMS* = ptr MCI_STATUS_PARMS
   LPMCI_STATUS_PARMS* = ptr MCI_STATUS_PARMS
   TMCI_STATUS_PARMS* = MCI_STATUS_PARMS
-  MCI_INFO_PARMSA* = record
+  MCI_INFO_PARMSA* {.final.} = object
     dwCallback*: DWORD
     lpstrReturn*: cstring
     dwRetSize*: DWORD
 
   LPMCI_INFO_PARMSA* = ptr MCI_INFO_PARMSA
   TMCI_INFO_PARMSA* = MCI_INFO_PARMSA
-  MCI_INFO_PARMSW* = record
+  MCI_INFO_PARMSW* {.final.} = object
     dwCallback*: DWORD
     lpstrReturn*: LPWSTR
     dwRetSize*: DWORD
@@ -1775,7 +1775,7 @@ else:
     LPMCI_INFO_PARMS* = LPMCI_INFO_PARMSA
 type
   TMCI_INFO_PARMS* = MCI_INFO_PARMS
-  MCI_GETDEVCAPS_PARMS* = record
+  MCI_GETDEVCAPS_PARMS* {.final.} = object
     dwCallback*: DWORD
     dwReturn*: DWORD
     dwItem*: DWORD
@@ -1783,7 +1783,7 @@ type
   PMCI_GETDEVCAPS_PARMS* = ptr MCI_GETDEVCAPS_PARMS
   LPMCI_GETDEVCAPS_PARMS* = ptr MCI_GETDEVCAPS_PARMS
   TMCI_GETDEVCAPS_PARMS* = MCI_GETDEVCAPS_PARMS
-  MCI_SYSINFO_PARMSA* = record
+  MCI_SYSINFO_PARMSA* {.final.} = object
     dwCallback*: DWORD
     lpstrReturn*: cstring
     dwRetSize*: DWORD
@@ -1793,7 +1793,7 @@ type
   PMCI_SYSINFO_PARMSA* = ptr MCI_SYSINFO_PARMSA
   LPMCI_SYSINFO_PARMSA* = ptr MCI_SYSINFO_PARMSA
   TMCI_SYSINFO_PARMSA* = MCI_SYSINFO_PARMSA
-  MCI_SYSINFO_PARMSW* = record
+  MCI_SYSINFO_PARMSW* {.final.} = object
     dwCallback*: DWORD
     lpstrReturn*: LPWSTR
     dwRetSize*: DWORD
@@ -1816,7 +1816,7 @@ else:
     LPMCI_SYSINFO_PARMS* = LPMCI_SYSINFO_PARMSA
 type
   TMCI_SYSINFO_PARMS* = MCI_SYSINFO_PARMS
-  MCI_SET_PARMS* = record
+  MCI_SET_PARMS* {.final.} = object
     dwCallback*: DWORD
     dwTimeFormat*: DWORD
     dwAudio*: DWORD
@@ -1824,7 +1824,7 @@ type
   PMCI_SET_PARMS* = ptr MCI_SET_PARMS
   LPMCI_SET_PARMS* = ptr MCI_SET_PARMS
   TMCI_SET_PARMS* = MCI_SET_PARMS
-  MCI_BREAK_PARMS* = record
+  MCI_BREAK_PARMS* {.final.} = object
     dwCallback*: DWORD
     nVirtKey*: int32
     hwndBreak*: HWND
@@ -1832,14 +1832,14 @@ type
   PMCI_BREAK_PARMS* = ptr MCI_BREAK_PARMS
   LPMCI_BREAK_PARMS* = ptr MCI_BREAK_PARMS
   TMCI_BREAK_PARMS* = MCI_BREAK_PARMS
-  MCI_SAVE_PARMSA* = record
+  MCI_SAVE_PARMSA* {.final.} = object
     dwCallback*: DWORD
     lpfilename*: LPCSTR
 
   PMCI_SAVE_PARMSA* = ptr MCI_SAVE_PARMSA
   LPMCI_SAVE_PARMSA* = ptr MCI_SAVE_PARMSA
   TMCI_SAVE_PARMSA* = MCI_SAVE_PARMSA
-  MCI_SAVE_PARMSW* = record
+  MCI_SAVE_PARMSW* {.final.} = object
     dwCallback*: DWORD
     lpfilename*: LPCWSTR
 
@@ -1859,14 +1859,14 @@ else:
     LPMCI_SAVE_PARMS* = LPMCI_SAVE_PARMSA
 type
   TMCI_SAVE_PARMS* = MCI_SAVE_PARMS
-  MCI_LOAD_PARMSA* = record
+  MCI_LOAD_PARMSA* {.final.} = object
     dwCallback*: DWORD
     lpfilename*: LPCSTR
 
   PMCI_LOAD_PARMSA* = ptr MCI_LOAD_PARMSA
   LPMCI_LOAD_PARMSA* = ptr MCI_LOAD_PARMSA
   TMCI_LOAD_PARMSA* = MCI_LOAD_PARMSA
-  MCI_LOAD_PARMSW* = record
+  MCI_LOAD_PARMSW* {.final.} = object
     dwCallback*: DWORD
     lpfilename*: LPCWSTR
 
@@ -1886,14 +1886,14 @@ else:
     LPMCI_LOAD_PARMS* = LPMCI_LOAD_PARMSA
 type
   TMCI_LOAD_PARMS* = MCI_LOAD_PARMS
-  MCI_RECORD_PARMS* = record
+  MCI_RECORD_PARMS* {.final.} = object
     dwCallback*: DWORD
     dwFrom*: DWORD
     dwTo*: DWORD
 
   LPMCI_RECORD_PARMS* = ptr MCI_RECORD_PARMS
   TMCI_RECORD_PARMS* = MCI_RECORD_PARMS
-  MCI_VD_PLAY_PARMS* = record
+  MCI_VD_PLAY_PARMS* {.final.} = object
     dwCallback*: DWORD
     dwFrom*: DWORD
     dwTo*: DWORD
@@ -1902,20 +1902,20 @@ type
   PMCI_VD_PLAY_PARMS* = ptr MCI_VD_PLAY_PARMS
   LPMCI_VD_PLAY_PARMS* = ptr MCI_VD_PLAY_PARMS
   TMCI_VD_PLAY_PARMS* = MCI_VD_PLAY_PARMS
-  MCI_VD_STEP_PARMS* = record
+  MCI_VD_STEP_PARMS* {.final.} = object
     dwCallback*: DWORD
     dwFrames*: DWORD
 
   PMCI_VD_STEP_PARMS* = ptr MCI_VD_STEP_PARMS
   LPMCI_VD_STEP_PARMS* = ptr MCI_VD_STEP_PARMS
-  MCI_VD_ESCAPE_PARMSA* = record
+  MCI_VD_ESCAPE_PARMSA* {.final.} = object
     dwCallback*: DWORD
     lpstrCommand*: LPCSTR
 
   PMCI_VD_ESCAPE_PARMSA* = ptr MCI_VD_ESCAPE_PARMSA
   LPMCI_VD_ESCAPE_PARMSA* = ptr MCI_VD_ESCAPE_PARMSA
   TMCI_VD_ESCAPE_PARMSA* = MCI_VD_ESCAPE_PARMSA
-  MCI_VD_ESCAPE_PARMSW* = record
+  MCI_VD_ESCAPE_PARMSW* {.final.} = object
     dwCallback*: DWORD
     lpstrCommand*: LPCWSTR
 
@@ -1935,7 +1935,7 @@ else:
     LPMCI_VD_ESCAPE_PARMS* = LPMCI_VD_ESCAPE_PARMSA
 type
   TMCI_VD_ESCAPE_PARMS* = MCI_VD_ESCAPE_PARMS
-  MCI_WAVE_OPEN_PARMSA* = record
+  MCI_WAVE_OPEN_PARMSA* {.final.} = object
     dwCallback*: DWORD
     wDeviceID*: MCIDEVICEID
     lpstrDeviceType*: LPCSTR
@@ -1946,7 +1946,7 @@ type
   PMCI_WAVE_OPEN_PARMSA* = ptr MCI_WAVE_OPEN_PARMSA
   LPMCI_WAVE_OPEN_PARMSA* = ptr MCI_WAVE_OPEN_PARMSA
   TMCI_WAVE_OPEN_PARMSA* = MCI_WAVE_OPEN_PARMSA
-  MCI_WAVE_OPEN_PARMSW* = record
+  MCI_WAVE_OPEN_PARMSW* {.final.} = object
     dwCallback*: DWORD
     wDeviceID*: MCIDEVICEID
     lpstrDeviceType*: LPCWSTR
@@ -1970,7 +1970,7 @@ else:
     LPMCI_WAVE_OPEN_PARMS* = LPMCI_WAVE_OPEN_PARMSA
 type
   TMCI_WAVE_OPEN_PARMS* = MCI_WAVE_OPEN_PARMS
-  MCI_WAVE_DELETE_PARMS* = record
+  MCI_WAVE_DELETE_PARMS* {.final.} = object
     dwCallback*: DWORD
     dwFrom*: DWORD
     dwTo*: DWORD
@@ -1978,7 +1978,7 @@ type
   PMCI_WAVE_DELETE_PARMS* = ptr MCI_WAVE_DELETE_PARMS
   LPMCI_WAVE_DELETE_PARMS* = ptr MCI_WAVE_DELETE_PARMS
   TMCI_WAVE_DELETE_PARMS* = MCI_WAVE_DELETE_PARMS
-  MCI_WAVE_SET_PARMS* = record
+  MCI_WAVE_SET_PARMS* {.final.} = object
     dwCallback*: DWORD
     dwTimeFormat*: DWORD
     dwAudio*: DWORD
@@ -1998,7 +1998,7 @@ type
   PMCI_WAVE_SET_PARMS* = ptr MCI_WAVE_SET_PARMS
   LPMCI_WAVE_SET_PARMS* = ptr MCI_WAVE_SET_PARMS
   TMCI_WAVE_SET_PARMS* = MCI_WAVE_SET_PARMS
-  MCI_SEQ_SET_PARMS* = record
+  MCI_SEQ_SET_PARMS* {.final.} = object
     dwCallback*: DWORD
     dwTimeFormat*: DWORD
     dwAudio*: DWORD
@@ -2011,7 +2011,7 @@ type
   PMCI_SEQ_SET_PARMS* = ptr MCI_SEQ_SET_PARMS
   LPMCI_SEQ_SET_PARMS* = ptr MCI_SEQ_SET_PARMS
   TMCI_SEQ_SET_PARMS* = MCI_SEQ_SET_PARMS
-  MCI_ANIM_OPEN_PARMSA* = record
+  MCI_ANIM_OPEN_PARMSA* {.final.} = object
     dwCallback*: DWORD
     wDeviceID*: MCIDEVICEID
     lpstrDeviceType*: LPCSTR
@@ -2023,7 +2023,7 @@ type
   PMCI_ANIM_OPEN_PARMSA* = ptr MCI_ANIM_OPEN_PARMSA
   LPMCI_ANIM_OPEN_PARMSA* = ptr MCI_ANIM_OPEN_PARMSA
   TMCI_ANIM_OPEN_PARMSA* = MCI_ANIM_OPEN_PARMSA
-  MCI_ANIM_OPEN_PARMSW* = record
+  MCI_ANIM_OPEN_PARMSW* {.final.} = object
     dwCallback*: DWORD
     wDeviceID*: MCIDEVICEID
     lpstrDeviceType*: LPCWSTR
@@ -2047,7 +2047,7 @@ else:
     LPMCI_ANIM_OPEN_PARMS* = LPMCI_ANIM_OPEN_PARMSA
 type
   TMCI_ANIM_OPEN_PARMS* = MCI_ANIM_OPEN_PARMS
-  MCI_ANIM_WINDOW_PARMSW* = record
+  MCI_ANIM_WINDOW_PARMSW* {.final.} = object
     dwCallback*: DWORD
     hWnd*: HWND
     nCmdShow*: UINT
@@ -2056,14 +2056,14 @@ type
   PMCI_ANIM_WINDOW_PARMSW* = ptr MCI_ANIM_WINDOW_PARMSW
   LPMCI_ANIM_WINDOW_PARMSW* = ptr MCI_ANIM_WINDOW_PARMSW
   TMCI_ANIM_WINDOW_PARMSW* = MCI_ANIM_WINDOW_PARMSW
-  MCI_ANIM_STEP_PARMS* = record
+  MCI_ANIM_STEP_PARMS* {.final.} = object
     dwCallback*: DWORD
     dwFrames*: DWORD
 
   PMCI_ANIM_STEP_PARMS* = ptr MCI_ANIM_STEP_PARMS
   LPMCI_ANIM_STEP_PARMS* = ptr MCI_ANIM_STEP_PARMS
   TMCI_ANIM_STEP_PARMS* = MCI_ANIM_STEP_PARMS
-  MCI_ANIM_WINDOW_PARMSA* = record
+  MCI_ANIM_WINDOW_PARMSA* {.final.} = object
     dwCallback*: DWORD
     hWnd*: HWND
     nCmdShow*: UINT
@@ -2072,7 +2072,7 @@ type
   PMCI_ANIM_WINDOW_PARMSA* = ptr MCI_ANIM_WINDOW_PARMSA
   LPMCI_ANIM_WINDOW_PARMSA* = ptr MCI_ANIM_WINDOW_PARMSA
   TMCI_ANIM_WINDOW_PARMSA* = MCI_ANIM_WINDOW_PARMSA
-  MCI_ANIM_PLAY_PARMS* = record
+  MCI_ANIM_PLAY_PARMS* {.final.} = object
     dwCallback*: DWORD
     dwFrom*: DWORD
     dwTo*: DWORD
@@ -2092,14 +2092,14 @@ else:
     PMCI_ANIM_WINDOW_PARMS* = PMCI_ANIM_WINDOW_PARMSA
     LPMCI_ANIM_WINDOW_PARMS* = LPMCI_ANIM_WINDOW_PARMSA
 type
-  MCI_ANIM_RECT_PARMS* = record
+  MCI_ANIM_RECT_PARMS* {.final.} = object
     dwCallback*: DWORD
     rc*: TRECT
 
   PMCI_ANIM_RECT_PARMS* = ptr MCI_ANIM_RECT_PARMS
   LPMCI_ANIM_RECT_PARMS* = ptr MCI_ANIM_RECT_PARMS
   TMCI_ANIM_RECT_PARMS* = MCI_ANIM_RECT_PARMS
-  MCI_ANIM_UPDATE_PARMS* = record
+  MCI_ANIM_UPDATE_PARMS* {.final.} = object
     dwCallback*: DWORD
     rc*: TRECT
     hDC*: HDC
@@ -2107,7 +2107,7 @@ type
   PMCI_ANIM_UPDATE_PARMS* = ptr MCI_ANIM_UPDATE_PARMS
   LPMCI_ANIM_UPDATE_PARMS* = ptr MCI_ANIM_UPDATE_PARMS
   TMCI_ANIM_UPDATE_PARMS* = MCI_ANIM_UPDATE_PARMS
-  MCI_OVLY_OPEN_PARMSA* = record
+  MCI_OVLY_OPEN_PARMSA* {.final.} = object
     dwCallback*: DWORD
     wDeviceID*: MCIDEVICEID
     lpstrDeviceType*: LPCSTR
@@ -2119,7 +2119,7 @@ type
   PMCI_OVLY_OPEN_PARMSA* = ptr MCI_OVLY_OPEN_PARMSA
   LPMCI_OVLY_OPEN_PARMSA* = ptr MCI_OVLY_OPEN_PARMSA
   TMCI_OVLY_OPEN_PARMSA* = MCI_OVLY_OPEN_PARMSA
-  MCI_OVLY_OPEN_PARMSW* = record
+  MCI_OVLY_OPEN_PARMSW* {.final.} = object
     dwCallback*: DWORD
     wDeviceID*: MCIDEVICEID
     lpstrDeviceType*: LPCWSTR
@@ -2144,7 +2144,7 @@ else:
     LPMCI_OVLY_OPEN_PARMS* = LPMCI_OVLY_OPEN_PARMSA
 type
   TMCI_OVLY_OPEN_PARMS* = MCI_OVLY_OPEN_PARMS
-  MCI_OVLY_WINDOW_PARMSA* = record
+  MCI_OVLY_WINDOW_PARMSA* {.final.} = object
     dwCallback*: DWORD
     hWnd*: HWND
     nCmdShow*: UINT
@@ -2153,7 +2153,7 @@ type
   PMCI_OVLY_WINDOW_PARMSA* = ptr MCI_OVLY_WINDOW_PARMSA
   LPMCI_OVLY_WINDOW_PARMSA* = ptr MCI_OVLY_WINDOW_PARMSA
   TMCI_OVLY_WINDOW_PARMSA* = MCI_OVLY_WINDOW_PARMSA
-  MCI_OVLY_WINDOW_PARMSW* = record
+  MCI_OVLY_WINDOW_PARMSW* {.final.} = object
     dwCallback*: DWORD
     hWnd*: HWND
     nCmdShow*: UINT
@@ -2175,14 +2175,14 @@ else:
     LPMCI_OVLY_WINDOW_PARMS* = LPMCI_OVLY_WINDOW_PARMSA
 type
   TMCI_OVLY_WINDOW_PARMS* = MCI_OVLY_WINDOW_PARMSW
-  MCI_OVLY_RECT_PARMS* = record
+  MCI_OVLY_RECT_PARMS* {.final.} = object
     dwCallback*: DWORD
     rc*: TRECT
 
   PMCI_OVLY_RECT_PARMS* = ptr MCI_OVLY_RECT_PARMS
   LPMCI_OVLY_RECT_PARMS* = ptr MCI_OVLY_RECT_PARMS
   TMCI_OVLY_RECT_PARMS* = MCI_OVLY_RECT_PARMS
-  MCI_OVLY_SAVE_PARMSA* = record
+  MCI_OVLY_SAVE_PARMSA* {.final.} = object
     dwCallback*: DWORD
     lpfilename*: LPCSTR
     rc*: TRECT
@@ -2190,7 +2190,7 @@ type
   PMCI_OVLY_SAVE_PARMSA* = ptr MCI_OVLY_SAVE_PARMSA
   LPMCI_OVLY_SAVE_PARMSA* = ptr MCI_OVLY_SAVE_PARMSA
   TMCI_OVLY_SAVE_PARMSA* = MCI_OVLY_SAVE_PARMSA
-  MCI_OVLY_SAVE_PARMSW* = record
+  MCI_OVLY_SAVE_PARMSW* {.final.} = object
     dwCallback*: DWORD
     lpfilename*: LPCWSTR
     rc*: TRECT
@@ -2211,7 +2211,7 @@ else:
     LPMCI_OVLY_SAVE_PARMS* = LPMCI_OVLY_SAVE_PARMSA
 type
   TMCI_OVLY_SAVE_PARMS* = MCI_OVLY_SAVE_PARMS
-  MCI_OVLY_LOAD_PARMSA* = record
+  MCI_OVLY_LOAD_PARMSA* {.final.} = object
     dwCallback*: DWORD
     lpfilename*: LPCSTR
     rc*: TRECT
@@ -2219,7 +2219,7 @@ type
   PMCI_OVLY_LOAD_PARMSA* = ptr MCI_OVLY_LOAD_PARMSA
   LPMCI_OVLY_LOAD_PARMSA* = ptr MCI_OVLY_LOAD_PARMSA
   TMCI_OVLY_LOAD_PARMSA* = MCI_OVLY_LOAD_PARMSA
-  MCI_OVLY_LOAD_PARMSW* = record
+  MCI_OVLY_LOAD_PARMSW* {.final.} = object
     dwCallback*: DWORD
     lpfilename*: LPCWSTR
     rc*: TRECT
diff --git a/lib/windows/nb30.nim b/lib/windows/nb30.nim
index 8c61bbaf7..615488ac1 100644
--- a/lib/windows/nb30.nim
+++ b/lib/windows/nb30.nim
@@ -8,7 +8,7 @@
 #
 #       NetBIOS 3.0 interface unit 
 
-# This unit contains the definitions for portable NetBIOS 3.0 support. 
+# This module contains the definitions for portable NetBIOS 3.0 support. 
 
 import                        # Data structure templates 
   Windows
@@ -20,8 +20,8 @@ const
 type                          # Network Control Block
   PNCB* = ptr TNCB
   TNCBPostProc* = proc (P: PNCB)
-  TNCB* = record # Structure returned to the NCB command NCBASTAT is ADAPTER_STATUS followed
-                 # by an array of NAME_BUFFER structures.
+  TNCB* {.final.} = object # Structure returned to the NCB command NCBASTAT is ADAPTER_STATUS followed
+                           # by an array of NAME_BUFFER structures.
     ncb_command*: Char        # command code
     ncb_retcode*: Char        # return code
     ncb_lsn*: Char            # local session number
@@ -42,7 +42,7 @@ type                          # Network Control Block
                               # completes
   
   PAdapterStatus* = ptr TAdapterStatus
-  TAdapterStatus* = record 
+  TAdapterStatus* {.final.} = object 
     adapter_address*: array[0..5, Char]
     rev_major*: Char
     reserved0*: Char
@@ -72,7 +72,7 @@ type                          # Network Control Block
     name_count*: int16
 
   PNameBuffer* = ptr TNameBuffer
-  TNameBuffer* = record 
+  TNameBuffer* {.final.} = object 
     name*: array[0..NCBNAMSZ - 1, Char]
     name_num*: Char
     name_flags*: Char
@@ -93,14 +93,14 @@ type # Structure returned to the NCB command NCBSSTAT is SESSION_HEADER followed
      # asterisk then an array of these structures is returned containing the
      # status for all names.
   PSessionHeader* = ptr TSessionHeader
-  TSessionHeader* = record 
+  TSessionHeader* {.final.} = object 
     sess_name*: Char
     num_sess*: Char
     rcv_dg_outstanding*: Char
     rcv_any_outstanding*: Char
 
   PSessionBuffer* = ptr TSessionBuffer
-  TSessionBuffer* = record 
+  TSessionBuffer* {.final.} = object 
     lsn*: Char
     state*: Char
     local_name*: array[0..NCBNAMSZ - 1, Char]
@@ -121,20 +121,20 @@ type # Structure returned to the NCB command NCBENUM.
      # On a system containing lana's 0, 2 and 3, a structure with
      # length =3, lana[0]=0, lana[1]=2 and lana[2]=3 will be returned.
   PLanaEnum* = ptr TLanaEnum
-  TLanaEnum* = record # Structure returned to the NCB command NCBFINDNAME is FIND_NAME_HEADER followed
-                      # by an array of FIND_NAME_BUFFER structures.
+  TLanaEnum* {.final.} = object # Structure returned to the NCB command NCBFINDNAME is FIND_NAME_HEADER followed
+                                # by an array of FIND_NAME_BUFFER structures.
     len*: Char                #  Number of valid entries in lana[]
     lana*: array[0..MAX_LANA, Char]
 
   PFindNameHeader* = ptr TFindNameHeader
-  TFindNameHeader* = record 
+  TFindNameHeader* {.final.} = object 
     node_count*: int16
     reserved*: Char
     unique_group*: Char
 
   PFindNameBuffer* = ptr TFindNameBuffer
-  TFindNameBuffer* = record # Structure provided with NCBACTION. The purpose of NCBACTION is to provide
-                            # transport specific extensions to netbios.
+  TFindNameBuffer* {.final.} = object # Structure provided with NCBACTION. The purpose of NCBACTION is to provide
+                                      # transport specific extensions to netbios.
     len*: Char
     access_control*: Char
     frame_control*: Char
@@ -143,7 +143,7 @@ type # Structure returned to the NCB command NCBENUM.
     routing_info*: array[0..17, Char]
 
   PActionHeader* = ptr TActionHeader
-  TActionHeader* = record 
+  TActionHeader* {.final.} = object 
     transport_id*: int32
     action_code*: int16
     reserved*: int16
diff --git a/lib/windows/shellapi.nim b/lib/windows/shellapi.nim
index fbbd1999a..af6972c96 100644
--- a/lib/windows/shellapi.nim
+++ b/lib/windows/shellapi.nim
@@ -33,7 +33,7 @@ type
   DWORD_PTR* = ptr DWORD
   pHICON* = ptr HICON
   pBool* = ptr BOOL
-  STARTUPINFOW* = record      # a guess. Omission should get fixed in Windows.
+  STARTUPINFOW* {.final.} = object      # a guess. Omission should get fixed in Windows.
     cb*: DWORD
     lpReserved*: LPTSTR
     lpDesktop*: LPTSTR
@@ -122,7 +122,7 @@ proc ExtractIcon*(hInst: HINST, lpszExeFileName: LPCWSTR, nIconIndex: UINT): HIC
     stdcall, dynlib: "shell32.dll", importc: "ExtractIconW".}
   # if(WINVER >= 0x0400)
 type                          # init with sizeof(DRAGINFO)
-  DRAGINFOA* = record
+  DRAGINFOA* {.final.} = object
     uSize*: UINT
     pt*: POINT
     fNC*: BOOL
@@ -131,7 +131,7 @@ type                          # init with sizeof(DRAGINFO)
 
   TDRAGINFOA* = DRAGINFOA
   LPDRAGINFOA* = ptr DRAGINFOA # init with sizeof(DRAGINFO)
-  DRAGINFOW* = record
+  DRAGINFOW* {.final.} = object
     uSize*: UINT
     pt*: POINT
     fNC*: BOOL
@@ -178,7 +178,7 @@ const
   ABE_BOTTOM* = 3
 
 type
-  AppBarData* = record
+  AppBarData* {.final.} = object
     cbSize*: DWORD
     hWnd*: HWND
     uCallbackMessage*: UINT
@@ -286,7 +286,7 @@ type
                            # only used if FOF_SIMPLEPROGRESS
 
 type
-  SHFILEOPSTRUCTA* = record
+  SHFILEOPSTRUCTA* {.final.} = object
     hwnd*: HWND
     wFunc*: UINT
     pFrom*: LPCSTR
@@ -298,7 +298,7 @@ type
 
   TSHFILEOPSTRUCTA* = SHFILEOPSTRUCTA
   LPSHFILEOPSTRUCTA* = ptr SHFILEOPSTRUCTA
-  SHFILEOPSTRUCTW* = record
+  SHFILEOPSTRUCTW* {.final.} = object
     hwnd*: HWND
     wFunc*: UINT
     pFrom*: LPCWSTR
@@ -332,7 +332,7 @@ proc SHFileOperation*(lpFileOp: LPSHFILEOPSTRUCTW): int32{.stdcall,
 proc SHFreeNameMappings*(hNameMappings: THandle){.stdcall,
     dynlib: "shell32.dll", importc: "SHFreeNameMappings".}
 type
-  SHNAMEMAPPINGA* = record
+  SHNAMEMAPPINGA* {.final.} = object
     pszOldPath*: LPSTR
     pszNewPath*: LPSTR
     cchOldPath*: int32
@@ -340,7 +340,7 @@ type
 
   TSHNAMEMAPPINGA* = SHNAMEMAPPINGA
   LPSHNAMEMAPPINGA* = ptr SHNAMEMAPPINGA
-  SHNAMEMAPPINGW* = record
+  SHNAMEMAPPINGW* {.final.} = object
     pszOldPath*: LPWSTR
     pszNewPath*: LPWSTR
     cchOldPath*: int32
@@ -404,7 +404,7 @@ const
                                         # (_WIN32_IE >= 0x560)
 
 type
-  SHELLEXECUTEINFOA* = record
+  SHELLEXECUTEINFOA* {.final.} = object
     cbSize*: DWORD
     fMask*: ULONG
     hwnd*: HWND
@@ -423,7 +423,7 @@ type
 
   TSHELLEXECUTEINFOA* = SHELLEXECUTEINFOA
   LPSHELLEXECUTEINFOA* = ptr SHELLEXECUTEINFOA
-  SHELLEXECUTEINFOW* = record
+  SHELLEXECUTEINFOW* {.final.} = object
     cbSize*: DWORD
     fMask*: ULONG
     hwnd*: HWND
@@ -474,7 +474,7 @@ proc WinExecError*(HWND: hwnd, error: int32, lpstrFileName: LPCWSTR,
                    lpstrTitle: LPCWSTR){.stdcall, dynlib: "shell32.dll",
     importc: "WinExecErrorW".}
 type
-  SHCREATEPROCESSINFOW* = record
+  SHCREATEPROCESSINFOW* {.final.} = object
     cbSize*: DWORD
     fMask*: ULONG
     hwnd*: HWND
@@ -502,7 +502,7 @@ proc SHCreateProcessAsUserW*(pscpi: PSHCREATEPROCESSINFOW): Bool{.stdcall,
   #
   # struct for query recycle bin info
 type
-  SHQUERYRBINFO* = record
+  SHQUERYRBINFO* {.final.} = object
     cbSize*: DWORD
     i64Size*: int64
     i64NumItems*: int64
@@ -538,7 +538,7 @@ proc SHEmptyRecycleBin*(hwnd: HWND, pszRootPath: LPCWSTR, dwFlags: DWORD): HRESU
   # Tray notification definitions
   #
 type
-  NOTIFYICONDATAA* = record
+  NOTIFYICONDATAA* {.final.} = object
     cbSize*: DWORD
     hWnd*: HWND
     uID*: UINT
@@ -556,7 +556,7 @@ type
 
   TNOTIFYICONDATAA* = NOTIFYICONDATAA
   PNOTIFYICONDATAA* = ptr NOTIFYICONDATAA
-  NOTIFYICONDATAW* = record
+  NOTIFYICONDATAW* {.final.} = object
     cbSize*: DWORD
     hWnd*: HWND
     uID*: UINT
@@ -645,7 +645,7 @@ proc Shell_NotifyIcon*(dwMessage: Dword, lpData: PNOTIFYICONDATAW): Bool{.
   # out: display name (or path)
   # out: type name
 type
-  SHFILEINFOA* = record
+  SHFILEINFOA* {.final.} = object
     hIcon*: HICON             # out: icon
     iIcon*: int32             # out: icon index
     dwAttributes*: DWORD      # out: SFGAO_ flags
@@ -654,7 +654,7 @@ type
 
   TSHFILEINFOA* = SHFILEINFOA
   pSHFILEINFOA* = ptr SHFILEINFOA
-  SHFILEINFOW* = record
+  SHFILEINFOW* {.final.} = object
     hIcon*: HICON             # out: icon
     iIcon*: int32             # out: icon index
     dwAttributes*: DWORD      # out: SFGAO_ flags
diff --git a/lib/windows/windows.nim b/lib/windows/windows.nim
index 409977e7a..ab87bbd98 100644
--- a/lib/windows/windows.nim
+++ b/lib/windows/windows.nim
@@ -5030,7 +5030,7 @@ const
                               # added manually PM, TREEITEM is not defined in the C headers
 
 type
-  TREEITEM* = record
+  TREEITEM* {.final.} = object
   HTREEITEM* = ptr TREEITEM
   TTREEITEM* = TREEITEM
   PTREEITEM* = ptr TREEITEM   # was #define dname def_expr
@@ -6481,7 +6481,7 @@ type                          # WARNING
                               #      va_list is just a dummy record
                               #      MvdV: Nevertheless it should be a pointer type, not a record
   va_list* = cstring
-  ABC* = record
+  ABC* {.final.} = object
     abcA*: int32
     abcB*: UINT
     abcC*: int32
@@ -6489,7 +6489,7 @@ type                          # WARNING
   LPABC* = ptr ABC
   TABC* = ABC
   PABC* = ptr ABC
-  ABCFLOAT* = record
+  ABCFLOAT* {.final.} = object
     abcfA*: float32
     abcfB*: float32
     abcfC*: float32
@@ -6497,7 +6497,7 @@ type                          # WARNING
   LPABCFLOAT* = ptr ABCFLOAT
   TABCFLOAT* = ABCFLOAT
   PABCFLOAT* = ptr ABCFLOAT
-  ACCEL* = record
+  ACCEL* {.final.} = object
     fVirt*: int8
     key*: int16
     cmd*: int16
@@ -6505,7 +6505,7 @@ type                          # WARNING
   LPACCEL* = ptr ACCEL
   TACCEL* = ACCEL
   PACCEL* = ptr ACCEL
-  ACE_HEADER* = record
+  ACE_HEADER* {.final.} = object
     AceType*: int8
     AceFlags*: int8
     AceSize*: int16
@@ -6514,27 +6514,27 @@ type                          # WARNING
   PACE_HEADER* = ptr ACE_HEADER
   ACCESS_MASK* = DWORD
   REGSAM* = ACCESS_MASK
-  ACCESS_ALLOWED_ACE* = record
+  ACCESS_ALLOWED_ACE* {.final.} = object
     Header*: ACE_HEADER
     Mask*: ACCESS_MASK
     SidStart*: DWORD
 
   TACCESS_ALLOWED_ACE* = ACCESS_ALLOWED_ACE
   PACCESS_ALLOWED_ACE* = ptr ACCESS_ALLOWED_ACE
-  ACCESS_DENIED_ACE* = record
+  ACCESS_DENIED_ACE* {.final.} = object
     Header*: ACE_HEADER
     Mask*: ACCESS_MASK
     SidStart*: DWORD
 
   TACCESS_DENIED_ACE* = ACCESS_DENIED_ACE
-  ACCESSTIMEOUT* = record
+  ACCESSTIMEOUT* {.final.} = object
     cbSize*: UINT
     dwFlags*: DWORD
     iTimeOutMSec*: DWORD
 
   TACCESSTIMEOUT* = ACCESSTIMEOUT
   PACCESSTIMEOUT* = ptr ACCESSTIMEOUT
-  ACL* = record
+  ACL* {.final.} = object
     AclRevision*: int8
     Sbz1*: int8
     AclSize*: int16
@@ -6543,23 +6543,23 @@ type                          # WARNING
 
   PACL* = ptr ACL
   TACL* = ACL
-  TACL_REVISION_INFORMATION* = record
+  TACL_REVISION_INFORMATION* {.final.} = object
     AclRevision*: DWORD
   PACLREVISIONINFORMATION* = ptr TACL_REVISION_INFORMATION
 
-  TACL_SIZE_INFORMATION* = record
+  TACL_SIZE_INFORMATION* {.final.} = object
     AceCount*: DWORD
     AclBytesInUse*: DWORD
     AclBytesFree*: DWORD
   PACLSIZEINFORMATION* = ptr TACL_SIZE_INFORMATION
-  ACTION_HEADER* = record
+  ACTION_HEADER* {.final.} = object
     transport_id*: ULONG
     action_code*: USHORT
     reserved*: USHORT
 
   TACTIONHEADER* = ACTION_HEADER
   PACTIONHEADER* = ptr ACTION_HEADER
-  ADAPTER_STATUS* = record
+  ADAPTER_STATUS* {.final.} = object
     adapter_address*: array[0..5, UCHAR]
     rev_major*: UCHAR
     reserved0*: UCHAR
@@ -6590,33 +6590,33 @@ type                          # WARNING
 
   TADAPTERSTATUS* = ADAPTER_STATUS
   PADAPTERSTATUS* = ptr ADAPTER_STATUS
-  ADDJOB_INFO_1* = record
+  ADDJOB_INFO_1* {.final.} = object
     Path*: LPTSTR
     JobId*: DWORD
 
   TADDJOB_INFO_1* = ADDJOB_INFO_1
   PADDJOB_INFO_1* = ptr ADDJOB_INFO_1
-  ANIMATIONINFO* = record
+  ANIMATIONINFO* {.final.} = object
     cbSize*: UINT
     iMinAnimate*: int32
 
   LPANIMATIONINFO* = ptr ANIMATIONINFO
   TANIMATIONINFO* = ANIMATIONINFO
   PANIMATIONINFO* = ptr ANIMATIONINFO
-  POINT* = record
+  POINT* {.final.} = object
     x*: LONG
     y*: LONG
 
   LPPOINT* = ptr POINT
   TPOINT* = POINT
   PPOINT* = ptr POINT
-  RECT* = record
+  RECT* {.final.} = object
     TopLeft*, BottomRight*: TPoint
 
   LPRECT* = ptr RECT
   TRECT* = RECT
   PRECT* = ptr RECT
-  RECTL* = record
+  RECTL* {.final.} = object
     left*: LONG
     top*: LONG
     right*: LONG
@@ -6624,7 +6624,7 @@ type                          # WARNING
 
   TRECTL* = RECTL
   PRECTL* = ptr RECTL
-  APPBARDATA* = record
+  APPBARDATA* {.final.} = object
     cbSize*: DWORD
     hWnd*: HWND
     uCallbackMessage*: UINT
@@ -6634,7 +6634,7 @@ type                          # WARNING
 
   TAppBarData* = APPBARDATA
   PAppBarData* = ptr APPBARDATA
-  BITMAP* = record
+  BITMAP* {.final.} = object
     bmType*: LONG
     bmWidth*: LONG
     bmHeight*: LONG
@@ -6648,7 +6648,7 @@ type                          # WARNING
   LPBITMAP* = ptr BITMAP
   tagBITMAP* = BITMAP
   TBITMAP* = BITMAP
-  BITMAPCOREHEADER* = record
+  BITMAPCOREHEADER* {.final.} = object
     bcSize*: DWORD
     bcWidth*: int16
     bcHeight*: int16
@@ -6657,14 +6657,14 @@ type                          # WARNING
 
   TBITMAPCOREHEADER* = BITMAPCOREHEADER
   PBITMAPCOREHEADER* = ptr BITMAPCOREHEADER
-  RGBTRIPLE* = record
+  RGBTRIPLE* {.final.} = object
     rgbtBlue*: int8
     rgbtGreen*: int8
     rgbtRed*: int8
 
   TRGBTRIPLE* = RGBTRIPLE
   PRGBTRIPLE* = ptr RGBTRIPLE
-  BITMAPCOREINFO* = record
+  BITMAPCOREINFO* {.final.} = object
     bmciHeader*: BITMAPCOREHEADER
     bmciColors*: array[0..0, RGBTRIPLE]
 
@@ -6674,7 +6674,7 @@ type                          # WARNING
                                     #  WORD    bfReserved1;
                                     #  WORD    bfReserved2;
                                     # in declarator_list
-  BITMAPINFOHEADER* = record
+  BITMAPINFOHEADER* {.final.} = object
     biSize*: DWORD
     biWidth*: LONG
     biHeight*: LONG
@@ -6690,7 +6690,7 @@ type                          # WARNING
   LPBITMAPINFOHEADER* = ptr BITMAPINFOHEADER
   TBITMAPINFOHEADER* = BITMAPINFOHEADER
   PBITMAPINFOHEADER* = ptr BITMAPINFOHEADER
-  RGBQUAD* = record
+  RGBQUAD* {.final.} = object
     rgbBlue*: int8
     rgbGreen*: int8
     rgbRed*: int8
@@ -6699,7 +6699,7 @@ type                          # WARNING
   tagRGBQUAD* = RGBQUAD
   TRGBQUAD* = RGBQUAD
   PRGBQUAD* = ptr RGBQUAD
-  BITMAPINFO* = record
+  BITMAPINFO* {.final.} = object
     bmiHeader*: BITMAPINFOHEADER
     bmiColors*: array[0..0, RGBQUAD]
 
@@ -6710,7 +6710,7 @@ type                          # WARNING
   LPFXPT2DOT30* = ptr FXPT2DOT30
   TPFXPT2DOT30* = FXPT2DOT30
   PPFXPT2DOT30* = ptr FXPT2DOT30
-  CIEXYZ* = record
+  CIEXYZ* {.final.} = object
     ciexyzX*: FXPT2DOT30
     ciexyzY*: FXPT2DOT30
     ciexyzZ*: FXPT2DOT30
@@ -6719,7 +6719,7 @@ type                          # WARNING
   LPCIEXYZ* = ptr CIEXYZ
   TPCIEXYZ* = CIEXYZ
   PCIEXYZ* = ptr CIEXYZ
-  CIEXYZTRIPLE* = record
+  CIEXYZTRIPLE* {.final.} = object
     ciexyzRed*: CIEXYZ
     ciexyzGreen*: CIEXYZ
     ciexyzBlue*: CIEXYZ
@@ -6728,7 +6728,7 @@ type                          # WARNING
   LPCIEXYZTRIPLE* = ptr CIEXYZTRIPLE
   TCIEXYZTRIPLE* = CIEXYZTRIPLE
   PCIEXYZTRIPLE* = ptr CIEXYZTRIPLE
-  BITMAPV4HEADER* = record
+  BITMAPV4HEADER* {.final.} = object
     bV4Size*: DWORD
     bV4Width*: LONG
     bV4Height*: LONG
@@ -6753,20 +6753,20 @@ type                          # WARNING
   LPBITMAPV4HEADER* = ptr BITMAPV4HEADER
   TBITMAPV4HEADER* = BITMAPV4HEADER
   PBITMAPV4HEADER* = ptr BITMAPV4HEADER
-  BITMAPFILEHEADER* = record
+  BITMAPFILEHEADER* {.final.} = object
     bfType*: int16
     bfSize*: DWord
     bfReserved1*: int16
     bfReserved2*: int16
     bfOffBits*: DWord
 
-  BLOB* = record
+  BLOB* {.final.} = object
     cbSize*: ULONG
     pBlobData*: ptr int8
 
   TBLOB* = BLOB
   PBLOB* = ptr BLOB
-  SHITEMID* = record
+  SHITEMID* {.final.} = object
     cb*: USHORT
     abID*: array[0..0, int8]
 
@@ -6774,14 +6774,14 @@ type                          # WARNING
   LPCSHITEMID* = ptr SHITEMID
   TSHITEMID* = SHITEMID
   PSHITEMID* = ptr SHITEMID
-  ITEMIDLIST* = record
+  ITEMIDLIST* {.final.} = object
     mkid*: SHITEMID
 
   LPITEMIDLIST* = ptr ITEMIDLIST
   LPCITEMIDLIST* = ptr ITEMIDLIST
   TITEMIDLIST* = ITEMIDLIST
   PITEMIDLIST* = ptr ITEMIDLIST
-  BROWSEINFO* = record
+  BROWSEINFO* {.final.} = object
     hwndOwner*: HWND
     pidlRoot*: LPCITEMIDLIST
     pszDisplayName*: LPSTR
@@ -6794,14 +6794,14 @@ type                          # WARNING
   LPBROWSEINFO* = ptr BROWSEINFO
   Tbrowseinfo* = BROWSEINFO
   PBROWSEINFO* = ptr BROWSEINFO
-  FILETIME* = record
+  FILETIME* {.final.} = object
     dwLowDateTime*: DWORD
     dwHighDateTime*: DWORD
 
   LPFILETIME* = ptr FILETIME
   TFILETIME* = FILETIME
   PFILETIME* = ptr FILETIME
-  BY_HANDLE_FILE_INFORMATION* = record
+  BY_HANDLE_FILE_INFORMATION* {.final.} = object
     dwFileAttributes*: DWORD
     ftCreationTime*: FILETIME
     ftLastAccessTime*: FILETIME
@@ -6816,34 +6816,34 @@ type                          # WARNING
   LPBY_HANDLE_FILE_INFORMATION* = ptr BY_HANDLE_FILE_INFORMATION
   TBYHANDLEFILEINFORMATION* = BY_HANDLE_FILE_INFORMATION
   PBYHANDLEFILEINFORMATION* = ptr BY_HANDLE_FILE_INFORMATION
-  FIXED* = record
+  FIXED* {.final.} = object
     fract*: int16
     value*: SHORT
 
   TFIXED* = FIXED
   PFIXED* = ptr FIXED
-  POINTFX* = record
+  POINTFX* {.final.} = object
     x*: FIXED
     y*: FIXED
 
   TPOINTFX* = POINTFX
   PPOINTFX* = ptr POINTFX
-  POINTL* = record
+  POINTL* {.final.} = object
     x*: LONG
     y*: LONG
 
   TPOINTL* = POINTL
   PPOINTL* = ptr POINTL
-  TSmallPoint* = record
+  TSmallPoint* {.final.} = object
     X*, Y*: SHORT
 
-  POINTS* = record
+  POINTS* {.final.} = object
     x*: SHORT
     y*: SHORT
 
   TPOINTS* = POINTS
   PPOINTS* = ptr POINTS
-  CANDIDATEFORM* = record
+  CANDIDATEFORM* {.final.} = object
     dwIndex*: DWORD
     dwStyle*: DWORD
     ptCurrentPos*: POINT
@@ -6852,7 +6852,7 @@ type                          # WARNING
   LPCANDIDATEFORM* = ptr CANDIDATEFORM
   TCANDIDATEFORM* = CANDIDATEFORM
   PCANDIDATEFORM* = ptr CANDIDATEFORM
-  CANDIDATELIST* = record
+  CANDIDATELIST* {.final.} = object
     dwSize*: DWORD
     dwStyle*: DWORD
     dwCount*: DWORD
@@ -6864,7 +6864,7 @@ type                          # WARNING
   LPCANDIDATELIST* = ptr CANDIDATELIST
   TCANDIDATELIST* = CANDIDATELIST
   PCANDIDATELIST* = ptr CANDIDATELIST
-  CREATESTRUCT* = record
+  CREATESTRUCT* {.final.} = object
     lpCreateParams*: LPVOID
     hInstance*: HINST
     hMenu*: HMENU
@@ -6881,25 +6881,25 @@ type                          # WARNING
   LPCREATESTRUCT* = ptr CREATESTRUCT
   TCREATESTRUCT* = CREATESTRUCT
   PCREATESTRUCT* = ptr CREATESTRUCT
-  CBT_CREATEWND* = record
+  CBT_CREATEWND* {.final.} = object
     lpcs*: LPCREATESTRUCT
     hwndInsertAfter*: HWND
 
   TCBT_CREATEWND* = CBT_CREATEWND
   PCBT_CREATEWND* = ptr CBT_CREATEWND
-  CBTACTIVATESTRUCT* = record
+  CBTACTIVATESTRUCT* {.final.} = object
     fMouse*: WINBOOL
     hWndActive*: HWND
 
   TCBTACTIVATESTRUCT* = CBTACTIVATESTRUCT
   PCBTACTIVATESTRUCT* = ptr CBTACTIVATESTRUCT
-  CHAR_INFO* = record
+  CHAR_INFO* {.final.} = object
     UnicodeChar*: WCHAR
     Attributes*: int16        # other union part: AsciiChar : CHAR
 
   TCHAR_INFO* = CHAR_INFO
   PCHAR_INFO* = ptr CHAR_INFO
-  CHARFORMAT* = record
+  CHARFORMAT* {.final.} = object
     cbSize*: UINT
     dwMask*: DWORD
     dwEffects*: DWORD
@@ -6912,19 +6912,19 @@ type                          # WARNING
 
   Tcharformat* = CHARFORMAT
   Pcharformat* = ptr CHARFORMAT
-  CHARRANGE* = record
+  CHARRANGE* {.final.} = object
     cpMin*: LONG
     cpMax*: LONG
 
   Tcharrange* = CHARRANGE
   Pcharrange* = ptr CHARRANGE
-  CHARSET* = record
+  CHARSET* {.final.} = object
     aflBlock*: array[0..2, DWORD]
     flLang*: DWORD
 
   TCHARSET* = CHARSET
   PCHARSET* = ptr CHARSET
-  FONTSIGNATURE* = record
+  FONTSIGNATURE* {.final.} = object
     fsUsb*: array[0..3, DWORD]
     fsCsb*: array[0..1, DWORD]
 
@@ -6932,7 +6932,7 @@ type                          # WARNING
   tagFONTSIGNATURE* = FONTSIGNATURE
   TFONTSIGNATURE* = FONTSIGNATURE
   PFONTSIGNATURE* = ptr FONTSIGNATURE
-  CHARSETINFO* = record
+  CHARSETINFO* {.final.} = object
     ciCharset*: UINT
     ciACP*: UINT
     fs*: FONTSIGNATURE
@@ -6940,7 +6940,7 @@ type                          # WARNING
   LPCHARSETINFO* = ptr CHARSETINFO
   TCHARSETINFO* = CHARSETINFO
   PCHARSETINFO* = ptr CHARSETINFO #CHOOSECOLOR = record confilcts with function ChooseColor
-  TCHOOSECOLOR* = record
+  TCHOOSECOLOR* {.final.} = object
     lStructSize*: DWORD
     hwndOwner*: HWND
     hInstance*: HWND
@@ -6953,7 +6953,7 @@ type                          # WARNING
 
   LPCHOOSECOLOR* = ptr TCHOOSECOLOR
   PCHOOSECOLOR* = ptr TCHOOSECOLOR
-  LOGFONT* = record
+  LOGFONT* {.final.} = object
     lfHeight*: LONG
     lfWidth*: LONG
     lfEscapement*: LONG
@@ -6974,7 +6974,7 @@ type                          # WARNING
   TLOGFONTA* = LOGFONT
   PLOGFONT* = ptr LOGFONT
   PLOGFONTA* = PLOGFONT
-  LOGFONTW* = record
+  LOGFONTW* {.final.} = object
     lfHeight*: LONG
     lfWidth*: LONG
     lfEscapement*: LONG
@@ -6994,7 +6994,7 @@ type                          # WARNING
   NPLOGFONTW* = ptr LOGFONTW
   TLogFontW* = LOGFONTW
   PLogFontW* = ptr TLogFontW
-  TCHOOSEFONT* = record
+  TCHOOSEFONT* {.final.} = object
     lStructSize*: DWORD
     hwndOwner*: HWND
     hDC*: HDC
@@ -7014,14 +7014,14 @@ type                          # WARNING
 
   LPCHOOSEFONT* = ptr TCHOOSEFONT
   PCHOOSEFONT* = ptr TCHOOSEFONT
-  CIDA* = record
+  CIDA* {.final.} = object
     cidl*: UINT
     aoffset*: array[0..0, UINT]
 
   LPIDA* = ptr CIDA
   TIDA* = CIDA
   PIDA* = ptr CIDA
-  CLIENTCREATESTRUCT* = record
+  CLIENTCREATESTRUCT* {.final.} = object
     hWindowMenu*: HANDLE
     idFirstChild*: UINT
 
@@ -7029,7 +7029,7 @@ type                          # WARNING
   tagCLIENTCREATESTRUCT* = CLIENTCREATESTRUCT
   TCLIENTCREATESTRUCT* = CLIENTCREATESTRUCT
   PCLIENTCREATESTRUCT* = ptr CLIENTCREATESTRUCT
-  CMINVOKECOMMANDINFO* = record
+  CMINVOKECOMMANDINFO* {.final.} = object
     cbSize*: DWORD
     fMask*: DWORD
     hwnd*: HWND
@@ -7043,7 +7043,7 @@ type                          # WARNING
   LPCMINVOKECOMMANDINFO* = ptr CMINVOKECOMMANDINFO
   TCMInvokeCommandInfo* = CMINVOKECOMMANDINFO
   PCMInvokeCommandInfo* = ptr CMINVOKECOMMANDINFO
-  COLORADJUSTMENT* = record
+  COLORADJUSTMENT* {.final.} = object
     caSize*: int16
     caFlags*: int16
     caIlluminantIndex*: int16
@@ -7061,14 +7061,14 @@ type                          # WARNING
   tagCOLORADJUSTMENT* = COLORADJUSTMENT
   TCOLORADJUSTMENT* = COLORADJUSTMENT
   PCOLORADJUSTMENT* = ptr COLORADJUSTMENT
-  COLORMAP* = record
+  COLORMAP* {.final.} = object
     `from`*: COLORREF
     `to`*: COLORREF          # XXX!
 
   LPCOLORMAP* = ptr COLORMAP
   TCOLORMAP* = COLORMAP
   PCOLORMAP* = ptr COLORMAP
-  DCB* = record
+  DCB* {.final.} = object
     DCBlength*: DWORD
     BaudRate*: DWORD
     flags*: DWORD
@@ -7148,7 +7148,7 @@ proc set_fAbortOnError*(a: var DCB, fAbortOnError: DWORD)
 proc fDummy2*(a: var DCB): DWORD
 proc set_fDummy2*(a: var DCB, fDummy2: DWORD)
 type
-  COMMCONFIG* = record
+  COMMCONFIG* {.final.} = object
     dwSize*: DWORD
     wVersion*: int16
     wReserved*: int16
@@ -7161,7 +7161,7 @@ type
   LPCOMMCONFIG* = ptr COMMCONFIG
   TCOMMCONFIG* = COMMCONFIG
   PCOMMCONFIG* = ptr COMMCONFIG
-  COMMPROP* = record
+  COMMPROP* {.final.} = object
     wPacketLength*: int16
     wPacketVersion*: int16
     dwServiceMask*: DWORD
@@ -7184,7 +7184,7 @@ type
   LPCOMMPROP* = ptr COMMPROP
   TCOMMPROP* = COMMPROP
   PCOMMPROP* = ptr COMMPROP
-  COMMTIMEOUTS* = record
+  COMMTIMEOUTS* {.final.} = object
     ReadIntervalTimeout*: DWORD
     ReadTotalTimeoutMultiplier*: DWORD
     ReadTotalTimeoutConstant*: DWORD
@@ -7194,7 +7194,7 @@ type
   LPCOMMTIMEOUTS* = ptr COMMTIMEOUTS
   TCOMMTIMEOUTS* = COMMTIMEOUTS
   PCOMMTIMEOUTS* = ptr COMMTIMEOUTS
-  COMPAREITEMSTRUCT* = record
+  COMPAREITEMSTRUCT* {.final.} = object
     CtlType*: UINT
     CtlID*: UINT
     hwndItem*: HWND
@@ -7206,14 +7206,14 @@ type
   tagCOMPAREITEMSTRUCT* = COMPAREITEMSTRUCT
   TCOMPAREITEMSTRUCT* = COMPAREITEMSTRUCT
   PCOMPAREITEMSTRUCT* = ptr COMPAREITEMSTRUCT
-  COMPCOLOR* = record
+  COMPCOLOR* {.final.} = object
     crText*: COLORREF
     crBackground*: COLORREF
     dwEffects*: DWORD
 
   TCOMPCOLOR* = COMPCOLOR
   PCOMPCOLOR* = ptr COMPCOLOR
-  COMPOSITIONFORM* = record
+  COMPOSITIONFORM* {.final.} = object
     dwStyle*: DWORD
     ptCurrentPos*: POINT
     rcArea*: RECT
@@ -7222,7 +7222,7 @@ type
   TCOMPOSITIONFORM* = COMPOSITIONFORM
   PCOMPOSITIONFORM* = ptr COMPOSITIONFORM #     TComStatFlags = set of (fCtsHold, fDsrHold, fRlsdHold , fXoffHold ,
                                           #                    fXoffSent , fEof ,  fTxim  , fReserved);
-  COMSTAT* = record
+  COMSTAT* {.final.} = object
     flag0*: DWORD             # can't use tcomstatflags, set packing issues
                               # and conflicts with macro's
     cbInQue*: DWORD
@@ -7268,20 +7268,20 @@ proc set_fTxim*(a: var COMSTAT, fTxim: DWORD)
 proc fReserved*(a: var COMSTAT): DWORD
 proc set_fReserved*(a: var COMSTAT, fReserved: DWORD)
 type
-  CONSOLE_CURSOR_INFO* = record
+  CONSOLE_CURSOR_INFO* {.final.} = object
     dwSize*: DWORD
     bVisible*: WINBOOL
 
   PCONSOLE_CURSOR_INFO* = ptr CONSOLE_CURSOR_INFO
   TCONSOLECURSORINFO* = CONSOLE_CURSOR_INFO
   TCURSORINFO* = CONSOLE_CURSOR_INFO
-  COORD* = record
+  COORD* {.final.} = object
     X*: SHORT
     Y*: SHORT
 
   TCOORD* = COORD
   PCOORD* = ptr COORD
-  SMALL_RECT* = record
+  SMALL_RECT* {.final.} = object
     Left*: SHORT
     Top*: SHORT
     Right*: SHORT
@@ -7289,7 +7289,7 @@ type
 
   TSMALL_RECT* = SMALL_RECT
   PSMALL_RECT* = ptr SMALL_RECT
-  CONSOLE_SCREEN_BUFFER_INFO* = record
+  CONSOLE_SCREEN_BUFFER_INFO* {.final.} = object
     dwSize*: COORD
     dwCursorPosition*: COORD
     wAttributes*: int16
@@ -7301,7 +7301,7 @@ type
 
 when defined(i386):
   type
-    FLOATING_SAVE_AREA* = record
+    FLOATING_SAVE_AREA* {.final.} = object
       ControlWord*: DWORD
       StatusWord*: DWORD
       TagWord*: DWORD
@@ -7314,7 +7314,7 @@ when defined(i386):
 
     TFLOATINGSAVEAREA* = FLOATING_SAVE_AREA
     PFLOATINGSAVEAREA* = ptr FLOATING_SAVE_AREA
-    CONTEXT* = record
+    CONTEXT* {.final.} = object
       ContextFlags*: DWORD
       Dr0*: DWORD
       Dr1*: DWORD
@@ -7345,7 +7345,7 @@ when defined(x86_64):
   # Define 128-bit 16-byte aligned xmm register type.
   #
   type
-    M128A* = record
+    M128A* {.final.} = object
       Low*: ULONGLONG
       High*: LONGLONG
 
@@ -7355,7 +7355,7 @@ when defined(x86_64):
                      #
                      #typedef struct _XMM_SAVE_AREA32 {
   type
-    XMM_SAVE_AREA32* = record
+    XMM_SAVE_AREA32* {.final.} = object
       ControlWord*: int16
       StatusWord*: int16
       TagWord*: int8
@@ -7378,7 +7378,7 @@ when defined(x86_64):
   const
     LEGACY_SAVE_AREA_LENGTH* = sizeof(XMM_SAVE_AREA32)
   type
-    CONTEXT* = record
+    CONTEXT* {.final.} = object
       P1Home*: DWORD64
       P2Home*: DWORD64
       P3Home*: DWORD64
@@ -7465,7 +7465,7 @@ when defined(powerpc32):
   # Debug Status Register
   # Debug Control Register
   type
-    CONTEXT* = record
+    CONTEXT* {.final.} = object
       Fpr0*: float64
       Fpr1*: float64
       Fpr2*: float64
@@ -7554,13 +7554,13 @@ type
   PCONTEXT* = ptr CONTEXT
 
 type
-  LIST_ENTRY* = record
+  LIST_ENTRY* {.final.} = object
     Flink*: ptr LIST_ENTRY
     Blink*: ptr LIST_ENTRY
 
   TLISTENTRY* = LIST_ENTRY
   PLISTENTRY* = ptr LIST_ENTRY
-  CRITICAL_SECTION_DEBUG* = record
+  CRITICAL_SECTION_DEBUG* {.final.} = object
     `type`*: int16
     CreatorBackTraceIndex*: int16
     CriticalSection*: ptr TCRITICAL_SECTION
@@ -7570,7 +7570,7 @@ type
     Depth*: DWORD
     OwnerBackTrace*: array[0..4, PVOID]
 
-  TRTL_CRITICAL_SECTION* = record
+  TRTL_CRITICAL_SECTION* {.final.} = object
     DebugInfo*: ptr CRITICAL_SECTION_DEBUG
     LockCount*: int32
     RecursionCount*: int32
@@ -7586,7 +7586,7 @@ type
   TCRITICAL_SECTION* = TRTLCriticalSection
   PCRITICAL_SECTION* = PRTLCriticalSection
   LPCRITICAL_SECTION* = PRTLCriticalSection
-  SECURITY_QUALITY_OF_SERVICE* = record
+  SECURITY_QUALITY_OF_SERVICE* {.final.} = object
     len*: DWORD
     ImpersonationLevel*: SECURITY_IMPERSONATION_LEVEL
     ContextTrackingMode*: WINBOOL
@@ -7594,7 +7594,7 @@ type
 
   PSECURITY_QUALITY_OF_SERVICE* = ptr SECURITY_QUALITY_OF_SERVICE
   TSECURITYQUALITYOFSERVICE* = SECURITY_QUALITY_OF_SERVICE
-  CONVCONTEXT* = record
+  CONVCONTEXT* {.final.} = object
     cb*: UINT
     wFlags*: UINT
     wCountryID*: UINT
@@ -7605,7 +7605,7 @@ type
 
   TCONVCONTEXT* = CONVCONTEXT
   PCONVCONTEXT* = ptr CONVCONTEXT
-  CONVINFO* = record
+  CONVINFO* {.final.} = object
     cb*: DWORD
     hUser*: DWORD
     hConvPartner*: HCONV
@@ -7626,7 +7626,7 @@ type
   tagCONVINFO* = CONVINFO
   TCONVINFO* = CONVINFO
   PCONVINFO* = ptr CONVINFO
-  COPYDATASTRUCT* = record
+  COPYDATASTRUCT* {.final.} = object
     dwData*: DWORD
     cbData*: DWORD
     lpData*: PVOID
@@ -7634,7 +7634,7 @@ type
   tagCOPYDATASTRUCT* = COPYDATASTRUCT
   TCOPYDATASTRUCT* = COPYDATASTRUCT
   PCOPYDATASTRUCT* = ptr COPYDATASTRUCT
-  CPINFO* = record
+  CPINFO* {.final.} = object
     MaxCharSize*: UINT
     DefaultChar*: array[0..(MAX_DEFAULTCHAR) - 1, int8]
     LeadByte*: array[0..(MAX_LEADBYTES) - 1, int8]
@@ -7642,7 +7642,7 @@ type
   LPCPINFO* = ptr CPINFO
   Tcpinfo* = CPINFO
   Pcpinfo* = ptr CPINFO
-  CPLINFO* = record
+  CPLINFO* {.final.} = object
     idIcon*: int32
     idName*: int32
     idInfo*: int32
@@ -7651,7 +7651,7 @@ type
   tagCPLINFO* = CPLINFO
   TCPLINFO* = CPLINFO
   PCPLINFO* = ptr CPLINFO
-  CREATE_PROCESS_DEBUG_INFO* = record
+  CREATE_PROCESS_DEBUG_INFO* {.final.} = object
     hFile*: HANDLE
     hProcess*: HANDLE
     hThread*: HANDLE
@@ -7665,7 +7665,7 @@ type
 
   TCREATEPROCESSDEBUGINFO* = CREATE_PROCESS_DEBUG_INFO
   PCREATEPROCESSDEBUGINFO* = ptr CREATE_PROCESS_DEBUG_INFO
-  CREATE_THREAD_DEBUG_INFO* = record
+  CREATE_THREAD_DEBUG_INFO* {.final.} = object
     hThread*: HANDLE
     lpThreadLocalBase*: LPVOID
     lpStartAddress*: LPTHREAD_START_ROUTINE
@@ -7686,7 +7686,7 @@ type
                                                          #    INT             iProtocol;
                                                          #  } CSADDR_INFO;
                                                          #
-  CURRENCYFMT* = record
+  CURRENCYFMT* {.final.} = object
     NumDigits*: UINT
     LeadingZero*: UINT
     Grouping*: UINT
@@ -7698,7 +7698,7 @@ type
 
   Tcurrencyfmt* = CURRENCYFMT
   Pcurrencyfmt* = ptr CURRENCYFMT
-  CURSORSHAPE* = record
+  CURSORSHAPE* {.final.} = object
     xHotSpot*: int32
     yHotSpot*: int32
     cx*: int32
@@ -7710,7 +7710,7 @@ type
   LPCURSORSHAPE* = ptr CURSORSHAPE
   TCURSORSHAPE* = CURSORSHAPE
   PCURSORSHAPE* = ptr CURSORSHAPE
-  CWPRETSTRUCT* = record
+  CWPRETSTRUCT* {.final.} = object
     lResult*: LRESULT
     lParam*: LPARAM
     wParam*: WPARAM
@@ -7719,7 +7719,7 @@ type
 
   TCWPRETSTRUCT* = CWPRETSTRUCT
   PCWPRETSTRUCT* = ptr CWPRETSTRUCT
-  CWPSTRUCT* = record
+  CWPSTRUCT* {.final.} = object
     lParam*: LPARAM
     wParam*: WPARAM
     message*: UINT
@@ -7727,12 +7727,12 @@ type
 
   TCWPSTRUCT* = CWPSTRUCT
   PCWPSTRUCT* = ptr CWPSTRUCT
-  DATATYPES_INFO_1* = record
+  DATATYPES_INFO_1* {.final.} = object
     pName*: LPTSTR
 
   TDATATYPESINFO1* = DATATYPES_INFO_1
   PDATATYPESINFO1* = ptr DATATYPES_INFO_1
-  DDEACK* = record
+  DDEACK* {.final.} = object
     flag0*: int16
 
   TDDEACK* = DDEACK
@@ -7757,7 +7757,7 @@ proc set_fBusy*(a: var DDEACK, fBusy: int16)
 proc fAck*(a: var DDEACK): int16
 proc set_fAck*(a: var DDEACK, fAck: int16)
 type
-  DDEADVISE* = record
+  DDEADVISE* {.final.} = object
     flag0*: int16
     cfFormat*: SHORT
 
@@ -7779,7 +7779,7 @@ proc set_fDeferUpd*(a: var DDEADVISE, fDeferUpd: int16)
 proc fAckReq*(a: var DDEADVISE): int16
 proc set_fAckReq*(a: var DDEADVISE, fAckReq: int16)
 type
-  DDEDATA* = record
+  DDEDATA* {.final.} = object
     flag0*: int16
     cfFormat*: SHORT
     Value*: array[0..0, int8]
@@ -7809,7 +7809,7 @@ proc set_reserved*(a: var DDEDATA, reserved: int16)
 proc fAckReq*(a: var DDEDATA): int16
 proc set_fAckReq*(a: var DDEDATA, fAckReq: int16)
 type
-  DDELN* = record
+  DDELN* {.final.} = object
     flag0*: int16
     cfFormat*: SHORT
 
@@ -7835,7 +7835,7 @@ proc set_fDeferUpd*(a: var DDELN, fDeferUpd: int16)
 proc fAckReq*(a: var DDELN): int16
 proc set_fAckReq*(a: var DDELN, fAckReq: int16)
 type
-  DDEML_MSG_HOOK_DATA* = record
+  DDEML_MSG_HOOK_DATA* {.final.} = object
     uiLo*: UINT
     uiHi*: UINT
     cbData*: DWORD
@@ -7843,7 +7843,7 @@ type
 
   TDDEMLMSGHOOKDATA* = DDEML_MSG_HOOK_DATA
   PDDEMLMSGHOOKDATA* = ptr DDEML_MSG_HOOK_DATA
-  DDEPOKE* = record
+  DDEPOKE* {.final.} = object
     flag0*: int16
     cfFormat*: SHORT
     Value*: array[0..0, int8]
@@ -7866,7 +7866,7 @@ proc set_fRelease*(a: var DDEPOKE, fRelease: int16)
 proc fReserved*(a: var DDEPOKE): int16
 proc set_fReserved*(a: var DDEPOKE, fReserved: int16)
 type
-  DDEUP* = record
+  DDEUP* {.final.} = object
     flag0*: int16
     cfFormat*: SHORT
     rgb*: array[0..0, int8]
@@ -7897,7 +7897,7 @@ proc set_fReserved*(a: var DDEUP, fReserved: int16)
 proc fAckReq*(a: var DDEUP): int16
 proc set_fAckReq*(a: var DDEUP, fAckReq: int16)
 type
-  EXCEPTION_RECORD* = record
+  EXCEPTION_RECORD* {.final.} = object
     ExceptionCode*: DWORD
     ExceptionFlags*: DWORD
     ExceptionRecord*: ptr EXCEPTION_RECORD
@@ -7908,13 +7908,13 @@ type
 
   PEXCEPTION_RECORD* = ptr EXCEPTION_RECORD
   TEXCEPTIONRECORD* = EXCEPTION_RECORD
-  EXCEPTION_DEBUG_INFO* = record
+  EXCEPTION_DEBUG_INFO* {.final.} = object
     ExceptionRecord*: EXCEPTION_RECORD
     dwFirstChance*: DWORD
 
   PEXCEPTION_DEBUG_INFO* = ptr EXCEPTION_DEBUG_INFO
   TEXCEPTIONDEBUGINFO* = EXCEPTION_DEBUG_INFO
-  EXCEPTION_RECORD32* = record
+  EXCEPTION_RECORD32* {.final.} = object
     ExceptionCode*: DWORD
     ExceptionFlags*: DWORD
     ExceptionRecord*: DWORD
@@ -7924,13 +7924,13 @@ type
 
   PEXCEPTION_RECORD32* = ptr EXCEPTION_RECORD32
   TExceptionRecord32* = EXCEPTION_RECORD32
-  EXCEPTION_DEBUG_INFO32* = record
+  EXCEPTION_DEBUG_INFO32* {.final.} = object
     ExceptionRecord*: EXCEPTION_RECORD32
     dwFirstChance*: DWORD
 
   PEXCEPTION_DEBUG_INFO32* = ptr EXCEPTION_DEBUG_INFO32
   TExceptionDebugInfo32* = EXCEPTION_DEBUG_INFO32
-  EXCEPTION_RECORD64* = record
+  EXCEPTION_RECORD64* {.final.} = object
     ExceptionCode*: DWORD
     ExceptionFlags*: DWORD
     ExceptionRecord*: DWORD64
@@ -7941,23 +7941,23 @@ type
 
   PEXCEPTION_RECORD64* = ptr EXCEPTION_RECORD64
   TExceptionRecord64* = EXCEPTION_RECORD64
-  EXCEPTION_DEBUG_INFO64* = record
+  EXCEPTION_DEBUG_INFO64* {.final.} = object
     ExceptionRecord*: EXCEPTION_RECORD64
     dwFirstChance*: DWORD
 
   PEXCEPTION_DEBUG_INFO64* = ptr EXCEPTION_DEBUG_INFO64
   TExceptionDebugInfo64* = EXCEPTION_DEBUG_INFO64
-  EXIT_PROCESS_DEBUG_INFO* = record
+  EXIT_PROCESS_DEBUG_INFO* {.final.} = object
     dwExitCode*: DWORD
 
   TEXITPROCESSDEBUGINFO* = EXIT_PROCESS_DEBUG_INFO
   PEXITPROCESSDEBUGINFO* = ptr EXIT_PROCESS_DEBUG_INFO
-  EXIT_THREAD_DEBUG_INFO* = record
+  EXIT_THREAD_DEBUG_INFO* {.final.} = object
     dwExitCode*: DWORD
 
   TEXITTHREADDEBUGINFO* = EXIT_THREAD_DEBUG_INFO
   PEXITTHREADDEBUGINFO* = ptr EXIT_THREAD_DEBUG_INFO
-  LOAD_DLL_DEBUG_INFO* = record
+  LOAD_DLL_DEBUG_INFO* {.final.} = object
     hFile*: HANDLE
     lpBaseOfDll*: LPVOID
     dwDebugInfoFileOffset*: DWORD
@@ -7967,25 +7967,25 @@ type
 
   TLOADDLLDEBUGINFO* = LOAD_DLL_DEBUG_INFO
   PLOADDLLDEBUGINFO* = ptr LOAD_DLL_DEBUG_INFO
-  UNLOAD_DLL_DEBUG_INFO* = record
+  UNLOAD_DLL_DEBUG_INFO* {.final.} = object
     lpBaseOfDll*: LPVOID
 
   TUNLOADDLLDEBUGINFO* = UNLOAD_DLL_DEBUG_INFO
   PUNLOADDLLDEBUGINFO* = ptr UNLOAD_DLL_DEBUG_INFO
-  OUTPUT_DEBUG_STRING_INFO* = record
+  OUTPUT_DEBUG_STRING_INFO* {.final.} = object
     lpDebugStringData*: LPSTR
     fUnicode*: int16
     nDebugStringLength*: int16
 
   TOUTPUTDEBUGSTRINGINFO* = OUTPUT_DEBUG_STRING_INFO
   POUTPUTDEBUGSTRINGINFO* = ptr OUTPUT_DEBUG_STRING_INFO
-  RIP_INFO* = record
+  RIP_INFO* {.final.} = object
     dwError*: DWORD
     dwType*: DWORD
 
   TRIPINFO* = RIP_INFO
   PRIPINFO* = ptr RIP_INFO
-  DEBUG_EVENT* = record
+  DEBUG_EVENT* {.final.} = object
     dwDebugEventCode*: DWORD
     dwProcessId*: DWORD
     dwThreadId*: DWORD
@@ -8004,7 +8004,7 @@ type
   LPDEBUG_EVENT* = ptr DEBUG_EVENT
   TDEBUGEVENT* = DEBUG_EVENT
   PDEBUGEVENT* = ptr DEBUG_EVENT
-  DEBUGHOOKINFO* = record
+  DEBUGHOOKINFO* {.final.} = object
     idThread*: DWORD
     idThreadInstaller*: DWORD
     lParam*: LPARAM
@@ -8013,7 +8013,7 @@ type
 
   TDEBUGHOOKINFO* = DEBUGHOOKINFO
   PDEBUGHOOKINFO* = ptr DEBUGHOOKINFO
-  DELETEITEMSTRUCT* = record
+  DELETEITEMSTRUCT* {.final.} = object
     CtlType*: UINT
     CtlID*: UINT
     itemID*: UINT
@@ -8022,14 +8022,14 @@ type
 
   TDELETEITEMSTRUCT* = DELETEITEMSTRUCT
   PDELETEITEMSTRUCT* = ptr DELETEITEMSTRUCT
-  DEV_BROADCAST_HDR* = record
+  DEV_BROADCAST_HDR* {.final.} = object
     dbch_size*: ULONG
     dbch_devicetype*: ULONG
     dbch_reserved*: ULONG
 
   PDEV_BROADCAST_HDR* = ptr DEV_BROADCAST_HDR
   TDEVBROADCASTHDR* = DEV_BROADCAST_HDR
-  DEV_BROADCAST_OEM* = record
+  DEV_BROADCAST_OEM* {.final.} = object
     dbco_size*: ULONG
     dbco_devicetype*: ULONG
     dbco_reserved*: ULONG
@@ -8038,7 +8038,7 @@ type
 
   PDEV_BROADCAST_OEM* = ptr DEV_BROADCAST_OEM
   TDEVBROADCASTOEM* = DEV_BROADCAST_OEM
-  DEV_BROADCAST_PORT* = record
+  DEV_BROADCAST_PORT* {.final.} = object
     dbcp_size*: ULONG
     dbcp_devicetype*: ULONG
     dbcp_reserved*: ULONG
@@ -8046,14 +8046,14 @@ type
 
   PDEV_BROADCAST_PORT* = ptr DEV_BROADCAST_PORT
   TDEVBROADCASTPORT* = DEV_BROADCAST_PORT
-  DEV_BROADCAST_USERDEFINED* = record
+  DEV_BROADCAST_USERDEFINED* {.final.} = object
     dbud_dbh*: DEV_BROADCAST_HDR
     dbud_szName*: array[0..0, char]
     dbud_rgbUserDefined*: array[0..0, int8]
 
   TDEVBROADCASTUSERDEFINED* = DEV_BROADCAST_USERDEFINED
   PDEVBROADCASTUSERDEFINED* = ptr DEV_BROADCAST_USERDEFINED
-  DEV_BROADCAST_VOLUME* = record
+  DEV_BROADCAST_VOLUME* {.final.} = object
     dbcv_size*: ULONG
     dbcv_devicetype*: ULONG
     dbcv_reserved*: ULONG
@@ -8062,7 +8062,7 @@ type
 
   PDEV_BROADCAST_VOLUME* = ptr DEV_BROADCAST_VOLUME
   TDEVBROADCASTVOLUME* = DEV_BROADCAST_VOLUME
-  DEVMODE* = record
+  DEVMODE* {.final.} = object
     dmDeviceName*: array[0..(CCHDEVICENAME) - 1, BCHAR]
     dmSpecVersion*: int16
     dmDriverVersion*: int16
@@ -8107,7 +8107,7 @@ type
   PDeviceMode* = LPDEVMODE
   TDEVMODE* = DEVMODE
   PDEVMODE* = LPDEVMODE
-  devmodeW* = record
+  devmodeW* {.final.} = object
     dmDeviceName*: array[0..CCHDEVICENAME - 1, WCHAR]
     dmSpecVersion*: int16
     dmDriverVersion*: int16
@@ -8149,7 +8149,7 @@ type
   PDeviceModeW* = LPDEVMODEW
   TDEVMODEW* = DEVMODEW
   PDEVMODEW* = LPDEVMODEW
-  DEVNAMES* = record
+  DEVNAMES* {.final.} = object
     wDriverOffset*: int16
     wDeviceOffset*: int16
     wOutputOffset*: int16
@@ -8159,7 +8159,7 @@ type
   tagDEVNAMES* = DEVNAMES
   TDEVNAMES* = DEVNAMES
   PDEVNAMES* = ptr DEVNAMES
-  DIBSECTION* = record
+  DIBSECTION* {.final.} = object
     dsBm*: BITMAP
     dsBmih*: BITMAPINFOHEADER
     dsBitfields*: array[0..2, DWORD]
@@ -8187,7 +8187,7 @@ type
   TLargeInteger* = Int64
   PULARGE_INTEGER* = ptr ULARGE_INTEGER
   TULargeInteger* = int64
-  DISK_GEOMETRY* = record
+  DISK_GEOMETRY* {.final.} = object
     Cylinders*: LARGE_INTEGER
     MediaType*: MEDIA_TYPE
     TracksPerCylinder*: DWORD
@@ -8196,7 +8196,7 @@ type
 
   TDISKGEOMETRY* = DISK_GEOMETRY
   PDISKGEOMETRY* = ptr DISK_GEOMETRY
-  DISK_PERFORMANCE* = record
+  DISK_PERFORMANCE* {.final.} = object
     BytesRead*: LARGE_INTEGER
     BytesWritten*: LARGE_INTEGER
     ReadTime*: LARGE_INTEGER
@@ -8207,7 +8207,7 @@ type
 
   TDISKPERFORMANCE* = DISK_PERFORMANCE
   PDISKPERFORMANCE* = ptr DISK_PERFORMANCE
-  DLGITEMTEMPLATE* = record
+  DLGITEMTEMPLATE* {.final.} = object
     style*: DWORD
     dwExtendedStyle*: DWORD
     x*: int16
@@ -8219,7 +8219,7 @@ type
   LPDLGITEMTEMPLATE* = ptr DLGITEMTEMPLATE
   TDLGITEMTEMPLATE* = DLGITEMTEMPLATE
   PDLGITEMTEMPLATE* = ptr DLGITEMTEMPLATE
-  DLGTEMPLATE* = record
+  DLGTEMPLATE* {.final.} = object
     style*: DWORD
     dwExtendedStyle*: DWORD
     cdit*: int16
@@ -8232,14 +8232,14 @@ type
   LPCDLGTEMPLATE* = ptr DLGTEMPLATE
   TDLGTEMPLATE* = DLGTEMPLATE
   PDLGTEMPLATE* = ptr DLGTEMPLATE
-  DOC_INFO_1* = record
+  DOC_INFO_1* {.final.} = object
     pDocName*: LPTSTR
     pOutputFile*: LPTSTR
     pDatatype*: LPTSTR
 
   TDOCINFO1* = DOC_INFO_1
   PDOCINFO1* = ptr DOC_INFO_1
-  DOC_INFO_2* = record
+  DOC_INFO_2* {.final.} = object
     pDocName*: LPTSTR
     pOutputFile*: LPTSTR
     pDatatype*: LPTSTR
@@ -8248,7 +8248,7 @@ type
 
   TDOCINFO2* = DOC_INFO_2
   PDOCINFO2* = ptr DOC_INFO_2
-  DOCINFO* = record
+  DOCINFO* {.final.} = object
     cbSize*: int32
     lpszDocName*: LPCTSTR
     lpszOutput*: LPCTSTR
@@ -8258,7 +8258,7 @@ type
   TDOCINFO* = DOCINFO
   TDOCINFOA* = DOCINFO
   PDOCINFO* = ptr DOCINFO
-  DRAGLISTINFO* = record
+  DRAGLISTINFO* {.final.} = object
     uNotification*: UINT
     hWnd*: HWND
     ptCursor*: POINT
@@ -8266,7 +8266,7 @@ type
   LPDRAGLISTINFO* = ptr DRAGLISTINFO
   TDRAGLISTINFO* = DRAGLISTINFO
   PDRAGLISTINFO* = ptr DRAGLISTINFO
-  DRAWITEMSTRUCT* = record
+  DRAWITEMSTRUCT* {.final.} = object
     CtlType*: UINT
     CtlID*: UINT
     itemID*: UINT
@@ -8281,7 +8281,7 @@ type
   tagDRAWITEMSTRUCT* = DRAWITEMSTRUCT
   TDRAWITEMSTRUCT* = DRAWITEMSTRUCT
   PDRAWITEMSTRUCT* = ptr DRAWITEMSTRUCT
-  DRAWTEXTPARAMS* = record
+  DRAWTEXTPARAMS* {.final.} = object
     cbSize*: UINT
     iTabLength*: int32
     iLeftMargin*: int32
@@ -8291,7 +8291,7 @@ type
   LPDRAWTEXTPARAMS* = ptr DRAWTEXTPARAMS
   TDRAWTEXTPARAMS* = DRAWTEXTPARAMS
   PDRAWTEXTPARAMS* = ptr DRAWTEXTPARAMS
-  PARTITION_INFORMATION* = record
+  PARTITION_INFORMATION* {.final.} = object
     PartitionType*: int8
     BootIndicator*: bool
     RecognizedPartition*: bool
@@ -8302,19 +8302,19 @@ type
 
   TPARTITIONINFORMATION* = PARTITION_INFORMATION
   PPARTITIONINFORMATION* = ptr PARTITION_INFORMATION
-  DRIVE_LAYOUT_INFORMATION* = record
+  DRIVE_LAYOUT_INFORMATION* {.final.} = object
     PartitionCount*: DWORD
     Signature*: DWORD
     PartitionEntry*: array[0..0, PARTITION_INFORMATION]
 
   TDRIVELAYOUTINFORMATION* = DRIVE_LAYOUT_INFORMATION
   PDRIVELAYOUTINFORMATION* = ptr DRIVE_LAYOUT_INFORMATION
-  DRIVER_INFO_1* = record
+  DRIVER_INFO_1* {.final.} = object
     pName*: LPTSTR
 
   TDRIVERINFO1* = DRIVER_INFO_1
   PDRIVERINFO1* = ptr DRIVER_INFO_1
-  DRIVER_INFO_2* = record
+  DRIVER_INFO_2* {.final.} = object
     cVersion*: DWORD
     pName*: LPTSTR
     pEnvironment*: LPTSTR
@@ -8324,7 +8324,7 @@ type
 
   TDRIVERINFO2* = DRIVER_INFO_2
   PDRIVERINFO2* = ptr DRIVER_INFO_2
-  DRIVER_INFO_3* = record
+  DRIVER_INFO_3* {.final.} = object
     cVersion*: DWORD
     pName*: LPTSTR
     pEnvironment*: LPTSTR
@@ -8338,21 +8338,21 @@ type
 
   TDRIVERINFO3* = DRIVER_INFO_3
   PDRIVERINFO3* = ptr DRIVER_INFO_3
-  EDITSTREAM* = record
+  EDITSTREAM* {.final.} = object
     dwCookie*: DWORD
     dwError*: DWORD
     pfnCallback*: EDITSTREAMCALLBACK
 
   Teditstream* = EDITSTREAM
   Peditstream* = ptr EDITSTREAM
-  EMR* = record
+  EMR* {.final.} = object
     iType*: DWORD
     nSize*: DWORD
 
   tagEMR* = EMR
   TEMR* = EMR
   PEMR* = ptr EMR
-  EMRANGLEARC* = record
+  EMRANGLEARC* {.final.} = object
     emr*: EMR
     ptlCenter*: POINTL
     nRadius*: DWORD
@@ -8362,7 +8362,7 @@ type
   tagEMRANGLEARC* = EMRANGLEARC
   TEMRANGLEARC* = EMRANGLEARC
   PEMRANGLEARC* = ptr EMRANGLEARC
-  EMRARC* = record
+  EMRARC* {.final.} = object
     emr*: EMR
     rclBox*: RECTL
     ptlStart*: POINTL
@@ -8380,7 +8380,7 @@ type
   EMRPIE* = EMRARC
   TEMRPIE* = EMRARC
   PEMRPIE* = ptr EMRARC
-  XFORM* = record
+  XFORM* {.final.} = object
     eM11*: float32
     eM12*: float32
     eM21*: float32
@@ -8391,7 +8391,7 @@ type
   LPXFORM* = ptr XFORM
   TXFORM* = XFORM
   PXFORM* = ptr XFORM
-  EMRBITBLT* = record
+  EMRBITBLT* {.final.} = object
     emr*: EMR
     rclBounds*: RECTL
     xDest*: LONG
@@ -8411,7 +8411,7 @@ type
   tagEMRBITBLT* = EMRBITBLT
   TEMRBITBLT* = EMRBITBLT
   PEMRBITBLT* = ptr EMRBITBLT
-  LOGBRUSH* = record
+  LOGBRUSH* {.final.} = object
     lbStyle*: UINT
     lbColor*: COLORREF
     lbHatch*: LONG
@@ -8419,7 +8419,7 @@ type
   tagLOGBRUSH* = LOGBRUSH
   TLOGBRUSH* = LOGBRUSH
   PLOGBRUSH* = ptr LOGBRUSH
-  EMRCREATEBRUSHINDIRECT* = record
+  EMRCREATEBRUSHINDIRECT* {.final.} = object
     emr*: EMR
     ihBrush*: DWORD
     lb*: LOGBRUSH
@@ -8429,7 +8429,7 @@ type
   PEMRCREATEBRUSHINDIRECT* = ptr EMRCREATEBRUSHINDIRECT
   LCSCSTYPE* = LONG
   LCSGAMUTMATCH* = LONG
-  LOGCOLORSPACE* = record
+  LOGCOLORSPACE* {.final.} = object
     lcsSignature*: DWORD
     lcsVersion*: DWORD
     lcsSize*: DWORD
@@ -8446,7 +8446,7 @@ type
   TLOGCOLORSPACE* = LOGCOLORSPACE
   TLOGCOLORSPACEA* = LOGCOLORSPACE
   PLOGCOLORSPACE* = ptr LOGCOLORSPACE
-  EMRCREATECOLORSPACE* = record
+  EMRCREATECOLORSPACE* {.final.} = object
     emr*: EMR
     ihCS*: DWORD
     lcs*: LOGCOLORSPACE
@@ -8454,7 +8454,7 @@ type
   tagEMRCREATECOLORSPACE* = EMRCREATECOLORSPACE
   TEMRCREATECOLORSPACE* = EMRCREATECOLORSPACE
   PEMRCREATECOLORSPACE* = ptr EMRCREATECOLORSPACE
-  EMRCREATEDIBPATTERNBRUSHPT* = record
+  EMRCREATEDIBPATTERNBRUSHPT* {.final.} = object
     emr*: EMR
     ihBrush*: DWORD
     iUsage*: DWORD
@@ -8466,7 +8466,7 @@ type
   tagEMRCREATEDIBPATTERNBRUSHPT* = EMRCREATEDIBPATTERNBRUSHPT
   TEMRCREATEDIBPATTERNBRUSHPT* = EMRCREATEDIBPATTERNBRUSHPT
   PEMRCREATEDIBPATTERNBRUSHPT* = EMRCREATEDIBPATTERNBRUSHPT
-  EMRCREATEMONOBRUSH* = record
+  EMRCREATEMONOBRUSH* {.final.} = object
     emr*: EMR
     ihBrush*: DWORD
     iUsage*: DWORD
@@ -8478,7 +8478,7 @@ type
   tagEMRCREATEMONOBRUSH* = EMRCREATEMONOBRUSH
   TEMRCREATEMONOBRUSH* = EMRCREATEMONOBRUSH
   PEMRCREATEMONOBRUSH* = ptr EMRCREATEMONOBRUSH
-  PALETTEENTRY* = record
+  PALETTEENTRY* {.final.} = object
     peRed*: int8
     peGreen*: int8
     peBlue*: int8
@@ -8488,7 +8488,7 @@ type
   tagPALETTEENTRY* = PALETTEENTRY
   TPALETTEENTRY* = PALETTEENTRY
   PPALETTEENTRY* = ptr PALETTEENTRY
-  LOGPALETTE* = record
+  LOGPALETTE* {.final.} = object
     palVersion*: int16
     palNumEntries*: int16
     palPalEntry*: array[0..0, PALETTEENTRY]
@@ -8497,7 +8497,7 @@ type
   tagLOGPALETTE* = LOGPALETTE
   TLOGPALETTE* = LOGPALETTE
   PLOGPALETTE* = ptr LOGPALETTE
-  EMRCREATEPALETTE* = record
+  EMRCREATEPALETTE* {.final.} = object
     emr*: EMR
     ihPal*: DWORD
     lgpl*: LOGPALETTE
@@ -8505,7 +8505,7 @@ type
   tagEMRCREATEPALETTE* = EMRCREATEPALETTE
   TEMRCREATEPALETTE* = EMRCREATEPALETTE
   PEMRCREATEPALETTE* = ptr EMRCREATEPALETTE
-  LOGPEN* = record
+  LOGPEN* {.final.} = object
     lopnStyle*: UINT
     lopnWidth*: POINT
     lopnColor*: COLORREF
@@ -8513,7 +8513,7 @@ type
   tagLOGPEN* = LOGPEN
   TLOGPEN* = LOGPEN
   PLOGPEN* = ptr LOGPEN
-  EMRCREATEPEN* = record
+  EMRCREATEPEN* {.final.} = object
     emr*: EMR
     ihPen*: DWORD
     lopn*: LOGPEN
@@ -8521,7 +8521,7 @@ type
   tagEMRCREATEPEN* = EMRCREATEPEN
   TEMRCREATEPEN* = EMRCREATEPEN
   PEMRCREATEPEN* = ptr EMRCREATEPEN
-  EMRELLIPSE* = record
+  EMRELLIPSE* {.final.} = object
     emr*: EMR
     rclBox*: RECTL
 
@@ -8531,7 +8531,7 @@ type
   EMRRECTANGLE* = EMRELLIPSE
   TEMRRECTANGLE* = EMRELLIPSE
   PEMRRECTANGLE* = ptr EMRELLIPSE
-  EMREOF* = record
+  EMREOF* {.final.} = object
     emr*: EMR
     nPalEntries*: DWORD
     offPalEntries*: DWORD
@@ -8540,7 +8540,7 @@ type
   tagEMREOF* = EMREOF
   TEMREOF* = EMREOF
   PEMREOF* = ptr EMREOF
-  EMREXCLUDECLIPRECT* = record
+  EMREXCLUDECLIPRECT* {.final.} = object
     emr*: EMR
     rclClip*: RECTL
 
@@ -8550,7 +8550,7 @@ type
   EMRINTERSECTCLIPRECT* = EMREXCLUDECLIPRECT
   TEMRINTERSECTCLIPRECT* = EMREXCLUDECLIPRECT
   PEMRINTERSECTCLIPRECT* = ptr EMREXCLUDECLIPRECT
-  PANOSE* = record
+  PANOSE* {.final.} = object
     bFamilyType*: int8
     bSerifStyle*: int8
     bWeight*: int8
@@ -8565,7 +8565,7 @@ type
   tagPANOSE* = PANOSE
   TPANOSE* = PANOSE
   PPANOSE* = ptr PANOSE
-  EXTLOGFONT* = record
+  EXTLOGFONT* {.final.} = object
     elfLogFont*: LOGFONT
     elfFullName*: array[0..(LF_FULLFACESIZE) - 1, BCHAR]
     elfStyle*: array[0..(LF_FACESIZE) - 1, BCHAR]
@@ -8580,7 +8580,7 @@ type
   tagEXTLOGFONT* = EXTLOGFONT
   TEXTLOGFONT* = EXTLOGFONT
   PEXTLOGFONT* = ptr EXTLOGFONT
-  EMREXTCREATEFONTINDIRECTW* = record
+  EMREXTCREATEFONTINDIRECTW* {.final.} = object
     emr*: EMR
     ihFont*: DWORD
     elfw*: EXTLOGFONT
@@ -8588,7 +8588,7 @@ type
   tagEMREXTCREATEFONTINDIRECTW* = EMREXTCREATEFONTINDIRECTW
   TEMREXTCREATEFONTINDIRECTW* = EMREXTCREATEFONTINDIRECTW
   PEMREXTCREATEFONTINDIRECTW* = ptr EMREXTCREATEFONTINDIRECTW
-  EXTLOGPEN* = record
+  EXTLOGPEN* {.final.} = object
     elpPenStyle*: UINT
     elpWidth*: UINT
     elpBrushStyle*: UINT
@@ -8600,7 +8600,7 @@ type
   tagEXTLOGPEN* = EXTLOGPEN
   TEXTLOGPEN* = EXTLOGPEN
   PEXTLOGPEN* = ptr EXTLOGPEN
-  EMREXTCREATEPEN* = record
+  EMREXTCREATEPEN* {.final.} = object
     emr*: EMR
     ihPen*: DWORD
     offBmi*: DWORD
@@ -8612,7 +8612,7 @@ type
   tagEMREXTCREATEPEN* = EMREXTCREATEPEN
   TEMREXTCREATEPEN* = EMREXTCREATEPEN
   PEMREXTCREATEPEN* = ptr EMREXTCREATEPEN
-  EMREXTFLOODFILL* = record
+  EMREXTFLOODFILL* {.final.} = object
     emr*: EMR
     ptlStart*: POINTL
     crColor*: COLORREF
@@ -8621,7 +8621,7 @@ type
   tagEMREXTFLOODFILL* = EMREXTFLOODFILL
   TEMREXTFLOODFILL* = EMREXTFLOODFILL
   PEMREXTFLOODFILL* = ptr EMREXTFLOODFILL
-  EMREXTSELECTCLIPRGN* = record
+  EMREXTSELECTCLIPRGN* {.final.} = object
     emr*: EMR
     cbRgnData*: DWORD
     iMode*: DWORD
@@ -8630,7 +8630,7 @@ type
   tagEMREXTSELECTCLIPRGN* = EMREXTSELECTCLIPRGN
   TEMREXTSELECTCLIPRGN* = EMREXTSELECTCLIPRGN
   PEMREXTSELECTCLIPRGN* = ptr EMREXTSELECTCLIPRGN
-  EMRTEXT* = record
+  EMRTEXT* {.final.} = object
     ptlReference*: POINTL
     nChars*: DWORD
     offString*: DWORD
@@ -8641,7 +8641,7 @@ type
   tagEMRTEXT* = EMRTEXT
   TEMRTEXT* = EMRTEXT
   PEMRTEXT* = ptr EMRTEXT
-  EMREXTTEXTOUTA* = record
+  EMREXTTEXTOUTA* {.final.} = object
     emr*: EMR
     rclBounds*: RECTL
     iGraphicsMode*: DWORD
@@ -8655,7 +8655,7 @@ type
   EMREXTTEXTOUTW* = EMREXTTEXTOUTA
   TEMREXTTEXTOUTW* = EMREXTTEXTOUTA
   PEMREXTTEXTOUTW* = ptr EMREXTTEXTOUTA
-  EMRFILLPATH* = record
+  EMRFILLPATH* {.final.} = object
     emr*: EMR
     rclBounds*: RECTL
 
@@ -8668,7 +8668,7 @@ type
   EMRSTROKEPATH* = EMRFILLPATH
   TEMRSTROKEPATH* = EMRFILLPATH
   PEMRSTROKEPATH* = ptr EMRFILLPATH
-  EMRFILLRGN* = record
+  EMRFILLRGN* {.final.} = object
     emr*: EMR
     rclBounds*: RECTL
     cbRgnData*: DWORD
@@ -8678,7 +8678,7 @@ type
   tagEMRFILLRGN* = EMRFILLRGN
   TEMRFILLRGN* = EMRFILLRGN
   PEMRFILLRGN* = ptr EMRFILLRGN
-  EMRFORMAT* = record
+  EMRFORMAT* {.final.} = object
     dSignature*: DWORD
     nVersion*: DWORD
     cbData*: DWORD
@@ -8687,7 +8687,7 @@ type
   tagEMRFORMAT* = EMRFORMAT
   TEMRFORMAT* = EMRFORMAT
   PEMRFORMAT* = ptr EMRFORMAT
-  SIZE* = record
+  SIZE* {.final.} = object
     cx*: LONG
     cy*: LONG
 
@@ -8699,7 +8699,7 @@ type
   TSIZEL* = SIZE
   PSIZEL* = ptr SIZE
   LPSIZEL* = ptr SIZE
-  EMRFRAMERGN* = record
+  EMRFRAMERGN* {.final.} = object
     emr*: EMR
     rclBounds*: RECTL
     cbRgnData*: DWORD
@@ -8710,7 +8710,7 @@ type
   tagEMRFRAMERGN* = EMRFRAMERGN
   TEMRFRAMERGN* = EMRFRAMERGN
   PEMRFRAMERGN* = ptr EMRFRAMERGN
-  EMRGDICOMMENT* = record
+  EMRGDICOMMENT* {.final.} = object
     emr*: EMR
     cbData*: DWORD
     Data*: array[0..0, int8]
@@ -8718,7 +8718,7 @@ type
   tagEMRGDICOMMENT* = EMRGDICOMMENT
   TEMRGDICOMMENT* = EMRGDICOMMENT
   PEMRGDICOMMENT* = ptr EMRGDICOMMENT
-  EMRINVERTRGN* = record
+  EMRINVERTRGN* {.final.} = object
     emr*: EMR
     rclBounds*: RECTL
     cbRgnData*: DWORD
@@ -8730,7 +8730,7 @@ type
   EMRPAINTRGN* = EMRINVERTRGN
   TEMRPAINTRGN* = EMRINVERTRGN
   PEMRPAINTRGN* = ptr EMRINVERTRGN
-  EMRLINETO* = record
+  EMRLINETO* {.final.} = object
     emr*: EMR
     ptl*: POINTL
 
@@ -8740,7 +8740,7 @@ type
   EMRMOVETOEX* = EMRLINETO
   TEMRMOVETOEX* = EMRLINETO
   PEMRMOVETOEX* = ptr EMRLINETO
-  EMRMASKBLT* = record
+  EMRMASKBLT* {.final.} = object
     emr*: EMR
     rclBounds*: RECTL
     xDest*: LONG
@@ -8768,7 +8768,7 @@ type
   tagEMRMASKBLT* = EMRMASKBLT
   TEMRMASKBLT* = EMRMASKBLT
   PEMRMASKBLT* = ptr EMRMASKBLT
-  EMRMODIFYWORLDTRANSFORM* = record
+  EMRMODIFYWORLDTRANSFORM* {.final.} = object
     emr*: EMR
     xform*: XFORM
     iMode*: DWORD
@@ -8776,14 +8776,14 @@ type
   tagEMRMODIFYWORLDTRANSFORM* = EMRMODIFYWORLDTRANSFORM
   TEMRMODIFYWORLDTRANSFORM* = EMRMODIFYWORLDTRANSFORM
   PEMRMODIFYWORLDTRANSFORM* = EMRMODIFYWORLDTRANSFORM
-  EMROFFSETCLIPRGN* = record
+  EMROFFSETCLIPRGN* {.final.} = object
     emr*: EMR
     ptlOffset*: POINTL
 
   tagEMROFFSETCLIPRGN* = EMROFFSETCLIPRGN
   TEMROFFSETCLIPRGN* = EMROFFSETCLIPRGN
   PEMROFFSETCLIPRGN* = ptr EMROFFSETCLIPRGN
-  EMRPLGBLT* = record
+  EMRPLGBLT* {.final.} = object
     emr*: EMR
     rclBounds*: RECTL
     aptlDest*: array[0..2, POINTL]
@@ -8809,7 +8809,7 @@ type
   tagEMRPLGBLT* = EMRPLGBLT
   TEMRPLGBLT* = EMRPLGBLT
   PEMRPLGBLT* = ptr EMRPLGBLT
-  EMRPOLYDRAW* = record
+  EMRPOLYDRAW* {.final.} = object
     emr*: EMR
     rclBounds*: RECTL
     cptl*: DWORD
@@ -8819,7 +8819,7 @@ type
   tagEMRPOLYDRAW* = EMRPOLYDRAW
   TEMRPOLYDRAW* = EMRPOLYDRAW
   PEMRPOLYDRAW* = ptr EMRPOLYDRAW
-  EMRPOLYDRAW16* = record
+  EMRPOLYDRAW16* {.final.} = object
     emr*: EMR
     rclBounds*: RECTL
     cpts*: DWORD
@@ -8829,7 +8829,7 @@ type
   tagEMRPOLYDRAW16* = EMRPOLYDRAW16
   TEMRPOLYDRAW16* = EMRPOLYDRAW16
   PEMRPOLYDRAW16* = ptr EMRPOLYDRAW16
-  EMRPOLYLINE* = record
+  EMRPOLYLINE* {.final.} = object
     emr*: EMR
     rclBounds*: RECTL
     cptl*: DWORD
@@ -8850,7 +8850,7 @@ type
   EMRPOLYLINETO* = EMRPOLYLINE
   TEMRPOLYLINETO* = EMRPOLYLINE
   PEMRPOLYLINETO* = ptr EMRPOLYLINE
-  EMRPOLYLINE16* = record
+  EMRPOLYLINE16* {.final.} = object
     emr*: EMR
     rclBounds*: RECTL
     cpts*: DWORD
@@ -8871,7 +8871,7 @@ type
   EMRPOLYLINETO16* = EMRPOLYLINE16
   TEMRPOLYLINETO16* = EMRPOLYLINE16
   PEMRPOLYLINETO16* = ptr EMRPOLYLINE16
-  EMRPOLYPOLYLINE* = record
+  EMRPOLYPOLYLINE* {.final.} = object
     emr*: EMR
     rclBounds*: RECTL
     nPolys*: DWORD
@@ -8885,7 +8885,7 @@ type
   EMRPOLYPOLYGON* = EMRPOLYPOLYLINE
   TEMRPOLYPOLYGON* = EMRPOLYPOLYLINE
   PEMRPOLYPOLYGON* = ptr EMRPOLYPOLYLINE
-  EMRPOLYPOLYLINE16* = record
+  EMRPOLYPOLYLINE16* {.final.} = object
     emr*: EMR
     rclBounds*: RECTL
     nPolys*: DWORD
@@ -8899,7 +8899,7 @@ type
   EMRPOLYPOLYGON16* = EMRPOLYPOLYLINE16
   TEMRPOLYPOLYGON16* = EMRPOLYPOLYLINE16
   PEMRPOLYPOLYGON16* = ptr EMRPOLYPOLYLINE16
-  EMRPOLYTEXTOUTA* = record
+  EMRPOLYTEXTOUTA* {.final.} = object
     emr*: EMR
     rclBounds*: RECTL
     iGraphicsMode*: DWORD
@@ -8914,7 +8914,7 @@ type
   EMRPOLYTEXTOUTW* = EMRPOLYTEXTOUTA
   TEMRPOLYTEXTOUTW* = EMRPOLYTEXTOUTA
   PEMRPOLYTEXTOUTW* = ptr EMRPOLYTEXTOUTA
-  EMRRESIZEPALETTE* = record
+  EMRRESIZEPALETTE* {.final.} = object
     emr*: EMR
     ihPal*: DWORD
     cEntries*: DWORD
@@ -8922,14 +8922,14 @@ type
   tagEMRRESIZEPALETTE* = EMRRESIZEPALETTE
   TEMRRESIZEPALETTE* = EMRRESIZEPALETTE
   PEMRRESIZEPALETTE* = ptr EMRRESIZEPALETTE
-  EMRRESTOREDC* = record
+  EMRRESTOREDC* {.final.} = object
     emr*: EMR
     iRelative*: LONG
 
   tagEMRRESTOREDC* = EMRRESTOREDC
   TEMRRESTOREDC* = EMRRESTOREDC
   PEMRRESTOREDC* = ptr EMRRESTOREDC
-  EMRROUNDRECT* = record
+  EMRROUNDRECT* {.final.} = object
     emr*: EMR
     rclBox*: RECTL
     szlCorner*: SIZEL
@@ -8937,7 +8937,7 @@ type
   tagEMRROUNDRECT* = EMRROUNDRECT
   TEMRROUNDRECT* = EMRROUNDRECT
   PEMRROUNDRECT* = ptr EMRROUNDRECT
-  EMRSCALEVIEWPORTEXTEX* = record
+  EMRSCALEVIEWPORTEXTEX* {.final.} = object
     emr*: EMR
     xNum*: LONG
     xDenom*: LONG
@@ -8950,7 +8950,7 @@ type
   EMRSCALEWINDOWEXTEX* = EMRSCALEVIEWPORTEXTEX
   TEMRSCALEWINDOWEXTEX* = EMRSCALEVIEWPORTEXTEX
   PEMRSCALEWINDOWEXTEX* = ptr EMRSCALEVIEWPORTEXTEX
-  EMRSELECTCOLORSPACE* = record
+  EMRSELECTCOLORSPACE* {.final.} = object
     emr*: EMR
     ihCS*: DWORD
 
@@ -8960,7 +8960,7 @@ type
   EMRDELETECOLORSPACE* = EMRSELECTCOLORSPACE
   TEMRDELETECOLORSPACE* = EMRSELECTCOLORSPACE
   PEMRDELETECOLORSPACE* = ptr EMRSELECTCOLORSPACE
-  EMRSELECTOBJECT* = record
+  EMRSELECTOBJECT* {.final.} = object
     emr*: EMR
     ihObject*: DWORD
 
@@ -8970,21 +8970,21 @@ type
   EMRDELETEOBJECT* = EMRSELECTOBJECT
   TEMRDELETEOBJECT* = EMRSELECTOBJECT
   PEMRDELETEOBJECT* = ptr EMRSELECTOBJECT
-  EMRSELECTPALETTE* = record
+  EMRSELECTPALETTE* {.final.} = object
     emr*: EMR
     ihPal*: DWORD
 
   tagEMRSELECTPALETTE* = EMRSELECTPALETTE
   TEMRSELECTPALETTE* = EMRSELECTPALETTE
   PEMRSELECTPALETTE* = ptr EMRSELECTPALETTE
-  EMRSETARCDIRECTION* = record
+  EMRSETARCDIRECTION* {.final.} = object
     emr*: EMR
     iArcDirection*: DWORD
 
   tagEMRSETARCDIRECTION* = EMRSETARCDIRECTION
   TEMRSETARCDIRECTION* = EMRSETARCDIRECTION
   PEMRSETARCDIRECTION* = ptr EMRSETARCDIRECTION
-  EMRSETBKCOLOR* = record
+  EMRSETBKCOLOR* {.final.} = object
     emr*: EMR
     crColor*: COLORREF
 
@@ -8994,14 +8994,14 @@ type
   EMRSETTEXTCOLOR* = EMRSETBKCOLOR
   TEMRSETTEXTCOLOR* = EMRSETBKCOLOR
   PEMRSETTEXTCOLOR* = ptr EMRSETBKCOLOR
-  EMRSETCOLORADJUSTMENT* = record
+  EMRSETCOLORADJUSTMENT* {.final.} = object
     emr*: EMR
     ColorAdjustment*: COLORADJUSTMENT
 
   tagEMRSETCOLORADJUSTMENT* = EMRSETCOLORADJUSTMENT
   TEMRSETCOLORADJUSTMENT* = EMRSETCOLORADJUSTMENT
   PEMRSETCOLORADJUSTMENT* = ptr EMRSETCOLORADJUSTMENT
-  EMRSETDIBITSTODEVICE* = record
+  EMRSETDIBITSTODEVICE* {.final.} = object
     emr*: EMR
     rclBounds*: RECTL
     xDest*: LONG
@@ -9021,21 +9021,21 @@ type
   tagEMRSETDIBITSTODEVICE* = EMRSETDIBITSTODEVICE
   TEMRSETDIBITSTODEVICE* = EMRSETDIBITSTODEVICE
   PEMRSETDIBITSTODEVICE* = ptr EMRSETDIBITSTODEVICE
-  EMRSETMAPPERFLAGS* = record
+  EMRSETMAPPERFLAGS* {.final.} = object
     emr*: EMR
     dwFlags*: DWORD
 
   tagEMRSETMAPPERFLAGS* = EMRSETMAPPERFLAGS
   TEMRSETMAPPERFLAGS* = EMRSETMAPPERFLAGS
   PEMRSETMAPPERFLAGS* = ptr EMRSETMAPPERFLAGS
-  EMRSETMITERLIMIT* = record
+  EMRSETMITERLIMIT* {.final.} = object
     emr*: EMR
     eMiterLimit*: float32
 
   tagEMRSETMITERLIMIT* = EMRSETMITERLIMIT
   TEMRSETMITERLIMIT* = EMRSETMITERLIMIT
   PEMRSETMITERLIMIT* = ptr EMRSETMITERLIMIT
-  EMRSETPALETTEENTRIES* = record
+  EMRSETPALETTEENTRIES* {.final.} = object
     emr*: EMR
     ihPal*: DWORD
     iStart*: DWORD
@@ -9045,7 +9045,7 @@ type
   tagEMRSETPALETTEENTRIES* = EMRSETPALETTEENTRIES
   TEMRSETPALETTEENTRIES* = EMRSETPALETTEENTRIES
   PEMRSETPALETTEENTRIES* = ptr EMRSETPALETTEENTRIES
-  EMRSETPIXELV* = record
+  EMRSETPIXELV* {.final.} = object
     emr*: EMR
     ptlPixel*: POINTL
     crColor*: COLORREF
@@ -9053,7 +9053,7 @@ type
   tagEMRSETPIXELV* = EMRSETPIXELV
   TEMRSETPIXELV* = EMRSETPIXELV
   PEMRSETPIXELV* = ptr EMRSETPIXELV
-  EMRSETVIEWPORTEXTEX* = record
+  EMRSETVIEWPORTEXTEX* {.final.} = object
     emr*: EMR
     szlExtent*: SIZEL
 
@@ -9063,7 +9063,7 @@ type
   EMRSETWINDOWEXTEX* = EMRSETVIEWPORTEXTEX
   TEMRSETWINDOWEXTEX* = EMRSETVIEWPORTEXTEX
   PEMRSETWINDOWEXTEX* = ptr EMRSETVIEWPORTEXTEX
-  EMRSETVIEWPORTORGEX* = record
+  EMRSETVIEWPORTORGEX* {.final.} = object
     emr*: EMR
     ptlOrigin*: POINTL
 
@@ -9076,14 +9076,14 @@ type
   EMRSETBRUSHORGEX* = EMRSETVIEWPORTORGEX
   TEMRSETBRUSHORGEX* = EMRSETVIEWPORTORGEX
   PEMRSETBRUSHORGEX* = ptr EMRSETVIEWPORTORGEX
-  EMRSETWORLDTRANSFORM* = record
+  EMRSETWORLDTRANSFORM* {.final.} = object
     emr*: EMR
     xform*: XFORM
 
   tagEMRSETWORLDTRANSFORM* = EMRSETWORLDTRANSFORM
   TEMRSETWORLDTRANSFORM* = EMRSETWORLDTRANSFORM
   PEMRSETWORLDTRANSFORM* = ptr EMRSETWORLDTRANSFORM
-  EMRSTRETCHBLT* = record
+  EMRSTRETCHBLT* {.final.} = object
     emr*: EMR
     rclBounds*: RECTL
     xDest*: LONG
@@ -9106,7 +9106,7 @@ type
   tagEMRSTRETCHBLT* = EMRSTRETCHBLT
   TEMRSTRETCHBLT* = EMRSTRETCHBLT
   PEMRSTRETCHBLT* = ptr EMRSTRETCHBLT
-  EMRSTRETCHDIBITS* = record
+  EMRSTRETCHDIBITS* {.final.} = object
     emr*: EMR
     rclBounds*: RECTL
     xDest*: LONG
@@ -9127,7 +9127,7 @@ type
   tagEMRSTRETCHDIBITS* = EMRSTRETCHDIBITS
   TEMRSTRETCHDIBITS* = EMRSTRETCHDIBITS
   PEMRSTRETCHDIBITS* = ptr EMRSTRETCHDIBITS
-  EMRABORTPATH* = record
+  EMRABORTPATH* {.final.} = object
     emr*: EMR
 
   TEMRABORTPATH* = EMRABORTPATH
@@ -9158,7 +9158,7 @@ type
   EMRREALIZEPALETTE* = EMRABORTPATH
   TEMRREALIZEPALETTE* = EMRABORTPATH
   PEMRREALIZEPALETTE* = ptr EMRABORTPATH
-  EMRSELECTCLIPPATH* = record
+  EMRSELECTCLIPPATH* {.final.} = object
     emr*: EMR
     iMode*: DWORD
 
@@ -9186,7 +9186,7 @@ type
   EMRENABLEICM* = EMRSELECTCLIPPATH
   TEMRENABLEICM* = EMRSELECTCLIPPATH
   PEMRENABLEICM* = ptr EMRSELECTCLIPPATH
-  NMHDR* = record
+  NMHDR* {.final.} = object
     hwndFrom*: HWND
     idFrom*: UINT
     code*: UINT
@@ -9194,33 +9194,33 @@ type
   tagNMHDR* = NMHDR
   TNMHDR* = NMHDR
   PNMHDR* = ptr NMHDR
-  TENCORRECTTEXT* = record
+  TENCORRECTTEXT* {.final.} = object
     nmhdr*: NMHDR
     chrg*: CHARRANGE
     seltyp*: int16
 
   Pencorrecttext* = ptr TENCORRECTTEXT
-  TENDROPFILES* = record
+  TENDROPFILES* {.final.} = object
     nmhdr*: NMHDR
     hDrop*: HANDLE
     cp*: LONG
     fProtected*: WINBOOL
 
   Pendropfiles* = ptr TENDROPFILES
-  TENSAVECLIPBOARD* = record
+  TENSAVECLIPBOARD* {.final.} = object
     nmhdr*: NMHDR
     cObjectCount*: LONG
     cch*: LONG
 
   PENSAVECLIPBOARD* = ptr TENSAVECLIPBOARD
-  TENOLEOPFAILED* = record
+  TENOLEOPFAILED* {.final.} = object
     nmhdr*: NMHDR
     iob*: LONG
     lOper*: LONG
     hr*: HRESULT
 
   PENOLEOPFAILED* = ptr TENOLEOPFAILED
-  TENHMETAHEADER* = record
+  TENHMETAHEADER* {.final.} = object
     iType*: DWORD
     nSize*: DWORD
     rclBounds*: RECTL
@@ -9239,14 +9239,14 @@ type
 
   LPENHMETAHEADER* = ptr TENHMETAHEADER
   PENHMETAHEADER* = ptr TENHMETAHEADER
-  TENHMETARECORD* = record
+  TENHMETARECORD* {.final.} = object
     iType*: DWORD
     nSize*: DWORD
     dParm*: array[0..0, DWORD]
 
   LPENHMETARECORD* = ptr TENHMETARECORD
   PENHMETARECORD* = ptr TENHMETARECORD
-  TENPROTECTED* = record
+  TENPROTECTED* {.final.} = object
     nmhdr*: NMHDR
     msg*: UINT
     wParam*: WPARAM
@@ -9254,7 +9254,7 @@ type
     chrg*: CHARRANGE
 
   Penprotected* = ptr TENPROTECTED
-  SERVICE_STATUS* = record
+  SERVICE_STATUS* {.final.} = object
     dwServiceType*: DWORD
     dwCurrentState*: DWORD
     dwControlsAccepted*: DWORD
@@ -9266,7 +9266,7 @@ type
   LPSERVICE_STATUS* = ptr SERVICE_STATUS
   TSERVICESTATUS* = SERVICE_STATUS
   PSERVICESTATUS* = ptr SERVICE_STATUS
-  ENUM_SERVICE_STATUS* = record
+  ENUM_SERVICE_STATUS* {.final.} = object
     lpServiceName*: LPTSTR
     lpDisplayName*: LPTSTR
     ServiceStatus*: SERVICE_STATUS
@@ -9274,14 +9274,14 @@ type
   LPENUM_SERVICE_STATUS* = ptr ENUM_SERVICE_STATUS
   TENUMSERVICESTATUS* = ENUM_SERVICE_STATUS
   PENUMSERVICESTATUS* = ptr ENUM_SERVICE_STATUS
-  ENUMLOGFONT* = record
+  ENUMLOGFONT* {.final.} = object
     elfLogFont*: LOGFONT
     elfFullName*: array[0..(LF_FULLFACESIZE) - 1, BCHAR]
     elfStyle*: array[0..(LF_FACESIZE) - 1, BCHAR]
 
   TENUMLOGFONT* = ENUMLOGFONT
   PENUMLOGFONT* = ptr ENUMLOGFONT
-  ENUMLOGFONTEX* = record
+  ENUMLOGFONTEX* {.final.} = object
     elfLogFont*: LOGFONT
     elfFullName*: array[0..(LF_FULLFACESIZE) - 1, BCHAR]
     elfStyle*: array[0..(LF_FACESIZE) - 1, BCHAR]
@@ -9300,7 +9300,7 @@ type
                                       #    CHAR  Pad[]
                                       #    DWORD Length;
                                       #
-  EVENTLOGRECORD* = record
+  EVENTLOGRECORD* {.final.} = object
     len*: DWORD
     Reserved*: DWORD
     RecordNumber*: DWORD
@@ -9320,7 +9320,7 @@ type
 
   TEVENTLOGRECORD* = EVENTLOGRECORD
   PEVENTLOGRECORD* = ptr EVENTLOGRECORD
-  EVENTMSG* = record
+  EVENTMSG* {.final.} = object
     message*: UINT
     paramL*: UINT
     paramH*: UINT
@@ -9330,14 +9330,14 @@ type
   tagEVENTMSG* = EVENTMSG
   TEVENTMSG* = EVENTMSG
   PEVENTMSG* = ptr EVENTMSG
-  EXCEPTION_POINTERS* = record
+  EXCEPTION_POINTERS* {.final.} = object
     ExceptionRecord*: PEXCEPTION_RECORD
     ContextRecord*: PCONTEXT
 
   LPEXCEPTION_POINTERS* = ptr EXCEPTION_POINTERS
   PEXCEPTION_POINTERS* = ptr EXCEPTION_POINTERS
   TEXCEPTIONPOINTERS* = EXCEPTION_POINTERS
-  EXT_BUTTON* = record
+  EXT_BUTTON* {.final.} = object
     idCommand*: int16
     idsHelp*: int16
     fsStyle*: int16
@@ -9345,7 +9345,7 @@ type
   LPEXT_BUTTON* = ptr EXT_BUTTON
   TEXTBUTTON* = EXT_BUTTON
   PEXTBUTTON* = ptr EXT_BUTTON
-  FILTERKEYS* = record
+  FILTERKEYS* {.final.} = object
     cbSize*: UINT
     dwFlags*: DWORD
     iWaitMSec*: DWORD
@@ -9355,7 +9355,7 @@ type
 
   TFILTERKEYS* = FILTERKEYS
   PFILTERKEYS* = ptr FILTERKEYS
-  FIND_NAME_BUFFER* = record
+  FIND_NAME_BUFFER* {.final.} = object
     len*: UCHAR
     access_control*: UCHAR
     frame_control*: UCHAR
@@ -9365,14 +9365,14 @@ type
 
   TFINDNAMEBUFFER* = FIND_NAME_BUFFER
   PFINDNAMEBUFFER* = ptr FIND_NAME_BUFFER
-  FIND_NAME_HEADER* = record
+  FIND_NAME_HEADER* {.final.} = object
     node_count*: int16
     reserved*: UCHAR
     unique_group*: UCHAR
 
   TFINDNAMEHEADER* = FIND_NAME_HEADER
   PFINDNAMEHEADER* = ptr FIND_NAME_HEADER
-  FINDREPLACE* = record
+  FINDREPLACE* {.final.} = object
     lStructSize*: DWORD
     hwndOwner*: HWND
     hInstance*: HINST
@@ -9388,19 +9388,19 @@ type
   LPFINDREPLACE* = ptr FINDREPLACE
   TFINDREPLACE* = FINDREPLACE
   PFINDREPLACE* = ptr FINDREPLACE #FINDTEXT = record conflicts with FindText function
-  TFINDTEXT* = record
+  TFINDTEXT* {.final.} = object
     chrg*: CHARRANGE
     lpstrText*: LPSTR
 
   Pfindtext* = ptr TFINDTEXT
-  FINDTEXTEX* = record
+  FINDTEXTEX* {.final.} = object
     chrg*: CHARRANGE
     lpstrText*: LPSTR
     chrgText*: CHARRANGE
 
   Tfindtextex* = FINDTEXTEX
   Pfindtextex* = ptr FINDTEXTEX
-  FMS_GETDRIVEINFO* = record
+  FMS_GETDRIVEINFO* {.final.} = object
     dwTotalSpace*: DWORD
     dwFreeSpace*: DWORD
     szPath*: array[0..259, TCHAR]
@@ -9409,7 +9409,7 @@ type
 
   TFMSGETDRIVEINFO* = FMS_GETDRIVEINFO
   PFMSGETDRIVEINFO* = ptr FMS_GETDRIVEINFO
-  FMS_GETFILESEL* = record
+  FMS_GETFILESEL* {.final.} = object
     ftTime*: FILETIME
     dwSize*: DWORD
     bAttr*: int8
@@ -9417,7 +9417,7 @@ type
 
   TFMSGETFILESEL* = FMS_GETFILESEL
   PFMSGETFILESEL* = ptr FMS_GETFILESEL
-  FMS_LOAD* = record
+  FMS_LOAD* {.final.} = object
     dwSize*: DWORD
     szMenuName*: array[0..(MENU_TEXT_LEN) - 1, TCHAR]
     hMenu*: HMENU
@@ -9425,7 +9425,7 @@ type
 
   TFMSLOAD* = FMS_LOAD
   PFMSLOAD* = ptr FMS_LOAD
-  FMS_TOOLBARLOAD* = record
+  FMS_TOOLBARLOAD* {.final.} = object
     dwSize*: DWORD
     lpButtons*: LPEXT_BUTTON
     cButtons*: int16
@@ -9435,12 +9435,12 @@ type
 
   TFMSTOOLBARLOAD* = FMS_TOOLBARLOAD
   PFMSTOOLBARLOAD* = ptr FMS_TOOLBARLOAD
-  FOCUS_EVENT_RECORD* = record
+  FOCUS_EVENT_RECORD* {.final.} = object
     bSetFocus*: WINBOOL
 
   TFOCUSEVENTRECORD* = FOCUS_EVENT_RECORD
   PFOCUSEVENTRECORD* = ptr FOCUS_EVENT_RECORD
-  FORM_INFO_1* = record
+  FORM_INFO_1* {.final.} = object
     Flags*: DWORD
     pName*: LPTSTR
     Size*: SIZEL
@@ -9448,7 +9448,7 @@ type
 
   TFORMINFO1* = FORM_INFO_1
   PFORMINFO1* = ptr FORM_INFO_1
-  FORMAT_PARAMETERS* = record
+  FORMAT_PARAMETERS* {.final.} = object
     MediaType*: MEDIA_TYPE
     StartCylinderNumber*: DWORD
     EndCylinderNumber*: DWORD
@@ -9457,7 +9457,7 @@ type
 
   TFORMATPARAMETERS* = FORMAT_PARAMETERS
   PFORMATPARAMETERS* = ptr FORMAT_PARAMETERS
-  FORMATRANGE* = record
+  FORMATRANGE* {.final.} = object
     hdc*: HDC
     hdcTarget*: HDC
     rc*: RECT
@@ -9466,7 +9466,7 @@ type
 
   Tformatrange* = FORMATRANGE
   Pformatrange* = ptr FORMATRANGE
-  GCP_RESULTS* = record
+  GCP_RESULTS* {.final.} = object
     lStructSize*: DWORD
     lpOutString*: LPTSTR
     lpOrder*: ptr UINT
@@ -9481,7 +9481,7 @@ type
   tagGCP_RESULTS* = GCP_RESULTS
   TGCPRESULTS* = GCP_RESULTS
   PGCPRESULTS* = ptr GCP_RESULTS
-  GENERIC_MAPPING* = record
+  GENERIC_MAPPING* {.final.} = object
     GenericRead*: ACCESS_MASK
     GenericWrite*: ACCESS_MASK
     GenericExecute*: ACCESS_MASK
@@ -9489,7 +9489,7 @@ type
 
   PGENERIC_MAPPING* = ptr GENERIC_MAPPING
   TGENERICMAPPING* = GENERIC_MAPPING
-  GLYPHMETRICS* = record
+  GLYPHMETRICS* {.final.} = object
     gmBlackBoxX*: UINT
     gmBlackBoxY*: UINT
     gmptGlyphOrigin*: POINT
@@ -9499,20 +9499,20 @@ type
   LPGLYPHMETRICS* = ptr GLYPHMETRICS
   TGLYPHMETRICS* = GLYPHMETRICS
   PGLYPHMETRICS* = ptr GLYPHMETRICS
-  HANDLETABLE* = record
+  HANDLETABLE* {.final.} = object
     objectHandle*: array[0..0, HGDIOBJ]
 
   tagHANDLETABLE* = HANDLETABLE
   THANDLETABLE* = HANDLETABLE
   LPHANDLETABLE* = ptr HANDLETABLE
-  HD_HITTESTINFO* = record
+  HD_HITTESTINFO* {.final.} = object
     pt*: POINT
     flags*: UINT
     iItem*: int32
 
   THDHITTESTINFO* = HD_HITTESTINFO
   PHDHITTESTINFO* = ptr HD_HITTESTINFO
-  HD_ITEM* = record
+  HD_ITEM* {.final.} = object
     mask*: UINT
     cxy*: int32
     pszText*: LPTSTR
@@ -9523,7 +9523,7 @@ type
 
   THDITEM* = HD_ITEM
   PHDITEM* = ptr HD_ITEM
-  WINDOWPOS* = record
+  WINDOWPOS* {.final.} = object
     hwnd*: HWND
     hwndInsertAfter*: HWND
     x*: int32
@@ -9535,13 +9535,13 @@ type
   LPWINDOWPOS* = ptr WINDOWPOS
   TWINDOWPOS* = WINDOWPOS
   PWINDOWPOS* = ptr WINDOWPOS
-  HD_LAYOUT* = record
+  HD_LAYOUT* {.final.} = object
     prc*: ptr RECT
     pwpos*: ptr WINDOWPOS
 
   THDLAYOUT* = HD_LAYOUT
   PHDLAYOUT* = ptr HD_LAYOUT
-  HD_NOTIFY* = record
+  HD_NOTIFY* {.final.} = object
     hdr*: NMHDR
     iItem*: int32
     iButton*: int32
@@ -9549,7 +9549,7 @@ type
 
   THDNOTIFY* = HD_NOTIFY
   PHDNOTIFY* = ptr HD_NOTIFY
-  HELPINFO* = record
+  HELPINFO* {.final.} = object
     cbSize*: UINT
     iContextType*: int32
     iCtrlId*: int32
@@ -9561,7 +9561,7 @@ type
   tagHELPINFO* = HELPINFO
   THELPINFO* = HELPINFO
   PHELPINFO* = ptr HELPINFO
-  HELPWININFO* = record
+  HELPWININFO* {.final.} = object
     wStructSize*: int32
     x*: int32
     y*: int32
@@ -9572,7 +9572,7 @@ type
 
   THELPWININFO* = HELPWININFO
   PHELPWININFO* = ptr HELPWININFO
-  HIGHCONTRAST* = record
+  HIGHCONTRAST* {.final.} = object
     cbSize*: UINT
     dwFlags*: DWORD
     lpszDefaultScheme*: LPTSTR
@@ -9581,14 +9581,14 @@ type
   tagHIGHCONTRAST* = HIGHCONTRAST
   THIGHCONTRAST* = HIGHCONTRAST
   PHIGHCONTRAST* = ptr HIGHCONTRAST
-  HSZPAIR* = record
+  HSZPAIR* {.final.} = object
     hszSvc*: HSZ
     hszTopic*: HSZ
 
   tagHSZPAIR* = HSZPAIR
   THSZPAIR* = HSZPAIR
   PHSZPAIR* = ptr HSZPAIR
-  ICONINFO* = record
+  ICONINFO* {.final.} = object
     fIcon*: WINBOOL
     xHotspot*: DWORD
     yHotspot*: DWORD
@@ -9597,7 +9597,7 @@ type
 
   TICONINFO* = ICONINFO
   PICONINFO* = ptr ICONINFO
-  ICONMETRICS* = record
+  ICONMETRICS* {.final.} = object
     cbSize*: UINT
     iHorzSpacing*: int32
     iVertSpacing*: int32
@@ -9608,7 +9608,7 @@ type
   tagICONMETRICS* = ICONMETRICS
   TICONMETRICS* = ICONMETRICS
   PICONMETRICS* = ptr ICONMETRICS
-  IMAGEINFO* = record
+  IMAGEINFO* {.final.} = object
     hbmImage*: HBITMAP
     hbmMask*: HBITMAP
     Unused1*: int32
@@ -9617,7 +9617,7 @@ type
 
   TIMAGEINFO* = IMAGEINFO
   PIMAGEINFO* = ptr IMAGEINFO
-  KEY_EVENT_RECORD* = record
+  KEY_EVENT_RECORD* {.final.} = object
     bKeyDown*: WINBOOL
     wRepeatCount*: int16
     wVirtualKeyCode*: int16
@@ -9627,7 +9627,7 @@ type
 
   TKEYEVENTRECORD* = KEY_EVENT_RECORD
   PKEYEVENTRECORD* = ptr KEY_EVENT_RECORD
-  MOUSE_EVENT_RECORD* = record
+  MOUSE_EVENT_RECORD* {.final.} = object
     dwMousePosition*: COORD
     dwButtonState*: DWORD
     dwControlKeyState*: DWORD
@@ -9635,17 +9635,17 @@ type
 
   TMOUSEEVENTRECORD* = MOUSE_EVENT_RECORD
   PMOUSEEVENTRECORD* = ptr MOUSE_EVENT_RECORD
-  WINDOW_BUFFER_SIZE_RECORD* = record
+  WINDOW_BUFFER_SIZE_RECORD* {.final.} = object
     dwSize*: COORD
 
   TWINDOWBUFFERSIZERECORD* = WINDOW_BUFFER_SIZE_RECORD
   PWINDOWBUFFERSIZERECORD* = ptr WINDOW_BUFFER_SIZE_RECORD
-  MENU_EVENT_RECORD* = record
+  MENU_EVENT_RECORD* {.final.} = object
     dwCommandId*: UINT
 
   PMENU_EVENT_RECORD* = ptr MENU_EVENT_RECORD
   TMENUEVENTRECORD* = MENU_EVENT_RECORD
-  INPUT_RECORD* = record
+  INPUT_RECORD* {.final.} = object
     EventType*: int16
     Reserved*: int16
     event*: array[0..5, DWORD] #Event : record case longint of
@@ -9658,7 +9658,7 @@ type
 
   PINPUT_RECORD* = ptr INPUT_RECORD
   TINPUTRECORD* = INPUT_RECORD
-  SYSTEMTIME* = record
+  SYSTEMTIME* {.final.} = object
     wYear*: int16
     wMonth*: int16
     wDayOfWeek*: int16
@@ -9671,7 +9671,7 @@ type
   LPSYSTEMTIME* = ptr SYSTEMTIME
   TSYSTEMTIME* = SYSTEMTIME
   PSYSTEMTIME* = ptr SYSTEMTIME
-  JOB_INFO_1* = record
+  JOB_INFO_1* {.final.} = object
     JobId*: DWORD
     pPrinterName*: LPTSTR
     pMachineName*: LPTSTR
@@ -9688,13 +9688,13 @@ type
 
   TJOBINFO1* = JOB_INFO_1
   PJOBINFO1* = ptr JOB_INFO_1
-  SID_IDENTIFIER_AUTHORITY* = record
+  SID_IDENTIFIER_AUTHORITY* {.final.} = object
     Value*: array[0..5, int8]
 
   LPSID_IDENTIFIER_AUTHORITY* = ptr SID_IDENTIFIER_AUTHORITY
   PSID_IDENTIFIER_AUTHORITY* = ptr SID_IDENTIFIER_AUTHORITY
   TSIDIDENTIFIERAUTHORITY* = SID_IDENTIFIER_AUTHORITY
-  SID* = record
+  SID* {.final.} = object
     Revision*: int8
     SubAuthorityCount*: int8
     IdentifierAuthority*: SID_IDENTIFIER_AUTHORITY
@@ -9705,7 +9705,7 @@ type
   SECURITY_DESCRIPTOR_CONTROL* = int16
   PSECURITY_DESCRIPTOR_CONTROL* = ptr SECURITY_DESCRIPTOR_CONTROL
   TSECURITYDESCRIPTORCONTROL* = SECURITY_DESCRIPTOR_CONTROL
-  SECURITY_DESCRIPTOR* = record
+  SECURITY_DESCRIPTOR* {.final.} = object
     Revision*: int8
     Sbz1*: int8
     Control*: SECURITY_DESCRIPTOR_CONTROL
@@ -9716,7 +9716,7 @@ type
 
   PSECURITY_DESCRIPTOR* = ptr SECURITY_DESCRIPTOR
   TSECURITYDESCRIPTOR* = SECURITY_DESCRIPTOR
-  JOB_INFO_2* = record
+  JOB_INFO_2* {.final.} = object
     JobId*: DWORD
     pPrinterName*: LPTSTR
     pMachineName*: LPTSTR
@@ -9743,7 +9743,7 @@ type
 
   TJOBINFO2* = JOB_INFO_2
   PJOBINFO2* = ptr JOB_INFO_2
-  KERNINGPAIR* = record
+  KERNINGPAIR* {.final.} = object
     wFirst*: int16
     wSecond*: int16
     iKernAmount*: int32
@@ -9751,13 +9751,13 @@ type
   LPKERNINGPAIR* = ptr KERNINGPAIR
   TKERNINGPAIR* = KERNINGPAIR
   PKERNINGPAIR* = ptr KERNINGPAIR
-  LANA_ENUM* = record
+  LANA_ENUM* {.final.} = object
     len*: UCHAR
     lana*: array[0..(MAX_LANA) - 1, UCHAR]
 
   TLANAENUM* = LANA_ENUM
   PLANAENUM* = ptr LANA_ENUM
-  LDT_ENTRY* = record
+  LDT_ENTRY* {.final.} = object
     LimitLow*: int16
     BaseLow*: int16
     BaseMid*: int8
@@ -9792,7 +9792,7 @@ const
   bp_LDT_ENTRY_BaseHi* = 24
 
 type
-  LOCALESIGNATURE* = record
+  LOCALESIGNATURE* {.final.} = object
     lsUsb*: array[0..3, DWORD]
     lsCsbDefault*: array[0..1, DWORD]
     lsCsbSupported*: array[0..1, DWORD]
@@ -9800,12 +9800,12 @@ type
   tagLOCALESIGNATURE* = LOCALESIGNATURE
   TLOCALESIGNATURE* = LOCALESIGNATURE
   PLOCALESIGNATURE* = ptr LOCALESIGNATURE
-  LOCALGROUP_MEMBERS_INFO_0* = record
+  LOCALGROUP_MEMBERS_INFO_0* {.final.} = object
     lgrmi0_sid*: PSID
 
   TLOCALGROUPMEMBERSINFO0* = LOCALGROUP_MEMBERS_INFO_0
   PLOCALGROUPMEMBERSINFO0* = ptr LOCALGROUP_MEMBERS_INFO_0
-  LOCALGROUP_MEMBERS_INFO_3* = record
+  LOCALGROUP_MEMBERS_INFO_3* {.final.} = object
     lgrmi3_domainandname*: LPWSTR
 
   TLOCALGROUPMEMBERSINFO3* = LOCALGROUP_MEMBERS_INFO_3
@@ -9817,7 +9817,7 @@ type
   LUID* = TlargeInteger
   TLUID* = LUID
   PLUID* = ptr LUID
-  LUID_AND_ATTRIBUTES* = record
+  LUID_AND_ATTRIBUTES* {.final.} = object
     Luid*: LUID
     Attributes*: DWORD
 
@@ -9826,7 +9826,7 @@ type
   LUID_AND_ATTRIBUTES_ARRAY* = array[0..(ANYSIZE_ARRAY) - 1, LUID_AND_ATTRIBUTES]
   PLUID_AND_ATTRIBUTES_ARRAY* = ptr LUID_AND_ATTRIBUTES_ARRAY
   TLUIDANDATTRIBUTESARRAY* = LUID_AND_ATTRIBUTES_ARRAY
-  LV_COLUMN* = record
+  LV_COLUMN* {.final.} = object
     mask*: UINT
     fmt*: int32
     cx*: int32
@@ -9836,7 +9836,7 @@ type
 
   TLVCOLUMN* = LV_COLUMN
   PLVCOLUMN* = ptr LV_COLUMN
-  LV_ITEM* = record
+  LV_ITEM* {.final.} = object
     mask*: UINT
     iItem*: int32
     iSubItem*: int32
@@ -9849,14 +9849,14 @@ type
 
   TLVITEM* = LV_ITEM
   PLVITEM* = ptr LV_ITEM
-  LV_DISPINFO* = record
+  LV_DISPINFO* {.final.} = object
     hdr*: NMHDR
     item*: LV_ITEM
 
   tagLV_DISPINFO* = LV_DISPINFO
   TLVDISPINFO* = LV_DISPINFO
   PLVDISPINFO* = ptr LV_DISPINFO
-  LV_FINDINFO* = record
+  LV_FINDINFO* {.final.} = object
     flags*: UINT
     psz*: LPCTSTR
     lParam*: LPARAM
@@ -9865,14 +9865,14 @@ type
 
   TLVFINDINFO* = LV_FINDINFO
   PLVFINDINFO* = ptr LV_FINDINFO
-  LV_HITTESTINFO* = record
+  LV_HITTESTINFO* {.final.} = object
     pt*: POINT
     flags*: UINT
     iItem*: int32
 
   TLVHITTESTINFO* = LV_HITTESTINFO
   PLVHITTESTINFO* = ptr LV_HITTESTINFO
-  LV_KEYDOWN* = record
+  LV_KEYDOWN* {.final.} = object
     hdr*: NMHDR
     wVKey*: int16
     flags*: UINT
@@ -9880,7 +9880,7 @@ type
   tagLV_KEYDOWN* = LV_KEYDOWN
   TLVKEYDOWN* = LV_KEYDOWN
   PLVKEYDOWN* = ptr LV_KEYDOWN
-  MAT2* = record
+  MAT2* {.final.} = object
     eM11*: FIXED
     eM12*: FIXED
     eM21*: FIXED
@@ -9888,7 +9888,7 @@ type
 
   TMAT2* = MAT2
   PMAT2* = ptr MAT2
-  MDICREATESTRUCT* = record
+  MDICREATESTRUCT* {.final.} = object
     szClass*: LPCTSTR
     szTitle*: LPCTSTR
     hOwner*: HANDLE
@@ -9903,7 +9903,7 @@ type
   tagMDICREATESTRUCT* = MDICREATESTRUCT
   TMDICREATESTRUCT* = MDICREATESTRUCT
   PMDICREATESTRUCT* = ptr MDICREATESTRUCT
-  MEASUREITEMSTRUCT* = record
+  MEASUREITEMSTRUCT* {.final.} = object
     CtlType*: UINT
     CtlID*: UINT
     itemID*: UINT
@@ -9915,7 +9915,7 @@ type
   tagMEASUREITEMSTRUCT* = MEASUREITEMSTRUCT
   TMEASUREITEMSTRUCT* = MEASUREITEMSTRUCT
   PMEASUREITEMSTRUCT* = ptr MEASUREITEMSTRUCT
-  MEMORY_BASIC_INFORMATION* = record
+  MEMORY_BASIC_INFORMATION* {.final.} = object
     BaseAddress*: PVOID
     AllocationBase*: PVOID
     AllocationProtect*: DWORD
@@ -9926,7 +9926,7 @@ type
 
   PMEMORY_BASIC_INFORMATION* = ptr MEMORY_BASIC_INFORMATION
   TMEMORYBASICINFORMATION* = MEMORY_BASIC_INFORMATION
-  MEMORYSTATUS* = record
+  MEMORYSTATUS* {.final.} = object
     dwLength*: DWORD
     dwMemoryLoad*: DWORD
     dwTotalPhys*: int
@@ -9936,7 +9936,7 @@ type
     dwTotalVirtual*: int
     dwAvailVirtual*: int
 
-  TGUID* = record
+  TGUID* {.final.} = object
     D1*: int32
     D2*: int16
     D3*: int16
@@ -9945,14 +9945,14 @@ type
   LPMEMORYSTATUS* = ptr MEMORYSTATUS
   TMEMORYSTATUS* = MEMORYSTATUS
   PMEMORYSTATUS* = ptr MEMORYSTATUS
-  MENUEX_TEMPLATE_HEADER* = record
+  MENUEX_TEMPLATE_HEADER* {.final.} = object
     wVersion*: int16
     wOffset*: int16
     dwHelpId*: DWORD
 
   TMENUXTEMPLATEHEADER* = MENUEX_TEMPLATE_HEADER
   PMENUXTEMPLATEHEADER* = ptr MENUEX_TEMPLATE_HEADER
-  MENUEX_TEMPLATE_ITEM* = record
+  MENUEX_TEMPLATE_ITEM* {.final.} = object
     dwType*: DWORD
     dwState*: DWORD
     uId*: UINT
@@ -9962,7 +9962,7 @@ type
 
   TMENUEXTEMPLATEITEM* = MENUEX_TEMPLATE_ITEM
   PMENUEXTEMPLATEITEM* = ptr MENUEX_TEMPLATE_ITEM
-  MENUINFO* = record
+  MENUINFO* {.final.} = object
     cbSize*: DWORD
     fMask*: DWORD
     dwStyle*: DWORD
@@ -9976,7 +9976,7 @@ type
   tagMENUINFO* = MENUINFO
   TMENUINFO* = MENUINFO
   PMENUINFO* = ptr MENUINFO
-  MENUITEMINFO* = record
+  MENUITEMINFO* {.final.} = object
     cbSize*: UINT
     fMask*: UINT
     fType*: UINT
@@ -9996,24 +9996,24 @@ type
   TMENUITEMINFO* = MENUITEMINFO
   TMENUITEMINFOA* = MENUITEMINFO
   PMENUITEMINFO* = ptr MENUITEMINFO
-  MENUITEMTEMPLATE* = record
+  MENUITEMTEMPLATE* {.final.} = object
     mtOption*: int16
     mtID*: int16
     mtString*: array[0..0, WCHAR]
 
   TMENUITEMTEMPLATE* = MENUITEMTEMPLATE
   PMENUITEMTEMPLATE* = ptr MENUITEMTEMPLATE
-  MENUITEMTEMPLATEHEADER* = record
+  MENUITEMTEMPLATEHEADER* {.final.} = object
     versionNumber*: int16
     offset*: int16
 
   TMENUITEMTEMPLATEHEADER* = MENUITEMTEMPLATEHEADER
   PMENUITEMTEMPLATEHEADER* = ptr MENUITEMTEMPLATEHEADER
-  MENUTEMPLATE* = record
+  MENUTEMPLATE* {.final.} = object
   LPMENUTEMPLATE* = ptr MENUTEMPLATE
   TMENUTEMPLATE* = MENUTEMPLATE
   PMENUTEMPLATE* = ptr MENUTEMPLATE
-  METAFILEPICT* = record
+  METAFILEPICT* {.final.} = object
     mm*: LONG
     xExt*: LONG
     yExt*: LONG
@@ -10023,7 +10023,7 @@ type
   tagMETAFILEPICT* = METAFILEPICT
   TMETAFILEPICT* = METAFILEPICT
   PMETAFILEPICT* = ptr METAFILEPICT
-  METAHEADER* = record
+  METAHEADER* {.final.} = object
     mtType*: int16
     mtHeaderSize*: int16
     mtVersion*: int16
@@ -10035,7 +10035,7 @@ type
   tagMETAHEADER* = METAHEADER
   TMETAHEADER* = METAHEADER
   PMETAHEADER* = ptr METAHEADER
-  METARECORD* = record
+  METARECORD* {.final.} = object
     rdSize*: DWORD
     rdFunction*: int16
     rdParm*: array[0..0, int16]
@@ -10044,7 +10044,7 @@ type
   tagMETARECORD* = METARECORD
   TMETARECORD* = METARECORD
   PMETARECORD* = ptr METARECORD
-  MINIMIZEDMETRICS* = record
+  MINIMIZEDMETRICS* {.final.} = object
     cbSize*: UINT
     iWidth*: int32
     iHorzGap*: int32
@@ -10055,7 +10055,7 @@ type
   tagMINIMIZEDMETRICS* = MINIMIZEDMETRICS
   TMINIMIZEDMETRICS* = MINIMIZEDMETRICS
   PMINIMIZEDMETRICS* = ptr MINIMIZEDMETRICS
-  MINMAXINFO* = record
+  MINMAXINFO* {.final.} = object
     ptReserved*: POINT
     ptMaxSize*: POINT
     ptMaxPosition*: POINT
@@ -10065,7 +10065,7 @@ type
   tagMINMAXINFO* = MINMAXINFO
   TMINMAXINFO* = MINMAXINFO
   PMINMAXINFO* = ptr MINMAXINFO
-  MODEMDEVCAPS* = record
+  MODEMDEVCAPS* {.final.} = object
     dwActualSize*: DWORD
     dwRequiredSize*: DWORD
     dwDevSpecificOffset*: DWORD
@@ -10091,7 +10091,7 @@ type
   TMODEMDEVCAPS* = MODEMDEVCAPS
   PMODEMDEVCAPS* = ptr MODEMDEVCAPS
   modemdevcaps_tag* = MODEMDEVCAPS
-  MODEMSETTINGS* = record
+  MODEMSETTINGS* {.final.} = object
     dwActualSize*: DWORD
     dwRequiredSize*: DWORD
     dwDevSpecificOffset*: DWORD
@@ -10109,7 +10109,7 @@ type
   TMODEMSETTINGS* = MODEMSETTINGS
   PMODEMSETTINGS* = ptr MODEMSETTINGS
   modemsettings_tag* = MODEMSETTINGS
-  MONCBSTRUCT* = record
+  MONCBSTRUCT* {.final.} = object
     cb*: UINT
     dwTime*: DWORD
     hTask*: HANDLE
@@ -10129,7 +10129,7 @@ type
   tagMONCBSTRUCT* = MONCBSTRUCT
   TMONCBSTRUCT* = MONCBSTRUCT
   PMONCBSTRUCT* = ptr MONCBSTRUCT
-  MONCONVSTRUCT* = record
+  MONCONVSTRUCT* {.final.} = object
     cb*: UINT
     fConnect*: WINBOOL
     dwTime*: DWORD
@@ -10142,7 +10142,7 @@ type
   tagMONCONVSTRUCT* = MONCONVSTRUCT
   TMONCONVSTRUCT* = MONCONVSTRUCT
   PMONCONVSTRUCT* = ptr MONCONVSTRUCT
-  MONERRSTRUCT* = record
+  MONERRSTRUCT* {.final.} = object
     cb*: UINT
     wLastError*: UINT
     dwTime*: DWORD
@@ -10151,7 +10151,7 @@ type
   tagMONERRSTRUCT* = MONERRSTRUCT
   TMONERRSTRUCT* = MONERRSTRUCT
   PMONERRSTRUCT* = ptr MONERRSTRUCT
-  MONHSZSTRUCT* = record
+  MONHSZSTRUCT* {.final.} = object
     cb*: UINT
     fsAction*: WINBOOL
     dwTime*: DWORD
@@ -10162,19 +10162,19 @@ type
   tagMONHSZSTRUCT* = MONHSZSTRUCT
   TMONHSZSTRUCT* = MONHSZSTRUCT
   PMONHSZSTRUCT* = ptr MONHSZSTRUCT
-  MONITOR_INFO_1* = record
+  MONITOR_INFO_1* {.final.} = object
     pName*: LPTSTR
 
   TMONITORINFO1* = MONITOR_INFO_1
   PMONITORINFO1* = ptr MONITOR_INFO_1
-  MONITOR_INFO_2* = record
+  MONITOR_INFO_2* {.final.} = object
     pName*: LPTSTR
     pEnvironment*: LPTSTR
     pDLLName*: LPTSTR
 
   TMONITORINFO2* = MONITOR_INFO_2
   PMONITORINFO2* = ptr MONITOR_INFO_2
-  MONLINKSTRUCT* = record
+  MONLINKSTRUCT* {.final.} = object
     cb*: UINT
     dwTime*: DWORD
     hTask*: HANDLE
@@ -10191,7 +10191,7 @@ type
   tagMONLINKSTRUCT* = MONLINKSTRUCT
   TMONLINKSTRUCT* = MONLINKSTRUCT
   PMONLINKSTRUCT* = ptr MONLINKSTRUCT
-  MONMSGSTRUCT* = record
+  MONMSGSTRUCT* {.final.} = object
     cb*: UINT
     hwndTo*: HWND
     dwTime*: DWORD
@@ -10204,7 +10204,7 @@ type
   tagMONMSGSTRUCT* = MONMSGSTRUCT
   TMONMSGSTRUCT* = MONMSGSTRUCT
   PMONMSGSTRUCT* = ptr MONMSGSTRUCT
-  MOUSEHOOKSTRUCT* = record
+  MOUSEHOOKSTRUCT* {.final.} = object
     pt*: POINT
     hwnd*: HWND
     wHitTestCode*: UINT
@@ -10214,7 +10214,7 @@ type
   tagMOUSEHOOKSTRUCT* = MOUSEHOOKSTRUCT
   TMOUSEHOOKSTRUCT* = MOUSEHOOKSTRUCT
   PMOUSEHOOKSTRUCT* = ptr MOUSEHOOKSTRUCT
-  MOUSEKEYS* = record
+  MOUSEKEYS* {.final.} = object
     cbSize*: DWORD
     dwFlags*: DWORD
     iMaxSpeed*: DWORD
@@ -10227,7 +10227,7 @@ type
   PMOUSEKEYS* = ptr MOUSEKEYS
   MSGBOXCALLBACK* = proc (lpHelpInfo: LPHELPINFO){.stdcall.}
   TMSGBOXCALLBACK* = MSGBOXCALLBACK
-  MSGBOXPARAMS* = record
+  MSGBOXPARAMS* {.final.} = object
     cbSize*: UINT
     hwndOwner*: HWND
     hInstance*: HINST
@@ -10243,7 +10243,7 @@ type
   TMSGBOXPARAMS* = MSGBOXPARAMS
   TMSGBOXPARAMSA* = MSGBOXPARAMS
   PMSGBOXPARAMS* = ptr MSGBOXPARAMS
-  MSGFILTER* = record
+  MSGFILTER* {.final.} = object
     nmhdr*: NMHDR
     msg*: UINT
     wParam*: WPARAM
@@ -10251,7 +10251,7 @@ type
 
   Tmsgfilter* = MSGFILTER
   Pmsgfilter* = ptr MSGFILTER
-  MULTIKEYHELP* = record
+  MULTIKEYHELP* {.final.} = object
     mkSize*: DWORD
     mkKeylist*: TCHAR
     szKeyphrase*: array[0..0, TCHAR]
@@ -10259,7 +10259,7 @@ type
   tagMULTIKEYHELP* = MULTIKEYHELP
   TMULTIKEYHELP* = MULTIKEYHELP
   PMULTIKEYHELP* = ptr MULTIKEYHELP
-  NAME_BUFFER* = record
+  NAME_BUFFER* {.final.} = object
     name*: array[0..(NCBNAMSZ) - 1, UCHAR]
     name_num*: UCHAR
     name_flags*: UCHAR
@@ -10267,7 +10267,7 @@ type
   TNAMEBUFFER* = NAME_BUFFER
   PNAMEBUFFER* = ptr NAME_BUFFER
   p_NCB* = ptr NCB
-  NCB* = record
+  NCB* {.final.} = object
     ncb_command*: UCHAR
     ncb_retcode*: UCHAR
     ncb_lsn*: UCHAR
@@ -10285,13 +10285,13 @@ type
     ncb_event*: HANDLE
 
   TNCB* = NCB
-  NCCALCSIZE_PARAMS* = record
+  NCCALCSIZE_PARAMS* {.final.} = object
     rgrc*: array[0..2, RECT]
     lppos*: PWINDOWPOS
 
   TNCCALCSIZEPARAMS* = NCCALCSIZE_PARAMS
   PNCCALCSIZEPARAMS* = ptr NCCALCSIZE_PARAMS
-  NDDESHAREINFO* = record
+  NDDESHAREINFO* {.final.} = object
     lRevision*: LONG
     lpszShareName*: LPTSTR
     lShareType*: LONG
@@ -10306,7 +10306,7 @@ type
 
   TNDDESHAREINFO* = NDDESHAREINFO
   PNDDESHAREINFO* = ptr NDDESHAREINFO
-  NETRESOURCE* = record
+  NETRESOURCE* {.final.} = object
     dwScope*: DWORD
     dwType*: DWORD
     dwDisplayType*: DWORD
@@ -10321,7 +10321,7 @@ type
   TNETRESOURCEA* = NETRESOURCE
   PNETRESOURCE* = ptr NETRESOURCE
   PNETRESOURCEA* = ptr NETRESOURCE
-  NEWCPLINFO* = record
+  NEWCPLINFO* {.final.} = object
     dwSize*: DWORD
     dwFlags*: DWORD
     dwHelpContext*: DWORD
@@ -10334,7 +10334,7 @@ type
   tagNEWCPLINFO* = NEWCPLINFO
   TNEWCPLINFO* = NEWCPLINFO
   PNEWCPLINFO* = ptr NEWCPLINFO
-  NEWTEXTMETRIC* = record
+  NEWTEXTMETRIC* {.final.} = object
     tmHeight*: LONG
     tmAscent*: LONG
     tmDescent*: LONG
@@ -10363,14 +10363,14 @@ type
   tagNEWTEXTMETRIC* = NEWTEXTMETRIC
   TNEWTEXTMETRIC* = NEWTEXTMETRIC
   PNEWTEXTMETRIC* = ptr NEWTEXTMETRIC
-  NEWTEXTMETRICEX* = record
+  NEWTEXTMETRICEX* {.final.} = object
     ntmentm*: NEWTEXTMETRIC
     ntmeFontSignature*: FONTSIGNATURE
 
   tagNEWTEXTMETRICEX* = NEWTEXTMETRICEX
   TNEWTEXTMETRICEX* = NEWTEXTMETRICEX
   PNEWTEXTMETRICEX* = ptr NEWTEXTMETRICEX
-  NM_LISTVIEW* = record
+  NM_LISTVIEW* {.final.} = object
     hdr*: NMHDR
     iItem*: int32
     iSubItem*: int32
@@ -10383,7 +10383,7 @@ type
   tagNM_LISTVIEW* = NM_LISTVIEW
   TNMLISTVIEW* = NM_LISTVIEW
   PNMLISTVIEW* = ptr NM_LISTVIEW
-  TV_ITEM* = record
+  TV_ITEM* {.final.} = object
     mask*: UINT
     hItem*: HTREEITEM
     state*: UINT
@@ -10398,7 +10398,7 @@ type
   LPTV_ITEM* = ptr TV_ITEM
   TTVITEM* = TV_ITEM
   PTVITEM* = ptr TV_ITEM
-  NM_TREEVIEW* = record
+  NM_TREEVIEW* {.final.} = object
     hdr*: NMHDR
     action*: UINT
     itemOld*: TV_ITEM
@@ -10408,14 +10408,14 @@ type
   LPNM_TREEVIEW* = ptr NM_TREEVIEW
   TNMTREEVIEW* = NM_TREEVIEW
   PNMTREEVIEW* = ptr NM_TREEVIEW
-  NM_UPDOWNW* = record
+  NM_UPDOWNW* {.final.} = object
     hdr*: NMHDR
     iPos*: int32
     iDelta*: int32
 
   TNMUPDOWN* = NM_UPDOWNW
   PNMUPDOWN* = ptr NM_UPDOWNW
-  NONCLIENTMETRICS* = record
+  NONCLIENTMETRICS* {.final.} = object
     cbSize*: UINT
     iBorderWidth*: int32
     iScrollWidth*: int32
@@ -10436,7 +10436,7 @@ type
   tagNONCLIENTMETRICS* = NONCLIENTMETRICS
   TNONCLIENTMETRICS* = NONCLIENTMETRICS
   PNONCLIENTMETRICS* = ptr NONCLIENTMETRICS
-  SERVICE_ADDRESS* = record
+  SERVICE_ADDRESS* {.final.} = object
     dwAddressType*: DWORD
     dwAddressFlags*: DWORD
     dwAddressLength*: DWORD
@@ -10446,7 +10446,7 @@ type
 
   TSERVICEADDRESS* = SERVICE_ADDRESS
   PSERVICEADDRESS* = ptr SERVICE_ADDRESS
-  SERVICE_ADDRESSES* = record
+  SERVICE_ADDRESSES* {.final.} = object
     dwAddressCount*: DWORD
     Addresses*: array[0..0, SERVICE_ADDRESS]
 
@@ -10459,7 +10459,7 @@ type
   LPCLSID* = ptr CLSID
   TCLSID* = CLSID
   PCLSID* = ptr CLSID
-  SERVICE_INFO* = record
+  SERVICE_INFO* {.final.} = object
     lpServiceType*: LPGUID
     lpServiceName*: LPTSTR
     lpComment*: LPTSTR
@@ -10473,13 +10473,13 @@ type
 
   TSERVICEINFO* = SERVICE_INFO
   PSERVICEINFO* = ptr SERVICE_INFO
-  NS_SERVICE_INFO* = record
+  NS_SERVICE_INFO* {.final.} = object
     dwNameSpace*: DWORD
     ServiceInfo*: SERVICE_INFO
 
   TNSSERVICEINFO* = NS_SERVICE_INFO
   PNSSERVICEINFO* = ptr NS_SERVICE_INFO
-  NUMBERFMT* = record
+  NUMBERFMT* {.final.} = object
     NumDigits*: UINT
     LeadingZero*: UINT
     Grouping*: UINT
@@ -10489,7 +10489,7 @@ type
 
   Tnumberfmt* = NUMBERFMT
   Pnumberfmt* = ptr NUMBERFMT
-  OFSTRUCT* = record
+  OFSTRUCT* {.final.} = object
     cBytes*: int8
     fFixedDisk*: int8
     nErrCode*: int16
@@ -10500,7 +10500,7 @@ type
   LPOFSTRUCT* = ptr OFSTRUCT
   TOFSTRUCT* = OFSTRUCT
   POFSTRUCT* = ptr OFSTRUCT
-  OPENFILENAME_NT4* = record
+  OPENFILENAME_NT4* {.final.} = object
     lStructSize*: DWORD
     hwndOwner*: HWND
     hInstance*: HINST
@@ -10525,7 +10525,7 @@ type
   LPOPENFILENAME_NT4* = ptr OPENFILENAME_NT4
   TOPENFILENAME_NT4* = OPENFILENAME_NT4
   POPENFILENAME_NT4* = ptr OPENFILENAME_NT4
-  TOPENFILENAME* = record
+  TOPENFILENAME* {.final.} = object
     lStructSize*: DWORD
     hwndOwner*: HWND
     hInstance*: HINST
@@ -10554,7 +10554,7 @@ type
   POPENFILENAME* = ptr TOPENFILENAME
   OFN* = TOPENFILENAME
   POFN* = ptr TOPENFILENAME
-  OFNOTIFY* = record
+  OFNOTIFY* {.final.} = object
     hdr*: NMHDR
     lpOFN*: LPOPENFILENAME
     pszFile*: LPTSTR
@@ -10562,7 +10562,7 @@ type
   LPOFNOTIFY* = ptr OFNOTIFY
   TOFNOTIFY* = OFNOTIFY
   POFNOTIFY* = ptr OFNOTIFY
-  OSVERSIONINFO* = record
+  OSVERSIONINFO* {.final.} = object
     dwOSVersionInfoSize*: DWORD
     dwMajorVersion*: DWORD
     dwMinorVersion*: DWORD
@@ -10573,7 +10573,7 @@ type
   LPOSVERSIONINFO* = ptr OSVERSIONINFO
   TOSVERSIONINFO* = OSVERSIONINFO
   POSVERSIONINFO* = ptr OSVERSIONINFO
-  OSVERSIONINFOW* = record
+  OSVERSIONINFOW* {.final.} = object
     dwOSVersionInfoSize*: DWORD
     dwMajorVersion*: DWORD
     dwMinorVersion*: DWORD
@@ -10584,7 +10584,7 @@ type
   LPOSVERSIONINFOW* = ptr OSVERSIONINFOW
   TOSVERSIONINFOW* = OSVERSIONINFOW
   POSVERSIONINFOW* = ptr OSVERSIONINFOW
-  TEXTMETRIC* = record
+  TEXTMETRIC* {.final.} = object
     tmHeight*: LONG
     tmAscent*: LONG
     tmDescent*: LONG
@@ -10610,7 +10610,7 @@ type
   tagTEXTMETRIC* = TEXTMETRIC
   TTEXTMETRIC* = TEXTMETRIC
   PTEXTMETRIC* = ptr TEXTMETRIC
-  TEXTMETRICW* = record
+  TEXTMETRICW* {.final.} = object
     tmHeight*: LONG
     tmAscent*: LONG
     tmDescent*: LONG
@@ -10636,7 +10636,7 @@ type
   tagTEXTMETRICW* = TEXTMETRICW
   TTEXTMETRICW* = TEXTMETRICW
   PTEXTMETRICW* = ptr TEXTMETRICW
-  OUTLINETEXTMETRIC* = record
+  OUTLINETEXTMETRIC* {.final.} = object
     otmSize*: UINT
     otmTextMetrics*: TEXTMETRIC
     otmFiller*: int8
@@ -10673,7 +10673,7 @@ type
   LPOUTLINETEXTMETRIC* = ptr OUTLINETEXTMETRIC
   TOUTLINETEXTMETRIC* = OUTLINETEXTMETRIC
   POUTLINETEXTMETRIC* = ptr OUTLINETEXTMETRIC
-  OVERLAPPED* = record
+  OVERLAPPED* {.final.} = object
     Internal*: DWORD
     InternalHigh*: DWORD
     Offset*: DWORD
@@ -10683,7 +10683,7 @@ type
   LPOVERLAPPED* = ptr OVERLAPPED
   TOVERLAPPED* = OVERLAPPED
   POVERLAPPED* = ptr OVERLAPPED #PAGESETUPDLG = record conflicts with function PageSetupDlg
-  TPAGESETUPDLG* = record
+  TPAGESETUPDLG* {.final.} = object
     lStructSize*: DWORD
     hwndOwner*: HWND
     hDevMode*: HGLOBAL
@@ -10704,7 +10704,7 @@ type
   tagPSD* = TPAGESETUPDLG
   TPSD* = TPAGESETUPDLG
   PPSD* = ptr TPAGESETUPDLG
-  PAINTSTRUCT* = record
+  PAINTSTRUCT* {.final.} = object
     hdc*: HDC
     fErase*: WINBOOL
     rcPaint*: RECT
@@ -10716,7 +10716,7 @@ type
   tagPAINTSTRUCT* = PAINTSTRUCT
   TPAINTSTRUCT* = PAINTSTRUCT
   PPAINTSTRUCT* = ptr PAINTSTRUCT
-  PARAFORMAT* = record
+  PARAFORMAT* {.final.} = object
     cbSize*: UINT
     dwMask*: DWORD
     wNumbering*: int16
@@ -10730,12 +10730,12 @@ type
 
   Tparaformat* = PARAFORMAT
   Pparaformat* = ptr PARAFORMAT
-  PERF_COUNTER_BLOCK* = record
+  PERF_COUNTER_BLOCK* {.final.} = object
     ByteLength*: DWORD
 
   TPERFCOUNTERBLOCK* = PERF_COUNTER_BLOCK
   PPERFCOUNTERBLOCK* = ptr PERF_COUNTER_BLOCK
-  PERF_COUNTER_DEFINITION* = record
+  PERF_COUNTER_DEFINITION* {.final.} = object
     ByteLength*: DWORD
     CounterNameTitleIndex*: DWORD
     CounterNameTitle*: LPWSTR
@@ -10749,7 +10749,7 @@ type
 
   TPERFCOUNTERDEFINITION* = PERF_COUNTER_DEFINITION
   PPERFCOUNTERDEFINITION* = ptr PERF_COUNTER_DEFINITION
-  PERF_DATA_BLOCK* = record
+  PERF_DATA_BLOCK* {.final.} = object
     Signature*: array[0..3, WCHAR]
     LittleEndian*: DWORD
     Version*: DWORD
@@ -10767,7 +10767,7 @@ type
 
   TPERFDATABLOCK* = PERF_DATA_BLOCK
   PPERFDATABLOCK* = ptr PERF_DATA_BLOCK
-  PERF_INSTANCE_DEFINITION* = record
+  PERF_INSTANCE_DEFINITION* {.final.} = object
     ByteLength*: DWORD
     ParentObjectTitleIndex*: DWORD
     ParentObjectInstance*: DWORD
@@ -10777,7 +10777,7 @@ type
 
   TPERFINSTANCEDEFINITION* = PERF_INSTANCE_DEFINITION
   PPERFINSTANCEDEFINITION* = PERF_INSTANCE_DEFINITION
-  PERF_OBJECT_TYPE* = record
+  PERF_OBJECT_TYPE* {.final.} = object
     TotalByteLength*: DWORD
     DefinitionLength*: DWORD
     HeaderLength*: DWORD
@@ -10795,7 +10795,7 @@ type
 
   TPERFOBJECTTYPE* = PERF_OBJECT_TYPE
   PPERFOBJECTTYPE* = ptr PERF_OBJECT_TYPE
-  POLYTEXT* = record
+  POLYTEXT* {.final.} = object
     x*: int32
     y*: int32
     n*: UINT
@@ -10806,12 +10806,12 @@ type
 
   TPOLYTEXT* = POLYTEXT
   PPOLYTEXT* = ptr POLYTEXT
-  PORT_INFO_1* = record
+  PORT_INFO_1* {.final.} = object
     pName*: LPTSTR
 
   TPORTINFO1* = PORT_INFO_1
   PPORTINFO1* = ptr PORT_INFO_1
-  PORT_INFO_2* = record
+  PORT_INFO_2* {.final.} = object
     pPortName*: LPSTR
     pMonitorName*: LPSTR
     pDescription*: LPSTR
@@ -10820,12 +10820,12 @@ type
 
   TPORTINFO2* = PORT_INFO_2
   PPORTINFO2* = ptr PORT_INFO_2
-  PREVENT_MEDIA_REMOVAL* = record
+  PREVENT_MEDIA_REMOVAL* {.final.} = object
     PreventMediaRemoval*: bool
 
   TPREVENTMEDIAREMOVAL* = PREVENT_MEDIA_REMOVAL
   PPREVENTMEDIAREMOVAL* = ptr PREVENT_MEDIA_REMOVAL #PRINTDLG = record conflicts with PrintDlg function
-  TPRINTDLG* = record
+  TPRINTDLG* {.final.} = object
     lStructSize*: DWORD
     hwndOwner*: HWND
     hDevMode*: HANDLE
@@ -10851,14 +10851,14 @@ type
   tagPD* = TPRINTDLG
   TPD* = TPRINTDLG
   PPD* = ptr TPRINTDLG
-  PRINTER_DEFAULTS* = record
+  PRINTER_DEFAULTS* {.final.} = object
     pDatatype*: LPTSTR
     pDevMode*: LPDEVMODE
     DesiredAccess*: ACCESS_MASK
 
   TPRINTERDEFAULTS* = PRINTER_DEFAULTS
   PPRINTERDEFAULTS* = ptr PRINTER_DEFAULTS
-  PRINTER_INFO_1* = record
+  PRINTER_INFO_1* {.final.} = object
     Flags*: DWORD
     pDescription*: LPTSTR
     pName*: LPTSTR
@@ -10867,7 +10867,7 @@ type
   LPPRINTER_INFO_1* = ptr PRINTER_INFO_1
   PPRINTER_INFO_1* = ptr PRINTER_INFO_1
   TPRINTERINFO1* = PRINTER_INFO_1
-  PRINTER_INFO_2* = record
+  PRINTER_INFO_2* {.final.} = object
     pServerName*: LPTSTR
     pPrinterName*: LPTSTR
     pShareName*: LPTSTR
@@ -10892,19 +10892,19 @@ type
 
   TPRINTERINFO2* = PRINTER_INFO_2
   PPRINTERINFO2* = ptr PRINTER_INFO_2
-  PRINTER_INFO_3* = record
+  PRINTER_INFO_3* {.final.} = object
     pSecurityDescriptor*: PSECURITY_DESCRIPTOR
 
   TPRINTERINFO3* = PRINTER_INFO_3
   PPRINTERINFO3* = ptr PRINTER_INFO_3
-  PRINTER_INFO_4* = record
+  PRINTER_INFO_4* {.final.} = object
     pPrinterName*: LPTSTR
     pServerName*: LPTSTR
     Attributes*: DWORD
 
   TPRINTERINFO4* = PRINTER_INFO_4
   PPRINTERINFO4* = ptr PRINTER_INFO_4
-  PRINTER_INFO_5* = record
+  PRINTER_INFO_5* {.final.} = object
     pPrinterName*: LPTSTR
     pPortName*: LPTSTR
     Attributes*: DWORD
@@ -10913,7 +10913,7 @@ type
 
   TPRINTERINFO5* = PRINTER_INFO_5
   PPRINTERINFO5* = ptr PRINTER_INFO_5
-  PRINTER_NOTIFY_INFO_DATA* = record
+  PRINTER_NOTIFY_INFO_DATA* {.final.} = object
     `type`*: int16
     Field*: int16
     Reserved*: DWORD
@@ -10923,7 +10923,7 @@ type
 
   TPRINTERNOTIFYINFODATA* = PRINTER_NOTIFY_INFO_DATA
   PPRINTERNOTIFYINFODATA* = ptr PRINTER_NOTIFY_INFO_DATA
-  PRINTER_NOTIFY_INFO* = record
+  PRINTER_NOTIFY_INFO* {.final.} = object
     Version*: DWORD
     Flags*: DWORD
     Count*: DWORD
@@ -10931,7 +10931,7 @@ type
 
   TPRINTERNOTIFYINFO* = PRINTER_NOTIFY_INFO
   PPRINTERNOTIFYINFO* = ptr PRINTER_NOTIFY_INFO
-  PRINTER_NOTIFY_OPTIONS_TYPE* = record
+  PRINTER_NOTIFY_OPTIONS_TYPE* {.final.} = object
     `type`*: int16
     Reserved0*: int16
     Reserved1*: DWORD
@@ -10941,7 +10941,7 @@ type
 
   PPRINTER_NOTIFY_OPTIONS_TYPE* = ptr PRINTER_NOTIFY_OPTIONS_TYPE
   TPRINTERNOTIFYOPTIONSTYPE* = PRINTER_NOTIFY_OPTIONS_TYPE
-  PRINTER_NOTIFY_OPTIONS* = record
+  PRINTER_NOTIFY_OPTIONS* {.final.} = object
     Version*: DWORD
     Flags*: DWORD
     Count*: DWORD
@@ -10949,12 +10949,12 @@ type
 
   TPRINTERNOTIFYOPTIONS* = PRINTER_NOTIFY_OPTIONS
   PPRINTERNOTIFYOPTIONS* = ptr PRINTER_NOTIFY_OPTIONS
-  PRINTPROCESSOR_INFO_1* = record
+  PRINTPROCESSOR_INFO_1* {.final.} = object
     pName*: LPTSTR
 
   TPRINTPROCESSORINFO1* = PRINTPROCESSOR_INFO_1
   PPRINTPROCESSORINFO1* = ptr PRINTPROCESSOR_INFO_1
-  PRIVILEGE_SET* = record
+  PRIVILEGE_SET* {.final.} = object
     PrivilegeCount*: DWORD
     Control*: DWORD
     Privilege*: array[0..(ANYSIZE_ARRAY) - 1, LUID_AND_ATTRIBUTES]
@@ -10962,7 +10962,7 @@ type
   LPPRIVILEGE_SET* = ptr PRIVILEGE_SET
   PPRIVILEGE_SET* = ptr PRIVILEGE_SET
   TPRIVILEGESET* = PRIVILEGE_SET
-  PROCESS_HEAPENTRY* = record
+  PROCESS_HEAPENTRY* {.final.} = object
     lpData*: PVOID
     cbData*: DWORD
     cbOverhead*: int8
@@ -10977,7 +10977,7 @@ type
   LPPROCESS_HEAP_ENTRY* = ptr PROCESS_HEAPENTRY
   TPROCESSHEAPENTRY* = PROCESS_HEAPENTRY
   PPROCESSHEAPENTRY* = ptr PROCESS_HEAPENTRY
-  PROCESS_INFORMATION* = record
+  PROCESS_INFORMATION* {.final.} = object
     hProcess*: HANDLE
     hThread*: HANDLE
     dwProcessId*: DWORD
@@ -10989,7 +10989,7 @@ type
   LPFNPSPCALLBACK* = proc (para1: HWND, para2: UINT, para3: LPVOID): UINT{.
       stdcall.}
   TFNPSPCALLBACK* = LPFNPSPCALLBACK
-  PROPSHEETPAGE* = record
+  PROPSHEETPAGE* {.final.} = object
     dwSize*: DWORD
     dwFlags*: DWORD
     hInstance*: HINST
@@ -11004,10 +11004,10 @@ type
   LPCPROPSHEETPAGE* = ptr PROPSHEETPAGE
   TPROPSHEETPAGE* = PROPSHEETPAGE
   PPROPSHEETPAGE* = ptr PROPSHEETPAGE
-  emptyrecord* = record
+  emptyrecord* {.final.} = object
   lpemptyrecord* = ptr emptyrecord
   HPROPSHEETPAGE* = ptr emptyrecord
-  PROPSHEETHEADER* = record
+  PROPSHEETHEADER* {.final.} = object
     dwSize*: DWORD
     dwFlags*: DWORD
     hwndParent*: HWND
@@ -11032,7 +11032,7 @@ type
   LPFNADDPROPSHEETPAGES* = proc (para1: LPVOID, para2: LPFNADDPROPSHEETPAGE,
                                  para3: LPARAM): WINBOOL{.stdcall.}
   TFNADDPROPSHEETPAGES* = LPFNADDPROPSHEETPAGES
-  PROTOCOL_INFO* = record
+  PROTOCOL_INFO* {.final.} = object
     dwServiceFlags*: DWORD
     iAddressFamily*: WINT
     iMaxSockAddr*: WINT
@@ -11044,27 +11044,27 @@ type
 
   TPROTOCOLINFO* = PROTOCOL_INFO
   PPROTOCOLINFO* = ptr PROTOCOL_INFO
-  PROVIDOR_INFO_1* = record
+  PROVIDOR_INFO_1* {.final.} = object
     pName*: LPTSTR
     pEnvironment*: LPTSTR
     pDLLName*: LPTSTR
 
   TPROVIDORINFO1* = PROVIDOR_INFO_1
   PPROVIDORINFO1* = ptr PROVIDOR_INFO_1
-  PSHNOTIFY* = record
+  PSHNOTIFY* {.final.} = object
     hdr*: NMHDR
     lParam*: LPARAM
 
   LPPSHNOTIFY* = ptr PSHNOTIFY
   TPSHNOTIFY* = PSHNOTIFY
   PPSHNOTIFY* = ptr PSHNOTIFY
-  PUNCTUATION* = record
+  PUNCTUATION* {.final.} = object
     iSize*: UINT
     szPunctuation*: LPSTR
 
   Tpunctuation* = PUNCTUATION
   Ppunctuation* = ptr PUNCTUATION
-  TQUERY_SERVICE_CONFIG* = record
+  TQUERY_SERVICE_CONFIG* {.final.} = object
     dwServiceType*: DWORD
     dwStartType*: DWORD
     dwErrorControl*: DWORD
@@ -11077,14 +11077,14 @@ type
 
   LPQUERY_SERVICE_CONFIG* = ptr TQUERY_SERVICE_CONFIG
   PQUERYSERVICECONFIG* = ptr TQUERY_SERVICE_CONFIG
-  TQUERY_SERVICE_LOCK_STATUS* = record
+  TQUERY_SERVICE_LOCK_STATUS* {.final.} = object
     fIsLocked*: DWORD
     lpLockOwner*: LPTSTR
     dwLockDuration*: DWORD
 
   LPQUERY_SERVICE_LOCK_STATUS* = ptr TQUERY_SERVICE_LOCK_STATUS
   PQUERYSERVICELOCKSTATUS* = ptr TQUERY_SERVICE_LOCK_STATUS
-  RASAMB* = record
+  RASAMB* {.final.} = object
     dwSize*: DWORD
     dwError*: DWORD
     szNetBiosError*: array[0..(NETBIOS_NAME_LEN + 1) - 1, TCHAR]
@@ -11092,7 +11092,7 @@ type
 
   TRASAMB* = RASAMB
   PRASAMB* = ptr RASAMB
-  RASCONN* = record
+  RASCONN* {.final.} = object
     dwSize*: DWORD
     hrasconn*: HRASCONN
     szEntryName*: array[0..(RAS_MaxEntryName + 1) - 1, TCHAR]
@@ -11101,7 +11101,7 @@ type
 
   TRASCONN* = RASCONN
   PRASCONN* = ptr RASCONN
-  RASCONNSTATUS* = record
+  RASCONNSTATUS* {.final.} = object
     dwSize*: DWORD
     rasconnstate*: RASCONNSTATE
     dwError*: DWORD
@@ -11110,7 +11110,7 @@ type
 
   TRASCONNSTATUS* = RASCONNSTATUS
   PRASCONNSTATUS* = ptr RASCONNSTATUS
-  RASDIALEXTENSIONS* = record
+  RASDIALEXTENSIONS* {.final.} = object
     dwSize*: DWORD
     dwfOptions*: DWORD
     hwndParent*: HWND
@@ -11118,7 +11118,7 @@ type
 
   TRASDIALEXTENSIONS* = RASDIALEXTENSIONS
   PRASDIALEXTENSIONS* = ptr RASDIALEXTENSIONS
-  RASDIALPARAMS* = record
+  RASDIALPARAMS* {.final.} = object
     dwSize*: DWORD
     szEntryName*: array[0..(RAS_MaxEntryName + 1) - 1, TCHAR]
     szPhoneNumber*: array[0..(RAS_MaxPhoneNumber + 1) - 1, TCHAR]
@@ -11129,27 +11129,27 @@ type
 
   TRASDIALPARAMS* = RASDIALPARAMS
   PRASDIALPARAMS* = ptr RASDIALPARAMS
-  RASENTRYNAME* = record
+  RASENTRYNAME* {.final.} = object
     dwSize*: DWORD
     szEntryName*: array[0..(RAS_MaxEntryName + 1) - 1, TCHAR]
 
   TRASENTRYNAME* = RASENTRYNAME
   PRASENTRYNAME* = ptr RASENTRYNAME
-  RASPPPIP* = record
+  RASPPPIP* {.final.} = object
     dwSize*: DWORD
     dwError*: DWORD
     szIpAddress*: array[0..(RAS_MaxIpAddress + 1) - 1, TCHAR]
 
   TRASPPPIP* = RASPPPIP
   PRASPPPIP* = ptr RASPPPIP
-  RASPPPIPX* = record
+  RASPPPIPX* {.final.} = object
     dwSize*: DWORD
     dwError*: DWORD
     szIpxAddress*: array[0..(RAS_MaxIpxAddress + 1) - 1, TCHAR]
 
   TRASPPPIPX* = RASPPPIPX
   PRASPPPIPX* = ptr RASPPPIPX
-  RASPPPNBF* = record
+  RASPPPNBF* {.final.} = object
     dwSize*: DWORD
     dwError*: DWORD
     dwNetBiosError*: DWORD
@@ -11159,7 +11159,7 @@ type
 
   TRASPPPNBF* = RASPPPNBF
   PRASPPPNBF* = ptr RASPPPNBF
-  RASTERIZER_STATUS* = record
+  RASTERIZER_STATUS* {.final.} = object
     nSize*: short
     wFlags*: short
     nLanguageID*: short
@@ -11167,14 +11167,14 @@ type
   LPRASTERIZER_STATUS* = ptr RASTERIZER_STATUS
   TRASTERIZERSTATUS* = RASTERIZER_STATUS
   PRASTERIZERSTATUS* = ptr RASTERIZER_STATUS
-  REASSIGN_BLOCKS* = record
+  REASSIGN_BLOCKS* {.final.} = object
     Reserved*: int16
     Count*: int16
     BlockNumber*: array[0..0, DWORD]
 
   TREASSIGNBLOCKS* = REASSIGN_BLOCKS
   PREASSIGNBLOCKS* = ptr REASSIGN_BLOCKS
-  REMOTE_NAME_INFO* = record
+  REMOTE_NAME_INFO* {.final.} = object
     lpUniversalName*: LPTSTR
     lpConnectionName*: LPTSTR
     lpRemainingPath*: LPTSTR
@@ -11195,19 +11195,19 @@ type
                                           #    DWORD  dwUser;
                                           #  } REOBJECT;
                                           #
-  REPASTESPECIAL* = record
+  REPASTESPECIAL* {.final.} = object
     dwAspect*: DWORD
     dwParam*: DWORD
 
   Trepastespecial* = REPASTESPECIAL
   Prepastespecial* = ptr REPASTESPECIAL
-  REQRESIZE* = record
+  REQRESIZE* {.final.} = object
     nmhdr*: NMHDR
     rc*: RECT
 
   Treqresize* = REQRESIZE
   Preqresize* = ptr REQRESIZE
-  RGNDATAHEADER* = record
+  RGNDATAHEADER* {.final.} = object
     dwSize*: DWORD
     iType*: DWORD
     nCount*: DWORD
@@ -11216,14 +11216,14 @@ type
 
   TRGNDATAHEADER* = RGNDATAHEADER
   PRGNDATAHEADER* = ptr RGNDATAHEADER
-  RGNDATA* = record
+  RGNDATA* {.final.} = object
     rdh*: RGNDATAHEADER
     Buffer*: array[0..0, char]
 
   LPRGNDATA* = ptr RGNDATA
   TRGNDATA* = RGNDATA
   PRGNDATA* = ptr RGNDATA
-  SCROLLINFO* = record
+  SCROLLINFO* {.final.} = object
     cbSize*: UINT
     fMask*: UINT
     nMin*: int32
@@ -11236,7 +11236,7 @@ type
   LPCSCROLLINFO* = ptr SCROLLINFO
   TSCROLLINFO* = SCROLLINFO
   PSCROLLINFO* = ptr SCROLLINFO
-  SECURITY_ATTRIBUTES* = record
+  SECURITY_ATTRIBUTES* {.final.} = object
     nLength*: DWORD
     lpSecurityDescriptor*: LPVOID
     bInheritHandle*: WINBOOL
@@ -11247,14 +11247,14 @@ type
   SECURITY_INFORMATION* = DWORD
   PSECURITY_INFORMATION* = ptr SECURITY_INFORMATION
   TSECURITYINFORMATION* = SECURITY_INFORMATION
-  SELCHANGE* = record
+  SELCHANGE* {.final.} = object
     nmhdr*: NMHDR
     chrg*: CHARRANGE
     seltyp*: int16
 
   Tselchange* = SELCHANGE
   Pselchange* = ptr SELCHANGE
-  SERIALKEYS* = record
+  SERIALKEYS* {.final.} = object
     cbSize*: DWORD
     dwFlags*: DWORD
     lpszActivePort*: LPSTR
@@ -11265,14 +11265,14 @@ type
   LPSERIALKEYS* = ptr SERIALKEYS
   TSERIALKEYS* = SERIALKEYS
   PSERIALKEYS* = ptr SERIALKEYS
-  SERVICE_TABLE_ENTRY* = record
+  SERVICE_TABLE_ENTRY* {.final.} = object
     lpServiceName*: LPTSTR
     lpServiceProc*: LPSERVICE_MAIN_FUNCTION
 
   LPSERVICE_TABLE_ENTRY* = ptr SERVICE_TABLE_ENTRY
   TSERVICETABLEENTRY* = SERVICE_TABLE_ENTRY
   PSERVICETABLEENTRY* = ptr SERVICE_TABLE_ENTRY
-  SERVICE_TYPE_VALUE_ABS* = record
+  SERVICE_TYPE_VALUE_ABS* {.final.} = object
     dwNameSpace*: DWORD
     dwValueType*: DWORD
     dwValueSize*: DWORD
@@ -11281,14 +11281,14 @@ type
 
   TSERVICETYPEVALUEABS* = SERVICE_TYPE_VALUE_ABS
   PSERVICETYPEVALUEABS* = ptr SERVICE_TYPE_VALUE_ABS
-  SERVICE_TYPE_INFO_ABS* = record
+  SERVICE_TYPE_INFO_ABS* {.final.} = object
     lpTypeName*: LPTSTR
     dwValueCount*: DWORD
     Values*: array[0..0, SERVICE_TYPE_VALUE_ABS]
 
   TSERVICETYPEINFOABS* = SERVICE_TYPE_INFO_ABS
   PSERVICETYPEINFOABS* = ptr SERVICE_TYPE_INFO_ABS
-  SESSION_BUFFER* = record
+  SESSION_BUFFER* {.final.} = object
     lsn*: UCHAR
     state*: UCHAR
     local_name*: array[0..(NCBNAMSZ) - 1, UCHAR]
@@ -11298,7 +11298,7 @@ type
 
   TSESSIONBUFFER* = SESSION_BUFFER
   PSESSIONBUFFER* = ptr SESSION_BUFFER
-  SESSION_HEADER* = record
+  SESSION_HEADER* {.final.} = object
     sess_name*: UCHAR
     num_sess*: UCHAR
     rcv_dg_outstanding*: UCHAR
@@ -11306,7 +11306,7 @@ type
 
   TSESSIONHEADER* = SESSION_HEADER
   PSESSIONHEADER* = ptr SESSION_HEADER
-  SET_PARTITION_INFORMATION* = record
+  SET_PARTITION_INFORMATION* {.final.} = object
     PartitionType*: int8
 
   TSETPARTITIONINFORMATION* = SET_PARTITION_INFORMATION
@@ -11314,7 +11314,7 @@ type
   SHCONTF* = enum
     SHCONTF_FOLDERS = 32, SHCONTF_NONFOLDERS = 64, SHCONTF_INCLUDEHIDDEN = 128
   TSHCONTF* = SHCONTF
-  SHFILEINFO* = record
+  SHFILEINFO* {.final.} = object
     hIcon*: HICON
     iIcon*: int32
     dwAttributes*: DWORD
@@ -11326,7 +11326,7 @@ type
   FILEOP_FLAGS* = int16
   TFILEOPFLAGS* = FILEOP_FLAGS
   PFILEOPFLAGS* = ptr FILEOP_FLAGS
-  SHFILEOPSTRUCT* = record
+  SHFILEOPSTRUCT* {.final.} = object
     hwnd*: HWND
     wFunc*: UINT
     pFrom*: LPCSTR
@@ -11343,7 +11343,7 @@ type
     SHGDN_NORMAL = 0, SHGDN_INFOLDER = 1, SHGDN_FORPARSING = 0x00008000
   tagSHGDN* = SHGNO
   TSHGDN* = SHGNO
-  SHNAMEMAPPING* = record
+  SHNAMEMAPPING* {.final.} = object
     pszOldPath*: LPSTR
     pszNewPath*: LPSTR
     cchOldPath*: int32
@@ -11352,7 +11352,7 @@ type
   LPSHNAMEMAPPING* = ptr SHNAMEMAPPING
   TSHNAMEMAPPING* = SHNAMEMAPPING
   PSHNAMEMAPPING* = ptr SHNAMEMAPPING
-  SID_AND_ATTRIBUTES* = record
+  SID_AND_ATTRIBUTES* {.final.} = object
     Sid*: PSID
     Attributes*: DWORD
 
@@ -11361,12 +11361,12 @@ type
   SID_AND_ATTRIBUTES_ARRAY* = array[0..(ANYSIZE_ARRAY) - 1, SID_AND_ATTRIBUTES]
   PSID_AND_ATTRIBUTES_ARRAY* = ptr SID_AND_ATTRIBUTES_ARRAY
   TSIDANDATTRIBUTESARRAY* = SID_AND_ATTRIBUTES_ARRAY
-  SINGLE_LIST_ENTRY* = record
+  SINGLE_LIST_ENTRY* {.final.} = object
     Next*: ptr SINGLE_LIST_ENTRY
 
   TSINGLELISTENTRY* = SINGLE_LIST_ENTRY
   PSINGLELISTENTRY* = ptr SINGLE_LIST_ENTRY
-  SOUNDSENTRY* = record
+  SOUNDSENTRY* {.final.} = object
     cbSize*: UINT
     dwFlags*: DWORD
     iFSTextEffect*: DWORD
@@ -11384,7 +11384,7 @@ type
   tagSOUNDSENTRY* = SOUNDSENTRY
   TSOUNDSENTRY* = SOUNDSENTRY
   PSOUNDSENTRY* = ptr SOUNDSENTRY
-  STARTUPINFO* = record
+  STARTUPINFO* {.final.} = object
     cb*: DWORD
     lpReserved*: LPTSTR
     lpDesktop*: LPTSTR
@@ -11407,42 +11407,42 @@ type
   LPSTARTUPINFO* = ptr STARTUPINFO
   TSTARTUPINFO* = STARTUPINFO
   PSTARTUPINFO* = ptr STARTUPINFO
-  STICKYKEYS* = record
+  STICKYKEYS* {.final.} = object
     cbSize*: DWORD
     dwFlags*: DWORD
 
   LPSTICKYKEYS* = ptr STICKYKEYS
   TSTICKYKEYS* = STICKYKEYS
   PSTICKYKEYS* = ptr STICKYKEYS
-  STRRET* = record
+  STRRET* {.final.} = object
     uType*: UINT
     cStr*: array[0..(MAX_PATH) - 1, char]
 
   LPSTRRET* = ptr STRRET
   TSTRRET* = STRRET
   PSTRRET* = ptr STRRET
-  STYLEBUF* = record
+  STYLEBUF* {.final.} = object
     dwStyle*: DWORD
     szDescription*: array[0..31, CHAR]
 
   LPSTYLEBUF* = ptr STYLEBUF
   TSTYLEBUF* = STYLEBUF
   PSTYLEBUF* = ptr STYLEBUF
-  STYLESTRUCT* = record
+  STYLESTRUCT* {.final.} = object
     styleOld*: DWORD
     styleNew*: DWORD
 
   LPSTYLESTRUCT* = ptr STYLESTRUCT
   TSTYLESTRUCT* = STYLESTRUCT
   PSTYLESTRUCT* = ptr STYLESTRUCT
-  SYSTEM_AUDIT_ACE* = record
+  SYSTEM_AUDIT_ACE* {.final.} = object
     Header*: ACE_HEADER
     Mask*: ACCESS_MASK
     SidStart*: DWORD
 
   TSYSTEMAUDITACE* = SYSTEM_AUDIT_ACE
   PSYSTEMAUDITACE* = ptr SYSTEM_AUDIT_ACE
-  SYSTEM_INFO* = record
+  SYSTEM_INFO* {.final.} = object
     dwOemId*: DWORD
     dwPageSize*: DWORD
     lpMinimumApplicationAddress*: LPVOID
@@ -11457,7 +11457,7 @@ type
   LPSYSTEM_INFO* = ptr SYSTEM_INFO
   TSYSTEMINFO* = SYSTEM_INFO
   PSYSTEMINFO* = ptr SYSTEM_INFO
-  SYSTEM_POWER_STATUS* = record
+  SYSTEM_POWER_STATUS* {.final.} = object
     ACLineStatus*: int8
     BatteryFlag*: int8
     BatteryLifePercent*: int8
@@ -11468,12 +11468,12 @@ type
   TSYSTEMPOWERSTATUS* = SYSTEM_POWER_STATUS
   PSYSTEMPOWERSTATUS* = ptr SYSTEM_POWER_STATUS
   LPSYSTEM_POWER_STATUS* = ptr emptyrecord
-  TAPE_ERASE* = record
+  TAPE_ERASE* {.final.} = object
     `type`*: ULONG
 
   TTAPEERASE* = TAPE_ERASE
   PTAPEERASE* = ptr TAPE_ERASE
-  TAPE_GET_DRIVE_PARAMETERS* = record
+  TAPE_GET_DRIVE_PARAMETERS* {.final.} = object
     ECC*: bool
     Compression*: bool
     DataPadding*: bool
@@ -11488,7 +11488,7 @@ type
 
   TTAPEGETDRIVEPARAMETERS* = TAPE_GET_DRIVE_PARAMETERS
   PTAPEGETDRIVEPARAMETERS* = ptr TAPE_GET_DRIVE_PARAMETERS
-  TAPE_GET_MEDIA_PARAMETERS* = record
+  TAPE_GET_MEDIA_PARAMETERS* {.final.} = object
     Capacity*: LARGE_INTEGER
     Remaining*: LARGE_INTEGER
     BlockSize*: DWORD
@@ -11497,7 +11497,7 @@ type
 
   TTAPEGETMEDIAPARAMETERS* = TAPE_GET_MEDIA_PARAMETERS
   PTAPEGETMEDIAPARAMETERS* = ptr TAPE_GET_MEDIA_PARAMETERS
-  TAPE_GET_POSITION* = record
+  TAPE_GET_POSITION* {.final.} = object
     `type`*: ULONG
     Partition*: ULONG
     OffsetLow*: ULONG
@@ -11505,12 +11505,12 @@ type
 
   TTAPEGETPOSITION* = TAPE_GET_POSITION
   PTAPEGETPOSITION* = ptr TAPE_GET_POSITION
-  TAPE_PREPARE* = record
+  TAPE_PREPARE* {.final.} = object
     Operation*: ULONG
 
   TTAPEPREPARE* = TAPE_PREPARE
   PTAPEPREPARE* = ptr TAPE_PREPARE
-  TAPE_SET_DRIVE_PARAMETERS* = record
+  TAPE_SET_DRIVE_PARAMETERS* {.final.} = object
     ECC*: bool
     Compression*: bool
     DataPadding*: bool
@@ -11519,12 +11519,12 @@ type
 
   TTAPESETDRIVEPARAMETERS* = TAPE_SET_DRIVE_PARAMETERS
   PTAPESETDRIVEPARAMETERS* = ptr TAPE_SET_DRIVE_PARAMETERS
-  TAPE_SET_MEDIA_PARAMETERS* = record
+  TAPE_SET_MEDIA_PARAMETERS* {.final.} = object
     BlockSize*: ULONG
 
   TTAPESETMEDIAPARAMETERS* = TAPE_SET_MEDIA_PARAMETERS
   PTAPESETMEDIAPARAMETERS* = ptr TAPE_SET_MEDIA_PARAMETERS
-  TAPE_SET_POSITION* = record
+  TAPE_SET_POSITION* {.final.} = object
     `Method`*: ULONG
     Partition*: ULONG
     OffsetLow*: ULONG
@@ -11532,19 +11532,19 @@ type
 
   TTAPESETPOSITION* = TAPE_SET_POSITION
   PTAPESETPOSITION* = ptr TAPE_SET_POSITION
-  TAPE_WRITE_MARKS* = record
+  TAPE_WRITE_MARKS* {.final.} = object
     `type`*: ULONG
     Count*: ULONG
 
   TTAPEWRITEMARKS* = TAPE_WRITE_MARKS
   PTAPEWRITEMARKS* = ptr TAPE_WRITE_MARKS
-  TTBADDBITMAP* = record
+  TTBADDBITMAP* {.final.} = object
     hInst*: HINST
     nID*: UINT
 
   LPTBADDBITMAP* = ptr TTBADDBITMAP
   PTBADDBITMAP* = ptr TTBADDBITMAP
-  TBBUTTON* = record
+  TBBUTTON* {.final.} = object
     iBitmap*: int32
     idCommand*: int32
     fsState*: int8
@@ -11556,7 +11556,7 @@ type
   LPCTBBUTTON* = ptr TBBUTTON
   TTBBUTTON* = TBBUTTON
   PTBBUTTON* = ptr TBBUTTON
-  TBNOTIFY* = record
+  TBNOTIFY* {.final.} = object
     hdr*: NMHDR
     iItem*: int32
     tbButton*: TBBUTTON
@@ -11566,20 +11566,20 @@ type
   LPTBNOTIFY* = ptr TBNOTIFY
   TTBNOTIFY* = TBNOTIFY
   PTBNOTIFY* = ptr TBNOTIFY
-  TBSAVEPARAMS* = record
+  TBSAVEPARAMS* {.final.} = object
     hkr*: HKEY
     pszSubKey*: LPCTSTR
     pszValueName*: LPCTSTR
 
   TTBSAVEPARAMS* = TBSAVEPARAMS
   PTBSAVEPARAMS* = ptr TBSAVEPARAMS
-  TC_HITTESTINFO* = record
+  TC_HITTESTINFO* {.final.} = object
     pt*: POINT
     flags*: UINT
 
   TTCHITTESTINFO* = TC_HITTESTINFO
   PTCHITTESTINFO* = ptr TC_HITTESTINFO
-  TC_ITEM* = record
+  TC_ITEM* {.final.} = object
     mask*: UINT
     lpReserved1*: UINT
     lpReserved2*: UINT
@@ -11590,7 +11590,7 @@ type
 
   TTCITEM* = TC_ITEM
   PTCITEM* = ptr TC_ITEM
-  TC_ITEMHEADER* = record
+  TC_ITEMHEADER* {.final.} = object
     mask*: UINT
     lpReserved1*: UINT
     lpReserved2*: UINT
@@ -11600,20 +11600,20 @@ type
 
   TTCITEMHEADER* = TC_ITEMHEADER
   PTCITEMHEADER* = ptr TC_ITEMHEADER
-  TC_KEYDOWN* = record
+  TC_KEYDOWN* {.final.} = object
     hdr*: NMHDR
     wVKey*: int16
     flags*: UINT
 
   TTCKEYDOWN* = TC_KEYDOWN
   PTCKEYDOWN* = ptr TC_KEYDOWN
-  TEXTRANGE* = record
+  TEXTRANGE* {.final.} = object
     chrg*: CHARRANGE
     lpstrText*: LPSTR
 
   Ttextrange* = TEXTRANGE
   Ptextrange* = ptr TEXTRANGE
-  TIME_ZONE_INFORMATION* = record
+  TIME_ZONE_INFORMATION* {.final.} = object
     Bias*: LONG
     StandardName*: array[0..31, WCHAR]
     StandardDate*: SYSTEMTIME
@@ -11625,18 +11625,18 @@ type
   LPTIME_ZONE_INFORMATION* = ptr TIME_ZONE_INFORMATION
   TTIMEZONEINFORMATION* = TIME_ZONE_INFORMATION
   PTIMEZONEINFORMATION* = ptr TIME_ZONE_INFORMATION
-  TOGGLEKEYS* = record
+  TOGGLEKEYS* {.final.} = object
     cbSize*: DWORD
     dwFlags*: DWORD
 
   TTOGGLEKEYS* = TOGGLEKEYS
   PTOGGLEKEYS* = ptr TOGGLEKEYS
-  TTOKEN_SOURCE* = record
+  TTOKEN_SOURCE* {.final.} = object
     SourceName*: array[0..7, CHAR]
     SourceIdentifier*: LUID
 
   PTOKENSOURCE* = ptr TTOKEN_SOURCE
-  TOKEN_CONTROL* = record
+  TOKEN_CONTROL* {.final.} = object
     TokenId*: LUID
     AuthenticationId*: LUID
     ModifiedId*: LUID
@@ -11644,31 +11644,31 @@ type
 
   TTOKENCONTROL* = TOKEN_CONTROL
   PTOKENCONTROL* = ptr TOKEN_CONTROL
-  TTOKEN_DEFAULT_DACL* = record
+  TTOKEN_DEFAULT_DACL* {.final.} = object
     DefaultDacl*: PACL
 
   PTOKENDEFAULTDACL* = ptr TTOKEN_DEFAULT_DACL
-  TTOKEN_GROUPS* = record
+  TTOKEN_GROUPS* {.final.} = object
     GroupCount*: DWORD
     Groups*: array[0..(ANYSIZE_ARRAY) - 1, SID_AND_ATTRIBUTES]
 
   LPTOKEN_GROUPS* = ptr TTOKEN_GROUPS
   PTOKENGROUPS* = ptr TTOKEN_GROUPS
-  TTOKEN_OWNER* = record
+  TTOKEN_OWNER* {.final.} = object
     Owner*: PSID
 
   PTOKENOWNER* = ptr TTOKEN_OWNER
-  TTOKEN_PRIMARY_GROUP* = record
+  TTOKEN_PRIMARY_GROUP* {.final.} = object
     PrimaryGroup*: PSID
 
   PTOKENPRIMARYGROUP* = ptr TTOKEN_PRIMARY_GROUP
-  TTOKEN_PRIVILEGES* = record
+  TTOKEN_PRIVILEGES* {.final.} = object
     PrivilegeCount*: DWORD
     Privileges*: array[0..(ANYSIZE_ARRAY) - 1, LUID_AND_ATTRIBUTES]
 
   PTOKEN_PRIVILEGES* = ptr TTOKEN_PRIVILEGES
   LPTOKEN_PRIVILEGES* = ptr TTOKEN_PRIVILEGES
-  TTOKEN_STATISTICS* = record
+  TTOKEN_STATISTICS* {.final.} = object
     TokenId*: LUID
     AuthenticationId*: LUID
     ExpirationTime*: LARGE_INTEGER
@@ -11681,11 +11681,11 @@ type
     ModifiedId*: LUID
 
   PTOKENSTATISTICS* = ptr TTOKEN_STATISTICS
-  TTOKEN_USER* = record
+  TTOKEN_USER* {.final.} = object
     User*: SID_AND_ATTRIBUTES
 
   PTOKENUSER* = ptr TTOKEN_USER
-  TOOLINFO* = record
+  TOOLINFO* {.final.} = object
     cbSize*: UINT
     uFlags*: UINT
     hwnd*: HWND
@@ -11697,7 +11697,7 @@ type
   LPTOOLINFO* = ptr TOOLINFO
   TTOOLINFO* = TOOLINFO
   PTOOLINFO* = ptr TOOLINFO
-  TOOLTIPTEXT* = record
+  TOOLTIPTEXT* {.final.} = object
     hdr*: NMHDR
     lpszText*: LPTSTR
     szText*: array[0..79, char]
@@ -11707,7 +11707,7 @@ type
   LPTOOLTIPTEXT* = ptr TOOLTIPTEXT
   TTOOLTIPTEXT* = TOOLTIPTEXT
   PTOOLTIPTEXT* = ptr TOOLTIPTEXT
-  TPMPARAMS* = record
+  TPMPARAMS* {.final.} = object
     cbSize*: UINT
     rcExclude*: RECT
 
@@ -11715,7 +11715,7 @@ type
   tagTPMPARAMS* = TPMPARAMS
   TTPMPARAMS* = TPMPARAMS
   PTPMPARAMS* = ptr TPMPARAMS
-  TRANSMIT_FILE_BUFFERS* = record
+  TRANSMIT_FILE_BUFFERS* {.final.} = object
     Head*: PVOID
     HeadLength*: DWORD
     Tail*: PVOID
@@ -11723,7 +11723,7 @@ type
 
   TTRANSMITFILEBUFFERS* = TRANSMIT_FILE_BUFFERS
   PTRANSMITFILEBUFFERS* = ptr TRANSMIT_FILE_BUFFERS
-  TTHITTESTINFO* = record
+  TTHITTESTINFO* {.final.} = object
     hwnd*: HWND
     pt*: POINT
     ti*: TOOLINFO
@@ -11731,7 +11731,7 @@ type
   LPHITTESTINFO* = ptr TTHITTESTINFO
   TTTHITTESTINFO* = TTHITTESTINFO
   PTTHITTESTINFO* = ptr TTHITTESTINFO
-  TTPOLYCURVE* = record
+  TTPOLYCURVE* {.final.} = object
     wType*: int16
     cpfx*: int16
     apfx*: array[0..0, POINTFX]
@@ -11739,7 +11739,7 @@ type
   LPTTPOLYCURVE* = ptr TTPOLYCURVE
   TTTPOLYCURVE* = TTPOLYCURVE
   PTTPOLYCURVE* = ptr TTPOLYCURVE
-  TTPOLYGONHEADER* = record
+  TTPOLYGONHEADER* {.final.} = object
     cb*: DWORD
     dwType*: DWORD
     pfxStart*: POINTFX
@@ -11747,13 +11747,13 @@ type
   LPTTPOLYGONHEADER* = ptr TTPOLYGONHEADER
   TTTPOLYGONHEADER* = TTPOLYGONHEADER
   PTTPOLYGONHEADER* = ptr TTPOLYGONHEADER
-  TV_DISPINFO* = record
+  TV_DISPINFO* {.final.} = object
     hdr*: NMHDR
     item*: TV_ITEM
 
   TTVDISPINFO* = TV_DISPINFO
   PTVDISPINFO* = ptr TV_DISPINFO
-  TV_HITTESTINFO* = record
+  TV_HITTESTINFO* {.final.} = object
     pt*: POINT
     flags*: UINT
     hItem*: HTREEITEM
@@ -11761,7 +11761,7 @@ type
   LPTV_HITTESTINFO* = ptr TV_HITTESTINFO
   TTVHITTESTINFO* = TV_HITTESTINFO
   PTVHITTESTINFO* = ptr TV_HITTESTINFO
-  TV_INSERTSTRUCT* = record
+  TV_INSERTSTRUCT* {.final.} = object
     hParent*: HTREEITEM
     hInsertAfter*: HTREEITEM
     item*: TV_ITEM
@@ -11769,14 +11769,14 @@ type
   LPTV_INSERTSTRUCT* = ptr TV_INSERTSTRUCT
   TTVINSERTSTRUCT* = TV_INSERTSTRUCT
   PTVINSERTSTRUCT* = ptr TV_INSERTSTRUCT
-  TV_KEYDOWN* = record
+  TV_KEYDOWN* {.final.} = object
     hdr*: NMHDR
     wVKey*: int16
     flags*: UINT
 
   TTVKEYDOWN* = TV_KEYDOWN
   PTVKEYDOWN* = ptr TV_KEYDOWN
-  TV_SORTCB* = record
+  TV_SORTCB* {.final.} = object
     hParent*: HTREEITEM
     lpfnCompare*: PFNTVCOMPARE
     lParam*: LPARAM
@@ -11784,18 +11784,18 @@ type
   LPTV_SORTCB* = ptr TV_SORTCB
   TTVSORTCB* = TV_SORTCB
   PTVSORTCB* = ptr TV_SORTCB
-  UDACCEL* = record
+  UDACCEL* {.final.} = object
     nSec*: UINT
     nInc*: UINT
 
   TUDACCEL* = UDACCEL
   PUDACCEL* = ptr UDACCEL
-  UNIVERSAL_NAME_INFO* = record
+  UNIVERSAL_NAME_INFO* {.final.} = object
     lpUniversalName*: LPTSTR
 
   TUNIVERSALNAMEINFO* = UNIVERSAL_NAME_INFO
   PUNIVERSALNAMEINFO* = ptr UNIVERSAL_NAME_INFO
-  USEROBJECTFLAGS* = record
+  USEROBJECTFLAGS* {.final.} = object
     fInherit*: WINBOOL
     fReserved*: WINBOOL
     dwFlags*: DWORD
@@ -11803,7 +11803,7 @@ type
   tagUSEROBJECTFLAGS* = USEROBJECTFLAGS
   TUSEROBJECTFLAGS* = USEROBJECTFLAGS
   PUSEROBJECTFLAGS* = ptr USEROBJECTFLAGS
-  VALENT* = record
+  VALENT* {.final.} = object
     ve_valuename*: LPTSTR
     ve_valuelen*: DWORD
     ve_valueptr*: DWORD
@@ -11814,13 +11814,13 @@ type
   value_ent* = VALENT
   Tvalue_ent* = VALENT
   Pvalue_ent* = ptr VALENT
-  VERIFY_INFORMATION* = record
+  VERIFY_INFORMATION* {.final.} = object
     StartingOffset*: LARGE_INTEGER
     len*: DWORD
 
   TVERIFYINFORMATION* = VERIFY_INFORMATION
   PVERIFYINFORMATION* = ptr VERIFY_INFORMATION
-  VS_FIXEDFILEINFO* = record
+  VS_FIXEDFILEINFO* {.final.} = object
     dwSignature*: DWORD
     dwStrucVersion*: DWORD
     dwFileVersionMS*: DWORD
@@ -11837,7 +11837,7 @@ type
 
   TVSFIXEDFILEINFO* = VS_FIXEDFILEINFO
   PVSFIXEDFILEINFO* = ptr VS_FIXEDFILEINFO
-  WIN32_FIND_DATA* = record
+  WIN32_FIND_DATA* {.final.} = object
     dwFileAttributes*: DWORD
     ftCreationTime*: FILETIME
     ftLastAccessTime*: FILETIME
@@ -11853,7 +11853,7 @@ type
   PWIN32_FIND_DATA* = ptr WIN32_FIND_DATA
   TWIN32FINDDATA* = WIN32_FIND_DATA
   TWIN32FINDDATAA* = WIN32_FIND_DATA
-  WIN32_FIND_DATAW* = record
+  WIN32_FIND_DATAW* {.final.} = object
     dwFileAttributes*: DWORD
     ftCreationTime*: FILETIME
     ftLastAccessTime*: FILETIME
@@ -11868,7 +11868,7 @@ type
   LPWIN32_FIND_DATAW* = ptr WIN32_FIND_DATAW
   PWIN32_FIND_DATAW* = ptr WIN32_FIND_DATAW
   TWIN32FINDDATAW* = WIN32_FIND_DATAW
-  WIN32_STREAM_ID* = record
+  WIN32_STREAM_ID* {.final.} = object
     dwStreamId*: DWORD
     dwStreamAttributes*: DWORD
     Size*: LARGE_INTEGER
@@ -11877,7 +11877,7 @@ type
 
   TWIN32STREAMID* = WIN32_STREAM_ID
   PWIN32STREAMID* = ptr WIN32_STREAM_ID
-  WINDOWPLACEMENT* = record
+  WINDOWPLACEMENT* {.final.} = object
     len*: UINT
     flags*: UINT
     showCmd*: UINT
@@ -11887,7 +11887,7 @@ type
 
   TWINDOWPLACEMENT* = WINDOWPLACEMENT
   PWINDOWPLACEMENT* = ptr WINDOWPLACEMENT
-  WNDCLASS* = record
+  WNDCLASS* {.final.} = object
     style*: UINT
     lpfnWndProc*: WNDPROC
     cbClsExtra*: int32
@@ -11903,7 +11903,7 @@ type
   TWNDCLASS* = WNDCLASS
   TWNDCLASSA* = WNDCLASS
   PWNDCLASS* = ptr WNDCLASS
-  WNDCLASSW* = record
+  WNDCLASSW* {.final.} = object
     style*: UINT
     lpfnWndProc*: WNDPROC
     cbClsExtra*: int32
@@ -11918,7 +11918,7 @@ type
   LPWNDCLASSW* = ptr WNDCLASSW
   TWNDCLASSW* = WNDCLASSW
   PWNDCLASSW* = ptr WNDCLASSW
-  WNDCLASSEX* = record
+  WNDCLASSEX* {.final.} = object
     cbSize*: UINT
     style*: UINT
     lpfnWndProc*: WNDPROC
@@ -11936,7 +11936,7 @@ type
   TWNDCLASSEX* = WNDCLASSEX
   TWNDCLASSEXA* = WNDCLASSEX
   PWNDCLASSEX* = ptr WNDCLASSEX
-  WNDCLASSEXW* = record
+  WNDCLASSEXW* {.final.} = object
     cbSize*: UINT
     style*: UINT
     lpfnWndProc*: WNDPROC
@@ -11953,7 +11953,7 @@ type
   LPWNDCLASSEXW* = ptr WNDCLASSEXW
   TWNDCLASSEXW* = WNDCLASSEXW
   PWNDCLASSEXW* = ptr WNDCLASSEXW
-  CONNECTDLGSTRUCT* = record
+  CONNECTDLGSTRUCT* {.final.} = object
     cbStructure*: DWORD
     hwndOwner*: HWND
     lpConnRes*: LPNETRESOURCE
@@ -11963,7 +11963,7 @@ type
   LPCONNECTDLGSTRUCT* = ptr CONNECTDLGSTRUCT
   TCONNECTDLGSTRUCT* = CONNECTDLGSTRUCT
   PCONNECTDLGSTRUCT* = ptr CONNECTDLGSTRUCT
-  DISCDLGSTRUCT* = record
+  DISCDLGSTRUCT* {.final.} = object
     cbStructure*: DWORD
     hwndOwner*: HWND
     lpLocalName*: LPTSTR
@@ -11974,7 +11974,7 @@ type
   TDISCDLGSTRUCT* = DISCDLGSTRUCT
   TDISCDLGSTRUCTA* = DISCDLGSTRUCT
   PDISCDLGSTRUCT* = ptr DISCDLGSTRUCT
-  NETINFOSTRUCT* = record
+  NETINFOSTRUCT* {.final.} = object
     cbStructure*: DWORD
     dwProviderVersion*: DWORD
     dwStatus*: DWORD
@@ -11987,7 +11987,7 @@ type
   LPNETINFOSTRUCT* = ptr NETINFOSTRUCT
   TNETINFOSTRUCT* = NETINFOSTRUCT
   PNETINFOSTRUCT* = ptr NETINFOSTRUCT
-  NETCONNECTINFOSTRUCT* = record
+  NETCONNECTINFOSTRUCT* {.final.} = object
     cbStructure*: DWORD
     dwFlags*: DWORD
     dwSpeed*: DWORD
@@ -12009,13 +12009,13 @@ type
                           para3: int32, para4: LPARAM): int32{.stdcall.}
   LPOVERLAPPED_COMPLETION_ROUTINE* = proc (para1: DWORD, para2: DWORD,
       para3: LPOVERLAPPED){.stdcall.} # Structures for the extensions to OpenGL
-  POINTFLOAT* = record
+  POINTFLOAT* {.final.} = object
     x*: float32
     y*: float32
 
   TPOINTFLOAT* = POINTFLOAT
   PPOINTFLOAT* = ptr POINTFLOAT
-  GLYPHMETRICSFLOAT* = record
+  GLYPHMETRICSFLOAT* {.final.} = object
     gmfBlackBoxX*: float32
     gmfBlackBoxY*: float32
     gmfptGlyphOrigin*: POINTFLOAT
@@ -12025,7 +12025,7 @@ type
   LPGLYPHMETRICSFLOAT* = ptr GLYPHMETRICSFLOAT
   TGLYPHMETRICSFLOAT* = GLYPHMETRICSFLOAT
   PGLYPHMETRICSFLOAT* = ptr GLYPHMETRICSFLOAT
-  LAYERPLANEDESCRIPTOR* = record
+  LAYERPLANEDESCRIPTOR* {.final.} = object
     nSize*: int16
     nVersion*: int16
     dwFlags*: DWORD
@@ -12055,7 +12055,7 @@ type
   tagLAYERPLANEDESCRIPTOR* = LAYERPLANEDESCRIPTOR
   TLAYERPLANEDESCRIPTOR* = LAYERPLANEDESCRIPTOR
   PLAYERPLANEDESCRIPTOR* = ptr LAYERPLANEDESCRIPTOR
-  PIXELFORMATDESCRIPTOR* = record
+  PIXELFORMATDESCRIPTOR* {.final.} = object
     nSize*: int16
     nVersion*: int16
     dwFlags*: DWORD
@@ -12087,7 +12087,7 @@ type
   tagPIXELFORMATDESCRIPTOR* = PIXELFORMATDESCRIPTOR
   TPIXELFORMATDESCRIPTOR* = PIXELFORMATDESCRIPTOR
   PPIXELFORMATDESCRIPTOR* = ptr PIXELFORMATDESCRIPTOR
-  USER_INFO_2* = record
+  USER_INFO_2* {.final.} = object
     usri2_name*: LPWSTR
     usri2_password*: LPWSTR
     usri2_password_age*: DWORD
@@ -12116,13 +12116,13 @@ type
   PUSER_INFO_2* = ptr USER_INFO_2
   LPUSER_INFO_2* = ptr USER_INFO_2
   TUSERINFO2* = USER_INFO_2
-  USER_INFO_0* = record
+  USER_INFO_0* {.final.} = object
     usri0_name*: LPWSTR
 
   PUSER_INFO_0* = ptr USER_INFO_0
   LPUSER_INFO_0* = ptr USER_INFO_0
   TUSERINFO0* = USER_INFO_0
-  USER_INFO_3* = record
+  USER_INFO_3* {.final.} = object
     usri3_name*: LPWSTR
     usri3_password*: LPWSTR
     usri3_password_age*: DWORD
@@ -12156,7 +12156,7 @@ type
   PUSER_INFO_3* = ptr USER_INFO_3
   LPUSER_INFO_3* = ptr USER_INFO_3
   TUSERINFO3* = USER_INFO_3
-  GROUP_INFO_2* = record
+  GROUP_INFO_2* {.final.} = object
     grpi2_name*: LPWSTR
     grpi2_comment*: LPWSTR
     grpi2_group_id*: DWORD
@@ -12164,13 +12164,13 @@ type
 
   PGROUP_INFO_2* = ptr GROUP_INFO_2
   TGROUPINFO2* = GROUP_INFO_2
-  LOCALGROUP_INFO_0* = record
+  LOCALGROUP_INFO_0* {.final.} = object
     lgrpi0_name*: LPWSTR
 
   PLOCALGROUP_INFO_0* = ptr LOCALGROUP_INFO_0
   LPLOCALGROUP_INFO_0* = ptr LOCALGROUP_INFO_0
   TLOCALGROUPINFO0* = LOCALGROUP_INFO_0
-  IMAGE_DOS_HEADER* = record
+  IMAGE_DOS_HEADER* {.final.} = object
     e_magic*: int16
     e_cblp*: int16
     e_cp*: int16
@@ -12193,7 +12193,7 @@ type
 
   PIMAGE_DOS_HEADER* = ptr IMAGE_DOS_HEADER
   TIMAGEDOSHEADER* = IMAGE_DOS_HEADER
-  NOTIFYICONDATAA* = record
+  NOTIFYICONDATAA* {.final.} = object
     cbSize*: DWORD
     Wnd*: HWND
     uID*: UINT
@@ -12203,7 +12203,7 @@ type
     szTip*: array[0..63, Char]
 
   NOTIFYICONDATA* = NOTIFYICONDATAA
-  NOTIFYICONDATAW* = record
+  NOTIFYICONDATAW* {.final.} = object
     cbSize*: DWORD
     Wnd*: HWND
     uID*: UINT
@@ -12224,7 +12224,7 @@ type
 
 type
   PWaveFormatEx* = ptr TWaveFormatEx
-  TWaveFormatEx* = record
+  TWaveFormatEx* {.final.} = object
     wFormatTag*: int16        # format type
     nChannels*: int16         # number of channels (i.e. mono, stereo, etc.)
     nSamplesPerSec*: DWORD    # sample rate
@@ -12233,7 +12233,7 @@ type
     wBitsPerSample*: int16    # number of bits per sample of mono data
     cbSize*: int16            # the count in bytes of the size of
 
-  WIN32_FILE_ATTRIBUTE_DATA* = record
+  WIN32_FILE_ATTRIBUTE_DATA* {.final.} = object
     dwFileAttributes*: DWORD
     ftCreationTime*: FILETIME
     ftLastAccessTime*: FILETIME
@@ -12244,7 +12244,7 @@ type
   LPWIN32_FILE_ATTRIBUTE_DATA* = ptr WIN32_FILE_ATTRIBUTE_DATA
   TWIN32FILEATTRIBUTEDATA* = WIN32_FILE_ATTRIBUTE_DATA
   PWIN32FILEATTRIBUTEDATA* = ptr WIN32_FILE_ATTRIBUTE_DATA # TrackMouseEvent. NT or higher only.
-  TTrackMouseEvent* = record
+  TTrackMouseEvent* {.final.} = object
     cbSize*: DWORD
     dwFlags*: DWORD
     hwndTrack*: HWND
@@ -13317,7 +13317,7 @@ else:
     HALFPARAM* = int16
     HALFPARAMBOOL* = WORDBOOL
 type
-  MSG* = record
+  MSG* {.final.} = object
     hwnd*: HWND
     message*: UINT
     wParam*: WPARAM
@@ -13330,20 +13330,20 @@ type
   TMSG* = MSG
   PMSG* = ptr MSG
   PMessage* = ptr TMessage
-  TMessage* = record          #fields according to ICS
+  TMessage* {.final.} = object          #fields according to ICS
     msg*: UINT
     wParam*: WPARAM
     lParam*: LPARAM
     Result*: LRESULT
 
-  TWMSize* = record
+  TWMSize* {.final.} = object
     Msg*: UINT
     SizeType*: WPARAM
     Width*: HALFPARAM
     Height*: HALFPARAM
     Result*: LRESULT
 
-  TWMNoParams* = record
+  TWMNoParams* {.final.} = object
     Msg*: UINT
     Unused*: array[0..3, HALFPARAM]
     Result*: LRESULT
@@ -13353,7 +13353,7 @@ type
   TWMDestroy* = TWMNoParams
   TWMClose* = TWMNoParams
   TWMQueryUIState* = TWMNoParams
-  TWMUIState* = record
+  TWMUIState* {.final.} = object
     Msg*: UINT
     Action*: int16
     Flags*: int16
@@ -13361,7 +13361,7 @@ type
 
   TWMChangeUIState* = TWMUIState
   TWMUpdateUIState* = TWMUIState
-  TWMKey* = record
+  TWMKey* {.final.} = object
     Msg*: UINT
     CharCode*: int16
     Unused*: int16
@@ -13374,7 +13374,7 @@ type
   TWMSysChar* = TWMKey
   TWMSysKeyDown* = TWMKey
   TWMSysKeyUp* = TWMKey
-  TWMMenuChar* = record
+  TWMMenuChar* {.final.} = object
     Msg*: UINT
     User*: Char
     MenuFlag*: int16
@@ -13386,7 +13386,7 @@ type
   TWMGetFont* = TWMNoParams
   TWMSysColorChange* = TWMNoParams
   TWMQueryDragIcon* = TWMNoParams
-  TWMScroll* = record
+  TWMScroll* {.final.} = object
     Msg*: UINT
     ScrollCode*: HALFPARAM
     Pos*: HALFPARAM
@@ -13395,59 +13395,59 @@ type
 
   TWMHScroll* = TWMScroll
   TWMVScroll* = TWMScroll
-  TWMGetText* = record
+  TWMGetText* {.final.} = object
     Msg*: UINT
     TextMax*: LPARAM
     Text*: cstring
     Result*: LRESULT
 
   TWMGetTextLength* = TWMNoParams
-  TWMKillFocus* = record
+  TWMKillFocus* {.final.} = object
     Msg*: UINT
     FocusedWnd*: HWND
     UnUsed*: WPARAM
     Result*: LRESULT
 
-  TWMSetCursor* = record
+  TWMSetCursor* {.final.} = object
     Msg*: UINT
     CursorWnd*: HWND
     HitTest*: HALFPARAM
     MouseMsg*: HALFPARAM
     Result*: LRESULT
 
-  TWMSetFocus* = record
+  TWMSetFocus* {.final.} = object
     Msg*: UINT
     FocusedWnd*: HWND
     Unused*: WPARAM
     Result*: LRESULT
 
-  TWMSetFont* = record
+  TWMSetFont* {.final.} = object
     Msg*: UINT
     Font*: HFONT
     Redraw*: HALFPARAMBOOL
     Unused*: HALFPARAM
     Result*: LRESULT
 
-  TWMShowWindow* = record
+  TWMShowWindow* {.final.} = object
     Msg*: UINT
     Show*: HALFPARAMBOOL
     Unused*: HALFPARAM
     Status*: WPARAM
     Result*: LRESULT
 
-  TWMEraseBkgnd* = record
+  TWMEraseBkgnd* {.final.} = object
     Msg*: UINT
     DC*: HDC
     Unused*: LPARAM
     Result*: LRESULT
 
-  TWMNCHitTest* = record
+  TWMNCHitTest* {.final.} = object
     Msg*: UINT
     Unused*: int32
     Pos*: TSmallPoint
     Result*: LRESULT
 
-  TWMMouse* = record
+  TWMMouse* {.final.} = object
     Msg*: UINT
     Keys*: int32
     Pos*: TSmallPoint
@@ -13459,14 +13459,14 @@ type
   TWMMButtonDblClk* = TWMMouse
   TWMMButtonDown* = TWMMouse
   TWMMButtonUp* = TWMMouse
-  TWMMouseWheel* = record
+  TWMMouseWheel* {.final.} = object
     Msg*: UINT
     Keys*: int16
     WheelDelta*: int16
     Pos*: TSmallPoint
     Result*: LRESULT
 
-  TWMNCHitMessage* = record
+  TWMNCHitMessage* {.final.} = object
     Msg*: UINT
     HitTest*: int32
     XCursor*: int16
@@ -13484,51 +13484,51 @@ type
   TWMRButtonDown* = TWMMouse
   TWMRButtonUp* = TWMMouse
   TWMMouseMove* = TWMMouse
-  TWMPaint* = record
+  TWMPaint* {.final.} = object
     Msg*: UINT
     DC*: HDC
     Unused*: int32
     Result*: LRESULT
 
-  TWMCommand* = record
+  TWMCommand* {.final.} = object
     Msg*: UINT
     ItemID*: int16
     NotifyCode*: int16
     Ctl*: HWND
     Result*: LRESULT
 
-  TWMNotify* = record
+  TWMNotify* {.final.} = object
     Msg*: UINT
     IDCtrl*: int32
     NMHdr*: PNMHdr
     Result*: LRESULT
 
-  TWMPrint* = record
+  TWMPrint* {.final.} = object
     Msg*: UINT
     DC*: HDC
     Flags*: int
     Result*: LRESULT
 
   TWMPrintClient* = TWMPrint
-  TWMWinIniChange* = record
+  TWMWinIniChange* {.final.} = object
     Msg*: UINT
     Unused*: int
     Section*: cstring
     Result*: LRESULT
 
-  TWMContextMenu* = record
+  TWMContextMenu* {.final.} = object
     Msg*: UINT
     hWnd*: HWND
     Pos*: TSmallPoint
     Result*: LRESULT
 
-  TWMNCCalcSize* = record
+  TWMNCCalcSize* {.final.} = object
     Msg*: UINT
     CalcValidRects*: WINBOOL
     CalcSize_Params*: PNCCalcSizeParams
     Result*: LRESULT
 
-  TWMCharToItem* = record
+  TWMCharToItem* {.final.} = object
     Msg*: UINT
     Key*: int16
     CaretPos*: int16
@@ -13537,7 +13537,7 @@ type
 
   TWMVKeyToItem* = TWMCharToItem
   TMyEventRange = range[0'i16..16000'i16]
-  TWMParentNotify* = record
+  TWMParentNotify* {.final.} = object
     Msg*: UINT
     case Event*: TMyEventRange
     of TMyEventRange(WM_CREATE), TMyEventRange(WM_DESTROY):
@@ -13556,7 +13556,7 @@ type
         Value2*: int32
         Result*: LRESULT
 
-  TWMSysCommand* = record
+  TWMSysCommand* {.final.} = object
     Msg*: UINT
     CmdType*: int32
     XPos*: int16
@@ -13574,13 +13574,13 @@ type
   #  else: # of SC_KEYMENU:
   #      Key*: int16
 
-  TWMMove* = record
+  TWMMove* {.final.} = object
     Msg*: UINT
     Unused*: int
     Pos*: TSmallPoint
     Result*: LRESULT
 
-  TWMWindowPosMsg* = record
+  TWMWindowPosMsg* {.final.} = object
     Msg*: UINT
     Unused*: int
     WindowPos*: PWindowPos
@@ -13588,101 +13588,101 @@ type
 
   TWMWindowPosChanged* = TWMWindowPosMsg
   TWMWindowPosChanging* = TWMWindowPosMsg
-  TWMCompareItem* = record
+  TWMCompareItem* {.final.} = object
     Msg*: UINT
     Ctl*: HWnd
     CompareItemStruct*: PCompareItemStruct
     Result*: LRESULT
 
-  TWMDeleteItem* = record
+  TWMDeleteItem* {.final.} = object
     Msg*: UINT
     Ctl*: HWND
     DeleteItemStruct*: PDeleteItemStruct
     Result*: LRESULT
 
-  TWMDrawItem* = record
+  TWMDrawItem* {.final.} = object
     Msg*: UINT
     Ctl*: HWND
     DrawItemStruct*: PDrawItemStruct
     Result*: LRESULT
 
-  TWMMeasureItem* = record
+  TWMMeasureItem* {.final.} = object
     Msg*: UINT
     IDCtl*: HWnd
     MeasureItemStruct*: PMeasureItemStruct
     Result*: LRESULT
 
-  TWMNCCreate* = record
+  TWMNCCreate* {.final.} = object
     Msg*: UINT
     Unused*: int
     CreateStruct*: PCreateStruct
     Result*: LRESULT
 
-  TWMInitMenuPopup* = record
+  TWMInitMenuPopup* {.final.} = object
     Msg*: UINT
     MenuPopup*: HMENU
     Pos*: int16
     SystemMenu*: WordBool
     Result*: LRESULT
 
-  TWMMenuSelect* = record
+  TWMMenuSelect* {.final.} = object
     Msg*: UINT
     IDItem*: int16
     MenuFlag*: int16
     Menu*: HMENU
     Result*: LRESULT
 
-  TWMActivate* = record
+  TWMActivate* {.final.} = object
     Msg*: UINT
     Active*: int16
     Minimized*: WordBool
     ActiveWindow*: HWND
     Result*: LRESULT
 
-  TWMQueryEndSession* = record
+  TWMQueryEndSession* {.final.} = object
     Msg*: UINT
     Source*: int32
     Unused*: int32
     Result*: LRESULT
 
-  TWMMDIActivate* = record
+  TWMMDIActivate* {.final.} = object
     Msg*: UINT
     DeactiveWnd*: HWND
     ActiveWnd*: HWND
     Result*: LRESULT
 
-  TWMNextDlgCtl* = record
+  TWMNextDlgCtl* {.final.} = object
     Msg*: UINT
     CtlFocus*: int32
     Handle*: WordBool
     Unused*: int16
     Result*: LRESULT
 
-  TWMHelp* = record
+  TWMHelp* {.final.} = object
     Msg*: UINT
     Unused*: int
     HelpInfo*: PHelpInfo
     Result*: LRESULT
 
-  TWMGetMinMaxInfo* = record
+  TWMGetMinMaxInfo* {.final.} = object
     Msg*: UINT
     Unused*: int
     MinMaxInfo*: PMinMaxInfo
     Result*: LRESULT
 
-  TWMSettingChange* = record
+  TWMSettingChange* {.final.} = object
     Msg*: UINT
     Flag*: int
     Section*: cstring
     Result*: LRESULT
 
-  TWMCreate* = record
+  TWMCreate* {.final.} = object
     Msg*: UINT
     Unused*: int
     CreateStruct*: PCreateStruct
     Result*: LRESULT
 
-  TWMCtlColor* = record
+  TWMCtlColor* {.final.} = object
     Msg*: UINT
     ChildDC*: HDC
     ChildWnd*: HWND
@@ -13695,38 +13695,38 @@ type
   TWMCtlColorMsgbox* = TWMCtlColor
   TWMCtlColorDlg* = TWMCtlColor
   TWMCtlColorEdit* = TWMCtlColor
-  TWMInitDialog* = record
+  TWMInitDialog* {.final.} = object
     Msg*: UINT
     Focus*: HWND
     InitParam*: int32
     Result*: LRESULT
 
-  TWMNCPaint* = record
+  TWMNCPaint* {.final.} = object
     Msg*: UINT
     RGN*: HRGN
     Unused*: int32
     Result*: LRESULT
 
-  TWMSetText* = record
+  TWMSetText* {.final.} = object
     Msg*: UINT
     Unused*: int32
     Text*: cstring
     Result*: LRESULT
 
-  TWMSizeClipboard* = record
+  TWMSizeClipboard* {.final.} = object
     Msg*: UINT
     Viewer*: HWND
     RC*: THandle
     Result*: LRESULT
 
-  TWMSpoolerStatus* = record
+  TWMSpoolerStatus* {.final.} = object
     Msg*: UINT
     JobStatus*: LPARAM
     JobsLeft*: WPARAM
     Unused*: WPARAM
     Result*: LRESULT
 
-  TWMStyleChange* = record
+  TWMStyleChange* {.final.} = object
     Msg*: UINT
     StyleType*: LPARAM
     StyleStruct*: PStyleStruct
@@ -13734,54 +13734,54 @@ type
 
   TWMStyleChanged* = TWMStyleChange
   TWMStyleChanging* = TWMStyleChange
-  TWMSysDeadChar* = record
+  TWMSysDeadChar* {.final.} = object
     Msg*: UINT
     CharCode*: WPARAM
     Unused*: WPARAM
     KeyData*: LPARAM
     Result*: LRESULT
 
-  TWMSystemError* = record
+  TWMSystemError* {.final.} = object
     Msg*: UINT
     ErrSpec*: WPARAM
     Unused*: LPARAM
     Result*: LRESULT
 
   TWMTimeChange* = TWMNoParams
-  TWMTimer* = record
+  TWMTimer* {.final.} = object
     Msg*: UINT
     TimerID*: LPARAM
     TimerProc*: TFarProc
     Result*: LRESULT
 
   TWMUndo* = TWMNoParams
-  TWMVScrollClipboard* = record
+  TWMVScrollClipboard* {.final.} = object
     Msg*: UINT
     Viewer*: HWND
     ScollCode*: WPARAM
     ThumbPos*: WPARAM
     Result*: LRESULT
 
-  TWMDisplayChange* = record
+  TWMDisplayChange* {.final.} = object
     Msg*: UINT
     BitsPerPixel*: int
     Width*: WPARAM
     Height*: WPARAM
     Result*: LRESULT
 
-  TWMDropFiles* = record
+  TWMDropFiles* {.final.} = object
     Msg*: UINT
     Drop*: THANDLE
     Unused*: LPARAM
     Result*: LRESULT
 
-  TWMEnable* = record
+  TWMEnable* {.final.} = object
     Msg*: int
     Enabled*: WINBOOL
     Unused*: int32
     Result*: int32
 
-  TWMMouseActivate* = record
+  TWMMouseActivate* {.final.} = object
     Msg*: int
     TopLevel*: HWND
     HitTestCode*: int16
@@ -20686,7 +20686,7 @@ type
   TFNFiberStartRoutine* = FARPROC
   TFNHookProc* = HOOKPROC
   PObjectTypeList* = ptr TObjectTypeList
-  OBJECT_TYPE_LIST* = record
+  OBJECT_TYPE_LIST* {.final.} = object
     Level*: int16
     Sbz*: int16
     ObjectType*: PGUID
@@ -20694,14 +20694,14 @@ type
   TObjectTypeList* = OBJECT_TYPE_LIST
   AUDIT_EVENT_TYPE* = DWORD
   PBlendFunction* = ptr TBlendFunction
-  BLENDFUNCTION* = record
+  BLENDFUNCTION* {.final.} = object
     BlendOp*: int8
     BlendFlags*: int8
     SourceConstantAlpha*: int8
     AlphaFormat*: int8
 
   TBlendFunction* = BLENDFUNCTION
-  WIN_CERTIFICATE* = record
+  WIN_CERTIFICATE* {.final.} = object
     dwLength*: DWord
     wRevision*: int16
     wCertificateType*: int16
@@ -20709,7 +20709,7 @@ type
 
   TWinCertificate* = WIN_CERTIFICATE
   PWinCertificate* = ptr TWinCertificate
-  TMaxLogPalette* = record
+  TMaxLogPalette* {.final.} = object
     palVersion*: int16
     palNumEntries*: int16
     palPalEntry*: array[int8, TPaletteEntry]
diff --git a/nim/ast.pas b/nim/ast.pas
index 6d5acf425..587284d56 100644
--- a/nim/ast.pas
+++ b/nim/ast.pas
@@ -65,140 +65,149 @@ for key, val in enums.iteritems():
   cog.out(b)
 ]]]*)
 type
-  TSymKind = (
-    skUnknownSym, skConditional, skDynLib, skParam, 
-    skTypeParam, skTemp, skType, skConst, 
-    skVar, skProc, skIterator, skConverter, 
-    skMacro, skTemplate, skField, skEnumField, 
-    skForVar, skModule, skLabel);
-  TSymKinds = set of TSymKind;
-const
-  SymKindToStr: array [TSymKind] of string = (
-    'skUnknownSym', 'skConditional', 'skDynLib', 'skParam', 
-    'skTypeParam', 'skTemp', 'skType', 'skConst', 
-    'skVar', 'skProc', 'skIterator', 'skConverter', 
-    'skMacro', 'skTemplate', 'skField', 'skEnumField', 
-    'skForVar', 'skModule', 'skLabel');
-type
   TNodeKind = (
     nkNone, nkEmpty, nkIdent, nkSym, 
-    nkType, nkCharLit, nkRCharLit, nkIntLit, 
-    nkInt8Lit, nkInt16Lit, nkInt32Lit, nkInt64Lit, 
-    nkFloatLit, nkFloat32Lit, nkFloat64Lit, nkStrLit, 
-    nkRStrLit, nkTripleStrLit, nkNilLit, nkDotCall, 
+    nkType, nkCharLit, nkIntLit, nkInt8Lit, 
+    nkInt16Lit, nkInt32Lit, nkInt64Lit, nkFloatLit, 
+    nkFloat32Lit, nkFloat64Lit, nkStrLit, nkRStrLit, 
+    nkTripleStrLit, nkMetaNode, nkNilLit, nkDotCall, 
     nkCommand, nkCall, nkGenericCall, nkExplicitTypeListCall, 
     nkExprEqExpr, nkExprColonExpr, nkIdentDefs, nkInfix, 
     nkPrefix, nkPostfix, nkPar, nkCurly, 
     nkBracket, nkBracketExpr, nkPragmaExpr, nkRange, 
     nkDotExpr, nkCheckedFieldExpr, nkDerefExpr, nkIfExpr, 
     nkElifExpr, nkElseExpr, nkLambda, nkAccQuoted, 
-    nkHeaderQuoted, nkSetConstr, nkConstSetConstr, nkArrayConstr, 
-    nkConstArrayConstr, nkRecordConstr, nkConstRecordConstr, nkTableConstr, 
-    nkConstTableConstr, nkQualified, nkHiddenStdConv, nkHiddenSubConv, 
-    nkHiddenCallConv, nkConv, nkCast, nkAddr, 
-    nkAsgn, nkDefaultTypeParam, nkGenericParams, nkFormalParams, 
-    nkOfInherit, nkModule, nkProcDef, nkConverterDef, 
-    nkMacroDef, nkTemplateDef, nkIteratorDef, nkOfBranch, 
-    nkElifBranch, nkExceptBranch, nkElse, nkMacroStmt, 
-    nkAsmStmt, nkPragma, nkIfStmt, nkWhenStmt, 
-    nkForStmt, nkWhileStmt, nkCaseStmt, nkVarSection, 
-    nkConstSection, nkConstDef, nkTypeSection, nkTypeDef, 
-    nkYieldStmt, nkTryStmt, nkFinally, nkRaiseStmt, 
-    nkReturnStmt, nkBreakStmt, nkContinueStmt, nkBlockStmt, 
-    nkGotoStmt, nkDiscardStmt, nkStmtList, nkImportStmt, 
-    nkFromStmt, nkImportAs, nkIncludeStmt, nkAccessStmt, 
-    nkCommentStmt, nkStmtListExpr, nkBlockExpr, nkVm, 
-    nkTypeOfExpr, nkRecordTy, nkObjectTy, nkRecList, 
-    nkRecCase, nkRecWhen, nkRefTy, nkPtrTy, 
-    nkVarTy, nkProcTy, nkEnumTy, nkEnumFieldDef);
+    nkHeaderQuoted, nkTableConstr, nkQualified, nkHiddenStdConv, 
+    nkHiddenSubConv, nkHiddenCallConv, nkConv, nkCast, 
+    nkAddr, nkHiddenAddr, nkHiddenDeref, nkObjDownConv, 
+    nkObjUpConv, nkChckRangeF, nkChckRange64, nkChckRange, 
+    nkStringToCString, nkCStringToString, nkPassAsOpenArray, nkAsgn, 
+    nkDefaultTypeParam, nkGenericParams, nkFormalParams, nkOfInherit, 
+    nkModule, nkProcDef, nkConverterDef, nkMacroDef, 
+    nkTemplateDef, nkIteratorDef, nkOfBranch, nkElifBranch, 
+    nkExceptBranch, nkElse, nkMacroStmt, nkAsmStmt, 
+    nkPragma, nkIfStmt, nkWhenStmt, nkForStmt, 
+    nkWhileStmt, nkCaseStmt, nkVarSection, nkConstSection, 
+    nkConstDef, nkTypeSection, nkTypeDef, nkYieldStmt, 
+    nkTryStmt, nkFinally, nkRaiseStmt, nkReturnStmt, 
+    nkBreakStmt, nkContinueStmt, nkBlockStmt, nkDiscardStmt, 
+    nkStmtList, nkImportStmt, nkFromStmt, nkImportAs, 
+    nkIncludeStmt, nkAccessStmt, nkCommentStmt, nkStmtListExpr, 
+    nkBlockExpr, nkVm, nkTypeOfExpr, nkObjectTy, 
+    nkTupleTy, nkRecList, nkRecCase, nkRecWhen, 
+    nkRefTy, nkPtrTy, nkVarTy, nkProcTy, 
+    nkEnumTy, nkEnumFieldDef, nkReturnToken);
   TNodeKinds = set of TNodeKind;
 const
   NodeKindToStr: array [TNodeKind] of string = (
     'nkNone', 'nkEmpty', 'nkIdent', 'nkSym', 
-    'nkType', 'nkCharLit', 'nkRCharLit', 'nkIntLit', 
-    'nkInt8Lit', 'nkInt16Lit', 'nkInt32Lit', 'nkInt64Lit', 
-    'nkFloatLit', 'nkFloat32Lit', 'nkFloat64Lit', 'nkStrLit', 
-    'nkRStrLit', 'nkTripleStrLit', 'nkNilLit', 'nkDotCall', 
+    'nkType', 'nkCharLit', 'nkIntLit', 'nkInt8Lit', 
+    'nkInt16Lit', 'nkInt32Lit', 'nkInt64Lit', 'nkFloatLit', 
+    'nkFloat32Lit', 'nkFloat64Lit', 'nkStrLit', 'nkRStrLit', 
+    'nkTripleStrLit', 'nkMetaNode', 'nkNilLit', 'nkDotCall', 
     'nkCommand', 'nkCall', 'nkGenericCall', 'nkExplicitTypeListCall', 
     'nkExprEqExpr', 'nkExprColonExpr', 'nkIdentDefs', 'nkInfix', 
     'nkPrefix', 'nkPostfix', 'nkPar', 'nkCurly', 
     'nkBracket', 'nkBracketExpr', 'nkPragmaExpr', 'nkRange', 
     'nkDotExpr', 'nkCheckedFieldExpr', 'nkDerefExpr', 'nkIfExpr', 
     'nkElifExpr', 'nkElseExpr', 'nkLambda', 'nkAccQuoted', 
-    'nkHeaderQuoted', 'nkSetConstr', 'nkConstSetConstr', 'nkArrayConstr', 
-    'nkConstArrayConstr', 'nkRecordConstr', 'nkConstRecordConstr', 'nkTableConstr', 
-    'nkConstTableConstr', 'nkQualified', 'nkHiddenStdConv', 'nkHiddenSubConv', 
-    'nkHiddenCallConv', 'nkConv', 'nkCast', 'nkAddr', 
-    'nkAsgn', 'nkDefaultTypeParam', 'nkGenericParams', 'nkFormalParams', 
-    'nkOfInherit', 'nkModule', 'nkProcDef', 'nkConverterDef', 
-    'nkMacroDef', 'nkTemplateDef', 'nkIteratorDef', 'nkOfBranch', 
-    'nkElifBranch', 'nkExceptBranch', 'nkElse', 'nkMacroStmt', 
-    'nkAsmStmt', 'nkPragma', 'nkIfStmt', 'nkWhenStmt', 
-    'nkForStmt', 'nkWhileStmt', 'nkCaseStmt', 'nkVarSection', 
-    'nkConstSection', 'nkConstDef', 'nkTypeSection', 'nkTypeDef', 
-    'nkYieldStmt', 'nkTryStmt', 'nkFinally', 'nkRaiseStmt', 
-    'nkReturnStmt', 'nkBreakStmt', 'nkContinueStmt', 'nkBlockStmt', 
-    'nkGotoStmt', 'nkDiscardStmt', 'nkStmtList', 'nkImportStmt', 
-    'nkFromStmt', 'nkImportAs', 'nkIncludeStmt', 'nkAccessStmt', 
-    'nkCommentStmt', 'nkStmtListExpr', 'nkBlockExpr', 'nkVm', 
-    'nkTypeOfExpr', 'nkRecordTy', 'nkObjectTy', 'nkRecList', 
-    'nkRecCase', 'nkRecWhen', 'nkRefTy', 'nkPtrTy', 
-    'nkVarTy', 'nkProcTy', 'nkEnumTy', 'nkEnumFieldDef');
+    'nkHeaderQuoted', 'nkTableConstr', 'nkQualified', 'nkHiddenStdConv', 
+    'nkHiddenSubConv', 'nkHiddenCallConv', 'nkConv', 'nkCast', 
+    'nkAddr', 'nkHiddenAddr', 'nkHiddenDeref', 'nkObjDownConv', 
+    'nkObjUpConv', 'nkChckRangeF', 'nkChckRange64', 'nkChckRange', 
+    'nkStringToCString', 'nkCStringToString', 'nkPassAsOpenArray', 'nkAsgn', 
+    'nkDefaultTypeParam', 'nkGenericParams', 'nkFormalParams', 'nkOfInherit', 
+    'nkModule', 'nkProcDef', 'nkConverterDef', 'nkMacroDef', 
+    'nkTemplateDef', 'nkIteratorDef', 'nkOfBranch', 'nkElifBranch', 
+    'nkExceptBranch', 'nkElse', 'nkMacroStmt', 'nkAsmStmt', 
+    'nkPragma', 'nkIfStmt', 'nkWhenStmt', 'nkForStmt', 
+    'nkWhileStmt', 'nkCaseStmt', 'nkVarSection', 'nkConstSection', 
+    'nkConstDef', 'nkTypeSection', 'nkTypeDef', 'nkYieldStmt', 
+    'nkTryStmt', 'nkFinally', 'nkRaiseStmt', 'nkReturnStmt', 
+    'nkBreakStmt', 'nkContinueStmt', 'nkBlockStmt', 'nkDiscardStmt', 
+    'nkStmtList', 'nkImportStmt', 'nkFromStmt', 'nkImportAs', 
+    'nkIncludeStmt', 'nkAccessStmt', 'nkCommentStmt', 'nkStmtListExpr', 
+    'nkBlockExpr', 'nkVm', 'nkTypeOfExpr', 'nkObjectTy', 
+    'nkTupleTy', 'nkRecList', 'nkRecCase', 'nkRecWhen', 
+    'nkRefTy', 'nkPtrTy', 'nkVarTy', 'nkProcTy', 
+    'nkEnumTy', 'nkEnumFieldDef', 'nkReturnToken');
 type
   TSymFlag = (
-    sfGeneric, sfForward, sfImportc, sfExportc, 
+    sfTypeCheck, sfForward, sfImportc, sfExportc, 
     sfVolatile, sfUsed, sfWrite, sfRegister, 
     sfPure, sfCodeGenerated, sfPrivate, sfGlobal, 
     sfResult, sfNoSideEffect, sfMainModule, sfSystemModule, 
-    sfNoReturn, sfReturnsNew, sfInInterface, sfNoStatic, 
+    sfNoReturn, sfAddrTaken, sfInInterface, sfNoStatic, 
     sfCompilerProc, sfCppMethod, sfDiscriminant, sfDeprecated, 
     sfInClosure, sfIsCopy, sfStar, sfMinus);
   TSymFlags = set of TSymFlag;
 const
   SymFlagToStr: array [TSymFlag] of string = (
-    'sfGeneric', 'sfForward', 'sfImportc', 'sfExportc', 
+    'sfTypeCheck', 'sfForward', 'sfImportc', 'sfExportc', 
     'sfVolatile', 'sfUsed', 'sfWrite', 'sfRegister', 
     'sfPure', 'sfCodeGenerated', 'sfPrivate', 'sfGlobal', 
     'sfResult', 'sfNoSideEffect', 'sfMainModule', 'sfSystemModule', 
-    'sfNoReturn', 'sfReturnsNew', 'sfInInterface', 'sfNoStatic', 
+    'sfNoReturn', 'sfAddrTaken', 'sfInInterface', 'sfNoStatic', 
     'sfCompilerProc', 'sfCppMethod', 'sfDiscriminant', 'sfDeprecated', 
     'sfInClosure', 'sfIsCopy', 'sfStar', 'sfMinus');
 type
   TTypeKind = (
     tyNone, tyBool, tyChar, tyEmptySet, 
-    tyArrayConstr, tyNil, tyRecordConstr, tyGeneric, 
-    tyGenericInst, tyGenericParam, tyEnum, tyAnyEnum, 
-    tyArray, tyRecord, tyObject, tyTuple, 
-    tySet, tyRange, tyPtr, tyRef, 
-    tyVar, tySequence, tyProc, tyPointer, 
-    tyOpenArray, tyString, tyCString, tyForward, 
-    tyInt, tyInt8, tyInt16, tyInt32, 
-    tyInt64, tyFloat, tyFloat32, tyFloat64, 
-    tyFloat128);
+    tyArrayConstr, tyNil, tyGeneric, tyGenericInst, 
+    tyGenericParam, tyEnum, tyAnyEnum, tyArray, 
+    tyObject, tyTuple, tySet, tyRange, 
+    tyPtr, tyRef, tyVar, tySequence, 
+    tyProc, tyPointer, tyOpenArray, tyString, 
+    tyCString, tyForward, tyInt, tyInt8, 
+    tyInt16, tyInt32, tyInt64, tyFloat, 
+    tyFloat32, tyFloat64, tyFloat128);
   TTypeKinds = set of TTypeKind;
 const
   TypeKindToStr: array [TTypeKind] of string = (
     'tyNone', 'tyBool', 'tyChar', 'tyEmptySet', 
-    'tyArrayConstr', 'tyNil', 'tyRecordConstr', 'tyGeneric', 
-    'tyGenericInst', 'tyGenericParam', 'tyEnum', 'tyAnyEnum', 
-    'tyArray', 'tyRecord', 'tyObject', 'tyTuple', 
-    'tySet', 'tyRange', 'tyPtr', 'tyRef', 
-    'tyVar', 'tySequence', 'tyProc', 'tyPointer', 
-    'tyOpenArray', 'tyString', 'tyCString', 'tyForward', 
-    'tyInt', 'tyInt8', 'tyInt16', 'tyInt32', 
-    'tyInt64', 'tyFloat', 'tyFloat32', 'tyFloat64', 
-    'tyFloat128');
+    'tyArrayConstr', 'tyNil', 'tyGeneric', 'tyGenericInst', 
+    'tyGenericParam', 'tyEnum', 'tyAnyEnum', 'tyArray', 
+    'tyObject', 'tyTuple', 'tySet', 'tyRange', 
+    'tyPtr', 'tyRef', 'tyVar', 'tySequence', 
+    'tyProc', 'tyPointer', 'tyOpenArray', 'tyString', 
+    'tyCString', 'tyForward', 'tyInt', 'tyInt8', 
+    'tyInt16', 'tyInt32', 'tyInt64', 'tyFloat', 
+    'tyFloat32', 'tyFloat64', 'tyFloat128');
+type
+  TNodeFlag = (
+    nfNone, nfBase2, nfBase8, nfBase16, 
+    nfAllConst);
+  TNodeFlags = set of TNodeFlag;
+const
+  NodeFlagToStr: array [TNodeFlag] of string = (
+    'nfNone', 'nfBase2', 'nfBase8', 'nfBase16', 
+    'nfAllConst');
 type
   TTypeFlag = (
     tfIsDistinct, tfGeneric, tfExternal, tfImported, 
     tfInfoGenerated, tfSemChecked, tfHasOutParams, tfEnumHasWholes, 
-    tfVarargs, tfAssignable);
+    tfVarargs, tfFinal);
   TTypeFlags = set of TTypeFlag;
 const
   TypeFlagToStr: array [TTypeFlag] of string = (
     'tfIsDistinct', 'tfGeneric', 'tfExternal', 'tfImported', 
     'tfInfoGenerated', 'tfSemChecked', 'tfHasOutParams', 'tfEnumHasWholes', 
-    'tfVarargs', 'tfAssignable');
+    'tfVarargs', 'tfFinal');
+type
+  TSymKind = (
+    skUnknownSym, skConditional, skDynLib, skParam, 
+    skTypeParam, skTemp, skType, skConst, 
+    skVar, skProc, skIterator, skConverter, 
+    skMacro, skTemplate, skField, skEnumField, 
+    skForVar, skModule, skLabel);
+  TSymKinds = set of TSymKind;
+const
+  SymKindToStr: array [TSymKind] of string = (
+    'skUnknownSym', 'skConditional', 'skDynLib', 'skParam', 
+    'skTypeParam', 'skTemp', 'skType', 'skConst', 
+    'skVar', 'skProc', 'skIterator', 'skConverter', 
+    'skMacro', 'skTemplate', 'skField', 'skEnumField', 
+    'skForVar', 'skModule', 'skLabel');
 {[[[end]]]}
 
 type
@@ -228,20 +237,28 @@ type
     mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, 
     mUnaryMinusI, mUnaryMinusI64, mAbsI, mAbsI64, mNot, mUnaryPlusI, 
     mBitnotI, mUnaryPlusI64, mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, 
-    mZe, mZe64, mToU8, mToU16, mToU32, mToFloat, 
-    mToBiggestFloat, mToInt, mToBiggestInt, mAnd, mOr, mEqStr, 
-    mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, 
-    mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT, 
-    mConTArr, mConTT, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem, 
-    mAppendSeqSeq, mInRange, mInSet, mIs, mAsgn, mRepr, 
-    mExit, mSetLengthStr, mSetLengthSeq, mAssert, mSwap, mArray, 
-    mOpenArray, mRange, mTuple, mSet, mSeq, mCompileDate, 
-    mCompileTime, mNimrodVersion, mNimrodMajor, mNimrodMinor, mNimrodPatch, mCpuEndian
+    mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, 
+    mToU8, mToU16, mToU32, mToFloat, mToBiggestFloat, mToInt, 
+    mToBiggestInt, mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, 
+    mCStrToStr, mStrToStr, mAnd, mOr, mEqStr, mLeStr, 
+    mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, 
+    mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT, mConTArr, 
+    mConTT, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendSeqSeq, 
+    mInRange, mInSet, mIs, mAsgn, mRepr, mExit, 
+    mSetLengthStr, mSetLengthSeq, mAssert, mSwap, mIsNil, mArray, 
+    mOpenArray, mRange, mSet, mSeq, mCompileDate, mCompileTime, 
+    mNimrodVersion, mNimrodMajor, mNimrodMinor, mNimrodPatch, mCpuEndian, 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]]]
   );
 
 type
   PNode = ^TNode;
+  PNodePtr = ^{@ptr}PNode;
   TNodeSeq = array of PNode;
 
   PType = ^TType;
@@ -254,22 +271,22 @@ type
     comment: string;
     sons: TNodeSeq; // else!
     info: TLineInfo;
-    base: TNumericalBase; // only valid for int or float literals
+    flags: TNodeFlags;
     case Kind: TNodeKind of
-      nkCharLit, nkRCharLit, 
-      nkIntLit, nkInt8Lit, nkInt16Lit, nkInt32Lit, nkInt64Lit:
+      nkCharLit, nkIntLit, nkInt8Lit, nkInt16Lit, nkInt32Lit, nkInt64Lit:
         (intVal: biggestInt);
       nkFloatLit, nkFloat32Lit, nkFloat64Lit:
         (floatVal: biggestFloat);
       nkSym: (sym: PSym);
       nkIdent: (ident: PIdent);
+      nkMetaNode: (nodePtr: PNodePtr);
   end;
   {@emit
   record // keep this below 32 bytes; otherwise the AST grows too much
     typ: PType;
     comment: string;
     info: TLineInfo;
-    base: TNumericalBase; // only valid for int or float literals
+    flags: TNodeFlags;
     case Kind: TNodeKind of
       nkCharLit..nkInt64Lit:
         (intVal: biggestInt);
@@ -279,6 +296,7 @@ type
         (strVal: string);
       nkSym: (sym: PSym);
       nkIdent: (ident: PIdent);
+      nkMetaNode: (nodePtr: PNodePtr);
       else (sons: TNodeSeq);
   end; }
 
@@ -305,29 +323,29 @@ type
     locCall,       // location is a call expression
     locOther       // location is something other
   );
-
+  
   TLocFlag = (
-  //  lfIndirect,    // location needs to be derefered
-    lfOnStack,     // location is on hardware stack
-    lfOnHeap,      // location is on heap
-    lfOnData,      // location is in the static constant data
-    lfOnUnknown,   // location is unknown (stack, heap or static)
-                   // other backend-flags:
+    lfIndirect,    // backend introduced a pointer
     lfNoDeepCopy,  // no need for a deep copy
     lfNoDecl,      // do not declare it in C
     lfDynamicLib,  // link symbol to dynamic library
     lfHeader       // include header file for symbol
   );
 
+  TStorageLoc = (
+    OnUnknown,     // location is unknown (stack, heap or static)
+    OnStack,       // location is on hardware stack
+    OnHeap         // location is on heap or global (reference counting needed)
+  );
+
   TLocFlags = set of TLocFlag;
   TLoc = record
     k: TLocKind;    // kind of location
+    s: TStorageLoc;
+    flags: TLocFlags;  // location's flags
     t: PType;       // type of location
-    r: PRope;       // rope value of location (C code generator)
+    r: PRope;       // rope value of location (code generators)
     a: int;         // location's "address", i.e. slot for temporaries
-    flags: TLocFlags;  // location's flags
-    indirect: int;  // count the number of dereferences needed to access the
-                    // location
   end;
 
 // ---------------- end of backend information ------------------------------
@@ -447,7 +465,7 @@ type
   PLib = ^TLib;
 
 const
-  OverloadableSyms = {@set}[skProc, skIterator, skEnumField];
+  OverloadableSyms = {@set}[skProc, skIterator, skConverter];
 
 const // "MagicToStr" array:
   MagicToStr: array [TMagic] of string = (
@@ -474,15 +492,22 @@ const // "MagicToStr" array:
     'EqProc', 'EqUntracedRef', 'LePtr', 'LtPtr', 'EqCString', 'Xor', 
     'UnaryMinusI', 'UnaryMinusI64', 'AbsI', 'AbsI64', 'Not', 'UnaryPlusI', 
     'BitnotI', 'UnaryPlusI64', 'BitnotI64', 'UnaryPlusF64', 'UnaryMinusF64', 'AbsF64', 
-    'Ze', 'Ze64', 'ToU8', 'ToU16', 'ToU32', 'ToFloat', 
-    'ToBiggestFloat', 'ToInt', 'ToBiggestInt', 'And', 'Or', 'EqStr', 
-    'LeStr', 'LtStr', 'EqSet', 'LeSet', 'LtSet', 'MulSet', 
-    'PlusSet', 'MinusSet', 'SymDiffSet', 'ConStrStr', 'ConArrArr', 'ConArrT', 
-    'ConTArr', 'ConTT', 'Slice', 'AppendStrCh', 'AppendStrStr', 'AppendSeqElem', 
-    'AppendSeqSeq', 'InRange', 'InSet', 'Is', 'Asgn', 'Repr', 
-    'Exit', 'SetLengthStr', 'SetLengthSeq', 'Assert', 'Swap', 'Array', 
-    'OpenArray', 'Range', 'Tuple', 'Set', 'Seq', 'CompileDate', 
-    'CompileTime', 'NimrodVersion', 'NimrodMajor', 'NimrodMinor', 'NimrodPatch', 'CpuEndian'
+    'Ze8ToI', 'Ze8ToI64', 'Ze16ToI', 'Ze16ToI64', 'Ze32ToI64', 'ZeIToI64', 
+    'ToU8', 'ToU16', 'ToU32', 'ToFloat', 'ToBiggestFloat', 'ToInt', 
+    'ToBiggestInt', 'CharToStr', 'BoolToStr', 'IntToStr', 'Int64ToStr', 'FloatToStr', 
+    'CStrToStr', 'StrToStr', 'And', 'Or', 'EqStr', 'LeStr', 
+    'LtStr', 'EqSet', 'LeSet', 'LtSet', 'MulSet', 'PlusSet', 
+    'MinusSet', 'SymDiffSet', 'ConStrStr', 'ConArrArr', 'ConArrT', 'ConTArr', 
+    'ConTT', 'Slice', 'AppendStrCh', 'AppendStrStr', 'AppendSeqElem', 'AppendSeqSeq', 
+    'InRange', 'InSet', 'Is', 'Asgn', 'Repr', 'Exit', 
+    'SetLengthStr', 'SetLengthSeq', 'Assert', 'Swap', 'IsNil', 'Array', 
+    'OpenArray', 'Range', 'Set', 'Seq', 'CompileDate', 'CompileTime', 
+    'NimrodVersion', 'NimrodMajor', 'NimrodMinor', 'NimrodPatch', 'CpuEndian', '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]]]
   );
 
@@ -490,7 +515,7 @@ const
   GenericTypes: TTypeKinds = {@set}[tyGeneric, tyGenericParam];
 
   StructuralEquivTypes: TTypeKinds = {@set}[
-    tyEmptySet, tyArrayConstr, tyNil, tyRecordConstr, tyTuple,
+    tyEmptySet, tyArrayConstr, tyNil, tyTuple,
     tyArray,
     tySet,
     tyRange,
@@ -503,16 +528,16 @@ const
   ConcreteTypes: TTypeKinds = {@set}[
   // types of the expr that may occur in::
   // var x = expr
-    tyBool, tyChar, tyEnum, tyArray, tyRecord, tyObject, tySet, tyTuple,
+    tyBool, tyChar, tyEnum, tyArray, tyObject, tySet, tyTuple,
     tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc,
     tyPointer, tyOpenArray,
     tyString, tyCString,
     tyInt..tyInt64,
     tyFloat..tyFloat128
   ];
-  ConstantDataTypes: TTypeKinds = {@set}[tyArray, tyRecord, tySet, tyTuple];
-  ExportableSymKinds = {@set}[skVar, skConst, skProc, skType, skEnumField,
-                              skIterator, skMacro, skTemplate];
+  ConstantDataTypes: TTypeKinds = {@set}[tyArray, tySet, tyTuple];
+  ExportableSymKinds = {@set}[skVar, skConst, skProc, skType,
+                              skIterator, skMacro, skTemplate, skConverter];
   namePos = 0;
   genericParamsPos = 1;
   paramsPos = 2;
@@ -534,7 +559,7 @@ function newIntTypeNode(kind: TNodeKind; const intVal: BiggestInt;
                         typ: PType): PNode;
 function newFloatNode(kind: TNodeKind; const floatVal: BiggestFloat): PNode;
 function newStrNode(kind: TNodeKind; const strVal: string): PNode;
-function newIdentNode(ident: PIdent): PNode;
+function newIdentNode(ident: PIdent; const info: TLineInfo): PNode;
 function newSymNode(sym: PSym): PNode;
 function newNodeI(kind: TNodeKind; const info: TLineInfo): PNode;
 function newNodeIT(kind: TNodeKind; const info: TLineInfo; typ: PType): PNode;
@@ -548,7 +573,7 @@ procedure initNodeTable(out x: TNodeTable);
 
 // copy procs:
 function copyType(t: PType; owner: PSym): PType;
-function copySym(s: PSym; owner: PSym): PSym;
+function copySym(s: PSym; keepId: bool = false): PSym;
 procedure assignType(dest, src: PType);
 
 procedure copyStrTable(out dest: TStrTable; const src: TStrTable);
@@ -620,7 +645,7 @@ begin
       if b.kind in [nkStrLit..nkTripleStrLit] then
         result := a.strVal <= b.strVal;
     end
-    else assert(false);
+    else InternalError(a.info, 'leValue');
   end
 end;
 
@@ -638,7 +663,7 @@ begin
       if b.kind in [nkStrLit..nkTripleStrLit] then
         result := a.strVal = b.strVal;
     end
-    else assert(false);
+    else InternalError(a.info, 'SameValue');
   end
 end;
 
@@ -652,7 +677,7 @@ begin
     nkStrLit..nkTripleStrLit:
       result := a.strVal;
     else begin
-      assert(false);
+      InternalError(a.info, 'valueToString');
       result := ''
     end
   end
@@ -663,6 +688,9 @@ var
   i: int;
 begin
   dest.counter := src.counter;
+{@emit
+  if isNil(src.data) then exit;
+}
   setLength(dest.data, length(src.data));
   for i := 0 to high(src.data) do
     dest.data[i] := src.data[i];
@@ -673,6 +701,9 @@ var
   i: int;
 begin
   dest.counter := src.counter;
+{@emit
+  if isNil(src.data) then exit;
+}
   setLength(dest.data, length(src.data));
   for i := 0 to high(src.data) do
     dest.data[i] := src.data[i];
@@ -683,6 +714,9 @@ var
   i: int;
 begin
   dest.counter := src.counter;
+{@emit
+  if isNil(src.data) then exit;
+}
   setLength(dest.data, length(src.data));
   for i := 0 to high(src.data) do
     dest.data[i] := src.data[i];
@@ -700,7 +734,7 @@ begin
   FillChar(result^, sizeof(result^), 0);
 {@emit}
   result.kind := kind;
-  result.info := UnknownLineInfo;
+  result.info := UnknownLineInfo();
 end;
 
 function newIntNode(kind: TNodeKind; const intVal: BiggestInt): PNode;
@@ -728,10 +762,11 @@ begin
   result.strVal := strVal
 end;
 
-function newIdentNode(ident: PIdent): PNode;
+function newIdentNode(ident: PIdent; const info: TLineInfo): PNode;
 begin
   result := newNode(nkIdent);
-  result.ident := ident
+  result.ident := ident;
+  result.info := info;
 end;
 
 function newSymNode(sym: PSym): PNode;
@@ -778,8 +813,9 @@ begin
   dest.n := src.n;
   dest.size := src.size;
   dest.align := src.align;
+  dest.containerID := src.containerID;
   newSons(dest, sonsLen(src));
-  for i := 0 to sonsLen(src)-1 do
+  for i := 0 to sonsLen(src)-1 do 
     dest.sons[i] := src.sons[i];
 end;
 
@@ -793,14 +829,13 @@ begin
   // backend-info should not be copied
 end;
 
-function copySym(s: PSym; owner: PSym): PSym;
+function copySym(s: PSym; keepId: bool = false): PSym;
 begin
-  result := newSym(s.kind, s.name, owner);
+  result := newSym(s.kind, s.name, s.owner);
   result.ast := nil; // BUGFIX; was: s.ast which made problems
   result.info := s.info;
   result.typ := s.typ;
-  if owner = s.owner then result.id := s.id
-  else result.id := getID();
+  if keepId then result.id := s.id else result.id := getID();
   result.flags := s.flags;
   result.magic := s.magic;
   copyStrTable(result.tab, s.tab);
@@ -820,7 +855,7 @@ begin
   result.Name := Name;
   result.Kind := symKind;
   result.flags := {@set}[];
-  result.info := UnknownLineInfo;
+  result.info := UnknownLineInfo();
   result.options := gOptions;
   result.owner := owner;
   result.offset := -1;
@@ -971,8 +1006,8 @@ begin
   if src = nil then begin result := nil; exit end;
   result := newNode(src.kind);
   result.info := src.info;
-  result.typ := src.typ;  
-  result.base := src.base;
+  result.typ := src.typ;
+  result.flags := src.flags;
   case src.Kind of
     nkCharLit..nkInt64Lit:
       result.intVal := src.intVal;
@@ -984,6 +1019,8 @@ begin
       result.ident := src.ident;
     nkStrLit..nkTripleStrLit:
       result.strVal := src.strVal;
+    nkMetaNode:
+      result.nodePtr := src.nodePtr;
     else begin end;
   end;
 end;
@@ -994,11 +1031,30 @@ var
   i: int;
 begin
   if src = nil then begin result := nil; exit end;
-  result := copyNode(src);
-  result.sons := nil; // BUGFIX
-  newSons(result, sonsLen(src));
-  for i := 0 to sonsLen(src)-1 do
-    result.sons[i] := copyTree(src.sons[i]);
+  result := newNode(src.kind);
+  result.info := src.info;
+  result.typ := src.typ;
+  result.flags := src.flags;
+  case src.Kind of
+    nkCharLit..nkInt64Lit:
+      result.intVal := src.intVal;
+    nkFloatLit, nkFloat32Lit, nkFloat64Lit:
+      result.floatVal := src.floatVal;
+    nkSym:
+      result.sym := src.sym;
+    nkIdent:
+      result.ident := src.ident;
+    nkStrLit..nkTripleStrLit:
+      result.strVal := src.strVal;
+    nkMetaNode:
+      result.nodePtr := src.nodePtr;
+    else begin
+      result.sons := nil;
+      newSons(result, sonsLen(src));
+      for i := 0 to sonsLen(src)-1 do
+        result.sons[i] := copyTree(src.sons[i]);
+    end;
+  end
 end;
 
 function lastSon(n: PNode): PNode;
@@ -1016,8 +1072,8 @@ var
   i: int;
 begin
   for i := 0 to sonsLen(n)-1 do begin
-    if (n.sons[i] <> nil) and (n.sons[i].kind = kind) then begin 
-      result := true; exit 
+    if (n.sons[i] <> nil) and (n.sons[i].kind = kind) then begin
+      result := true; exit
     end
   end;
   result := false
@@ -1031,9 +1087,9 @@ begin
     nkEmpty..nkNilLit: result := n.kind = kind;
     else begin
       for i := 0 to sonsLen(n)-1 do begin
-        if (n.sons[i] <> nil) and (n.sons[i].kind = kind) 
-        or hasSubnodeWith(n.sons[i], kind) then begin 
-          result := true; exit 
+        if (n.sons[i] <> nil) and (n.sons[i].kind = kind)
+        or hasSubnodeWith(n.sons[i], kind) then begin
+          result := true; exit
         end
       end;
       result := false
diff --git a/nim/astalgo.pas b/nim/astalgo.pas
index 5ab1683b3..a7ee3fc83 100644
--- a/nim/astalgo.pas
+++ b/nim/astalgo.pas
@@ -136,6 +136,10 @@ procedure debug(n: PNode); overload;
 function IdTableGet(const t: TIdTable; key: PIdObj): PObject;
 procedure IdTablePut(var t: TIdTable; key: PIdObj; val: PObject);
 
+function IdTableHasObjectAsKey(const t: TIdTable; key: PIdObj): bool;
+// checks if `t` contains the `key` (compared by the pointer value, not only
+// `key`'s id)
+
 function IdNodeTableGet(const t: TIdNodeTable; key: PIdObj): PNode;
 procedure IdNodeTablePut(var t: TIdNodeTable; key: PIdObj; val: PNode);
 
@@ -180,8 +184,6 @@ function nextTry(h, maxHash: THash): THash;
 implementation
 
 function lookupInRecord(n: PNode; field: PIdent): PSym;
-// XXX: transform in a node that contains the runtime check for the
-// field, if it is in a case-part...
 var
   i: int;
 begin
@@ -194,7 +196,7 @@ begin
       end
     end;
     nkRecCase: begin
-      assert(n.sons[0].kind = nkSym);
+      if (n.sons[0].kind <> nkSym) then InternalError(n.info, 'lookupInRecord');
       result := lookupInRecord(n.sons[0], field);
       if result <> nil then exit;
       for i := 1 to sonsLen(n)-1 do begin
@@ -203,7 +205,7 @@ begin
             result := lookupInRecord(lastSon(n.sons[i]), field);
             if result <> nil then exit;
           end;
-          else internalError('lookupInRecord(record case branch)');
+          else internalError(n.info, 'lookupInRecord(record case branch)');
         end
       end
     end;
@@ -226,7 +228,8 @@ var
   i: int;
 begin
   for i := start to sonsLen(list)-1 do begin
-    assert(list.sons[i].kind = nkSym);
+    if list.sons[i].kind <> nkSym then
+      InternalError(list.info, 'getSymFromList');
     result := list.sons[i].sym;
     if result.name.id = ident.id then exit
   end;
@@ -342,7 +345,7 @@ end;
 
 function lineInfoToStr(const info: TLineInfo): PRope;
 begin
-  result := ropeFormat('[$1, $2, $3]', [makeYamlString(toFilename(info)),
+  result := ropef('[$1, $2, $3]', [makeYamlString(toFilename(info)),
               toRope(toLinenumber(info)), toRope(toColumn(info))]);
 end;
 
@@ -367,11 +370,11 @@ begin
   for i := 0 to high(n.data) do
     if n.data[i] <> nil then begin
       if mycount > 0 then app(result, ','+'');
-      appRopeFormat(result, '$n$1$2',
+      appf(result, '$n$1$2',
         [istr, symToYamlAux(n.data[i], marker, indent+2, maxRecDepth-1)]);
       inc(mycount)
     end;
-  if mycount > 0 then appRopeFormat(result, '$n$1', [spaces(indent)]);
+  if mycount > 0 then appf(result, '$n$1', [spaces(indent)]);
   app(result, ']'+'');
   assert(mycount = n.counter);
 end;
@@ -387,10 +390,10 @@ begin
   i := 0;
   while i <= high(c) do begin
     if i > 0 then app(result, ','+'');
-    appRopeFormat(result, '$n$1"$2": $3', [istr, c[i], c[i+1]]);
+    appf(result, '$n$1"$2": $3', [istr, c[i], c[i+1]]);
     inc(i, 2)
   end;
-  appRopeFormat(result, '$n$1}', [spaces(indent)]);
+  appf(result, '$n$1}', [spaces(indent)]);
 end;
 
 function symToYamlAux(n: PSym; var marker: TObjectSet;
@@ -401,7 +404,7 @@ begin
   if n = nil then
     result := toRope('null')
   else if ObjectSetContainsOrIncl(marker, n) then
-    result := ropeFormat('"$1 @$2"', [
+    result := ropef('"$1 @$2"', [
       toRope(n.name.s),
       toRope(strutils.toHex({@cast}TAddress(n), sizeof(n)*2))])
   else begin
@@ -427,7 +430,7 @@ begin
   if n = nil then
     result := toRope('null')
   else if objectSetContainsOrIncl(marker, n) then
-    result := ropeFormat('"$1 @$2"', [
+    result := ropef('"$1 @$2"', [
       toRope(typeKindToStr[n.kind]),
       toRope(strutils.toHex({@cast}TAddress(n), sizeof(n)*2))])
   else begin
@@ -453,48 +456,48 @@ begin
     result := toRope('null')
   else begin
     istr := spaces(indent+2);
-    result := ropeFormat('{$n$1"kind": $2',
+    result := ropef('{$n$1"kind": $2',
                          [istr, makeYamlString(nodeKindToStr[n.kind])]);
     if maxRecDepth <> 0 then begin
-      appRopeFormat(result, ',$n$1"typ": $2',
-        [istr, typeToYamlAux(n.typ, marker, indent+2, maxRecDepth)]);
-      appRopeFormat(result, ',$n$1"info": $2',
+      appf(result, ',$n$1"info": $2',
         [istr, lineInfoToStr(n.info)]);
       case n.kind of
         nkCharLit..nkInt64Lit:
-          appRopeFormat(result, '$n$1"intVal": $2', [istr, toRope(n.intVal)]);
+          appf(result, '$n$1"intVal": $2', [istr, toRope(n.intVal)]);
         nkFloatLit, nkFloat32Lit, nkFloat64Lit:
-          appRopeFormat(result, '$n$1"floatVal": $2',
+          appf(result, '$n$1"floatVal": $2',
                         [istr, toRopeF(n.floatVal)]);
         nkStrLit..nkTripleStrLit:
-          appRopeFormat(result, '$n$1"strVal": $2',
+          appf(result, '$n$1"strVal": $2',
                         [istr, makeYamlString(n.strVal)]);
         nkSym:
-          appRopeFormat(result, ',$n$1"sym": $2',
+          appf(result, ',$n$1"sym": $2',
             [istr, symToYamlAux(n.sym, marker, indent+2, maxRecDepth)]);
 
         nkIdent: begin
           if n.ident <> nil then
-            appRopeFormat(result, '$n$1"ident": $2',
+            appf(result, '$n$1"ident": $2',
                           [istr, makeYamlString(n.ident.s)])
           else
-            appRopeFormat(result, '$n$1"ident": null', [istr])
+            appf(result, '$n$1"ident": null', [istr])
         end
         else begin
           if sonsLen(n) > 0 then begin
-            appRopeFormat(result, ',$n$1"sons": [', [istr]);
+            appf(result, ',$n$1"sons": [', [istr]);
             for i := 0 to sonsLen(n)-1 do begin
               if i > 0 then app(result, ','+'');
-              appRopeFormat(result, '$n$1$2',
+              appf(result, '$n$1$2',
                 [spaces(indent+4),
                  treeToYamlAux(n.sons[i], marker, indent + 4, maxRecDepth-1)]);
             end;
-            appRopeFormat(result, '$n$1]', [istr]);
+            appf(result, '$n$1]', [istr]);
           end
         end
-      end
+      end;
+      appf(result, ',$n$1"typ": $2',
+        [istr, typeToYamlAux(n.typ, marker, indent+2, maxRecDepth)]);
     end;
-    appRopeFormat(result, '$n$1}', [spaces(indent)]);
+    appf(result, '$n$1}', [spaces(indent)]);
   end
 end;
 
@@ -523,19 +526,88 @@ begin
 end;
 
 // these are for debugging only:
+function debugType(n: PType): PRope;
+var
+  i: int;
+begin
+  if n = nil then
+    result := toRope('null')
+  else begin
+    result := toRope(typeKindToStr[n.kind]);
+    app(result, '('+'');
+    for i := 0 to sonsLen(n)-1 do begin
+      if i > 0 then app(result, ', ');
+      if n.sons[i] = nil then app(result, 'null')
+      else app(result, debugType(n.sons[i]));
+       //  app(result, typeKindToStr[n.sons[i].kind]);
+    end;
+    app(result, ')'+'');
+  end
+end;
+
+function debugTree(n: PNode; indent: int; maxRecDepth: int): PRope;
+var
+  istr: PRope;
+  i: int;
+begin
+  if n = nil then
+    result := toRope('null')
+  else begin
+    istr := spaces(indent+2);
+    result := ropef('{$n$1"kind": $2',
+                         [istr, makeYamlString(nodeKindToStr[n.kind])]);
+    if maxRecDepth <> 0 then begin
+      case n.kind of
+        nkCharLit..nkInt64Lit:
+          appf(result, '$n$1"intVal": $2', [istr, toRope(n.intVal)]);
+        nkFloatLit, nkFloat32Lit, nkFloat64Lit:
+          appf(result, '$n$1"floatVal": $2',
+                        [istr, toRopeF(n.floatVal)]);
+        nkStrLit..nkTripleStrLit:
+          appf(result, '$n$1"strVal": $2',
+                        [istr, makeYamlString(n.strVal)]);
+        nkSym:
+          appf(result, ',$n$1"sym": $2_$3',
+            [istr, toRope(n.sym.name.s), toRope(n.sym.id)]);
+
+        nkIdent: begin
+          if n.ident <> nil then
+            appf(result, '$n$1"ident": $2',
+                          [istr, makeYamlString(n.ident.s)])
+          else
+            appf(result, '$n$1"ident": null', [istr])
+        end
+        else begin
+          if sonsLen(n) > 0 then begin
+            appf(result, ',$n$1"sons": [', [istr]);
+            for i := 0 to sonsLen(n)-1 do begin
+              if i > 0 then app(result, ','+'');
+              appf(result, '$n$1$2',
+                [spaces(indent+4),
+                 debugTree(n.sons[i], indent + 4, maxRecDepth-1)]);
+            end;
+            appf(result, '$n$1]', [istr]);
+          end
+        end
+      end;
+    end;
+    appf(result, '$n$1}', [spaces(indent)]);
+  end
+end;
+
 procedure debug(n: PSym); overload;
 begin
-  writeln(output, ropeToStr(symToYaml(n, 0, 3)));
+  writeln(output, ropeToStr(ropef('$1_$2', [toRope(n.name.s), toRope(n.id)])));
 end;
 
 procedure debug(n: PType); overload;
 begin
-  writeln(output, ropeToStr(typeToYaml(n, 0, 3)));
+  writeln(output, ropeToStr(debugType(n)));
 end;
 
 procedure debug(n: PNode); overload;
 begin
-  writeln(output, ropeToStr(treeToYaml(n, 0, -1)));
+  writeln(output, ropeToStr(debugTree(n, 0, 100)));
 end;
 
 // -------------------- node sets --------------------------------------------
@@ -748,7 +820,8 @@ var
 begin
   h := n.name.h and high(data);
   while data[h] <> nil do begin
-    assert(data[h] <> n);
+    if data[h] = n then
+      InternalError(n.info, 'StrTableRawInsert: ' + n.name.s);
     h := nextTry(h, high(data))
   end;
   assert(data[h] = nil);
@@ -963,6 +1036,15 @@ begin
   result := -1
 end;
 
+function IdTableHasObjectAsKey(const t: TIdTable; key: PIdObj): bool;
+var
+  index: int;
+begin
+  index := IdTableRawGet(t, key);
+  if index >= 0 then result := t.data[index].key = key
+  else result := false
+end;
+
 function IdTableGet(const t: TIdTable; key: PIdObj): PObject;
 var
   index: int;
@@ -999,6 +1081,7 @@ begin
   end
   else begin
     if mustRehash(length(t.data), t.counter) then begin
+      {@emit n := [];}
       setLength(n, length(t.data) * growthFactor);
     {@ignore}
       fillChar(n[0], length(n)*sizeof(n[0]), 0);
@@ -1083,6 +1166,7 @@ begin
   end
   else begin
     if mustRehash(length(t.data), t.counter) then begin
+      {@emit n := [];}
       setLength(n, length(t.data) * growthFactor);
     {@ignore}
       fillChar(n[0], length(n)*sizeof(n[0]), 0);
diff --git a/nim/bitsets.pas b/nim/bitsets.pas
index 6270fbb6a..ba039a786 100644
--- a/nim/bitsets.pas
+++ b/nim/bitsets.pas
@@ -49,17 +49,20 @@ end;
 
 procedure BitSetIncl(var x: TBitSet; const elem: BiggestInt);
 begin
-  x[int(elem div ElemSize)] := x[int(elem div ElemSize)] or (1 shl (elem mod ElemSize))
+  assert(elem >= 0);
+  x[int(elem div ElemSize)] := toU8(x[int(elem div ElemSize)] or 
+    int(1 shl (elem mod ElemSize)))
 end;
 
 procedure BitSetExcl(var x: TBitSet; const elem: BiggestInt);
 begin
-  x[int(elem div ElemSize)] := x[int(elem div ElemSize)] and
-                          not (1 shl (elem mod ElemSize))
+  x[int(elem div ElemSize)] := toU8(x[int(elem div ElemSize)] and
+                          not int(1 shl (elem mod ElemSize)))
 end;
 
 procedure BitSetInit(out b: TBitSet; len: int);
 begin
+  {@emit b := [];}
   setLength(b, len);
 {@ignore}
   fillChar(b[0], length(b)*sizeof(b[0]), 0);
@@ -70,28 +73,28 @@ procedure BitSetUnion(var x: TBitSet; const y: TBitSet);
 var
   i: int;
 begin
-  for i := 0 to high(x) do x[i] := x[i] or int(y[i])
+  for i := 0 to high(x) do x[i] := toU8(x[i] or int(y[i]))
 end;
 
 procedure BitSetDiff(var x: TBitSet; const y: TBitSet);
 var
   i: int;
 begin
-  for i := 0 to high(x) do x[i] := x[i] and not int(y[i])
+  for i := 0 to high(x) do x[i] := toU8(x[i] and not int(y[i]))
 end;
 
 procedure BitSetSymDiff(var x: TBitSet; const y: TBitSet);
 var
   i: int;
 begin
-  for i := 0 to high(x) do x[i] := x[i] xor int(y[i])
+  for i := 0 to high(x) do x[i] := toU8(x[i] xor int(y[i]))
 end;
 
 procedure BitSetIntersect(var x: TBitSet; const y: TBitSet);
 var
   i: int;
 begin
-  for i := 0 to high(x) do x[i] := x[i] and int(y[i])
+  for i := 0 to high(x) do x[i] := toU8(x[i] and int(y[i]))
 end;
 
 function BitSetEquals(const x, y: TBitSet): Boolean;
diff --git a/nim/ccgexprs.pas b/nim/ccgexprs.pas
index 027f6a816..7668f114a 100644
--- a/nim/ccgexprs.pas
+++ b/nim/ccgexprs.pas
@@ -17,25 +17,34 @@ begin
     // Nimrod has the same bug for the same reasons :-)
     result := toRope('(-2147483647 -1)')
   else if i > low(int64) then
-    result := ropeFormat('IL64($1)', [toRope(i)])
+    result := ropef('IL64($1)', [toRope(i)])
   else
     result := toRope('(IL64(-9223372036854775807) - IL64(1))')
 end;
 
+function int32Literal(i: Int): PRope;
+begin
+  if i = low(int32) then
+    // Nimrod has the same bug for the same reasons :-)
+    result := toRope('(-2147483647 -1)')
+  else
+    result := toRope(i)
+end;
+
 function genHexLiteral(v: PNode): PRope;
 // in C hex literals are unsigned (at least I think so)
 // so we don't generate hex literals any longer.
 begin
-  assert(v.kind in [nkIntLit..nkInt64Lit]);
+  if not (v.kind in [nkIntLit..nkInt64Lit]) then
+    internalError(v.info, 'genHexLiteral');
   result := intLiteral(v.intVal)
 end;
 
-function getStrLit(const s: string): PRope;
+function getStrLit(m: BModule; const s: string): PRope;
 begin
-  inc(currMod.unique);
-  result := con('Str', toRope(currMod.unique));
-  appRopeFormat(currMod.s[cfsData],
-    'STRING_LITERAL($1, $2, $3);$n',
+  inc(gunique);
+  result := con('Str', toRope(gunique));
+  appf(m.s[cfsData], 'STRING_LITERAL($1, $2, $3);$n',
     [result, makeCString(s), ToRope(length(s))])
 end;
 
@@ -45,15 +54,21 @@ var
 begin
   if ty = nil then internalError(v.info, 'genLiteral: ty is nil');
   case v.kind of
-    nkIntLit..nkInt64Lit, nkCharLit..nkRCharLit: begin
+    nkCharLit..nkInt64Lit: begin
       case skipVarGenericRange(ty).kind of
-        tyChar, tyInt..tyInt64, tyNil: result := intLiteral(v.intVal);
+        tyChar, tyInt64, tyNil: result := intLiteral(v.intVal);
+        tyInt..tyInt32: begin
+          if (v.intVal >= low(int32)) and (v.intVal <= high(int32)) then
+            result := int32Literal(int32(v.intVal))
+          else
+            result := intLiteral(v.intVal);
+        end;
         tyBool: begin
           if v.intVal <> 0 then result := toRope('NIM_TRUE')
-          else result := toRope('NIM_FALSE');        
+          else result := toRope('NIM_FALSE');
         end;
         else
-          result := ropeFormat('(($1) $2)', [getTypeDesc(
+          result := ropef('(($1) $2)', [getTypeDesc(p.module,
             skipVarGenericRange(ty)), intLiteral(v.intVal)])
       end
     end;
@@ -61,7 +76,7 @@ begin
       result := toRope('0'+'');
     nkStrLit..nkTripleStrLit: begin
       if skipVarGenericRange(ty).kind = tyString then
-        result := ropeFormat('((string) &$1)', [getStrLit(v.strVal)])
+        result := ropef('((string) &$1)', [getStrLit(p.module, v.strVal)])
       else
         result := makeCString(v.strVal)
     end;
@@ -81,71 +96,7 @@ begin
       InternalError(v.info, 'genLiteral(' +{&} nodeKindToStr[v.kind] +{&} ')');
       result := nil
     end
-  end;
-  (*
-  case ty.Kind of
-    tyRange: result := genLiteral(p, v, ty.sons[0]);
-    tyInt..tyInt64, tyEnum:
-      result := intLiteral(v.intVal);
-    tyPointer, tyRef, tyPtr, tyProc:
-      if v.kind = nkNilLit then
-        result := toRope('0'+'') // 0 is better for C++
-      else
-        result := ropeFormat('(($1) $2)',
-                             [getTypeDesc(ty), intLiteral(v.intVal)]);
-    tyFloat..tyFloat128: begin
-      f := v.floatVal;
-      // BUGFIX: handle INF and NAN correctly:
-      if f <> f then // NAN
-        result := toRope('NAN')
-      else if f = 0.0 then
-        result := toRopeF(f)
-      else if f = 0.5 * f then
-        if f > 0.0 then
-          result := toRope('INF')
-        else
-          result := toRope('-INF')
-      else
-        result := toRopeF(f);
-    end;
-    tyString: begin // also merges constants
-      if v.kind = nkNilLit then result := toRope('0'+'')
-      else result := ropeFormat('((string) &$1)', [getStrLit(v.strVal)]);
-    end;
-    tyCString: begin
-      if v.kind = nkNilLit then
-        result := toRope('0'+'')
-      else if v.kind in [nkIntLit..nkInt64Lit] then begin
-        result := ropeFormat('((NCSTRING) $1)', [intLiteral(v.intVal)])
-      end
-      else 
-        result := makeCString(v.strVal)
-    end;
-    tySequence: begin
-      if v.kind = nkNilLit then 
-        result := toRope('0'+'')      
-      else if v.kind in [nkIntLit..nkInt64Lit] then
-        result := ropeFormat('(($1) $2)',
-                            [getTypeDesc(ty), intLiteral(v.intVal)])
-      else begin
-        assert(false);
-        result := nil // XXX: to implement
-      end
-    end;
-    tyChar: begin
-      result := toRope('''' + toCChar(Chr(int(v.intVal))) + '''')
-    end;
-    tyBool:
-      if v.intVal <> 0 then result := toRope('NIM_TRUE')
-      else result := toRope('NIM_FALSE');
-    tyNil:
-      result := toRope('0'+''); // 0-pointer is better for C++
-    tyVar: result := genLiteral(p, v, ty.sons[0]);
-    else begin
-      InternalError(v.info, 'genLiteral(' +{&} typeKindToStr[ty.kind] +{&} ')');
-      result := nil
-    end
-  end*)
+  end
 end;
 
 function genLiteral(p: BProc; v: PNode): PRope; overload;
@@ -160,11 +111,13 @@ begin
   result := 0;
   if CPU[hostCPU].endian = CPU[targetCPU].endian then begin
     for j := 0 to size-1 do
-      if j < length(s) then result := result or shlu(s[j], j * 8)
+      if j < length(s) then
+        result := result or shlu(Ze64(s[j]), j * 8)
   end
   else begin
     for j := 0 to size-1 do
-      if j < length(s) then result := result or shlu(s[j], (Size - 1 - j) * 8)
+      if j < length(s) then
+        result := result or shlu(Ze64(s[j]), (Size-1-j) * 8)
   end
 end;
 
@@ -181,11 +134,11 @@ begin
         else frmt := '0x$1, '
       end
       else frmt := '0x$1}$n';
-      appRopeFormat(result, frmt, [toRope(toHex(cs[i], 2))])
+      appf(result, frmt, [toRope(toHex(Ze64(cs[i]), 2))])
     end
   end
   else
-    result := toRope('0x' + ToHex(bitSetToWord(cs, size), IntSize * 2))
+    result := toRope('0x' + ToHex(bitSetToWord(cs, size), size * 2))
 end;
 
 function genSetNode(p: BProc; n: PNode): PRope;
@@ -197,9 +150,9 @@ begin
   toBitSet(n, cs);
   if size > 8 then begin
     result := getTempName();
-    appRopeFormat(currMod.s[cfsData],
-      'static $1$2 $3 = $4;',  // BUGFIX
-      [constTok, getTypeDesc(n.typ), result, genRawSetData(cs, size)])
+    appf(p.module.s[cfsData],
+      'static NIM_CONST $1 $2 = $3;',
+      [getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)])
   end
   else
     result := genRawSetData(cs, size)
@@ -207,22 +160,45 @@ end;
 
 // --------------------------- assignment generator -----------------------
 
+function getStorageLoc(n: PNode): TStorageLoc;
+begin
+  case n.kind of
+    nkSym: begin
+      case n.sym.kind of
+        skParam, skForVar, skTemp: result := OnStack;
+        skVar: begin
+          if sfGlobal in n.sym.flags then result := OnHeap
+          else result := OnStack
+        end;
+        else result := OnUnknown;
+      end
+    end;
+    //nkHiddenAddr, nkAddr:
+    nkDerefExpr, nkHiddenDeref:
+      case n.sons[0].typ.kind of
+        tyVar: result := OnUnknown;
+        tyPtr: result := OnStack;
+        tyRef: result := OnHeap;
+        else InternalError(n.info, 'getStorageLoc');
+      end;
+    nkBracketExpr, nkDotExpr, nkObjDownConv, nkObjUpConv:
+      result := getStorageLoc(n.sons[0]);
+    else result := OnUnknown;
+  end
+end;
+
 function rdLoc(const a: TLoc): PRope; // 'read' location (deref if indirect)
 begin
   result := a.r;
-  if a.indirect > 0 then
-    result := ropeFormat('($2$1)', 
-                         [result, toRope(repeatChar(a.indirect, '*'))])
+  if lfIndirect in a.flags then
+    result := ropef('(*$1 /*rdLoc*/)', [result])
 end;
 
 function addrLoc(const a: TLoc): PRope;
 begin
   result := a.r;
-  if a.indirect = 0 then
+  if not (lfIndirect in a.flags) then
     result := con('&'+'', result)
-  else if a.indirect > 1 then
-    result := ropeFormat('($2$1)', 
-                         [result, toRope(repeatChar(a.indirect-1, '*'))])
 end;
 
 function rdCharLoc(const a: TLoc): PRope;
@@ -230,22 +206,22 @@ function rdCharLoc(const a: TLoc): PRope;
 begin
   result := rdLoc(a);
   if skipRange(a.t).kind = tyChar then
-    result := ropeFormat('((NU8)($1))', [result])
+    result := ropef('((NU8)($1))', [result])
 end;
 
 procedure genRefAssign(p: BProc; const dest, src: TLoc);
 begin
-  if (lfOnStack in dest.flags) or not (optRefcGC in gGlobalOptions) then
+  if (dest.s = OnStack) or not (optRefcGC in gGlobalOptions) then
     // location is on hardware stack
-    appRopeFormat(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)])
-  else if lfOnHeap in dest.flags then begin // location is on heap
-    UseMagic('asgnRef');
-    appRopeFormat(p.s[cpsStmts], 'asgnRef((void**) $1, $2);$n',
+    appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)])
+  else if dest.s = OnHeap then begin // location is on heap
+    UseMagic(p.module, 'asgnRef');
+    appf(p.s[cpsStmts], 'asgnRef((void**) $1, $2);$n',
       [addrLoc(dest), rdLoc(src)])
   end
   else begin
-    UseMagic('unsureAsgnRef');
-    appRopeFormat(p.s[cpsStmts], 'unsureAsgnRef((void**) $1, $2);$n',
+    UseMagic(p.module, 'unsureAsgnRef');
+    appf(p.s[cpsStmts], 'unsureAsgnRef((void**) $1, $2);$n',
       [addrLoc(dest), rdLoc(src)])
   end
 end;
@@ -261,8 +237,7 @@ procedure genAssignment(p: BProc; const dest, src: TLoc;
 var
   ty: PType;
 begin;
-  ty := skipAbstract(dest.t);
-  while ty.kind = tyVar do ty := ty.sons[0];
+  ty := skipVarGenericRange(dest.t);
   case ty.kind of
     tyRef:
       genRefAssign(p, dest, src);
@@ -270,92 +245,89 @@ begin;
       if not (needToCopy in flags) then
         genRefAssign(p, dest, src)
       else begin
-        useMagic('genericSeqAssign'); // BUGFIX
-        appRopeFormat(p.s[cpsStmts], 'genericSeqAssign($1, $2, $3);$n',
-          [addrLoc(dest), rdLoc(src), genTypeInfo(currMod, dest.t)])
+        useMagic(p.module, 'genericSeqAssign'); // BUGFIX
+        appf(p.s[cpsStmts], 'genericSeqAssign($1, $2, $3);$n',
+          [addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t)])
       end
     end;
     tyString: begin
       if not (needToCopy in flags) then
         genRefAssign(p, dest, src)
       else begin
-        useMagic('copyString');
-        if (lfOnStack in dest.flags) or not (optRefcGC in gGlobalOptions) then
-          // location is on hardware stack
-          appRopeFormat(p.s[cpsStmts], '$1 = copyString($2);$n',
+        useMagic(p.module, 'copyString');
+        if (dest.s = OnStack) or not (optRefcGC in gGlobalOptions) then
+          appf(p.s[cpsStmts], '$1 = copyString($2);$n',
             [rdLoc(dest), rdLoc(src)])
-        else if lfOnHeap in dest.flags then begin // location is on heap
-          useMagic('asgnRef');
-          useMagic('copyString'); // BUGFIX
-          appRopeFormat(p.s[cpsStmts], 'asgnRef((void**) $1, copyString($2));$n',
+        else if dest.s = OnHeap then begin
+          useMagic(p.module, 'asgnRef');
+          useMagic(p.module, 'copyString'); // BUGFIX
+          appf(p.s[cpsStmts], 'asgnRef((void**) $1, copyString($2));$n',
             [addrLoc(dest), rdLoc(src)])
         end
         else begin
-          useMagic('unsureAsgnRef');
-          useMagic('copyString'); // BUGFIX
-          appRopeFormat(p.s[cpsStmts],
+          useMagic(p.module, 'unsureAsgnRef');
+          useMagic(p.module, 'copyString'); // BUGFIX
+          appf(p.s[cpsStmts],
             'unsureAsgnRef((void**) $1, copyString($2));$n',
             [addrLoc(dest), rdLoc(src)])
         end
       end
     end;
 
-    tyRecordConstr, tyRecord:
-      // BUGFIX
+    tyTuple:
       if needsComplexAssignment(dest.t) then begin
-        useMagic('genericAssign');
-        appRopeFormat(p.s[cpsStmts],
+        useMagic(p.module, 'genericAssign');
+        appf(p.s[cpsStmts],
           'genericAssign((void*)$1, (void*)$2, $3);$n',
-          [addrLoc(dest), addrLoc(src), genTypeInfo(currMod, dest.t)])
+          [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
       end
       else
-        appRopeFormat(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]);
+        appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]);
     tyArray, tyArrayConstr:
       if needsComplexAssignment(dest.t) then begin
-        useMagic('genericAssign');
-        appRopeFormat(p.s[cpsStmts],
+        useMagic(p.module, 'genericAssign');
+        appf(p.s[cpsStmts],
           'genericAssign((void*)$1, (void*)$2, $3);$n',
-          // XXX: is this correct for arrays?
-          [addrLoc(dest), addrLoc(src), genTypeInfo(currMod, dest.t)])
+          [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
       end
       else
-        appRopeFormat(p.s[cpsStmts],
-          'memcpy((void*)$1, (const void*)$2, sizeof($1));$n',
-          [addrLoc(dest), addrLoc(src)]);
+        appf(p.s[cpsStmts],
+          'memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n',
+          [rdLoc(dest), rdLoc(src)]);
     tyObject:
       // XXX: check for subtyping?
       if needsComplexAssignment(dest.t) then begin
-        useMagic('genericAssign');
-        appRopeFormat(p.s[cpsStmts],
+        useMagic(p.module, 'genericAssign');
+        appf(p.s[cpsStmts],
           'genericAssign((void*)$1, (void*)$2, $3);$n',
-          [addrLoc(dest), addrLoc(src), genTypeInfo(currMod, dest.t)])
+          [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
       end
       else
-        appRopeFormat(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]);
+        appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]);
     tyOpenArray: begin
-      // open arrays are always on the stack, really? What if a sequence is
+      // open arrays are always on the stack - really? What if a sequence is
       // passed to an open array?
       if needsComplexAssignment(dest.t) then begin
-        useMagic('genericAssignOpenArray');
-        appRopeFormat(p.s[cpsStmts],// XXX: is this correct for arrays?
+        useMagic(p.module, 'genericAssignOpenArray');
+        appf(p.s[cpsStmts],// XXX: is this correct for arrays?
           'genericAssignOpenArray((void*)$1, (void*)$2, $1Len0, $3);$n',
-          [addrLoc(dest), addrLoc(src), genTypeInfo(currMod, dest.t)])
+          [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
       end
       else
-        appRopeFormat(p.s[cpsStmts],
-          'memcpy((void*)$1, (const void*)$2, sizeof($1[0])*$1Len0);$n',
-          [addrLoc(dest), addrLoc(src)]);
+        appf(p.s[cpsStmts],
+          'memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len0);$n',
+          [rdLoc(dest), rdLoc(src)]);
     end;
     tySet:
-      if getSize(ty) <= 8 then
-        appRopeFormat(p.s[cpsStmts], '$1 = $2;$n',
-          [rdLoc(dest), rdLoc(src)])
+      if mapType(ty) = ctArray then
+        appf(p.s[cpsStmts], 'memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n',
+          [rdLoc(dest), rdLoc(src), toRope(getSize(dest.t))])
       else
-        appRopeFormat(p.s[cpsStmts], 'memcpy((void*)$1, (const void*)$2, $3);$n',
-          [rdLoc(dest), rdLoc(src), toRope(getSize(dest.t))]);
+        appf(p.s[cpsStmts], '$1 = $2;$n',
+          [rdLoc(dest), rdLoc(src)]);
     tyPtr, tyPointer, tyChar, tyBool, tyProc, tyEnum,
         tyCString, tyInt..tyFloat128, tyRange:
-      appRopeFormat(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]);
+      appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]);
     else
       InternalError('genAssignment(' + typeKindToStr[ty.kind] + ')')
   end
@@ -367,7 +339,7 @@ procedure expr(p: BProc; e: PNode; var d: TLoc); forward;
 
 function initLocExpr(p: BProc; e: PNode): TLoc;
 begin
-  result := initLoc(locNone, e.typ);
+  result := initLoc(locNone, getUniqueType(e.typ), OnUnknown);
   expr(p, e, result)
 end;
 
@@ -392,7 +364,7 @@ var
   a: TLoc;
 begin
   if d.k <> locNone then begin // need to generate an assignment here
-    a := initLoc(locExpr, t);
+    a := initLoc(locExpr, getUniqueType(t), OnUnknown);
     a.r := r;
     if lfNoDeepCopy in d.flags then
       genAssignment(p, d, a, {@set}[])
@@ -402,7 +374,7 @@ begin
   else begin // we cannot call initLoc() here as that would overwrite
              // the flags field!
     d.k := locExpr;
-    d.t := t;
+    d.t := getUniqueType(t);
     d.r := r;
     d.a := -1
   end
@@ -413,12 +385,11 @@ procedure binaryStmt(p: BProc; e: PNode; var d: TLoc;
 var
   a, b: TLoc;
 begin
-  assert(d.k = locNone);
-  if magic <> '' then
-    useMagic(magic);
+  if (d.k <> locNone) then InternalError(e.info, 'binaryStmt');
+  if magic <> '' then useMagic(p.module, magic);
   a := InitLocExpr(p, e.sons[1]);
   b := InitLocExpr(p, e.sons[2]);
-  appRopeFormat(p.s[cpsStmts], frmt, [rdLoc(a), rdLoc(b)]);
+  appf(p.s[cpsStmts], frmt, [rdLoc(a), rdLoc(b)]);
   freeTemp(p, a);
   freeTemp(p, b)
 end;
@@ -428,12 +399,11 @@ procedure binaryStmtChar(p: BProc; e: PNode; var d: TLoc;
 var
   a, b: TLoc;
 begin
-  assert(d.k = locNone);
-  if magic <> '' then
-    useMagic(magic);
+  if (d.k <> locNone) then InternalError(e.info, 'binaryStmtChar');
+  if magic <> '' then useMagic(p.module, magic);
   a := InitLocExpr(p, e.sons[1]);
   b := InitLocExpr(p, e.sons[2]);
-  appRopeFormat(p.s[cpsStmts], frmt, [rdCharLoc(a), rdCharLoc(b)]);
+  appf(p.s[cpsStmts], frmt, [rdCharLoc(a), rdCharLoc(b)]);
   freeTemp(p, a);
   freeTemp(p, b)
 end;
@@ -443,13 +413,12 @@ procedure binaryExpr(p: BProc; e: PNode; var d: TLoc;
 var
   a, b: TLoc;
 begin
-  if magic <> '' then
-    useMagic(magic);
+  if magic <> '' then useMagic(p.module, magic);
   assert(e.sons[1].typ <> nil);
   assert(e.sons[2].typ <> nil);
   a := InitLocExpr(p, e.sons[1]);
   b := InitLocExpr(p, e.sons[2]);
-  putIntoDest(p, d, e.typ, ropeFormat(frmt, [rdLoc(a), rdLoc(b)]));
+  putIntoDest(p, d, e.typ, ropef(frmt, [rdLoc(a), rdLoc(b)]));
   if d.k <> locExpr then begin // BACKPORT
     freeTemp(p, a);
     freeTemp(p, b)
@@ -461,13 +430,12 @@ procedure binaryExprChar(p: BProc; e: PNode; var d: TLoc;
 var
   a, b: TLoc;
 begin
-  if magic <> '' then
-    useMagic(magic);
+  if magic <> '' then useMagic(p.module, magic);
   assert(e.sons[1].typ <> nil);
   assert(e.sons[2].typ <> nil);
   a := InitLocExpr(p, e.sons[1]);
   b := InitLocExpr(p, e.sons[2]);
-  putIntoDest(p, d, e.typ, ropeFormat(frmt, [rdCharLoc(a), rdCharLoc(b)]));
+  putIntoDest(p, d, e.typ, ropef(frmt, [rdCharLoc(a), rdCharLoc(b)]));
   if d.k <> locExpr then begin // BACKPORT
     freeTemp(p, a);
     freeTemp(p, b)
@@ -479,10 +447,9 @@ procedure unaryExpr(p: BProc; e: PNode; var d: TLoc;
 var
   a: TLoc;
 begin
-  if magic <> '' then
-    useMagic(magic);
+  if magic <> '' then useMagic(p.module, magic);
   a := InitLocExpr(p, e.sons[1]);
-  putIntoDest(p, d, e.typ, ropeFormat(frmt, [rdLoc(a)]));
+  putIntoDest(p, d, e.typ, ropef(frmt, [rdLoc(a)]));
   if d.k <> locExpr then // BACKPORT
     freeTemp(p, a)
 end;
@@ -492,10 +459,9 @@ procedure unaryExprChar(p: BProc; e: PNode; var d: TLoc;
 var
   a: TLoc;
 begin
-  if magic <> '' then
-    useMagic(magic);
+  if magic <> '' then useMagic(p.module, magic);
   a := InitLocExpr(p, e.sons[1]);
-  putIntoDest(p, d, e.typ, ropeFormat(frmt, [rdCharLoc(a)]));
+  putIntoDest(p, d, e.typ, ropef(frmt, [rdCharLoc(a)]));
   if d.k <> locExpr then // BACKPORT
     freeTemp(p, a)
 end;
@@ -510,15 +476,15 @@ const
     '($1 + $2)', '($1 - $2)', '($1 * $2)', '($1 / $2)', '($1 % $2)'
   );
   binArithTab: array [mShrI..mXor] of string = (
-    '(NS)((NU)($1) >> (NU)($2))', // ShrI
-    '(NS)((NU)($1) << (NU)($2))', // ShlI
+    '(NI)((NU)($1) >> (NU)($2))', // ShrI
+    '(NI)((NU)($1) << (NU)($2))', // ShlI
     '($1 & $2)', // BitandI
     '($1 | $2)', // BitorI
     '($1 ^ $2)', // BitxorI
     '(($1 <= $2) ? $1 : $2)', // MinI
     '(($1 >= $2) ? $1 : $2)', // MaxI
-    '(NS64)((NU64)($1) >> (NU64)($2))', // ShrI64
-    '(NS64)((NU64)($1) << (NU64)($2))', // ShlI64
+    '(NI64)((NU64)($1) >> (NU64)($2))', // ShrI64
+    '(NI64)((NU64)($1) << (NU64)($2))', // ShlI64
     '($1 & $2)', // BitandI64
     '($1 | $2)', // BitorI64
     '($1 ^ $2)', // BitxorI64
@@ -532,16 +498,16 @@ const
     '(($1 <= $2) ? $1 : $2)', // MinF64
     '(($1 >= $2) ? $1 : $2)', // MaxF64
 
-    '(NS)((NU)($1) + (NU)($2))', // AddU
-    '(NS)((NU)($1) - (NU)($2))', // SubU
-    '(NS)((NU)($1) * (NU)($2))', // MulU
-    '(NS)((NU)($1) / (NU)($2))', // DivU
-    '(NS)((NU)($1) % (NU)($2))', // ModU
-    '(NS64)((NU64)($1) + (NU64)($2))', // AddU64
-    '(NS64)((NU64)($1) - (NU64)($2))', // SubU64
-    '(NS64)((NU64)($1) * (NU64)($2))', // MulU64
-    '(NS64)((NU64)($1) / (NU64)($2))', // DivU64
-    '(NS64)((NU64)($1) % (NU64)($2))', // ModU64
+    '(NI)((NU)($1) + (NU)($2))', // AddU
+    '(NI)((NU)($1) - (NU)($2))', // SubU
+    '(NI)((NU)($1) * (NU)($2))', // MulU
+    '(NI)((NU)($1) / (NU)($2))', // DivU
+    '(NI)((NU)($1) % (NU)($2))', // ModU
+    '(NI64)((NU64)($1) + (NU64)($2))', // AddU64
+    '(NI64)((NU64)($1) - (NU64)($2))', // SubU64
+    '(NI64)((NU64)($1) * (NU64)($2))', // MulU64
+    '(NI64)((NU64)($1) / (NU64)($2))', // DivU64
+    '(NI64)((NU64)($1) % (NU64)($2))', // ModU64
 
     '($1 == $2)', // EqI
     '($1 <= $2)', // LeI
@@ -587,11 +553,16 @@ const
     '-($1)',  // UnaryMinusF64
     '($1 > 0? ($1) : -($1))',  // AbsF64; BUGFIX: fabs() makes problems for Tiny C, so we don't use it
 
-    '((NS)(NU)($1))',  // Ze
-    '((NS64)(NU64)($1))', // Ze64
-    '((NS8)(NU8)(NU)($1))', // ToU8
-    '((NS16)(NU16)(NU)($1))', // ToU16
-    '((NS32)(NU32)(NU64)($1))', // ToU32
+    '((NI)(NU)(NU8)($1))', // mZe8ToI
+    '((NI64)(NU64)(NU8)($1))', // mZe8ToI64
+    '((NI)(NU)(NU16)($1))', // mZe16ToI
+    '((NI64)(NU64)(NU16)($1))', // mZe16ToI64
+    '((NI64)(NU64)(NU32)($1))', // mZe32ToI64
+    '((NI64)(NU64)(NU)($1))', // mZeIToI64
+
+    '((NI8)(NU8)(NU)($1))', // ToU8
+    '((NI16)(NU16)(NU)($1))', // ToU16
+    '((NI32)(NU32)(NU64)($1))', // ToU32
 
     '((double) ($1))', // ToFloat
     '((double) ($1))', // ToBiggestFloat
@@ -641,29 +612,42 @@ procedure genDeref(p: BProc; e: PNode; var d: TLoc);
 var
   a: TLoc;
 begin
-  a := initLocExpr(p, e.sons[0]);
-  putIntoDest(p, d, a.t.sons[0], ropeFormat('(*$1)', [rdLoc(a)]));
-  if d.k <> locExpr then // BACKPORT
-    freeTemp(p, a)
+  if mapType(e.sons[0].typ) = ctArray then
+    expr(p, e.sons[0], d)
+  else begin
+    a := initLocExpr(p, e.sons[0]);
+    case skipGeneric(a.t).kind of
+      tyRef: d.s := OnHeap;
+      tyVar: d.s := OnUnknown;
+      tyPtr: d.s := OnStack;
+      else InternalError(e.info, 'genDeref ' + typekindToStr[a.t.kind]);
+    end;
+    putIntoDest(p, d, a.t.sons[0], ropef('(*$1)', [rdLoc(a)]));
+  end
 end;
 
-procedure fillInLocation(var a, d: TLoc);
+procedure genAddr(p: BProc; e: PNode; var d: TLoc);
+var
+  a: TLoc;
 begin
-  case skipAbstract(a.t).kind of
-    tyRef: begin
-      if d.k = locNone then d.flags := {@set}[lfOnHeap];
-      a.r := ropeFormat('(*$1)', [a.r])
-    end;
-    tyPtr: begin
-      if d.k = locNone then d.flags := {@set}[lfOnUnknown];
-      a.r := ropeFormat('(*$1)', [a.r])
-    end;
-    // element has same flags as the array (except lfIndirect):
-    else
-      if d.k = locNone then inheritStorage(d, a)
+  if mapType(e.sons[0].typ) = ctArray then
+    expr(p, e.sons[0], d)
+  else begin
+    a := InitLocExpr(p, e.sons[0]);
+    putIntoDest(p, d, e.typ, addrLoc(a));
+    if d.k <> locExpr then freeTemp(p, a)
   end
 end;
 
+function genRecordFieldAux(p: BProc; e: PNode; var d, a: TLoc): PType;
+begin
+  a := initLocExpr(p, e.sons[0]);
+  if (e.sons[1].kind <> nkSym) then InternalError(e.info, 'genRecordFieldAux');
+  if d.k = locNone then d.s := a.s;
+  {@discard} getTypeDesc(p.module, a.t); // fill the record's fields.loc
+  result := getUniqueType(a.t);
+end;
+
 procedure genRecordField(p: BProc; e: PNode; var d: TLoc);
 var
   a: TLoc;
@@ -671,45 +655,76 @@ var
   ty: PType;
   r: PRope;
 begin
-  a := initLocExpr(p, e.sons[0]);
-  assert(e.sons[1].kind = nkSym);
-  f := e.sons[1].sym;
-
-  if d.k = locNone then inheritStorage(d, a);
-  // for objects we have to search the hierarchy for determining
-  // how much ``Sup`` we need:
-  ty := skipAbstract(a.t);
-  while true do begin
-    case ty.kind of
-      tyRef: begin
-        if d.k = locNone then d.flags := {@set}[lfOnHeap];
-        inc(a.indirect);
-      end;
-      tyPtr: begin
-        if d.k = locNone then d.flags := {@set}[lfOnUnknown];
-        inc(a.indirect);
-      end;
-      tyVar: begin
-        if d.k = locNone then d.flags := {@set}[lfOnUnknown];
-      end;
-      else break
-    end;
-    ty := skipAbstract(ty.sons[0]);
-  end;
+  ty := genRecordFieldAux(p, e, d, a);
   r := rdLoc(a);
-  {@discard} getTypeDesc(ty); // fill the record's fields.loc
+  f := e.sons[1].sym;
   field := nil;
   while ty <> nil do begin
-    assert(ty.kind in [tyRecord, tyObject]);
+    assert(ty.kind in [tyTuple, tyObject]);
     field := lookupInRecord(ty.n, f.name);
     if field <> nil then break;
     if gCmd <> cmdCompileToCpp then app(r, '.Sup');
-    ty := ty.sons[0]
+    ty := GetUniqueType(ty.sons[0]);
   end;
-  assert((field <> nil) and (field.loc.r <> nil));
-  appRopeFormat(r, '.$1', [field.loc.r]);
+  if field = nil then InternalError(e.info, 'genRecordField');
+  if field.loc.r = nil then InternalError(e.info, 'genRecordField');
+  appf(r, '.$1', [field.loc.r]);
   putIntoDest(p, d, field.typ, r);
-  // freeTemp(p, a) // BACKPORT
+end;
+
+procedure genInExprAux(p: BProc; e: PNode; var a, b, d: TLoc); forward;
+
+procedure genCheckedRecordField(p: BProc; e: PNode; var d: TLoc);
+var
+  a, u, v, test: TLoc;
+  f, field, op: PSym;
+  ty: PType;
+  r: PRope;
+  i: int;
+  it: PNode;
+begin
+  if optFieldCheck in p.options then begin
+    useMagic(p.module, 'raiseFieldError');
+    ty := genRecordFieldAux(p, e.sons[0], d, a);
+    r := rdLoc(a);
+    f := e.sons[0].sons[1].sym;
+    field := nil;
+    while ty <> nil do begin
+      assert(ty.kind in [tyTuple, tyObject]);
+      field := lookupInRecord(ty.n, f.name);
+      if field <> nil then break;
+      if gCmd <> cmdCompileToCpp then app(r, '.Sup');
+      ty := getUniqueType(ty.sons[0])
+    end;
+    if field = nil then InternalError(e.info, 'genCheckedRecordField');
+    if field.loc.r = nil then InternalError(e.info, 'genCheckedRecordField');
+    // generate the checks:
+    for i := 1 to sonsLen(e)-1 do begin
+      it := e.sons[i];
+      assert(it.kind = nkCall);
+      assert(it.sons[0].kind = nkSym);
+      op := it.sons[0].sym;
+      if op.magic = mNot then it := it.sons[1];
+      assert(it.sons[2].kind = nkSym);
+      test := initLoc(locNone, it.typ, OnStack);
+      u := InitLocExpr(p, it.sons[1]);
+      v := initLoc(locExpr, it.sons[2].typ, OnUnknown);
+      v.r := ropef('$1.$2', [r, it.sons[2].sym.loc.r]);
+      genInExprAux(p, it, u, v, test);
+      if op.magic = mNot then
+        appf(p.s[cpsStmts],
+          'if ($1) raiseFieldError(((string) &$2));$n',
+          [rdLoc(test), getStrLit(p.module, field.name.s)])
+      else
+        appf(p.s[cpsStmts],
+          'if (!($1)) raiseFieldError(((string) &$2));$n',
+          [rdLoc(test), getStrLit(p.module, field.name.s)])
+    end;
+    appf(r, '.$1', [field.loc.r]);
+    putIntoDest(p, d, field.typ, r);
+  end
+  else
+    genRecordField(p, e.sons[0], d)
 end;
 
 procedure genArrayElem(p: BProc; e: PNode; var d: TLoc);
@@ -720,19 +735,18 @@ var
 begin
   a := initLocExpr(p, e.sons[0]);
   b := initLocExpr(p, e.sons[1]);
-  ty := skipAbstract(a.t);
-  if ty.kind in [tyRef, tyPtr] then ty := skipAbstract(ty.sons[0]);
+  ty := skipPtrsGeneric(skipVarGenericRange(a.t));
   first := intLiteral(firstOrd(ty));
   // emit range check:
   if optBoundsCheck in p.options then
     if b.k <> locImmediate then begin // semantic pass has already checked:
-      useMagic('raiseIndexError');
-      appRopeFormat(p.s[cpsStmts],
+      useMagic(p.module, 'raiseIndexError');
+      appf(p.s[cpsStmts],
                'if ($1 < $2 || $1 > $3) raiseIndexError();$n',
                [rdCharLoc(b), first, intLiteral(lastOrd(ty))])
     end;
-  fillInLocation(a, d);
-  putIntoDest(p, d, elemType(skipVarGeneric(ty)), ropeFormat('$1[($2)-$3]',
+  if d.k = locNone then d.s := a.s;
+  putIntoDest(p, d, elemType(skipVarGeneric(ty)), ropef('$1[($2)-$3]',
     [rdLoc(a), rdCharLoc(b), first]));
   // freeTemp(p, a); // backport
   // freeTemp(p, b)
@@ -745,9 +759,9 @@ var
 begin
   a := initLocExpr(p, e.sons[0]);
   b := initLocExpr(p, e.sons[1]);
-  ty := skipAbstract(a.t);
-  fillInLocation(a, d);
-  putIntoDest(p, d, elemType(skipVarGeneric(ty)), ropeFormat('$1[$2]',
+  ty := skipVarGenericRange(a.t);
+  if d.k = locNone then d.s := a.s;
+  putIntoDest(p, d, elemType(skipVarGeneric(ty)), ropef('$1[$2]',
     [rdLoc(a), rdCharLoc(b)]));
   // freeTemp(p, a); // backport
   // freeTemp(p, b)
@@ -760,14 +774,13 @@ begin
   a := initLocExpr(p, e.sons[0]);
   b := initLocExpr(p, e.sons[1]);
   // emit range check:
-  if optBoundsCheck in p.options then
-    if b.k <> locImmediate then begin // semantic pass has already checked:
-      useMagic('raiseIndexError');
-      appRopeFormat(p.s[cpsStmts],
-        'if ((NU)($1) > (NU)($2Len0)) raiseIndexError();$n', [rdLoc(b), a.r])
-    end;
-  if d.k = locNone then inheritStorage(d, a);
-  putIntoDest(p, d, elemType(skipVarGeneric(a.t)), ropeFormat('$1[$2]',
+  if optBoundsCheck in p.options then begin
+    useMagic(p.module, 'raiseIndexError');
+    appf(p.s[cpsStmts],
+      'if ((NU)($1) > (NU)($2Len0)) raiseIndexError();$n', [rdLoc(b), a.r])
+  end;
+  if d.k = locNone then d.s := a.s;
+  putIntoDest(p, d, elemType(skipVarGeneric(a.t)), ropef('$1[$2]',
     [rdLoc(a), rdCharLoc(b)]));
   // freeTemp(p, a); // backport
   // freeTemp(p, b)
@@ -780,26 +793,24 @@ var
 begin
   a := initLocExpr(p, e.sons[0]);
   b := initLocExpr(p, e.sons[1]);
-  ty := skipAbstract(a.t);
-  if ty.kind in [tyRef, tyPtr] then ty := skipAbstract(ty.sons[0]);
+  ty := skipVarGenericRange(a.t);
+  if ty.kind in [tyRef, tyPtr] then ty := skipVarGenericRange(ty.sons[0]);
   // emit range check:
-  if optBoundsCheck in p.options then
-    if b.k <> locImmediate then begin // semantic pass has already checked:
-      useMagic('raiseIndexError');
-      if ty.kind = tyString then
-        appRopeFormat(p.s[cpsStmts],
-          'if ((NU)($1) > (NU)($2->len)) raiseIndexError();$n',
-          [rdLoc(b), rdLoc(a)])
-      else
-        appRopeFormat(p.s[cpsStmts],
-          'if ((NU)($1) >= (NU)($2->len)) raiseIndexError();$n',
-          [rdLoc(b), rdLoc(a)])
-    end;
-  // element has same flags as the array (except lfIndirect):
-  if d.k = locNone then d.flags := {@set}[lfOnHeap];
-  if skipAbstract(a.t).kind in [tyRef, tyPtr] then
-    a.r := ropeFormat('(*$1)', [a.r]);
-  putIntoDest(p, d, elemType(skipVarGeneric(a.t)), ropeFormat('$1->data[$2]',
+  if optBoundsCheck in p.options then begin
+    useMagic(p.module, 'raiseIndexError');
+    if ty.kind = tyString then
+      appf(p.s[cpsStmts],
+        'if ((NU)($1) > (NU)($2->len)) raiseIndexError();$n',
+        [rdLoc(b), rdLoc(a)])
+    else
+      appf(p.s[cpsStmts],
+        'if ((NU)($1) >= (NU)($2->len)) raiseIndexError();$n',
+        [rdLoc(b), rdLoc(a)])
+  end;
+  if d.k = locNone then d.s := OnHeap;
+  if skipVarGenericRange(a.t).kind in [tyRef, tyPtr] then
+    a.r := ropef('(*$1)', [a.r]);
+  putIntoDest(p, d, elemType(skipVarGeneric(a.t)), ropef('$1->data[$2]',
     [rdLoc(a), rdCharLoc(b)]));
   // freeTemp(p, a); // backport
   // freeTemp(p, b)
@@ -834,9 +845,9 @@ begin
   expr(p, e.sons[1], tmp);
   L := getLabel(p);
   if m = mOr then
-    appRopeFormat(p.s[cpsStmts], 'if ($1) goto $2;$n', [rdLoc(tmp), L])
+    appf(p.s[cpsStmts], 'if ($1) goto $2;$n', [rdLoc(tmp), L])
   else // mAnd:
-    appRopeFormat(p.s[cpsStmts], 'if (!($1)) goto $2;$n', [rdLoc(tmp), L]);
+    appf(p.s[cpsStmts], 'if (!($1)) goto $2;$n', [rdLoc(tmp), L]);
   expr(p, e.sons[2], tmp);
   fixLabel(p, L);
   if d.k = locNone then
@@ -874,10 +885,10 @@ begin
       nkElifExpr: begin
         a := initLocExpr(p, it.sons[0]);
         Lelse := getLabel(p);
-        appRopeFormat(p.s[cpsStmts], 'if (!$1) goto $2;$n', [rdLoc(a), Lelse]);
+        appf(p.s[cpsStmts], 'if (!$1) goto $2;$n', [rdLoc(a), Lelse]);
         freeTemp(p, a);
         expr(p, it.sons[1], tmp);
-        appRopeFormat(p.s[cpsStmts], 'goto $1;$n', [Lend]);
+        appf(p.s[cpsStmts], 'goto $1;$n', [Lend]);
         fixLabel(p, Lelse);
       end;
       nkElseExpr: begin
@@ -905,9 +916,12 @@ var
   op, list: TLoc;
   len, i: int;
 begin
+{@emit
+  a := [];
+}
   op := initLocExpr(p, t.sons[0]);
   pl := con(op.r, '('+'');
-  typ := t.sons[0].typ;
+  typ := getUniqueType(t.sons[0].typ);
   assert(typ.kind = tyProc);
   invalidRetType := isInvalidReturnType(typ.sons[0]);
   len := sonsLen(t);
@@ -918,8 +932,8 @@ begin
     if (i < sonsLen(typ)) then begin
       assert(typ.n.sons[i].kind = nkSym);
       param := typ.n.sons[i].sym;
-      if usePtrPassing(param) then app(pl, addrLoc(a[i-1]))
-      else                         app(pl, rdLoc(a[i-1]));
+      if ccgIntroducedPtr(param) then app(pl, addrLoc(a[i-1]))
+      else                            app(pl, rdLoc(a[i-1]));
     end
     else
       app(pl, rdLoc(a[i-1]));
@@ -928,7 +942,7 @@ begin
   end;
   if (typ.sons[0] <> nil) and invalidRetType then begin
     if d.k = locNone then d := getTemp(p, typ.sons[0]);
-    app(pl, addrLoc(d))
+    app(pl, addrLoc(d));
   end;
   app(pl, ')'+'');
   for i := 0 to high(a) do
@@ -938,12 +952,12 @@ begin
     if d.k = locNone then d := getTemp(p, typ.sons[0]);
     assert(d.t <> nil);
     // generate an assignment to d:
-    list := initLoc(locCall, nil);
+    list := initLoc(locCall, nil, OnUnknown);
     list.r := pl;
     genAssignment(p, d, list, {@set}[]) // no need for deep copying
   end
   else
-    appRopeFormat(p.s[cpsStmts], '$1;$n', [pl])
+    appf(p.s[cpsStmts], '$1;$n', [pl])
 end;
 
 procedure genStrConcat(p: BProc; e: PNode; var d: TLoc);
@@ -969,30 +983,33 @@ var
   appends, lens: PRope;
   L, i: int;
 begin
-  useMagic('rawNewString');
+  useMagic(p.module, 'rawNewString');
   tmp := getTemp(p, e.typ);
   L := 0;
   appends := nil;
   lens := nil;
+{@emit
+  a := [];
+}
   setLength(a, sonsLen(e)-1);
   for i := 0 to sonsLen(e)-2 do begin
     // compute the length expression:
     a[i] := initLocExpr(p, e.sons[i+1]);
-    if skipAbstract(e.sons[i+1].Typ).kind = tyChar then begin
+    if skipVarGenericRange(e.sons[i+1].Typ).kind = tyChar then begin
       Inc(L);
-      useMagic('appendChar');
-      appRopeFormat(appends, 'appendChar($1, $2);$n', [tmp.r, rdLoc(a[i])])
+      useMagic(p.module, 'appendChar');
+      appf(appends, 'appendChar($1, $2);$n', [tmp.r, rdLoc(a[i])])
     end
     else begin
       if e.sons[i+1].kind in [nkStrLit..nkTripleStrLit] then  // string literal?
         Inc(L, length(e.sons[i+1].strVal))
       else
-        appRopeFormat(lens, '$1->len + ', [rdLoc(a[i])]);
-      useMagic('appendString');
-      appRopeFormat(appends, 'appendString($1, $2);$n', [tmp.r, rdLoc(a[i])])
+        appf(lens, '$1->len + ', [rdLoc(a[i])]);
+      useMagic(p.module, 'appendString');
+      appf(appends, 'appendString($1, $2);$n', [tmp.r, rdLoc(a[i])])
     end
   end;
-  appRopeFormat(p.s[cpsStmts], '$1 = rawNewString($2$3);$n',
+  appf(p.s[cpsStmts], '$1 = rawNewString($2$3);$n',
     [tmp.r, lens, toRope(L)]);
   app(p.s[cpsStmts], appends);
   for i := 0 to high(a) do
@@ -1023,32 +1040,35 @@ var
   appends, lens: PRope;
 begin
   assert(d.k = locNone);
-  useMagic('resizeString');
+  useMagic(p.module, 'resizeString');
   L := 0;
   appends := nil;
   lens := nil;
+{@emit
+  a := [];
+}
   setLength(a, sonsLen(e)-1);
   expr(p, e.sons[1], a[0]);
   for i := 0 to sonsLen(e)-3 do begin
     // compute the length expression:
     a[i+1] := initLocExpr(p, e.sons[i+2]);
-    if skipAbstract(e.sons[i+2].Typ).kind = tyChar then begin
+    if skipVarGenericRange(e.sons[i+2].Typ).kind = tyChar then begin
       Inc(L);
-      useMagic('appendChar');
-      appRopeFormat(appends, 'appendChar($1, $2);$n',
+      useMagic(p.module, 'appendChar');
+      appf(appends, 'appendChar($1, $2);$n',
         [rdLoc(a[0]), rdLoc(a[i+1])])
     end
     else begin
       if e.sons[i+2].kind in [nkStrLit..nkTripleStrLit] then  // string literal?
         Inc(L, length(e.sons[i+2].strVal))
       else
-        appRopeFormat(lens, '$1->len + ', [rdLoc(a[i+1])]);
-      useMagic('appendString');
-      appRopeFormat(appends, 'appendString($1, $2);$n',
+        appf(lens, '$1->len + ', [rdLoc(a[i+1])]);
+      useMagic(p.module, 'appendString');
+      appf(appends, 'appendString($1, $2);$n',
         [rdLoc(a[0]), rdLoc(a[i+1])])
     end
   end;
-  appRopeFormat(p.s[cpsStmts], '$1 = resizeString($1, $2$3);$n',
+  appf(p.s[cpsStmts], '$1 = resizeString($1, $2$3);$n',
     [rdLoc(a[0]), lens, toRope(L)]);
   app(p.s[cpsStmts], appends);
   for i := 0 to high(a) do
@@ -1062,16 +1082,15 @@ procedure genSeqElemAppend(p: BProc; e: PNode; var d: TLoc);
 var
   a, b, dest: TLoc;
 begin
-  useMagic('incrSeq');
+  useMagic(p.module, 'incrSeq');
   a := InitLocExpr(p, e.sons[1]);
   b := InitLocExpr(p, e.sons[2]);
-  appRopeFormat(p.s[cpsStmts],
+  appf(p.s[cpsStmts],
     '$1 = ($2) incrSeq((TGenericSeq*) $1, sizeof($3));$n',
-    [rdLoc(a), getTypeDesc(skipVarGeneric(e.sons[1].typ)),
-    getTypeDesc(skipVarGeneric(e.sons[2].Typ))]);
-  dest := initLoc(locExpr, b.t);
-  dest.flags := {@set}[lfOnHeap];
-  dest.r := ropeFormat('$1->data[$1->len-1]', [rdLoc(a)]);
+    [rdLoc(a), getTypeDesc(p.module, skipVarGeneric(e.sons[1].typ)),
+    getTypeDesc(p.module, skipVarGeneric(e.sons[2].Typ))]);
+  dest := initLoc(locExpr, b.t, OnHeap);
+  dest.r := ropef('$1->data[$1->len-1]', [rdLoc(a)]);
   genAssignment(p, dest, b, {@set}[needToCopy]);
   freeTemp(p, a);
   freeTemp(p, b)
@@ -1082,22 +1101,20 @@ var
   a, b: TLoc;
   reftype, bt: PType;
 begin
-  useMagic('newObj');
-  refType := skipAbstract(e.sons[1].typ);
-  if refType.kind = tyVar then refType := skipAbstract(refType.sons[0]);
+  useMagic(p.module, 'newObj');
+  refType := skipVarGenericRange(e.sons[1].typ);
   a := InitLocExpr(p, e.sons[1]);
-  b := initLoc(locExpr, a.t);
-  b.flags := {@set}[lfOnHeap];
-  b.r := ropeFormat('($1) newObj($2, sizeof($3))',
-    [getTypeDesc(reftype), genTypeInfo(currMod, refType),
-    getTypeDesc(skipAbstract(reftype.sons[0]))]);
+  b := initLoc(locExpr, a.t, OnHeap);
+  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 := skipAbstract(refType.sons[0]);
+  bt := skipGenericRange(refType.sons[0]);
   if containsObject(bt) then begin
-    useMagic('objectInit');
-    appRopeFormat(p.s[cpsStmts], 'objectInit($1, $2);$n',
-                  [rdLoc(a), genTypeInfo(currMod, bt)])
+    useMagic(p.module, 'objectInit');
+    appf(p.s[cpsStmts], 'objectInit($1, $2);$n',
+        [rdLoc(a), genTypeInfo(p.module, bt)])
   end;
   freeTemp(p, a)
 end;
@@ -1108,26 +1125,24 @@ var
   refType, bt: PType;
   ti: PRope;
 begin
-  useMagic('newObj');
-  refType := skipAbstract(e.sons[1].typ);
-  if refType.kind = tyVar then refType := skipAbstract(refType.sons[0]);
+  useMagic(p.module, 'newObj');
+  refType := skipVarGenericRange(e.sons[1].typ);
   a := InitLocExpr(p, e.sons[1]);
   f := InitLocExpr(p, e.sons[2]);
-  b := initLoc(locExpr, a.t);
-  b.flags := {@set}[lfOnHeap];
-  ti := genTypeInfo(currMod, refType);
-  appRopeFormat(currMod.s[cfsTypeInit3], '$1->finalizer = (void*)$2;$n', [
+  b := initLoc(locExpr, a.t, OnHeap);
+  ti := genTypeInfo(p.module, refType);
+  appf(p.module.s[cfsTypeInit3], '$1->finalizer = (void*)$2;$n', [
     ti, rdLoc(f)]);
-  b.r := ropeFormat('($1) newObj($2, sizeof($3))',
-                   [getTypeDesc(refType), ti,
-                    getTypeDesc(skipAbstract(reftype.sons[0]))]);
+  b.r := ropef('($1) newObj($2, sizeof($3))',
+                   [getTypeDesc(p.module, refType), ti,
+                    getTypeDesc(p.module, skipGenericRange(reftype.sons[0]))]);
   genAssignment(p, a, b, {@set}[]);
   // set the object type:
-  bt := skipAbstract(refType.sons[0]);
+  bt := skipGenericRange(refType.sons[0]);
   if containsObject(bt) then begin
-    useMagic('objectInit');
-    appRopeFormat(p.s[cpsStmts], 'objectInit($1, $2);$n',
-                  [rdLoc(a), genTypeInfo(currMod, bt)])
+    useMagic(p.module, 'objectInit');
+    appf(p.s[cpsStmts], 'objectInit($1, $2);$n',
+                  [rdLoc(a), genTypeInfo(p.module, bt)])
   end;
   freeTemp(p, a);
   freeTemp(p, f)
@@ -1139,67 +1154,92 @@ var
   t: PType;
 begin
   a := InitLocExpr(p, e.sons[1]);
-  t := skipAbstract(e.sons[1].typ);
+  t := skipVarGenericRange(e.sons[1].typ);
   case t.kind of
     tyInt..tyInt64: begin
-      UseMagic('reprInt');
-      putIntoDest(p, d, e.typ, ropeFormat('reprInt($1)', [rdLoc(a)]))
+      UseMagic(p.module, 'reprInt');
+      putIntoDest(p, d, e.typ, ropef('reprInt($1)', [rdLoc(a)]))
     end;
     tyFloat..tyFloat128: begin
-      UseMagic('reprFloat');
-      putIntoDest(p, d, e.typ, ropeFormat('reprFloat($1)', [rdLoc(a)]))
+      UseMagic(p.module, 'reprFloat');
+      putIntoDest(p, d, e.typ, ropef('reprFloat($1)', [rdLoc(a)]))
     end;
     tyBool: begin
-      UseMagic('reprBool');
-      putIntoDest(p, d, e.typ, ropeFormat('reprBool($1)', [rdLoc(a)]))
+      UseMagic(p.module, 'reprBool');
+      putIntoDest(p, d, e.typ, ropef('reprBool($1)', [rdLoc(a)]))
     end;
     tyChar: begin
-      UseMagic('reprChar');
-      putIntoDest(p, d, e.typ, ropeFormat('reprChar($1)', [rdLoc(a)]))
+      UseMagic(p.module, 'reprChar');
+      putIntoDest(p, d, e.typ, ropef('reprChar($1)', [rdLoc(a)]))
     end;
     tyEnum: begin
-      UseMagic('reprEnum');
+      UseMagic(p.module, 'reprEnum');
       putIntoDest(p, d, e.typ,
-        ropeFormat('reprEnum($1, $2)', [rdLoc(a), genTypeInfo(currMod, t)]))
+        ropef('reprEnum($1, $2)', [rdLoc(a), genTypeInfo(p.module, t)]))
     end;
     tyString: begin
-      UseMagic('reprStr');
-      putIntoDest(p, d, e.typ, ropeFormat('reprStr($1)', [rdLoc(a)]))
+      UseMagic(p.module, 'reprStr');
+      putIntoDest(p, d, e.typ, ropef('reprStr($1)', [rdLoc(a)]))
     end;
     tySet: begin
-      useMagic('reprSet');
-      putIntoDest(p, d, e.typ, ropeFormat('reprSet($1, $2)',
-        [rdLoc(a), genTypeInfo(currMod, t)]))
+      useMagic(p.module, 'reprSet');
+      putIntoDest(p, d, e.typ, ropef('reprSet($1, $2)',
+        [rdLoc(a), genTypeInfo(p.module, t)]))
     end;
-    tyCString, tyArray, tyOpenArray, tyArrayConstr,
-       tyRef, tyPtr, tyPointer, tyNil: begin
-      useMagic('reprAny');
-      putIntoDest(p, d, e.typ, ropeFormat('reprAny($1, $2)',
-        [rdLoc(a), genTypeInfo(currMod, t)]))
+    tyOpenArray: begin
+      useMagic(p.module, 'reprOpenArray');
+      case a.t.kind of
+        tyOpenArray:
+          putIntoDest(p, d, e.typ, ropef('$1, $1Len0', [rdLoc(a)]));
+        tyString, tySequence:
+          putIntoDest(p, d, e.typ, ropef('$1->data, $1->len', [rdLoc(a)]));
+        tyArray, tyArrayConstr:
+          putIntoDest(p, d, e.typ, ropef('$1, $2',
+            [rdLoc(a), toRope(lengthOrd(a.t))]));
+        else InternalError(e.sons[0].info, 'genRepr()')
+      end;
+      putIntoDest(p, d, e.typ, ropef('reprOpenArray($1, $2)',
+        [rdLoc(d), genTypeInfo(p.module, elemType(t))]))
+    end;
+    tyCString, tyArray, tyArrayConstr,
+       tyRef, tyPtr, tyPointer, tyNil, tySequence: begin
+      useMagic(p.module, 'reprAny');
+      putIntoDest(p, d, e.typ, ropef('reprAny($1, $2)',
+        [rdLoc(a), genTypeInfo(p.module, t)]))
     end
     else begin
-      useMagic('reprAny');
-      putIntoDest(p, d, e.typ, ropeFormat('reprAny($1, $2)',
-        [addrLoc(a), genTypeInfo(currMod, t)]))
+      useMagic(p.module, 'reprAny');
+      putIntoDest(p, d, e.typ, ropef('reprAny($1, $2)',
+        [addrLoc(a), genTypeInfo(p.module, t)]))
     end
   end;
   if d.k <> locExpr then
     freeTemp(p, a);
 end;
 
+procedure genDollar(p: BProc; n: PNode; var d: TLoc; const magic, frmt: string);
+var
+  a: TLoc;
+begin
+  a := InitLocExpr(p, n.sons[1]);
+  UseMagic(p.module, magic);
+  putIntoDest(p, d, n.typ, ropef(frmt, [rdLoc(a)]))
+end;
+
 procedure genArrayLen(p: BProc; e: PNode; var d: TLoc; op: TMagic);
 var
   typ: PType;
 begin
-  typ := skipAbstract(e.sons[1].Typ);
-  if typ.kind in [tyRef, tyPtr, tyVar] then
-    typ := skipAbstract(typ.sons[0]);
+  typ := skipPtrsGeneric(e.sons[1].Typ);
   case typ.kind of
-    tyOpenArray:
+    tyOpenArray: begin
+      while e.sons[1].kind = nkPassAsOpenArray do
+        e.sons[1] := e.sons[1].sons[0];
       if op = mHigh then
         unaryExpr(p, e, d, '', '($1Len0-1)')
       else
-        unaryExpr(p, e, d, '', '$1Len0');
+        unaryExpr(p, e, d, '', '$1Len0/*len*/');
+    end;
     tyString, tySequence:
       if op = mHigh then
         unaryExpr(p, e, d, '', '($1->len-1)')
@@ -1223,13 +1263,14 @@ var
   t: PType;
 begin
   assert(d.k = locNone);
-  useMagic('setLengthSeq');
+  useMagic(p.module, 'setLengthSeq');
   a := InitLocExpr(p, e.sons[1]);
   b := InitLocExpr(p, e.sons[2]);
   t := skipVarGeneric(e.sons[1].typ);
-  appRopeFormat(p.s[cpsStmts],
+  appf(p.s[cpsStmts],
     '$1 = ($3) setLengthSeq((TGenericSeq*) ($1), sizeof($4), $2);$n',
-    [rdLoc(a), rdLoc(b), getTypeDesc(t), getTypeDesc(t.sons[0])]);
+    [rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
+    getTypeDesc(p.module, t.sons[0])]);
   freeTemp(p, a);
   freeTemp(p, b)
 end;
@@ -1265,16 +1306,15 @@ begin
   result := rdCharLoc(a);
   assert(setType.kind = tySet);
   if (firstOrd(setType) <> 0) then
-    result := ropeFormat('($1-$2)', [result, toRope(firstOrd(setType))])
+    result := ropef('($1-$2)', [result, toRope(firstOrd(setType))])
 end;
 
 function fewCmps(s: PNode): bool;
 // this function estimates whether it is better to emit code
 // for constructing the set or generating a bunch of comparisons directly
 begin
-  assert(s.kind in [nkSetConstr, nkConstSetConstr]);
-  if (getSize(s.typ) <= platform.intSize) and
-      (s.kind = nkConstSetConstr) then
+  if s.kind <> nkCurly then InternalError(s.info, 'fewCmps');
+  if (getSize(s.typ) <= platform.intSize) and (nfAllConst in s.flags) then
     result := false      // it is better to emit the set generation code
   else if elemType(s.typ).Kind in [tyInt, tyInt16..tyInt64] then
     result := true       // better not emit the set if int is basetype!
@@ -1282,21 +1322,27 @@ begin
     result := sonsLen(s) <= 8 // 8 seems to be a good value
 end;
 
-procedure binaryExprIn(p: BProc; e: PNode; var d: TLoc; const frmt: string);
-var
-  a, b: TLoc;
+procedure binaryExprIn(p: BProc; e: PNode; var a, b, d: TLoc;
+                       const frmt: string);
 begin
-  assert(e.sons[1].typ <> nil);
-  assert(e.sons[2].typ <> nil);
-  a := InitLocExpr(p, e.sons[1]);
-  b := InitLocExpr(p, e.sons[2]);
-  putIntoDest(p, d, e.typ, ropeFormat(frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]));
+  putIntoDest(p, d, e.typ, ropef(frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]));
   if d.k <> locExpr then begin
     freeTemp(p, a);
     freeTemp(p, b)
   end
 end;
 
+procedure genInExprAux(p: BProc; e: PNode; var a, b, d: TLoc);
+begin
+  case int(getSize(skipVarGeneric(e.sons[1].typ))) of
+    1: binaryExprIn(p, e, a, b, d, '(($1 &(1<<(($2)&7)))!=0)');
+    2: binaryExprIn(p, e, a, b, d, '(($1 &(1<<(($2)&15)))!=0)');
+    4: binaryExprIn(p, e, a, b, d, '(($1 &(1<<(($2)&31)))!=0)');
+    8: binaryExprIn(p, e, a, b, d, '(($1 &(IL64(1)<<(($2)&IL64(63))))!=0)');
+    else binaryExprIn(p, e, a, b, d, '(($1[$2/8] &(1<<($2%8)))!=0)');
+  end
+end;
+
 procedure binaryStmtInExcl(p: BProc; e: PNode; var d: TLoc; const frmt: string);
 var
   a, b: TLoc;
@@ -1304,7 +1350,7 @@ begin
   assert(d.k = locNone);
   a := InitLocExpr(p, e.sons[1]);
   b := InitLocExpr(p, e.sons[2]);
-  appRopeFormat(p.s[cpsStmts], frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]);
+  appf(p.s[cpsStmts], frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]);
   freeTemp(p, a);
   freeTemp(p, b)
 end;
@@ -1315,25 +1361,26 @@ var
   c: array of TLoc;  // Generate code for the 'in' operator
   len, i: int;
 begin
-  if (e.sons[1].Kind = nkSetConstr) and fewCmps(e.sons[1]) then begin
+  if (e.sons[1].Kind = nkCurly) and fewCmps(e.sons[1]) then begin
     // a set constructor but not a constant set:
     // do not emit the set, but generate a bunch of comparisons
     a := initLocExpr(p, e.sons[2]);
-    b := initLoc(locExpr, e.typ);
+    b := initLoc(locExpr, e.typ, OnUnknown);
     b.r := toRope('('+'');
     len := sonsLen(e.sons[1]);
+    {@emit c := [];}
     for i := 0 to len-1 do begin
       if e.sons[1].sons[i].Kind = nkRange then begin
         setLength(c, length(c)+2);
         c[high(c)-1] := InitLocExpr(p, e.sons[1].sons[i].sons[0]);
         c[high(c)] := InitLocExpr(p, e.sons[1].sons[i].sons[1]);
-        appRopeFormat(b.r, '$1 >= $2 && $1 <= $3',
+        appf(b.r, '$1 >= $2 && $1 <= $3',
           [rdCharLoc(a), rdCharLoc(c[high(c)-1]), rdCharLoc(c[high(c)])])
       end
       else begin
         setLength(c, length(c)+1);
         c[high(c)] := InitLocExpr(p, e.sons[1].sons[i]);
-        appRopeFormat(b.r, '$1 == $2', [rdCharLoc(a), rdCharLoc(c[high(c)])])
+        appf(b.r, '$1 == $2', [rdCharLoc(a), rdCharLoc(c[high(c)])])
       end;
       if i < len - 1 then
         app(b.r, ' || ')
@@ -1346,13 +1393,11 @@ begin
     end
   end
   else begin
-    case int(getSize(skipVarGeneric(e.sons[1].typ))) of
-      1: binaryExprIn(p, e, d, '(($1 &(1<<(($2)&7)))!=0)');
-      2: binaryExprIn(p, e, d, '(($1 &(1<<(($2)&15)))!=0)');
-      4: binaryExprIn(p, e, d, '(($1 &(1<<(($2)&31)))!=0)');
-      8: binaryExprIn(p, e, d, '(($1 &(1<<(($2)&63)))!=0)');
-      else binaryExprIn(p, e, d, '(($1[$2/8] &(1<<($2%8)))!=0)');
-    end
+    assert(e.sons[1].typ <> nil);
+    assert(e.sons[2].typ <> nil);
+    a := InitLocExpr(p, e.sons[1]);
+    b := InitLocExpr(p, e.sons[2]);
+    genInExprAux(p, e, a, b, d);
   end
 end;
 
@@ -1373,20 +1418,19 @@ var
   a, b, i: TLoc;
   ts: string;
 begin
-  setType := e.sons[1].Typ;
-  if setType.kind = tyVar then setType := skipAbstract(setType.sons[0]);
+  setType := skipVarGeneric(e.sons[1].Typ);
   size := int(getSize(setType));
   case size of
     1, 2, 4, 8: begin
       case op of
         mIncl: begin
-          ts := 'NS' + toString(size*8);
+          ts := 'NI' + toString(size*8);
           binaryStmtInExcl(p, e, d,
-            '$1 |=(1<<((' +{&} ts +{&} ')($2)%(sizeof(' +{&} ts +{&} 
+            '$1 |=(1<<((' +{&} ts +{&} ')($2)%(sizeof(' +{&} ts +{&}
             ')*8)));$n');
         end;
         mExcl: begin
-          ts := 'NS' + toString(size*8);
+          ts := 'NI' + toString(size*8);
           binaryStmtInExcl(p, e, d,
             '$1 &= ~(1 << ((' +{&} ts +{&} ')($2) % (sizeof(' +{&} ts +{&}
             ')*8)));$n');
@@ -1420,7 +1464,7 @@ begin
           b := initLocExpr(p, e.sons[2]);
           if d.k = locNone then
             d := getTemp(p, a.t);
-          appRopeFormat(p.s[cpsStmts], lookupOpr[op], [rdLoc(i), toRope(size),
+          appf(p.s[cpsStmts], lookupOpr[op], [rdLoc(i), toRope(size),
             rdLoc(d), rdLoc(a), rdLoc(b)]);
           freeTemp(p, a);
           freeTemp(p, b);
@@ -1436,7 +1480,7 @@ begin
           b := initLocExpr(p, e.sons[2]);
           if d.k = locNone then
             d := getTemp(p, a.t);
-          appRopeFormat(p.s[cpsStmts],
+          appf(p.s[cpsStmts],
             'for ($1 = 0; $1 < $2; $1++) $n' +
             '  $3[$1] = $4[$1] $6 $5[$1];$n', [rdLoc(i), toRope(size),
             rdLoc(d), rdLoc(a), rdLoc(b), toRope(lookupOpr[op])]);
@@ -1453,6 +1497,98 @@ end;
 
 // --------------------- end of set operations ----------------------------
 
+procedure genOrd(p: BProc; e: PNode; var d: TLoc);
+begin
+  unaryExprChar(p, e, d, '', '$1');
+end;
+
+procedure genCast(p: BProc; e: PNode; var d: TLoc);
+const
+  ValueTypes = {@set}[tyTuple, tyObject, tyArray, tyOpenArray, tyArrayConstr];
+// we use whatever C gives us. Except if we have a value-type, we
+// need to go through its address:
+var
+  a: TLoc;
+begin
+  a := InitLocExpr(p, e.sons[1]);
+  if (skipGenericRange(e.typ).kind in ValueTypes)
+  and not (lfIndirect in a.flags) then
+    putIntoDest(p, d, e.typ, ropef('(*($1*) ($2))',
+      [getTypeDesc(p.module, e.typ), addrLoc(a)]))
+  else
+    putIntoDest(p, d, e.typ, ropef('(($1) ($2))',
+      [getTypeDesc(p.module, e.typ), rdCharLoc(a)]));
+  if d.k <> locExpr then freeTemp(p, a)
+end;
+
+procedure genRangeChck(p: BProc; n: PNode; var d: TLoc; const magic: string);
+var
+  a: TLoc;
+  dest: PType;
+begin
+  dest := skipVarGeneric(n.typ);
+  if not (optRangeCheck in p.options) then begin
+    a := InitLocExpr(p, n.sons[0]);
+    putIntoDest(p, d, n.typ, ropef('(($1) ($2))',
+      [getTypeDesc(p.module, dest), rdCharLoc(a)]));
+  end
+  else begin
+    a := InitLocExpr(p, n.sons[0]);
+    useMagic(p.module, magic);
+    putIntoDest(p, d, dest,
+      ropef('(($1)' +{&} magic +{&} '($2, $3, $4))',
+        [getTypeDesc(p.module, dest),
+         rdCharLoc(a), genLiteral(p, n.sons[1], dest),
+                       genLiteral(p, n.sons[2], dest)]));
+    if d.k <> locExpr then freeTemp(p, a)
+  end
+end;
+
+procedure genConv(p: BProc; e: PNode; var d: TLoc);
+begin
+  genCast(p, e, d)
+end;
+
+procedure passToOpenArray(p: BProc; n: PNode; var d: TLoc);
+var
+  a: TLoc;
+  dest: PType;
+begin
+  dest := skipVarGeneric(n.typ);
+  a := initLocExpr(p, n.sons[0]);
+  case a.t.kind of
+    tyOpenArray:
+      putIntoDest(p, d, dest, ropef('$1, $1Len0', [rdLoc(a)]));
+    tyString, tySequence:
+      putIntoDest(p, d, dest, ropef('$1->data, $1->len', [rdLoc(a)]));
+    tyArray, tyArrayConstr:
+      putIntoDest(p, d, dest, ropef('$1, $2',
+        [rdLoc(a), toRope(lengthOrd(a.t))]));
+    else InternalError(n.sons[0].info, 'passToOpenArray()')
+  end;
+  if d.k <> locExpr then freeTemp(p, a)
+end;
+
+procedure convStrToCStr(p: BProc; n: PNode; var d: TLoc);
+var
+  a: TLoc;
+begin
+  a := initLocExpr(p, n.sons[0]);
+  putIntoDest(p, d, skipVarGeneric(n.typ), ropef('$1->data', [rdLoc(a)]));
+  if d.k <> locExpr then freeTemp(p, a)
+end;
+
+procedure convCStrToStr(p: BProc; n: PNode; var d: TLoc);
+var
+  a: TLoc;
+begin
+  useMagic(p.module, 'cstrToNimstr');
+  a := initLocExpr(p, n.sons[0]);
+  putIntoDest(p, d, skipVarGeneric(n.typ),
+              ropef('cstrToNimstr($1)', [rdLoc(a)]));
+  if d.k <> locExpr then freeTemp(p, a)
+end;
+
 procedure genMagicExpr(p: BProc; e: PNode; var d: TLoc; op: TMagic);
 var
   a: TLoc;
@@ -1491,13 +1627,21 @@ begin
     mEqStr: binaryExpr(p, e, d, 'eqStrings', 'eqStrings($1, $2)');
     mLeStr: binaryExpr(p, e, d, 'cmpStrings', '(cmpStrings($1, $2) <= 0)');
     mLtStr: binaryExpr(p, e, d, 'cmpStrings', '(cmpStrings($1, $2) < 0)');
+    mIsNil: unaryExpr(p, e, d, '', '$1 == 0');
+    mIntToStr: genDollar(p, e, d, 'nimIntToStr', 'nimIntToStr($1)');
+    mInt64ToStr: genDollar(p, e, d, 'nimInt64ToStr', 'nimInt64ToStr($1)');
+    mBoolToStr: genDollar(p, e, d, 'nimBoolToStr', 'nimBoolToStr($1)');
+    mCharToStr: genDollar(p, e, d, 'nimCharToStr', 'nimCharToStr($1)');
+    mFloatToStr: genDollar(p, e, d, 'nimFloatToStr', 'nimFloatToStr($1)');
+    mCStrToStr: genDollar(p, e, d, 'cstrToNimstr', 'cstrToNimstr($1)');
+    mStrToStr: expr(p, e.sons[1], d);
     mAssert: begin
       if (optAssert in p.Options) then begin
-        useMagic('internalAssert');
+        useMagic(p.module, 'internalAssert');
         expr(p, e.sons[1], d);
         line := toRope(toLinenumber(e.info));
         filen := makeCString(ToFilename(e.info));
-        appRopeFormat(p.s[cpsStmts], 'internalAssert($1, $2, $3);$n',
+        appf(p.s[cpsStmts], 'internalAssert($1, $2, $3);$n',
                       [filen, line, rdLoc(d)])
       end
     end;
@@ -1505,23 +1649,24 @@ begin
     mNewFinalize: genNewFinalize(p, e);
     mSizeOf:
       putIntoDest(p, d, e.typ,
-        ropeFormat('sizeof($1)', [getTypeDesc(e.sons[1].typ)]));
-    mChr: expr(p, e.sons[1], d);
-    mOrd:
-      // ord only allows things that are allowed in C anyway, so generate
-      // no code for it:
-      expr(p, e.sons[1], d);
+        ropef('sizeof($1)', [getTypeDesc(p.module, e.sons[1].typ)]));
+    mChr: genCast(p, e, d); // expr(p, e.sons[1], d);
+    mOrd: genOrd(p, e, d);
     mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray:
       genArrayLen(p, e, d, op);
     mInc: begin
       if not (optOverflowCheck in p.Options) then
         binaryStmt(p, e, d, '', '$1 += $2;$n')
+      else if skipVarGeneric(e.sons[1].typ).kind = tyInt64 then
+        binaryStmt(p, e, d, 'addInt64', '$1 = addInt64($1, $2);$n')
       else
         binaryStmt(p, e, d, 'addInt', '$1 = addInt($1, $2);$n')
     end;
     ast.mDec: begin
       if not (optOverflowCheck in p.Options) then
         binaryStmt(p, e, d, '', '$1 -= $2;$n')
+      else if skipVarGeneric(e.sons[1].typ).kind = tyInt64 then
+        binaryStmt(p, e, d, 'subInt64', '$1 = subInt64($1, $2);$n')
       else
         binaryStmt(p, e, d, 'subInt', '$1 = subInt($1, $2);$n')
     end;
@@ -1530,6 +1675,8 @@ begin
     mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet,
     mMinusSet, mInSet: genSetOp(p, e, d, op);
     mExit: genCall(p, e, d);
+    mNLen..mNError:
+      liMessage(e.info, errCannotGenerateCodeForX, e.sons[0].sym.name.s);
     else internalError(e.info, 'genMagicExpr: ' + magicToStr[op]);
   end
 end;
@@ -1544,18 +1691,18 @@ var
   i: int;
   ts: string;
 begin
-  if e.kind = nkConstSetConstr then
+  if nfAllConst in e.flags then
     putIntoDest(p, d, e.typ, genSetNode(p, e))
   else begin
     if d.k = locNone then d := getTemp(p, e.typ);
     if getSize(e.typ) > 8 then begin // big set:
-      appRopeFormat(p.s[cpsStmts], 'memset($1, 0, sizeof($1));$n', [rdLoc(d)]);
+      appf(p.s[cpsStmts], 'memset($1, 0, sizeof($1));$n', [rdLoc(d)]);
       for i := 0 to sonsLen(e)-1 do begin
         if e.sons[i].kind = nkRange then begin
           idx := getTemp(p, getSysType(tyInt)); // our counter
           a := initLocExpr(p, e.sons[i].sons[1]);
           b := initLocExpr(p, e.sons[i].sons[2]);
-          appRopeFormat(p.s[cpsStmts],
+          appf(p.s[cpsStmts],
             'for ($1 = $3; $1 <= $4; $1++) $n' +
             '$2[$1/8] |=(1<<($1%8));$n',
             [rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ),
@@ -1566,21 +1713,21 @@ begin
         end
         else begin
           a := initLocExpr(p, e.sons[i]);
-          appRopeFormat(p.s[cpsStmts], '$1[$2/8] |=(1<<($2%8));$n',
+          appf(p.s[cpsStmts], '$1[$2/8] |=(1<<($2%8));$n',
                        [rdLoc(d), rdSetElemLoc(a, e.typ)]);
           freeTemp(p, a)
         end
       end
     end
     else begin // small set
-      ts := 'NS' + toString(getSize(e.typ)*8);
-      appRopeFormat(p.s[cpsStmts], '$1 = 0;$n', [rdLoc(d)]);
+      ts := 'NI' + toString(getSize(e.typ)*8);
+      appf(p.s[cpsStmts], '$1 = 0;$n', [rdLoc(d)]);
       for i := 0 to sonsLen(e) - 1 do begin
         if e.sons[i].kind = nkRange then begin
           idx := getTemp(p, getSysType(tyInt)); // our counter
           a := initLocExpr(p, e.sons[i].sons[1]);
           b := initLocExpr(p, e.sons[i].sons[2]);
-          appRopeFormat(p.s[cpsStmts],
+          appf(p.s[cpsStmts],
             'for ($1 = $3; $1 <= $4; $1++) $n' +{&}
             '$2 |=(1<<((' +{&} ts +{&} ')($1)%(sizeof(' +{&}ts+{&}')*8)));$n',
             [rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ),
@@ -1591,7 +1738,7 @@ begin
         end
         else begin
           a := initLocExpr(p, e.sons[i]);
-          appRopeFormat(p.s[cpsStmts],
+          appf(p.s[cpsStmts],
                         '$1 |=(1<<((' +{&} ts +{&} ')($2)%(sizeof(' +{&}ts+{&}
                         ')*8)));$n',
                         [rdLoc(d), rdSetElemLoc(a, e.typ)]);
@@ -1602,38 +1749,42 @@ begin
   end
 end;
 
-procedure genRecordConstr(p: BProc; t: PNode; var d: TLoc);
+procedure genTupleConstr(p: BProc; n: PNode; var d: TLoc);
 var
-  i, len: int;
+  i: int;
   rec: TLoc;
+  it: PNode;
+  t: PType;
 begin
-  {@discard} getTypeDesc(t.typ); // so that any fields are initialized
-  if d.k = locNone then
-    d := getTemp(p, t.typ);
-  i := 0;
-  len := sonsLen(t);
-  while i < len do begin
-    rec := initLoc(locExpr, t.sons[i].typ);
-    assert(t.sons[i].sym.loc.r <> nil);
-    rec.r := ropeFormat('$1.$2', [rdLoc(d), t.sons[i].sym.loc.r]);
-    inheritStorage(rec, d);
-    expr(p, t.sons[i+1], rec);
-    inc(i, 2)
+  // the code generator assumes that there are only tuple constructors with
+  // field names!
+  t := getUniqueType(n.typ);
+  {@discard} getTypeDesc(p.module, t); // so that any fields are initialized
+  if d.k = locNone then d := getTemp(p, t);
+  if t.n = nil then InternalError(n.info, 'genTupleConstr');
+  if sonsLen(t.n) <> sonsLen(n) then
+    InternalError(n.info, 'genTupleConstr');
+  for i := 0 to sonsLen(n)-1 do begin
+    it := n.sons[i];
+    if it.kind <> nkExprColonExpr then InternalError(n.info, 'genTupleConstr');
+    rec := initLoc(locExpr, it.sons[1].typ, d.s);
+    if (t.n.sons[i].kind <> nkSym) then
+      InternalError(n.info, 'genTupleConstr');
+    rec.r := ropef('$1.$2', [rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)]);
+    expr(p, it.sons[1], rec);
   end
 end;
 
-procedure genArrayConstr(p: BProc; t: PNode; var d: TLoc);
+procedure genArrayConstr(p: BProc; n: PNode; var d: TLoc);
 var
   arr: TLoc;
   i: int;
 begin
-  if d.k = locNone then
-    d := getTemp(p, t.typ);
-  for i := 0 to sonsLen(t)-1 do begin
-    arr := initLoc(locExpr, elemType(skipGeneric(t.typ)));
-    arr.r := ropeFormat('$1[$2]', [rdLoc(d), intLiteral(i)]);
-    inheritStorage(arr, d);
-    expr(p, t.sons[i], arr)
+  if d.k = locNone then d := getTemp(p, n.typ);
+  for i := 0 to sonsLen(n)-1 do begin
+    arr := initLoc(locExpr, elemType(skipGeneric(n.typ)), d.s);
+    arr.r := ropef('$1[$2]', [rdLoc(d), intLiteral(i)]);
+    expr(p, n.sons[i], arr)
   end
 end;
 
@@ -1642,157 +1793,27 @@ var
   newSeq, arr: TLoc;
   i: int;
 begin
-  useMagic('newSeq');
+  useMagic(p.module, 'newSeq');
   if d.k = locNone then
     d := getTemp(p, t.typ);
   // generate call to newSeq before adding the elements per hand:
 
-  newSeq := initLoc(locExpr, t.typ);
-  newSeq.r := ropeFormat('($1) newSeq($2, $3)',
-    [getTypeDesc(t.typ), genTypeInfo(currMod, t.typ), toRope(sonsLen(t))]);
+  newSeq := initLoc(locExpr, t.typ, OnHeap);
+  newSeq.r := ropef('($1) newSeq($2, $3)',
+    [getTypeDesc(p.module, t.typ),
+    genTypeInfo(p.module, t.typ), toRope(sonsLen(t))]);
   genAssignment(p, d, newSeq, {@set}[]);
   for i := 0 to sonsLen(t)-1 do begin
-    arr := initLoc(locExpr, elemType(skipGeneric(t.typ)));
-    arr.r := ropeFormat('$1->data[$2]', [rdLoc(d), intLiteral(i)]);
-    arr.flags := {@set}[lfOnHeap]; // we know that sequences are on the heap
+    arr := initLoc(locExpr, elemType(skipGeneric(t.typ)), OnHeap);
+    arr.r := ropef('$1->data[$2]', [rdLoc(d), intLiteral(i)]);
+    arr.s := OnHeap; // we know that sequences are on the heap
     expr(p, t.sons[i], arr)
   end
 end;
 
-procedure genCast(p: BProc; e: PNode; var d: TLoc);
-const
-  ValueTypes = {@set}[tyRecord, tyObject, tyArray, tyOpenArray, tyArrayConstr];
-// we use whatever C gives us. Except if we have a value-type, we
-// need to go through its address:
-var
-  a: TLoc;
-begin
-  a := InitLocExpr(p, e.sons[0]);
-  if (skipAbstract(e.typ).kind in ValueTypes) and (a.indirect = 0) then
-    putIntoDest(p, d, e.typ, ropeFormat('(*($1*) ($2))',
-      [getTypeDesc(e.typ), addrLoc(a)]))
-  else
-    putIntoDest(p, d, e.typ, ropeFormat('(($1) ($2))',
-      [getTypeDesc(e.typ), rdCharLoc(a)]));
-  if d.k <> locExpr then
-    freeTemp(p, a)
-end;
-
-procedure genConv(p: BProc; e: PNode; var d: TLoc);
-  // type conversion: it doesn't matter if implicit or explicit;
-  // type conversions are not casts!
-var
-  a: TLoc;
-  r: PRope;
-  source, dest: PType;
-begin
-  // numeric types need range checks:
-  dest := skipVarGeneric(e.typ);
-  case dest.kind of
-    tyRange, tyInt..tyInt64, tyEnum, tyChar, tyBool: begin
-      if not (optRangeCheck in p.options) or
-          (firstOrd(dest) <= firstOrd(skipVarGeneric(e.sons[0].typ))) and // first >= x
-           (lastOrd(skipVarGeneric(e.sons[0].typ)) <= lastOrd(dest)) then // x <= last
-        expr(p, e.sons[0], d) // no need for a range check
-      else begin // generate a range check:
-        a := InitLocExpr(p, e.sons[0]);
-        if    (a.t.kind in [tyFloat..tyFloat128]) or
-             (dest.kind in [tyFloat..tyFloat128]) then begin
-          useMagic('chckRangeF');
-          putIntoDest(p, d, dest, ropeFormat('chckRangeF($1, $2, $3)',
-            [rdCharLoc(a), genLiteral(p, dest.n.sons[0], dest),
-                           genLiteral(p, dest.n.sons[1], dest)]))
-        end
-        else if (a.t.kind = tyInt64) or (dest.kind = tyInt64) then begin
-          useMagic('chckRange64');
-          putIntoDest(p, d, dest, ropeFormat('chckRange64($1, $2, $3)',
-            [rdCharLoc(a), intLiteral(firstOrd(dest)),
-                           intLiteral(lastOrd(dest))]))
-        end
-        else begin
-          useMagic('chckRange');
-          putIntoDest(p, d, dest, ropeFormat('chckRange($1, $2, $3)',
-            [rdCharLoc(a), intLiteral(firstOrd(dest)),
-                           intLiteral(lastOrd(dest))]))
-        end;
-        if d.k <> locExpr then
-          freeTemp(p, a)
-      end
-    end;
-    // open arrays need implicit length passed:
-    tyOpenArray: begin
-      a := initLocExpr(p, e.sons[0]);
-      case a.t.kind of
-        tyOpenArray:
-          putIntoDest(p, d, dest, ropeFormat('$1, $1Len0', [rdLoc(a)]));
-        tyString, tySequence:
-          putIntoDest(p, d, dest, ropeFormat('$1->data, $1->len', [rdLoc(a)]));
-        tyArray, tyArrayConstr:
-          putIntoDest(p, d, dest, ropeFormat('$1, $2',
-            [rdLoc(a), toRope(lengthOrd(a.t))]));
-        else InternalError(e.sons[0].info, 'genConv()')
-      end;
-      if d.k <> locExpr then freeTemp(p, a)
-    end;
-    // conversions from string to cstring:
-    tyCString: begin
-      if skipVarGeneric(e.sons[0].typ).kind = tyString then begin
-        a := initLocExpr(p, e.sons[0]);
-        putIntoDest(p, d, e.typ, ropeFormat('$1->data', [rdLoc(a)]));
-        if d.k <> locExpr then freeTemp(p, a)
-      end
-      else if not isCompatibleToCString(e.sons[0].typ) then
-        // ordinary type cast:
-        genCast(p, e, d)
-      else
-        expr(p, e.sons[0], d) // BUGFIX!
-    end;
-    // conversions from cstring to string:
-    tyString: begin
-      if skipVarGeneric(e.sons[0].typ).kind = tyCString then begin
-        useMagic('cstrToNimstr');
-        a := initLocExpr(p, e.sons[0]);
-        putIntoDest(p, d, dest, ropeFormat('cstrToNimstr($1)', [rdLoc(a)]));
-        if d.k <> locExpr then freeTemp(p, a)
-      end
-      else // ordinary type cast:
-        genCast(p, e, d)
-    end;
-    // conversions between different object types:
-    tyObject: begin
-      source := skipVarGeneric(e.sons[0].typ);
-      // if source is a subtype of dest, downcast:
-      a := initLocExpr(p, e.sons[0]);
-      r := rdLoc(a);
-      while source.sons[0] <> nil do begin
-        source := source.sons[0];
-        if gCmd <> cmdCompileToCpp then
-          app(r, '.Sup');
-        if source.id = dest.id then break
-      end;
-      if source.id = dest.id then // we really have a downcast here:
-        if gCmd = cmdCompileToCpp then
-          putLocIntoDest(p, d, a) // downcast does C++ for us
-        else
-          putIntoDest(p, d, dest, r)
-      else if gCmd = cmdCompileToCpp then
-        genCast(p, e, d) // discard ``a``
-      else // upcasts are uglier in C
-        putIntoDest(p, d, dest, ropeFormat('(*($1*) ($2))',
-          [getTypeDesc(dest), addrLoc(a)]));
-      if d.k <> locExpr then freeTemp(p, a)
-    end;
-    tyGenericParam, tyAnyEnum:
-      expr(p, e.sons[0], d);
-      // happens sometimes for generated assignments, etc.
-    else // use an ordinary cast
-      genCast(p, e, d)
-  end
-end;
-
 procedure genComplexConst(p: BProc; sym: PSym; var d: TLoc);
 begin
-  genConstPrototype(sym);
+  genConstPrototype(p.module, sym);
   assert((sym.loc.r <> nil) and (sym.loc.t <> nil));
   putLocIntoDest(p, d, sym.loc)
 end;
@@ -1806,68 +1827,83 @@ begin
   if len > 0 then expr(p, n.sons[len-1], d);
 end;
 
+procedure upConv(p: BProc; n: PNode; var d: TLoc);
+var
+  a: TLoc;
+  dest, t: PType;
+  r, nilCheck: PRope;
+begin
+  a := initLocExpr(p, n.sons[0]);
+  dest := skipPtrsGeneric(n.typ);
+  if (optObjCheck in p.options) and not (isPureObject(dest)) then begin
+    useMagic(p.module, 'chckObj');
+    r := rdLoc(a);
+    nilCheck := nil;
+    t := skipGeneric(a.t);
+    while t.kind in [tyVar, tyPtr, tyRef] do begin
+      if t.kind <> tyVar then nilCheck := r;
+      r := ropef('(*$1)', [r]);
+      t := skipGeneric(t.sons[0])
+    end;
+    if gCmd <> cmdCompileToCpp then
+      while (t.kind = tyObject) and (t.sons[0] <> nil) do begin
+        app(r, '.Sup');
+        t := skipGeneric(t.sons[0]);
+      end;
+    if nilCheck <> nil then
+      appf(p.s[cpsStmts], 'if ($1) chckObj($2.m_type, $3);$n',
+        [nilCheck, r, genTypeInfo(p.module, dest)])
+    else
+      appf(p.s[cpsStmts], 'chckObj($1.m_type, $2);$n',
+        [r, genTypeInfo(p.module, dest)]);
+  end;
+  if n.sons[0].typ.kind <> tyObject then
+    putIntoDest(p, d, n.typ, ropef('(($1) ($2))',
+      [getTypeDesc(p.module, n.typ), rdLoc(a)]))
+  else
+    putIntoDest(p, d, n.typ, ropef('(*($1*) ($2))',
+      [getTypeDesc(p.module, dest), addrLoc(a)]));
+end;
+
+procedure downConv(p: BProc; n: PNode; var d: TLoc);
+var
+  a: TLoc;
+  dest, src: PType;
+  i: int;
+  r: PRope;
+begin
+  if gCmd = cmdCompileToCpp then
+    expr(p, n.sons[0], d) // downcast does C++ for us
+  else begin
+    dest := skipPtrsGeneric(n.typ);
+    src := skipPtrsGeneric(n.sons[0].typ);
+    a := initLocExpr(p, n.sons[0]);
+    r := rdLoc(a);
+    if skipGeneric(n.sons[0].typ).kind in [tyRef, tyPtr, tyVar] then begin
+      app(r, '->Sup');
+      for i := 2 to abs(inheritanceDiff(dest, src)) do app(r, '.Sup');
+      r := con('&'+'', r);
+    end
+    else
+      for i := 1 to abs(inheritanceDiff(dest, src)) do app(r, '.Sup');
+    putIntoDest(p, d, n.typ, r);
+  end
+end;
+
 procedure genBlock(p: BProc; t: PNode; var d: TLoc); forward;
 
 procedure expr(p: BProc; e: PNode; var d: TLoc);
-// do not forget that lfIndirect in d.flags may be requested!
 var
   sym: PSym;
-  a: TLoc;
   ty: PType;
 begin
   case e.kind of
-    nkQualified: expr(p, e.sons[1], d);
-    nkStrLit..nkTripleStrLit, nkIntLit..nkInt64Lit,
-    nkFloatLit..nkFloat64Lit, nkNilLit, nkCharLit, nkRCharLit: begin
-      putIntoDest(p, d, e.typ, genLiteral(p, e));
-      d.k := locImmediate // for removal of index checks
-    end;
-    nkCall, nkHiddenCallConv: begin
-      if (e.sons[0].kind = nkSym) and
-         (e.sons[0].sym.magic <> mNone) then
-        genMagicExpr(p, e, d, e.sons[0].sym.magic)
-      else
-        genCall(p, e, d)
-    end;
-    nkConstSetConstr, nkSetConstr: genSetConstr(p, e, d);
-    nkConstArrayConstr, nkArrayConstr:
-      if (skipAbstract(e.typ).kind = tySequence) then  // BUGFIX
-        genSeqConstr(p, e, d)
-      else
-        genArrayConstr(p, e, d);
-    nkConstRecordConstr, nkRecordConstr:
-      genRecordConstr(p, e, d);
-    nkCast: genCast(p, e, d);
-    nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, e, d);
-    nkAddr: begin
-      a := InitLocExpr(p, e.sons[0]);
-      putIntoDest(p, d, e.typ, addrLoc(a));
-      if d.k <> locExpr then
-        freeTemp(p, a)
-    end;
-    nkBracketExpr: begin
-      ty := skipAbstract(e.sons[0].typ);
-      if ty.kind in [tyRef, tyPtr, tyVar] then ty := skipAbstract(ty.sons[0]);
-      case ty.kind of
-        tyArray, tyArrayConstr: genArrayElem(p, e, d);
-        tyOpenArray: genOpenArrayElem(p, e, d);
-        tySequence, tyString: genSeqElem(p, e, d);
-        tyCString: genCStringElem(p, e, d);
-        else InternalError(e.info,
-               'expr(nkBracketExpr, ' + typeKindToStr[ty.kind] + ')');
-      end
-    end;
-    nkDerefExpr: genDeref(p, e, d);
-    nkDotExpr: genRecordField(p, e, d);
-    nkBlockExpr: genBlock(p, e, d);
-    nkStmtListExpr: genStmtListExpr(p, e, d);
-    nkIfExpr: genIfExpr(p, e, d);
     nkSym: begin
       sym := e.sym;
       case sym.Kind of
-        skProc: begin
+        skProc, skConverter: begin
           // generate prototype if not already declared in this translation unit
-          genProcPrototype(sym);
+          genProcPrototype(p.module, sym);
           if ((sym.loc.r = nil) or (sym.loc.t = nil)) then
             InternalError(e.info, 'expr: proc not init ' + sym.name.s);
           putLocIntoDest(p, d, sym.loc)
@@ -1879,7 +1915,7 @@ begin
             genComplexConst(p, sym, d);
         skEnumField: putIntoDest(p, d, e.typ, toRope(sym.position));
         skVar: begin
-          if (sfGlobal in sym.flags) then genVarPrototype(sym);
+          if (sfGlobal in sym.flags) then genVarPrototype(p.module, sym);
           if ((sym.loc.r = nil) or (sym.loc.t = nil)) then
             InternalError(e.info, 'expr: var not init ' + sym.name.s);
           putLocIntoDest(p, d, sym.loc);
@@ -1898,7 +1934,57 @@ begin
           InternalError(e.info, 'expr(' +{&} symKindToStr[sym.kind] +{&}
                                 '); unknown symbol')
       end
-    end
+    end;
+    nkQualified: expr(p, e.sons[1], d);
+    nkStrLit..nkTripleStrLit, nkIntLit..nkInt64Lit,
+    nkFloatLit..nkFloat64Lit, nkNilLit, nkCharLit: begin
+      putIntoDest(p, d, e.typ, genLiteral(p, e));
+      d.k := locImmediate // for removal of index checks
+    end;
+    nkCall, nkHiddenCallConv: begin
+      if (e.sons[0].kind = nkSym) and
+         (e.sons[0].sym.magic <> mNone) then
+        genMagicExpr(p, e, d, e.sons[0].sym.magic)
+      else
+        genCall(p, e, d)
+    end;
+    nkCurly: genSetConstr(p, e, d);
+    nkBracket:
+      if (skipVarGenericRange(e.typ).kind = tySequence) then  // BUGFIX
+        genSeqConstr(p, e, d)
+      else
+        genArrayConstr(p, e, d);
+    nkPar:
+      genTupleConstr(p, e, d);
+    nkCast: genCast(p, e, d);
+    nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, e, d);
+    nkHiddenAddr, nkAddr: genAddr(p, e, d);
+    nkBracketExpr: begin
+      ty := skipVarGenericRange(e.sons[0].typ);
+      if ty.kind in [tyRef, tyPtr] then ty := skipVarGenericRange(ty.sons[0]);
+      case ty.kind of
+        tyArray, tyArrayConstr: genArrayElem(p, e, d);
+        tyOpenArray: genOpenArrayElem(p, e, d);
+        tySequence, tyString: genSeqElem(p, e, d);
+        tyCString: genCStringElem(p, e, d);
+        else InternalError(e.info,
+               'expr(nkBracketExpr, ' + typeKindToStr[ty.kind] + ')');
+      end
+    end;
+    nkDerefExpr, nkHiddenDeref: genDeref(p, e, d);
+    nkDotExpr: genRecordField(p, e, d);
+    nkCheckedFieldExpr: genCheckedRecordField(p, e, d);
+    nkBlockExpr: genBlock(p, e, d);
+    nkStmtListExpr: genStmtListExpr(p, e, d);
+    nkIfExpr: genIfExpr(p, e, d);
+    nkObjDownConv: downConv(p, e, d);
+    nkObjUpConv: upConv(p, e, d);
+    nkChckRangeF: genRangeChck(p, e, d, 'chckRangeF');
+    nkChckRange64: genRangeChck(p, e, d, 'chckRange64');
+    nkChckRange: genRangeChck(p, e, d, 'chckRange');
+    nkStringToCString: convStrToCStr(p, e, d);
+    nkCStringToString: convCStrToStr(p, e, d);
+    nkPassAsOpenArray: passToOpenArray(p, e, d);
     else
       InternalError(e.info, 'expr(' +{&} nodeKindToStr[e.kind] +{&}
                             '); unknown node kind')
@@ -1915,8 +2001,8 @@ var
 begin
   result := copyNode(n);
   newSons(result, sonsLen(n));
-  t := skipAbstract(n.Typ);
-  if t.kind = tyRecordConstr then 
+  t := getUniqueType(skipVarGenericRange(n.Typ));
+  if t.n = nil then
     InternalError(n.info, 'transformRecordExpr: invalid type');
   for i := 0 to sonsLen(n)-1 do begin
     assert(n.sons[i].kind = nkExprColonExpr);
@@ -1940,7 +2026,7 @@ begin
   len := sonsLen(n);
   result := toRope('{'+'');
   for i := 0 to len - 2 do
-    app(result, ropeFormat('$1,$n', [genConstExpr(p, n.sons[i])]));
+    app(result, ropef('$1,$n', [genConstExpr(p, n.sons[i])]));
   if len > 0 then app(result, genConstExpr(p, n.sons[len-1]));
   app(result, '}' + tnl)
 end;
@@ -1951,17 +2037,19 @@ var
   cs: TBitSet;
 begin
   case n.Kind of
-    nkHiddenStdConv, nkHiddenSubConv: result := genConstExpr(p, n.sons[0]);
-    nkSetConstr, nkConstSetConstr: begin
+    nkHiddenStdConv, nkHiddenSubConv: result := genConstExpr(p, n.sons[1]);
+    nkCurly: begin
       toBitSet(n, cs);
       result := genRawSetData(cs, int(getSize(n.typ)))
+    end;
+    nkBracket: begin
       // XXX: tySequence!
+      result := genConstSimpleList(p, n);
     end;
-    nkConstArrayConstr: result := genConstSimpleList(p, n);
-    nkPar, nkConstRecordConstr, nkRecordConstr: begin
-      if hasSonWith(n, nkExprColonExpr) then 
+    nkPar: begin
+      if hasSonWith(n, nkExprColonExpr) then
         trans := transformRecordExpr(n)
-      else 
+      else
         trans := n;
       result := genConstSimpleList(p, trans);
     end
diff --git a/nim/ccgstmts.pas b/nim/ccgstmts.pas
index 38a9e9cdf..a59ef42d2 100644
--- a/nim/ccgstmts.pas
+++ b/nim/ccgstmts.pas
@@ -18,17 +18,25 @@ begin
   line := toLinenumber(t.info); // BUGFIX
   if line < 0 then line := 0; // negative numbers are not allowed in #line
   if optLineDir in p.Options then
-    appRopeFormat(p.s[cpsStmts], '#line $2 "$1"$n',
+    appf(p.s[cpsStmts], '#line $2 "$1"$n',
       [toRope(toFilename(t.info)), toRope(line)]);
   if ([optStackTrace, optEndb] * p.Options = [optStackTrace, optEndb]) and
       ((p.prc = nil) or not (sfPure in p.prc.flags)) then begin
-    useMagic('endb');      // new: endb support
-    appRopeFormat(p.s[cpsStmts], 'endb($1);$n', [toRope(line)])
+    useMagic(p.module, 'endb');      // new: endb support
+    appf(p.s[cpsStmts], 'endb($1);$n', [toRope(line)])
   end
   else if ([optLineTrace, optStackTrace] * p.Options =
         [optLineTrace, optStackTrace]) and ((p.prc = nil) or
       not (sfPure in p.prc.flags)) then
-    appRopeFormat(p.s[cpsStmts], 'F.line = $1;$n', [toRope(line)])
+    appf(p.s[cpsStmts], 'F.line = $1;$n', [toRope(line)])
+end;
+
+procedure finishTryStmt(p: BProc; howMany: int);
+var
+  i: int;
+begin
+  for i := 1 to howMany do
+    app(p.s[cpsStmts], 'excHandler = excHandler->prev;' + tnl);
 end;
 
 procedure genReturnStmt(p: BProc; t: PNode);
@@ -36,15 +44,16 @@ begin
   p.beforeRetNeeded := true;
   genLineDir(p, t);
   if (t.sons[0] <> nil) then genStmts(p, t.sons[0]);
+  finishTryStmt(p, p.nestedTryStmts);
   app(p.s[cpsStmts], 'goto BeforeRet;' + tnl)
 end;
 
 procedure genObjectInit(p: BProc; sym: PSym);
 begin
   if containsObject(sym.typ) then begin
-    useMagic('objectInit');
-    appRopeFormat(p.s[cpsInit], 'objectInit($1, $2);$n',
-      [addrLoc(sym.loc), genTypeInfo(currMod, sym.typ)])
+    useMagic(p.module, 'objectInit');
+    appf(p.s[cpsInit], 'objectInit($1, $2);$n',
+      [addrLoc(sym.loc), genTypeInfo(p.module, sym.typ)])
   end
 end;
 
@@ -52,11 +61,11 @@ procedure initVariable(p: BProc; v: PSym);
 begin
   if containsGarbageCollectedRef(v.typ) or (v.ast = nil) then
     // Language change: always initialize variables if v.ast == nil!
-    if not (skipAbstract(v.typ).Kind in [tyArray, tyArrayConstr, tySet,
-                                         tyRecord, tyTuple, tyObject]) then
-      appRopeFormat(p.s[cpsInit], '$1 = 0;$n', [v.loc.r])
+    if not (skipVarGenericRange(v.typ).Kind in [tyArray, tyArrayConstr, tySet,
+                                                tyTuple, tyObject]) then
+      appf(p.s[cpsStmts], '$1 = 0;$n', [v.loc.r])
     else
-      appRopeFormat(p.s[cpsInit], 'memset((void*)&$1, 0, sizeof($1));$n',
+      appf(p.s[cpsStmts], 'memset((void*)&$1, 0, sizeof($1));$n',
         [v.loc.r])
 end;
 
@@ -73,7 +82,7 @@ begin
     assert(a.sons[0].kind = nkSym);
     v := a.sons[0].sym;
     if sfGlobal in v.flags then
-      assignGlobalVar(v)
+      assignGlobalVar(p.module, v)
     else begin
       assignLocalVar(p, v);
       initVariable(p, v) // XXX: this is not required if a.sons[2] != nil,
@@ -95,19 +104,20 @@ var
 begin
   for i := 0 to sonsLen(t)-1 do begin
     if t.sons[i].kind = nkCommentStmt then continue;
-    assert(t.sons[i].kind = nkConstDef);
+    if t.sons[i].kind <> nkConstDef then InternalError(t.info, 'genConstStmt');
     c := t.sons[i].sons[0].sym;
     // This can happen for forward consts:
     if (c.ast <> nil) and (c.typ.kind in ConstantDataTypes) and
            not (lfNoDecl in c.loc.flags) then begin
       // generate the data:
-      fillLoc(c.loc, locData, c.typ, mangleName(c), {@set}[lfOnData]);
+      fillLoc(c.loc, locData, c.typ, mangleName(c), OnUnknown);
       if sfImportc in c.flags then
-        appRopeFormat(currMod.s[cfsData], 'extern $1$2 $3;$n',
-          [constTok, getTypeDesc(c.typ), c.loc.r])
+        appf(p.module.s[cfsData], 'extern NIM_CONST $1 $2;$n',
+          [getTypeDesc(p.module, c.typ), c.loc.r])
       else
-        appRopeFormat(currMod.s[cfsData], '$1$2 $3 = $4;$n',
-          [constTok, getTypeDesc(c.typ), c.loc.r, genConstExpr(p, c.ast)])
+        appf(p.module.s[cfsData], 'NIM_CONST $1 $2 = $3;$n',
+          [getTypeDesc(p.module, c.typ), c.loc.r,
+          genConstExpr(p, c.ast)])
     end
   end
 end;
@@ -139,11 +149,11 @@ begin
       nkElifBranch: begin
         a := initLocExpr(p, it.sons[0]);
         Lelse := getLabel(p);
-        appRopeFormat(p.s[cpsStmts], 'if (!$1) goto $2;$n', [rdLoc(a), Lelse]);
+        appf(p.s[cpsStmts], 'if (!$1) goto $2;$n', [rdLoc(a), Lelse]);
         freeTemp(p, a);
         genStmts(p, it.sons[1]);
         if sonsLen(n) > 1 then
-          appRopeFormat(p.s[cpsStmts], 'goto $1;$n', [Lend]);
+          appf(p.s[cpsStmts], 'goto $1;$n', [Lend]);
         fixLabel(p, Lelse);
       end;
       nkElse: begin
@@ -166,17 +176,18 @@ var
 begin
   genLineDir(p, t);
   assert(sonsLen(t) = 2);
-  inc(p.unique);
-  Labl := con('L'+'', toRope(p.unique));
+  inc(p.labels);
+  Labl := con('L'+'', toRope(p.labels));
   len := length(p.blocks);
   setLength(p.blocks, len+1);
-  p.blocks[len] := p.unique; // positive because we use it right away:
+  p.blocks[len].id := p.labels; // positive because we use it right away:
+  p.blocks[len].nestedTryStmts := p.nestedTryStmts;
   app(p.s[cpsStmts], 'while (1) {' + tnl);
   a := initLocExpr(p, t.sons[0]);
-  appRopeFormat(p.s[cpsStmts], 'if (!$1) goto $2;$n', [rdLoc(a), Labl]);
+  appf(p.s[cpsStmts], 'if (!$1) goto $2;$n', [rdLoc(a), Labl]);
   freeTemp(p, a);
   genStmts(p, t.sons[1]);
-  appRopeFormat(p.s[cpsStmts], '} $1: ;$n', [Labl]);
+  appf(p.s[cpsStmts], '} $1: ;$n', [Labl]);
   setLength(p.blocks, length(p.blocks)-1)
 end;
 
@@ -185,7 +196,7 @@ var
   idx: int;
   sym: PSym;
 begin
-  inc(p.unique);
+  inc(p.labels);
   idx := length(p.blocks);
   if t.sons[0] <> nil then begin // named block?
     assert(t.sons[0].kind = nkSym);
@@ -194,14 +205,22 @@ begin
     sym.loc.a := idx
   end;
   setLength(p.blocks, idx+1);
-  p.blocks[idx] := -p.unique; // negative because it isn't used yet
+  p.blocks[idx].id := -p.labels; // negative because it isn't used yet
+  p.blocks[idx].nestedTryStmts := p.nestedTryStmts;
   if t.kind = nkBlockExpr then genStmtListExpr(p, t.sons[1], d)
   else genStmts(p, t.sons[1]);
-  if p.blocks[idx] > 0 then // label has been used:
-    appRopeFormat(p.s[cpsStmts], 'L$1: ;$n', [toRope(p.blocks[idx])]);
+  if p.blocks[idx].id > 0 then // label has been used:
+    appf(p.s[cpsStmts], 'L$1: ;$n', [toRope(p.blocks[idx].id)]);
   setLength(p.blocks, idx)
 end;
 
+// try:
+//   while:
+//     try:
+//       if ...:
+//         break # we need to finish only one try statement here!
+// finally:
+
 procedure genBreakStmt(p: BProc; t: PNode);
 var
   idx: int;
@@ -215,8 +234,9 @@ begin
     assert(sym.loc.k = locOther);
     idx := sym.loc.a
   end;
-  p.blocks[idx] := abs(p.blocks[idx]); // label is used
-  appRopeFormat(p.s[cpsStmts], 'goto L$1;$n', [toRope(p.blocks[idx])])
+  p.blocks[idx].id := abs(p.blocks[idx].id); // label is used
+  finishTryStmt(p, p.nestedTryStmts - p.blocks[idx].nestedTryStmts);
+  appf(p.s[cpsStmts], 'goto L$1;$n', [toRope(p.blocks[idx].id)])
 end;
 
 procedure genAsmStmt(p: BProc; t: PNode);
@@ -245,15 +265,15 @@ begin
         InternalError(t.sons[i].info, 'genAsmStmt()')
     end
   end;
-  appRopeFormat(p.s[cpsStmts], CC[ccompiler].asmStmtFrmt, [s]);
+  appf(p.s[cpsStmts], CC[ccompiler].asmStmtFrmt, [s]);
 end;
 
-function getRaiseFrmt(): string;
+function getRaiseFrmt(p: BProc): string;
 begin
   if gCmd = cmdCompileToCpp then
     result := 'throw nimException($1, $2);$n'
-  else begin  
-    useMagic('E_Base');
+  else begin
+    useMagic(p.module, 'E_Base');
     result := 'raiseException((E_Base*)$1, $2);$n'
   end
 end;
@@ -266,14 +286,13 @@ var
 begin
   genLineDir(p, t);
   if t.sons[0] <> nil then begin
-    if gCmd <> cmdCompileToCpp then
-      useMagic('raiseException');
+    if gCmd <> cmdCompileToCpp then useMagic(p.module, 'raiseException');
     a := InitLocExpr(p, t.sons[0]);
     e := rdLoc(a);
     freeTemp(p, a);
     typ := t.sons[0].typ;
     while typ.kind in [tyVar, tyRef, tyPtr] do typ := typ.sons[0];
-    appRopeFormat(p.s[cpsStmts], getRaiseFrmt(),
+    appf(p.s[cpsStmts], getRaiseFrmt(p),
       [e, makeCString(typ.sym.name.s)])
   end
   else begin
@@ -281,7 +300,7 @@ begin
     if gCmd = cmdCompileToCpp then
       app(p.s[cpsStmts], 'throw;' + tnl)
     else begin
-      useMagic('reraiseException');
+      useMagic(p.module, 'reraiseException');
       app(p.s[cpsStmts], 'reraiseException();' + tnl)
     end
   end
@@ -309,13 +328,13 @@ begin
       y := initLocExpr(p, b.sons[i].sons[1]);
       freeTemp(p, x);
       freeTemp(p, y);
-      appRopeFormat(p.s[cpsStmts], rangeFormat,
+      appf(p.s[cpsStmts], rangeFormat,
         [rdCharLoc(e), rdCharLoc(x), rdCharLoc(y), labl])
     end
     else begin
       x := initLocExpr(p, b.sons[i]);
       freeTemp(p, x);
-      appRopeFormat(p.s[cpsStmts], eqFormat,
+      appf(p.s[cpsStmts], eqFormat,
         [rdCharLoc(e), rdCharLoc(x), labl])
     end
   end
@@ -328,11 +347,11 @@ var
 begin
   Lend := getLabel(p);
   for i := 1 to sonsLen(t) - 1 do begin
-    appRopeFormat(p.s[cpsStmts], 'L$1: ;$n', [toRope(labId+i)]);
+    appf(p.s[cpsStmts], 'L$1: ;$n', [toRope(labId+i)]);
     if t.sons[i].kind = nkOfBranch then begin
       len := sonsLen(t.sons[i]);
       genStmts(p, t.sons[i].sons[len-1]);
-      appRopeFormat(p.s[cpsStmts], 'goto $1;$n', [Lend])
+      appf(p.s[cpsStmts], 'goto $1;$n', [Lend])
     end
     else // else statement
       genStmts(p, t.sons[i].sons[0])
@@ -349,15 +368,15 @@ var
 begin
   a := initLocExpr(p, t.sons[0]);
   // fist pass: gnerate ifs+goto:
-  labId := p.unique;
+  labId := p.labels;
   for i := 1 to sonsLen(t) - 1 do begin
-    inc(p.unique);
+    inc(p.labels);
     if t.sons[i].kind = nkOfBranch then
       genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat,
-        con('L'+'', toRope(p.unique)))
+        con('L'+'', toRope(p.labels)))
     else
       // else statement
-      appRopeFormat(p.s[cpsStmts], 'goto L$1;$n', [toRope(p.unique)]);
+      appf(p.s[cpsStmts], 'goto L$1;$n', [toRope(p.labels)]);
   end;
   // second pass: generate statements
   genCaseSecondPass(p, t, labId);
@@ -435,7 +454,7 @@ begin
     freeTemp(p, x);
     assert(b.sons[i].kind in [nkStrLit..nkTripleStrLit]);
     j := int(hashString(b.sons[i].strVal) and high(branches));
-    appRopeFormat(branches[j], 'if (eqStrings($1, $2)) goto $3;$n',
+    appf(branches[j], 'if (eqStrings($1, $2)) goto $3;$n',
       [rdLoc(e), rdLoc(x), labl])
   end
 end;
@@ -446,38 +465,39 @@ var
   a: TLoc;
   branches: TRopeSeq;
 begin
-  useMagic('eqStrings');
+  useMagic(p.module, 'eqStrings');
   // count how many constant strings there are in the case:
   strings := 0;
   for i := 1 to sonsLen(t)-1 do
     if t.sons[i].kind = nkOfBranch then inc(strings, sonsLen(t.sons[i])-1);
   if strings > stringCaseThreshold then begin
-    useMagic('hashString');
+    useMagic(p.module, 'hashString');
     bitMask := nmath.nextPowerOfTwo(strings)-1;
     setLength(branches, bitMask+1);
     a := initLocExpr(p, t.sons[0]);
     // fist pass: gnerate ifs+goto:
-    labId := p.unique;
+    labId := p.labels;
     for i := 1 to sonsLen(t) - 1 do begin
-      inc(p.unique);
+      inc(p.labels);
       if t.sons[i].kind = nkOfBranch then
-        genCaseStringBranch(p, t.sons[i], a, con('L'+'', toRope(p.unique)),
+        genCaseStringBranch(p, t.sons[i], a, con('L'+'', toRope(p.labels)),
                             branches)
-      else begin end
+      else begin
         // else statement: nothing to do yet
         // but we reserved a label, which we use later
+      end
     end;
     // second pass: generate switch statement based on hash of string:
-    appRopeFormat(p.s[cpsStmts], 'switch (hashString($1) & $2) {$n',
+    appf(p.s[cpsStmts], 'switch (hashString($1) & $2) {$n',
       [rdLoc(a), toRope(bitMask)]);
     for j := 0 to high(branches) do
       if branches[j] <> nil then
-        appRopeFormat(p.s[cpsStmts], 'case $1: $n$2break;$n',
+        appf(p.s[cpsStmts], 'case $1: $n$2break;$n',
           [intLiteral(j), branches[j]]);
     app(p.s[cpsStmts], '}' + tnl);
     // else statement:
     if t.sons[sonsLen(t)-1].kind <> nkOfBranch then
-      appRopeFormat(p.s[cpsStmts], 'goto L$1;$n', [toRope(p.unique)]);
+      appf(p.s[cpsStmts], 'goto L$1;$n', [toRope(p.labels)]);
     // third pass: generate statements
     genCaseSecondPass(p, t, labId);
     freeTemp(p, a);
@@ -521,7 +541,7 @@ begin
       end;
   if canGenerateSwitch then begin
     a := initLocExpr(p, t.sons[0]);
-    appRopeFormat(p.s[cpsStmts], 'switch ($1) {$n', [rdCharLoc(a)]);
+    appf(p.s[cpsStmts], 'switch ($1) {$n', [rdCharLoc(a)]);
     freeTemp(p, a);
     for i := 1 to sonsLen(t)-1 do begin
       if t.sons[i].kind = nkOfBranch then begin
@@ -529,19 +549,19 @@ begin
         for j := 0 to len-2 do begin
           if t.sons[i].sons[j].kind = nkRange then begin // a range
             if hasSwitchRange in CC[ccompiler].props then
-              appRopeFormat(p.s[cpsStmts], 'case $1 ... $2:$n',
+              appf(p.s[cpsStmts], 'case $1 ... $2:$n',
                 [genLiteral(p, t.sons[i].sons[j].sons[0]),
                  genLiteral(p, t.sons[i].sons[j].sons[1])])
             else begin
               v := copyNode(t.sons[i].sons[j].sons[0]);
               while (v.intVal <= t.sons[i].sons[j].sons[1].intVal) do begin
-                appRopeFormat(p.s[cpsStmts], 'case $1:$n', [genLiteral(p, v)]);
+                appf(p.s[cpsStmts], 'case $1:$n', [genLiteral(p, v)]);
                 Inc(v.intVal)
               end
             end;
           end
           else
-            appRopeFormat(p.s[cpsStmts], 'case $1:$n',
+            appf(p.s[cpsStmts], 'case $1:$n',
               [genLiteral(p, t.sons[i].sons[j])]);
         end;
         genStmts(p, t.sons[i].sons[len-1])
@@ -563,7 +583,7 @@ end;
 procedure genCaseStmt(p: BProc; t: PNode);
 begin
   genLineDir(p, t);
-  case skipAbstract(t.sons[0].typ).kind of
+  case skipVarGenericRange(t.sons[0].typ).kind of
     tyString: genStringCase(p, t);
     tyFloat..tyFloat128:
       genCaseGeneric(p, t, 'if ($1 >= $2 && $1 <= $3) goto $4;$n',
@@ -622,21 +642,20 @@ begin
   exc := getTempName();
   if not hasGeneralExceptSection(t) then begin
     rethrowFlag := getTempName();
-    appRopeFormat(p.s[cpsLocals], 'volatile NIM_BOOL $1 = NIM_FALSE;$n',
+    appf(p.s[cpsLocals], 'volatile NIM_BOOL $1 = NIM_FALSE;$n',
       [rethrowFlag])
   end;
   if optStackTrace in p.Options then
     app(p.s[cpsStmts], 'framePtr = (TFrame*)&F;' + tnl);
   app(p.s[cpsStmts], 'try {' + tnl);
-  inc(p.inTryStmt);
+  inc(p.nestedTryStmts);
   genStmts(p, t.sons[0]);
-  dec(p.inTryStmt);
   len := sonsLen(t);
   if t.sons[1].kind = nkExceptBranch then begin
-    appRopeFormat(p.s[cpsStmts], '} catch (NimException& $1) {$n', [exc]);
+    appf(p.s[cpsStmts], '} catch (NimException& $1) {$n', [exc]);
     if rethrowFlag <> nil then
-      appRopeFormat(p.s[cpsStmts], '$1 = NIM_TRUE;$n', [rethrowFlag]);
-    appRopeFormat(p.s[cpsStmts], 'if ($1.sp.exc) {$n', [exc])
+      appf(p.s[cpsStmts], '$1 = NIM_TRUE;$n', [rethrowFlag]);
+    appf(p.s[cpsStmts], 'if ($1.sp.exc) {$n', [exc])
   end; // XXX: this is not correct!
   i := 1;
   while (i < len) and (t.sons[i].kind = nkExceptBranch) do begin
@@ -648,24 +667,25 @@ begin
     else begin
       for j := 0 to blen - 2 do begin
         assert(t.sons[i].sons[j].kind = nkType);
-        appRopeFormat(p.s[cpsStmts], 'case $1:$n',
+        appf(p.s[cpsStmts], 'case $1:$n',
           [toRope(t.sons[i].sons[j].typ.id)])
       end;
       genStmts(p, t.sons[i].sons[blen - 1])
     end;
     // code to clear the exception:
     if rethrowFlag <> nil then
-      appRopeFormat(p.s[cpsStmts], '$1 = NIM_FALSE;  ', [rethrowFlag]);
+      appf(p.s[cpsStmts], '$1 = NIM_FALSE;  ', [rethrowFlag]);
     app(p.s[cpsStmts], 'break;' + tnl);
     inc(i);
   end;
   if t.sons[1].kind = nkExceptBranch then // BUGFIX
     app(p.s[cpsStmts], '}}' + tnl); // end of catch-switch statement
+  dec(p.nestedTryStmts);
   app(p.s[cpsStmts], 'excHandler = excHandler->prev;' + tnl);
   if (i < len) and (t.sons[i].kind = nkFinally) then begin
     genStmts(p, t.sons[i].sons[0]);
     if rethrowFlag <> nil then
-      appRopeFormat(p.s[cpsStmts], 'if ($1) { throw; }$n', [rethrowFlag])
+      appf(p.s[cpsStmts], 'if ($1) { throw; }$n', [rethrowFlag])
   end
 end;
 
@@ -698,21 +718,21 @@ begin
   genLineDir(p, t);
 
   safePoint := getTempName();
-  useMagic('TSafePoint');
-  useMagic('E_Base');
-  useMagic('excHandler');
-  appRopeFormat(p.s[cpsLocals], 'volatile TSafePoint $1;$n', [safePoint]);
-  appRopeFormat(p.s[cpsStmts], '$1.prev = excHandler;$n' +
-                               'excHandler = &$1;$n' +
-                               '$1.status = setjmp($1.context);$n' +
-                               'if ($1.status == 0) {$n', [safePoint]);
+  useMagic(p.module, 'TSafePoint');
+  useMagic(p.module, 'E_Base');
+  useMagic(p.module, 'excHandler');
+  appf(p.s[cpsLocals], 'TSafePoint $1;$n', [safePoint]);
+  appf(p.s[cpsStmts], '$1.prev = excHandler;$n' +
+                      'excHandler = &$1;$n' +
+                      '$1.status = setjmp($1.context);$n',
+                      [safePoint]);
   if optStackTrace in p.Options then
     app(p.s[cpsStmts], 'framePtr = (TFrame*)&F;' + tnl);
+  appf(p.s[cpsStmts], 'if ($1.status == 0) {$n', [safePoint]);
   len := sonsLen(t);
-  inc(p.inTryStmt);
+  inc(p.nestedTryStmts);
   genStmts(p, t.sons[0]);
   app(p.s[cpsStmts], '} else {' + tnl);
-  dec(p.inTryStmt);
   i := 1;
   while (i < len) and (t.sons[i].kind = nkExceptBranch) do begin
     blen := sonsLen(t.sons[i]);
@@ -720,7 +740,7 @@ begin
       // general except section:
       if i > 1 then app(p.s[cpsStmts], 'else {' + tnl);
       genStmts(p, t.sons[i].sons[0]);
-      appRopeFormat(p.s[cpsStmts], '$1.status = 0;$n', [safePoint]);
+      appf(p.s[cpsStmts], '$1.status = 0;$n', [safePoint]);
       if i > 1 then app(p.s[cpsStmts], '}' + tnl);
     end
     else begin
@@ -728,24 +748,25 @@ begin
       for j := 0 to blen - 2 do begin
         assert(t.sons[i].sons[j].kind = nkType);
         if orExpr <> nil then app(orExpr, '||');
-        appRopeFormat(orExpr, '($1.exc->Sup.m_type == $2)',
-          [safePoint, genTypeInfo(currMod, t.sons[i].sons[j].typ)])
+        appf(orExpr, '($1.exc->Sup.m_type == $2)',
+          [safePoint, genTypeInfo(p.module, t.sons[i].sons[j].typ)])
       end;
       if i > 1 then app(p.s[cpsStmts], 'else ');
-      appRopeFormat(p.s[cpsStmts], 'if ($1) {$n', [orExpr]);
+      appf(p.s[cpsStmts], 'if ($1) {$n', [orExpr]);
       genStmts(p, t.sons[i].sons[blen - 1]);
       // code to clear the exception:
-      appRopeFormat(p.s[cpsStmts], '$1.status = 0;}$n', [safePoint]);
+      appf(p.s[cpsStmts], '$1.status = 0;}$n', [safePoint]);
     end;
     inc(i)
   end;
   app(p.s[cpsStmts], '}' + tnl); // end of if statement
-  app(p.s[cpsStmts], 'excHandler = excHandler->prev;' + tnl);
+  finishTryStmt(p, p.nestedTryStmts);
+  dec(p.nestedTryStmts);
   if (i < len) and (t.sons[i].kind = nkFinally) then begin
     genStmts(p, t.sons[i].sons[0]);
-    useMagic('raiseException');
-    appRopeFormat(p.s[cpsStmts], 'if ($1.status != 0) { ' +
-      'raiseException($1.exc, $1.exc->Name); }$n', [safePoint])
+    useMagic(p.module, 'raiseException');
+    appf(p.s[cpsStmts], 'if ($1.status != 0) { ' +
+      'raiseException($1.exc, $1.exc->name); }$n', [safePoint])
   end
 end;
 
@@ -767,7 +788,7 @@ begin
       name := 'bp' + toString(breakPointId)
     end;
     genLineDir(p, t); // BUGFIX
-    appRopeFormat(gBreakpoints,
+    appf(gBreakpoints,
       'dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n',
       [toRope(toLinenumber(t.info)), makeCString(toFilename(t.info)),
       makeCString(name)])
@@ -852,15 +873,15 @@ begin
     nkCommentStmt, nkNilLit, nkIteratorDef, nkIncludeStmt, nkImportStmt,
     nkFromStmt, nkTemplateDef, nkMacroDef: begin end;
     nkPragma: genPragma(p, t);
-    nkProcDef: begin
+    nkProcDef, nkConverterDef: begin
       if (t.sons[genericParamsPos] = nil) then begin
         prc := t.sons[namePos].sym;
-        if (t.sons[codePos] <> nil) 
+        if (t.sons[codePos] <> nil)
         or (lfDynamicLib in prc.loc.flags) then begin // BUGFIX
-          if IntSetContainsOrIncl(currMod.debugDeclared, prc.id) then begin
+          if IntSetContainsOrIncl(p.module.debugDeclared, prc.id) then begin
             internalError(t.info, 'genProc()'); // XXX: remove this check!
           end;
-          genProc(prc)
+          genProc(p.module, prc)
         end
         //else if sfCompilerProc in prc.flags then genProcPrototype(prc);
       end
diff --git a/nim/ccgtypes.pas b/nim/ccgtypes.pas
index f375daaae..329d9f60c 100644
--- a/nim/ccgtypes.pas
+++ b/nim/ccgtypes.pas
@@ -9,12 +9,6 @@
 
 // ------------------------- Name Mangling --------------------------------
 
-function getUnique(p: BProc): PRope;
-begin
-  inc(p.unique);
-  result := toRope(p.unique)
-end;
-
 function mangle(const name: string): string;
 var
   i: int;
@@ -23,7 +17,7 @@ begin
     result := toUpper(name[strStart])+''
   else
     result := 'HEX' + toHex(ord(name[strStart]), 2);
-  for i := 2 to length(name) - 1 + strStart do begin
+  for i := strStart+1 to length(name) + strStart-1 do begin
     case name[i] of
       'A'..'Z': addChar(result, chr(ord(name[i]) - ord('A') + ord('a')));
       '_': begin end;
@@ -35,22 +29,68 @@ end;
 
 function mangleName(s: PSym): PRope;
 begin
-  if s.owner <> nil then
-    result := ropeFormat('$1_$2_$3', [toRope(mangle(s.owner.name.s)),
-                                      toRope(mangle(s.name.s)),
-                                      toRope(s.id)])
-  else
-    result := ropeFormat('$1_$2', [toRope(mangle(s.name.s)),
-                                  toRope(s.id)]);
+  result := ropef('$1_$2', [toRope(mangle(s.name.s)), toRope(s.id)]);
   if optGenMapping in gGlobalOptions then
     if s.owner <> nil then
-      appRopeFormat(gMapping, '$1.$2    $3$n',
+      appf(gMapping, '$1.$2    $3$n',
         [toRope(s.owner.Name.s), toRope(s.name.s), result])
 end;
 
 // ------------------------------ C type generator ------------------------
 
-function getTypeDesc(typ: PType): PRope; forward;
+function mapType(typ: PType): TCTypeKind;
+begin
+  case typ.kind of
+    tyNone: result := ctVoid;
+    tyBool: result := ctBool;
+    tyChar: result := ctChar;
+    tyEmptySet, tySet: begin
+      case int(getSize(typ)) of
+        1: result := ctInt8;
+        2: result := ctInt16;
+        4: result := ctInt32;
+        8: result := ctInt64;
+        else result := ctArray
+      end
+    end;
+    tyOpenArray, tyArrayConstr, tyArray: result := ctArray;
+    tyObject, tyTuple: result := ctStruct;
+    tyGeneric, tyGenericInst, tyGenericParam: result := mapType(lastSon(typ));
+    tyEnum, tyAnyEnum: begin
+      if firstOrd(typ) < 0 then
+        result := ctInt32
+      else begin
+        case int(getSize(typ)) of
+          1: result := ctUInt8;
+          2: result := ctUInt16;
+          4: result := ctInt32;
+          else internalError('mapType');
+        end
+      end
+    end;
+    tyRange: result := mapType(typ.sons[0]);
+    tyPtr, tyVar, tyRef: begin
+      case typ.sons[0].kind of
+        tyOpenArray, tyArrayConstr, tyArray: result := ctArray;
+        (*tySet: begin
+          if mapType(typ.sons[0]) = ctArray then result := ctArray
+          else result := ctPtr
+        end*)
+        else result := ctPtr
+      end
+    end;
+    tyPointer: result := ctPtr;
+    tySequence: result := ctNimSeq;
+    tyProc: result := ctProc;
+    tyString: result := ctNimStr;
+    tyCString: result := ctCString;
+    tyInt..tyFloat128:
+      result := TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt));
+    else InternalError('mapType');
+  end
+end;
+
+function getTypeDesc(m: BModule; typ: PType): PRope; forward;
 
 function needsComplexAssignment(typ: PType): bool;
 begin
@@ -58,8 +98,6 @@ begin
 end;
 
 function isInvalidReturnType(rettype: PType): bool;
-var
-  t: PType;
 begin
   // Arrays and sets cannot be returned by a C procedure, because C is
   // such a poor programming language.
@@ -68,16 +106,9 @@ begin
   if rettype = nil then
     result := true
   else begin
-    t := skipAbstract(rettype);
-    case t.kind of
-      tyArray, tyArrayConstr: result := true;
-      tyObject, tyRecord: result := needsComplexAssignment(t);
-      tySet: begin
-        case int(getSize(t)) of
-          1, 2, 4, 8: result := false;
-          else result := true
-        end
-      end
+    case mapType(rettype) of
+      ctArray: result := true;
+      ctStruct: result := needsComplexAssignment(skipGeneric(rettype));
       else result := false;
     end
   end
@@ -96,65 +127,46 @@ begin
   result := PRope(TableGetType(tab, key))
 end;
 
-var
-  gUnique: int;
-
 function getTempName(): PRope;
 begin
   inc(gUnique);
   result := con('T'+'', toRope(gUnique))
 end;
 
-function isCArray(typ: PType): bool;
-var
-  t: PType;
-begin
-  t := skipVarGeneric(typ);
-  case t.kind of
-    tyArray, tyArrayConstr, tyOpenArray: result := true;
-    tySet: result := getSize(t) > 8;
-    else result := false
-  end
-end;
-
-function UsePtrPassing(param: PSym): bool;
-// this is pretty complicated ...
+function ccgIntroducedPtr(s: PSym): bool;
 var
   pt: PType;
 begin
-  pt := param.typ;
-  if (sfResult in param.flags) and not isInvalidReturnType(pt) then
-    result := false  // BUGFIX
-  else if pt.Kind = tyObject then begin
-    // objects are always passed by reference,
-    // otherwise implicit casting doesn't work
-    result := true;
-  end
-  else if (pt.kind in [tyRecordConstr, tyRecord]) and
-      ((getSize(pt) > platform.floatSize) or
-        (optByRef in param.options)) then begin
-    result := true;
-  end
-  else if isCArray(pt) then
-    result := false
-  else if (pt.kind = tyVar) or (getSize(pt) > platform.floatSize) then begin
-    result := true;
+  pt := s.typ;
+  assert(not (sfResult in s.flags));
+  case pt.Kind of
+    tyObject: begin
+      if (optByRef in s.options) or (getSize(pt) > platform.floatSize) then
+        result := true // requested anyway
+      else if (tfFinal in pt.flags) and (pt.sons[0] = nil) then
+        result := false // no need, because no subtyping possible
+      else
+        result := true; // ordinary objects are always passed by reference,
+                        // otherwise casting doesn't work
+    end;
+    tyTuple:
+      result := (getSize(pt) > platform.floatSize) or (optByRef in s.options);
+    else
+      result := false
   end
-  else
-    result := false
 end;
 
-const
-  PointerTypes = {@set}[tySequence, tyString, tyRef, tyPtr, tyPointer];
-
 procedure fillResult(param: PSym);
 begin
-  fillLoc(param.loc, locParam, param.typ,
-          toRope('Result'), {@set}[lfOnUnknown]);
-  if UsePtrPassing(param) then param.loc.indirect := 1
+  fillLoc(param.loc, locParam, param.typ, toRope('Result'), OnStack);
+  if (mapType(param.typ) <> ctArray) and IsInvalidReturnType(param.typ) then
+  begin
+    include(param.loc.flags, lfIndirect);
+    param.loc.s := OnUnknown
+  end
 end;
 
-procedure genProcParams(t: PType; out rettype, params: PRope);
+procedure genProcParams(m: BModule; t: PType; out rettype, params: PRope);
 var
   i, j: int;
   param: PSym;
@@ -165,31 +177,25 @@ begin
     // C cannot return arrays (what a poor language...)
     rettype := toRope('void')
   else
-    rettype := getTypeDesc(t.sons[0]);
+    rettype := getTypeDesc(m, t.sons[0]);
   for i := 1 to sonsLen(t.n)-1 do begin
-    assert(t.n.sons[i].kind = nkSym);
+    if t.n.sons[i].kind <> nkSym then InternalError(t.n.info, 'genProcParams');
     param := t.n.sons[i].sym;
-    fillLoc(param.loc, locParam, param.typ,
-            con(toRope('Par'), toRope(i)), {@set}[lfOnStack]);
-    if param.typ.kind = tyVar then begin
-      param.loc.flags := {@set}[lfOnUnknown]; // BUGFIX!
-      app(params, getTypeDesc(param.typ.sons[0]));
-    end
-    else
-      app(params, getTypeDesc(param.typ));
-    if UsePtrPassing(param) then begin
+    fillLoc(param.loc, locParam, param.typ, mangleName(param), OnStack);
+    app(params, getTypeDesc(m, param.typ));
+    if ccgIntroducedPtr(param) then begin
       app(params, '*'+'');
-      param.loc.indirect := 1
+      include(param.loc.flags, lfIndirect);
+      param.loc.s := OnUnknown;
     end;
     app(params, ' '+'');
-
     app(params, param.loc.r);
     // declare the len field for open arrays:
     arr := param.typ;
     if arr.kind = tyVar then arr := arr.sons[0];
     j := 0;
     while arr.Kind = tyOpenArray do begin // need to pass hidden parameter:
-      appRopeFormat(params, ', const int $1Len$2', [param.loc.r, toRope(j)]);
+      appf(params, ', NI $1Len$2', [param.loc.r, toRope(j)]);
       inc(j);
       arr := arr.sons[0]
     end;
@@ -197,8 +203,8 @@ begin
   end;
   if (t.sons[0] <> nil) and isInvalidReturnType(t.sons[0]) then begin
     if params <> nil then app(params, ', ');
-    app(params, getTypeDesc(t.sons[0]));
-    if not isCArray(t.sons[0]) then app(params, '*'+'');
+    app(params, getTypeDesc(m, t.sons[0]));
+    if mapType(t.sons[0]) <> ctArray then app(params, '*'+'');
     app(params, ' Result');
   end;
   if t.callConv = ccClosure then begin
@@ -216,11 +222,6 @@ begin
   params := con('('+'', params);
 end;
 
-function getLengthOfSet(s: PNode): int;
-begin
-  result := int(getSize(s.typ))
-end;
-
 function isImportedType(t: PType): bool;
 begin
   result := (t.sym <> nil) and (sfImportc in t.sym.flags)
@@ -228,25 +229,10 @@ end;
 
 function getTypeName(typ: PType): PRope;
 begin
-  if typ.sym <> nil then begin
-    result := typ.sym.loc.r;
-    if result = nil then begin
-      assert(typ.owner <> nil);
-      result := toRope(mangle(typ.owner.Name.s) + '_' +{&}
-                       mangle(typ.sym.name.s));
-    end
-  end
+  if (typ.sym <> nil) and ([sfImportc, sfExportc] * typ.sym.flags <> []) then
+    result := typ.sym.loc.r
   else begin
-    // we must use a unique type id here because we don't store
-    // whether a type has to be given a certain name because its
-    // forward declaration has already been given:
-    if typ.loc.r = nil then begin
-      inc(currMod.unique);
-      assert(typ.owner <> nil);
-      typ.loc.r := ropeFormat('$1_Ty$2', [
-        toRope(mangle(typ.owner.Name.s)),
-        toRope(currMod.unique)])
-    end;
+    if typ.loc.r = nil then typ.loc.r := con('Ty', toRope(typ.id));
     result := typ.loc.r
   end
 end;
@@ -262,18 +248,18 @@ end;
 function getSimpleTypeDesc(typ: PType): PRope;
 const
   NumericalTypeToStr: array [tyInt..tyFloat128] of string = (
-    'NS', 'NS8', 'NS16', 'NS32', 'NS64', 'NF', 'NF32', 'NF64', 'NF128');
+    'NI', 'NI8', 'NI16', 'NI32', 'NI64', 'NF', 'NF32', 'NF64', 'NF128');
 begin
   case typ.Kind of
     tyPointer: result := typeNameOrLiteral(typ, 'void*');
     tyEnum: begin
       if firstOrd(typ) < 0 then
-        result := typeNameOrLiteral(typ, 'NS32')
+        result := typeNameOrLiteral(typ, 'NI32')
       else begin
         case int(getSize(typ)) of
           1: result := typeNameOrLiteral(typ, 'NU8');
           2: result := typeNameOrLiteral(typ, 'NU16');
-          4: result := typeNameOrLiteral(typ, 'NS32');
+          4: result := typeNameOrLiteral(typ, 'NI32');
           else begin
             internalError('getSimpleTypeDesc()');
             result := nil
@@ -293,14 +279,14 @@ begin
   end
 end;
 
-function getTypePre(typ: PType): PRope;
+function getTypePre(m: BModule; typ: PType): PRope;
 begin
   if typ = nil then
     result := toRope('void')
   else begin
     result := getSimpleTypeDesc(typ);
     if result = nil then
-      result := CacheGetType(currMod.typeCache, typ)
+      result := CacheGetType(m.typeCache, typ)
   end
 end;
 
@@ -310,19 +296,18 @@ begin
   else result := 'typedef struct $1 $1;$n'
 end;
 
-function getTypeForward(typ: PType): PRope;
+function getTypeForward(m: BModule; typ: PType): PRope;
 begin
-  result := CacheGetType(currMod.forwTypeCache, typ);
+  result := CacheGetType(m.forwTypeCache, typ);
   if result <> nil then exit;
-  result := getTypePre(typ);
+  result := getTypePre(m, typ);
   if result <> nil then exit;
   case typ.kind of
-    tySequence, tyRecord, tyObject: begin
+    tySequence, tyTuple, tyObject: begin
       result := getTypeName(typ);
       if not isImportedType(typ) then
-        appRopeFormat(currMod.s[cfsForwardTypes],
-          getForwardStructFormat(), [result]);
-      IdTablePut(currMod.forwTypeCache, typ, result)
+        appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result]);
+      IdTablePut(m.forwTypeCache, typ, result)
     end
     else
       InternalError('getTypeForward(' + typeKindToStr[typ.kind] + ')')
@@ -333,205 +318,254 @@ function mangleRecFieldName(field: PSym; rectype: PType): PRope;
 begin
   if (rectype.sym <> nil)
   and ([sfImportc, sfExportc] * rectype.sym.flags <> []) then
-    result := toRope(field.name.s)
+    result := field.loc.r
   else
-    result := toRope(mangle(field.name.s))
+    result := toRope(mangle(field.name.s));
+  if result = nil then InternalError(field.info, 'mangleRecFieldName');
 end;
 
-function genRecordFieldsAux(n: PNode; accessExpr: PRope; rectype: PType): PRope;
+function genRecordFieldsAux(m: BModule; n: PNode; accessExpr: PRope;
+                            rectype: PType): PRope;
 var
   i: int;
   ae, uname, sname, a: PRope;
-  m: PNode;
+  k: PNode;
   field: PSym;
 begin
   result := nil;
   case n.kind of
     nkRecList: begin
       for i := 0 to sonsLen(n)-1 do begin
-        app(result, genRecordFieldsAux(n.sons[i], accessExpr, rectype));
+        app(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype));
       end
     end;
     nkRecCase: begin
-      assert(n.sons[0].kind = nkSym);
-      app(result, genRecordFieldsAux(n.sons[0], accessExpr, rectype));
+      if (n.sons[0].kind <> nkSym) then
+        InternalError(n.info, 'genRecordFieldsAux');
+      app(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype));
       uname := toRope(mangle(n.sons[0].sym.name.s)+ 'U');
-      if accessExpr <> nil then ae := ropeFormat('$1.$2', [accessExpr, uname])
+      if accessExpr <> nil then ae := ropef('$1.$2', [accessExpr, uname])
       else ae := uname;
       app(result, 'union {'+tnl);
       for i := 1 to sonsLen(n)-1 do begin
         case n.sons[i].kind of
           nkOfBranch, nkElse: begin
-            m := lastSon(n.sons[i]);
-            if m.kind <> nkSym then begin
+            k := lastSon(n.sons[i]);
+            if k.kind <> nkSym then begin
               sname := con('S'+'', toRope(i));
-              a := genRecordFieldsAux(m, ropeFormat('$1.$2', [ae, sname]),
+              a := genRecordFieldsAux(m, k, ropef('$1.$2', [ae, sname]),
                                       rectype);
               if a <> nil then begin
                 app(result, 'struct {');
                 app(result, a);
-                appRopeFormat(result, '} $1;$n', [sname]);
+                appf(result, '} $1;$n', [sname]);
               end
             end
-            else app(result, genRecordFieldsAux(m, ae, rectype));
+            else app(result, genRecordFieldsAux(m, k, ae, rectype));
           end;
           else internalError('genRecordFieldsAux(record case branch)');
         end;
       end;
-      appRopeFormat(result, '} $1;$n', [uname])
+      appf(result, '} $1;$n', [uname])
     end;
     nkSym: begin
       field := n.sym;
       assert(field.ast = nil);
       sname := mangleRecFieldName(field, rectype);
-      if accessExpr <> nil then ae := ropeFormat('$1.$2', [accessExpr, sname])
+      if accessExpr <> nil then ae := ropef('$1.$2', [accessExpr, sname])
       else ae := sname;
-      fillLoc(field.loc, locField, field.typ, ae, {@set}[]);
-      appRopeFormat(result, '$1 $2;$n', [getTypeDesc(field.loc.t), sname])
+      fillLoc(field.loc, locField, field.typ, ae, OnUnknown);
+      appf(result, '$1 $2;$n', [getTypeDesc(m, field.loc.t), sname])
     end;
     else internalError(n.info, 'genRecordFieldsAux()');
   end
 end;
 
-function getRecordFields(typ: PType): PRope;
+function getRecordFields(m: BModule; typ: PType): PRope;
 begin
-  result := genRecordFieldsAux(typ.n, nil, typ);
+  result := genRecordFieldsAux(m, typ.n, nil, typ);
 end;
 
-function getRecordDesc(typ: PType; name: PRope): PRope;
+function getRecordDesc(m: BModule; typ: PType; name: PRope): PRope;
 var
   desc: PRope;
+  hasField: bool;
 begin
   // declare the record:
+  hasField := false;
   if typ.kind = tyObject then begin
-    useMagic('TNimType');
+    useMagic(m, 'TNimType');
     if typ.sons[0] = nil then begin
-      if (typ.sym <> nil) and (sfPure in typ.sym.flags) then
-        result := ropeFormat('struct $1 {$n', [name])
-      else
-        result := ropeFormat('struct $1 {$nTNimType* m_type;$n', [name])
+      if (typ.sym <> nil) and (sfPure in typ.sym.flags)
+      or (tfFinal in typ.flags) then
+        result := ropef('struct $1 {$n', [name])
+      else begin
+        result := ropef('struct $1 {$nTNimType* m_type;$n', [name]);
+        hasField := true
+      end
+    end
+    else if gCmd = cmdCompileToCpp then begin
+      result := ropef('struct $1 : public $2 {$n',
+        [name, getTypeDesc(m, typ.sons[0])]);
+      hasField := true
+    end
+    else begin
+      result := ropef('struct $1 {$n  $2 Sup;$n',
+        [name, getTypeDesc(m, typ.sons[0])]);
+      hasField := true
     end
-    else if gCmd = cmdCompileToCpp then
-      result := ropeFormat('struct $1 : public $2 {$n',
-        [name, getTypeDesc(typ.sons[0])])
-    else
-      result := ropeFormat('struct $1 {$n  $2 Sup;$n',
-        [name, getTypeDesc(typ.sons[0])])
   end
   else
-    result := ropeFormat('struct $1 {$n', [name]);
-  desc := getRecordFields(typ);
-  if (typ.kind <> tyObject) and (desc = nil) and (gCmd <> cmdCompileToCpp) then
+    result := ropef('struct $1 {$n', [name]);
+  desc := getRecordFields(m, typ);
+  if (desc = nil) and not hasField then
   // no fields in struct are not valid in C, so generate a dummy:
-    appRopeFormat(result, 'char dummy;$n', [])
+    appf(result, 'char dummy;$n', [])
   else
     app(result, desc);
   app(result, '};' + tnl);
 end;
 
-function getTypeDesc(typ: PType): PRope;
+procedure pushType(m: BModule; typ: PType);
+var
+  L: int;
+begin
+  L := length(m.typeStack);
+  setLength(m.typeStack, L+1);
+  m.typeStack[L] := typ;
+end;
+
+function getTypeDesc(m: BModule; typ: PType): PRope;
 // returns only the type's name
 var
   name, rettype, desc, recdesc: PRope;
   n: biggestInt;
+  t, et: PType;
 begin
-  if typ.sym <> nil then useHeader(typ.sym);
-  result := getTypePre(typ);
+  t := getUniqueType(typ);
+  if t = nil then InternalError('getTypeDesc: t == nil');
+  if t.sym <> nil then useHeader(m, t.sym);
+  result := getTypePre(m, t);
   if result <> nil then exit;
-  case typ.Kind of
+  case t.Kind of
     tyRef, tyPtr, tyVar, tyOpenArray: begin
-      case typ.sons[0].Kind of
-        tyRecord, tyObject, tySequence: begin
-          // no restriction!
-          // We have a forward declaration for structs
-          name := getTypeForward(typ.sons[0]);
+      et := getUniqueType(t.sons[0]);
+      if et.kind in [tyArrayConstr, tyArray, tyOpenArray] then
+        et := getUniqueType(elemType(et));
+      case et.Kind of
+        tyObject, tyTuple: begin
+          // no restriction! We have a forward declaration for structs
+          name := getTypeForward(m, et);
           result := con(name, '*'+'');
-          IdTablePut(currMod.typeCache, typ, result)
+          IdTablePut(m.typeCache, t, result);
+          pushType(m, et);
+        end;
+        tySequence: begin
+          // no restriction! We have a forward declaration for structs
+          name := getTypeForward(m, et);
+          result := con(name, '**');
+          IdTablePut(m.typeCache, t, result);
+          pushType(m, et);
         end;
         else begin
           // else we have a strong dependency  :-(
-          result := con(getTypeDesc(typ.sons[0]), '*'+'');
-          IdTablePut(currMod.typeCache, typ, result)
+          result := con(getTypeDesc(m, et), '*'+'');
+          IdTablePut(m.typeCache, t, result)
         end
       end
     end;
     tyProc: begin
-      result := getTypeName(typ);
-      IdTablePut(currMod.typeCache, typ, result);
-      genProcParams(typ, rettype, desc);
-      if not isImportedType(typ) then begin
-        if typ.callConv <> ccClosure then
-          appRopeFormat(currMod.s[cfsTypes], 'typedef $1_PTR($2, $3) $4;$n',
-            [toRope(CallingConvToStr[typ.callConv]), rettype, result, desc])
+      result := getTypeName(t);
+      IdTablePut(m.typeCache, t, result);
+      genProcParams(m, t, rettype, desc);
+      if not isImportedType(t) then begin
+        if t.callConv <> ccClosure then
+          appf(m.s[cfsTypes], 'typedef $1_PTR($2, $3) $4;$n',
+            [toRope(CallingConvToStr[t.callConv]), rettype, result, desc])
         else // procedure vars may need a closure!
-          appRopeFormat(currMod.s[cfsTypes], 'typedef struct $1 {$n' +
-                                             'N_CDECL_PTR($2, PrcPart) $3;$n' +
-                                             'void* ClPart;$n};$n',
+          appf(m.s[cfsTypes], 'typedef struct $1 {$n' +
+                              'N_CDECL_PTR($2, PrcPart) $3;$n' +
+                              'void* ClPart;$n};$n',
             [result, rettype, desc]);
       end
     end;
     tySequence: begin
-      // we cannot use getTypeForward here because then typ would be associated
+      // we cannot use getTypeForward here because then t would be associated
       // with the name of the struct, not with the pointer to the struct:
-      result := getTypeName(typ);
-      IdTablePut(currMod.typeCache, typ, con(result, '*'+''));
-      if not isImportedType(typ) then begin
-        appRopeFormat(currMod.s[cfsForwardTypes],
-          getForwardStructFormat(), [result]);
-        appRopeFormat(currMod.s[cfsSeqTypes],
-          // BUGFIX: needed to introduce cfsSeqTypes
+      result := CacheGetType(m.forwTypeCache, t);
+      if result = nil then begin
+        result := getTypeName(t);
+        if not isImportedType(t) then
+          appf(m.s[cfsForwardTypes], getForwardStructFormat(), [result]);
+        IdTablePut(m.forwTypeCache, t, result);
+      end;
+      assert(CacheGetType(m.typeCache, t) = nil);
+      IdTablePut(m.typeCache, t, con(result, '*'+''));
+      if not isImportedType(t) then
+        appf(m.s[cfsSeqTypes],
           'struct $2 {$n' +
-          '  NS len, space;$n' +
+          '  NI len, space;$n' +
           '  $1 data[SEQ_DECL_SIZE];$n' +
-          '};$n', [getTypeDesc(typ.sons[0]), result]);
-      end;
+          '};$n', [getTypeDesc(m, t.sons[0]), result]);
       app(result, '*'+'');
     end;
     tyArrayConstr, tyArray: begin
-      n := lengthOrd(typ);
+      n := lengthOrd(t);
       if n <= 0 then n := 1; // make an array of at least one element
-      result := getTypeName(typ);
-      IdTablePut(currMod.typeCache, typ, result);
-      if not isImportedType(typ) then
-        appRopeFormat(currMod.s[cfsTypes], 'typedef $1 $2[$3];$n',
-          [getTypeDesc(typ.sons[1]), result, ToRope(n)])
+      result := getTypeName(t);
+      IdTablePut(m.typeCache, t, result);
+      if not isImportedType(t) then
+        appf(m.s[cfsTypes], 'typedef $1 $2[$3];$n',
+          [getTypeDesc(m, t.sons[1]), result, ToRope(n)])
     end;
-    tyObject, tyRecord, tyRecordConstr: begin
-      result := getTypeName(typ);
-      IdTablePut(currMod.typeCache, typ, result);
-      recdesc := getRecordDesc(typ, result); // always compute for sideeffects
-      if not isImportedType(typ) then
-        app(currMod.s[cfsTypes], recdesc);
-      if CacheGetType(currMod.forwTypeCache, typ) = nil then begin
-        if not isImportedType(typ) then
-          appRopeFormat(currMod.s[cfsForwardTypes],
+    tyObject, tyTuple: begin
+      result := CacheGetType(m.forwTypeCache, t);
+      if result = nil then begin
+        result := getTypeName(t);
+        if not isImportedType(t) then
+          appf(m.s[cfsForwardTypes],
             getForwardStructFormat(), [result]);
-        IdTablePut(currMod.forwTypeCache, typ, result)
-      end
+        IdTablePut(m.forwTypeCache, t, result)
+      end;
+      IdTablePut(m.typeCache, t, result);
+      recdesc := getRecordDesc(m, t, result); // always call for sideeffects
+      if not isImportedType(t) then app(m.s[cfsTypes], recdesc);
     end;
     tySet: begin
-      case int(getSize(typ)) of
-        1: result := toRope('NS8');
-        2: result := toRope('NS16');
-        4: result := toRope('NS32');
-        8: result := toRope('NS64');
+      case int(getSize(t)) of
+        1: result := toRope('NU8');
+        2: result := toRope('NU16');
+        4: result := toRope('NU32');
+        8: result := toRope('NU64');
         else begin
-          result := getTypeName(typ);
-          IdTablePut(currMod.typeCache, typ, result);
-          if not isImportedType(typ) then
-            appRopeFormat(currMod.s[cfsTypes], 'typedef NS8 $1[$2];$n',
-              [result, toRope(getSize(typ))])
+          result := getTypeName(t);
+          IdTablePut(m.typeCache, t, result);
+          if not isImportedType(t) then
+            appf(m.s[cfsTypes], 'typedef NU8 $1[$2];$n',
+              [result, toRope(getSize(t))])
         end
       end
-    end
+    end;
+    tyGenericInst: result := getTypeDesc(m, lastSon(t));
     else begin
-      InternalError('getTypeDesc(' + typeKindToStr[typ.kind] + ')');
+      InternalError('getTypeDesc(' + typeKindToStr[t.kind] + ')');
       result := nil
     end
   end
 end;
 
-function genProcHeader(prc: PSym): PRope;
+procedure finishTypeDescriptions(m: BModule);
+var
+  i: int;
+begin
+  i := 0;
+  while i < length(m.typeStack) do begin
+    {@discard} getTypeDesc(m, m.typeStack[i]);
+    inc(i);
+  end;
+end;
+
+function genProcHeader(m: BModule; prc: PSym): PRope;
 var
   rettype, params: PRope;
 begin
@@ -540,9 +574,9 @@ begin
     result := toRope('static ')
   else
     result := nil;
-  fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), {@set}[]);
-  genProcParams(prc.typ, rettype, params);
-  appRopeFormat(result, '$1($2, $3)$4',
+  fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), OnUnknown);
+  genProcParams(m, prc.typ, rettype, params);
+  appf(result, '$1($2, $3)$4',
                [toRope(CallingConvToStr[prc.typ.callConv]),
                rettype, prc.loc.r, params])
 end;
@@ -559,19 +593,26 @@ var
   tmp: PRope;
 begin
   tmp := getTempName();
-  appRopeFormat(m.s[cfsTypeInit1], 'static TNimType $1;$n', [tmp]);
-  appRopeFormat(m.s[cfsTypeInit2], '$2 = &$1;$n', [tmp, name]);
+  appf(m.s[cfsTypeInit1], 'static TNimType $1;$n', [tmp]);
+  appf(m.s[cfsTypeInit2], '$2 = &$1;$n', [tmp, name]);
 end;
 
 procedure genTypeInfoAuxBase(m: BModule; typ: PType; name, base: PRope);
+var
+  nimtypeKind: int;
 begin
   allocMemTI(m, name);
-  appRopeFormat(m.s[cfsTypeInit3],
+  if (typ.kind = tyObject) and (tfFinal in typ.flags)
+  and (typ.sons[0] = nil) then
+    nimtypeKind := ord(high(TTypeKind))+1 // tyPureObject
+  else
+    nimtypeKind := ord(typ.kind);
+  appf(m.s[cfsTypeInit3],
     '$1->size = sizeof($2);$n' +
     '$1->kind = $3;$n' +
     '$1->base = $4;$n', [
-    name, getTypeDesc(typ), toRope(ord(typ.kind)), base]);
-  appRopeFormat(m.s[cfsVars], 'TNimType* $1;$n', [name]);
+    name, getTypeDesc(m, typ), toRope(nimtypeKind), base]);
+  appf(m.s[cfsVars], 'TNimType* $1;$n', [name]);
 end;
 
 procedure genTypeInfoAux(m: BModule; typ: PType; name: PRope);
@@ -599,21 +640,21 @@ begin
         genObjectFields(m, typ, n.sons[0], expr)
       else if len > 0 then begin
         tmp := getTempName();
-        appRopeFormat(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n',
-                                         [tmp, toRope(len)]);
+        appf(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n',
+            [tmp, toRope(len)]);
         for i := 0 to len-1 do begin
           tmp2 := getTempName();
-          appRopeFormat(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp2]);
-          appRopeFormat(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
+          appf(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp2]);
+          appf(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
                         [tmp, toRope(i), tmp2]);
           genObjectFields(m, typ, n.sons[i], tmp2);
         end;
-        appRopeFormat(m.s[cfsTypeInit3],
-          '$1.len = $2; $1.kind = 2; $1.sons = &$3;$n', [
+        appf(m.s[cfsTypeInit3],
+          '$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n', [
           expr, toRope(len), tmp]);
       end
       else
-        appRopeFormat(m.s[cfsTypeInit3],
+        appf(m.s[cfsTypeInit3],
           '$1.len = $2; $1.kind = 2;$n', [expr, toRope(len)]);
     end;
     nkRecCase: begin
@@ -621,22 +662,22 @@ begin
       assert(n.sons[0].kind = nkSym);
       field := n.sons[0].sym;
       tmp := getTempName();
-      appRopeFormat(m.s[cfsTypeInit3], '$1.kind = 3;$n' +
-                                       '$1.offset = offsetof($2, $3);$n' +
-                                       '$1.typ = $4;$n' +
-                                       '$1.name = $5;$n' +
-                                       '$1.sons = &$6;$n' +
-                                       '$1.len = $7;$n',
-            [expr, getTypeDesc(typ), field.loc.r,
+      appf(m.s[cfsTypeInit3], '$1.kind = 3;$n' +
+                              '$1.offset = offsetof($2, $3);$n' +
+                              '$1.typ = $4;$n' +
+                              '$1.name = $5;$n' +
+                              '$1.sons = &$6[0];$n' +
+                              '$1.len = $7;$n',
+            [expr, getTypeDesc(m, typ), field.loc.r,
              genTypeInfo(m, field.typ),
              makeCString(field.name.s), tmp,
              toRope(lengthOrd(field.typ))]);
-      appRopeFormat(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n',
+      appf(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n',
                                        [tmp, toRope(lengthOrd(field.typ)+1)]);
       for i := 1 to len-1 do begin
         b := n.sons[i]; // branch
         tmp2 := getTempName();
-        appRopeFormat(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp2]);
+        appf(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp2]);
         genObjectFields(m, typ, lastSon(b), tmp2);
         //writeln(output, renderTree(b.sons[j]));
         case b.kind of
@@ -648,18 +689,18 @@ begin
                 x := int(getOrdValue(b.sons[j].sons[0]));
                 y := int(getOrdValue(b.sons[j].sons[1]));
                 while x <= y do begin
-                  appRopeFormat(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
+                  appf(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
                                 [tmp, toRope(x), tmp2]);
                   inc(x);
                 end;
               end
               else
-                appRopeFormat(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
+                appf(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
                              [tmp, toRope(getOrdValue(b.sons[j])), tmp2])
             end
           end;
           nkElse: begin
-            appRopeFormat(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
+            appf(m.s[cfsTypeInit3], '$1[$2] = &$3;$n',
                           [tmp, toRope(lengthOrd(field.typ)), tmp2]);
           end
           else
@@ -669,13 +710,13 @@ begin
     end;
     nkSym: begin
       field := n.sym;
-      appRopeFormat(m.s[cfsTypeInit3], '$1.kind = 1;$n' +
-                                       '$1.offset = offsetof($2, $3);$n' +
-                                       '$1.typ = $4;$n' +
-                                       '$1.name = $5;$n',
-                                       [expr, getTypeDesc(typ), field.loc.r,
-                                       genTypeInfo(m, field.typ),
-                                       makeCString(field.name.s)]);
+      appf(m.s[cfsTypeInit3], '$1.kind = 1;$n' +
+                              '$1.offset = offsetof($2, $3);$n' +
+                              '$1.typ = $4;$n' +
+                              '$1.name = $5;$n',
+                              [expr, getTypeDesc(m, typ), field.loc.r,
+                              genTypeInfo(m, field.typ),
+                              makeCString(field.name.s)]);
     end;
     else internalError(n.info, 'genObjectFields');
   end
@@ -685,11 +726,12 @@ procedure genObjectInfo(m: BModule; typ: PType; name: PRope);
 var
   tmp: PRope;
 begin
-  genTypeInfoAux(m, typ, name);
+  if typ.kind = tyObject then genTypeInfoAux(m, typ, name)
+  else genTypeInfoAuxBase(m, typ, name, toRope('0'+''));
   tmp := getTempName();
-  appRopeFormat(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp]);
+  appf(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp]);
   genObjectFields(m, typ, typ.n, tmp);
-  appRopeFormat(m.s[cfsTypeInit3], '$1->node = &$2;$n', [name, tmp]);
+  appf(m.s[cfsTypeInit3], '$1->node = &$2;$n', [name, tmp]);
 end;
 
 procedure genEnumInfo(m: BModule; typ: PType; name: PRope);
@@ -702,25 +744,25 @@ begin
   tmp := getTempName();
   tmp2 := getTempName();
   len := sonsLen(typ.n);
-  appRopeFormat(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n' +
-                                   'static TNimNode $3;$n',
-                                   [tmp, toRope(len), tmp2]);
+  appf(m.s[cfsTypeInit1], 'static TNimNode* $1[$2];$n' +
+                          'static TNimNode $3;$n',
+                          [tmp, toRope(len), tmp2]);
   for i := 0 to len-1 do begin
     assert(typ.n.sons[i].kind = nkSym);
     field := typ.n.sons[i].sym;
     tmp3 := getTempName();
-    appRopeFormat(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp3]);
-    appRopeFormat(m.s[cfsTypeInit3], '$1[$2] = &$3;$n' +
-                                     '$3.kind = 1;$n' +
-                                     '$3.offset = $4;$n' +
-                                     '$3.typ = $5;$n' +
-                                     '$3.name = $6;$n',
+    appf(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp3]);
+    appf(m.s[cfsTypeInit3], '$1[$2] = &$3;$n' +
+                            '$3.kind = 1;$n' +
+                            '$3.offset = $4;$n' +
+                            '$3.typ = $5;$n' +
+                            '$3.name = $6;$n',
                   [tmp, toRope(i), tmp3,
                    toRope(field.position),
                    name, makeCString(field.name.s)]);
   end;
-  appRopeFormat(m.s[cfsTypeInit3],
-    '$1.len = $2; $1.kind = 2; $1.sons = &$3;$n$4->node = &$1;$n', [
+  appf(m.s[cfsTypeInit3],
+    '$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n$4->node = &$1;$n', [
     tmp2, toRope(len), tmp, name]);
 end;
 
@@ -731,8 +773,8 @@ begin
   assert(typ.sons[0] <> nil);
   genTypeInfoAux(m, typ, name);
   tmp := getTempName();
-  appRopeFormat(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp]);
-  appRopeFormat(m.s[cfsTypeInit3],
+  appf(m.s[cfsTypeInit1], 'static TNimNode $1;$n', [tmp]);
+  appf(m.s[cfsTypeInit3],
     '$1.len = $2; $1.kind = 0;$n' +
     '$3->node = &$1;$n', [tmp, toRope(firstOrd(typ)), name]);
 end;
@@ -746,14 +788,13 @@ function genTypeInfo(m: BModule; typ: PType): PRope;
 var
   t: PType;
 begin
-  t := typ;
-  if t.kind = tyGenericInst then t := lastSon(t);
-  result := ropeFormat('NTI$1', [toRope(t.id)]);
+  t := getUniqueType(typ);
+  result := ropef('NTI$1', [toRope(t.id)]);
   if not IntSetContainsOrIncl(m.typeInfoMarker, t.id) then begin
     // declare type information structures:
-    useMagic('TNimType');
-    useMagic('TNimNode');
-    appRopeFormat(m.s[cfsVars], 'extern TNimType* $1;$n', [result]);
+    useMagic(m, 'TNimType');
+    useMagic(m, 'TNimNode');
+    appf(m.s[cfsVars], 'extern TNimType* $1;$n', [result]);
   end;
   if IntSetContainsOrIncl(gTypeInfoGenerated, t.id) then exit;
   case t.kind of
@@ -763,7 +804,7 @@ begin
     tyArrayConstr, tyArray: genArrayInfo(m, t, result);
     tySet: genSetInfo(m, t, result);
     tyEnum: genEnumInfo(m, t, result);
-    tyObject, tyRecord, tyRecordConstr: genObjectInfo(m, t, result);
+    tyObject, tyTuple: genObjectInfo(m, t, result);
     tyVar: result := genTypeInfo(m, typ.sons[0]);
     else InternalError('genTypeInfo(' + typekindToStr[t.kind] + ')');
   end
diff --git a/nim/ccgutils.pas b/nim/ccgutils.pas
index 6817f4518..09cd504bc 100644
--- a/nim/ccgutils.pas
+++ b/nim/ccgutils.pas
@@ -17,15 +17,41 @@ interface
 
 uses
   charsets, nsystem,
-  ast, astalgo, ropes, lists, hashes, strutils, types;
+  ast, astalgo, ropes, lists, hashes, strutils, types, msgs;
 
 function toCChar(c: Char): string;
 function makeCString(const s: string): PRope;
 
 function TableGetType(const tab: TIdTable; key: PType): PObject;
+function GetUniqueType(key: PType): PType;
 
 implementation
 
+var
+  gTypeTable: TIdTable;
+
+function GetUniqueType(key: PType): PType;
+var
+  t: PType;
+  h: THash;
+begin
+  result := key;
+  if key = nil then exit;
+  assert(key.kind <> tyForward);
+  if key.kind = tyGenericInst then begin
+    result := GetUniqueType(lastSon(key));
+    exit
+  end;
+  if IdTableHasObjectAsKey(gTypeTable, key) then exit;
+  // we have to do a slow linear search because types may need
+  // to be compared by their structure:
+  for h := 0 to high(gTypeTable.data) do begin
+    t := PType(gTypeTable.data[h].key);
+    if (t <> nil) and sameType(t, key) then begin result := t; exit end
+  end;
+  IdTablePut(gTypeTable, key, key);
+end;
+
 function TableGetType(const tab: TIdTable; key: PType): PObject;
 var
   t: PType;
@@ -69,7 +95,7 @@ begin
   result := nil;
   res := '"'+'';
   for i := strStart to length(s)+strStart-1 do begin
-    if i mod MaxLineLength = 0 then begin
+    if (i-strStart+1) mod MaxLineLength = 0 then begin
       res := res +{&} '"' +{&} nl;
       app(result, toRope(res));
       res := '"'+''; // reset
@@ -80,4 +106,6 @@ begin
   app(result, toRope(res));
 end;
 
+initialization
+  InitIdTable(gTypeTable);
 end.
diff --git a/nim/cgen.pas b/nim/cgen.pas
index 9c0e122f2..677a9b0ac 100644
--- a/nim/cgen.pas
+++ b/nim/cgen.pas
@@ -43,13 +43,28 @@ type
     cfsProcHeaders,    // section for C procs prototypes
     cfsProcs,          // section for C procs that are not inline
     cfsTypeInit1,      // section 1 for declarations of type information
-    cfsTypeInit2,      // section A for initialization of type information
-    cfsTypeInit3,      // section B for init of type information
+    cfsTypeInit2,      // section 2 for initialization of type information
+    cfsTypeInit3,      // section 3 for init of type information
     cfsDebugInit,      // section for initialization of debug information
     cfsDynLibInit,     // section for initialization of dynamic library binding
     cfsDynLibDeinit    // section for deinitialization of dynamic libraries
   );
 
+  TCTypeKind = (       // describes the type kind of a C type
+    ctVoid,
+    ctChar,
+    ctBool,
+    ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
+    ctInt, ctInt8, ctInt16, ctInt32, ctInt64,
+    ctFloat, ctFloat32, ctFloat64, ctFloat128,
+    ctArray,
+    ctStruct,
+    ctPtr,
+    ctNimStr,
+    ctNimSeq,
+    ctProc,
+    ctCString
+  );
 
   TCFileSections = array [TCFileSection] of PRope;
     // TCFileSections represents a generated C file
@@ -66,15 +81,20 @@ type
   BModule = ^TCGen;
   BProc = ^TCProc;
 
+  TBlock = record
+    id: int;  // the ID of the label; positive means that it
+              // has been used (i.e. the label should be emitted)
+    nestedTryStmts: int; // how many try statements is it nested into
+  end;
+
   TCProc = record            // represents C proc that is currently generated
     s: TCProcSections;       // the procs sections; short name for readability
     prc: PSym;               // the Nimrod proc that this C proc belongs to
     BeforeRetNeeded: bool;   // true iff 'BeforeRet' label for proc is needed
-    inTryStmt: Natural;      // wether we are in a try statement
+    nestedTryStmts: Natural; // in how many nested try statements we are
                              // (the vars must be volatile then)
-    unique: Natural;         // for generating unique names in the C proc
-    blocks: array of int;    // the ID of the label; positive means that it
-                             // has been used (i.e. the label should be emitted)
+    labels: Natural;         // for generating unique labels in the C proc
+    blocks: array of TBlock; // nested blocks
     locals: array of TLoc;   // locNone means slot is free again
     options: TOptions;       // options that should be used for code
                              // generation; this is the same as prc.options
@@ -82,8 +102,9 @@ type
     frameLen: int;           // current length of frame descriptor
     sendClosure: PType;      // closure record type that we pass
     receiveClosure: PType;   // closure record type that we get
+    module: BModule;         // used to prevent excessive parameter passing
   end;
-
+  TTypeSeq = array of PType;
   TCGen = object(TBackend)   // represents a C source file
     s: TCFileSections;       // sections of the C file
     cfilename: string;       // filename of the module (including path,
@@ -93,55 +114,48 @@ type
     declaredThings: TIntSet; // things we have declared in this .c file
     debugDeclared: TIntSet;  // for debugging purposes
     headerFiles: TLinkedList; // needed headers to include
-    unique: Natural;         // for generating unique names
+    //unique: Natural;         // for generating unique names
     typeInfoMarker: TIntSet; // needed for generating type information
     initProc: BProc;         // code for init procedure
+    typeStack: TTypeSeq;     // used for type generation
   end;
 
 var
-  currMod: BModule; // currently compiled module
-                    // a global so that this needs not to be
-                    // passed to every proc
+  gUnique: Natural;
   mainModProcs, mainModInit: PRope; // parts of the main module
   gMapping: PRope;  // the generated mapping file (if requested)
 
-  constTok: PRope; // either 'const ' or nil depending on gCmd
-
-function initLoc(k: TLocKind; typ: PType): TLoc;
+function initLoc(k: TLocKind; typ: PType; s: TStorageLoc): TLoc;
 begin
   result.k := k;
-  result.t := typ;
+  result.s := s;
+  result.t := GetUniqueType(typ);
   result.r := nil;
   result.a := -1;
-  result.indirect := 0;
   result.flags := {@set}[]
 end;
 
 procedure fillLoc(var a: TLoc; k: TLocKind; typ: PType; r: PRope;
-                  flags: TLocFlags);
+                  s: TStorageLoc);
 begin
   // fills the loc if it is not already initialized
   if a.k = locNone then begin
     a.k := k;
-    if typ.kind = tyGenericInst then a.t := lastSon(typ) else a.t := typ;
+    a.t := getUniqueType(typ);
     a.a := -1;
+    a.s := s;
     if a.r = nil then a.r := r;
-    a.flags := a.flags + flags
   end
 end;
 
-procedure inheritStorage(var dest: TLoc; const src: TLoc);
-begin
-  dest.flags := src.flags * [lfOnStack, lfOnHeap, lfOnData, lfOnUnknown]
-end;
-
-function newProc(prc: PSym): BProc;
+function newProc(prc: PSym; module: BModule): BProc;
 begin
   new(result);
 {@ignore}
   fillChar(result^, sizeof(result^), 0);
 {@emit}
   result.prc := prc;
+  result.module := module;
   if prc <> nil then
     result.options := prc.options
   else
@@ -157,20 +171,19 @@ end;
 
 function isSimpleConst(typ: PType): bool;
 begin
-  result := not (skipAbstract(typ).kind in [tyRecord, tyRecordConstr,
-                                            tyObject, tyArray,
+  result := not (skipVarGeneric(typ).kind in [tyTuple, tyObject, tyArray,
                                             tyArrayConstr, tySet, tySequence])
 end;
 
-procedure useHeader(sym: PSym);
+procedure useHeader(m: BModule; sym: PSym);
 begin
   if lfHeader in sym.loc.Flags then begin
     assert(sym.annex <> nil);
-    {@discard} lists.IncludeStr(currMod.headerFiles, PLib(sym.annex).path)
+    {@discard} lists.IncludeStr(m.headerFiles, PLib(sym.annex).path)
   end
 end;
 
-procedure UseMagic(const name: string); forward;
+procedure UseMagic(m: BModule; const name: string); forward;
 
 // ----------------------------- name mangling
 // +++++++++++++++++++++++++++++ type generation
@@ -182,14 +195,14 @@ procedure UseMagic(const name: string); forward;
 function beEqualTypes(a, b: PType): bool;
 begin
   // returns whether two type are equal for the backend
-  result := sameType(skipAbstract(a), skipAbstract(b))
+  result := sameType(skipGenericRange(a), skipGenericRange(b))
 end;
 
 function getTemp(p: BProc; t: PType): TLoc;
 var
   i, index: int;
   name: PRope;
-begin
+begin (*
   for i := 0 to high(p.locals) do begin
     assert(i = p.locals[i].a);
     if (p.locals[i].k = locNone) and beEqualTypes(p.locals[i].t, t) then begin
@@ -198,41 +211,41 @@ begin
       result := p.locals[i];
       exit
     end
-  end;
+  end; *)
   // not found:
   index := length(p.locals);
   setLength(p.locals, index+1);
   // declare the new temporary:
   name := con('Loc', toRope(index));
-  appRopeFormat(p.s[cpsLocals], '$1 $2; /* temporary */$n',
-                [getTypeDesc(t), name]);
+  appf(p.s[cpsLocals], '$1 $2; /* temporary */$n',
+       [getTypeDesc(p.module, t), name]);
   p.locals[index].k := locTemp;
   p.locals[index].a := index;
   p.locals[index].r := name;
-  p.locals[index].t := t;
-  p.locals[index].flags := {@set}[lfOnStack];
+  p.locals[index].t := getUniqueType(t);
+  p.locals[index].s := OnStack;
+  p.locals[index].flags := {@set}[];
   result := p.locals[index] // BUGFIX!
 end;
 
 procedure freeTemp(p: BProc; const temp: TLoc);
-begin
+begin (*
   if (temp.a >= 0) and (temp.a < length(p.locals)) and
                     (p.locals[temp.a].k = locTemp) then
-    p.locals[temp.a].k := locNone
+    p.locals[temp.a].k := locNone *)
 end;
 
 // -------------------------- Variable manager ----------------------------
 
-procedure declareGlobalVar(s: PSym);
+procedure declareGlobalVar(m: BModule; s: PSym);
 begin
-  if not IntSetContainsOrIncl(currMod.declaredThings, s.id) then begin
-    app(currMod.s[cfsVars], getTypeDesc(s.loc.t));
+  if not IntSetContainsOrIncl(m.declaredThings, s.id) then begin
+    app(m.s[cfsVars], getTypeDesc(m, s.loc.t));
     if sfRegister in s.flags then
-      app(currMod.s[cfsVars], ' register');
+      app(m.s[cfsVars], ' register');
     if sfVolatile in s.flags then
-      app(currMod.s[cfsVars], ' volatile');
-    appRopeFormat(currMod.s[cfsVars], ' $1; /* $2 */$n',
-      [s.loc.r, toRope(s.name.s)])
+      app(m.s[cfsVars], ' volatile');
+    appf(m.s[cfsVars], ' $1;$n', [s.loc.r])
   end
 end;
 
@@ -241,39 +254,38 @@ begin
   //assert(s.loc.k == locNone) // not yet assigned
   // this need not be fullfilled for inline procs; they are regenerated
   // for each module that uses them!
-  fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), {@set}[lfOnStack]);
-  app(p.s[cpsLocals], getTypeDesc(s.loc.t));
+  fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack);
+  app(p.s[cpsLocals], getTypeDesc(p.module, s.loc.t));
   if sfRegister in s.flags then
     app(p.s[cpsLocals], ' register');
-  if (sfVolatile in s.flags) or (p.inTryStmt > 0) then
+  if (sfVolatile in s.flags) or (p.nestedTryStmts > 0) then
     app(p.s[cpsLocals], ' volatile');
 
-  appRopeFormat(p.s[cpsLocals], ' $1; /* $2 */$n',
-    [s.loc.r, toRope(s.name.s)]);
+  appf(p.s[cpsLocals], ' $1;$n', [s.loc.r]);
   // if debugging we need a new slot for the local variable:
   if [optStackTrace, optEndb] * p.Options = [optStackTrace, optEndb] then begin
-    appRopeFormat(p.s[cpsInit],
+    appf(p.s[cpsInit],
       'F.s[$1].name = $2; F.s[$1].address = (void*)&$3; F.s[$1].typ = $4;$n',
       [toRope(p.frameLen), makeCString(normalize(s.name.s)), s.loc.r,
-      genTypeInfo(currMod, s.loc.t)]);
+      genTypeInfo(p.module, s.loc.t)]);
     inc(p.frameLen);
   end
 end;
 
-procedure assignGlobalVar(s: PSym);
+procedure assignGlobalVar(m: BModule; s: PSym);
 begin
-  fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), {@set}[lfOnData]);
-  useHeader(s);
+  fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), OnHeap);
+  useHeader(m, s);
   if lfNoDecl in s.loc.flags then exit;
-  if sfImportc in s.flags then app(currMod.s[cfsVars], 'extern ');
-  declareGlobalVar(s);
-  if [optStackTrace, optEndb] * currMod.module.options =
+  if sfImportc in s.flags then app(m.s[cfsVars], 'extern ');
+  declareGlobalVar(m, s);
+  if [optStackTrace, optEndb] * m.module.options =
      [optStackTrace, optEndb] then begin
-    useMagic('dbgRegisterGlobal');
-    appRopeFormat(currMod.s[cfsDebugInit],
+    useMagic(m, 'dbgRegisterGlobal');
+    appf(m.s[cfsDebugInit],
       'dbgRegisterGlobal($1, &$2, $3);$n',
       [makeCString(normalize(s.owner.name.s + '.' +{&} s.name.s)), s.loc.r,
-      genTypeInfo(currMod, s.typ)])
+      genTypeInfo(m, s.typ)])
   end;
 end;
 
@@ -286,12 +298,12 @@ procedure assignParam(p: BProc; s: PSym);
 begin
   assert(s.loc.r <> nil);
   if [optStackTrace, optEndb] * p.options = [optStackTrace, optEndb] then begin
-    appRopeFormat(p.s[cpsInit],
+    appf(p.s[cpsInit],
       'F.s[$1].name = $2; F.s[$1].address = (void*)$3; ' +
       'F.s[$1].typ = $4;$n',
       [toRope(p.frameLen), makeCString(normalize(s.name.s)),
-      iff(usePtrPassing(s), s.loc.r, con('&'+'', s.loc.r)),
-      genTypeInfo(currMod, s.loc.t)]);
+      iff(ccgIntroducedPtr(s), s.loc.r, con('&'+'', s.loc.r)),
+      genTypeInfo(p.module, s.loc.t)]);
     inc(p.frameLen)
   end
 end;
@@ -301,19 +313,19 @@ end;
 // note that a label is a location too
 function getLabel(p: BProc): TLabel;
 begin
-  inc(p.unique);
-  result := con('L'+'', toRope(p.unique))
+  inc(p.labels);
+  result := con('L'+'', toRope(p.labels))
 end;
 
 procedure fixLabel(p: BProc; labl: TLabel);
 begin
-  appRopeFormat(p.s[cpsStmts], '$1: ;$n', [labl])
+  appf(p.s[cpsStmts], '$1: ;$n', [labl])
 end;
 
-procedure genProcPrototype(sym: PSym); forward;
-procedure genVarPrototype(sym: PSym); forward;
-procedure genConstPrototype(sym: PSym); forward;
-procedure genProc(prc: PSym); forward;
+procedure genProcPrototype(m: BModule; sym: PSym); forward;
+procedure genVarPrototype(m: BModule; sym: PSym); forward;
+procedure genConstPrototype(m: BModule; sym: PSym); forward;
+procedure genProc(m: BModule; prc: PSym); forward;
 procedure genStmts(p: BProc; t: PNode); forward;
 
 {$include 'ccgexprs.pas'}
@@ -323,76 +335,76 @@ procedure genStmts(p: BProc; t: PNode); forward;
 
 // We don't finalize dynamic libs as this does the OS for us.
 
-procedure loadDynamicLib(lib: PLib);
+procedure loadDynamicLib(m: BModule; lib: PLib);
 var
   tmp: PRope;
 begin
   assert(lib <> nil);
   if lib.kind = libDynamic then begin
     lib.kind := libDynamicGenerated;
-    useMagic('nimLoadLibrary');
-    useMagic('nimUnloadLibrary');
+    useMagic(m, 'nimLoadLibrary');
+    useMagic(m, 'nimUnloadLibrary');
     tmp := getTempName();
-    appRopeFormat(currMod.s[cfsVars], 'static void* $1;$n', [tmp]);
-    appRopeFormat(currMod.s[cfsDynLibInit],
+    appf(m.s[cfsVars], 'static void* $1;$n', [tmp]);
+    appf(m.s[cfsDynLibInit],
       '$1 = nimLoadLibrary((string) &$2);$n',
-      [tmp, getStrLit(lib.path)]);
-    appRopeFormat(currMod.s[cfsDynLibDeinit],
+      [tmp, getStrLit(m, lib.path)]);
+    appf(m.s[cfsDynLibDeinit],
       'if ($1 != NIM_NIL) nimUnloadLibrary($1);$n', [tmp]);
     assert(lib.name = nil);
     lib.name := tmp
   end
 end;
 
-procedure SymInDynamicLib(sym: PSym);
+procedure SymInDynamicLib(m: BModule; sym: PSym);
 var
   lib: PLib;
   extname, tmp: PRope;
 begin
   lib := PLib(sym.annex);
   extname := sym.loc.r;
-  loadDynamicLib(lib);
-  useMagic('nimGetProcAddr');
-  tmp := ropeFormat('Dl_$1', [toRope(sym.id)]);
+  loadDynamicLib(m, lib);
+  useMagic(m, 'nimGetProcAddr');
+  tmp := ropef('Dl_$1', [toRope(sym.id)]);
   sym.loc.r := tmp; // from now on we only need the internal name
   sym.typ.sym := nil; // generate a new name
-  appRopeFormat(currMod.s[cfsDynLibInit],
+  appf(m.s[cfsDynLibInit],
     '$1 = ($2) nimGetProcAddr($3, $4);$n',
-    [tmp, getTypeDesc(sym.typ), lib.name,
+    [tmp, getTypeDesc(m, sym.typ), lib.name,
     makeCString(ropeToStr(extname))]);
-  declareGlobalVar(sym)
+  declareGlobalVar(m, sym)
 end;
 
 // ----------------------------- sections ---------------------------------
 
-procedure UseMagic(const name: string);
+procedure UseMagic(m: BModule; const name: string);
 var
   sym: PSym;
 begin
-  if (sfSystemModule in currMod.module.flags) then exit;
+  if (sfSystemModule in m.module.flags) then exit;
   // we don't know the magic symbols in the system module, but they will be
   // there anyway, because that is the way the code generator works
   sym := magicsys.getCompilerProc(name);
   case sym.kind of
-    skProc: genProcPrototype(sym);
-    skVar: genVarPrototype(sym);
-    skType: {@discard} getTypeDesc(sym.typ);
+    skProc, skConverter: genProcPrototype(m, sym);
+    skVar: genVarPrototype(m, sym);
+    skType: {@discard} getTypeDesc(m, sym.typ);
     else InternalError('useMagic: ' + name)
   end
 end;
 
-procedure generateHeaders();
+procedure generateHeaders(m: BModule);
 var
   it: PStrEntry;
 begin
-  app(currMod.s[cfsHeaders], '#include "nimbase.h"' +{&} tnl +{&} tnl);
-  it := PStrEntry(currMod.headerFiles.head);
+  app(m.s[cfsHeaders], '#include "nimbase.h"' +{&} tnl +{&} tnl);
+  it := PStrEntry(m.headerFiles.head);
   while it <> nil do begin
     if not (it.data[strStart] in ['"', '<']) then
-      appRopeFormat(currMod.s[cfsHeaders],
+      appf(m.s[cfsHeaders],
         '#include "$1"$n', [toRope(it.data)])
     else
-      appRopeFormat(currMod.s[cfsHeaders], '#include $1$n', [toRope(it.data)]);
+      appf(m.s[cfsHeaders], '#include $1$n', [toRope(it.data)]);
     it := PStrEntry(it.Next)
   end
 end;
@@ -402,15 +414,15 @@ var
   slots: PRope;
 begin
   if p.frameLen > 0 then begin
-    useMagic('TVarSlot');
-    slots := ropeFormat('  TVarSlot s[$1];$n', [toRope(p.frameLen)])
+    useMagic(p.module, 'TVarSlot');
+    slots := ropef('  TVarSlot s[$1];$n', [toRope(p.frameLen)])
   end
   else
     slots := nil;
-  appRopeFormat(p.s[cpsLocals], 'volatile struct {TFrame* prev;' +
-    'NCSTRING procname;NS line;NCSTRING filename;' +
-    'NS len;$n$1} F;$n', [slots]);
-  prepend(p.s[cpsInit], ropeFormat('F.len = $1;$n', [toRope(p.frameLen)]))
+  appf(p.s[cpsLocals], 'volatile struct {TFrame* prev;' +
+    'NCSTRING procname;NI line;NCSTRING filename;' +
+    'NI len;$n$1} F;$n', [slots]);
+  prepend(p.s[cpsInit], ropef('F.len = $1;$n', [toRope(p.frameLen)]))
 end;
 
 function retIsNotVoid(s: PSym): bool;
@@ -418,27 +430,27 @@ begin
   result := (s.typ.sons[0] <> nil) and not isInvalidReturnType(s.typ.sons[0])
 end;
 
-procedure genProc(prc: PSym);
+procedure genProc(m: BModule; prc: PSym);
 var
   p: BProc;
   generatedProc, header, returnStmt: PRope;
   i: int;
   res, param: PSym;
 begin
-  useHeader(prc);
-  fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), {@set}[lfOnData]);
+  useHeader(m, prc);
+  fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), OnStack);
   if (lfNoDecl in prc.loc.Flags) then exit;
   if lfDynamicLib in prc.loc.flags then
-    SymInDynamicLib(prc)
+    SymInDynamicLib(m, prc)
   else if not (sfImportc in prc.flags) then begin
     // we have a real proc here:
-    p := newProc(prc);
-    header := genProcHeader(prc);
+    p := newProc(prc, m);
+    header := genProcHeader(m, prc);
     if (sfCompilerProc in prc.flags)
-    and (sfSystemModule in currMod.module.flags)
-    and not IntSetContains(currMod.declaredThings, prc.id) then
-      appRopeFormat(currMod.s[cfsProcHeaders], '$1;$n', [header]);
-    intSetIncl(currMod.declaredThings, prc.id);
+    and (sfSystemModule in m.module.flags)
+    and not IntSetContains(m.declaredThings, prc.id) then
+      appf(m.s[cfsProcHeaders], '$1;$n', [header]);
+    intSetIncl(m.declaredThings, prc.id);
     returnStmt := nil;
     assert(prc.ast <> nil);
 
@@ -450,7 +462,7 @@ begin
         assert(res.loc.r <> nil);
         initVariable(p, res);
         genObjectInit(p, res);
-        returnStmt := ropeFormat('return $1;$n', [rdLoc(res.loc)]);
+        returnStmt := ropef('return $1;$n', [rdLoc(res.loc)]);
       end
       else if (prc.typ.sons[0] <> nil) then begin
         res := prc.ast.sons[resultPos].sym; // get result symbol
@@ -465,13 +477,13 @@ begin
 
     genStmts(p, prc.ast.sons[codePos]); // modifies p.locals, p.init, etc.
     if sfPure in prc.flags then
-      generatedProc := ropeFormat('$1 {$n$2$3$4}$n',
+      generatedProc := ropef('$1 {$n$2$3$4}$n',
         [header, p.s[cpsLocals], p.s[cpsInit], p.s[cpsStmts]])
     else begin
       generatedProc := con(header, '{' + tnl);
       if optStackTrace in prc.options then begin
         getFrameDecl(p);
-        prepend(p.s[cpsInit], ropeFormat(
+        prepend(p.s[cpsInit], ropef(
           'F.procname = $1;$n' +
           'F.prev = framePtr;$n' +
           'F.filename = $2;$n' +
@@ -491,86 +503,93 @@ begin
       //if prc.typ.callConv <> ccInline then
       //  prc.ast.sons[codePos] := nil;
     end;
-    app(currMod.s[cfsProcs], generatedProc);
+    app(m.s[cfsProcs], generatedProc);
   end
 end;
 
-procedure genVarPrototype(sym: PSym);
+procedure genVarPrototype(m: BModule; sym: PSym);
 begin
   assert(sfGlobal in sym.flags);
-  useHeader(sym);
-  fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), {@set}[lfOnData]);
+  useHeader(m, sym);
+  fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap);
   if (lfNoDecl in sym.loc.Flags) or
-      intSetContainsOrIncl(currMod.declaredThings, sym.id) then
+      intSetContainsOrIncl(m.declaredThings, sym.id) then
     exit;
-  if sym.owner.id <> currMod.module.id then begin
+  if sym.owner.id <> m.module.id then begin
     // else we already have the symbol generated!
     assert(sym.loc.r <> nil);
-    app(currMod.s[cfsVars], 'extern ');
-    app(currMod.s[cfsVars], getTypeDesc(sym.loc.t));
+    app(m.s[cfsVars], 'extern ');
+    app(m.s[cfsVars], getTypeDesc(m, sym.loc.t));
     if sfRegister in sym.flags then
-      app(currMod.s[cfsVars], ' register');
+      app(m.s[cfsVars], ' register');
     if sfVolatile in sym.flags then
-      app(currMod.s[cfsVars], ' volatile');
-    appRopeFormat(currMod.s[cfsVars], ' $1; /* $2 */$n',
-      [sym.loc.r, toRope(sym.name.s)])
+      app(m.s[cfsVars], ' volatile');
+    appf(m.s[cfsVars], ' $1;$n', [sym.loc.r])
   end
 end;
 
-procedure genConstPrototype(sym: PSym);
+procedure genConstPrototype(m: BModule; sym: PSym);
 begin
-  useHeader(sym);
-  fillLoc(sym.loc, locData, sym.typ, mangleName(sym), {@set}[lfOnData]);
+  useHeader(m, sym);
+  fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnUnknown);
   if (lfNoDecl in sym.loc.Flags) or
-      intSetContainsOrIncl(currMod.declaredThings, sym.id) then
+      intSetContainsOrIncl(m.declaredThings, sym.id) then
     exit;
-  if sym.owner.id <> currMod.module.id then begin
+  if sym.owner.id <> m.module.id then begin
     // else we already have the symbol generated!
     assert(sym.loc.r <> nil);
-    app(currMod.s[cfsData], 'extern ');
-    appRopeFormat(currMod.s[cfsData], '$1$2 $3; /* $4 */$n',
-      [constTok, getTypeDesc(sym.loc.t), sym.loc.r, toRope(sym.name.s)])
+    app(m.s[cfsData], 'extern ');
+    appf(m.s[cfsData], 'NIM_CONST $1 $2;$n',
+      [getTypeDesc(m, sym.loc.t), sym.loc.r])
   end
 end;
 
-procedure genProcPrototype(sym: PSym);
+procedure genProcPrototype(m: BModule; sym: PSym);
 begin
-  useHeader(sym);
-  fillLoc(sym.loc, locProc, sym.typ, mangleName(sym), {@set}[lfOnData]);
+  useHeader(m, sym);
+  fillLoc(sym.loc, locProc, sym.typ, mangleName(sym), OnStack);
   if lfDynamicLib in sym.loc.Flags then begin
     // it is a proc variable!
-    if (sym.owner.id <> currMod.module.id) and
-        not intSetContainsOrIncl(currMod.declaredThings, sym.id) then begin
-      app(currMod.s[cfsVars], 'extern ');
+    if (sym.owner.id <> m.module.id) and
+        not intSetContainsOrIncl(m.declaredThings, sym.id) then begin
+      app(m.s[cfsVars], 'extern ');
       // BUGFIX: declareGlobalVar() inlined, because of intSetContainsOrIncl
       // check
-      app(currMod.s[cfsVars], getTypeDesc(sym.loc.t));
-      appRopeFormat(currMod.s[cfsVars], ' $1; /* $2 */$n',
-        [sym.loc.r, toRope(sym.name.s)])
+      app(m.s[cfsVars], getTypeDesc(m, sym.loc.t));
+      appf(m.s[cfsVars], ' $1;$n', [sym.loc.r])
     end
   end
   else begin
     // it is a proc:
     if (lfNoDecl in sym.loc.Flags) then exit;
-    if intSetContainsOrIncl(currMod.declaredThings, sym.id) then exit;
-    appRopeFormat(currMod.s[cfsProcHeaders], '$1;$n', [genProcHeader(sym)]);
+    if intSetContainsOrIncl(m.declaredThings, sym.id) then exit;
+    appf(m.s[cfsProcHeaders], '$1;$n', [genProcHeader(m, sym)]);
     if (sym.typ.callConv = ccInline)
-    and (sym.owner.id <> currMod.module.id) then
-      genProc(sym) // generate the code again!
-//    else
-//      IntSetIncl(currMod.declaredThings, sym.id)
+    and (sym.owner.id <> m.module.id) then
+      genProc(m, sym) // generate the code again!
   end
 end;
 
-function getFileHeader: PRope;
+function getFileHeader(const cfilenoext: string): PRope;
 begin
-  result := ropeFormat(
+  result := ropef(
     '/* Generated by the Nimrod Compiler v$1 */$n' +
     '/*   (c) 2008 Andreas Rumpf */$n' +
-    '/* Compiled for: $2, $3, $4 */$n',
+    '/* Compiled for: $2, $3, $4 */$n' +
+    '/* Command for C compiler:$n   $5 */$n',
     [toRope(versionAsString), toRope(platform.OS[targetOS].name),
     toRope(platform.CPU[targetCPU].name),
-    toRope(extccomp.CC[extccomp.ccompiler].name)])
+    toRope(extccomp.CC[extccomp.ccompiler].name),
+    toRope(getCompileCFileCmd(cfilenoext))]);
+  case platform.CPU[targetCPU].intSize of
+    16: appf(result, '$ntypedef short int NI;$n' +
+                       'typedef unsigned short int NU;$n', []); 
+    32: appf(result, '$ntypedef long int NI;$n' +
+                       'typedef unsigned long int NU;$n', []); 
+    64: appf(result, '$ntypedef long long int NI;$n' +
+                       'typedef unsigned long long int NU;$n', []); 
+    else begin end
+  end
 end;
 
 procedure genMainProc(m: BModule);
@@ -581,13 +600,13 @@ const
     '$1' +
     '$2';
   PosixMain =
-    'NS cmdCount;$n' +
+    'NI cmdCount;$n' +
     'char** cmdLine;$n' +
     'char** gEnv;$n' +
     'int main(int argc, char** args, char** env) {$n' +
     '  int dummy[8];$n' +
     '  cmdLine = args;$n' +
-    '  cmdCount = (NS)argc;$n' +
+    '  cmdCount = (NI)argc;$n' +
     '  gEnv = env;$n' +{&}
     CommonMainBody +{&}
     '  return 0;$n' +
@@ -610,7 +629,7 @@ const
 var
   frmt: TFormatStr;
 begin
-  useMagic('setStackBottom');
+  useMagic(m, 'setStackBottom');
   if (platform.targetOS = osWindows) and
       (gGlobalOptions * [optGenGuiApp, optGenDynLib] <> []) then begin
     if optGenGuiApp in gGlobalOptions then
@@ -622,8 +641,8 @@ begin
   else
     frmt := PosixMain;
   if gBreakpoints <> nil then
-    useMagic('dbgRegisterBreakpoint');
-  appRopeFormat(m.s[cfsProcs], frmt, [gBreakpoints, mainModInit])
+    useMagic(m, 'dbgRegisterBreakpoint');
+  appf(m.s[cfsProcs], frmt, [gBreakpoints, mainModInit])
 end;
 
 procedure genInitCode(m: BModule);
@@ -631,16 +650,16 @@ var
   initname, prc: PRope;
 begin
   initname := con(m.module.name.s, toRope('Init'));
-  appRopeFormat(mainModProcs, 'N_NIMCALL(void, $1)(void);$n',
+  appf(mainModProcs, 'N_NIMCALL(void, $1)(void);$n',
     [initname]);
   if not (sfSystemModule in m.module.flags) then
-    appRopeFormat(mainModInit, '$1();$n', [initname]);
-  prc := ropeFormat('N_NIMCALL(void, $1)(void) {$n', [initname]);
+    appf(mainModInit, '$1();$n', [initname]);
+  prc := ropef('N_NIMCALL(void, $1)(void) {$n', [initname]);
   if optStackTrace in m.initProc.options then begin
     prepend(m.initProc.s[cpsLocals], toRope('volatile TFrame F;' + tnl));
     app(prc, m.initProc.s[cpsLocals]);
     app(prc, m.s[cfsTypeInit1]);
-    appRopeFormat(prc,
+    appf(prc,
       'F.len = 0;$n' + // IMPORTANT: else the debugger crashes!
       'F.procname = $1;$n' +
       'F.prev = framePtr;$n' +
@@ -666,12 +685,12 @@ begin
   app(m.s[cfsProcs], prc)
 end;
 
-function genModule(m: BModule): PRope;
+function genModule(m: BModule; const cfilenoext: string): PRope;
 var
   i: TCFileSection;
 begin
-  result := getFileHeader();
-  generateHeaders();
+  result := getFileHeader(cfilenoext);
+  generateHeaders(m);
   for i := low(TCFileSection) to cfsProcs do app(result, m.s[i])
 end;
 
@@ -688,11 +707,10 @@ begin
   initIdTable(result.typeCache);
   initIdTable(result.forwTypeCache);
   result.module := module;
-  if gCmd <> cmdCompileToCpp then
-    constTok := toRope('const ');
   intSetInit(result.typeInfoMarker);
-  result.initProc := newProc(nil);
+  result.initProc := newProc(nil, result);
   result.initProc.options := gOptions;
+{@emit result.typeStack := [];}
 end;
 
 function shouldRecompile(code: PRope; const cfile, cfilenoext: string): bool;
@@ -717,28 +735,27 @@ var
   code: PRope;
 begin
   m := BModule(b);
-  currMod := m;
-  currMod.initProc.options := gOptions;
-  genStmts(currMod.initProc, n);
+  m.initProc.options := gOptions;
+  genStmts(m.initProc, n);
   // generate code for the init statements of the module:
   genInitCode(m);
+  finishTypeDescriptions(m);
   if sfMainModule in m.module.flags then begin
     // generate mapping file (if requested):
     if gMapping <> nil then
       WriteRope(gMapping, ChangeFileExt(cfile + '_map', 'txt'));
 
     // generate main file:
-    app(currMod.s[cfsProcHeaders], mainModProcs);
-    genMainProc(currMod);
+    app(m.s[cfsProcHeaders], mainModProcs);
+    genMainProc(m);
   end;
   cfile := completeCFilePath(m.cfilename);
   cfilenoext := changeFileExt(cfile, '');
-  code := genModule(m);
+  code := genModule(m, cfilenoext);
   if shouldRecompile(code, changeFileExt(cfile, cExt), cfilenoext) then begin
     addFileToCompile(cfilenoext); // is to compile
   end;
   addFileToLink(cfilenoext);
-  currMod := nil // free the memory
 end;
 
 function CBackend(b: PBackend; module: PSym; const filename: string): PBackend;
@@ -749,7 +766,6 @@ begin
   g.backendCreator := CBackend;
   g.eventMask := {@set}[eAfterModule];
   g.afterModuleEvent := finishModule;
-  currMod := g;
   result := g;
 end;
 
diff --git a/nim/commands.pas b/nim/commands.pas
index 69edd86e9..ad6f21b07 100644
--- a/nim/commands.pas
+++ b/nim/commands.pas
@@ -7,10 +7,10 @@
 //    distribution, for details about the copyright.
 //
 
-// This module handles the parsing of command line arguments.
-
 unit commands;
 
+// This module handles the parsing of command line arguments.
+
 interface
 
 {$include 'config.inc'}
@@ -41,16 +41,14 @@ uses
 const
 {$ifdef fpc}
   compileDate = {$I %date%};
-  compileTime = {$I %time%};
 {$else}
   compileDate = '2008-0-0';
-  compileTime = '00:00:00';
 {$endif}
 {@emit}
 
 const
   HelpMessage = 'Nimrod Compiler Version $1 (' +{&}
-    compileDate +{&} ' ' +{&} compileTime +{&} ') [$2: $3]' +{&} nl +{&}
+    compileDate +{&} ') [$2: $3]' +{&} nl +{&}
     'Copyright (c) 2004-2008 by Andreas Rumpf' +{&} nl;
 
 const
@@ -66,7 +64,8 @@ const
 +{&} '  compile                   compile project with default code generator (C)' +{&} nl
 +{&} '  compile_to_c              compile project with C code generator' +{&} nl
 +{&} '  compile_to_cpp            compile project with C++ code generator' +{&} nl
-+{&} '  doc                       generate the documentation for inputfile; ' +{&} nl
++{&} '  compile_to_ecmascript     compile project to ECMAScript code (experimental)' +{&} nl
++{&} '  doc                       generate the documentation for inputfile;' +{&} nl
 +{&} '                            with --run switch opens it with $BROWSER' +{&} nl
 +{&} 'Arguments:' +{&} nl
 +{&} '  arguments are passed to the program being run (if --run option is selected)' +{&} nl
@@ -80,6 +79,8 @@ const
 +{&} '  --line_trace:on|off       code generation for line trace ON|OFF' +{&} nl
 +{&} '  --debugger:on|off         turn Embedded Nimrod Debugger ON|OFF' +{&} nl
 +{&} '  -x, --checks:on|off       code generation for all runtime checks ON|OFF' +{&} nl
++{&} '  --obj_checks:on|off       code generation for obj conversion checks ON|OFF' +{&} nl
++{&} '  --field_checks:on|off     code generation for case record fields ON|OFF' +{&} nl
 +{&} '  --range_checks:on|off     code generation for range checks ON|OFF' +{&} nl
 +{&} '  --bound_checks:on|off     code generation for bound checks ON|OFF' +{&} nl
 +{&} '  --overflow_checks:on|off  code generation for over-/underflow checks ON|OFF' +{&} nl
@@ -174,17 +175,8 @@ const
   ;
 
 function getCommandLineDesc: string;
-var
-  v: string;
 begin
-  // the Pascal version number gets a little star ('*'), the Nimrod version
-  // does not! This helps distinguishing the different builds.
-{@ignore}
-  v := VersionAsString +{&} '*';
-{@emit
-  v := VersionAsString
-}
-  result := format(HelpMessage, [v, platform.os[hostOS].name,
+  result := format(HelpMessage, [VersionAsString, platform.os[hostOS].name,
     cpu[hostCPU].name]) +{&} Usage
 end;
 
@@ -210,6 +202,7 @@ begin
                                     cpu[hostCPU].name]) +{&} AdvancedUsage);
     advHelpWritten := true;
     helpWritten := true;
+    halt(0);
   end
 end;
 
@@ -423,7 +416,7 @@ begin
       ProcessOnOffSwitch({@set}[optHints], arg, pass, info);
     wCheckpoints:
       ProcessOnOffSwitch({@set}[optCheckpoints], arg, pass, info);
-    wStackTrace, wS:
+    wStackTrace:
       ProcessOnOffSwitch({@set}[optStackTrace], arg, pass, info);
     wLineTrace:
       ProcessOnOffSwitch({@set}[optLineTrace], arg, pass, info);
@@ -436,6 +429,10 @@ begin
     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:
@@ -485,6 +482,10 @@ begin
           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
diff --git a/nim/crc.pas b/nim/crc.pas
index d669c17ee..d4c5d0661 100644
--- a/nim/crc.pas
+++ b/nim/crc.pas
@@ -19,7 +19,7 @@ type
   TCrc32 = int32;
 
 const
-  InitCrc32 = TCrc32($ffffffff);
+  InitCrc32 = TCrc32(-1);
 
 function updateCrc32(val: Byte; crc: TCrc32): TCrc32; overload;
 function updateCrc32(val: Char; crc: TCrc32): TCrc32; overload;
diff --git a/nim/docgen.pas b/nim/docgen.pas
index 9615dad35..a6d2725c3 100644
--- a/nim/docgen.pas
+++ b/nim/docgen.pas
@@ -40,6 +40,7 @@ type
     modDesc: PRope;     // module description
     dependsOn: PRope;   // dependencies
     id: int;            // for generating IDs
+    splitAfter: int;    // split to long entries in the TOC
     tocPart: array of TTocEntry;
     hasToc: bool;
     toc, section: TSections;
@@ -54,7 +55,7 @@ function findIndexNode(n: PRstNode): PRstNode;
 var
   i: int;
 begin
-  if n = nil then 
+  if n = nil then
     result := nil
   else if n.kind = rnIndex then begin
     result := n.sons[2];
@@ -62,7 +63,7 @@ begin
       result := newRstNode(rnDefList);
       n.sons[2] := result
     end
-    else if result.kind = rnInner then 
+    else if result.kind = rnInner then
       result := result.sons[0]
   end
   else begin
@@ -83,10 +84,10 @@ begin
   gIndexFile := appendFileExt(gIndexFile, 'txt');
   d.indexValFilename := changeFileExt(extractFilename(d.filename), HtmlExt);
   if ExistsFile(gIndexFile) then begin
-    d.indexFile := rstParse(readFile(gIndexFile), false, gIndexFile, 0, 1, 
+    d.indexFile := rstParse(readFile(gIndexFile), false, gIndexFile, 0, 1,
                             dummyHasToc);
     d.theIndex := findIndexNode(d.indexFile);
-    if (d.theIndex = nil) or (d.theIndex.kind <> rnDefList) then 
+    if (d.theIndex = nil) or (d.theIndex.kind <> rnDefList) then
       rawMessage(errXisNoValidIndexFile, gIndexFile);
     clearIndex(d.theIndex, d.indexValFilename);
   end
@@ -106,6 +107,8 @@ begin
 end;
 
 function newDocumentor(const filename: string): PDoc;
+var
+  s: string;
 begin
   new(result);
 {@ignore}
@@ -115,6 +118,10 @@ begin
 }
   result.filename := filename;
   result.id := 100;
+  result.splitAfter := 25;
+  s := getConfigVar('split.item.toc');
+  if s <> '' then
+    result.splitAfter := parseInt(s);
 end;
 
 function getVarIdx(const varnames: array of string; const id: string): int;
@@ -122,7 +129,7 @@ var
   i: int;
 begin
   for i := 0 to high(varnames) do
-    if cmpIgnoreStyle(varnames[i], id) = 0 then begin 
+    if cmpIgnoreStyle(varnames[i], id) = 0 then begin
       result := i; exit
     end;
   result := -1
@@ -209,12 +216,16 @@ begin
   end
 end;
 
-function toXml(const s: string): string;
+function toXml(const s: string; splitAfter: int = -1): string;
 var
   i: int;
 begin
   result := '';
-  for i := strStart to length(s)+strStart-1 do addXmlChar(result, s[i])
+  for i := strStart to length(s)+strStart-1 do begin
+    if (splitAfter >= 0) and ((i-strStart+1) mod splitAfter = 0) then 
+      addChar(result, ' ');
+    addXmlChar(result, s[i])
+  end
 end;
 
 function renderRstToHtml(d: PDoc; n: PRstNode): PRope; forward;
@@ -226,8 +237,8 @@ var
 begin
   result := nil;
   for i := 0 to rsonsLen(n)-1 do
-    appRopeFormat(result, inner, [renderRstToHtml(d, n.sons[i])]);
-  result := ropeFormat(outer, [result]);
+    appf(result, inner, [renderRstToHtml(d, n.sons[i])]);
+  result := ropef(outer, [result]);
 end;
 
 procedure setIndexForSourceTerm(d: PDoc; name: PRstNode; id: int);
@@ -241,7 +252,7 @@ begin
   addSon(h, a);
   a := newRstNode(rnIdx);
   addSon(a, name);
-  setIndexPair(d.theIndex, a, h);  
+  setIndexPair(d.theIndex, a, h);
 end;
 
 function renderIndexTerm(d: PDoc; n: PRstNode): PRope;
@@ -249,7 +260,7 @@ var
   a, h: PRstNode;
 begin
   inc(d.id);
-  result := ropeFormat('<em id="$1">$2</em>', 
+  result := ropef('<em id="$1">$2</em>',
                        [toRope(d.id), renderAux(d, n)]);
   h := newRstNode(rnHyperlink);
   a := newRstNode(rnLeaf, d.indexValFilename +{&} '#' +{&} toString(d.id));
@@ -277,11 +288,13 @@ var
 begin
   if n = nil then begin result := nil; exit end;
   result := genComment(d, n);
-  if result = nil then
-    for i := 0 to sonsLen(n)-1 do begin
-      result := genRecComment(d, n.sons[i]);
-      if result <> nil then exit
-    end
+  if result = nil then begin
+    if not (n.kind in [nkEmpty..nkNilLit]) then
+      for i := 0 to sonsLen(n)-1 do begin
+        result := genRecComment(d, n.sons[i]);
+        if result <> nil then exit
+      end
+  end
   else
     n.comment := snil
 end;
@@ -299,18 +312,18 @@ begin
   end
   else if n.kind = nkSym then
     result := sfInInterface in n.sym.flags
-  else if n.kind = nkPragmaExpr then 
+  else if n.kind = nkPragmaExpr then
     result := isVisible(n.sons[0]);
 end;
 
-function getName(n: PNode): string;
+function getName(n: PNode; splitAfter: int = -1): string;
 begin
   case n.kind of
-    nkPostfix: result := getName(n.sons[1]);
-    nkPragmaExpr: result := getName(n.sons[0]);
-    nkSym: result := toXML(n.sym.name.s);
-    nkIdent: result := toXML(n.ident.s);
-    nkAccQuoted: result := '`' +{&} getName(n.sons[0]) +{&} '`';
+    nkPostfix: result := getName(n.sons[1], splitAfter);
+    nkPragmaExpr: result := getName(n.sons[0], splitAfter);
+    nkSym: result := toXML(n.sym.name.s, splitAfter);
+    nkIdent: result := toXML(n.ident.s, splitAfter);
+    nkAccQuoted: result := '`' +{&} getName(n.sons[0], splitAfter) +{&} '`';
     else begin
       internalError(n.info, 'getName()');
       result := ''
@@ -354,50 +367,50 @@ begin
     getNextTok(r, kind, literal);
     case kind of
       tkEof: break;
-      tkComment: 
-        appRopeFormat(result, '<span class="Comment">$1</span>', 
+      tkComment:
+        appf(result, '<span class="Comment">$1</span>',
                       [toRope(toXml(literal))]);
-      tokKeywordLow..tokKeywordHigh: 
-        appRopeFormat(result, '<span class="Keyword">$1</span>', 
+      tokKeywordLow..tokKeywordHigh:
+        appf(result, '<span class="Keyword">$1</span>',
                       [toRope(literal)]);
-      tkOpr, tkHat: 
-        appRopeFormat(result, '<span class="Operator">$1</span>', 
+      tkOpr, tkHat:
+        appf(result, '<span class="Operator">$1</span>',
                       [toRope(toXml(literal))]);
-      tkStrLit..tkTripleStrLit: 
-        appRopeFormat(result, '<span class="StringLit">$1</span>', 
+      tkStrLit..tkTripleStrLit:
+        appf(result, '<span class="StringLit">$1</span>',
                       [toRope(toXml(literal))]);
-      tkCharLit, tkRCharLit:
-        appRopeFormat(result, '<span class="CharLit">$1</span>', 
+      tkCharLit:
+        appf(result, '<span class="CharLit">$1</span>',
                       [toRope(toXml(literal))]);
       tkIntLit..tkInt64Lit:
-        appRopeFormat(result, '<span class="DecNumber">$1</span>', 
+        appf(result, '<span class="DecNumber">$1</span>',
                       [toRope(literal)]);
-      tkFloatLit..tkFloat64Lit: 
-        appRopeFormat(result, '<span class="FloatNumber">$1</span>', 
+      tkFloatLit..tkFloat64Lit:
+        appf(result, '<span class="FloatNumber">$1</span>',
                       [toRope(literal)]);
       tkSymbol:
-        appRopeFormat(result, '<span class="Identifier">$1</span>', 
+        appf(result, '<span class="Identifier">$1</span>',
                       [toRope(literal)]);
-      tkInd, tkSad, tkDed, tkSpaces: 
+      tkInd, tkSad, tkDed, tkSpaces:
         app(result, literal);
-        //appRopeFormat(result, '<span class="Whitespace">$1</span>', 
+        //appf(result, '<span class="Whitespace">$1</span>',
         //              [toRope(literal)]);
       tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
-      tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, 
+      tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi,
       tkParDotLe, tkParDotRi, tkComma, tkSemiColon, tkColon,
       tkEquals, tkDot, tkDotDot, tkAccent:
-        appRopeFormat(result, '<span class="Other">$1</span>', 
+        appf(result, '<span class="Other">$1</span>',
                       [toRope(literal)]);
       else InternalError(n.info, 'docgen.genThing(' + toktypeToStr[kind] + ')');
     end
   end;
   inc(d.id);
   app(d.section[k], ropeFormatNamedVars(getConfigVar('doc.item'),
-                ['name', 'header', 'desc', 'itemID'],
-                [name, result, comm, toRope(d.id)]));
+      ['name', 'header', 'desc', 'itemID'],
+      [name, result, comm, toRope(d.id)]));
   app(d.toc[k], ropeFormatNamedVars(getConfigVar('doc.item.toc'),
-                ['name', 'header', 'desc', 'itemID'],
-                [name, result, comm, toRope(d.id)]));
+      ['name', 'header', 'desc', 'itemID'],
+      [toRope(getName(nameNode, d.splitAfter)), result, comm, toRope(d.id)]));
   setIndexForSourceTerm(d, getRstName(nameNode), d.id);
 end;
 
@@ -416,12 +429,12 @@ begin
     d.tocPart[len].refname := refname;
     d.tocPart[len].n := n;
     d.tocPart[len].header := result;
-    result := ropeFormat('<h$1><a class="toc-backref" id="$2" href="#$2_toc">$3'+
+    result := ropef('<h$1><a class="toc-backref" id="$2" href="#$2_toc">$3'+
                          '</a></h$1>',
                          [toRope(n.level), d.tocPart[len].refname, result]);
   end
-  else 
-    result := ropeFormat('<h$1 id="$2">$3</h$1>', 
+  else
+    result := ropef('<h$1 id="$2">$3</h$1>',
                          [toRope(n.level), refname, result]);
 end;
 
@@ -437,8 +450,8 @@ begin
   if d.meta[metaTitle] = nil then d.meta[metaTitle] := t
   else if d.meta[metaSubtitle] = nil then d.meta[metaSubtitle] := t
   else
-    result := ropeFormat('<h$1 id="$2"><center>$3</center></h$1>',
-                         [toRope(n.level), toRope(rstnodeToRefname(n)), t]);  
+    result := ropef('<h$1 id="$2"><center>$3</center></h$1>',
+                         [toRope(n.level), toRope(rstnodeToRefname(n)), t]);
 end;
 
 function renderRstToRst(d: PDoc; n: PRstNode): PRope; forward;
@@ -455,7 +468,7 @@ function renderRstToRst(d: PDoc; n: PRstNode): PRope;
 // this is needed for the index generation; it may also be useful for
 // debugging, but most code is already debugged...
 const
-  lvlToChar: array [0..8] of char = ('!', '=', '-', '~', '`', 
+  lvlToChar: array [0..8] of char = ('!', '=', '-', '~', '`',
                                      '<', '*', '|', '+');
 var
   L: int;
@@ -469,60 +482,60 @@ begin
     rnHeadline: begin
       result := renderRstSons(d, n);
       L := ropeLen(result);
-      result := ropeFormat('$n$1$2$n$1$3', [ind, result, 
+      result := ropef('$n$1$2$n$1$3', [ind, result,
                            toRope(repeatChar(L, lvlToChar[n.level]))]);
     end;
     rnOverline: begin
       result := renderRstSons(d, n);
       L := ropeLen(result);
-      result := ropeFormat('$n$1$3$n$1$2$n$1$3', [ind, result, 
+      result := ropef('$n$1$3$n$1$2$n$1$3', [ind, result,
                            toRope(repeatChar(L, lvlToChar[n.level]))]);
     end;
-    rnTransition: 
-      result := ropeFormat('$n$n$1$2$n$n', 
+    rnTransition:
+      result := ropef('$n$n$1$2$n$n',
                           [ind, toRope(repeatChar(78-d.indent, '-'))]);
     rnParagraph: begin
       result := renderRstSons(d, n);
-      result := ropeFormat('$n$n$1$2', [ind, result]);
+      result := ropef('$n$n$1$2', [ind, result]);
     end;
     rnBulletItem: begin
       inc(d.indent, 2);
       result := renderRstSons(d, n);
-      if result <> nil then result := ropeFormat('$n$1* $2', [ind, result]);
+      if result <> nil then result := ropef('$n$1* $2', [ind, result]);
       dec(d.indent, 2);
     end;
     rnEnumItem: begin
       inc(d.indent, 4);
       result := renderRstSons(d, n);
-      if result <> nil then result := ropeFormat('$n$1(#) $2', [ind, result]);
+      if result <> nil then result := ropef('$n$1(#) $2', [ind, result]);
       dec(d.indent, 4);
     end;
     rnOptionList, rnFieldList, rnDefList, rnDefItem, rnLineBlock, rnFieldName,
-    rnFieldBody, rnStandaloneHyperlink, rnBulletList, rnEnumList: 
+    rnFieldBody, rnStandaloneHyperlink, rnBulletList, rnEnumList:
       result := renderRstSons(d, n);
     rnDefName: begin
       result := renderRstSons(d, n);
-      result := ropeFormat('$n$n$1$2', [ind, result]);
+      result := ropef('$n$n$1$2', [ind, result]);
     end;
     rnDefBody: begin
       inc(d.indent, 2);
       result := renderRstSons(d, n);
       if n.sons[0].kind <> rnBulletList then
-        result := ropeFormat('$n$1  $2', [ind, result]);
+        result := ropef('$n$1  $2', [ind, result]);
       dec(d.indent, 2);
     end;
     rnField: begin
       result := renderRstToRst(d, n.sons[0]);
       L := max(ropeLen(result)+3, 30);
       inc(d.indent, L);
-      result := ropeFormat('$n$1:$2:$3$4', [
+      result := ropef('$n$1:$2:$3$4', [
         ind, result, toRope(repeatChar(L-ropeLen(result)-2)),
         renderRstToRst(d, n.sons[1])]);
       dec(d.indent, L);
     end;
     rnLineBlockItem: begin
       result := renderRstSons(d, n);
-      result := ropeFormat('$n$1| $2', [ind, result]);
+      result := ropef('$n$1| $2', [ind, result]);
     end;
     rnBlockQuote: begin
       inc(d.indent, 2);
@@ -531,48 +544,48 @@ begin
     end;
     rnRef: begin
       result := renderRstSons(d, n);
-      result := ropeFormat('`$1`_', [result]);
+      result := ropef('`$1`_', [result]);
     end;
     rnHyperlink: begin
-      result := ropeFormat('`$1 <$2>`_', [renderRstToRst(d, n.sons[0]), 
+      result := ropef('`$1 <$2>`_', [renderRstToRst(d, n.sons[0]),
                                           renderRstToRst(d, n.sons[1])]);
     end;
     rnGeneralRole: begin
       result := renderRstToRst(d, n.sons[0]);
-      result := ropeFormat('`$1`:$2:', [result, renderRstToRst(d, n.sons[1])]);    
+      result := ropef('`$1`:$2:', [result, renderRstToRst(d, n.sons[1])]);
     end;
     rnSub: begin
       result := renderRstSons(d, n);
-      result := ropeFormat('`$1`:sub:', [result]);
+      result := ropef('`$1`:sub:', [result]);
     end;
     rnSup: begin
       result := renderRstSons(d, n);
-      result := ropeFormat('`$1`:sup:', [result]);
+      result := ropef('`$1`:sup:', [result]);
     end;
     rnIdx: begin
       result := renderRstSons(d, n);
-      result := ropeFormat('`$1`:idx:', [result]);
+      result := ropef('`$1`:idx:', [result]);
     end;
     rnEmphasis: begin
       result := renderRstSons(d, n);
-      result := ropeFormat('*$1*', [result]);
+      result := ropef('*$1*', [result]);
     end;
     rnStrongEmphasis: begin
       result := renderRstSons(d, n);
-      result := ropeFormat('**$1**', [result]);
+      result := ropef('**$1**', [result]);
     end;
     rnInterpretedText: begin
       result := renderRstSons(d, n);
-      result := ropeFormat('`$1`', [result]);
+      result := ropef('`$1`', [result]);
     end;
     rnInlineLiteral: begin
       inc(d.verbatim);
       result := renderRstSons(d, n);
-      result := ropeFormat('``$1``', [result]);
+      result := ropef('``$1``', [result]);
       dec(d.verbatim);
     end;
     rnLeaf: begin
-      if (d.verbatim = 0) and (n.text = '\'+'') then 
+      if (d.verbatim = 0) and (n.text = '\'+'') then
         result := toRope('\\') // XXX: escape more special characters!
       else
         result := toRope(n.text);
@@ -582,10 +595,10 @@ begin
       if n.sons[2] <> nil then
         result := renderRstSons(d, n.sons[2]);
       dec(d.indent, 3);
-      result := ropeFormat('$n$n$1.. index::$n$2', [ind, result]);
+      result := ropef('$n$n$1.. index::$n$2', [ind, result]);
     end;
     rnContents: begin
-      result := ropeFormat('$n$n$1.. contents::', [ind]);
+      result := ropef('$n$n$1.. contents::', [ind]);
     end;
     else rawMessage(errCannotRenderX, rstnodeKindToStr[n.kind]);
   end;
@@ -593,7 +606,7 @@ end;
 
 function renderTocEntry(d: PDoc; const e: TTocEntry): PRope;
 begin
-  result := ropeFormat('<li><a class="reference" id="$1_toc" href="#$1">$2' +
+  result := ropef('<li><a class="reference" id="$1_toc" href="#$1">$2' +
                        '</a></li>$n', [e.refname, e.header]);
 end;
 
@@ -614,24 +627,24 @@ begin
       break
   end;
   if lvl > 1 then
-    result := ropeFormat('<ul class="simple">$1</ul>', [result]);
+    result := ropef('<ul class="simple">$1</ul>', [result]);
 end;
 
 function renderImage(d: PDoc; n: PRstNode): PRope;
 var
   s: string;
 begin
-  result := ropeFormat('<img src="$1"', [toRope(getArgument(n))]);
+  result := ropef('<img src="$1"', [toRope(getArgument(n))]);
   s := getFieldValue(n, 'height');
-  if s <> '' then appRopeFormat(result, ' height="$1"', [toRope(s)]);
+  if s <> '' then appf(result, ' height="$1"', [toRope(s)]);
   s := getFieldValue(n, 'width');
-  if s <> '' then appRopeFormat(result, ' width="$1"', [toRope(s)]);
+  if s <> '' then appf(result, ' width="$1"', [toRope(s)]);
   s := getFieldValue(n, 'scale');
-  if s <> '' then appRopeFormat(result, ' scale="$1"', [toRope(s)]);
+  if s <> '' then appf(result, ' scale="$1"', [toRope(s)]);
   s := getFieldValue(n, 'alt');
-  if s <> '' then appRopeFormat(result, ' alt="$1"', [toRope(s)]);
+  if s <> '' then appf(result, ' alt="$1"', [toRope(s)]);
   s := getFieldValue(n, 'align');
-  if s <> '' then appRopeFormat(result, ' align="$1"', [toRope(s)]);
+  if s <> '' then appf(result, ' align="$1"', [toRope(s)]);
   app(result, ' />');
   if rsonsLen(n) >= 3 then app(result, renderRstToHtml(d, n.sons[2]))
 end;
@@ -644,14 +657,14 @@ var
   lang: TSourceLanguage;
 begin
   m := n.sons[2].sons[0];
-  assert(m.kind = rnLeaf);
+  if (m.kind <> rnLeaf) then InternalError('renderCodeBlock');
   result := nil;
   langstr := strip(getArgument(n));
   if langstr = '' then lang := langNimrod // default language
   else lang := getSourceLanguage(langstr);
   if lang = langNone then begin
     rawMessage(warnLanguageXNotSupported, langstr);
-    result := ropeFormat('<pre>$1</pre>', [toRope(m.text)])
+    result := ropef('<pre>$1</pre>', [toRope(m.text)])
   end
   else begin
     initGeneralTokenizer(g, m.text);
@@ -659,16 +672,18 @@ begin
       getNextToken(g, lang);
       case g.kind of
         gtEof: break;
-        gtNone, gtWhitespace: 
-          app(result, ncopy(m.text, g.start+strStart, g.len+g.start));
-        else 
-          appRopeFormat(result, '<span class="$2">$1</span>',
-            [toRope(ncopy(m.text, g.start+strStart, g.len+g.start)),
+        gtNone, gtWhitespace:
+          app(result, ncopy(m.text, g.start+strStart,
+                            g.len+g.start-1+strStart));
+        else
+          appf(result, '<span class="$2">$1</span>',
+            [toRope(ncopy(m.text, g.start+strStart,
+                          g.len+g.start-1+strStart)),
              toRope(tokenClassToStr[g.kind])]);
       end;
     end;
     deinitGeneralTokenizer(g);
-    if result <> nil then result := ropeFormat('<pre>$1</pre>', [result]);
+    if result <> nil then result := ropef('<pre>$1</pre>', [result]);
   end
 end;
 
@@ -697,10 +712,10 @@ begin
     rnDefItem: begin end;
     rnDefName: outer := '<dt>$1</dt>'+nl;
     rnDefBody: outer := '<dd>$1</dd>'+nl;
-    rnFieldList: 
+    rnFieldList:
       outer := '<table class="docinfo" frame="void" rules="none">' +
                '<col class="docinfo-name" />' +
-               '<col class="docinfo-content" />' +    
+               '<col class="docinfo-content" />' +
                '<tbody valign="top">$1' +
                '</tbody></table>';
     rnField: outer := '<tr>$1</tr>$n';
@@ -711,7 +726,7 @@ begin
       exit
     end;
 
-    rnOptionList: 
+    rnOptionList:
       outer := '<table frame="void">$1</table>';
     rnOptionListItem:
       outer := '<tr>$1</tr>$n';
@@ -719,36 +734,36 @@ begin
     rnDescription: outer := '<td align="left">$1</td>$n';
     rnOption,
     rnOptionString,
-    rnOptionArgument: assert(false);
+    rnOptionArgument: InternalError('renderRstToHtml');
 
     rnLiteralBlock: outer := '<pre>$1</pre>'+nl;
-    rnQuotedLiteralBlock: assert(false);
+    rnQuotedLiteralBlock: InternalError('renderRstToHtml');
 
     rnLineBlock: outer := '<p>$1</p>';
     rnLineBlockItem: outer := '$1<br />';
 
     rnBlockQuote: outer := '<blockquote>$1</blockquote>$n';
 
-    rnTable, rnGridTable: 
+    rnTable, rnGridTable:
       outer := '<table border="1" class="docutils">$1</table>';
     rnTableRow: outer := '<tr>$1</tr>$n';
     rnTableDataCell: outer := '<td>$1</td>';
     rnTableHeaderCell: outer := '<th>$1</th>';
 
-    rnLabel: assert(false);       // used for footnotes and other things
-    rnFootnote: assert(false);    // a footnote
+    rnLabel: InternalError('renderRstToHtml'); // used for footnotes and other
+    rnFootnote: InternalError('renderRstToHtml'); // a footnote
 
-    rnCitation: assert(false);    // similar to footnote
+    rnCitation: InternalError('renderRstToHtml');    // similar to footnote
     rnRef: begin
-      result := ropeFormat('<a class="reference external" href="#$2">$1</a>',
+      result := ropef('<a class="reference external" href="#$2">$1</a>',
                            [renderAux(d, n), toRope(rstnodeToRefname(n))]);
       exit
     end;
     rnStandaloneHyperlink:
       outer := '<a class="reference external" href="$1">$1</a>';
     rnHyperlink: begin
-      result := ropeFormat('<a class="reference external" href="$2">$1</a>',
-                           [renderRstToHtml(d, n.sons[0]), 
+      result := ropef('<a class="reference external" href="$2">$1</a>',
+                           [renderRstToHtml(d, n.sons[0]),
                             renderRstToHtml(d, n.sons[1])]);
       exit
     end;
@@ -766,8 +781,8 @@ begin
 
     // Inline markup:
     rnGeneralRole: begin
-      result := ropeFormat('<span class="$2">$1</span>',
-                           [renderRstToHtml(d, n.sons[0]), 
+      result := ropef('<span class="$2">$1</span>',
+                           [renderRstToHtml(d, n.sons[0]),
                             renderRstToHtml(d, n.sons[1])]);
       exit
     end;
@@ -776,8 +791,8 @@ begin
     rnEmphasis: outer := '<em>$1</em>';
     rnStrongEmphasis: outer := '<strong>$1</strong>';
     rnInterpretedText: outer := '<cite>$1</cite>';
-    rnIdx: begin 
-      if d.theIndex = nil then 
+    rnIdx: begin
+      if d.theIndex = nil then
         outer := '<em>$1</em>'
       else begin
         result := renderIndexTerm(d, n); exit
@@ -798,7 +813,7 @@ begin
       d.meta[metaTitle] := renderRstToHtml(d, n.sons[0]);
       exit
     end;
-    else assert(false);
+    else InternalError('renderRstToHtml');
   end;
   result := renderAux(d, n, outer, inner);
 end;
@@ -809,11 +824,12 @@ var
 begin
   if n = nil then exit;
   case n.kind of
-    nkCommentStmt: app(d.modDesc, genComment(d, n));
-    nkProcDef:     genItem(d, n, n.sons[namePos], skProc);
-    nkIteratorDef: genItem(d, n, n.sons[namePos], skIterator);
-    nkMacroDef:    genItem(d, n, n.sons[namePos], skMacro);
-    nkTemplateDef: genItem(d, n, n.sons[namePos], skTemplate);
+    nkCommentStmt:  app(d.modDesc, genComment(d, n));
+    nkProcDef:      genItem(d, n, n.sons[namePos], skProc);
+    nkIteratorDef:  genItem(d, n, n.sons[namePos], skIterator);
+    nkMacroDef:     genItem(d, n, n.sons[namePos], skMacro);
+    nkTemplateDef:  genItem(d, n, n.sons[namePos], skTemplate);
+    nkConverterDef: genItem(d, n, n.sons[namePos], skConverter);
     nkVarSection: begin
       for i := 0 to sonsLen(n)-1 do
         genItem(d, n.sons[i], n.sons[i].sons[0], skVar);
@@ -860,14 +876,16 @@ var
 begin
   j := 0;
   toc := renderTocEntries(d, j, 1);
+  code := nil;
+  content := nil;
+  title := nil;
   for i := low(TSymKind) to high(TSymKind) do begin
     genSection(d, i);
     app(toc, d.toc[i]);
   end;
   if toc <> nil then
     toc := ropeFormatNamedVars(getConfigVar('doc.toc'), ['content'], [toc]);
-  code := nil;
-  for i := low(TSymKind) to high(TSymKind) do 
+  for i := low(TSymKind) to high(TSymKind) do
     app(code, d.section[i]);
   if d.meta[metaTitle] <> nil then
     title := d.meta[metaTitle]
@@ -880,7 +898,7 @@ begin
   content := ropeFormatNamedVars(getConfigVar(bodyname),
     ['title', 'tableofcontents', 'moduledesc', 'date', 'time', 'content'],
     [title, toc, d.modDesc, toRope(getDateStr()), toRope(getClockStr()), code]);
-  if not (optCompileOnly in gGlobalOptions) then 
+  if not (optCompileOnly in gGlobalOptions) then
     code := ropeFormatNamedVars(getConfigVar('doc.file'),
       ['title', 'tableofcontents', 'moduledesc', 'date', 'time', 'content'],
       [title, toc, d.modDesc,
@@ -918,13 +936,16 @@ var
   filen: string;
   d: PDoc;
   rst: PRstNode;
+  code: PRope;
 begin
   filen := appendFileExt(filename, 'txt');
   d := newDocumentor(filen);
   initIndexFile(d);
   rst := rstParse(readFile(filen), false, filen, 0, 1, d.hasToc);
   d.modDesc := renderRstToHtml(d, rst);
-  writeRope(genHtmlFile(d), getOutFile(filename, HtmlExt));
+  code := genHtmlFile(d);
+  assert(ropeInvariant(code));
+  writeRope(code, getOutFile(filename, HtmlExt));
   generateIndex(d);
 end;
 
diff --git a/nim/ecmasgen.pas b/nim/ecmasgen.pas
new file mode 100644
index 000000000..53ab4f069
--- /dev/null
+++ b/nim/ecmasgen.pas
@@ -0,0 +1,1869 @@
+//
+//
+//           The Nimrod Compiler
+//        (c) Copyright 2008 Andreas Rumpf
+//
+//    See the file "copying.txt", included in this
+//    distribution, for details about the copyright.
+//
+unit ecmasgen;
+
+// This is the EMCAScript (also known as JavaScript) code generator.
+// **Invariant: each expression only occurs once in the generated
+// code!**
+
+interface
+
+{$include 'config.inc'}
+
+uses
+  nsystem, ast, astalgo, strutils, hashes, trees, platform, magicsys,
+  extccomp, options, nversion, nimsets, msgs, crc, bitsets, idents,
+  lists, types, nos, ntime, ropes, nmath, backends, ccgutils, wordrecg, rnimsyn;
+
+function EcmasBackend(b: PBackend; module: PSym;
+                      const filename: string): PBackend;
+
+implementation
+
+type
+  TEcmasGen = object(TBackend)
+  end;
+  BModule = ^TEcmasGen;
+
+  TEcmasTypeKind = (
+    etyNone,         // no type
+    etyNull,         // null type
+    etyProc,         // proc type
+    etyBool,         // bool type
+    etyInt,          // Ecmascript's int
+    etyFloat,        // Ecmascript's float
+    etyString,       // Ecmascript's string
+    etyObject,       // Ecmascript's reference to an object
+    etyBaseIndex     // base + index needed
+  );
+
+  TCompRes = record
+    kind: TEcmasTypeKind;
+    com: PRope; // computation part
+                // address if this is a (address, index)-tuple
+    res: PRope; // result part; index if this is a (address, index)-tuple
+  end;
+
+  TBlock = record
+    id: int;  // the ID of the label; positive means that it
+              // has been used (i.e. the label should be emitted)
+    nestedTryStmts: int; // how many try statements is it nested into
+  end;
+
+  TGlobals = record
+    typeInfo, code: PRope;
+    typeInfoGenerated: TIntSet;
+  end;
+  PGlobals = ^TGlobals;
+
+  TProc = record
+    procDef: PNode;
+    prc: PSym;
+    data: PRope;
+    options: TOptions;
+    module: BModule;
+    globals: PGlobals;
+    BeforeRetNeeded: bool;
+    nestedTryStmts: int;
+    unique: int;
+    blocks: array of TBlock;
+  end;
+
+function newGlobals(): PGlobals;
+begin
+  new(result);
+{@ignore} fillChar(result^, sizeof(result^), 0); {@emit}
+  IntSetInit(result.typeInfoGenerated);
+end;
+
+procedure initCompRes(var r: TCompRes);
+begin
+  r.com := nil; r.res := nil; r.kind := etyNone;
+end;
+
+procedure initProc(var p: TProc; globals: PGlobals; module: BModule;
+                   procDef: PNode; options: TOptions);
+begin
+{@ignore}
+  fillChar(p, sizeof(p), 0);
+{@emit
+  p.blocks := [];}
+  p.options := options;
+  p.module := module;
+  p.procDef := procDef;
+  p.globals := globals;
+  if procDef <> nil then p.prc := procDef.sons[namePos].sym;
+end;
+
+const
+  MappedToObject = {@set}[tyObject, tyArray, tyArrayConstr, tyTuple,
+                          tyEmptySet, tyOpenArray, tySet, tyVar,
+                          tyRef, tyPtr];
+
+function mapType(typ: PType): TEcmasTypeKind;
+begin
+  case skipGeneric(typ).kind of
+    tyVar, tyRef, tyPtr: begin
+      if typ.sons[0].kind in mappedToObject then
+        result := etyObject
+      else
+        result := etyBaseIndex
+    end;
+    tyPointer: begin
+      // treat a tyPointer like a typed pointer to an array of bytes
+      result := etyInt;
+    end;
+    tyRange: result := mapType(typ.sons[0]);
+    tyInt..tyInt64, tyEnum, tyAnyEnum, tyChar:
+      result := etyInt;
+    tyBool: result := etyBool;
+    tyFloat..tyFloat128: result := etyFloat;
+    tySet: begin
+      result := etyObject // map a set to a table
+    end;
+    tyString, tySequence:
+      result := etyInt; // little hack to get the right semantics
+    tyObject, tyArray, tyArrayConstr, tyTuple, tyEmptySet, tyOpenArray:
+      result := etyObject;
+    tyNil: result := etyNull;
+    tyGenericInst, tyGenericParam, tyGeneric, tyNone, tyForward:
+      result := etyNone;
+    tyProc: result := etyProc;
+    tyCString: result := etyString;
+  end
+end;
+
+function mangle(const name: string): string;
+var
+  i: int;
+begin
+  result := '';
+  for i := strStart to length(name) + strStart-1 do begin
+    case name[i] of
+      'A'..'Z': addChar(result, chr(ord(name[i]) - ord('A') + ord('a')));
+      '_': begin end;
+      'a'..'z', '0'..'9': addChar(result, name[i]);
+      else result := result +{&} 'X' +{&} toHex(ord(name[i]), 2);
+    end
+  end
+end;
+
+function mangleName(s: PSym): PRope;
+begin
+  result := s.loc.r;
+  if result = nil then begin
+    result := toRope(mangle(s.name.s));
+    app(result, '_'+'');
+    app(result, toRope(s.id));
+    s.loc.r := result;
+  end
+end;
+
+// ----------------------- type information ----------------------------------
+
+function genTypeInfo(var p: TProc; typ: PType): PRope; forward;
+
+function genObjectFields(var p: TProc; typ: PType; n: PNode): PRope;
+var
+  s, u: PRope;
+  len, i, j: int;
+  field: PSym;
+  b: PNode;
+begin
+  result := nil;
+  case n.kind of
+    nkRecList: begin
+      len := sonsLen(n);
+      if len = 1 then  // generates more compact code!
+        result := genObjectFields(p, typ, n.sons[0])
+      else begin
+        s := nil;
+        for i := 0 to len-1 do begin
+          if i > 0 then app(s, ', ' + tnl);
+          app(s, genObjectFields(p, typ, n.sons[i]));
+        end;
+        result := ropef('{kind: 2, len: $1, offset: 0, ' +
+                        'typ: null, name: null, sons: [$2]}', [toRope(len), s]);
+      end
+    end;
+    nkSym: begin
+      field := n.sym;
+      s := genTypeInfo(p, field.typ);
+      result := ropef('{kind: 1, offset: "$1", len: 0, ' +
+                      'typ: $2, name: $3, sons: null}', [
+                      mangleName(field), s, makeCString(field.name.s)]);
+    end;
+    nkRecCase: begin
+      len := sonsLen(n);
+      if (n.sons[0].kind <> nkSym) then
+        InternalError(n.info, 'genObjectFields');
+      field := n.sons[0].sym;
+      s := genTypeInfo(p, field.typ);
+      for i := 1 to len-1 do begin
+        b := n.sons[i]; // branch
+        u := nil;
+        case b.kind of
+          nkOfBranch: begin
+            if sonsLen(b) < 2 then
+              internalError(b.info, 'genObjectFields; nkOfBranch broken');
+            for j := 0 to sonsLen(b)-2 do begin
+              if u <> nil then app(u, ', ');
+              if b.sons[j].kind = nkRange then begin
+                appf(u, '[$1, $2]', [toRope(getOrdValue(b.sons[j].sons[0])),
+                                     toRope(getOrdValue(b.sons[j].sons[1]))]);
+              end
+              else
+                app(u, toRope(getOrdValue(b.sons[j])))
+            end
+          end;
+          nkElse: u := toRope(lengthOrd(field.typ));
+          else internalError(n.info, 'genObjectFields(nkRecCase)');
+        end;
+        if result <> nil then app(result, ', ' + tnl);
+        appf(result, '[SetConstr($1), $2]',
+             [u, genObjectFields(p, typ, lastSon(b))]);
+      end;
+      result := ropef('{kind: 3, offset: "$1", len: $3, ' +
+                      'typ: $2, name: $4, sons: [$5]}', [mangleName(field), s,
+                      toRope(lengthOrd(field.typ)),
+                      makeCString(field.name.s),
+                      result]);
+    end;
+    else internalError(n.info, 'genObjectFields');
+  end
+end;
+
+procedure genObjectInfo(var p: TProc; typ: PType; name: PRope);
+var
+  s: PRope;
+begin
+  s := ropef('var $1 = {size: 0, kind: $2, base: null, node: null, ' +
+             'finalizer: null};$n', [name, toRope(ord(typ.kind))]);
+  prepend(p.globals.typeInfo, s);
+
+  appf(p.globals.typeInfo, 'var NNI$1 = $2;$n',
+      [toRope(typ.id), genObjectFields(p, typ, typ.n)]);
+  appf(p.globals.typeInfo, '$1.node = NNI$2;$n', [name, toRope(typ.id)]);
+  if (typ.kind = tyObject) and (typ.sons[0] <> nil) then begin
+    appf(p.globals.typeInfo, '$1.base = $2;$n',
+        [name, genTypeInfo(p, typ.sons[0])]);
+  end
+end;
+
+procedure genEnumInfo(var p: TProc; typ: PType; name: PRope);
+var
+  s, n: PRope;
+  len, i: int;
+  field: PSym;
+begin
+  len := sonsLen(typ.n);
+  s := nil;
+  for i := 0 to len-1 do begin
+    if (typ.n.sons[i].kind <> nkSym) then
+      InternalError(typ.n.info, 'genEnumInfo');
+    field := typ.n.sons[i].sym;
+    if i > 0 then app(s, ', '+tnl);
+    appf(s, '{kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}',
+            [toRope(field.position), name, makeCString(field.name.s)]);
+  end;
+  n := ropef('var NNI$1 = {kind: 2, offset: 0, typ: null, ' +
+             'name: null, len: $2, sons: [$3]};$n',
+             [toRope(typ.id), toRope(len), s]);
+
+  s := ropef('var $1 = {size: 0, kind: $2, base: null, node: null, ' +
+             'finalizer: null};$n', [name, toRope(ord(typ.kind))]);
+  prepend(p.globals.typeInfo, s);
+
+  app(p.globals.typeInfo, n);
+  appf(p.globals.typeInfo, '$1.node = NNI$2;$n', [name, toRope(typ.id)]);
+  if typ.sons[0] <> nil then begin
+    appf(p.globals.typeInfo, '$1.base = $2;$n',
+        [name, genTypeInfo(p, typ.sons[0])]);
+  end;
+end;
+
+function genTypeInfo(var p: TProc; typ: PType): PRope;
+var
+  t: PType;
+  s: PRope;
+begin
+  t := typ;
+  if t.kind = tyGenericInst then t := lastSon(t);
+  result := ropef('NTI$1', [toRope(t.id)]);
+  if IntSetContainsOrIncl(p.globals.TypeInfoGenerated, t.id) then exit;
+  case t.kind of
+    tyPointer, tyProc, tyBool, tyChar, tyCString, tyString,
+    tyInt..tyFloat128: begin
+      s := ropef(
+        'var $1 = {size: 0, kind: $2, base: null, node: null, finalizer: null};$n',
+        [result, toRope(ord(t.kind))]);
+      prepend(p.globals.typeInfo, s);
+    end;
+    tyVar, tyRef, tyPtr, tySequence, tyRange, tySet: begin
+      s := ropef(
+        'var $1 = {size: 0, kind: $2, base: null, node: null, finalizer: null};$n',
+        [result, toRope(ord(t.kind))]);
+      prepend(p.globals.typeInfo, s);
+      appf(p.globals.typeInfo, '$1.base = $2;$n',
+          [result, genTypeInfo(p, typ.sons[0])]);
+    end;
+    tyArrayConstr, tyArray: begin
+      s := ropef(
+        'var $1 = {size: 0, kind: $2, base: null, node: null, finalizer: null};$n',
+        [result, toRope(ord(t.kind))]);
+      prepend(p.globals.typeInfo, s);
+      appf(p.globals.typeInfo, '$1.base = $2;$n',
+          [result, genTypeInfo(p, typ.sons[1])]);
+    end;
+    tyEnum: genEnumInfo(p, t, result);
+    tyObject, tyTuple: genObjectInfo(p, t, result);
+    else InternalError('genTypeInfo(' + typekindToStr[t.kind] + ')');
+  end
+end;
+
+// ---------------------------------------------------------------------------
+
+procedure gen(var p: TProc; n: PNode; var r: TCompRes); forward;
+procedure genStmt(var p: TProc; n: PNode; var r: TCompRes); forward;
+
+procedure useMagic(var p: TProc; const ident: string);
+begin
+  // to implement
+end;
+
+function mergeExpr(a, b: PRope): PRope; overload;
+begin
+  if (a <> nil) then begin
+    if b <> nil then result := ropef('($1, $2)', [a, b])
+    else result := a
+  end
+  else result := b
+end;
+
+function mergeExpr(const r: TCompRes): PRope; overload;
+begin
+  result := mergeExpr(r.com, r.res);
+end;
+
+function mergeStmt(const r: TCompRes): PRope;
+begin
+  if r.res = nil then result := r.com
+  else if r.com = nil then result := r.res
+  else result := ropef('$1$2', [r.com, r.res])
+end;
+
+procedure genAnd(var p: TProc; a, b: PNode; var r: TCompRes);
+var
+  x, y: TCompRes;
+begin
+  gen(p, a, x);
+  gen(p, b, y);
+  r.res := ropef('($1 && $2)', [mergeExpr(x), mergeExpr(y)])
+end;
+
+procedure genOr(var p: TProc; a, b: PNode; var r: TCompRes);
+var
+  x, y: TCompRes;
+begin
+  gen(p, a, x);
+  gen(p, b, y);
+  r.res := ropef('($1 || $2)', [mergeExpr(x), mergeExpr(y)])
+end;
+
+type
+  TMagicFrmt = array [0..3] of string;
+
+const
+  // magic checked op; magic unchecked op; checked op; unchecked op
+  ops: array [mAddi..mStrToStr] of TMagicFrmt = (
+    ('addInt', '',   'addInt($1, $2)',    '($1 + $2)'), // AddI
+    ('subInt', '',   'subInt($1, $2)',    '($1 - $2)'), // SubI
+    ('mulInt', '',   'mulInt($1, $2)',    '($1 * $2)'), // MulI
+    ('divInt', '',   'divInt($1, $2)',    'Math.floor($1 / $2)'), // DivI
+    ('modInt', '',   'modInt($1, $2)',    'Math.floor($1 % $2)'), // ModI
+    ('addInt64', '',   'addInt64($1, $2)',  '($1 + $2)'), // AddI64
+    ('subInt64', '',   'subInt64($1, $2)',  '($1 - $2)'), // SubI64
+    ('mulInt64', '',   'mulInt64($1, $2)',  '($1 * $2)'), // MulI64
+    ('divInt64', '',   'divInt64($1, $2)',  'Math.floor($1 / $2)'), // DivI64
+    ('modInt64', '',   'modInt64($1, $2)',  'Math.floor($1 % $2)'), // ModI64
+    ('',   '',   '($1 >>> $2)',       '($1 >>> $2)'), // ShrI
+    ('',   '',   '($1 << $2)',        '($1 << $2)'), // ShlI
+    ('',   '',   '($1 & $2)',         '($1 & $2)'), // BitandI
+    ('',   '',   '($1 | $2)',         '($1 | $2)'), // BitorI
+    ('',   '',   '($1 ^ $2)',         '($1 ^ $2)'), // BitxorI
+    ('nimMin', 'nimMin', 'nimMin($1, $2)',    'nimMin($1, $2)'), // MinI
+    ('nimMax', 'nimMax', 'nimMax($1, $2)',    'nimMax($1, $2)'), // MaxI
+    ('',   '',   '($1 >>> $2)',       '($1 >>> $2)'), // ShrI64
+    ('',   '',   '($1 << $2)',        '($1 << $2)'), // ShlI64
+    ('',   '',   '($1 & $2)',         '($1 & $2)'), // BitandI64
+    ('',   '',   '($1 | $2)',         '($1 | $2)'), // BitorI64
+    ('',   '',   '($1 ^ $2)',         '($1 ^ $2)'), // BitxorI64
+    ('nimMin', 'nimMin', 'nimMin($1, $2)',    'nimMin($1, $2)'), // MinI64
+    ('nimMax', 'nimMax', 'nimMax($1, $2)',    'nimMax($1, $2)'), // MaxI64
+    ('',   '',   '($1 + $2)',         '($1 + $2)'), // AddF64
+    ('',   '',   '($1 - $2)',         '($1 - $2)'), // SubF64
+    ('',   '',   '($1 * $2)',         '($1 * $2)'), // MulF64
+    ('',   '',   '($1 / $2)',         '($1 / $2)'), // DivF64
+    ('nimMin', 'nimMin', 'nimMin($1, $2)',    'nimMin($1, $2)'), // MinF64
+    ('nimMax', 'nimMax', 'nimMax($1, $2)',    'nimMax($1, $2)'), // MaxF64
+    ('AddU', 'AddU', 'AddU($1, $2)',      'AddU($1, $2)'), // AddU
+    ('SubU', 'SubU', 'SubU($1, $2)',      'SubU($1, $2)'), // SubU
+    ('MulU', 'MulU', 'MulU($1, $2)',      'MulU($1, $2)'), // MulU
+    ('DivU', 'DivU', 'DivU($1, $2)',      'DivU($1, $2)'), // DivU
+    ('ModU', 'ModU', 'ModU($1, $2)',      'ModU($1, $2)'), // ModU
+    ('AddU64', 'AddU64', 'AddU64($1, $2)',    'AddU64($1, $2)'), // AddU64
+    ('SubU64', 'SubU64', 'SubU64($1, $2)',    'SubU64($1, $2)'), // SubU64
+    ('MulU64', 'MulU64', 'MulU64($1, $2)',    'MulU64($1, $2)'), // MulU64
+    ('DivU64', 'DivU64', 'DivU64($1, $2)',    'DivU64($1, $2)'), // DivU64
+    ('ModU64', 'ModU64', 'ModU64($1, $2)',    'ModU64($1, $2)'), // ModU64
+    ('',   '',   '($1 == $2)',        '($1 == $2)'), // EqI
+    ('',   '',   '($1 <= $2)',        '($1 <= $2)'), // LeI
+    ('',   '',   '($1 < $2)',         '($1 < $2)'), // LtI
+    ('',   '',   '($1 == $2)',        '($1 == $2)'), // EqI64
+    ('',   '',   '($1 <= $2)',        '($1 <= $2)'), // LeI64
+    ('',   '',   '($1 < $2)',         '($1 < $2)'), // LtI64
+    ('',   '',   '($1 == $2)',        '($1 == $2)'), // EqF64
+    ('',   '',   '($1 <= $2)',        '($1 <= $2)'), // LeF64
+    ('',   '',   '($1 < $2)',         '($1 < $2)'), // LtF64
+    ('LeU', 'LeU', 'LeU($1, $2)',       'LeU($1, $2)'), // LeU
+    ('LtU', 'LtU', 'LtU($1, $2)',       'LtU($1, $2)'), // LtU
+    ('LeU64', 'LeU64', 'LeU64($1, $2)',     'LeU64($1, $2)'), // LeU64
+    ('LtU64', 'LtU64', 'LtU64($1, $2)',     'LtU64($1, $2)'), // LtU64
+    ('',   '',   '($1 == $2)',        '($1 == $2)'), // EqEnum
+    ('',   '',   '($1 <= $2)',        '($1 <= $2)'), // LeEnum
+    ('',   '',   '($1 < $2)',         '($1 < $2)'), // LtEnum
+    ('',   '',   '($1 == $2)',        '($1 == $2)'), // EqCh
+    ('',   '',   '($1 <= $2)',        '($1 <= $2)'), // LeCh
+    ('',   '',   '($1 < $2)',         '($1 < $2)'), // LtCh
+    ('',   '',   '($1 == $2)',        '($1 == $2)'), // EqB
+    ('',   '',   '($1 <= $2)',        '($1 <= $2)'), // LeB
+    ('',   '',   '($1 < $2)',         '($1 < $2)'), // LtB
+    ('',   '',   '($1 == $2)',        '($1 == $2)'), // EqRef
+    ('',   '',   '($1 == $2)',        '($1 == $2)'), // EqProc
+    ('',   '',   '($1 == $2)',        '($1 == $2)'), // EqUntracedRef
+    ('',   '',   '($1 <= $2)',        '($1 <= $2)'), // LePtr
+    ('',   '',   '($1 < $2)',         '($1 < $2)'), // LtPtr
+    ('',   '',   '($1 == $2)',        '($1 == $2)'), // EqCString
+    ('',   '',   '($1 != $2)',        '($1 != $2)'), // Xor
+    ('NegInt', '',   'NegInt($1)',        '-($1)'), // UnaryMinusI
+    ('NegInt64', '',   'NegInt64($1)',      '-($1)'), // UnaryMinusI64
+    ('AbsInt', '',   'AbsInt($1)',        'Math.abs($1)'), // AbsI
+    ('AbsInt64', '', 'AbsInt64($1)',      'Math.abs($1)'), // AbsI64
+    ('',   '',   '!($1)',             '!($1)'), // Not
+    ('',   '',   '+($1)',             '+($1)'), // UnaryPlusI
+    ('',   '',   '~($1)',             '~($1)'), // BitnotI
+    ('',   '',   '+($1)',             '+($1)'), // UnaryPlusI64
+    ('',   '',   '~($1)',             '~($1)'), // BitnotI64
+    ('',   '',   '+($1)',             '+($1)'), // UnaryPlusF64
+    ('',   '',   '-($1)',             '-($1)'), // UnaryMinusF64
+    ('',   '',   'Math.abs($1)',      'Math.abs($1)'), // AbsF64
+
+    ('Ze8ToI', 'Ze8ToI', 'Ze8ToI($1)', 'Ze8ToI($1)'),  // mZe8ToI
+    ('Ze8ToI64', 'Ze8ToI64', 'Ze8ToI64($1)', 'Ze8ToI64($1)'),  // mZe8ToI64
+    ('Ze16ToI', 'Ze16ToI', 'Ze16ToI($1)', 'Ze16ToI($1)'),  // mZe16ToI
+    ('Ze16ToI64', 'Ze16ToI64', 'Ze16ToI64($1)', 'Ze16ToI64($1)'),  // mZe16ToI64
+    ('Ze32ToI64', 'Ze32ToI64', 'Ze32ToI64($1)', 'Ze32ToI64($1)'),  // mZe32ToI64
+    ('ZeIToI64', 'ZeIToI64', 'ZeIToI64($1)', 'ZeIToI64($1)'),  // mZeIToI64
+
+    ('ToU8', 'ToU8', 'ToU8($1)',          'ToU8($1)'), // ToU8
+    ('ToU16', 'ToU16', 'ToU16($1)',         'ToU16($1)'), // ToU16
+    ('ToU32', 'ToU32', 'ToU32($1)',         'ToU32($1)'), // ToU32
+    ('',   '',   '$1',                '$1'), // ToFloat
+    ('',   '',   '$1',                '$1'), // ToBiggestFloat
+    ('',   '',   'Math.floor($1)',    'Math.floor($1)'), // ToInt
+    ('',   '',   'Math.floor($1)',    'Math.floor($1)'), // ToBiggestInt
+
+    ('nimCharToStr', 'nimCharToStr', 'nimCharToStr($1)', 'nimCharToStr($1)'),
+    ('nimBoolToStr', 'nimBoolToStr', 'nimBoolToStr($1)', 'nimBoolToStr($1)'),
+    ('cstrToNimStr', 'cstrToNimStr', 'cstrToNimStr(($1)+"")', 'cstrToNimStr(($1)+"")'),
+    ('cstrToNimStr', 'cstrToNimStr', 'cstrToNimStr(($1)+"")', 'cstrToNimStr(($1)+"")'),
+    ('cstrToNimStr', 'cstrToNimStr', 'cstrToNimStr(($1)+"")', 'cstrToNimStr(($1)+"")'),
+    ('cstrToNimStr', 'cstrToNimStr', 'cstrToNimStr($1)', 'cstrToNimStr($1)'),
+    ('', '', '$1', '$1')
+  );
+
+procedure binaryExpr(var p: TProc; n: PNode; var r: TCompRes;
+                     const magic, frmt: string);
+var
+  x, y: TCompRes;
+begin
+  if magic <> '' then useMagic(p, magic);
+  gen(p, n.sons[1], x);
+  gen(p, n.sons[2], y);
+  r.res := ropef(frmt, [x.res, y.res]);
+  r.com := mergeExpr(x.com, y.com);
+end;
+
+procedure binaryStmt(var p: TProc; n: PNode; var r: TCompRes;
+                     const magic, frmt: string);
+var
+  x, y: TCompRes;
+begin
+  if magic <> '' then useMagic(p, magic);
+  gen(p, n.sons[1], x);
+  gen(p, n.sons[2], y);
+  if x.com <> nil then appf(r.com, '$1;$n', [x.com]);
+  if y.com <> nil then appf(r.com, '$1;$n', [y.com]);
+  appf(r.com, frmt, [x.res, y.res]);
+end;
+
+procedure unaryExpr(var p: TProc; n: PNode; var r: TCompRes;
+                    const magic, frmt: string);
+begin
+  if magic <> '' then useMagic(p, magic);
+  gen(p, n.sons[1], r);
+  r.res := ropef(frmt, [r.res]);
+end;
+
+procedure arith(var p: TProc; n: PNode; var r: TCompRes; op: TMagic);
+var
+  x, y: TCompRes;
+  i: int;
+begin
+  if optOverflowCheck in p.options then i := 0 else i := 1;
+  useMagic(p, ops[op][i]);
+  if sonsLen(n) > 2 then begin
+    gen(p, n.sons[1], x);
+    gen(p, n.sons[2], y);
+    r.res := ropef(ops[op][i+2], [x.res, y.res]);
+    r.com := mergeExpr(x.com, y.com);
+  end
+  else begin
+    gen(p, n.sons[1], r);
+    r.res := ropef(ops[op][i+2], [r.res])
+  end
+end;
+
+procedure genLineDir(var p: TProc; n: PNode; var r: TCompRes);
+var
+  line: int;
+begin
+  line := toLinenumber(n.info);
+  if optLineDir in p.Options then // pretty useless, but better than nothing
+    appf(r.com, '// line $2 "$1"$n',
+      [toRope(toFilename(n.info)), toRope(line)]);
+  if ([optStackTrace, optEndb] * p.Options = [optStackTrace, optEndb]) and
+      ((p.prc = nil) or not (sfPure in p.prc.flags)) then begin
+    useMagic(p, 'endb');
+    appf(r.com, 'endb($1);$n', [toRope(line)])
+  end
+  else if ([optLineTrace, optStackTrace] * p.Options =
+        [optLineTrace, optStackTrace]) and ((p.prc = nil) or
+      not (sfPure in p.prc.flags)) then
+    appf(r.com, 'F.line = $1;$n', [toRope(line)])
+end;
+
+procedure finishTryStmt(var p: TProc; var r: TCompRes; howMany: int);
+var
+  i: int;
+begin
+  for i := 1 to howMany do
+    app(r.com, 'excHandler = excHandler.prev;' + tnl);
+end;
+
+procedure genWhileStmt(var p: TProc; n: PNode; var r: TCompRes);
+var
+  cond, stmt: TCompRes;
+  len, labl: int;
+begin
+  genLineDir(p, n, r);
+  inc(p.unique);
+  len := length(p.blocks);
+  setLength(p.blocks, len+1);
+  p.blocks[len].id := -p.unique;
+  p.blocks[len].nestedTryStmts := p.nestedTryStmts;
+  labl := p.unique;
+  gen(p, n.sons[0], cond);
+  genStmt(p, n.sons[1], stmt);
+  if p.blocks[len].id > 0 then
+    appf(r.com, 'L$3: while ($1) {$n$2}$n',
+      [mergeExpr(cond), mergeStmt(stmt), toRope(labl)])
+  else
+    appf(r.com, 'while ($1) {$n$2}$n',
+      [mergeExpr(cond), mergeStmt(stmt)]);
+  setLength(p.blocks, len);
+end;
+
+procedure genTryStmt(var p: TProc; n: PNode; var r: TCompRes);
+  // code to generate:
+(*
+  var sp = {prev: excHandler, exc: null};
+  excHandler = sp;
+  try {
+    stmts;
+  } catch (e) {
+    if (e.typ && e.typ == NTI433 || e.typ == NTI2321) {
+      stmts;
+    } else if (e.typ && e.typ == NTI32342) {
+      stmts;
+    } else {
+      stmts;
+    }
+  } finally {
+    stmts;
+    excHandler = excHandler.prev;
+  }
+*)
+var
+  i, j, len, blen: int;
+  safePoint, orExpr, epart: PRope;
+  a: TCompRes;
+begin
+  genLineDir(p, n, r);
+  inc(p.unique);
+  safePoint := ropef('Tmp$1', [toRope(p.unique)]);
+  appf(r.com, 'var $1 = {prev: excHandler, exc: null};$n' +
+              'excHandler = $1;$n', [safePoint]);
+  if optStackTrace in p.Options then
+    app(r.com, 'framePtr = F;' + tnl);
+  app(r.com, 'try {' + tnl);
+  len := sonsLen(n);
+  inc(p.nestedTryStmts);
+  genStmt(p, n.sons[0], a);
+  app(r.com, mergeStmt(a));
+  i := 1;
+  epart := nil;
+  while (i < len) and (n.sons[i].kind = nkExceptBranch) do begin
+    blen := sonsLen(n.sons[i]);
+    if blen = 1 then begin
+      // general except section:
+      if i > 1 then app(epart, 'else {' + tnl);
+      genStmt(p, n.sons[i].sons[0], a);
+      app(epart, mergeStmt(a));
+      if i > 1 then app(epart, '}' + tnl);
+    end
+    else begin
+      orExpr := nil;
+      for j := 0 to blen-2 do begin
+        if (n.sons[i].sons[j].kind <> nkType) then
+          InternalError(n.info, 'genTryStmt');
+        if orExpr <> nil then app(orExpr, '||');
+        appf(orExpr, '($1.exc.m_type == $2)',
+          [safePoint, genTypeInfo(p, n.sons[i].sons[j].typ)])
+      end;
+      if i > 1 then app(epart, 'else ');
+      appf(epart, 'if ($1.exc && $2) {$n', [safePoint, orExpr]);
+      genStmt(p, n.sons[i].sons[blen - 1], a);
+      appf(epart, '$1}$n', [mergeStmt(a)]);
+    end;
+    inc(i)
+  end;
+  if epart <> nil then
+    appf(r.com, '} catch (EXC) {$n$1', [epart]);
+  finishTryStmt(p, r, p.nestedTryStmts);
+  dec(p.nestedTryStmts);
+  app(r.com, '} finally {' + tnl + 'excHandler = excHandler.prev;' +{&} tnl);
+  if (i < len) and (n.sons[i].kind = nkFinally) then begin
+    genStmt(p, n.sons[i].sons[0], a);
+    app(r.com, mergeStmt(a));
+  end;
+  app(r.com, '}' + tnl);
+end;
+
+procedure genRaiseStmt(var p: TProc; n: PNode; var r: TCompRes);
+var
+  a: TCompRes;
+  typ: PType;
+begin
+  genLineDir(p, n, r);
+  if n.sons[0] <> nil then begin
+    gen(p, n.sons[0], a);
+    if a.com <> nil then appf(r.com, '$1;$n', [a.com]);
+    typ := skipPtrsGeneric(n.sons[0].typ);
+    useMagic(p, 'raiseException');
+    appf(r.com, 'raiseException($1, $2);$n',
+      [a.res, makeCString(typ.sym.name.s)]);
+  end
+  else begin
+    useMagic(p, 'reraiseException');
+    app(r.com, 'reraiseException();' + tnl);
+  end
+end;
+
+procedure genCaseStmt(var p: TProc; n: PNode; var r: TCompRes);
+var
+  cond, stmt: TCompRes;
+  i, j: int;
+  it, e, v: PNode;
+  stringSwitch: bool;
+begin
+  genLineDir(p, n, r);
+  gen(p, n.sons[0], cond);
+  if cond.com <> nil then
+    appf(r.com, '$1;$n', [cond.com]);
+  stringSwitch := skipVarGeneric(n.sons[0].typ).kind = tyString;
+  if stringSwitch then begin
+    useMagic(p, 'toEcmaStr');
+    appf(r.com, 'switch (toEcmaStr($1)) {$n', [cond.res])
+  end
+  else
+    appf(r.com, 'switch ($1) {$n', [cond.res]);
+  for i := 1 to sonsLen(n)-1 do begin
+    it := n.sons[i];
+    case it.kind of
+      nkOfBranch: begin
+        for j := 0 to sonsLen(it)-2 do begin
+          e := it.sons[j];
+          if e.kind = nkRange then begin
+            v := copyNode(e.sons[0]);
+            while (v.intVal <= e.sons[1].intVal) do begin
+              gen(p, v, cond);
+              if cond.com <> nil then
+                internalError(v.info, 'ecmasgen.genCaseStmt');
+              appf(r.com, 'case $1: ', [cond.res]);
+              Inc(v.intVal)
+            end
+          end
+          else begin
+            gen(p, e, cond);
+            if cond.com <> nil then
+              internalError(e.info, 'ecmasgen.genCaseStmt');
+            if stringSwitch then begin
+              case e.kind of
+                nkStrLit..nkTripleStrLit:
+                  appf(r.com, 'case $1: ', [makeCString(e.strVal)]);
+                else InternalError(e.info, 'ecmasgen.genCaseStmt: 2');
+              end
+            end
+            else
+              appf(r.com, 'case $1: ', [cond.res]);
+          end
+        end;
+        genStmt(p, lastSon(it), stmt);
+        appf(r.com, '$n$1break;$n', [mergeStmt(stmt)]);
+      end;
+      nkElse: begin
+        genStmt(p, it.sons[0], stmt);
+        appf(r.com, 'default: $n$1break;$n', [mergeStmt(stmt)]);
+      end
+      else internalError(it.info, 'ecmasgen.genCaseStmt')
+    end
+  end;
+  appf(r.com, '}$n', []);
+end;
+
+procedure genStmtListExpr(var p: TProc; n: PNode; var r: TCompRes); forward;
+
+procedure genBlock(var p: TProc; n: PNode; var r: TCompRes);
+var
+  idx, labl: int;
+  sym: PSym;
+begin
+  inc(p.unique);
+  idx := length(p.blocks);
+  if n.sons[0] <> nil then begin // named block?
+    if (n.sons[0].kind <> nkSym) then InternalError(n.info, 'genBlock');
+    sym := n.sons[0].sym;
+    sym.loc.k := locOther;
+    sym.loc.a := idx
+  end;
+  setLength(p.blocks, idx+1);
+  p.blocks[idx].id := -p.unique; // negative because it isn't used yet
+  p.blocks[idx].nestedTryStmts := p.nestedTryStmts;
+  labl := p.unique;
+  if n.kind = nkBlockExpr then genStmtListExpr(p, n.sons[1], r)
+  else genStmt(p, n.sons[1], r);
+  if p.blocks[idx].id > 0 then begin // label has been used:
+    r.com := ropef('L$1: do {$n$2} while(false);$n',
+                   [toRope(labl), r.com]);
+  end;
+  setLength(p.blocks, idx)
+end;
+
+procedure genBreakStmt(var p: TProc; n: PNode; var r: TCompRes);
+var
+  idx: int;
+  sym: PSym;
+begin
+  genLineDir(p, n, r);
+  idx := length(p.blocks)-1;
+  if n.sons[0] <> nil then begin // named break?
+    assert(n.sons[0].kind = nkSym);
+    sym := n.sons[0].sym;
+    assert(sym.loc.k = locOther);
+    idx := sym.loc.a
+  end;
+  p.blocks[idx].id := abs(p.blocks[idx].id); // label is used
+  finishTryStmt(p, r, p.nestedTryStmts - p.blocks[idx].nestedTryStmts);
+  appf(r.com, 'break L$1;$n', [toRope(p.blocks[idx].id)])
+end;
+
+procedure genAsmStmt(var p: TProc; n: PNode; var r: TCompRes);
+var
+  i: int;
+begin
+  genLineDir(p, n, r);
+  assert(n.kind = nkAsmStmt);
+  for i := 0 to sonsLen(n)-1 do begin
+    case n.sons[i].Kind of
+      nkStrLit..nkTripleStrLit: app(r.com, n.sons[i].strVal);
+      nkSym: app(r.com, mangleName(n.sons[i].sym));
+      else InternalError(n.sons[i].info, 'ecmasgen: genAsmStmt()')
+    end
+  end
+end;
+
+procedure genIfStmt(var p: TProc; n: PNode; var r: TCompRes);
+var
+  i, toClose: int;
+  cond, stmt: TCompRes;
+  it: PNode;
+begin
+  toClose := 0;
+  for i := 0 to sonsLen(n)-1 do begin
+    it := n.sons[i];
+    if sonsLen(it) <> 1 then begin
+      gen(p, it.sons[0], cond);
+      genStmt(p, it.sons[1], stmt);
+      if i > 0 then begin appf(r.com, 'else {$n', []); inc(toClose) end;
+      if cond.com <> nil then appf(r.com, '$1;$n', [cond.com]);
+      appf(r.com, 'if ($1) {$n$2}', [cond.res, mergeStmt(stmt)]);
+    end
+    else begin
+      // else part:
+      genStmt(p, it.sons[0], stmt);
+      appf(r.com, 'else {$n$1}$n', [mergeStmt(stmt)]);
+    end
+  end;
+  app(r.com, repeatChar(toClose, '}')+{&}tnl);
+end;
+
+procedure genIfExpr(var p: TProc; n: PNode; var r: TCompRes);
+var
+  i, toClose: int;
+  cond, stmt: TCompRes;
+  it: PNode;
+begin
+  toClose := 0;
+  for i := 0 to sonsLen(n)-1 do begin
+    it := n.sons[i];
+    if sonsLen(it) <> 1 then begin
+      gen(p, it.sons[0], cond);
+      gen(p, it.sons[1], stmt);
+      if i > 0 then begin app(r.res, ': ('); inc(toClose); end;
+      r.com := mergeExpr(r.com, cond.com);
+      r.com := mergeExpr(r.com, stmt.com);
+      appf(r.res, '($1) ? ($2)', [cond.res, stmt.res]);
+    end
+    else begin
+      // else part:
+      gen(p, it.sons[0], stmt);
+      r.com := mergeExpr(r.com, stmt.com);
+      appf(r.res, ': ($1)', [stmt.res]);
+    end
+  end;
+  app(r.res, repeatChar(toClose, ')'));
+end;
+
+function generateHeader(var p: TProc; typ: PType): PRope;
+var
+  i: int;
+  param: PSym;
+  name: PRope;
+begin
+  result := nil;
+  for i := 1 to sonsLen(typ.n)-1 do begin
+    if result <> nil then app(result, ', ');
+    assert(typ.n.sons[i].kind = nkSym);
+    param := typ.n.sons[i].sym;
+    name := mangleName(param);
+    app(result, name);
+    if mapType(param.typ) = etyBaseIndex then begin
+      app(result, ', ');
+      app(result, name);
+      app(result, '_Idx');
+    end
+  end
+end;
+
+const
+  nodeKindsNeedNoCopy = {@set}[nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
+                               nkFloatLit..nkFloat64Lit,
+                               nkCurly, nkPar, 
+                               nkStringToCString, nkCStringToString,
+                               nkCall, nkHiddenCallConv];
+
+function needsNoCopy(y: PNode): bool;
+begin
+  result := (y.kind in nodeKindsNeedNoCopy)
+      or (skipGeneric(y.typ).kind in [tyRef, tyPtr, tyVar])
+end;
+
+procedure genAsgnAux(var p: TProc; x, y: PNode; var r: TCompRes);
+var
+  a, b: TCompRes;
+begin
+  gen(p, x, a);
+  gen(p, y, b);
+  case mapType(x.typ) of
+    etyObject: begin
+      if a.com <> nil then appf(r.com, '$1;$n', [a.com]);
+      if b.com <> nil then appf(r.com, '$1;$n', [b.com]);
+      if needsNoCopy(y) then
+        appf(r.com, '$1 = $2;$n', [a.res, b.res])
+      else begin
+        useMagic(p, 'NimCopy');
+        appf(r.com, '$1 = NimCopy($2, $3);$n',
+            [a.res, b.res, genTypeInfo(p, y.typ)]);
+      end
+    end;
+    etyBaseIndex: begin
+      if (a.kind <> etyBaseIndex) or (b.kind <> etyBaseIndex) then
+        internalError(x.info, 'genAsgn');
+      appf(r.com, '$1 = $2; $3 = $4;$n', [a.com, b.com, a.res, b.res]);
+    end
+    else begin
+      if a.com <> nil then appf(r.com, '$1;$n', [a.com]);
+      if b.com <> nil then appf(r.com, '$1;$n', [b.com]);
+      appf(r.com, '$1 = $2;$n', [a.res, b.res]);
+    end
+  end
+end;
+
+procedure genAsgn(var p: TProc; n: PNode; var r: TCompRes);
+begin
+  genLineDir(p, n, r);
+  genAsgnAux(p, n.sons[0], n.sons[1], r);
+end;
+
+procedure genSwap(var p: TProc; n: PNode; var r: TCompRes);
+var
+  a, b: TCompRes;
+  tmp, tmp2: PRope;
+begin
+  gen(p, n.sons[1], a);
+  gen(p, n.sons[2], b);
+  inc(p.unique);
+  tmp := ropef('Tmp$1', [toRope(p.unique)]);
+  case mapType(n.sons[1].typ) of
+    etyBaseIndex: begin
+      inc(p.unique);
+      tmp2 := ropef('Tmp$1', [toRope(p.unique)]);
+      if (a.kind <> etyBaseIndex) or (b.kind <> etyBaseIndex) then
+        internalError(n.info, 'genSwap');
+      appf(r.com, 'var $1 = $2; $2 = $3; $3 = $1;$n', [tmp, a.com, b.com]);
+      appf(r.com, 'var $1 = $2; $2 = $3; $3 = $1', [tmp2, a.res, b.res]);
+    end
+    else begin
+      if a.com <> nil then appf(r.com, '$1;$n', [a.com]);
+      if b.com <> nil then appf(r.com, '$1;$n', [b.com]);
+      appf(r.com, 'var $1 = $2; $2 = $3; $3 = $1', [tmp, a.res, b.res]);
+    end
+  end
+end;
+
+procedure genFieldAddr(var p: TProc; n: PNode; var r: TCompRes);
+var
+  a: TCompRes;
+  f: PSym;
+begin
+  r.kind := etyBaseIndex;
+  gen(p, n.sons[0], a);
+  if n.sons[1].kind <> nkSym then
+    InternalError(n.sons[1].info, 'genFieldAddr');
+  f := n.sons[1].sym;
+  if f.loc.r = nil then f.loc.r := mangleName(f);
+  r.res := makeCString(ropeToStr(f.loc.r));
+  r.com := mergeExpr(a);
+end;
+
+procedure genFieldAccess(var p: TProc; n: PNode; var r: TCompRes);
+var
+  f: PSym;
+begin
+  r.kind := etyNone;
+  gen(p, n.sons[0], r);
+  if n.sons[1].kind <> nkSym then
+    InternalError(n.sons[1].info, 'genFieldAddr');
+  f := n.sons[1].sym;
+  if f.loc.r = nil then f.loc.r := mangleName(f);
+  r.res := ropef('$1.$2', [r.res, f.loc.r]);
+end;
+
+procedure genCheckedFieldAddr(var p: TProc; n: PNode; var r: TCompRes);
+begin
+  genFieldAddr(p, n.sons[0], r); // XXX
+end;
+
+procedure genCheckedFieldAccess(var p: TProc; n: PNode; var r: TCompRes);
+begin
+  genFieldAccess(p, n.sons[0], r); // XXX
+end;
+
+procedure genArrayAddr(var p: TProc; n: PNode; var r: TCompRes);
+var
+  a, b: TCompRes;
+  first: biggestInt;
+  typ: PType;
+begin
+  r.kind := etyBaseIndex;
+  gen(p, n.sons[0], a);
+  gen(p, n.sons[1], b);
+  r.com := mergeExpr(a);
+  typ := skipPtrsGeneric(n.sons[0].typ);
+  if typ.kind in [tyArray, tyArrayConstr] then first := FirstOrd(typ.sons[0])
+  else first := 0;
+  if (optBoundsCheck in p.options) and not isConstExpr(n.sons[1]) then begin
+    useMagic(p, 'chckIndx');
+    b.res := ropef('chckIndx($1, $2, $3.length)-$2',
+                  [b.res, toRope(first), a.res]);
+    // XXX: BUG: a.res evaluated twice!
+  end
+  else if first <> 0 then begin
+    b.res := ropef('($1)-$2', [b.res, toRope(first)]);
+  end;
+  r.res := mergeExpr(b);
+end;
+
+procedure genArrayAccess(var p: TProc; n: PNode; var r: TCompRes);
+begin
+  genArrayAddr(p, n, r);
+  r.kind := etyNone;
+  r.res := ropef('$1[$2]', [r.com, r.res]);
+  r.com := nil;
+end;
+
+(*
+type
+  TMyList = record
+    x: seq[ptr ptr int]
+    L: int
+    next: ptr TMyList
+
+proc myAdd(head: var ptr TMyList, item: ptr TMyList) =
+  item.next = head
+  head = item
+
+proc changeInt(i: var int) = inc(i)
+
+proc f(p: ptr TMyList, x: ptr ptr int) =
+  add p.x, x
+  p.next = nil
+  changeInt(p.L)
+
+*)
+
+procedure genAddr(var p: TProc; n: PNode; var r: TCompRes);
+var
+  s: PSym;
+begin
+  case n.sons[0].kind of
+    nkSym: begin
+      s := n.sons[0].sym;
+      if s.loc.r = nil then InternalError(n.info, 'genAddr: 3');
+      case s.kind of
+        skVar: begin
+          if mapType(n.typ) = etyObject then begin
+            // make addr() a no-op:
+            r.kind := etyNone;
+            r.res := s.loc.r;
+            r.com := nil;
+          end
+          else if sfGlobal in s.flags then begin
+            // globals are always indirect accessible
+            r.kind := etyBaseIndex;
+            r.com := toRope('Globals');
+            r.res := makeCString(ropeToStr(s.loc.r));
+          end
+          else if sfAddrTaken in s.flags then begin
+            r.kind := etyBaseIndex;
+            r.com := s.loc.r;
+            r.res := toRope('0'+'');
+          end
+          else InternalError(n.info, 'genAddr: 4');
+        end;
+        else InternalError(n.info, 'genAddr: 2');
+      end;
+    end;
+    nkCheckedFieldExpr: genCheckedFieldAddr(p, n, r);
+    nkDotExpr, nkQualified: genFieldAddr(p, n, r);
+    nkBracketExpr: genArrayAddr(p, n, r);
+    else InternalError(n.info, 'genAddr');
+  end
+end;
+
+procedure genSym(var p: TProc; n: PNode; var r: TCompRes);
+var
+  s: PSym;
+  k: TEcmasTypeKind;
+begin
+  s := n.sym;
+  if s.loc.r = nil then
+    InternalError(n.info, 'symbol has no generated name: ' + s.name.s);
+  case s.kind of
+    skVar, skParam, skTemp: begin
+      k := mapType(s.typ);
+      if k = etyBaseIndex then begin
+        r.kind := etyBaseIndex;
+        if [sfAddrTaken, sfGlobal] * s.flags <> [] then begin
+          r.com := ropef('$1[0]', [s.loc.r]);
+          r.res := ropef('$1[1]', [s.loc.r]);
+        end
+        else begin
+          r.com := s.loc.r;
+          r.res := con(s.loc.r, '_Idx');
+        end
+      end
+      else if (k <> etyObject) and (sfAddrTaken in s.flags) then
+        r.res := ropef('$1[0]', [s.loc.r])
+      else
+        r.res := s.loc.r
+    end
+    else r.res := s.loc.r;
+  end
+end;
+
+procedure genDeref(var p: TProc; n: PNode; var r: TCompRes);
+var
+  a: TCompRes;
+begin
+  if mapType(n.sons[0].typ) = etyObject then
+    gen(p, n.sons[0], r)
+  else begin
+    gen(p, n.sons[0], a);
+    if a.kind <> etyBaseIndex then InternalError(n.info, 'genDeref');
+    r.res := ropef('$1[$2]', [a.com, a.res])
+  end
+end;
+
+procedure genCall(var p: TProc; n: PNode; var r: TCompRes);
+var
+  a: TCompRes;
+  i: int;
+begin
+  gen(p, n.sons[0], r);
+  app(r.res, '('+'');
+  for i := 1 to sonsLen(n)-1 do begin
+    if i > 1 then app(r.res, ', ');
+    gen(p, n.sons[i], a);
+    if a.kind = etyBaseIndex then begin
+      app(r.res, a.com);
+      app(r.res, ', ');
+      app(r.res, a.res);
+    end
+    else
+      app(r.res, mergeExpr(a));
+  end;
+  app(r.res, ')'+'');
+end;
+
+function putToSeq(const s: string; indirect: bool): PRope;
+begin
+  result := toRope(s);
+  if indirect then result := ropef('[$1]', [result])
+end;
+
+function createVar(var p: TProc; typ: PType;
+                   indirect: bool): PRope; forward;
+
+function createRecordVarAux(var p: TProc; rec: PNode; var c: int): PRope;
+var
+  i: int;
+begin
+  result := nil;
+  case rec.kind of
+    nkRecList: begin
+      for i := 0 to sonsLen(rec)-1 do
+        app(result, createRecordVarAux(p, rec.sons[i], c))
+    end;
+    nkRecCase: begin
+      app(result, createRecordVarAux(p, rec.sons[0], c));
+      for i := 1 to sonsLen(rec)-1 do
+        app(result, createRecordVarAux(p, lastSon(rec.sons[i]), c));
+    end;
+    nkSym: begin
+      if c > 0 then app(result, ', ');
+      app(result, mangleName(rec.sym));
+      app(result, ': ');
+      app(result, createVar(p, rec.sym.typ, false));
+      inc(c);
+    end;
+    else InternalError(rec.info, 'createRecordVarAux')
+  end
+end;
+
+function createVar(var p: TProc; typ: PType; indirect: bool): PRope;
+var
+  i, len, c: int;
+  t, e: PType;
+begin
+  t := skipGeneric(typ);
+  case t.kind of
+    tyInt..tyInt64, tyEnum, tyAnyEnum, tyChar: begin
+      result := putToSeq('0'+'', indirect)
+    end;
+    tyFloat..tyFloat128: result := putToSeq('0.0', indirect);
+    tyRange: result := createVar(p, typ.sons[0], indirect);
+    tySet: result := toRope('{}');
+    tyBool: result := putToSeq('false', indirect);
+    tyArray, tyArrayConstr: begin
+      len := int(lengthOrd(t));
+      e := elemType(t);
+      if len > 32 then begin
+        useMagic(p, 'ArrayConstr');
+        result := ropef('ArrayConstr($1, $2, $3)',
+                        [toRope(len), createVar(p, e, false),
+                        genTypeInfo(p, e)])
+      end
+      else begin
+        result := toRope('['+'');
+        i := 0;
+        while i < len do begin
+          if i > 0 then app(result, ', ');
+          app(result, createVar(p, e, false));
+          inc(i);
+        end;
+        app(result, ']'+'');
+      end
+    end;
+    tyTuple: begin
+      result := toRope('{'+'');
+      c := 0;
+      app(result, createRecordVarAux(p, t.n, c));
+      app(result, '}'+'');
+    end;
+    tyObject: begin
+      result := toRope('{'+'');
+      c := 0;
+      if not (tfFinal in t.flags) or (t.sons[0] <> nil) then begin
+        inc(c);
+        appf(result, 'm_type: $1', [genTypeInfo(p, t)]);
+      end;
+      while t <> nil do begin
+        app(result, createRecordVarAux(p, t.n, c));
+        t := t.sons[0];
+      end;
+      app(result, '}'+'');
+    end;
+    tyVar, tyPtr, tyRef: begin
+      if mapType(t) = etyBaseIndex then
+        result := putToSeq('[null, 0]', indirect)
+      else
+        result := putToSeq('null', indirect);
+    end;
+    tySequence, tyString, tyCString, tyPointer: begin
+      result := putToSeq('null', indirect);
+    end
+    else begin
+      internalError('createVar: ' + typekindtoStr[t.kind]);
+      result := nil;
+    end
+  end
+end;
+
+function isIndirect(v: PSym): bool;
+begin
+  result := (sfAddrTaken in v.flags) and (mapType(v.typ) <> etyObject);
+end;
+
+procedure genVarInit(var p: TProc; v: PSym; n: PNode; var r: TCompRes);
+var
+  a: TCompRes;
+  s: PRope;
+begin
+  if n = nil then begin
+    appf(r.com, 'var $1 = $2;$n',
+        [mangleName(v), createVar(p, v.typ, isIndirect(v))])
+  end
+  else begin
+    {@discard} mangleName(v);
+    gen(p, n, a);
+    case mapType(v.typ) of
+      etyObject: begin
+        if a.com <> nil then appf(r.com, '$1;$n', [a.com]);
+        if needsNoCopy(n) then s := a.res
+        else begin
+          useMagic(p, 'NimCopy');
+          s := ropef('NimCopy($1, $2)', [a.res, genTypeInfo(p, n.typ)]);
+        end
+      end;
+      etyBaseIndex: begin
+        if (a.kind <> etyBaseIndex) then InternalError(n.info, 'genVarInit');
+        if [sfAddrTaken, sfGlobal] * v.flags <> [] then
+          appf(r.com, 'var $1 = [$2, $3];$n', [v.loc.r, a.com, a.res])
+        else
+          appf(r.com, 'var $1 = $2; var $1_Idx = $3;$n',
+               [v.loc.r, a.com, a.res]);
+        exit
+      end
+      else begin
+        if a.com <> nil then appf(r.com, '$1;$n', [a.com]);
+        s := a.res;
+      end
+    end;
+    if isIndirect(v) then
+      appf(r.com, 'var $1 = [$2];$n', [v.loc.r, s])
+    else
+      appf(r.com, 'var $1 = $2;$n', [v.loc.r, s])
+  end;
+end;
+
+procedure genVarStmt(var p: TProc; n: PNode; var r: TCompRes);
+var
+  i: int;
+  v: PSym;
+  a: PNode;
+begin
+  for i := 0 to sonsLen(n)-1 do begin
+    a := n.sons[i];
+    if a.kind = nkCommentStmt then continue;
+    assert(a.kind = nkIdentDefs);
+    assert(a.sons[0].kind = nkSym);
+    v := a.sons[0].sym;
+    if lfNoDecl in v.loc.flags then continue;
+    genLineDir(p, a, r);
+    genVarInit(p, v, a.sons[2], r);
+  end
+end;
+
+procedure genConstStmt(var p: TProc; n: PNode; var r: TCompRes);
+var
+  c: PSym;
+  i: int;
+begin
+  genLineDir(p, n, r);
+  for i := 0 to sonsLen(n)-1 do begin
+    if n.sons[i].kind = nkCommentStmt then continue;
+    assert(n.sons[i].kind = nkConstDef);
+    c := n.sons[i].sons[0].sym;
+    if (c.ast <> nil) and (c.typ.kind in ConstantDataTypes) and
+           not (lfNoDecl in c.loc.flags) then begin
+      genLineDir(p, n.sons[i], r);
+      genVarInit(p, c, c.ast, r);
+    end
+  end
+end;
+
+procedure genNew(var p: TProc; n: PNode; var r: TCompRes);
+var
+  a: TCompRes;
+  t: Ptype;
+begin
+  gen(p, n.sons[1], a);
+  t := skipVarGeneric(n.sons[1].typ).sons[0];
+  if a.com <> nil then appf(r.com, '$1;$n', [a.com]);
+  appf(r.com, '$1 = $2;$n', [a.res, createVar(p, t, true)]);
+end;
+
+procedure genOrd(var p: TProc; n: PNode; var r: TCompRes);
+begin
+  case skipVarGeneric(n.sons[1].typ).kind of
+    tyEnum, tyAnyEnum, tyInt..tyInt64, tyChar: gen(p, n.sons[1], r);
+    tyBool: unaryExpr(p, n, r, '', '($1 ? 1:0)');
+    else InternalError(n.info, 'genOrd');
+  end
+end;
+
+procedure genConStrStr(var p: TProc; n: PNode; var r: TCompRes);
+var
+  a, b: TCompRes;
+begin
+  gen(p, n.sons[1], a);
+  gen(p, n.sons[2], b);
+  r.com := mergeExpr(a.com, b.com);
+  if skipVarGenericRange(n.sons[1].typ).kind = tyChar then
+    a.res := ropef('[$1, 0]', [a.res]);
+  if skipVarGenericRange(n.sons[2].typ).kind = tyChar then
+    b.res := ropef('[$1, 0]', [b.res]);
+  r.res := ropef('($1.slice(0,-1)).concat($2)', [a.res, b.res]);
+end;
+
+procedure genMagic(var p: TProc; n: PNode; var r: TCompRes);
+var
+  a: TCompRes;
+  line, filen: PRope;
+  op: TMagic;
+begin
+  op := n.sons[0].sym.magic;
+  case op of
+    mOr: genOr(p, n.sons[1], n.sons[2], r);
+    mAnd: genAnd(p, n.sons[1], n.sons[2], r);
+    mAddi..mStrToStr: arith(p, n, r, op);
+    //mRepr: genRepr(p, n, r);
+    mSwap: genSwap(p, n, r);
+    mPred: begin // XXX: range checking?
+      if not (optOverflowCheck in p.Options) then
+        binaryExpr(p, n, r, '', '$1 - $2')
+      else
+        binaryExpr(p, n, r, 'subInt', 'subInt($1, $2)')
+    end;
+    mSucc: begin // XXX: range checking?
+      if not (optOverflowCheck in p.Options) then
+        binaryExpr(p, n, r, '', '$1 - $2')
+      else
+        binaryExpr(p, n, r, 'addInt', 'addInt($1, $2)')
+    end;
+    mAppendStrCh: binaryStmt(p, n, r, 'addChar', '$1 = addChar($1, $2)');
+    mAppendStrStr:
+      binaryStmt(p, n, r, '', '$1 = ($1.slice(0,-1)).concat($2)');
+      // XXX: make a copy of $2, because of EMCAScript's sucking semantics
+    mAppendSeqElem: binaryStmt(p, n, r, '', '$1.push($2)');
+    mConStrStr: genConStrStr(p, n, r);
+    mEqStr: binaryExpr(p, n, r, 'eqStrings', 'eqStrings($1, $2)');
+    mLeStr: binaryExpr(p, n, r, 'cmpStrings', '(cmpStrings($1, $2) <= 0)');
+    mLtStr: binaryExpr(p, n, r, 'cmpStrings', '(cmpStrings($1, $2) < 0)');
+    mIsNil: unaryExpr(p, n, r, '', '$1 == null');
+    mAssert: begin
+      if (optAssert in p.Options) then begin
+        useMagic(p, 'internalAssert');
+        gen(p, n.sons[1], a);
+        line := toRope(toLinenumber(n.info));
+        filen := makeCString(ToFilename(n.info));
+        appf(r.com, 'if (!($3)) internalAssert($1, $2)',
+                      [filen, line, mergeExpr(a)])
+      end
+    end;
+    mNew, mNewFinalize: genNew(p, n, r);
+    mSizeOf: r.res := toRope(getSize(n.sons[1].typ));
+    mChr: gen(p, n.sons[1], r); // nothing to do
+    mOrd: genOrd(p, n, r);
+    mLengthStr: unaryExpr(p, n, r, '', '($1.length-1)');
+    mLengthSeq, mLengthOpenArray, mLengthArray:
+      unaryExpr(p, n, r, '', '$1.length');
+    mHigh: begin
+      if skipVarGeneric(n.sons[0].typ).kind = tyString then
+        unaryExpr(p, n, r, '', '($1.length-2)')
+      else
+        unaryExpr(p, n, r, '', '($1.length-1)');
+    end;
+    mInc: begin
+      if not (optOverflowCheck in p.Options) then
+        binaryStmt(p, n, r, '', '$1 += $2')
+      else
+        binaryStmt(p, n, r, 'addInt', '$1 = addInt($1, $2)')
+    end;
+    ast.mDec: begin
+      if not (optOverflowCheck in p.Options) then
+        binaryStmt(p, n, r, '', '$1 -= $2')
+      else
+        binaryStmt(p, n, r, 'subInt', '$1 = subInt($1, $2)')
+    end;
+    mSetLengthStr: binaryStmt(p, n, r, '', '$1.length = ($2)-1');
+    mSetLengthSeq: binaryStmt(p, n, r, '', '$1.length = $2');
+    mCard: unaryExpr(p, n, r, 'SetCard', 'SetCard($1)');
+    mLtSet: binaryExpr(p, n, r, 'SetLt', 'SetLt($1, $2)');
+    mLeSet: binaryExpr(p, n, r, 'SetLe', 'SetLe($1, $2)');
+    mEqSet: binaryExpr(p, n, r, 'SetEq', 'SetEq($1, $2)');
+    mMulSet: binaryExpr(p, n, r, 'SetMul', 'SetMul($1, $2)');
+    mPlusSet: binaryExpr(p, n, r, 'SetPlus', 'SetPlus($1, $2)');
+    mMinusSet: binaryExpr(p, n, r, 'SetMinus', 'SetMinus($1, $2)');
+    mIncl: binaryStmt(p, n, r, '', '$1[$2] = true');
+    mExcl: binaryStmt(p, n, r, '', 'delete $1[$2]');
+    mInSet: binaryExpr(p, n, r, '', '($1[$2] != undefined)');
+    mNLen..mNError:
+      liMessage(n.info, errCannotGenerateCodeForX, n.sons[0].sym.name.s);
+    else genCall(p, n, r);
+    //else internalError(e.info, 'genMagic: ' + magicToStr[op]);
+  end
+end;
+
+procedure genSetConstr(var p: TProc; n: PNode; var r: TCompRes);
+var
+  a, b: TCompRes;
+  i: int;
+  it: PNode;
+begin
+  useMagic(p, 'SetConstr');
+  r.res := toRope('SetConstr(');
+  for i := 0 to sonsLen(n)-1 do begin
+    if i > 0 then app(r.res, ', ');
+    it := n.sons[i];
+    if it.kind = nkRange then begin
+      gen(p, it.sons[0], a);
+      gen(p, it.sons[1], b);
+      r.com := mergeExpr(r.com, mergeExpr(a.com, b.com));
+      appf(r.res, '[$1, $2]', [a.res, b.res]);
+    end
+    else begin
+      gen(p, it, a);
+      r.com := mergeExpr(r.com, a.com);
+      app(r.res, a.res);
+    end
+  end;
+  app(r.res, ')'+'');
+end;
+
+procedure genArrayConstr(var p: TProc; n: PNode; var r: TCompRes);
+var
+  a: TCompRes;
+  i: int;
+begin
+  r.res := toRope('['+'');
+  for i := 0 to sonsLen(n)-1 do begin
+    if i > 0 then app(r.res, ', ');
+    gen(p, n.sons[i], a);
+    r.com := mergeExpr(r.com, a.com);
+    app(r.res, a.res);
+  end;
+  app(r.res, ']'+'');
+end;
+
+procedure genRecordConstr(var p: TProc; n: PNode; var r: TCompRes);
+var
+  a: TCompRes;
+  i, len: int;
+begin
+  i := 0;
+  len := sonsLen(n);
+  r.res := toRope('{'+'');
+  while i < len do begin
+    if i > 0 then app(r.res, ', ');
+    if (n.sons[i].kind <> nkSym) then
+      internalError(n.sons[i].info, 'genRecordConstr');
+    gen(p, n.sons[i+1], a);
+    r.com := mergeExpr(r.com, a.com);
+    appf(r.res, '$1: $2', [mangleName(n.sons[i].sym), a.res]);
+    inc(i, 2)
+  end
+end;
+
+procedure genConv(var p: TProc; n: PNode; var r: TCompRes);
+var
+  src, dest: PType;
+begin
+  dest := skipVarGenericRange(n.typ);
+  src := skipVarGenericRange(n.sons[1].typ);
+  gen(p, n.sons[1], r);
+  if (dest.kind <> src.kind) and (src.kind = tyBool) then
+    r.res := ropef('(($1)? 1:0)', [r.res])
+end;
+
+procedure upConv(var p: TProc; n: PNode; var r: TCompRes);
+begin
+  gen(p, n.sons[0], r); // XXX
+end;
+
+procedure genRangeChck(var p: TProc; n: PNode; var r: TCompRes;
+                       const magic: string);
+var
+  a, b: TCompRes;
+begin
+  gen(p, n.sons[0], r);
+  if optRangeCheck in p.options then begin
+    gen(p, n.sons[1], a);
+    gen(p, n.sons[2], b);
+    r.com := mergeExpr(r.com, mergeExpr(a.com, b.com));
+    useMagic(p, 'chckRange');
+    r.res := ropef('chckRange($1, $2, $3)', [r.res, a.res, b.res]);
+  end
+end;
+
+procedure convStrToCStr(var p: TProc; n: PNode; var r: TCompRes);
+begin
+  // we do an optimization here as this is likely to slow down
+  // much of the code otherwise:
+  if n.sons[0].kind = nkCStringToString then
+    gen(p, n.sons[0].sons[0], r)
+  else begin
+    gen(p, n.sons[0], r);
+    if r.res = nil then InternalError(n.info, 'convStrToCStr');
+    useMagic(p, 'toEcmaStr');
+    r.res := ropef('toEcmaStr($1)', [r.res]);
+  end;
+end;
+
+procedure convCStrToStr(var p: TProc; n: PNode; var r: TCompRes);
+begin
+  // we do an optimization here as this is likely to slow down
+  // much of the code otherwise:
+  if n.sons[0].kind = nkStringToCString then
+    gen(p, n.sons[0].sons[0], r)
+  else begin
+    gen(p, n.sons[0], r);
+    if r.res = nil then InternalError(n.info, 'convCStrToStr');
+    useMagic(p, 'cstrToNimstr');
+    r.res := ropef('cstrToNimstr($1)', [r.res]);
+  end;
+end;
+
+procedure genReturnStmt(var p: TProc; n: PNode; var r: TCompRes);
+var
+  a: TCompRes;
+begin
+  if p.procDef = nil then InternalError(n.info, 'genReturnStmt');
+  p.BeforeRetNeeded := true;
+  if (n.sons[0] <> nil) then begin
+    genStmt(p, n.sons[0], a);
+    if a.com <> nil then appf(r.com, '$1;$n', mergeStmt(a));
+  end
+  else genLineDir(p, n, r);
+  finishTryStmt(p, r, p.nestedTryStmts);
+  app(r.com, 'break BeforeRet;' + tnl);
+end;
+
+function genProcBody(var p: TProc; prc: PSym; const r: TCompRes): PRope;
+begin
+  if optStackTrace in prc.options then begin
+    result := ropef(
+      'var F = {procname: $1, prev: framePtr, filename: $2, line: 0};$n' +
+      'framePtr = F;$n',
+      [makeCString(prc.owner.name.s +{&} '.' +{&} prc.name.s),
+      makeCString(toFilename(prc.info))]);
+  end
+  else
+    result := nil;
+  if p.beforeRetNeeded then
+    appf(result, 'BeforeRet: do {$n$1} while (false); $n', [mergeStmt(r)])
+  else
+    app(result, mergeStmt(r));
+  if prc.typ.callConv = ccSysCall then begin
+    result := ropef('try {$n$1} catch (e) {$n'+
+                    ' alert("Unhandled exception:\n" + e.message + "\n"$n}',
+                    [result]);
+  end;
+  if optStackTrace in prc.options then
+    app(result, 'framePtr = framePtr.prev;' + tnl);
+end;
+
+procedure genProc(var oldProc: TProc; n: PNode; var r: TCompRes);
+var
+  p: TProc;
+  prc, resultSym: PSym;
+  name, returnStmt, resultAsgn, header: PRope;
+  a: TCompRes;
+begin
+  prc := n.sons[namePos].sym;
+  initProc(p, oldProc.globals, oldProc.module, n, prc.options);
+  returnStmt := nil;
+  resultAsgn := nil;
+  name := mangleName(prc);
+  header := generateHeader(p, prc.typ);
+  if (prc.typ.sons[0] <> nil) and not (sfPure in prc.flags) then begin
+    resultSym := n.sons[resultPos].sym;
+    resultAsgn := ropef('var $1 = $2;$n', [mangleName(resultSym),
+      createVar(p, resultSym.typ, isIndirect(resultSym))]);
+    gen(p, n.sons[resultPos], a);
+    if a.com <> nil then appf(returnStmt, '$1;$n', [a.com]);
+    returnStmt := ropef('return $1;$n', [a.res]);
+  end;
+  genStmt(p, n.sons[codePos], r);
+  r.com := ropef('function $1($2) {$n$3$4$5}$n',
+           [name, header, resultAsgn, genProcBody(p, prc, r), returnStmt]);
+  r.res := nil;
+end;
+
+procedure genStmtListExpr(var p: TProc; n: PNode; var r: TCompRes);
+var
+  i: int;
+  a: TCompRes;
+begin
+  // watch out this trick: ``function () { stmtList; return expr; }()``
+  r.res := toRope('function () {');
+  for i := 0 to sonsLen(n)-2 do begin
+    genStmt(p, n.sons[i], a);
+    app(r.res, mergeStmt(a));
+  end;
+  gen(p, lastSon(n), a);
+  if a.com <> nil then appf(r.res, '$1;$n', [a.com]);
+  appf(r.res, 'return $1; }()', [a.res]);
+end;
+
+procedure genStmt(var p: TProc; n: PNode; var r: TCompRes);
+var
+  prc: PSym;
+  i: int;
+  a: TCompRes;
+begin
+  r.kind := etyNone;
+  r.com := nil;
+  r.res := nil;
+  case n.kind of
+    nkNilLit: begin end;
+    nkStmtList: begin
+      for i := 0 to sonsLen(n)-1 do begin
+        genStmt(p, n.sons[i], a);
+        app(r.com, mergeStmt(a));
+      end
+    end;
+    nkBlockStmt:   genBlock(p, n, r);
+    nkIfStmt:      genIfStmt(p, n, r);
+    nkWhileStmt:   genWhileStmt(p, n, r);
+    nkVarSection:  genVarStmt(p, n, r);
+    nkConstSection: genConstStmt(p, n, r);
+    nkForStmt:     internalError(n.info, 'for statement not eliminated');
+    nkCaseStmt:    genCaseStmt(p, n, r);
+    nkReturnStmt:  genReturnStmt(p, n, r);
+    nkBreakStmt:   genBreakStmt(p, n, r);
+    nkAsgn:        genAsgn(p, n, r);
+    nkDiscardStmt: begin
+      genLineDir(p, n, r);
+      gen(p, n.sons[0], r);
+      app(r.res, ';'+ tnl);
+    end;
+    nkAsmStmt: genAsmStmt(p, n, r);
+    nkTryStmt: genTryStmt(p, n, r);
+    nkRaiseStmt: genRaiseStmt(p, n, r);
+    nkTypeSection, nkCommentStmt, nkIteratorDef,
+    nkIncludeStmt, nkImportStmt,
+    nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: begin end;
+    nkProcDef, nkConverterDef: begin
+      if (n.sons[genericParamsPos] = nil) then begin
+        prc := n.sons[namePos].sym;
+        if (n.sons[codePos] <> nil) and not (lfNoDecl in prc.loc.flags) then
+          genProc(p, n, r)
+        else
+          {@discard} mangleName(prc);
+      end
+    end;
+    else begin
+      genLineDir(p, n, r);
+      gen(p, n, r);
+      app(r.res, ';'+ tnl);
+    end
+  end
+end;
+
+procedure gen(var p: TProc; n: PNode; var r: TCompRes);
+var
+  f: BiggestFloat;
+begin
+  r.kind := etyNone;
+  r.com := nil;
+  r.res := nil;
+  case n.kind of
+    nkSym: genSym(p, n, r);
+    nkCharLit..nkInt64Lit: begin
+      r.res := toRope(n.intVal);
+    end;
+    nkNilLit: begin
+      if mapType(n.typ) = etyBaseIndex then begin
+        r.kind := etyBaseIndex;
+        r.com := toRope('null');
+        r.res := toRope('0'+'');
+      end
+      else
+        r.res := toRope('null');
+    end;
+    nkStrLit..nkTripleStrLit: begin
+      if skipVarGenericRange(n.typ).kind = tyString then begin
+        useMagic(p, 'cstrToNimstr');
+        r.res := ropef('cstrToNimstr($1)', [makeCString(n.strVal)])
+      end
+      else
+        r.res := makeCString(n.strVal)
+    end;
+    nkFloatLit..nkFloat64Lit: begin
+      f := n.floatVal;
+      if f <> f then
+        r.res := toRope('NaN')
+      else if f = 0.0 then
+        r.res := toRopeF(f)
+      else if f = 0.5 * f then
+        if f > 0.0 then r.res := toRope('Infinity')
+        else r.res := toRope('-Infinity')
+      else
+        r.res := toRopeF(f);
+    end;
+    nkBlockExpr: genBlock(p, n, r);
+    nkIfExpr: genIfExpr(p, n, r);
+    nkCall, nkHiddenCallConv: begin
+      if (n.sons[0].kind = nkSym) and (n.sons[0].sym.magic <> mNone) then
+        genMagic(p, n, r)
+      else
+        genCall(p, n, r)
+    end;
+    nkCurly: genSetConstr(p, n, r);
+    nkBracket: genArrayConstr(p, n, r);
+    nkPar: genRecordConstr(p, n, r);
+    nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r);
+    nkAddr, nkHiddenAddr: genAddr(p, n, r);
+    nkDerefExpr, nkHiddenDeref: genDeref(p, n, r);
+    nkBracketExpr: genArrayAccess(p, n, r);
+    nkDotExpr: genFieldAccess(p, n, r);
+    nkCheckedFieldExpr: genCheckedFieldAccess(p, n, r);
+    nkObjDownConv: gen(p, n.sons[0], r);
+    nkObjUpConv: upConv(p, n, r);
+    nkChckRangeF: genRangeChck(p, n, r, 'chckRangeF');
+    nkChckRange64: genRangeChck(p, n, r, 'chckRange64');
+    nkChckRange: genRangeChck(p, n, r, 'chckRange');
+    nkStringToCString: convStrToCStr(p, n, r);
+    nkCStringToString: convCStrToStr(p, n, r);
+    nkPassAsOpenArray: gen(p, n.sons[0], r);
+    nkStmtListExpr: genStmtListExpr(p, n, r);
+    else
+      InternalError(n.info, 'gen: unknown node type: ' + nodekindToStr[n.kind])
+  end
+end;
+
+// ------------------------------------------------------------------------
+
+var
+  globals: PGlobals;
+
+function newModule(module: PSym; const filename: string): BModule;
+begin
+  new(result);
+{@ignore}
+  fillChar(result^, sizeof(result^), 0);
+{@emit}
+  result.filename := filename;
+  result.module := module;
+  if globals = nil then globals := newGlobals();
+end;
+
+function genHeader(): PRope;
+begin
+  result := ropef(
+    '/* Generated by the Nimrod Compiler v$1 */$n' +
+    '/*   (c) 2008 Andreas Rumpf */$n$n' +
+    '$nvar Globals = this;$n' +
+    'var framePtr = null;$n' +
+    'var excHandler = null;$n',
+    [toRope(versionAsString)])
+end;
+
+procedure genModule(var p: TProc; n: PNode; var r: TCompRes);
+begin
+  genStmt(p, n, r);
+  if optStackTrace in p.options then begin
+    r.com := ropef(
+      'var F = {procname: $1, prev: framePtr, filename: $2, line: 0};$n' +
+      'framePtr = F;$n' +
+      '$3' +
+      'framePtr = framePtr.prev;$n',
+      [makeCString('module ' + p.module.module.name.s),
+      makeCString(toFilename(p.module.module.info)), r.com])
+  end
+end;
+
+procedure finishModule(b: PBackend; n: PNode);
+var
+  m: BModule;
+  outfile: string;
+  p: TProc;
+  r: TCompRes;
+  code: PRope;
+begin
+  m := BModule(b);
+  if m.module = nil then InternalError(n.info, 'finishModule');
+  initProc(p, globals, m, nil, m.module.options);
+  genModule(p, n, r);
+  app(p.globals.code, p.data);
+  app(p.globals.code, mergeStmt(r));
+  if sfMainModule in m.module.flags then begin
+    // write the file:
+    code := con(p.globals.typeInfo, p.globals.code);
+    outfile := changeFileExt(completeCFilePath(m.filename), 'js');
+    {@discard} writeRopeIfNotEqual(con(genHeader(), code), outfile);
+  end;
+end;
+
+function EcmasBackend(b: PBackend; module: PSym;
+                      const filename: string): PBackend;
+var
+  g: BModule;
+begin
+  g := newModule(module, filename);
+  g.backendCreator := EcmasBackend;
+  g.eventMask := {@set}[eAfterModule];
+  g.afterModuleEvent := finishModule;
+  result := g;
+end;
+
+end.
diff --git a/nim/eval.pas b/nim/eval.pas
index 3f9d60b7a..501667c80 100644
--- a/nim/eval.pas
+++ b/nim/eval.pas
@@ -13,138 +13,293 @@
 // stuff at compile time, performance is not that
 // important. Later a real interpreter may get out of this...
 
+// We reuse the TTranscon type here::
+//
+//  TTransCon = record      # part of TContext; stackable
+//    mapping: TIdNodeTable # mapping from symbols to nodes
+//    owner: PSym           # current owner; proc that is evaluated
+//    forStmt: PNode        # unused
+//    next: PTransCon       # for stacking; up the call stack
+
+const
+  evalMaxIterations = 10000000; // max iterations of all loops
+  evalMaxRecDepth = 100000;     // max recursion depth for evaluation
+
 type
-  PBinding = ^TBinding;
-  TBinding = record
-    up: PBinding; // call stack
-    tab: TIdNodeTable; // maps syms to nodes
-    procname: PIdent;
-    info: TLineInfo;
-  end;
+  PBinding = PContext;
+  PCallStack = PTransCon;
 
 var
   emptyNode: PNode;
+
+function evalAux(c: PContext; n: PNode): PNode; forward;
   
-procedure stackTraceAux(x: PBinding);
+procedure stackTraceAux(x: PCallStack);
 begin
   if x <> nil then begin
-    stackTraceAux(x.up);
-    messageOut(format('$1 called at line $2 file $3',
-                      [x.procname.s, toLinenumber(info), ToFilename(info)]));
+    stackTraceAux(x.next);
+    messageOut(format('file: $1, line: $2', [toFilename(x.forStmt.info),
+                    toString(toLineNumber(x.forStmt.info))]));
   end
 end;
 
 procedure stackTrace(c: PBinding; n: PNode; msg: TMsgKind;
                      const arg: string = '');
-var
-  x: PBinding;
 begin
-  x := c;
-  messageOut('stack trace: (most recent call last)') 
-  stackTraceAux(c);
+  messageOut('stack trace: (most recent call last)');
+  stackTraceAux(c.transCon);
   liMessage(n.info, msg, arg);
 end;
 
-function eval(c: PBinding; n: PNode): PNode; forward;
-// eval never returns nil! This simplifies the code a lot and
-// makes it faster too.
-
-function evalSym(c: PBinding; sym: PSym): PNode;
-// We need to return a node to the actual value,
-// which can be modified.
-var
-  x: PBinding;
-begin
-  x := c;
-  while x <> nil do begin
-    result := IdNodeTableGet(x.tab, sym);
-    if result <> nil then exit;
-    x := x.up
-  end;
-  result := emptyNode;
-end;
-
 function evalIf(c: PBinding; n: PNode): PNode;
 var
-  i: int;
-  res: PNode;
+  i, len: int;
 begin
   i := 0;
   len := sonsLen(n);
   while (i < len) and (sonsLen(n.sons[i]) >= 2) do begin
-    res := eval(c, n.sons[i].sons[0]);
-    if (res.kind = nkIntLit) and (res.intVal <> 0) then begin
-      result := eval(c, n.sons[i].sons[1]); exit
+    result := evalAux(c, n.sons[i].sons[0]);
+    if result.kind = nkExceptBranch then exit;
+    if (result.kind = nkIntLit) and (result.intVal <> 0) then begin
+      result := evalAux(c, n.sons[i].sons[1]); 
+      exit
     end;
     inc(i)
   end;
   if (i < len) and (sonsLen(n.sons[i]) < 2) then // eval else-part
-    result := eval(c, n.sons[0])
+    result := evalAux(c, n.sons[0])
   else
     result := emptyNode
 end;
 
+function evalCase(c: PBinding; n: PNode): PNode;
+var
+  i, j: int;
+  res: PNode;
+begin
+  result := evalAux(c, n.sons[0]);
+  if result.kind = nkExceptBranch then exit;
+  res := result;
+  result := emptyNode;
+  for i := 1 to sonsLen(n)-1 do begin
+    if n.sons[i].kind = nkOfBranch then begin
+      for j := 0 to sonsLen(n.sons[i])-2 do begin
+        if overlap(res, n.sons[i].sons[j]) then begin
+          result := evalAux(c, lastSon(n.sons[i]));
+          exit
+        end
+      end
+    end
+    else begin
+      result := evalAux(c, lastSon(n.sons[i]));
+    end  
+  end;
+end;
+
 var 
   gWhileCounter: int;  // Use a counter to prevend 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
+                       // endless recursion
 
 function evalWhile(c: PBinding; n: PNode): PNode;
-var
-  res: PNode;
 begin
-  result := emptyNode;
   while true do begin
-    res := eval(c, n.sons[0]);
-    if getOrdValue(res) = 0 then break;
-    result := eval(c, n.sons[1]);
-    inc(gWhileCounter);
-    if gWhileCounter > 10000000 then begin
+    result := evalAux(c, n.sons[0]);
+    if result.kind = nkExceptBranch then exit;
+    if getOrdValue(result) = 0 then break;
+    result := evalAux(c, n.sons[1]);
+    case result.kind of
+      nkBreakStmt: begin
+        if result.sons[0] = nil then begin
+          result := emptyNode; // consume ``break`` token
+          break
+        end
+      end;
+      nkExceptBranch, nkReturnToken: break;
+      else begin end
+    end;
+    dec(gWhileCounter);
+    if gWhileCounter <= 0 then begin
       stackTrace(c, n, errTooManyIterations);
       break;
     end
   end
 end;
 
+function evalBlock(c: PBinding; n: PNode): PNode;
+begin
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkBreakStmt then begin
+    if result.sons[0] <> nil then begin
+      assert(result.sons[0].kind = nkSym);
+      if n.sons[0] <> nil then begin
+        assert(n.sons[0].kind = nkSym);
+        if result.sons[0].sym.id = n.sons[0].sym.id then 
+          result := emptyNode
+      end
+    end
+    else 
+      result := emptyNode // consume ``break`` token
+  end
+end;
+
+function evalFinally(c: PBinding; n, exc: PNode): PNode;
+var
+  finallyNode: PNode;
+begin
+  finallyNode := lastSon(n);
+  if finallyNode.kind = nkFinally then begin
+    result := evalAux(c, finallyNode);
+    if result.kind <> nkExceptBranch then
+      result := exc
+  end
+  else
+    result := exc
+end;
+
+function evalTry(c: PBinding; n: PNode): PNode;
+var
+  exc: PNode;
+  i, j, len, blen: int;
+begin
+  result := evalAux(c, n.sons[0]);
+  case result.kind of 
+    nkBreakStmt, nkReturnToken: begin end;
+    nkExceptBranch: begin
+      // exception token!
+      exc := result;
+      i := 1;
+      len := sonsLen(n);
+      while (i < len) and (n.sons[i].kind = nkExceptBranch) do begin
+        blen := sonsLen(n.sons[i]);
+        if blen = 1 then begin
+          // general except section:
+          result := evalAux(c, n.sons[i].sons[0]);
+          exc := result;
+          break
+        end
+        else begin
+          for j := 0 to blen-2 do begin
+            assert(n.sons[i].sons[j].kind = nkType);
+            if exc.typ.id = n.sons[i].sons[j].typ.id then begin
+              result := evalAux(c, n.sons[i].sons[blen-1]);
+              exc := result;
+              break
+            end
+          end
+        end;
+        inc(i);
+      end;
+      result := evalFinally(c, n, exc);
+    end;
+    else 
+      result := evalFinally(c, n, emptyNode);
+  end
+end;
+
+function getNullValue(typ: PType; const info: TLineInfo): PNode;
+var
+  i: int;
+  t: PType;
+begin
+  t := skipGenericRange(typ);
+  result := emptyNode;
+  case t.kind of 
+    tyBool, tyChar, tyInt..tyInt64: result := newNodeIT(nkIntLit, info, t);
+    tyFloat..tyFloat128: result := newNodeIt(nkFloatLit, info, t);
+    tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString: 
+      result := newNodeIT(nkNilLit, info, t);
+    tyObject: begin
+      result := newNodeIT(nkPar, info, t);
+      internalError(info, 'init to implement');
+    end;
+    tyArray, tyArrayConstr: begin
+      result := newNodeIT(nkBracket, info, t);
+      for i := 0 to int(lengthOrd(t))-1 do 
+        addSon(result, getNullValue(elemType(t), info));
+    end;
+    tyTuple: begin
+      result := newNodeIT(nkPar, info, t);
+      for i := 0 to sonsLen(t)-1 do 
+        addSon(result, getNullValue(t.sons[i], info));    
+    end;
+    else InternalError('getNullValue')
+  end
+end;
+
+function evalVar(c: PBinding; n: PNode): PNode;
+var
+  i: int;
+  v: PSym;
+  a: PNode;
+begin
+  for i := 0 to sonsLen(n)-1 do begin
+    a := n.sons[i];
+    if a.kind = nkCommentStmt then continue;
+    assert(a.kind = nkIdentDefs);
+    assert(a.sons[0].kind = nkSym);
+    v := a.sons[0].sym;
+    if a.sons[2] <> nil then begin
+      result := evalAux(c, a.sons[2]);
+      if result.kind = nkExceptBranch then exit;
+    end
+    else 
+      result := getNullValue(a.sons[0].typ, a.sons[0].info);
+    IdNodeTablePut(c.transCon.mapping, v, result);
+  end;
+  result := emptyNode;
+end;
+
 function evalCall(c: PBinding; n: PNode): PNode;
 var
-  d: PBinding;
+  d: PCallStack;
   prc: PNode;
-  op: PSym
+  i: int;
 begin
-  prc := eval(c, n.sons[0]);
-  assert(prc.kind = nkSym);
-  assert(prc.sym.kind in [skIterator, skProc, skConverter]);
-  op := prc.sym;
+  result := evalAux(c, n.sons[0]);
+  if result.kind = nkExceptBranch then exit;
+  prc := result;
   // bind the actual params to the local parameter
   // of a new binding
-  d := newBinding(c, n.info);
-  for i := 0 to sonsLen(op.typ.n)-1 do
-    addSym(d.tab, op.typ.n.sons[i].sym, n.sons[i+1]);
-  result := eval(d, op.ast[codePos]);
+  d := newTransCon();
+  d.forStmt := n;
+  if prc.kind = nkSym then begin
+    d.owner := prc.sym;
+    if not (prc.sym.kind in [skProc, skConverter]) then 
+      InternalError(n.info, 'evalCall');
+  end;
+  setLength(d.params, sonsLen(n));
+  for i := 1 to sonsLen(n)-1 do begin
+    result := evalAux(c, n.sons[i]);
+    if result.kind = nkExceptBranch then exit;
+    d.params[i] := result;
+  end;
+  if n.typ <> nil then d.params[0] := getNullValue(n.typ, n.info);
+  pushTransCon(c, d);
+  result := evalAux(c, prc);
+  if n.typ <> nil then result := d.params[0];
+  popTransCon(c);
 end;
 
-function evalAsgn(c: PBinding; n: PNode): PNode;
+function evalVariable(c: PCallStack; sym: PSym): PNode;
+// We need to return a node to the actual value,
+// which can be modified.
 var
-  x, y: PNode;
+  x: PCallStack;
 begin
-  x := eval(c, n.sons[0]);
-  y := eval(c, n.sons[1]);
-  if (x.kind <> y.kind) then
-    stackTrace(c, n, errInvalidAsgn)
-  else begin
-    case x.kind of
-      nkCharLit..nkInt64Lit: x.intVal := y.intVal;
-      nkFloatLit..nkFloat64Lit: x.floatVal := y.floatVal;
-      nkStrLit..nkTripleStrLit: x.strVal := y.strVal;
-      else begin
-        discardSons(x);
-        for i := 0 to sonsLen(y)-1 do
-          addSon(x, y.sons[i]);
-      end
-    end
+  x := c;
+  while x <> nil do begin
+    if sfResult in sym.flags then begin
+      result := x.params[0];
+      exit
+    end;
+    result := IdNodeTableGet(x.mapping, sym);
+    if result <> nil then exit;
+    x := x.next
   end;
-  result := y
+  result := emptyNode;
 end;
 
 function evalArrayAccess(c: PBinding; n: PNode): PNode;
@@ -152,140 +307,871 @@ var
   x: PNode;
   idx: biggestInt;
 begin
-  x := eval(c, n.sons[0]);
-  idx := getOrdValue(eval(c, n.sons[1]));
+  result := evalAux(c, n.sons[0]);
+  if result.kind = nkExceptBranch then exit;
+  x := result;
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkExceptBranch then exit;
+  idx := getOrdValue(result);
   result := emptyNode;
   case x.kind of 
-    nkArrayConstr, nkPar: begin
+    nkBracket, nkPar, nkMetaNode: begin
       if (idx >= 0) and (idx < sonsLen(x)) then
-        result := x.sons[indx]
+        result := x.sons[int(idx)]
       else
-        stackTrace(c, n, errInvalidIndex);
+        stackTrace(c, n, errIndexOutOfBounds);
     end;
     nkStrLit..nkTripleStrLit: begin
-      if (idx >= 0) and (idx < length(x.strLit)) then
-        result := newCharNode(x.strLit[indx+strStart])
-      else if idx = length(x.strLit) then
-        result := newCharNode(#0)
+      result := newNodeIT(nkCharLit, x.info, getSysType(tyChar));
+      if (idx >= 0) and (idx < length(x.strVal)) then
+        result.intVal := ord(x.strVal[int(idx)+strStart])
+      else if idx = length(x.strVal) then begin end
       else
-        stackTrace(c, n, errInvalidIndex);
-    end
+        stackTrace(c, n, errIndexOutOfBounds);
+    end;
     else
-      stackTrace(c, n, errInvalidOp);
+      stackTrace(c, n, errIndexNoIntType);
   end
 end;
 
 function evalFieldAccess(c: PBinding; n: PNode): PNode;
 // a real field access; proc calls have already been
 // transformed
+// XXX: field checks!
 var
   x: PNode;
   field: PSym;
+  i: int;
 begin
-  x := eval(c, n.sons[0]);
+  result := evalAux(c, n.sons[0]);
+  if result.kind = nkExceptBranch then exit;
+  x := result;
+  if x.kind <> nkPar then InternalError(n.info, 'evalFieldAccess');
   field := n.sons[1].sym;
-  for i := 0 to sonsLen(n)-1 do
+  for i := 0 to sonsLen(n)-1 do begin
+    if x.sons[i].kind <> nkExprColonExpr then 
+      InternalError(n.info, 'evalFieldAccess');
     if x.sons[i].sons[0].sym.name.id = field.id then begin
       result := x.sons[i].sons[1]; exit
+    end
+  end;
+  stackTrace(c, n, errFieldXNotFound, field.name.s);
+  result := emptyNode;
+end;
+
+function evalAsgn(c: PBinding; n: PNode): PNode;
+var
+  x: PNode;
+  i: int;
+begin
+  result := evalAux(c, n.sons[0]);
+  if result.kind = nkExceptBranch then exit;
+  x := result;
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkExceptBranch then exit;
+  x.kind := result.kind;
+  x.typ := result.typ; 
+  case x.kind of
+    nkCharLit..nkInt64Lit: x.intVal := result.intVal;
+    nkFloatLit..nkFloat64Lit: x.floatVal := result.floatVal;
+    nkStrLit..nkTripleStrLit: begin
+      x.strVal := result.strVal;
+    end
+    else begin
+      if not (x.kind in [nkEmpty..nkNilLit]) then begin
+        discardSons(x);
+        for i := 0 to sonsLen(result)-1 do addSon(x, result.sons[i]);
+      end
+    end
+  end;
+  result := emptyNode
+end;
+
+function evalSwap(c: PBinding; n: PNode): PNode;
+var
+  x: PNode;
+  i: int;
+  tmpi: biggestInt;
+  tmpf: biggestFloat;
+  tmps: string;
+  tmpn: PNode;
+begin
+  result := evalAux(c, n.sons[0]);
+  if result.kind = nkExceptBranch then exit;
+  x := result;
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkExceptBranch then exit;
+  if (x.kind <> result.kind) then
+    stackTrace(c, n, errCannotInterpretNodeX, nodeKindToStr[n.kind])
+  else begin
+    case x.kind of
+      nkCharLit..nkInt64Lit: begin
+        tmpi := x.intVal;
+        x.intVal := result.intVal;
+        result.intVal := tmpi
+      end;
+      nkFloatLit..nkFloat64Lit: begin
+        tmpf := x.floatVal;
+        x.floatVal := result.floatVal;
+        result.floatVal := tmpf;
+      end;
+      nkStrLit..nkTripleStrLit: begin
+        tmps := x.strVal;
+        x.strVal := result.strVal;
+        result.strVal := tmps;
+      end
+      else begin
+        tmpn := copyTree(x);
+        discardSons(x);
+        for i := 0 to sonsLen(result)-1 do
+          addSon(x, result.sons[i]);
+        discardSons(result);
+        for i := 0 to sonsLen(tmpn)-1 do
+          addSon(result, tmpn.sons[i]);
+      end
+    end
+  end;
+  result := emptyNode
+end;
+
+function evalSym(c: PBinding; n: PNode): PNode;
+begin
+  case n.sym.kind of 
+    skProc, skConverter, skMacro: result := n.sym.ast.sons[codePos];
+    skVar, skForVar, skTemp: result := evalVariable(c.transCon, n.sym);
+    skParam: result := c.transCon.params[n.sym.position+1];
+    skConst: result := n.sym.ast;
+    else begin
+      stackTrace(c, n, errCannotInterpretNodeX, symKindToStr[n.sym.kind]);
+      result := emptyNode
+    end
+  end;
+  if result = nil then InternalError(n.info, 'evalSym: ' + n.sym.name.s);
+end;
+
+function evalIncDec(c: PBinding; n: PNode; sign: biggestInt): PNode;
+var
+  a, b: PNode;
+begin
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkExceptBranch then exit;
+  a := result;
+  result := evalAux(c, n.sons[2]);
+  if result.kind = nkExceptBranch then exit;
+  b := result;
+  case a.kind of
+    nkCharLit..nkInt64Lit: a.intval := a.intVal + sign * getOrdValue(b);
+    else internalError(n.info, 'evalIncDec');  
+  end;
+  result := emptyNode
+end;
+
+function evalExit(c: PBinding; n: PNode): PNode;
+begin
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkExceptBranch then exit;
+  liMessage(n.info, hintQuitCalled);
+  halt(int(getOrdValue(result)));
+end;
+
+function evalOr(c: PBinding; n: PNode): PNode;
+begin
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkExceptBranch then exit;
+  if result.kind <> nkIntLit then InternalError(n.info, 'evalOr');
+  if result.intVal = 0 then result := evalAux(c, n.sons[2])
+end;
+
+function evalAnd(c: PBinding; n: PNode): PNode;
+begin
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkExceptBranch then exit;
+  if result.kind <> nkIntLit then InternalError(n.info, 'evalAnd');
+  if result.intVal <> 0 then result := evalAux(c, n.sons[2])
+end;
+
+function evalNew(c: PBinding; n: PNode): PNode;
+var
+  t: PType;
+begin
+  t := skipVarGeneric(n.sons[1].typ);
+  result := newNodeIT(nkRefTy, n.info, t);
+  addSon(result, getNullValue(t.sons[0], n.info));
+end;
+
+function evalDeref(c: PBinding; 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];
+end;
+
+function evalAddr(c: PBinding; n: PNode): PNode;
+var
+  a: PNode;
+begin
+  result := evalAux(c, n.sons[0]);
+  if result.kind = nkExceptBranch then exit;
+  if result.kind <> nkRefTy then InternalError(n.info, 'evalDeref');
+  a := result;
+  result := newNodeIT(nkRefTy, n.info, makePtrType(c, a.typ));
+  addSon(result, a);
+end;
+
+function evalConv(c: PBinding; n: PNode): PNode;
+begin
+  // hm, I cannot think of any conversions that need to be handled here...
+  result := evalAux(c, n.sons[1]);
+  result.typ := n.typ;
+end;
+
+function evalCheckedFieldAccess(c: PBinding; n: PNode): PNode;
+begin
+  result := evalAux(c, n.sons[0]);
+end;
+
+function evalUpConv(c: PBinding; n: PNode): PNode;
+var
+  dest, src: PType;
+begin
+  result := evalAux(c, n.sons[0]);
+  if result.kind = nkExceptBranch then exit;
+  dest := skipPtrsGeneric(n.typ);
+  src := skipPtrsGeneric(result.typ);
+  if inheritanceDiff(src, dest) > 0 then 
+    stackTrace(c, n, errInvalidConversionFromTypeX, typeToString(src));  
+end;
+
+function evalRangeChck(c: PBinding; n: PNode): PNode;
+var
+  x, a, b: PNode;
+begin
+  result := evalAux(c, n.sons[0]);
+  if result.kind = nkExceptBranch then exit;
+  x := result; 
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkExceptBranch then exit;
+  a := result; 
+  result := evalAux(c, n.sons[2]);
+  if result.kind = nkExceptBranch then exit;
+  b := result; 
+
+  if leValueConv(a, x) and leValueConv(x, b) then begin
+    result := x; // a <= x and x <= b
+    result.typ := n.typ
+  end
+  else
+    stackTrace(c, n, errGenerated,
+      format(msgKindToString(errIllegalConvFromXtoY),
+        [typeToString(n.sons[0].typ), typeToString(n.typ)]));  
+end;
+
+function evalConvStrToCStr(c: PBinding; n: PNode): PNode;
+begin
+  result := evalAux(c, n.sons[0]);
+  if result.kind = nkExceptBranch then exit;
+  result.typ := n.typ;
+end;
+
+function evalConvCStrToStr(c: PBinding; n: PNode): PNode;
+begin
+  result := evalAux(c, n.sons[0]);
+  if result.kind = nkExceptBranch then exit;
+  result.typ := n.typ;
+end;
+
+function evalRaise(c: PBinding; n: PNode): PNode;
+var
+  a: PNode;
+begin
+  if n.sons[0] <> nil then begin
+    result := evalAux(c, n.sons[0]);
+    if result.kind = nkExceptBranch then exit;
+    a := result;
+    result := newNodeIT(nkExceptBranch, n.info, a.typ);
+    addSon(result, a);
+    c.lastException := result;
+  end
+  else if c.lastException <> nil then 
+    result := c.lastException
+  else begin
+    stackTrace(c, n, errExceptionAlreadyHandled);
+    result := newNodeIT(nkExceptBranch, n.info, nil);
+    addSon(result, nil);
+  end
+end;
+
+function evalReturn(c: PBinding; n: PNode): PNode;
+begin
+  if n.sons[0] <> nil then begin
+    result := evalAsgn(c, n.sons[0]);
+    if result.kind = nkExceptBranch then exit;
+  end;
+  result := newNodeIT(nkReturnToken, n.info, nil);
+end;
+
+function evalProc(c: PBinding; n: PNode): PNode;
+var
+  v: PSym;
+begin
+  if n.sons[genericParamsPos] = nil then begin
+    if (resultPos < sonsLen(n)) and (n.sons[resultPos] <> nil) then begin
+      v := n.sons[resultPos].sym;
+      result := getNullValue(v.typ, n.info);
+      IdNodeTablePut(c.transCon.mapping, v, result);
     end;
-  stackTrace(c, n, errFieldNotFound, field.name.s);
+    result := evalAux(c, transform(c, n.sons[codePos]));
+    if result.kind = nkReturnToken then 
+      result := IdNodeTableGet(c.transCon.mapping, v);
+  end
+  else
+    result := emptyNode
+end;
+
+function evalHigh(c: PBinding; n: PNode): PNode;
+begin
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkExceptBranch then exit;
+  case skipVarGeneric(n.sons[1].typ).kind of
+    tyOpenArray, tySequence:
+      result := newIntNodeT(sonsLen(result), n);
+    tyString:
+      result := newIntNodeT(length(result.strVal)-1, n);
+    else InternalError(n.info, 'evalHigh')
+  end
+end;
+
+function evalSetLengthStr(c: PBinding; n: PNode): PNode;
+var
+  a, b: PNode;
+begin
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkExceptBranch then exit;
+  a := result;
+  result := evalAux(c, n.sons[2]);
+  if result.kind = nkExceptBranch then exit;
+  b := result;
+  case a.kind of 
+    nkStrLit..nkTripleStrLit: setLength(a.strVal, int(getOrdValue(b)));
+    else InternalError(n.info, 'evalSetLengthStr')
+  end;
+  result := emptyNode
+end;
+
+function evalSetLengthSeq(c: PBinding; n: PNode): PNode;
+var
+  a, b: PNode;
+begin
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkExceptBranch then exit;
+  a := result;
+  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');
+  result := emptyNode
+end;
+
+function evalAssert(c: PBinding; n: PNode): PNode;
+begin
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkExceptBranch then exit;
+  if getOrdValue(result) <> 0 then 
+    result := emptyNode
+  else
+    stackTrace(c, n, errAssertionFailed)
+end;
+
+function evalIncl(c: PBinding; n: PNode): PNode;
+var
+  a, b: PNode;
+begin
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkExceptBranch then exit;
+  a := result;
+  result := evalAux(c, n.sons[2]);
+  if result.kind = nkExceptBranch then exit;
+  b := result;
+  if not inSet(a, b) then addSon(a, copyTree(b));
+  result := emptyNode;
+end;
+
+function evalExcl(c: PBinding; n: PNode): PNode;
+var
+  a, b, r: PNode;
+  i: int;
+begin
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkExceptBranch then exit;
+  a := result;
+  result := evalAux(c, n.sons[2]);
+  if result.kind = nkExceptBranch then exit;
+  b := newNodeIT(nkCurly, n.info, n.sons[1].typ);
+  addSon(b, result);
+  r := diffSets(a, b);
+  discardSons(a);
+  for i := 0 to sonsLen(r)-1 do addSon(a, r.sons[i]);
+  result := emptyNode;
+end;
+
+function evalAppendStrCh(c: PBinding; n: PNode): PNode;
+var
+  a, b: PNode;
+begin
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkExceptBranch then exit;
+  a := result;
+  result := evalAux(c, n.sons[2]);
+  if result.kind = nkExceptBranch then exit;
+  b := result;
+  case a.kind of
+    nkStrLit..nkTripleStrLit: addChar(a.strVal, chr(int(getOrdValue(b))));
+    else InternalError(n.info, 'evalAppendStrCh');
+  end;
+  result := emptyNode;
+end;
+
+function getStrValue(n: PNode): string;
+begin
+  case n.kind of
+    nkStrLit..nkTripleStrLit: result := n.strVal;
+    else begin InternalError(n.info, 'getStrValue'); result := '' end;
+  end
+end;
+
+function evalAppendStrStr(c: PBinding; n: PNode): PNode;
+var
+  a, b: PNode;
+begin
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkExceptBranch then exit;
+  a := result;
+  result := evalAux(c, n.sons[2]);
+  if result.kind = nkExceptBranch then exit;
+  b := result;
+  case a.kind of
+    nkStrLit..nkTripleStrLit: a.strVal := a.strVal +{&} getStrValue(b);
+    else InternalError(n.info, 'evalAppendStrStr');
+  end;
+  result := emptyNode;
+end;
+
+function evalAppendSeqElem(c: PBinding; n: PNode): PNode;
+var
+  a, b: PNode;
+begin
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkExceptBranch then exit;
+  a := result;
+  result := evalAux(c, n.sons[2]);
+  if result.kind = nkExceptBranch then exit;
+  b := result;
+  if a.kind = nkBracket then addSon(a, copyTree(b))
+  else InternalError(n.info, 'evalAppendSeqElem');
   result := emptyNode;
 end;
 
-function eval(c: PBinding; n: PNode): PNode;
+function evalAppendSeqSeq(c: PBinding; n: PNode): PNode;
+var
+  a, b: PNode;
+  i: int;
+begin
+  result := evalAux(c, n.sons[1]);
+  if result.kind = nkExceptBranch then exit;
+  a := result;
+  result := evalAux(c, n.sons[2]);
+  if result.kind = nkExceptBranch then exit;
+  b := result;
+  if a.kind = nkBracket then
+    for i := 0 to sonsLen(b)-1 do addSon(a, copyTree(b.sons[i]))
+  else InternalError(n.info, 'evalAppendSeqSeq');
+  result := emptyNode;
+end;
+
+function evalMagicOrCall(c: PBinding; n: PNode): PNode;
 var
   m: TMagic;
-  b: PNode;
+  a, b: PNode;
+  k: biggestInt;
+  i: int;
+begin
+  m := getMagic(n);
+  case m of
+    mNone: result := evalCall(c, n);
+    mSizeOf: internalError(n.info, 'sizeof() should have been evaluated');
+    mHigh: result := evalHigh(c, n);
+    mAssert: result := evalAssert(c, n);
+    mExit: result := evalExit(c, n);
+    mNew, mNewFinalize: result := evalNew(c, n);
+    mSwap: result := evalSwap(c, n);
+    mInc: result := evalIncDec(c, n, 1);
+    ast.mDec: result := evalIncDec(c, n, -1);
+    mSetLengthStr: result := evalSetLengthStr(c, n);
+    mSetLengthSeq: result := evalSetLengthSeq(c, n);
+    mIncl: result := evalIncl(c, n);
+    mExcl: result := evalExcl(c, n);
+    mAnd: result := evalAnd(c, n);
+    mOr: result := evalOr(c, n);
+    
+    mAppendStrCh: result := evalAppendStrCh(c, n);
+    mAppendStrStr: result := evalAppendStrStr(c, n);
+    mAppendSeqElem: result := evalAppendSeqElem(c, n);
+    mAppendSeqSeq: result := evalAppendSeqSeq(c, n);
+    
+    mNLen: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      result := newNodeIT(nkIntLit, n.info, n.typ);
+      case a.kind of
+        nkEmpty..nkNilLit: begin end;
+        else result.intVal := sonsLen(a);
+      end
+    end;
+    mNChild: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      result := evalAux(c, n.sons[2]);
+      if result.kind = nkExceptBranch then exit;
+      k := getOrdValue(result);
+      if (k >= 0) and (k < sonsLen(a))
+      and not (a.kind in [nkEmpty..nkNilLit]) then
+        result := a.sons[int(k)]
+      else begin
+        stackTrace(c, n, errIndexOutOfBounds);
+        result := emptyNode
+      end;
+    end;
+    mNSetChild: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      result := evalAux(c, n.sons[2]);
+      if result.kind = nkExceptBranch then exit;
+      b := result;
+      result := evalAux(c, n.sons[3]);
+      if result.kind = nkExceptBranch then exit;
+      k := getOrdValue(b);
+      if (k >= 0) and (k < sonsLen(a))
+      and not (a.kind in [nkEmpty..nkNilLit]) then
+        a.sons[int(k)] := result
+      else
+        stackTrace(c, n, errIndexOutOfBounds);
+      result := emptyNode;
+    end;
+    mNAdd: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      result := evalAux(c, n.sons[2]);
+      if result.kind = nkExceptBranch then exit;
+      addSon(a, result);
+      result := emptyNode
+    end;
+    mNAddMultiple: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      result := evalAux(c, n.sons[2]);
+      if result.kind = nkExceptBranch then exit;
+      for i := 0 to sonsLen(result)-1 do addSon(a, result.sons[i]);
+      result := emptyNode
+    end;
+    mNDel: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      result := evalAux(c, n.sons[2]);
+      if result.kind = nkExceptBranch then exit;
+      b := result;
+      result := evalAux(c, n.sons[3]);
+      if result.kind = nkExceptBranch then exit;
+      for i := 0 to int(getOrdValue(result))-1 do
+        delSon(a, int(getOrdValue(b)));
+      result := emptyNode;
+    end;
+    mNKind: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      result := newNodeIT(nkIntLit, n.info, n.typ);
+      result.intVal := ord(a.kind);
+    end;
+    mNIntVal: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      result := newNodeIT(nkIntLit, n.info, n.typ);
+      case a.kind of
+        nkCharLit..nkInt64Lit: result.intVal := a.intVal;
+        else InternalError(n.info, 'no int value')
+      end
+    end;
+    mNFloatVal: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      result := newNodeIT(nkFloatLit, n.info, n.typ);
+      case a.kind of
+        nkFloatLit..nkFloat64Lit: result.floatVal := a.floatVal;
+        else InternalError(n.info, 'no float value')
+      end
+    end;
+    mNSymbol: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      if result.kind <> nkSym then InternalError(n.info, 'no symbol')
+    end;
+    mNIdent: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      if result.kind <> nkIdent then InternalError(n.info, 'no symbol')
+    end;
+    mNGetType: result := evalAux(c, n.sons[1]);
+    mNStrVal: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      result := newNodeIT(nkStrLit, n.info, n.typ);
+      case a.kind of
+        nkStrLit..nkTripleStrLit: result.strVal := a.strVal;
+        else InternalError(n.info, 'no string value')
+      end
+    end;
+    mNSetIntVal: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      result := evalAux(c, n.sons[2]);
+      if result.kind = nkExceptBranch then exit;
+      a.intVal := result.intVal; // XXX: exception handling?
+      result := emptyNode
+    end;
+    mNSetFloatVal: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      result := evalAux(c, n.sons[2]);
+      if result.kind = nkExceptBranch then exit;
+      a.floatVal := result.floatVal; // XXX: exception handling?
+      result := emptyNode
+    end;
+    mNSetSymbol: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      result := evalAux(c, n.sons[2]);
+      if result.kind = nkExceptBranch then exit;
+      a.sym := result.sym; // XXX: exception handling?
+      result := emptyNode
+    end;
+    mNSetIdent: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      result := evalAux(c, n.sons[2]);
+      if result.kind = nkExceptBranch then exit;
+      a.ident := result.ident; // XXX: exception handling?
+      result := emptyNode
+    end;
+    mNSetType: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      result := evalAux(c, n.sons[2]);
+      if result.kind = nkExceptBranch then exit;
+      a.typ := result.typ; // XXX: exception handling?
+      result := emptyNode
+    end;
+    mNSetStrVal: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      result := evalAux(c, n.sons[2]);
+      if result.kind = nkExceptBranch then exit;
+      a.strVal := result.strVal; // XXX: exception handling?
+      result := emptyNode
+    end;
+    mNNewNimNode: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      k := getOrdValue(result);
+      result := evalAux(c, n.sons[2]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      if (k < 0) or (k > ord(high(TNodeKind))) then
+        internalError(n.info, 'request to create a NimNode with invalid kind');
+      if a.kind = nkNilLit then
+        result := newNodeI(TNodeKind(int(k)), n.info)
+      else
+        result := newNodeI(TNodeKind(int(k)), a.info)
+    end;
+    mNCopyNimNode: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      result := copyNode(result);
+    end;
+    mNCopyNimTree: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      result := copyTree(result);    
+    end;
+    mStrToIdent: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      if not (result.kind in [nkStrLit..nkTripleStrLit]) then
+        InternalError(n.info, 'no string node');
+      a := result;
+      result := newNodeIT(nkIdent, n.info, n.typ);
+      result.ident := getIdent(a.strVal);
+    end;
+    mIdentToStr: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      if result.kind <> nkIdent then
+        InternalError(n.info, 'no ident node');
+      a := result;
+      result := newNodeIT(nkStrLit, n.info, n.typ);
+      result.strVal := a.ident.s;
+    end;
+    mEqIdent: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      result := evalAux(c, n.sons[2]);
+      if result.kind = nkExceptBranch then exit;
+      b := result;
+      result := newNodeIT(nkIntLit, n.info, n.typ);
+      if (a.kind = nkIdent) and (b.kind = nkIdent) then
+        if a.ident.id = b.ident.id then result.intVal := 1
+    end;
+    mNHint: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      liMessage(n.info, hintUser, getStrValue(result));
+      result := emptyNode
+    end;
+    mNWarning: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      liMessage(n.info, warnUser, getStrValue(result));
+      result := emptyNode
+    end;
+    mNError: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      liMessage(n.info, errUser, getStrValue(result));
+      result := emptyNode
+    end;
+    else begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      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);
+    end
+  end
+end;
+
+function evalAux(c: PContext; n: PNode): PNode;
+var
   i: int;
 begin
+  result := emptyNode;
+  dec(gNestedEvals);
+  if gNestedEvals <= 0 then stackTrace(c, n, errTooManyIterations);
   case n.kind of // atoms:
-    nkEmpty: result := n; // do not produce further error messages!
-    nkSym: result := evalSym(c, n.sym);
+    nkEmpty: result := n;
+    nkSym: result := evalSym(c, n);
     nkType..pred(nkNilLit): result := copyNode(n);
     nkNilLit: result := n; // end of atoms
 
-    nkCall: begin
-      m := getMagic(n);
-      case m of
-        mNone: result := evalCall(b, n);
-        mSizeOf: internalError(n.info, 'sizeof() should have been evaluated');
-        mHigh: begin end;
-        mLow: begin end;
-        else begin
-          if sonsLen(n) > 2 then b := eval(c, n.sons[2])
-          else b := nil;
-          result := evalOp(m, n, eval(c, n.sons[1]), b);
+    nkCall, nkHiddenCallConv, nkMacroStmt: result := evalMagicOrCall(c, n);
+    nkCurly, nkBracket: begin
+      result := copyNode(n);
+      for i := 0 to sonsLen(n)-1 do addSon(result, evalAux(c, n.sons[i]));
+    end;
+    nkPar: begin
+      result := copyTree(n);
+      for i := 0 to sonsLen(n)-1 do
+        result.sons[i].sons[1] := evalAux(c, n.sons[i].sons[1]);
+    end;
+    nkBracketExpr: result := evalArrayAccess(c, n);
+    nkDotExpr: result := evalFieldAccess(c, n);
+    nkDerefExpr, nkHiddenDeref: result := evalDeref(c, n);
+    nkAddr, nkHiddenAddr: result := evalAddr(c, n);
+    nkHiddenStdConv, nkHiddenSubConv, nkConv: result := evalConv(c, n);
+    nkAsgn: result := evalAsgn(c, n);
+    nkWhenStmt, nkIfStmt, nkIfExpr: result := evalIf(c, n);
+    nkWhileStmt: result := evalWhile(c, n);
+    nkCaseStmt: result := evalCase(c, n);
+    nkVarSection: result := evalVar(c, n);
+    nkTryStmt: result := evalTry(c, n);
+    nkRaiseStmt: result := evalRaise(c, n);
+    nkReturnStmt: result := evalReturn(c, n);
+    nkBreakStmt, nkReturnToken: result := n;
+    nkBlockExpr, nkBlockStmt: result := evalBlock(c, n);
+    nkDiscardStmt: result := evalAux(c, n.sons[0]);
+    nkCheckedFieldExpr: result := evalCheckedFieldAccess(c, n);
+    nkObjDownConv: result := evalAux(c, n.sons[0]);
+    nkObjUpConv: result := evalUpConv(c, n);
+    nkChckRangeF, nkChckRange64, nkChckRange: result := evalRangeChck(c, n);
+    nkStringToCString: result := evalConvStrToCStr(c, n);
+    nkCStringToString: result := evalConvCStrToStr(c, n);
+    nkPassAsOpenArray: result := evalAux(c, n.sons[0]);
+    
+    nkStmtListExpr, nkStmtList, nkModule: begin 
+      for i := 0 to sonsLen(n)-1 do begin
+        result := evalAux(c, n.sons[i]);
+        case result.kind of 
+          nkExceptBranch, nkReturnToken, nkBreakStmt: break;
+          else begin end
         end
       end
     end;
-    nkIdentDefs: begin end;
+    nkProcDef, nkMacroDef, nkCommentStmt: begin end;
+    nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,
+    nkQualified, nkLambda, nkContinueStmt: 
+      stackTrace(c, n, errCannotInterpretNodeX, nodeKindToStr[n.kind]);
+    else InternalError(n.info, 'evalAux: ' + nodekindToStr[n.kind]);
+  end;
+  if result = nil then 
+    InternalError(n.info, 'evalAux: returned nil ' + nodekindToStr[n.kind]);
+  inc(gNestedEvals);
+end;
 
-    nkPar: begin
-      // tuple constructor, already in the right format
-      result := copyTree(n)
-    end;
-    nkCurly, nkBracket: result := copyTree(n);
-    nkBracketExpr:begin end;
-    nkPragmaExpr:begin end;
-    nkRange:begin end;
-    nkDotExpr:begin end;
-    nkDerefExpr:begin end;
-    nkIfExpr:begin end;
-    nkElifExpr:begin end;
-    nkElseExpr:begin end;
-    nkLambda:begin end;
-
-    nkSetConstr:begin end;
-    nkConstSetConstr:begin end;
-    nkArrayConstr:begin end;
-    nkConstArrayConstr:begin end;
-    nkRecordConstr:begin end;
-    nkConstRecordConstr:begin end;
-    nkTableConstr:begin end;
-    nkConstTableConstr:begin end;
-    nkQualified:begin end;
-    nkImplicitConv, nkConv: result := evalConv(c, n);
-    nkCast: result := evalCast(c, n); // this is hard!
-    nkAsgn: result := evalAsgn(c, n);
-    nkDefaultTypeParam:begin end;
-    nkGenericParams:begin end;
-    nkFormalParams:begin end;
-    nkOfInherit:begin end;
-    nkOfBranch: begin end;
-    nkElifBranch: begin end;
-    nkExceptBranch: begin end;
-    nkElse: begin end;
-    nkMacroStmt: begin end;
-    nkAsmStmt: begin end;
-    nkPragma: begin end;
-    nkIfStmt: begin end;
-    nkWhenStmt: begin end;
-    nkForStmt: begin end;
-    nkWhileStmt: begin end;
-    nkCaseStmt: begin end;
-    nkVarSection: begin end;
-    nkConstSection, nkConstDef, nkTypeDef, nkTypeSection, nkProcDef,
-    nkConverterDef, nkMacroDef, nkTemplateDef, nkIteratorDef:
-      result := emptyNode;
-    nkYieldStmt: begin end;
-    nkTryStmt: begin end;
-    nkFinally: begin end;
-    nkRaiseStmt: begin end;
-    nkReturnStmt: begin end;
-    nkBreakStmt: begin end;
-    nkContinueStmt: begin end;
-    nkBlockStmt: begin end;
-    nkDiscardStmt: begin end;
-    nkStmtList, nkModule: begin 
-      for i := 0 to sonsLen(n)-1 do 
-        result := eval(c, n.sons[i]);
-    end;
-    //nkImportStmt: begin end;
-    //nkFromStmt: begin end;
-    //nkImportAs: begin end;
-    //nkIncludeStmt: begin end;
-    nkCommentStmt: result := emptyNode; // do nothing
-    else
-      stackTrace(c, n, errCannotInterpretNode);
-  end
+function eval(c: PContext; n: PNode): PNode;
+begin
+  gWhileCounter := evalMaxIterations;
+  gNestedEvals := evalMaxRecDepth;
+  result := evalAux(c, transform(c, n));
+  if result.kind = nkExceptBranch then
+    stackTrace(c, n, errUnhandledExceptionX, typeToString(result.typ));
+end;
+
+function semMacroExpr(c: PContext; n: PNode; sym: PSym): PNode; 
+var
+  p: PTransCon;
+begin
+  p := newTransCon();
+  p.forStmt := n;
+  setLength(p.params, 2);
+  p.params[0] := newNodeIT(nkNilLit, n.info, sym.typ.sons[0]);
+  p.params[1] := n;
+  pushTransCon(c, p);
+  {@discard} eval(c, sym.ast.sons[codePos]);
+  result := p.params[0];
+  popTransCon(c);
+  if cyclicTree(result) then liMessage(n.info, errCyclicTree);
+  result := semStmt(c, result);
+  // now, that was easy ...
+  // and we get more flexibility than in any other programming language
 end;
diff --git a/nim/extccomp.pas b/nim/extccomp.pas
index 0fc24f8d3..a6d8cc147 100644
--- a/nim/extccomp.pas
+++ b/nim/extccomp.pas
@@ -15,10 +15,12 @@ interface
 {$include 'config.inc'}
 
 uses
-  nimconf, msgs; // some things are read in from the configuration file
+  nsystem, nimconf, msgs;
+
+// some things are read in from the configuration file
 
 type
-  TSystemCC = (ccNone, ccGcc, ccLLVM_Gcc, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc, 
+  TSystemCC = (ccNone, ccGcc, ccLLVM_Gcc, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc,
                ccTcc, ccPcc, ccUcc, ccIcc, ccGpp);
 
   TInfoCCProp = ( // properties of the C compiler:
@@ -27,15 +29,17 @@ type
     hasCpp           // CC is/contains a C++ compiler
   );
   TInfoCCProps = set of TInfoCCProp;
-  TInfoCC = record
+  TInfoCC = record{@tuple}
     name: string;            // the short name of the compiler
     objExt: string;          // the compiler's object file extenstion
     optSpeed: string;        // the options for optimization for speed
     optSize: string;         // the options for optimization for size
-    compile: string;         // the compile command template
+    compilerExe: string;     // the compiler's executable
+    compileTmpl: string;     // the compile command template
     buildGui: string;        // command to build a GUI application
     buildDll: string;        // command to build a shared library
-    link: string;            // command to link files to produce an executable
+    linkerExe: string;       // the linker's executable
+    linkTmpl: string;        // command to link files to produce an executable
     includeCmd: string;      // command to add an include directory path
     debug: string;           // flags for debug build
     pic: string;             // command for position independent code
@@ -50,10 +54,12 @@ const
       objExt: 'o'+'';
       optSpeed: ' -O3 -ffast-math ';
       optSize: ' -Os -ffast-math ';
-      compile: 'gcc -c $options $include -o $objfile $file';
+      compilerExe: 'gcc';
+      compileTmpl: '-c $options $include -o $objfile $file';
       buildGui: ' -mwindows';
       buildDll: ' -mdll';
-      link: 'gcc $options $buildgui $builddll -o $exefile $objfiles';
+      linkerExe: 'gcc';
+      linkTmpl: '$options $buildgui $builddll -o $exefile $objfiles';
       includeCmd: ' -I';
       debug: '';
       pic: '-fPIC';
@@ -65,10 +71,12 @@ const
       objExt: 'o'+'';
       optSpeed: ' -O3 -ffast-math ';
       optSize: ' -Os -ffast-math ';
-      compile: 'llvm-gcc -c $options $include -o $objfile $file';
+      compilerExe: 'llvm-gcc';
+      compileTmpl: '-c $options $include -o $objfile $file';
       buildGui: ' -mwindows';
       buildDll: ' -mdll';
-      link: 'llvm-gcc $options $buildgui $builddll -o $exefile $objfiles';
+      linkerExe: 'llvm-gcc';
+      linkTmpl: '$options $buildgui $builddll -o $exefile $objfiles';
       includeCmd: ' -I';
       debug: '';
       pic: '-fPIC';
@@ -80,10 +88,12 @@ const
       objExt: 'obj';
       optSpeed: ' -O -p6 ';
       optSize: ' -O -p6 ';
-      compile: 'lcc -e1 $options $include -Fo$objfile $file';
+      compilerExe: 'lcc';
+      compileTmpl: '-e1 $options $include -Fo$objfile $file';
       buildGui: ' -subsystem windows';
       buildDll: ' -dll';
-      link: 'lcclnk $options $buildgui $builddll -O $exefile $objfiles';
+      linkerExe: 'lcclnk';
+      linkTmpl: '$options $buildgui $builddll -O $exefile $objfiles';
       includeCmd: ' -I';
       debug: ' -g5 ';
       pic: '';
@@ -95,10 +105,12 @@ const
       objExt: 'obj';
       optSpeed: ' -O2 -6 ';
       optSize: ' -O1 -6 ';
-      compile: 'bcc32 -c $options $include -o$objfile $file';
+      compilerExe: 'bcc32';
+      compileTmpl: '-c $options $include -o$objfile $file';
       buildGui: ' -tW';
       buildDll: ' -tWD';
-      link: 'bcc32 $options $buildgui $builddll -e$exefile $objfiles';
+      linkerExe: 'bcc32';
+      linkTmpl: '$options $buildgui $builddll -e$exefile $objfiles';
       includeCmd: ' -I';
       debug: '';
       pic: '';
@@ -110,14 +122,16 @@ const
       objExt: 'obj';
       optSpeed: ' -ff -o -6 ';
       optSize: ' -ff -o -6 ';
-      compile: 'dmc -c $options $include -o$objfile $file';
+      compilerExe: 'dmc';
+      compileTmpl: '-c $options $include -o$objfile $file';
       buildGui: ' -L/exet:nt/su:windows';
       buildDll: ' -WD';
-      link: 'dmc $options $buildgui $builddll -o$exefile $objfiles';
+      linkerExe: 'dmc';
+      linkTmpl: '$options $buildgui $builddll -o$exefile $objfiles';
       includeCmd: ' -I';
       debug: ' -g ';
       pic: '';
-      asmStmtFrmt: '__asm{$n$1$n}$n';      
+      asmStmtFrmt: '__asm{$n$1$n}$n';
       props: {@set}[hasCpp];
     ),
     (
@@ -125,14 +139,16 @@ const
       objExt: 'obj';
       optSpeed: ' -ox -on -6 -d0 -fp6 -zW ';
       optSize: '';
-      compile: 'wcl386 -c $options $include -fo=$objfile $file';
+      compilerExe: 'wcl386';
+      compileTmpl: '-c $options $include -fo=$objfile $file';
       buildGui: ' -bw';
       buildDll: ' -bd';
-      link: 'wcl386 $options $buildgui $builddll -fe=$exefile $objfiles ';
+      linkerExe: 'wcl386';
+      linkTmpl: '$options $buildgui $builddll -fe=$exefile $objfiles ';
       includeCmd: ' -i=';
       debug: ' -d2 ';
       pic: '';
-      asmStmtFrmt: '__asm{$n$1$n}$n';      
+      asmStmtFrmt: '__asm{$n$1$n}$n';
       props: {@set}[hasCpp];
     ),
     (
@@ -140,10 +156,12 @@ const
       objExt: 'obj';
       optSpeed: ' /Ogityb2 /G7 /arch:SSE2 ';
       optSize: ' /O1 /G7 ';
-      compile: 'cl /c $options $include /Fo$objfile $file';
+      compilerExe: 'cl';
+      compileTmpl: '/c $options $include /Fo$objfile $file';
       buildGui: ' /link /SUBSYSTEM:WINDOWS ';
       buildDll: ' /LD';
-      link: 'cl $options $builddll /Fe$exefile $objfiles $buildgui';
+      linkerExe: 'cl';
+      linkTmpl: '$options $builddll /Fe$exefile $objfiles $buildgui';
       includeCmd: ' /I';
       debug: ' /GZ /Zi ';
       pic: '';
@@ -155,10 +173,12 @@ const
       objExt: 'o'+'';
       optSpeed: '';
       optSize: '';
-      compile: 'tcc -c $options $include -o $objfile $file';
+      compilerExe: 'tcc';
+      compileTmpl: '-c $options $include -o $objfile $file';
       buildGui: 'UNAVAILABLE!';
       buildDll: ' -shared';
-      link: 'tcc -o $exefile $options $buildgui $builddll $objfiles';
+      linkerExe: 'tcc';
+      linkTmpl: '-o $exefile $options $buildgui $builddll $objfiles';
       includeCmd: ' -I';
       debug: ' -g ';
       pic: '';
@@ -170,10 +190,12 @@ const
       objExt: 'obj';
       optSpeed: ' -Ox ';
       optSize: ' -Os ';
-      compile: 'cc -c $options $include -Fo$objfile $file';
+      compilerExe: 'cc';
+      compileTmpl: '-c $options $include -Fo$objfile $file';
       buildGui: ' -SUBSYSTEM:WINDOWS';
       buildDll: ' -DLL';
-      link: 'cc $options $buildgui $builddll -OUT:$exefile $objfiles';
+      linkerExe: 'cc';
+      linkTmpl: '$options $buildgui $builddll -OUT:$exefile $objfiles';
       includeCmd: ' -I';
       debug: ' -Zi ';
       pic: '';
@@ -185,10 +207,12 @@ const
       objExt: 'o'+'';
       optSpeed: ' -O3 ';
       optSize: ' -O1 ';
-      compile: 'cc -c $options $include -o $objfile $file';
+      compilerExe: 'cc';
+      compileTmpl: '-c $options $include -o $objfile $file';
       buildGui: '';
       buildDll: ' -shared ';
-      link: 'cc -o $exefile $options $buildgui $builddll $objfiles';
+      linkerExe: 'cc';
+      linkTmpl: '-o $exefile $options $buildgui $builddll $objfiles';
       includeCmd: ' -I';
       debug: '';
       pic: '';
@@ -199,10 +223,12 @@ const
       objExt: 'o'+'';
       optSpeed: ' -O3 ';
       optSize: ' -Os ';
-      compile: 'icc -c $options $include -o $objfile $file';
+      compilerExe: 'icc';
+      compileTmpl: '-c $options $include -o $objfile $file';
       buildGui: ' -mwindows';
       buildDll: ' -mdll';
-      link: 'icc $options $buildgui $builddll -o $exefile $objfiles';
+      linkerExe: 'icc';
+      linkTmpl: '$options $buildgui $builddll -o $exefile $objfiles';
       includeCmd: ' -I';
       debug: '';
       pic: '-fPIC';
@@ -213,10 +239,12 @@ const
       objExt: 'o'+'';
       optSpeed: ' -O3 -ffast-math ';
       optSize: ' -Os -ffast-math ';
-      compile: 'g++ -c $options $include -o $objfile $file';
+      compilerExe: 'g++';
+      compileTmpl: '-c $options $include -o $objfile $file';
       buildGui: ' -mwindows';
       buildDll: ' -mdll';
-      link: 'g++ $options $buildgui $builddll -o $exefile $objfiles';
+      linkerExe: 'g++';
+      linkTmpl: '$options $buildgui $builddll -o $exefile $objfiles';
       includeCmd: ' -I';
       debug: ' -g ';
       pic: '-fPIC';
@@ -238,6 +266,9 @@ var
 function completeCFilePath(const cfile: string;
   createSubDir: Boolean = true): string;
 
+function getCompileCFileCmd(const cfilename: string;
+                            isExternal: bool = false): string;
+
 procedure addFileToCompile(const filename: string);
 procedure addExternalFileToCompile(const filename: string);
 procedure addFileToLink(const filename: string);
@@ -260,7 +291,7 @@ procedure setCC(const ccname: string);
 implementation
 
 uses
-  nsystem, charsets,
+  charsets,
   lists, options, ropes, nos, strutils, platform, condsyms;
 
 var
@@ -389,16 +420,13 @@ begin
     result := cc[c].optSize // use default settings from this file
 end;
 
-procedure CompileCFile(const list: TLinkedList;
-                       var script: PRope; isExternal: Boolean);
+function getCompileCFileCmd(const cfilename: string;
+                            isExternal: bool = false): string;
 var
-  it: PStrEntry;
-  compileCmd, cfile, objfile, options, includeCmd, compilePattern: string;
+  cfile, objfile, options, includeCmd, compilePattern: string;
   c: TSystemCC; // an alias to ccompiler
 begin
   c := ccompiler;
-  it := PStrEntry(list.head);
-
   options := compileOptions;
   if optCDebug in gGlobalOptions then addStr(options, ' ' + getDebug(c));
   if optOptimizeSpeed in gOptions then addStr(options, ' ' + getOptSpeed(c))
@@ -413,31 +441,43 @@ begin
     includeCmd := cc[c].includeCmd; // this is more complex than needed, but
     // a workaround of a FPC bug...
     addStr(includeCmd, libpath);
-    compilePattern := JoinPath(ccompilerpath, cc[c].compile);
+    compilePattern := quoteIfSpaceExists(
+      JoinPath(ccompilerpath, cc[c].compilerExe));
   end
   else begin
     includeCmd := '';
-    compilePattern := cc[c].compile
+    compilePattern := cc[c].compilerExe
   end;
+  if targetOS = hostOS then
+    cfile := cfilename
+  else
+    cfile := extractFileName(cfilename);
+
+  if not isExternal or (targetOS <> hostOS) then
+    objfile := toObjFile(cfile)
+  else
+    objfile := completeCFilePath(toObjFile(cfile));
+
+  result := compilePattern +{&} ' ' +{&} format(cc[c].compileTmpl,
+    ['file', AppendFileExt(cfile, cExt),
+     'objfile', objfile,
+     'options', options,
+     'include', includeCmd,
+     'nimrod', getPrefixDir(),
+     'lib', libpath
+    ]);
+end;
 
+procedure CompileCFile(const list: TLinkedList;
+                       var script: PRope; isExternal: Boolean);
+var
+  it: PStrEntry;
+  compileCmd: string;
+begin
+  it := PStrEntry(list.head);
   while it <> nil do begin
     // call the C compiler for the .c file:
-    if targetOS = hostOS then
-      cfile := it.data
-    else
-      cfile := extractFileName(it.data);
-
-    if not isExternal or (targetOS <> hostOS) then
-      objfile := toObjFile(cfile)
-    else
-      objfile := completeCFilePath(toObjFile(cfile));
-
-    compileCmd := format(compilePattern,
-      ['file', AppendFileExt(cfile, cExt),
-       'objfile', objfile,
-       'options', options,
-       'include', includeCmd
-      ]);
+    compileCmd := getCompileCFileCmd(it.data, isExternal);
     if not (optCompileOnly in gGlobalOptions) then
       execExternalProgram(compileCmd);
     if (optGenScript in gGlobalOptions) then begin
@@ -469,9 +509,9 @@ begin
   if not (optNoLinking in gGlobalOptions) then begin
     // call the linker:
     if (hostOS <> targetOS) then
-      linkCmd := cc[c].link
+      linkCmd := cc[c].linkerExe
     else
-      linkCmd := JoinPath(ccompilerpath, cc[c].link);
+      linkCmd := quoteIfSpaceExists(JoinPath(ccompilerpath, cc[c].linkerExe));
 
     if optGenDynLib in gGlobalOptions then
       buildDll := cc[c].buildDll
@@ -506,12 +546,14 @@ begin
       it := PStrEntry(it.next);
     end;
 
-    linkCmd := format(linkCmd, [
+    linkCmd := linkCmd +{&} ' ' +{&} format(cc[c].linkTmpl, [
       'builddll', builddll,
       'buildgui', buildgui,
       'options', linkOptions,
       'objfiles', objfiles,
-      'exefile', exefile
+      'exefile', exefile,
+      'nimrod', getPrefixDir(),
+      'lib', libpath
     ]);
     if not (optCompileOnly in gGlobalOptions) then
       execExternalProgram(linkCmd);
diff --git a/nim/genhelp.pas b/nim/genhelp.pas
deleted file mode 100644
index 382a0b8bf..000000000
--- a/nim/genhelp.pas
+++ /dev/null
@@ -1,175 +0,0 @@
-//
-//
-//           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
-//
-//    See the file "copying.txt", included in this
-//    distribution, for details about the copyright.
-//
-
-unit genhelp;
-
-// This module contains some helper routines used by the different
-// code generators.
-
-interface
-
-{$include 'config.inc'}
-
-uses
-  nsystem,
-  ast, astalgo, trees, msgs, options, platform;
-
-function hasSideEffect(t: PNode): Boolean;
-
-function ReturnsNewThing(op: PNode): Boolean;
-
-
-function containsGarbageCollectedRef(typ: PType): Boolean;
-// returns true if typ contains a reference, sequence or string (all the things
-// that are garbage-collected)
-
-function containsHiddenPointer(typ: PType): Boolean;
-// returns true if typ contains a string, table or sequence (all the things
-// that need to be copied deeply)
-
-function containsObject(typ: PType): Boolean;
-// Returns true if typ contains an object type directly; then it has to
-// be initialized in a complex way that sets up the typeid field.
-
-function isGarbageCollected(typ: PType): Boolean;
-
-function pointerOf(typ: PType): PType;
-
-implementation
-
-function pointerOf(typ: PType): PType;
-begin
-  result := newType(unknownLineInfo, tyPtr);
-  result.baseType := typ;
-  result.align := platform.PtrSize;
-  result.size := platform.PtrSize;
-end;
-
-function isGarbageCollected(typ: PType): Boolean;
-begin
-  result := typ.Kind in [tyTable, tyRef, tySequence, tyString]
-end;
-
-function ReturnsNewThing(op: PNode): Boolean;
-var
-  s: PSym;
-begin
-  result := false;
-  if op.kind = nkCall then begin
-    if op.sons[0].kind = nkSym then begin
-      s := op.sons[0].sym;
-      result := (sfReturnsNew in s.flags)
-    end
-  end
-  else if op.typ.Kind = tyArrayConstr then
-    result := true // array constructor returns a newly allocated thing
-end;
-
-function containsHiddenPointer(typ: PType): Boolean;
-var
-  t: PType;
-  i: int;
-begin
-  t := typ;
-  result := false;
-  if t = nil then exit;
-  case t.Kind of
-    tySequence, tyString, tyTable: result := true;
-    tyArray, tyArrayConstr, tyOpenArray:
-      result := containsHiddenPointer(t.baseType);
-    tySubtype: result := containsHiddenPointer(typ.baseType);
-    tyRecord, tyObject: begin
-      if (t.baseType <> nil) and containsHiddenPointer(t.baseType) then
-        result := true
-      else
-        // walk through all fields:
-        for i := 0 to seqTableLen(t.symList)-1 do
-          if containsHiddenPointer(seqTableAt(t.symList, i).typ) then begin
-            result := true; break
-          end;
-    end
-    else result := false
-  end
-end;
-
-function containsGarbageCollectedRef(typ: PType): Boolean;
-var
-  t: PType;
-  i: int;
-begin
-  t := typ;
-  result := false;
-  if t = nil then exit;
-  case t.Kind of
-    tySequence, tyRef, tyString, tyTable: result := true;
-    tyArray: result := containsGarbageCollectedRef(t.baseType);
-    tyRecord, tyObject: begin
-      if (t.baseType <> nil) and containsGarbageCollectedRef(t.baseType) then
-        result := true
-      else
-        // walk through all fields:
-        for i := 0 to seqTableLen(t.symList)-1 do
-          if containsGarbageCollectedRef(SeqTableAt(t.symList, i).typ) then
-          begin
-            result := true; break
-          end;
-    end
-    else result := false
-  end
-end;
-
-function containsObject(typ: PType): Boolean;
-var
-  t: PType;
-  i: int;
-begin
-  t := typ;
-  result := false;
-  if t = nil then exit;
-  case t.Kind of
-    tyArray, tyArrayConstr:
-      result := containsObject(t.baseType);
-    tyObject: result := true;
-    tySubtype: result := containsObject(typ.baseType);
-    tyRecord: begin
-      // walk through all fields:
-      for i := 0 to seqTableLen(t.symList)-1 do
-        if containsObject(SeqTableAt(t.symList, i).typ) then begin
-          result := true; break
-        end;
-    end
-    else result := false
-  end
-end;
-
-function hasSideEffect(t: PNode): Boolean;
-{var
-  it: PNode; }
-begin
-  result := t.kind in [nkCall, nkArrayConstr, nkRecordConstr, nkSetConstr]
-  // assume side effect for operations
-        {
-  if t.Kind = nkOperation then begin
-    // this is for function pointers:
-    if hasSideEffect(t.left) then begin
-      result := true; exit
-    end;
-    it := t.right;
-    while it <> nil do begin
-      if hasSideEffect(it) then begin
-        result := true; exit
-      end;
-      it := it.next
-    end;
-    result := true
-  end;
-  result := false            }
-end;
-
-end.
diff --git a/nim/hashes.pas b/nim/hashes.pas
index 80acc57ca..059a42998 100644
--- a/nim/hashes.pas
+++ b/nim/hashes.pas
@@ -60,7 +60,9 @@ type
 function nextPowerOfTwo(x: int): int;
 begin
   result := x -{%} 1;
-  result := result or (result shr 32);
+  // complicated, to make it a nop if sizeof(int) == 4,
+  // because shifting more than 31 bits is undefined in C
+  result := result or (result shr ((sizeof(int)-4)* 32));
   result := result or (result shr 16);
   result := result or (result shr 8);
   result := result or (result shr 4);
@@ -115,7 +117,7 @@ var
   h: TUnsignedHash;
   i: int;
 begin
-  h := 0; 
+  h := 0;
   i := 0;
   while str[i] <> #0 do begin
     h := h +{%} ord(str[i]);
@@ -134,7 +136,7 @@ var
   h: TUnsignedHash;
   i: int;
 begin
-  h := 0; 
+  h := 0;
   for i := 1 to Length(s) do begin
     h := h +{%} ord(s[i]);
     h := h +{%} h shl 10;
@@ -152,7 +154,7 @@ var
   c: Char;
   i: int;
 begin
-  h := 0; 
+  h := 0;
   for i := strStart to length(s)+strStart-1 do begin
     c := s[i];
     if c = '_' then continue; // skip _
@@ -173,7 +175,7 @@ var
   c: Char;
   i: int;
 begin
-  h := 0; 
+  h := 0;
   for i := strStart to length(s)+strStart-1 do begin
     c := s[i];
     if c in ['A'..'Z'] then c := chr(ord(c) + (ord('a')-ord('A'))); // toLower()
@@ -194,7 +196,7 @@ var
   i: int;
 begin
   h := 0;
-  i := 0; 
+  i := 0;
   while str[i] <> #0 do begin
     c := str[i];
     if c in ['A'..'Z'] then c := chr(ord(c) + (ord('a')-ord('A'))); // toLower()
diff --git a/nim/highlite.pas b/nim/highlite.pas
index ee115b815..8547d9904 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, hashes, options, msgs, strutils, platform,
   idents, lexbase, wordrecg, scanner;
 
 type
@@ -42,14 +42,14 @@ type
     gtLongComment,
     gtRegularExpression,
     gtTagStart,
-    gtTagEnd, 
+    gtTagEnd,
     gtKey,
     gtValue,
     gtRawData,
     gtAssembler,
     gtPreprocessor,
     gtDirective,
-    gtCommand, 
+    gtCommand,
     gtRule,
     gtHyperlink,
     gtLabel,
@@ -65,7 +65,7 @@ type
     state: TTokenClass;
   end;
   TSourceLanguage = (
-    langNone, 
+    langNone,
     langNimrod,
     langCpp,
     langCsharp,
@@ -97,14 +97,14 @@ const
     'LongComment',
     'RegularExpression',
     'TagStart',
-    'TagEnd', 
+    'TagEnd',
     'Key',
     'Value',
     'RawData',
     'Assembler',
     'Preprocessor',
     'Directive',
-    'Command', 
+    'Command',
     'Rule',
     'Hyperlink',
     'Label',
@@ -114,7 +114,7 @@ const
 
 function getSourceLanguage(const name: string): TSourceLanguage;
 
-procedure initGeneralTokenizer(var g: TGeneralTokenizer; 
+procedure initGeneralTokenizer(var g: TGeneralTokenizer;
                                const buf: string);
 procedure deinitGeneralTokenizer(var g: TGeneralTokenizer);
 procedure getNextToken(var g: TGeneralTokenizer; lang: TSourceLanguage);
@@ -125,18 +125,23 @@ function getSourceLanguage(const name: string): TSourceLanguage;
 var
   i: TSourceLanguage;
 begin
-  for i := succ(low(TSourceLanguage)) to high(TSourceLanguage) do 
+  for i := succ(low(TSourceLanguage)) to high(TSourceLanguage) do
     if cmpIgnoreStyle(name, sourceLanguageToStr[i]) = 0 then begin
       result := i; exit
     end;
   result := langNone
 end;
 
-procedure initGeneralTokenizer(var g: TGeneralTokenizer; 
+procedure initGeneralTokenizer(var g: TGeneralTokenizer;
                                const buf: string);
 begin
 {@ignore} fillChar(g, sizeof(g), 0); {@emit}
   g.buf := PChar(buf);
+  g.kind := low(TTokenClass);
+  g.start := 0;
+  g.len := 0;
+  g.pos := 0;
+  g.state := low(TTokenClass);
 end;
 
 procedure deinitGeneralTokenizer(var g: TGeneralTokenizer);
@@ -221,7 +226,7 @@ begin
         '\': begin
           g.kind := gtEscapeSequence;
           inc(pos);
-          case g.buf[pos] of 
+          case g.buf[pos] of
             'x', 'X': begin
               inc(pos);
               if g.buf[pos] in hexChars then inc(pos);
@@ -243,8 +248,8 @@ begin
       end
     end
   end
-  else begin 
-    case g.buf[pos] of 
+  else begin
+    case g.buf[pos] of
       ' ', #9..#13: begin
         g.kind := gtWhitespace;
         while g.buf[pos] in [' ', #9..#13] do inc(pos);
@@ -284,10 +289,10 @@ begin
           end;
           'o', 'O': begin
             inc(pos);
-            while g.buf[pos] in octChars do inc(pos);          
+            while g.buf[pos] in octChars do inc(pos);
             pos := nimNumberPostfix(g, pos);
           end;
-          else 
+          else
             pos := nimNumber(g, pos);
         end
       end;
@@ -315,7 +320,7 @@ begin
             case g.buf[pos] of
               #0: break;
               '"': begin
-                inc(pos); 
+                inc(pos);
                 if (g.buf[pos] = '"') and (g.buf[pos+1] = '"') then begin
                   inc(pos, 2);
                   break
@@ -411,7 +416,7 @@ begin
         end
       end;
       else if g.buf[pos] = c then begin
-        inc(pos); break;      
+        inc(pos); break;
       end
       else
         inc(pos);
@@ -468,7 +473,7 @@ type
   TTokenizerFlag = (hasPreprocessor, hasNestedComments);
   TTokenizerFlags = set of TTokenizerFlag;
 
-procedure clikeNextToken(var g: TGeneralTokenizer; 
+procedure clikeNextToken(var g: TGeneralTokenizer;
                          const keywords: array of string;
                          flags: TTokenizerFlags);
 const
@@ -489,7 +494,7 @@ begin
         '\': begin
           g.kind := gtEscapeSequence;
           inc(pos);
-          case g.buf[pos] of 
+          case g.buf[pos] of
             'x', 'X': begin
               inc(pos);
               if g.buf[pos] in hexChars then inc(pos);
@@ -511,8 +516,8 @@ begin
       end
     end
   end
-  else begin 
-    case g.buf[pos] of 
+  else begin
+    case g.buf[pos] of
       ' ', #9..#13: begin
         g.kind := gtWhitespace;
         while g.buf[pos] in [' ', #9..#13] do inc(pos);
@@ -583,7 +588,7 @@ begin
           end;
           '0'..'7': begin
             inc(pos);
-            while g.buf[pos] in octChars do inc(pos);          
+            while g.buf[pos] in octChars do inc(pos);
             if g.buf[pos] in ['A'..'Z', 'a'..'z'] then inc(pos);
           end;
           else begin
@@ -635,13 +640,13 @@ end;
 // --------------------------------------------------------------------------
 
 procedure cNextToken(var g: TGeneralTokenizer);
-const 
+const
   keywords: array [0..36] of string = (
     '_Bool', '_Complex', '_Imaginary',
-    'auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do', 
-    'double', 'else', 'enum', 'extern', 'float', 'for', 'goto', 'if', 
-    'inline', 'int', 'long', 'register', 'restrict', 'return', 'short', 
-    'signed', 'sizeof', 'static', 'struct', 'switch', 'typedef', 'union', 
+    'auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do',
+    'double', 'else', 'enum', 'extern', 'float', 'for', 'goto', 'if',
+    'inline', 'int', 'long', 'register', 'restrict', 'return', 'short',
+    'signed', 'sizeof', 'static', 'struct', 'switch', 'typedef', 'union',
     'unsigned', 'void', 'volatile', 'while'
   );
 begin
@@ -649,12 +654,12 @@ begin
 end;
 
 procedure cppNextToken(var g: TGeneralTokenizer);
-const 
+const
   keywords: array [0..47] of string = (
     'asm', 'auto', 'break', 'case', 'catch', 'char', 'class', 'const',
     'continue', 'default', 'delete', 'do', 'double', 'else', 'enum', 'extern',
     'float', 'for', 'friend', 'goto', 'if', 'inline', 'int', 'long', 'new',
-    'operator', 'private', 'protected', 'public', 'register', 'return', 
+    'operator', 'private', 'protected', 'public', 'register', 'return',
     'short', 'signed', 'sizeof', 'static', 'struct', 'switch', 'template',
     'this', 'throw', 'try', 'typedef', 'union', 'unsigned', 'virtual', 'void',
     'volatile', 'while'
@@ -664,33 +669,33 @@ begin
 end;
 
 procedure csharpNextToken(var g: TGeneralTokenizer);
-const 
+const
   keywords: array [0..76] of string = (
-    'abstract', 'as', 'base', 'bool', 'break', 'byte', 'case', 'catch', 
-    'char', 'checked', 'class', 'const', 'continue', 'decimal', 'default', 
-    'delegate', 'do', 'double', 'else', 'enum', 'event', 'explicit', 'extern', 
-    'false', 'finally', 'fixed', 'float', 'for', 'foreach', 'goto', 'if', 
-    'implicit', 'in', 'int', 'interface', 'internal', 'is', 'lock', 'long', 
-    'namespace', 'new', 'null', 'object', 'operator', 'out', 'override', 
-    'params', 'private', 'protected', 'public', 'readonly', 'ref', 'return', 
-    'sbyte', 'sealed', 'short', 'sizeof', 'stackalloc', 'static', 'string', 
-    'struct', 'switch', 'this', 'throw', 'true', 'try', 'typeof', 'uint', 
-    'ulong', 'unchecked', 'unsafe', 'ushort', 'using', 'virtual', 'void', 
-    'volatile', 'while'  
+    'abstract', 'as', 'base', 'bool', 'break', 'byte', 'case', 'catch',
+    'char', 'checked', 'class', 'const', 'continue', 'decimal', 'default',
+    'delegate', 'do', 'double', 'else', 'enum', 'event', 'explicit', 'extern',
+    'false', 'finally', 'fixed', 'float', 'for', 'foreach', 'goto', 'if',
+    'implicit', 'in', 'int', 'interface', 'internal', 'is', 'lock', 'long',
+    'namespace', 'new', 'null', 'object', 'operator', 'out', 'override',
+    'params', 'private', 'protected', 'public', 'readonly', 'ref', 'return',
+    'sbyte', 'sealed', 'short', 'sizeof', 'stackalloc', 'static', 'string',
+    'struct', 'switch', 'this', 'throw', 'true', 'try', 'typeof', 'uint',
+    'ulong', 'unchecked', 'unsafe', 'ushort', 'using', 'virtual', 'void',
+    'volatile', 'while'
   );
 begin
   clikeNextToken(g, keywords, {@set}[hasPreprocessor]);
 end;
 
 procedure javaNextToken(var g: TGeneralTokenizer);
-const 
+const
   keywords: array [0..52] of string = (
-    'abstract', 'assert', 'boolean', 'break', 'byte', 'case', 'catch', 
-    'char', 'class', 'const', 'continue', 'default', 'do', 'double', 'else', 
-    'enum', 'extends', 'false', 'final', 'finally', 'float', 'for', 'goto', 
-    'if', 'implements', 'import', 'instanceof', 'int', 'interface', 'long', 
-    'native', 'new', 'null', 'package', 'private', 'protected', 'public', 
-    'return', 'short', 'static', 'strictfp', 'super', 'switch', 
+    'abstract', 'assert', 'boolean', 'break', 'byte', 'case', 'catch',
+    'char', 'class', 'const', 'continue', 'default', 'do', 'double', 'else',
+    'enum', 'extends', 'false', 'final', 'finally', 'float', 'for', 'goto',
+    'if', 'implements', 'import', 'instanceof', 'int', 'interface', 'long',
+    'native', 'new', 'null', 'package', 'private', 'protected', 'public',
+    'return', 'short', 'static', 'strictfp', 'super', 'switch',
     'synchronized', 'this', 'throw', 'throws', 'transient', 'true', 'try',
     'void', 'volatile', 'while'
   );
@@ -700,7 +705,7 @@ end;
 
 procedure getNextToken(var g: TGeneralTokenizer; lang: TSourceLanguage);
 begin
-  case lang of 
+  case lang of
     langNimrod: nimNextToken(g);
     langCpp: cppNextToken(g);
     langCsharp: csharpNextToken(g);
diff --git a/nim/importer.pas b/nim/importer.pas
index 5377434fe..0658783a3 100644
--- a/nim/importer.pas
+++ b/nim/importer.pas
@@ -40,10 +40,11 @@ procedure rawImportSymbol(c: PContext; s: PSym);
 var
   check, copy, e: PSym;
   j: int;
-  etyp: PType; // enumeration type  
+  etyp: PType; // enumeration type
 begin
-  copy := copySym(s, s.owner);
-  copy.ast := s.ast; // BUGFIX
+  //copy := copySym(s, true);
+  //copy.ast := s.ast;
+  copy := s; // do not copy symbols when importing!
   // check if we have already a symbol of the same name:
   check := StrTableGet(c.tab.stack[importTablePos], s.name);
   if check <> nil then begin
@@ -55,17 +56,17 @@ begin
   end;
   StrTableAdd(c.tab.stack[importTablePos], copy);
   if s.kind = skType then begin
-    // types are special: we need to copy types but need to
-    // consider private fields
     etyp := s.typ;
     if etyp.kind = tyEnum then begin
       for j := 0 to sonsLen(etyp.n)-1 do begin
         e := etyp.n.sons[j].sym;
-        assert(e.Kind = skEnumField);
-        rawImportSymbol(c, e)
+        if (e.Kind = skEnumField) then rawImportSymbol(c, e)
+        else InternalError(s.info, 'rawImportSymbol');
       end
     end
-  end;
+  end
+  else if s.kind = skConverter then
+    addConverter(c, s);
 end;
 
 procedure importSymbol(c: PContext; ident: PNode; fromMod: PSym);
@@ -73,18 +74,20 @@ var
   s, e: PSym;
   it: TIdentIter;
 begin
-  assert(ident.kind = nkIdent);
+  if (ident.kind <> nkIdent) then InternalError(ident.info, 'importSymbol');
   s := StrTableGet(fromMod.tab, ident.ident);
   if s = nil then
     liMessage(ident.info, errUndeclaredIdentifier, ident.ident.s);
-  assert(s.Kind in ExportableSymKinds);
+  if not (s.Kind in ExportableSymKinds) then
+    InternalError(ident.info, 'importSymbol: 2');
   // for an enumeration we have to add all identifiers
   case s.Kind of
-    skProc, skIterator, skMacro, skTemplate: begin
-    // for a overloadable syms add all overloaded routines
+    skProc, skIterator, skMacro, skTemplate, skConverter: begin
+      // for a overloadable syms add all overloaded routines
       e := InitIdentIter(it, fromMod.tab, s.name);
       while e <> nil do begin
-        assert(e.name.id = s.Name.id);
+        if (e.name.id <> s.Name.id) then
+          InternalError(ident.info, 'importSymbol: 3');
         rawImportSymbol(c, e);
         e := NextIdentIter(it, fromMod.tab);
       end
@@ -101,8 +104,11 @@ begin
   s := InitTabIter(i, fromMod.tab);
   while s <> nil do begin
     if s.kind <> skModule then begin
-      assert(s.Kind in ExportableSymKinds);
-      rawImportSymbol(c, s); // this is correct!
+      if s.kind <> skEnumField then begin
+        if not (s.Kind in ExportableSymKinds) then
+          InternalError(s.info, 'importAllSymbols');
+        rawImportSymbol(c, s); // this is correct!
+      end
     end;
     s := NextIter(i, fromMod.tab)
   end
@@ -129,6 +135,7 @@ var
   i: int;
 begin
   result := n;
+  checkMinSonsLen(n, 2);
   m := c.ImportModule(getModuleFile(n.sons[0]), c.b);
   n.sons[0] := newSymNode(m);
   addDecl(c, m); // add symbol to symbol table of module
@@ -140,7 +147,7 @@ var
   i: int;
   x: PNode;
 begin
-  result := newNode(nkStmtList);
+  result := newNodeI(nkStmtList, n.info);
   for i := 0 to sonsLen(n)-1 do begin
     x := c.includeFile(getModuleFile(n.sons[i]));
     x := semStmt(c, x);
diff --git a/nim/instgen.pas b/nim/instgen.pas
index 2d5abc8b2..e64034f9e 100644
--- a/nim/instgen.pas
+++ b/nim/instgen.pas
@@ -21,11 +21,12 @@ type
     newOwner: PSym;
     instantiator: TLineInfo;
   end;
-  PInstClosure = ^TInstantiateClosure;
+  PInstantiateClosure = ^TInstantiateClosure;
+  PInstClosure = PInstantiateClosure;
 
-function instantiateTree(var c: TInstantiateClosure; t: PNode): PNode; forward;
-
-function instantiateSym(var c: TInstantiateClosure; sym: PSym): PSym; forward;
+function instantiateTree(c: PInstantiateClosure; t: PNode): PNode; forward;
+function instantiateSym(c: PInstantiateClosure; sym: PSym): PSym; forward;
+function instantiateType(c: PInstantiateClosure; typ: PType): PType; forward;
 
 function containsGenericTypeIter(t: PType; closure: PObject): bool;
 begin
@@ -37,35 +38,58 @@ begin
   result := iterOverType(t, containsGenericTypeIter, nil);
 end;
 
+function instTypeNode(c: PInstantiateClosure; n: PNode): PNode;
+var
+  i: int;
+begin
+  result := nil;
+  if n <> nil then begin
+    result := copyNode(n);
+    result.typ := instantiateType(c, n.typ);
+    case n.kind of
+      nkNone..nkNilLit: begin // a leaf
+      end;
+      else begin
+        for i := 0 to sonsLen(n)-1 do
+          addSon(result, instTypeNode(c, n.sons[i]));
+      end
+    end
+  end
+end;
 
-function instantiateTypeMutator(typ: PType; c: PObject): PType;
+function instantiateType(c: PInstantiateClosure; typ: PType): PType;
+var 
+  i: int;
 begin
-  result := PType(idTableGet(PInstClosure(c).mapping, typ));
+  result := PType(idTableGet(c.mapping, typ));
   if result <> nil then exit;
   if containsGenericType(typ) then begin
-    result := copyType(typ, PInstClosure(c).newOwner);
-    idTablePut(PInstClosure(c).mapping, typ, result)
+    result := copyType(typ, c.newOwner);
+    idTablePut(c.mapping, typ, result); // to avoid cycles
+    for i := 0 to sonsLen(result)-1 do 
+      result.sons[i] := instantiateType(c, result.sons[i]);
+    if result.n <> nil then
+      result.n := instTypeNode(c, result.n);
   end
   else
     result := typ;
   if result.Kind in GenericTypes then begin
-    liMessage(PInstClosure(c).instantiator, errCannotInstantiateX,
+    liMessage(c.instantiator, errCannotInstantiateX, 
               TypeToString(typ, preferName));
+  end
+  else if result.kind = tyVar then begin
+    if result.sons[0].kind = tyVar then
+      liMessage(c.instantiator, errVarVarTypeNotAllowed);
   end;
 end;
 
-function instantiateType(var c: TInstantiateClosure; typ: PType): PType;
-begin
-  result := mutateType(typ, instantiateTypeMutator, {@cast}PObject(addr(c)));
-end;
-
-function instantiateSym(var c: TInstantiateClosure; sym: PSym): PSym;
+function instantiateSym(c: PInstantiateClosure; sym: PSym): PSym;
 begin
   if sym = nil then begin result := nil; exit end; // BUGFIX
   result := PSym(idTableGet(c.mapping, sym));
   if (result = nil) then begin
     if (sym.owner.id = c.fn.id) or (sym.id = c.fn.id) then begin
-      result := copySym(sym, nil);
+      result := copySym(sym);
       if sym.id = c.fn.id then c.newOwner := result;
       include(result.flags, sfIsCopy);
       idTablePut(c.mapping, sym, result); // BUGFIX
@@ -83,7 +107,7 @@ begin
   end
 end;
 
-function instantiateTree(var c: TInstantiateClosure; t: PNode): PNode;
+function instantiateTree(c: PInstantiateClosure; t: PNode): PNode;
 var
   len, i: int;
 begin
@@ -124,7 +148,8 @@ begin
     q := n.sons[i].sym;
     s := newSym(skType, q.name, getCurrOwner(c));
     t := PType(IdTableGet(pt, q.typ));
-    if t = nil then liMessage(n.sons[i].info, errCannotInstantiateX, s.name.s);
+    if t = nil then
+      liMessage(n.sons[i].info, errCannotInstantiateX, s.name.s);
     assert(t.kind <> tyGenericParam);
     s.typ := t;
     addDecl(c, s);
@@ -138,7 +163,8 @@ var
 begin
   result := nil;
   for i := 0 to sonsLen(c.generics)-1 do begin
-    assert(c.generics.sons[i].kind = nkExprEqExpr);
+    if c.generics.sons[i].kind <> nkExprEqExpr then
+      InternalError(genericSym.info, 'GenericCacheGet');
     a := c.generics.sons[i].sons[0].sym;
     if genericSym.id = a.id then begin
       b := c.generics.sons[i].sons[1].sym;
@@ -173,8 +199,8 @@ var
   n: PNode;
 begin
   oldP := c.p; // restore later
-  result := copySym(fn, getCurrOwner(c));
-  result.id := getId();
+  result := copySym(fn);
+  result.owner := getCurrOwner(c);
   n := copyTree(fn.ast);
   result.ast := n;
   pushOwner(c, result);
@@ -202,7 +228,7 @@ begin
     addDecl(c, result);
     if n.sons[codePos] <> nil then begin
       c.p := newProcCon(result);
-      if result.kind = skProc then begin
+      if result.kind in [skProc, skConverter] then begin
         addResult(c, result.typ.sons[0], n.info);
         addResultNode(c, n);
       end;
@@ -221,8 +247,12 @@ end;
 function generateTypeInstance(p: PContext; const pt: TIdTable;
                               const instantiator: TLineInfo; t: PType): PType;
 var
-  c: TInstantiateClosure;
+  c: PInstantiateClosure;
 begin
+  new(c);
+{@ignore}
+  fillChar(c^, sizeof(c^), 0);
+{@emit}
   c.mapping := pt; // making a copy is not necessary
   c.fn := nil;
   c.instantiator := instantiator;
diff --git a/nim/lexbase.pas b/nim/lexbase.pas
index f02c375ff..c840dc6d2 100644
--- a/nim/lexbase.pas
+++ b/nim/lexbase.pas
@@ -227,7 +227,7 @@ begin
   L.linenumber := 1; // lines start at 1
   L.fileOpened := false;
   if L.bufLen > 0 then begin
-    copyMem(L.buf, addr(buffer[strStart]), L.bufLen);
+    copyMem(L.buf, {@cast}pointer(buffer), L.bufLen);
     L.buf[L.bufLen-1] := EndOfFile;
   end
   else
diff --git a/nim/lookup.pas b/nim/lookup.pas
index 143967f3e..192dba7ca 100644
--- a/nim/lookup.pas
+++ b/nim/lookup.pas
@@ -12,8 +12,7 @@
 function getSymRepr(s: PSym): string;
 begin
   case s.kind of
-    skProc, skConverter, skIterator:
-      result := getProcHeader(s);
+    skProc, skConverter, skIterator: result := getProcHeader(s);
     else result := s.name.s
   end
 end;
@@ -24,7 +23,7 @@ var
   s: PSym;
 begin
   // check if all symbols have been used and defined:
-  assert(tab.tos <= length(tab.stack));
+  if (tab.tos > length(tab.stack)) then InternalError('CloseScope');
   s := InitTabIter(it, tab.stack[tab.tos-1]);
   while s <> nil do begin
     if sfForward in s.flags then
@@ -59,7 +58,8 @@ procedure addOverloadableSymAt(c: PContext; fn: PSym; at: Natural);
 var
   check: PSym;
 begin
-  assert(fn.kind in OverloadableSyms);
+  if not (fn.kind in OverloadableSyms) then
+    InternalError(fn.info, 'addOverloadableSymAt');
   check := StrTableGet(c.tab.stack[at], fn.name);
   if (check <> nil) and (check.Kind <> fn.kind) then
     liMessage(fn.info, errAttemptToRedefine, fn.Name.s);
@@ -70,7 +70,7 @@ procedure AddInterfaceDeclAux(c: PContext; sym: PSym);
 begin
   if (sfInInterface in sym.flags) then begin
     // add to interface:
-    assert(c.module <> nil);
+    if c.module = nil then InternalError(sym.info, 'AddInterfaceDeclAux');
     StrTableAdd(c.module.tab, sym);
   end;
   if getCurrOwner(c).kind = skModule then
@@ -92,12 +92,21 @@ end;
 function lookUp(c: PContext; n: PNode): PSym;
 // Looks up a symbol. Generates an error in case of nil.
 begin
-  if n.kind = nkAccQuoted then result := lookup(c, n.sons[0])
-  else begin
-    assert(n.kind = nkIdent);
-    result := SymtabGet(c.Tab, n.ident);
-    if result = nil then liMessage(n.info, errUndeclaredIdentifier, n.ident.s);
-    include(result.flags, sfUsed);
+  case n.kind of
+    nkAccQuoted: result := lookup(c, n.sons[0]);
+    nkSym: begin
+      result := SymtabGet(c.Tab, n.sym.name);
+      if result = nil then
+        liMessage(n.info, errUndeclaredIdentifier, n.sym.name.s);
+      include(result.flags, sfUsed);
+    end;
+    nkIdent: begin
+      result := SymtabGet(c.Tab, n.ident);
+      if result = nil then
+        liMessage(n.info, errUndeclaredIdentifier, n.ident.s);
+      include(result.flags, sfUsed);
+    end
+    else InternalError(n.info, 'lookUp');
   end
 end;
 
@@ -115,6 +124,14 @@ begin
           and StrTableContains(c.AmbigiousSymbols, result) then
         liMessage(n.info, errUseQualifier, n.ident.s)
     end;
+    nkSym: begin
+      result := SymtabGet(c.Tab, n.sym.name);
+      if result = nil then
+        liMessage(n.info, errUndeclaredIdentifier, n.sym.name.s)
+      else if ambigiousCheck
+          and StrTableContains(c.AmbigiousSymbols, result) then
+        liMessage(n.info, errUseQualifier, n.sym.name.s)
+    end;    
     nkDotExpr, nkQualified: begin
       result := nil;
       m := qualifiedLookUp(c, n.sons[0], false);
@@ -165,6 +182,15 @@ begin
         result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.ident);
       end;
     end;
+    nkSym: begin
+      o.stackPtr := c.tab.tos;
+      o.mode := oimNoQualifier;
+      while (result = nil) do begin
+        dec(o.stackPtr);
+        if o.stackPtr < 0 then break;
+        result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.sym.name);
+      end;
+    end;
     nkDotExpr, nkQualified: begin
       o.mode := oimOtherModule;
       o.m := qualifiedLookUp(c, n.sons[0], false);
@@ -199,7 +225,8 @@ begin
         while (result = nil) do begin
           dec(o.stackPtr);
           if o.stackPtr < 0 then break;
-          result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.ident);
+          result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], o.it.name);
+          // BUGFIX: o.it.name <-> n.ident
         end
       end
       else result := nil;
diff --git a/nim/main.pas b/nim/main.pas
index 8ea82ced3..6e0afda98 100644
--- a/nim/main.pas
+++ b/nim/main.pas
@@ -17,7 +17,8 @@ interface
 uses
   nsystem, strutils, ast, astalgo, scanner, pnimsyn, rnimsyn, options, msgs,
   nos, lists, condsyms, paslex, pasparse, rodgen, ropes, trees,
-  wordrecg, sem, idents, magicsys, backends, docgen, extccomp, cgen;
+  wordrecg, sem, idents, magicsys, backends, docgen, extccomp, cgen,
+  platform, ecmasgen;
 
 procedure MainCommand(const cmd, filename: string);
 
@@ -109,7 +110,9 @@ begin
     // compile the module
     // XXX: here caching could be implemented
     result := compileModule(filename, backend, false, false);
-  end;
+  end
+  else if sfSystemModule in result.flags then
+    liMessage(result.info, errAttemptToRedefine, result.Name.s);
 end;
 
 function CompileModule(const filename: string; backend: PBackend;
@@ -131,8 +134,8 @@ begin
   openScope(c.tab); // scope for imported symbols
   SymTabAdd(c.tab, result);
   if not isSystemFile then begin
-    importAllSymbols(c, magicsys.SystemModule);
     SymTabAdd(c.tab, magicsys.SystemModule); // import the "System" identifier
+    importAllSymbols(c, magicsys.SystemModule);
     SymTabAdd(c.tab, newIsMainModuleSym(result, isMainFile));
   end
   else begin
@@ -142,7 +145,6 @@ begin
   end;
   {@discard} semModule(c, ast);
   rawCloseScope(c.tab); // imported symbols; don't check for unused ones!
-  // XXX: compile the generated generic procs!
   msgCompiled(result.name.s);
 end;
 
@@ -161,8 +163,8 @@ var
 
 procedure addDependencyAux(importing, imported: PSym);
 begin
-  appRopeFormat(gDotGraph, '$1 -> $2;$n', [toRope(importing.name.s),
-                                           toRope(imported.name.s)]);
+  appf(gDotGraph, '$1 -> $2;$n', [toRope(importing.name.s),
+                                  toRope(imported.name.s)]);
   //    s1 -> s2_4 [label="[0-9]"];
 end;
 
@@ -193,7 +195,7 @@ end;
 procedure generateDot(const project: string);
 begin
   writeRope(
-    ropeFormat('digraph $1 {$n$2}$n', [
+    ropef('digraph $1 {$n$2}$n', [
       toRope(changeFileExt(extractFileName(project), '')), gDotGraph]),
     changeFileExt(project, 'dot') );
 end;
@@ -257,13 +259,21 @@ begin
   extccomp.CallCCompiler(changeFileExt(filename, ''));
 end;
 
+procedure CommandCompileToEcmaScript(const filename: string);
+begin
+  include(gGlobalOptions, optSafeCode);
+  setTarget(osEcmaScript, cpuEcmaScript);
+  initDefines();
+  compileProject(filename, EcmasBackend(nil, nil, filename));
+end;
+
 // --------------------------------------------------------------------------
 
 procedure exSymbols(n: PNode);
 var
   i: int;
 begin
-  case n.kind of 
+  case n.kind of
     nkEmpty..nkNilLit: begin end; // atoms
     nkProcDef..nkIteratorDef: begin
       exSymbol(n.sons[namePos]);
@@ -279,7 +289,7 @@ begin
       for i := 0 to sonsLen(n)-1 do begin
         exSymbol(n.sons[i].sons[0]);
         if (n.sons[i].sons[2] <> nil) and
-            (n.sons[i].sons[2].kind in [nkRecordTy, nkObjectTy]) then
+            (n.sons[i].sons[2].kind = nkObjectTy) then
           fixRecordDef(n.sons[i].sons[2])
       end
     end;
@@ -406,6 +416,11 @@ begin
       wantFile(filename);
       CommandCompileToC(filename);
     end;
+    wCompileToEcmaScript: begin
+      gCmd := cmdCompileToEcmaScript;
+      wantFile(filename);
+      CommandCompileToEcmaScript(filename);
+    end;
     wPretty: begin
       // compile means compileToC currently
       gCmd := cmdPretty;
diff --git a/nim/msgs.pas b/nim/msgs.pas
index 6f4f8225e..8112b8df7 100644
--- a/nim/msgs.pas
+++ b/nim/msgs.pas
@@ -74,10 +74,6 @@ type
     errTokenExpected,
     errStringAfterIncludeExpected,
     errRecursiveInclude,
-    errAtIfExpected,
-    errAtIfExpectedBeforeElse,
-    errAtIfExpectedBeforeElif,
-    errAtEndExpected,
     errOnOrOffExpected,
     errNoneSpeedOrSizeExpected,
     errInvalidPragma,
@@ -186,7 +182,7 @@ type
     errSizeTooBig,
     errSetTooBig,
     errBaseTypeMustBeOrdinal,
-    errInheritanceOnlyWithObjects,
+    errInheritanceOnlyWithNonFinalObjects,
     errInheritanceOnlyWithEnums,
     errIllegalRecursionInTypeX,
     errCannotInstantiateX,
@@ -267,6 +263,20 @@ type
     errWhitespaceExpected,
     errXisNoValidIndexFile,
     errCannotRenderX,
+    errVarVarTypeNotAllowed,
+    errIsExpectsTwoArguments,
+    errIsExpectsObjectTypes,
+    errXcanNeverBeOfThisSubtype,
+    errTooManyIterations,
+    errCannotInterpretNodeX,
+    errFieldXNotFound,
+    errInvalidConversionFromTypeX,
+    errAssertionFailed,
+    errCannotGenerateCodeForX,
+    errXNeedsReturnType,
+    errXRequiresOneArgument,
+    errUnhandledExceptionX,
+    errCyclicTree,
     errUser,
     warnCannotOpenFile,
     warnOctalEscape,
@@ -291,6 +301,8 @@ type
     hintMo2FileInvalid,
     hintModuleHasChanged,
     hintCannotOpenMo2File,
+    hintQuitCalled,
+    hintProcessing,
     hintUser);
 
 const
@@ -310,7 +322,7 @@ const
     'invalid token: $1',
     'line too long',
     '$1 is not a valid number',
-    '$1 is too large or too small',
+    'number $1 out of valid range',
     '\n not allowed in character literal',
     'closing '']'' expected, but end of file reached',
     'missing final ''',
@@ -319,10 +331,6 @@ const
     '''$1'' expected',
     'string after ''include'' expected',
     'recursive include file: ''$1''',
-    '''@if'' expected',
-    '''@if'' expected before ''@else''',
-    '''@if'' expected before ''@elif''',
-    '''@end'' expected',
     '''on'' or ''off'' expected',
     '''none'', ''speed'' or ''size'' expected',
     'invalid pragma',
@@ -431,12 +439,12 @@ const
     'computing the type''s size produced an overflow',
     'set is too large',
     'base type of a set must be an ordinal',
-    'inheritance only works with an object',
+    'inheritance only works non-final objects',
     'inheritance only works with an enum',
     'illegal recursion in type ''$1''',
     'cannot instantiate: ''$1''',
     'expression has no address',
-    'to an out parameter a variable needs to be passed',
+    'for a ''var'' type a variable needs to be passed',
     'type mismatch',
     'type mismatch: got (',
     'but expected one of: ',
@@ -512,6 +520,20 @@ const
     'whitespace expected, got ''$1''',
     '''$1'' is no valid index file',
     'cannot render reStructuredText element ''$1''',
+    'type ''var var'' is not allowed',
+    '''is'' expects two arguments',
+    '''is'' expects object types',
+    '''$1'' can never be of this subtype',
+    'interpretation requires too many iterations',
+    'cannot interpret node kind ''$1''',
+    'field ''$1'' cannot be found',
+    'invalid conversion from type ''$1''',
+    'assertion failed',
+    'cannot generate code for ''$1''',
+    'converter needs return type',
+    'converter requires one parameter',
+    'unhandled exception: $1',
+    'macro returned a cyclic abstract syntax tree',
     '$1',
     'cannot open ''$1'' [CannotOpenFile]',
     'octal escape sequences do not exist; leading zero is ignored [OctalEscape]',
@@ -536,6 +558,8 @@ const
     'mo2 file ''$1'' is invalid [Mo2FileInvalid]',
     'module ''$1'' has been changed [ModuleHasChanged]',
     'mo2 file ''$1'' does not exist [CannotOpenMo2File]',
+    'quit() called [QuitCalled]',
+    'processing [Processing]',
     '$1 [User]'
   );
 const
@@ -556,7 +580,7 @@ const
     'User'
   );
 const
-  HintsToStr: array [0..9] of string = (
+  HintsToStr: array [0..11] of string = (
     'Success',
     'LineTooLong',
     'XDeclaredButNotUsed',
@@ -566,6 +590,8 @@ const
     'Mo2FileInvalid',
     'ModuleHasChanged',
     'CannotOpenMo2File',
+    'QuitCalled',
+    'Processing',
     'User'
   );
 //[[[end]]]
@@ -593,12 +619,7 @@ type
     fileIndex: int32;
   end;
 
-const
-  UnknownLineInfo: TLineInfo = (
-    line: -1;
-    col: -1;
-    fileIndex: -1;
-  );
+function UnknownLineInfo(): TLineInfo;
 
 var
   gNotes: TNoteKinds = [low(TNoteKind)..high(TNoteKind)];
@@ -649,6 +670,13 @@ procedure popInfoContext;
 
 implementation
 
+function UnknownLineInfo(): TLineInfo;
+begin
+  result.line := -1;
+  result.col := -1;
+  result.fileIndex := -1;
+end;
+
 {@ignore}
 var
   filenames: array of string;
@@ -781,13 +809,14 @@ end;
 
 procedure handleError(const msg: TMsgKind);
 begin
-  if (msg >= fatalMin) and (msg <= fatalMax) then begin 
-    assert(false); halt(1) 
+  if (msg >= fatalMin) and (msg <= fatalMax) then begin
+    if optVerbose in gGlobalOptions then assert(false);
+    halt(1)
   end;
   if (msg >= errMin) and (msg <= errMax) then begin
     inc(gErrorCounter);
     if gErrorCounter >= gErrorMax then begin
-      assert(false); // stack trace for debugging
+      if optVerbose in gGlobalOptions then assert(false);
       halt(1) // one error stops the compiler
     end
   end
@@ -797,7 +826,7 @@ procedure writeContext;
 var
   i: int;
 begin
-  for i := length(msgContext)-1 downto 0 do begin
+  for i := 0 to length(msgContext)-1 do begin
     MessageOut(Format(posErrorFormat, [toFilename(msgContext[i]),
                              coordToStr(msgContext[i].line),
                              coordToStr(msgContext[i].col),
diff --git a/nim/nimconf.pas b/nim/nimconf.pas
index dd29684f6..5a4a13702 100644
--- a/nim/nimconf.pas
+++ b/nim/nimconf.pas
@@ -101,7 +101,7 @@ var
 
 procedure doEnd(var L: TLexer; tok: PToken);
 begin
-  if high(condStack) < 0 then lexMessage(L, errAtIfExpected);
+  if high(condStack) < 0 then lexMessage(L, errTokenExpected, '@if');
   ppGetTok(L, tok); // skip 'end'
   setLength(condStack, high(condStack))
 end;
@@ -114,7 +114,7 @@ procedure jumpToDirective(var L: TLexer; tok: PToken; dest: TJumpDest); forward;
 procedure doElse(var L: TLexer; tok: PToken);
 begin
   if high(condStack) < 0 then
-    lexMessage(L, errAtIfExpectedBeforeElse);
+    lexMessage(L, errTokenExpected, '@if');
   ppGetTok(L, tok);
   if tok.tokType = tkColon then ppGetTok(L, tok);
   if condStack[high(condStack)] then
@@ -126,7 +126,7 @@ var
   res: bool;
 begin
   if high(condStack) < 0 then
-    lexMessage(L, errAtIfExpectedBeforeElif);
+    lexMessage(L, errTokenExpected, '@if');
   res := EvalppIf(L, tok);
   if condStack[high(condStack)] or not res then
     jumpToDirective(L, tok, jdElseEndif)
@@ -168,7 +168,7 @@ begin
       ppGetTok(L, tok)
     end
     else if tok.tokType = tkEof then
-      lexMessage(L, errAtEndExpected)
+      lexMessage(L, errTokenExpected, '@end')
     else
       ppGetTok(L, tok)
   end
@@ -303,7 +303,7 @@ begin
     while tok.tokType <> tkEof do
       parseAssignment(L, tok);
     if length(condStack) > 0 then
-      lexMessage(L, errAtEndExpected);
+      lexMessage(L, errTokenExpected, '@end');
     closeLexer(L)
   end
 end;
diff --git a/nim/nimrod.pas b/nim/nimrod.pas
index 7f8512984..5d3785af4 100644
--- a/nim/nimrod.pas
+++ b/nim/nimrod.pas
@@ -6,7 +6,7 @@
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
 //
-program nim;
+program nimrod;
 
 {$include 'config.inc'}
 {@ignore}
@@ -18,39 +18,37 @@ program nim;
 uses
   nsystem,
   charsets, sysutils, commands, scanner, condsyms, options, msgs, nversion,
-  nimconf, ropes, extccomp, strutils, nos, platform, main;
+  nimconf, ropes, extccomp, strutils, nos, platform, main, parseopt;
 
 var
   arguments: string = ''; // the arguments to be passed to the program that
                           // should be run
+  cmdLineInfo: TLineInfo;
 
-function ProcessCmdLine(pass: TCmdLinePass): string;
+procedure ProcessCmdLine(pass: TCmdLinePass; var command, filename: string);
 var
-  i, paramCounter: int;
-  param: string;
+  p: TOptParser;
 begin
-  i := 1;
-  result := '';
-  paramCounter := paramCount();
-  while i <= paramCounter do begin
-    param := ParamStr(i);
-    if param[strStart] = '-' then begin
-      commands.ProcessCommand(param, pass);
+  p := parseopt.init();
+  while true do begin
+    parseopt.next(p);
+    case p.kind of
+      cmdEnd: break;
+      cmdLongOption, cmdShortOption:
+        ProcessSwitch(p.key, p.val, pass, cmdLineInfo);
+      cmdArgument: begin
+        if command = '' then command := p.key
+        else if filename = '' then begin
+          filename := unixToNativePath(p.key);
+          // BUGFIX for portable build scripts
+          break
+        end
+      end
     end
-    else if i > 1 then begin
-      result := unixToNativePath(param); // BUGFIX for portable build scripts
-      options.compilerArgs := i;
-      break // do not process the arguments
-    end;
-    Inc(i)
   end;
-  inc(i); // skip program file
   // collect the arguments:
   if pass = passCmd2 then begin
-    while i <= paramCounter do begin
-      arguments := arguments + ' ' +{&} paramStr(i);
-      inc(i)
-    end;
+    arguments := getRestOfCommandLine(p);
     if not (optRun in gGlobalOptions) and (arguments <> '') then
       rawMessage(errArgsNeedRunOption);
   end
@@ -58,42 +56,36 @@ end;
 
 procedure HandleCmdLine;
 var
-  inp: string;
+  command, filename: string;
 begin
   if paramCount() = 0 then
     writeCommandLineUsage()
   else begin
     // Process command line arguments:
-    inp := ProcessCmdLine(passCmd1);
-    if inp <> '' then begin
+    command := '';
+    filename := '';
+    ProcessCmdLine(passCmd1, command, filename);
+    if filename <> '' then begin
       if gCmd = cmdInterpret then DefineSymbol('interpreting');
-      nimconf.LoadConfig(inp); // load the right config file
+      nimconf.LoadConfig(filename); // load the right config file
       // now process command line arguments again, because some options in the
       // command line can overwite the config file's settings
       extccomp.initVars();
-      inp := ProcessCmdLine(passCmd2);
+      command := '';
+      filename := '';
+      ProcessCmdLine(passCmd2, command, filename);
     end;
-    MainCommand(paramStr(1), inp);
+    MainCommand(command, filename);
     if (gCmd <> cmdInterpret) and (msgs.gErrorCounter = 0) then
       rawMessage(hintSuccess);
     if optRun in gGlobalOptions then
-      execExternalProgram(changeFileExt(inp, '') +{&} arguments)
+      execExternalProgram(changeFileExt(filename, '') +{&} ' ' +{&} arguments)
   end
 end;
 
-{@ignore}
-var
-  Saved8087CW: Word;
-{@emit}
 begin
-{@ignore}
-  Saved8087CW := Default8087CW;
-  Set8087CW($133f); // Disable all fpu exceptions
-{@emit}
+  cmdLineInfo := newLineInfo('command line', -1, -1);
   condsyms.InitDefines();
   HandleCmdLine();
-{@ignore}
-  Set8087CW(Saved8087CW);
-{@emit}
   halt(options.gExitcode);
 end.
diff --git a/nim/nimsets.pas b/nim/nimsets.pas
index 2b8dff20a..04ec943e7 100644
--- a/nim/nimsets.pas
+++ b/nim/nimsets.pas
@@ -49,7 +49,7 @@ function inSet(s: PNode; const elem: PNode): Boolean;
 var
   i: int;
 begin
-  assert(s.kind in [nkSetConstr, nkConstSetConstr]);
+  if s.kind <> nkCurly then InternalError(s.info, 'inSet');
   for i := 0 to sonsLen(s)-1 do
     if s.sons[i].kind = nkRange then begin
       if leValue(s.sons[i].sons[0], elem)
@@ -95,7 +95,7 @@ function SomeInSet(s: PNode; const a, b: PNode): Boolean;
 var
   i: int;
 begin
-  assert(s.kind in [nkSetConstr, nkConstSetConstr]);
+  if s.kind <> nkCurly then InternalError(s.info, 'SomeInSet');
   for i := 0 to sonsLen(s)-1 do
     if s.sons[i].kind = nkRange then begin
       if leValue(s.sons[i].sons[0], b)     
@@ -142,7 +142,7 @@ var
 begin
   elemType := settype.sons[0];
   first := firstOrd(elemType);
-  result := newNode(nkConstSetConstr);
+  result := newNode(nkCurly);
   result.typ := settype;
   result.info := info;
 
@@ -244,7 +244,7 @@ function SetHasRange(s: PNode): Boolean;
 var
   i: int;
 begin
-  assert(s.kind in [nkSetConstr, nkConstSetConstr]);
+  if s.kind <> nkCurly then InternalError(s.info, 'SetHasRange');
   for i := 0 to sonsLen(s)-1 do
     if s.sons[i].kind = nkRange then begin
       result := true; exit
diff --git a/nim/nos.pas b/nim/nos.pas
index bafa28d43..b4c77681b 100644
--- a/nim/nos.pas
+++ b/nim/nos.pas
@@ -22,8 +22,8 @@ uses
 {$ifdef mswindows}
   windows,
 {$else}
-  unix,
   dos,
+  unix,
 {$endif}
   strutils,
   nsystem;
@@ -83,23 +83,23 @@ function sameFile(const path1, path2: string): boolean;
 
 implementation
 
-function expandFilename(filename: string): string;
+function UnixToNativePath(const path: string): string;
 begin
-  result := sysutils.expandFilename(filename)
+  if dirSep <> '/' then
+    result := replaceStr(path, '/', dirSep)
+  else
+    result := path;
 end;
 
-function sameFile(const path1, path2: string): boolean;
+function expandFilename(filename: string): string;
 begin
-  result := cmpIgnoreCase(expandFilename(path1),
-                          expandFilename(path2)) = 0;
+  result := sysutils.expandFilename(filename)
 end;
 
-function UnixToNativePath(const path: string): string;
+function sameFile(const path1, path2: string): boolean;
 begin
-  if dirSep <> '/' then
-    result := replaceStr(path, '/', dirSep)
-  else
-    result := path;
+  result := cmpIgnoreCase(expandFilename(UnixToNativePath(path1)),
+                          expandFilename(UnixToNativePath(path2))) = 0;
 end;
 
 procedure createDir(dir: string);
@@ -417,8 +417,9 @@ begin
   SI.hStdError := GetStdHandle(STD_ERROR_HANDLE);
   SI.hStdInput := GetStdHandle(STD_INPUT_HANDLE);
   SI.hStdOutput := GetStdHandle(STD_OUTPUT_HANDLE);
-  if not Windows.CreateProcess(nil, PChar(cmd), nil, nil, true,
-    NORMAL_PRIORITY_CLASS, Windows.GetEnvironmentStrings(), nil, SI, ProcInfo)
+  if not Windows.CreateProcess(nil, PChar(cmd), nil, nil, false,
+    NORMAL_PRIORITY_CLASS, nil {Windows.GetEnvironmentStrings()},
+    nil, SI, ProcInfo)
   then
     result := getLastError()
   else begin
@@ -435,11 +436,19 @@ begin
 end;
 
 {$else}
+  {$ifdef windows}
+function executeProcess(const cmd: string): int;
+begin
+  result := dos.Exec(cmd, '')
+end;
+//C:\Eigenes\compiler\MinGW\bin;
+  {$else}
 // fpc has a portable function for this
 function executeProcess(const cmd: string): int;
 begin
   result := shell(cmd);
 end;
+  {$endif}
 {$endif}
 
 {$ifdef windows}
diff --git a/nim/nsystem.pas b/nim/nsystem.pas
index 0b8b897c2..9f3adfc7d 100644
--- a/nim/nsystem.pas
+++ b/nim/nsystem.pas
@@ -90,10 +90,11 @@ type
   TAddress = longint;
 {$endif}
 
+var
+  NaN: float;
+  inf: float;
+  NegInf: float;
 {$ifdef fpc}
-const
-  inf = math.Infinity;
-  NegInf = -inf;
 {$else}
   {$ifopt Q+}
     {$define Q_on}
@@ -150,6 +151,10 @@ function shlU(a, b: biggestInt): biggestInt;
 function shrU(a, b: biggestInt): biggestInt;
 function ltU(a, b: biggestInt): bool;
 function leU(a, b: biggestInt): bool;
+
+function toU8(a: biggestInt): byte;
+function toU32(a: biggestInt): int32;
+function ze64(a: byte): biggestInt;
 {@emit}
 
 function alloc(size: int): Pointer;
@@ -257,6 +262,23 @@ function leU(a, b: biggestInt): bool;
 begin
   result := biggestUInt(a) < biggestUInt(b);
 end;
+
+function toU8(a: biggestInt): byte;
+begin
+  assert(a >= 0);
+  assert(a <= 255);
+  result := a;
+end;
+
+function toU32(a: biggestInt): int32;
+begin
+  result := int32(a and $ffffffff);
+end;
+
+function ze64(a: byte): biggestInt;
+begin
+  result := a
+end;
 {@emit}
 
 procedure addChar(var s: string; c: Char);
@@ -486,4 +508,21 @@ end;
 
 {$ifdef I_on} {$undef I_on} {$I+} {$endif}
 
+{$ifopt R+} {$R-,Q-} {$define R_on} {$endif}
+var
+  zero: float;
+  Saved8087CW: Word;
+initialization
+  Saved8087CW := Default8087CW;
+  Set8087CW($133f); // Disable all fpu exceptions
+
+  zero := 0.0;
+  NaN := 0.0 / zero;
+  inf := 1.0 / zero;
+  NegInf := -inf;
+finalization
+  Set8087CW(Saved8087CW);
+{$ifdef R_on}
+  {$R+,Q+}
+{$endif}
 end.
diff --git a/nim/nversion.pas b/nim/nversion.pas
index 6b6ee6169..4958353f8 100644
--- a/nim/nversion.pas
+++ b/nim/nversion.pas
@@ -1,41 +1,51 @@
-//

-//

-//           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

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

-  //ver = NIMROD_VERSION.split('.')

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

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

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

-  //]]]

-  VersionAsString = '0.5.1';

-  VersionMajor = 0;

-  VersionMinor = 5;

-  VersionPatch = 1;

-  //[[[[end]]]]

-

-implementation

-

-end.

+//
+//
+//           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;
+
+// the Pascal version number gets a little star ('*'), the Nimrod version
+// does not! This helps distinguishing the different builds.
+{@ignore}
+const
+  VersionStar = '*'+'';
+{@emit
+const
+  VersionStar = '';
+}
+
+const
+  MaxSetElements = 1 shl 16; // (2^16) to support unicode character sets?
+  defaultAsmMarkerSymbol = '!';
+
+  //[[[cog
+  //from koch import NIMROD_VERSION
+  //cog.outl("VersionAsString = '%s'+VersionStar;" % NIMROD_VERSION)
+  //ver = NIMROD_VERSION.split('.')
+  //cog.outl('VersionMajor = %s;' % ver[0])
+  //cog.outl('VersionMinor = %s;' % ver[1])
+  //cog.outl('VersionPatch = %s;' % ver[2])
+  //]]]
+  VersionAsString = '0.6.0'+VersionStar;
+  VersionMajor = 0;
+  VersionMinor = 6;
+  VersionPatch = 0;
+  //[[[[end]]]]
+
+implementation
+
+end.
diff --git a/nim/optast.pas b/nim/optast.pas
new file mode 100644
index 000000000..9f66a53db
--- /dev/null
+++ b/nim/optast.pas
@@ -0,0 +1,34 @@
+//
+//
+//           The Nimrod Compiler
+//        (c) Copyright 2008 Andreas Rumpf
+//
+//    See the file "copying.txt", included in this
+//    distribution, for details about the copyright.
+//
+
+unit optast;
+
+// Optimizations that can be done by AST transformations. The code generators
+// should work without the optimizer. The optimizer does the following:
+
+// - cross-module constant merging
+// - cross-module generic merging
+// - lowers set operations to bit operations
+// - inlining of procs
+// - ``s == ""`` --> ``len(s) == 0``
+// - optimization of ``&`` string operator
+
+interface
+
+{$include 'config.inc'}
+
+uses
+  nsystem, ast, astalgo, strutils, hashes, trees, treetab, platform, magicsys,
+  options, msgs, crc, idents, lists, types, ropes, nmath, wordrecg, rnimsyn;
+  
+implementation
+
+
+end.
+
diff --git a/nim/options.pas b/nim/options.pas
index e7ec0a1ce..93b56c330 100644
--- a/nim/options.pas
+++ b/nim/options.pas
@@ -13,12 +13,14 @@ interface
 {$include 'config.inc'}
 
 uses
-  nsystem, nos, lists, strutils;
+  nsystem, nos, lists, strutils, strtabs;
 
 type
   // please make sure we have under 32 options
   // (improves code efficiency a lot!)
-  TOption = (optNone, optRangeCheck,
+  TOption = (optNone,
+    optObjCheck,
+    optFieldCheck, optRangeCheck,
     optBoundsCheck, optOverflowCheck, optNilCheck, optAssert, optLineDir,
     optWarns, optHints,
     optOptimizeSpeed,
@@ -56,6 +58,7 @@ type
     cmdNone,
     cmdCompileToC,
     cmdCompileToCpp,
+    cmdCompileToEcmaScript,
     cmdInterpret,
     cmdPretty,
     cmdDoc,
@@ -69,32 +72,27 @@ type
     cmdDebugTrans, // debug a transformation pass
     cmdRst2html    // convert a reStructuredText file to HTML
   );
-
-  TNumericalBase = (base10, // base10 is listed as the first element,
-                            // so that it is the correct default value
-                    base2,
-                    base8,
-                    base16);
-
+  TStringSeq = array of string;
 
 const
-  ChecksOptions = {@set}[optRangeCheck, optNilCheck, optOverflowCheck,
-                         optBoundsCheck, optAssert];
+  ChecksOptions = {@set}[optObjCheck, optFieldCheck, optRangeCheck,
+                         optNilCheck, optOverflowCheck, optBoundsCheck,
+                         optAssert];
   optionToStr: array [TOption] of string = (
-    'optNone', 'optRangeCheck',
+    'optNone', 'optObjCheck', 'optFieldCheck', 'optRangeCheck',
     'optBoundsCheck', 'optOverflowCheck', 'optNilCheck', 'optAssert',
     'optLineDir', 'optWarns', 'optHints', 'optOptimizeSpeed',
     'optOptimizeSize', 'optStackTrace', 'optLineTrace', 'optEmdb',
     'optByRef', 'optCheckpoints'
   );
 var
-  gOptions: TOptions = {@set}[optRangeCheck, optBoundsCheck, optOverflowCheck,
+  gOptions: TOptions = {@set}[optObjCheck, optFieldCheck, optRangeCheck,
+                              optBoundsCheck, optOverflowCheck,
                               optAssert, optWarns, optHints, optLineDir,
                               optStackTrace, optLineTrace];
 
   gGlobalOptions: TGlobalOptions = {@set}[optRefcGC];
 
-  compilerArgs: int;
   gExitcode: Byte;
   searchPaths: TLinkedList;
   outFile: string = '';
@@ -124,22 +122,15 @@ function getPrefixDir: string;
 // gets the application directory
 
 // additional configuration variables:
-type
-  TPair = record
-    key, val: string;
-  end;
-  TPairs = array of TPair;
-
-  TStringSeq = array of string;
 var
-  gConfigVars: TPairs = {@ignore} nil {@emit []};
+  gConfigVars: PStringTable;
   libpath: string = '';
   gKeepComments: boolean = true; // whether the parser needs to keep comments
   gImplicitMods: TStringSeq = {@ignore} nil {@emit []};
     // modules that are to be implicitly imported
 
-procedure setConfigVar(const key, val: string);
 function getConfigVar(const key: string): string;
+procedure setConfigVar(const key, val: string);
 
 procedure addImplicitMod(const filename: string);
 
@@ -149,6 +140,16 @@ function binaryStrSearch(const x: array of string; const y: string): int;
 
 implementation
 
+function getConfigVar(const key: string): string;
+begin
+  result := strtabs.get(gConfigVars, key);
+end;
+
+procedure setConfigVar(const key, val: string);
+begin
+  strtabs.put(gConfigVars, key, val);
+end;
+
 function getOutFile(const filename, ext: string): string;
 begin
   if options.outFile <> '' then result := options.outFile
@@ -172,38 +173,6 @@ begin
   SplitPath(appdir, result, bin);
 end;
 
-function getConfigIdx(const key: string): int;
-var
-  i: int;
-begin
-  for i := 0 to high(gConfigVars) do
-    if cmpIgnoreStyle(gConfigVars[i].key, key) = 0 then begin
-      result := i; exit end;
-  result := -1
-end;
-
-function getConfigVar(const key: string): string;
-var
-  i: int;
-begin
-  i := getConfigIdx(key);
-  if i >= 0 then result := gConfigVars[i].val
-  else result := ''
-end;
-
-procedure setConfigVar(const key, val: string);
-var
-  i: int;
-begin
-  i := getConfigIdx(key);
-  if i < 0 then begin
-    i := length(gConfigVars);
-    setLength(gConfigVars, i+1);
-    gConfigVars[i].key := key
-  end;
-  gConfigVars[i].val := val
-end;
-
 function toGeneratedFile(const path, ext: string): string;
 var
   head, tail: string;
@@ -261,4 +230,6 @@ begin
   result := -1
 end;
 
+initialization
+  gConfigVars := newStringTable([], modeStyleInsensitive);
 end.
diff --git a/nim/parsecfg.pas b/nim/parsecfg.pas
new file mode 100644
index 000000000..1f049536d
--- /dev/null
+++ b/nim/parsecfg.pas
@@ -0,0 +1,414 @@
+//
+//
+//            Nimrod's Runtime Library
+//        (c) Copyright 2008 Andreas Rumpf
+//
+//    See the file "copying.txt", included in this
+//    distribution, for details about the copyright.
+//
+unit parsecfg;
+
+// A HIGH-PERFORMANCE configuration file parser;
+// the Nimrod version of this file will become part
+// of the standard library.
+
+interface
+
+{$include 'config.inc'}
+
+uses
+  charsets, nsystem, sysutils, hashes, strutils, lexbase;
+
+type
+  TCfgEventKind = (
+    cfgEof,     // end of file reached
+    cfgSectionStart, // a ``[section]`` has been parsed
+    cfgKeyValuePair, // a ``key=value`` pair has been detected
+    cfgOption, // a ``--key=value`` command line option
+    cfgError   // an error ocurred during parsing; msg contains the 
+               // error message
+  );
+  TCfgEvent = {@ignore} record
+    kind: TCfgEventKind;
+    section: string;
+    key, value: string;
+    msg: string;
+  end;
+  {@emit object(NObject)
+    case kind: TCfgEventKind of
+      cfgSection: (section: string);
+      cfgKeyValuePair, cfgOption: (key, value: string);
+      cfgError: (msg: string);
+  end;}
+  TTokKind = (tkInvalid, tkEof, // order is important here!
+    tkSymbol, tkEquals, tkColon,
+    tkBracketLe, tkBracketRi, tkDashDash
+  );
+  TToken = record          // a token
+    kind: TTokKind;     // the type of the token
+    literal: string;       // the parsed (string) literal
+  end;
+  TParserState = (startState, commaState);
+  TCfgParser = object(TBaseLexer)
+    tok: TToken;
+    state: TParserState;
+    filename: string;
+  end;
+
+function Open(var c: TCfgParser; const filename: string): bool;
+procedure OpenFromBuffer(var c: TCfgParser; const buf: string);
+procedure Close(var c: TCfgParser);
+
+function next(var c: TCfgParser): TCfgEvent;
+
+function getColumn(const c: TCfgParser): int;
+function getLine(const c: TCfgParser): int;
+function getFilename(const c: TCfgParser): string;
+
+implementation
+
+const
+  SymChars: TCharSet = ['a'..'z', 'A'..'Z', '0'..'9', '_', #128..#255];
+
+// ----------------------------------------------------------------------------
+procedure rawGetTok(var c: TCfgParser; var tok: TToken); forward;
+
+function open(var c: TCfgParser; const filename: string): bool;
+begin
+{@ignore}
+  FillChar(c, sizeof(c), 0); // work around Delphi/fpc bug
+{@emit}
+  result := initBaseLexer(c, filename);
+  c.filename := filename;
+  c.state := startState;
+  c.tok.kind := tkInvalid;
+  c.tok.literal := '';
+  if result then rawGetTok(c, c.tok);
+end;
+
+procedure openFromBuffer(var c: TCfgParser; const buf: string);
+begin
+{@ignore}
+  FillChar(c, sizeof(c), 0); // work around Delphi/fpc bug
+{@emit}
+  initBaseLexerFromBuffer(c, buf);
+  c.filename := 'buffer';
+  c.state := startState;
+  c.tok.kind := tkInvalid;
+  c.tok.literal := '';
+  rawGetTok(c, c.tok);
+end;
+
+procedure close(var c: TCfgParser);
+begin
+  deinitBaseLexer(c);
+end;
+
+function getColumn(const c: TCfgParser): int;
+begin
+  result := getColNumber(c, c.bufPos)
+end;
+
+function getLine(const c: TCfgParser): int;
+begin
+  result := c.linenumber
+end;
+
+function getFilename(const c: TCfgParser): string;
+begin
+  result := c.filename
+end;
+
+// ----------------------------------------------------------------------------
+
+procedure handleHexChar(var c: TCfgParser; var xi: int);
+begin
+  case c.buf[c.bufpos] of
+    '0'..'9': begin
+      xi := (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'));
+      inc(c.bufpos);
+    end;
+    'a'..'f': begin
+      xi := (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10);
+      inc(c.bufpos);
+    end;
+    'A'..'F': begin
+      xi := (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10);
+      inc(c.bufpos);
+    end;
+    else begin end // do nothing
+  end
+end;
+
+procedure handleDecChars(var c: TCfgParser; var xi: int);
+begin
+  while c.buf[c.bufpos] in ['0'..'9'] do begin
+    xi := (xi * 10) + (ord(c.buf[c.bufpos]) - ord('0'));
+    inc(c.bufpos);
+  end;
+end;
+
+procedure getEscapedChar(var c: TCfgParser; var tok: TToken);
+var
+  xi: int;
+begin
+  inc(c.bufpos); // skip '\'
+  case c.buf[c.bufpos] of
+    'n', 'N': begin
+      tok.literal := tok.literal +{&} nl;
+      Inc(c.bufpos);
+    end;
+    'r', 'R', 'c', 'C': begin addChar(tok.literal, CR); Inc(c.bufpos); end;
+    'l', 'L': begin addChar(tok.literal, LF); Inc(c.bufpos); end;
+    'f', 'F': begin addChar(tok.literal, FF); inc(c.bufpos); end;
+    'e', 'E': begin addChar(tok.literal, ESC); Inc(c.bufpos); end;
+    'a', 'A': begin addChar(tok.literal, BEL); Inc(c.bufpos); end;
+    'b', 'B': begin addChar(tok.literal, BACKSPACE); Inc(c.bufpos); end;
+    'v', 'V': begin addChar(tok.literal, VT); Inc(c.bufpos); end;
+    't', 'T': begin addChar(tok.literal, Tabulator); Inc(c.bufpos); end;
+    '''', '"': begin addChar(tok.literal, c.buf[c.bufpos]); Inc(c.bufpos); end;
+    '\': begin addChar(tok.literal, '\'); Inc(c.bufpos) end;
+    'x', 'X': begin
+      inc(c.bufpos);
+      xi := 0;
+      handleHexChar(c, xi);
+      handleHexChar(c, xi);
+      addChar(tok.literal, Chr(xi));
+    end;
+    '0'..'9': begin
+      xi := 0;
+      handleDecChars(c, xi);
+      if (xi <= 255) then
+        addChar(tok.literal, Chr(xi))
+      else
+        tok.kind := tkInvalid
+    end
+    else tok.kind := tkInvalid
+  end
+end;
+
+function HandleCRLF(var c: TCfgParser; pos: int): int;
+begin
+  case c.buf[pos] of
+    CR: result := lexbase.HandleCR(c, pos);
+    LF: result := lexbase.HandleLF(c, pos);
+    else result := pos
+  end
+end;
+
+procedure getString(var c: TCfgParser; var tok: TToken; rawMode: Boolean);
+var
+  pos: int;
+  ch: Char;
+  buf: PChar;
+begin
+  pos := c.bufPos + 1; // skip "
+  buf := c.buf; // put `buf` in a register
+  tok.kind := tkSymbol;
+  if (buf[pos] = '"') and (buf[pos+1] = '"') then begin
+    // long string literal:
+    inc(pos, 2); // skip ""
+    // skip leading newline:
+    pos := HandleCRLF(c, pos);
+    repeat
+      case buf[pos] of
+        '"': begin
+          if (buf[pos+1] = '"') and (buf[pos+2] = '"') then
+            break;
+          addChar(tok.literal, '"');
+          Inc(pos)
+        end;
+        CR, LF: begin
+          pos := HandleCRLF(c, pos);
+          tok.literal := tok.literal +{&} nl;
+        end;
+        lexbase.EndOfFile: begin
+          tok.kind := tkInvalid;
+          break
+        end
+        else begin
+          addChar(tok.literal, buf[pos]);
+          Inc(pos)
+        end
+      end
+    until false;
+    c.bufpos := pos + 3 // skip the three """
+  end
+  else begin // ordinary string literal
+    repeat
+      ch := buf[pos];
+      if ch = '"' then begin
+        inc(pos); // skip '"'
+        break
+      end;
+      if ch in [CR, LF, lexbase.EndOfFile] then begin
+        tok.kind := tkInvalid;
+        break
+      end;
+      if (ch = '\') and not rawMode then begin
+        c.bufPos := pos;
+        getEscapedChar(c, tok);
+        pos := c.bufPos;
+      end
+      else begin
+        addChar(tok.literal, ch);
+        Inc(pos)
+      end
+    until false;
+    c.bufpos := pos;
+  end
+end;
+
+procedure getSymbol(var c: TCfgParser; var tok: TToken);
+var
+  pos: int;
+  buf: pchar;
+begin
+  pos := c.bufpos;
+  buf := c.buf;
+  while true do begin
+    addChar(tok.literal, buf[pos]);
+    Inc(pos);
+    if not (buf[pos] in SymChars) then break;
+  end;
+  c.bufpos := pos;
+  tok.kind := tkSymbol
+end;
+
+procedure skip(var c: TCfgParser);
+var
+  buf: PChar;
+  pos: int;
+begin
+  pos := c.bufpos;
+  buf := c.buf;
+  repeat
+    case buf[pos] of
+      ' ': Inc(pos);
+      Tabulator: inc(pos); 
+      '#', ';': while not (buf[pos] in [CR, LF, lexbase.EndOfFile]) do inc(pos);
+      CR, LF: pos := HandleCRLF(c, pos);
+      else break // EndOfFile also leaves the loop
+    end
+  until false;
+  c.bufpos := pos;
+end;
+
+procedure rawGetTok(var c: TCfgParser; var tok: TToken);
+begin
+  tok.kind := tkInvalid;
+  setLength(tok.literal, 0);
+  skip(c);
+  case c.buf[c.bufpos] of
+    '=': begin
+      tok.kind := tkEquals;
+      inc(c.bufpos);
+      tok.literal := '='+'';
+    end;
+    '-': begin
+      inc(c.bufPos);
+      if c.buf[c.bufPos] = '-' then inc(c.bufPos);
+      tok.kind := tkDashDash;
+      tok.literal := '--';
+    end;
+    ':': begin
+      tok.kind := tkColon;
+      inc(c.bufpos);
+      tok.literal := ':'+'';
+    end;
+    'r', 'R': begin
+      if c.buf[c.bufPos+1] = '"' then begin
+        Inc(c.bufPos);
+        getString(c, tok, true);
+      end
+      else 
+        getSymbol(c, tok);
+    end;
+    '[': begin
+      tok.kind := tkBracketLe;
+      inc(c.bufpos);
+      tok.literal := '['+'';
+    end;
+    ']': begin
+      tok.kind := tkBracketRi;
+      Inc(c.bufpos);
+      tok.literal := ']'+'';
+    end;
+    '"': getString(c, tok, false);
+    lexbase.EndOfFile: tok.kind := tkEof;
+    else getSymbol(c, tok);
+  end
+end;
+
+function errorStr(const c: TCfgParser; const msg: string): string;
+begin
+  result := format('$1($2, $3) Error: $4', [
+    c.filename, toString(getLine(c)), toString(getColumn(c)), 
+    msg
+  ]);
+end;
+
+function getKeyValPair(var c: TCfgParser; kind: TCfgEventKind): TCfgEvent;
+begin
+  if c.tok.kind = tkSymbol then begin
+    result.kind := kind;
+    result.key := c.tok.literal;
+    result.value := '';
+    rawGetTok(c, c.tok);
+    if c.tok.kind in [tkEquals, tkColon] then begin
+      rawGetTok(c, c.tok);
+      if c.tok.kind = tkSymbol then begin
+        result.value := c.tok.literal;
+      end
+      else begin
+        result.kind := cfgError;
+        result.msg := errorStr(c, 'symbol expected, but found: ' 
+                               + c.tok.literal);
+      end;
+      rawGetTok(c, c.tok);
+    end
+  end
+  else begin
+    result.kind := cfgError;
+    result.msg := errorStr(c, 'symbol expected, but found: ' + c.tok.literal);
+    rawGetTok(c, c.tok);
+  end;
+end;
+
+function next(var c: TCfgParser): TCfgEvent;
+begin
+  case c.tok.kind of
+    tkEof: result.kind := cfgEof;
+    tkDashDash: begin
+      rawGetTok(c, c.tok);
+      result := getKeyValPair(c, cfgOption);
+    end;
+    tkSymbol: begin
+      result := getKeyValPair(c, cfgKeyValuePair);
+    end;
+    tkBracketLe: begin
+      rawGetTok(c, c.tok);
+      if c.tok.kind = tkSymbol then begin
+        result.kind := cfgSectionStart;
+        result.section := c.tok.literal;
+      end
+      else begin
+        result.kind := cfgError;
+        result.msg := errorStr(c, 'symbol expected, but found: ' + c.tok.literal);
+      end;
+      rawGetTok(c, c.tok);
+      if c.tok.kind = tkBracketRi then rawGetTok(c, c.tok)
+      else begin
+        result.kind := cfgError;
+        result.msg := errorStr(c, ''']'' expected, but found: ' + c.tok.literal);      
+      end
+    end;
+    tkInvalid, tkEquals, tkColon: begin
+      result.kind := cfgError;
+      result.msg := errorStr(c, 'invalid token: ' + c.tok.literal);
+      rawGetTok(c, c.tok);
+    end
+  end
+end;
+
+end.
diff --git a/nim/parseopt.pas b/nim/parseopt.pas
new file mode 100644
index 000000000..d543b998e
--- /dev/null
+++ b/nim/parseopt.pas
@@ -0,0 +1,153 @@
+//
+//
+//            Nimrod's Runtime Library
+//        (c) Copyright 2008 Andreas Rumpf
+//
+//    See the file "copying.txt", included in this
+//    distribution, for details about the copyright.
+//
+unit parseopt;
+
+// A command line parser; the Nimrod version of this file
+// will become part of the standard library.
+
+interface
+
+{$include 'config.inc'}
+
+uses
+  nsystem, charsets, nos, strutils;
+
+type
+  TCmdLineKind = (
+    cmdEnd,          // end of command line reached
+    cmdArgument,     // argument detected
+    cmdLongoption,   // a long option ``--option`` detected
+    cmdShortOption   // a short option ``-c`` detected
+  );
+  TOptParser = object(NObject)
+    cmd: string;
+    pos: int;
+    inShortState: bool;
+    kind: TCmdLineKind;
+    key, val: string;
+  end;
+
+function init(const cmdline: string = ''): TOptParser;
+procedure next(var p: TOptParser);
+
+function getRestOfCommandLine(const p: TOptParser): string;
+
+implementation
+
+function init(const cmdline: string = ''): TOptParser;
+var
+  i: int;
+begin
+  result.pos := strStart;
+  result.inShortState := false;
+  if cmdline <> '' then
+    result.cmd := cmdline
+  else begin
+    result.cmd := '';
+    for i := 1 to ParamCount() do
+      result.cmd := result.cmd +{&} quoteIfSpaceExists(paramStr(i)) +{&} ' ';
+  {@ignore}
+    result.cmd := result.cmd + #0;
+  {@emit}
+  end;
+  result.kind := cmdEnd;
+  result.key := '';
+  result.val := '';
+end;
+
+function parseWord(const s: string; const i: int; var w: string;
+          const delim: TCharSet = {@set}[#9, ' ', #0]): int;
+begin
+  result := i;
+  if s[result] = '"' then begin
+    inc(result);
+    while not (s[result] in [#0, '"']) do begin
+      addChar(w, s[result]);
+      inc(result);
+    end;
+    if s[result] = '"' then inc(result)
+  end
+  else begin
+    while not (s[result] in delim) do begin
+      addChar(w, s[result]);
+      inc(result);
+    end
+  end
+end;
+
+procedure handleShortOption(var p: TOptParser);
+var
+  i: int;
+begin
+  i := p.pos;
+  p.kind := cmdShortOption;
+  addChar(p.key, p.cmd[i]);
+  inc(i);
+  p.inShortState := true;
+  while p.cmd[i] in [#9, ' '] do begin
+    inc(i);
+    p.inShortState := false;
+  end;
+  if p.cmd[i] in [':', '='] then begin
+    inc(i); p.inShortState := false;
+    while p.cmd[i] in [#9, ' '] do inc(i);
+    i := parseWord(p.cmd, i, p.val);
+  end;
+  if p.cmd[i] = #0 then p.inShortState := false;
+  p.pos := i;
+end;
+
+procedure next(var p: TOptParser);
+var
+  i: int;
+begin
+  i := p.pos;
+  while p.cmd[i] in [#9, ' '] do inc(i);
+  p.pos := i;
+  setLength(p.key, 0);
+  setLength(p.val, 0);
+  if p.inShortState then begin
+    handleShortOption(p); exit
+  end;
+  case p.cmd[i] of
+    #0: p.kind := cmdEnd;
+    '-': begin
+      inc(i);
+      if p.cmd[i] = '-' then begin
+        p.kind := cmdLongOption;
+        inc(i);
+        i := parseWord(p.cmd, i, p.key, {@set}[#0, ' ', #9, ':', '=']);
+        while p.cmd[i] in [#9, ' '] do inc(i);
+        if p.cmd[i] in [':', '='] then begin
+          inc(i);
+          while p.cmd[i] in [#9, ' '] do inc(i);
+          p.pos := parseWord(p.cmd, i, p.val);
+        end
+        else
+          p.pos := i;
+      end
+      else begin
+        p.pos := i;
+        handleShortOption(p)
+      end
+    end;
+    else begin
+      p.kind := cmdArgument;
+      p.pos := parseWord(p.cmd, i, p.key);
+    end
+  end
+end;
+
+function getRestOfCommandLine(const p: TOptParser): string;
+begin
+  result := strip(ncopy(p.cmd, p.pos+strStart, length(p.cmd)-1))
+  // always -1, because Pascal version uses a trailing zero here
+end;
+
+end.
diff --git a/nim/paslex.pas b/nim/paslex.pas
index 5b90a6138..c7aa6e19a 100644
--- a/nim/paslex.pas
+++ b/nim/paslex.pas
@@ -70,6 +70,7 @@ type
     pxSymbol,    // a symbol
 
     pxIntLit,
+    pxInt64Lit,  // long constant like 0x00000070fffffff or out of int range
     pxFloatLit,
 
     pxParLe, pxParRi, pxBracketLe, pxBracketRi,
@@ -110,7 +111,8 @@ const
     'with', 'xor', 
     //[[[end]]]
     'pxComment', 'pxCommand',
-    '{&}', '{%}', 'pxStrLit', '[IDENTIFIER]', 'pxIntLit', 'pxFloatLit',
+    '{&}', '{%}', 'pxStrLit', '[IDENTIFIER]', 'pxIntLit', 'pxInt64Lit',
+    'pxFloatLit',
     '('+'', ')'+'', '['+'', ']'+'',
     ','+'', ';'+'', ':'+'',
     ':=', '='+'', '.'+'', '..', '^'+'', '+'+'', '-'+'', '*'+'', '/'+'',
@@ -135,7 +137,7 @@ implementation
 function pastokToStr(const tok: TPasTok): string;
 begin
   case tok.xkind of
-    pxIntLit:
+    pxIntLit, pxInt64Lit:
       result := toString(tok.iNumber);
     pxFloatLit:
       result := toStringF(tok.fNumber);
@@ -271,7 +273,7 @@ end;
 
 procedure getNumber2(var L: TPasLex; var tok: TPasTok);
 var
-  pos: int;
+  pos, bits: int;
   xi: biggestInt;
 begin
   pos := L.bufpos+1; // skip %
@@ -284,6 +286,7 @@ begin
 
   tok.base := base2;
   xi := 0;
+  bits := 0;
   while true do begin
     case L.buf[pos] of
       'A'..'Z', 'a'..'z', '2'..'9', '.': begin
@@ -294,23 +297,28 @@ begin
       '0', '1': begin
         xi := (xi shl 1) or (ord(L.buf[pos]) - ord('0'));
         inc(pos);
+        inc(bits);
       end;
       else break;
     end
   end;
   tok.iNumber := xi;
-  tok.xkind := pxIntLit;
+  if (bits > 32) then //or (xi < low(int32)) or (xi > high(int32)) then
+    tok.xkind := pxInt64Lit
+  else
+    tok.xkind := pxIntLit;
   L.bufpos := pos;
 end;
 
 procedure getNumber16(var L: TPasLex; var tok: TPasTok);
 var
-  pos: int;
+  pos, bits: int;
   xi: biggestInt;
 begin
   pos := L.bufpos+1; // skip $
   tok.base := base16;
   xi := 0;
+  bits := 0;
   while true do begin
     case L.buf[pos] of
       'G'..'Z', 'g'..'z', '.': begin
@@ -321,20 +329,26 @@ begin
       '0'..'9': begin
         xi := (xi shl 4) or (ord(L.buf[pos]) - ord('0'));
         inc(pos);
+        inc(bits, 4);
       end;
       'a'..'f': begin
         xi := (xi shl 4) or (ord(L.buf[pos]) - ord('a') + 10);
         inc(pos);
+        inc(bits, 4);
       end;
       'A'..'F': begin
         xi := (xi shl 4) or (ord(L.buf[pos]) - ord('A') + 10);
         inc(pos);
+        inc(bits, 4);
       end;
       else break;
     end
   end;
   tok.iNumber := xi;
-  tok.xkind := pxIntLit;
+  if (bits > 32) then // (xi < low(int32)) or (xi > high(int32)) then
+    tok.xkind := pxInt64Lit
+  else
+    tok.xkind := pxIntLit;
   L.bufpos := pos;
 end;
 
@@ -354,7 +368,10 @@ begin
     end
     else begin
       tok.iNumber := ParseInt(tok.literal);
-      tok.xkind := pxIntLit;
+      if (tok.iNumber < low(int32)) or (tok.iNumber > high(int32)) then
+        tok.xkind := pxInt64Lit
+      else
+        tok.xkind := pxIntLit;
     end;
   except
     on EInvalidValue do
diff --git a/nim/pasparse.pas b/nim/pasparse.pas
index 2d581d81a..357918029 100644
--- a/nim/pasparse.pas
+++ b/nim/pasparse.pas
@@ -322,6 +322,10 @@ begin
     result := newNodeP(nkPtrTy, p);
     getTok(p); eat(p, pxCurlyDirRi);
   end
+  else if p.tok.ident.id = getIdent('tuple').id then begin
+    result := newNodeP(nkTupleTy, p);
+    getTok(p); eat(p, pxCurlyDirRi);
+  end
   else begin
     parMessage(p, errUnknownDirective, pasTokToStr(p.tok));
     while true do begin
@@ -481,6 +485,16 @@ begin
   exprListAux(p, elemKind, endTok, sepTok, result);
 end;
 
+procedure setBaseFlags(n: PNode; base: TNumericalBase);
+begin
+  case base of
+    base10: begin end;
+    base2: include(n.flags, nfBase2);
+    base8: include(n.flags, nfBase8);
+    base16: include(n.flags, nfBase16);
+  end
+end;
+
 function identOrLiteral(var p: TPasParser): PNode;
 var
   a: PNode;
@@ -493,12 +507,17 @@ begin
     // literals
     pxIntLit: begin
       result := newIntNodeP(nkIntLit, p.tok.iNumber, p);
-      result.base := p.tok.base;
+      setBaseFlags(result, p.tok.base);
+      getTok(p);
+    end;
+    pxInt64Lit: begin
+      result := newIntNodeP(nkInt64Lit, p.tok.iNumber, p);
+      setBaseFlags(result, p.tok.base);
       getTok(p);
     end;
     pxFloatLit: begin
       result := newFloatNodeP(nkFloatLit, p.tok.fNumber, p);
-      result.base := p.tok.base;
+      setBaseFlags(result, p.tok.base);
       getTok(p);
     end;
     pxStrLit: begin
@@ -683,8 +702,9 @@ begin
     end
     else begin end
   end;
-  for i := 0 to sonsLen(n)-1 do
-    result.sons[i] := fixExpr(n.sons[i])
+  if not (n.kind in [nkEmpty..nkNilLit]) then
+    for i := 0 to sonsLen(n)-1 do
+      result.sons[i] := fixExpr(n.sons[i])
 end;
 
 function parseExpr(var p: TPasParser): PNode;
@@ -948,6 +968,7 @@ begin
       if p.tok.xkind <> pxIf then begin
         // ordinary else part:
         branch := newNodeP(nkElse, p);
+        skipCom(p, result); // BUGFIX
         addSon(branch, parseStmt(p));
         addSon(result, branch);
         break
@@ -1235,6 +1256,14 @@ begin
         noBody := true;
         getTok(p); opt(p, pxSemicolon);
       end;
+      wNoConv: begin
+        // This is a fake for platform module. There is no ``noconv``
+        // directive in Pascal.
+        if result = nil then result := newNodeP(nkPragma, p);
+        addSon(result, newIdentNodeP(getIdent('noconv'), p));
+        noBody := true;
+        getTok(p); opt(p, pxSemicolon);
+      end;
       wVarargs: begin
         if result = nil then result := newNodeP(nkPragma, p);
         addSon(result, newIdentNodeP(getIdent('varargs'), p));
@@ -1464,7 +1493,7 @@ begin
     nkIdent, nkAccQuoted: begin
       a := newNode(nkPostFix);
       a.info := n.info;
-      addSon(a, newIdentNode(getIdent('*'+'')));
+      addSon(a, newIdentNode(getIdent('*'+''), n.info));
       addSon(a, n);
       n := a
     end;
@@ -1486,7 +1515,7 @@ begin
       end
     end;
     nkRecList, nkRecWhen, nkElse, nkOfBranch, nkElifBranch,
-    nkRecordTy, nkObjectTy: begin
+    nkObjectTy: begin
       for i := 0 to sonsLen(n)-1 do fixRecordDef(n.sons[i])
     end;
     nkIdentDefs: begin
@@ -1497,6 +1526,19 @@ begin
   end
 end;
 
+procedure parseRecordBody(var p: TPasParser; result: PNode);
+var
+  a: PNode;
+begin
+  skipCom(p, result);
+  a := parseRecordPart(p);
+  if result.kind <> nkTupleTy then fixRecordDef(a);
+  addSon(result, a);
+  eat(p, pxEnd);
+  opt(p, pxSemicolon);
+  skipCom(p, result);  
+end;
+
 function parseRecordOrObject(var p: TPasParser; kind: TNodeKind): PNode;
 var
   a: PNode;
@@ -1512,19 +1554,14 @@ begin
     eat(p, pxParRi);
   end
   else addSon(result, nil);
-  skipCom(p, result);
-  a := parseRecordPart(p);
-  fixRecordDef(a);
-  addSon(result, a);
-  eat(p, pxEnd);
-  opt(p, pxSemicolon);
-  skipCom(p, result);
+  parseRecordBody(p, result);
 end;
 
 function parseTypeDesc(var p: TPasParser): PNode;
 var
   oldcontext: TPasContext;
   a, r: PNode;
+  i: int;
 begin
   oldcontext := p.context;
   p.context := conTypeDesc;
@@ -1532,7 +1569,28 @@ begin
   case p.tok.xkind of
     pxCommand: result := parseCommand(p);
     pxProcedure, pxFunction: result := parseRoutineType(p);
-    pxRecord: result := parseRecordOrObject(p, nkRecordTy);
+    pxRecord: begin
+      getTok(p);
+      if p.tok.xkind = pxCommand then begin
+        result := parseCommand(p);
+        if result.kind <> nkTupleTy then 
+          InternalError(result.info, 'parseTypeDesc');
+        parseRecordBody(p, result);
+        a := lastSon(result);
+        // embed nkRecList directly into nkTupleTy
+        for i := 0 to sonsLen(a)-1 do
+          if i = 0 then result.sons[sonsLen(result)-1] := a.sons[0]
+          else addSon(result, a.sons[i]);
+      end
+      else begin
+        result := newNodeP(nkReturnToken, p); 
+        // we use nkReturnToken to signal that this object should be marked as
+        // final
+        addSon(result, nil);
+        addSon(result, nil);
+        parseRecordBody(p, result);
+      end;
+    end;
     pxObject: result := parseRecordOrObject(p, nkObjectTy);
     pxParLe: result := parseEnum(p);
     pxArray: begin
@@ -1591,13 +1649,29 @@ begin
 end;
 
 function parseTypeDef(var p: TPasParser): PNode;
+var
+  a, e, pragmasNode: PNode;
 begin
   result := newNodeP(nkTypeDef, p);
   addSon(result, identVis(p));
   addSon(result, nil); // generic params
   if p.tok.xkind = pxEquals then begin
     getTok(p); skipCom(p, result);
-    addSon(result, parseTypeDesc(p));
+    a := parseTypeDesc(p);
+    addSon(result, a);
+    if a.kind = nkReturnToken then begin // a `final` object?
+      a.kind := nkObjectTy;
+      if result.sons[0].kind <> nkPragmaExpr then begin
+        e := newNodeP(nkPragmaExpr, p);
+        pragmasNode := newNodeP(nkPragma, p);
+        addSon(e, result.sons[0]);
+        addSon(e, pragmasNode);
+        result.sons[0] := e;
+      end
+      else
+        pragmasNode := result.sons[1];
+      addSon(pragmasNode, newIdentNodeP(getIdent('final'), p));
+    end
   end
   else
     addSon(result, nil);
diff --git a/nim/platform.pas b/nim/platform.pas
index 3bb109943..896d7b4a2 100644
--- a/nim/platform.pas
+++ b/nim/platform.pas
@@ -13,7 +13,7 @@ unit platform;
 // Note: Unfortunately if an OS or CPU is listed here this does not mean that
 // Nimrod has been tested on this platform or that the RTL has been ported.
 // Feel free to test for your exentric platform! (Windows on I386 and Linux
-// on AMD64 have been tested, though.)
+// on I386 have been tested, though.)
 
 interface
 
@@ -45,7 +45,8 @@ type
     osAtari,
     osNetware,
     osMacos,
-    osMacosx
+    osMacosx,
+    osEcmaScript
   );
 type
   TInfoOSProp = (
@@ -55,7 +56,7 @@ type
   );
 
   TInfoOSProps = set of TInfoOSProp;
-  TInfoOS = record
+  TInfoOS = record{@tuple}
     name: string;
     parDir: string;
     dllExt: string;
@@ -73,7 +74,7 @@ type
   end;
 const
   OS: array [succ(low(TSystemOS))..high(TSystemOS)] of TInfoOS = (
-  ( 
+  (
     name: 'DOS';
     parDir: '..';
     dllExt: '.dll';
@@ -89,7 +90,7 @@ const
     extSep: '.'+'';
     props: {@set}[ospCaseInsensitive];
   ),
-  ( 
+  (
     name: 'Windows';
     parDir: '..';
     dllExt: '.dll';
@@ -105,7 +106,7 @@ const
     extSep: '.'+'';
     props: {@set}[ospCaseInsensitive];
   ),
-  ( 
+  (
     name: 'OS2';
     parDir: '..';
     dllExt: '.dll';
@@ -121,7 +122,7 @@ const
     extSep: '.'+'';
     props: {@set}[ospCaseInsensitive];
   ),
-  ( 
+  (
     name: 'Linux';
     parDir: '..';
     dllExt: '.so';
@@ -137,7 +138,7 @@ const
     extSep: '.'+'';
     props: {@set}[ospNeedsPIC, ospPosix];
   ),
-  ( 
+  (
     name: 'MorphOS';
     parDir: '..';
     dllExt: '.so';
@@ -153,7 +154,7 @@ const
     extSep: '.'+'';
     props: {@set}[ospNeedsPIC, ospPosix];
   ),
-  ( 
+  (
     name: 'SkyOS';
     parDir: '..';
     dllExt: '.so';
@@ -169,7 +170,7 @@ const
     extSep: '.'+'';
     props: {@set}[ospNeedsPIC, ospPosix];
   ),
-  ( 
+  (
     name: 'Solaris';
     parDir: '..';
     dllExt: '.so';
@@ -185,7 +186,7 @@ const
     extSep: '.'+'';
     props: {@set}[ospNeedsPIC, ospPosix];
   ),
-  ( 
+  (
     name: 'Irix';
     parDir: '..';
     dllExt: '.so';
@@ -201,7 +202,7 @@ const
     extSep: '.'+'';
     props: {@set}[ospNeedsPIC, ospPosix];
   ),
-  ( 
+  (
     name: 'NetBSD';
     parDir: '..';
     dllExt: '.so';
@@ -217,7 +218,7 @@ const
     extSep: '.'+'';
     props: {@set}[ospNeedsPIC, ospPosix];
   ),
-  ( 
+  (
     name: 'FreeBSD';
     parDir: '..';
     dllExt: '.so';
@@ -233,7 +234,7 @@ const
     extSep: '.'+'';
     props: {@set}[ospNeedsPIC, ospPosix];
   ),
-  ( 
+  (
     name: 'OpenBSD';
     parDir: '..';
     dllExt: '.so';
@@ -249,7 +250,7 @@ const
     extSep: '.'+'';
     props: {@set}[ospNeedsPIC, ospPosix];
   ),
-  ( 
+  (
     name: 'PalmOS';
     parDir: '..';
     dllExt: '.so';
@@ -265,7 +266,7 @@ const
     extSep: '.'+'';
     props: {@set}[ospNeedsPIC];
   ),
-  ( 
+  (
     name: 'QNX';
     parDir: '..';
     dllExt: '.so';
@@ -281,7 +282,7 @@ const
     extSep: '.'+'';
     props: {@set}[ospNeedsPIC, ospPosix];
   ),
-  ( 
+  (
     name: 'Amiga';
     parDir: '..';
     dllExt: '.library';
@@ -297,7 +298,7 @@ const
     extSep: '.'+'';
     props: {@set}[ospNeedsPIC];
   ),
-  ( 
+  (
     name: 'Atari';
     parDir: '..';
     dllExt: '.dll';
@@ -313,7 +314,7 @@ const
     extSep: '.'+'';
     props: {@set}[ospNeedsPIC];
   ),
-  ( 
+  (
     name: 'Netware';
     parDir: '..';
     dllExt: '.nlm';
@@ -329,7 +330,7 @@ const
     extSep: '.'+'';
     props: {@set}[ospCaseInsensitive];
   ),
-  ( 
+  (
     name: 'MacOS';
     parDir: '::';
     dllExt: 'Lib';
@@ -345,7 +346,7 @@ const
     extSep: '.'+'';
     props: {@set}[ospCaseInsensitive];
   ),
-  ( 
+  (
     name: 'MacOSX';
     parDir: '..';
     dllExt: '.dylib';
@@ -353,13 +354,29 @@ const
     dllPrefix: 'lib';
     objExt: '.o';
     newLine: #10+'';
-    pathSep: ':'+''; 
+    pathSep: ':'+'';
     dirSep: '/'+'';
     scriptExt: '.sh';
     curDir: '.'+'';
     exeExt: '';
     extSep: '.'+'';
     props: {@set}[ospNeedsPIC, ospPosix];
+  ),
+  (
+    name: 'EcmaScript';
+    parDir: '..';
+    dllExt: '.so';
+    altDirSep: '/'+'';
+    dllPrefix: 'lib';
+    objExt: '.o';
+    newLine: #10+'';
+    pathSep: ':'+'';
+    dirSep: '/'+'';
+    scriptExt: '.sh';
+    curDir: '.'+'';
+    exeExt: '';
+    extSep: '.'+'';
+    props: {@set}[];
   )
 );
 type
@@ -377,11 +394,12 @@ type
     cpuIa64,
     cpuAmd64,
     cpuMips,
-    cpuArm
+    cpuArm,
+    cpuEcmaScript
   );
 type
   TEndian = (littleEndian, bigEndian);
-  TInfoCPU = record
+  TInfoCPU = record{@tuple}
     name: string;
     intSize: int;
     endian: TEndian;
@@ -460,6 +478,13 @@ const
     endian: littleEndian;
     floatSize: 64;
     bit: 32;
+  ),
+  (
+    name: 'ecmascript';
+    intSize: 32;
+    endian: bigEndian;
+    floatSize: 64;
+    bit: 32;
   )
 );
 
@@ -517,9 +542,9 @@ end;
 // this is Ok for the Pascal version, but the Nimrod version needs a different
 // mechanism
 {@emit
-procedure nimCPU(): cstring; importc;}
+procedure nimCPU(): cstring; importc; noconv;}
 {@emit
-procedure nimOS(): cstring; importc;}
+procedure nimOS(): cstring; importc; noconv;}
 
 {@ignore}
 initialization
diff --git a/nim/pnimsyn.pas b/nim/pnimsyn.pas
index 8407804e7..27841229e 100644
--- a/nim/pnimsyn.pas
+++ b/nim/pnimsyn.pas
@@ -240,6 +240,9 @@ begin
 end;
 
 function parseSymbol(var p: TParser): PNode;
+var
+  s: string;
+  id: PIdent;
 begin
   case p.tok.tokType of
     tkSymbol: begin
@@ -251,9 +254,31 @@ begin
       getTok(p);
       case p.tok.tokType of
         tkBracketLe: begin
-          addSon(result, newIdentNodeP(getIdent('[]'), p));
+          s := '['+'';
           getTok(p);
+          if (p.tok.tokType = tkOpr) and (p.tok.ident.s = '$'+'') then begin
+            s := s + '$..';
+            getTok(p);
+            eat(p, tkDotDot);
+            if (p.tok.tokType = tkOpr) and (p.tok.ident.s = '$'+'') then begin
+              s := s + '$'+'';
+              getTok(p);          
+            end;
+          end
+          else if p.tok.tokType = tkDotDot then begin
+            s := s + '..';
+            getTok(p);
+            if (p.tok.tokType = tkOpr) and (p.tok.ident.s = '$'+'') then begin
+              s := s + '$'+'';
+              getTok(p);
+            end;
+          end;
           eat(p, tkBracketRi);
+          s := s + ']'+'';
+          if p.tok.tokType = tkEquals then begin
+            s := s + '='; getTok(p);
+          end;
+          addSon(result, newIdentNodeP(getIdent(s), p));
         end;
         tkParLe: begin
           addSon(result, newIdentNodeP(getIdent('()'), p));
@@ -261,8 +286,14 @@ begin
           eat(p, tkParRi);
         end;
         tokKeywordLow..tokKeywordHigh, tkSymbol, tkOpr: begin
-          addSon(result, newIdentNodeP(p.tok.ident, p));
+          id := p.tok.ident;
           getTok(p);
+          if p.tok.tokType = tkEquals then begin
+            addSon(result, newIdentNodeP(getIdent(id.s + '='), p));
+            getTok(p);
+          end
+          else
+            addSon(result, newIdentNodeP(id, p));
         end;
         else begin
           parMessage(p, errIdentifierExpected, tokToStr(p.tok));
@@ -350,7 +381,7 @@ var
 begin
   case p.tok.tokType of
     tkDotDot: result := dotdotExpr(p);
-    tkVar, tkRef, tkPtr, tkProc, tkType: result := parseTypeDescK(p);
+    tkVar, tkRef, tkPtr, tkProc, tkTuple, tkType: result := parseTypeDescK(p);
     else begin
       a := parseExpr(p);
       case p.tok.tokType of
@@ -519,6 +550,16 @@ begin
   eat(p, tkParRi);
 end;
 
+procedure setBaseFlags(n: PNode; base: TNumericalBase);
+begin
+  case base of
+    base10: begin end;
+    base2: include(n.flags, nfBase2);
+    base8: include(n.flags, nfBase8);
+    base16: include(n.flags, nfBase16);
+  end
+end;
+
 function identOrLiteral(var p: TParser): PNode;
 begin
   case p.tok.tokType of
@@ -530,42 +571,42 @@ begin
     // literals
     tkIntLit: begin
       result := newIntNodeP(nkIntLit, p.tok.iNumber, p);
-      result.base := p.tok.base;
+      setBaseFlags(result, p.tok.base);
       getTok(p);
     end;
     tkInt8Lit: begin
       result := newIntNodeP(nkInt8Lit, p.tok.iNumber, p);
-      result.base := p.tok.base;
+      setBaseFlags(result, p.tok.base);
       getTok(p);
     end;
     tkInt16Lit: begin
       result := newIntNodeP(nkInt16Lit, p.tok.iNumber, p);
-      result.base := p.tok.base;
+      setBaseFlags(result, p.tok.base);
       getTok(p);
     end;
     tkInt32Lit: begin
       result := newIntNodeP(nkInt32Lit, p.tok.iNumber, p);
-      result.base := p.tok.base;
+      setBaseFlags(result, p.tok.base);
       getTok(p);
     end;
     tkInt64Lit: begin
       result := newIntNodeP(nkInt64Lit, p.tok.iNumber, p);
-      result.base := p.tok.base;
+      setBaseFlags(result, p.tok.base);
       getTok(p);
     end;
     tkFloatLit: begin
       result := newFloatNodeP(nkFloatLit, p.tok.fNumber, p);
-      result.base := p.tok.base;
+      setBaseFlags(result, p.tok.base);
       getTok(p);
     end;
     tkFloat32Lit: begin
       result := newFloatNodeP(nkFloat32Lit, p.tok.fNumber, p);
-      result.base := p.tok.base;
+      setBaseFlags(result, p.tok.base);
       getTok(p);
     end;
     tkFloat64Lit: begin
       result := newFloatNodeP(nkFloat64Lit, p.tok.fNumber, p);
-      result.base := p.tok.base;
+      setBaseFlags(result, p.tok.base);
       getTok(p);
     end;
     tkStrLit: begin
@@ -584,10 +625,6 @@ begin
       result := newIntNodeP(nkCharLit, ord(p.tok.literal[strStart]), p);
       getTok(p);
     end;
-    tkRCharLit: begin
-      result := newIntNodeP(nkRCharLit, ord(p.tok.literal[strStart]), p);
-      getTok(p);
-    end;
     tkNil: begin
       result := newNodeP(nkNilLit, p);
       getTok(p);
@@ -598,8 +635,7 @@ begin
                                     tkColon);
     end;
     tkCurlyLe: begin // {} constructor
-      result := exprColonEqExprList(p, nkCurly, nkRange, tkCurlyRi,
-                                    tkDotDot);
+      result := exprColonEqExprList(p, nkCurly, nkRange, tkCurlyRi, tkDotDot);
     end;
     tkBracketLe: begin // [] constructor
       result := exprColonEqExprList(p, nkBracket, nkExprColonExpr, tkBracketRi,
@@ -1278,6 +1314,8 @@ begin
 end;
 
 function parseTypeDescK(var p: TParser): PNode;
+var
+  a: PNode;
 begin
   case p.tok.tokType of
     tkVar: result := parseTypeDescKAux(p, nkVarTy);
@@ -1298,7 +1336,25 @@ begin
         addSon(result, parsePragma(p))
       else
         addSon(result, nil);
-    end
+    end;
+    tkTuple: begin
+      result := newNodeP(nkTupleTy, p);
+      getTok(p);
+      eat(p, tkBracketLe);
+      optInd(p, result);
+      while true do begin
+        case p.tok.tokType of
+          tkSymbol, tkAccent: a := parseIdentColonEquals(p, false);
+          tkBracketRi: begin getTok(p); break end;
+          else begin parMessage(p, errTokenExpected, ']'+''); break; end;
+        end;
+        optInd(p, a);
+        if p.tok.tokType = tkComma then begin
+          getTok(p); optInd(p, a)
+        end;
+        addSon(result, a);
+      end;
+    end;
     else begin
       InternalError(parLineInfo(p), 'pnimsyn.parseTypeDescK');
       result := nil
@@ -1309,7 +1365,7 @@ end;
 function parseTypeDesc(var p: TParser): PNode;
 begin
   case p.tok.tokType of
-    tkVar, tkRef, tkPtr, tkProc, tkType:
+    tkVar, tkRef, tkPtr, tkProc, tkType, tkTuple:
       result := parseTypeDescK(p);
     else result := primary(p)
   end
@@ -1599,7 +1655,7 @@ begin
     if kind = nkObjectTy then
       addSon(result, a)
     else
-      parMessage(p, errInheritanceOnlyWithObjects);
+      parMessage(p, errInheritanceOnlyWithNonFinalObjects);
   end
   else addSon(result, nil);
   skipComment(p, result);
@@ -1617,7 +1673,6 @@ begin
   if p.tok.tokType = tkEquals then begin
     getTok(p); optInd(p, result);
     case p.tok.tokType of
-      tkRecord: a := parseRecordOrObject(p, nkRecordTy);
       tkObject: a := parseRecordOrObject(p, nkObjectTy);
       tkEnum: a := parseEnum(p);
       else a := parseTypeDesc(p);
@@ -1660,22 +1715,23 @@ end;
 function complexOrSimpleStmt(var p: TParser): PNode;
 begin
   case p.tok.tokType of
-    tkIf:       result := parseIfOrWhen(p, nkIfStmt);
-    tkWhile:    result := parseWhile(p);
-    tkCase:     result := parseCase(p);
-    tkTry:      result := parseTry(p);
-    tkFor:      result := parseFor(p);
-    tkBlock:    result := parseBlock(p);
-    tkAsm:      result := parseAsm(p);
-    tkProc:     result := parseRoutine(p, nkProcDef);
-    tkIterator: result := parseRoutine(p, nkIteratorDef);
-    tkMacro:    result := parseRoutine(p, nkMacroDef);
-    tkTemplate: result := parseRoutine(p, nkTemplateDef);
-    tkType:     result := parseSection(p, nkTypeSection, parseTypeDef);
-    tkConst:    result := parseSection(p, nkConstSection, parseConstant);
-    tkWhen:     result := parseIfOrWhen(p, nkWhenStmt);
-    tkVar:      result := parseSection(p, nkVarSection, parseVariable);
-    else        result := simpleStmt(p);
+    tkIf:        result := parseIfOrWhen(p, nkIfStmt);
+    tkWhile:     result := parseWhile(p);
+    tkCase:      result := parseCase(p);
+    tkTry:       result := parseTry(p);
+    tkFor:       result := parseFor(p);
+    tkBlock:     result := parseBlock(p);
+    tkAsm:       result := parseAsm(p);
+    tkProc:      result := parseRoutine(p, nkProcDef);
+    tkIterator:  result := parseRoutine(p, nkIteratorDef);
+    tkMacro:     result := parseRoutine(p, nkMacroDef);
+    tkTemplate:  result := parseRoutine(p, nkTemplateDef);
+    tkConverter: result := parseRoutine(p, nkConverterDef);
+    tkType:      result := parseSection(p, nkTypeSection, parseTypeDef);
+    tkConst:     result := parseSection(p, nkConstSection, parseConstant);
+    tkWhen:      result := parseIfOrWhen(p, nkWhenStmt);
+    tkVar:       result := parseSection(p, nkVarSection, parseVariable);
+    else         result := simpleStmt(p);
   end
 end;
 
diff --git a/nim/pragmas.pas b/nim/pragmas.pas
index f257be390..c3a6c42d2 100644
--- a/nim/pragmas.pas
+++ b/nim/pragmas.pas
@@ -26,10 +26,9 @@ begin
       if (it.kind = nkExprColonExpr) and (it.sons[0].kind = nkIdent) then begin
         case whichKeyword(it.sons[0].ident) of
           wAsmQuote: begin
-            case it.sons[1].kind of
-              nkCharLit, nkRCharLit: result := chr(int(it.sons[1].intVal));
-              else invalidPragma(it)
-            end
+            if it.sons[1].kind = nkCharLit then
+              result := chr(int(it.sons[1].intVal))
+            else invalidPragma(it)
           end
           else
             invalidPragma(it)
@@ -246,6 +245,8 @@ begin
     sw := whichKeyword(n.sons[0].ident);
     case sw of
       wChecks: OnOff(c, n, checksOptions);
+      wObjChecks: OnOff(c, n, {@set}[optObjCheck]);
+      wFieldchecks: OnOff(c, n, {@set}[optFieldCheck]);
       wRangechecks: OnOff(c, n, {@set}[optRangeCheck]);
       wBoundchecks: OnOff(c, n, {@set}[optBoundsCheck]);
       wOverflowchecks: OnOff(c, n, {@set}[optOverflowCheck]);
@@ -373,12 +374,12 @@ begin
   end
 end;
 
-procedure Breakpoint(c: PContext; n: PNode);
+procedure PragmaBreakpoint(c: PContext; n: PNode);
 begin
   {@discard} getOptionalStr(c, n, '');
 end;
 
-procedure Checkpoint(c: PContext; n: PNode);
+procedure PragmaCheckpoint(c: PContext; n: PNode);
 // checkpoints can be used to debug the compiler; they are not documented
 var
   info: TLineInfo;
@@ -427,7 +428,10 @@ begin
               liMessage(it.info, errPowerOfTwoExpected);
           end;
           wNodecl: begin noVal(it); Include(sym.loc.Flags, lfNoDecl); end;
-          wPure: begin noVal(it); include(sym.flags, sfPure); end;
+          wPure: begin
+            noVal(it);
+            if sym <> nil then include(sym.flags, sfPure);
+          end;
           wVolatile: begin noVal(it); Include(sym.flags, sfVolatile); end;
           wRegister: begin noVal(it); include(sym.flags, sfRegister); end;
           wMagic: processMagic(c, it, sym);
@@ -444,7 +448,6 @@ begin
           wNosideeffect: begin noVal(it); Include(sym.flags, sfNoSideEffect); end;
           wNoReturn: begin noVal(it); Include(sym.flags, sfNoReturn); end;
           wDynLib: processDynLib(c, it, sym);
-          wReturnsNew: begin noVal(it); Include(sym.flags, sfReturnsNew); end;
           wCompilerProc: begin
             noVal(it); // compilerproc may not get a string!
             makeExternExport(sym, sym.name.s);
@@ -464,6 +467,14 @@ begin
             noVal(it);
             include(sym.typ.flags, tfVarargs);
           end;
+          wFinal: begin
+            noVal(it);
+            include(sym.typ.flags, tfFinal);
+          end;
+          wTypeCheck: begin
+            noVal(it);
+            include(sym.flags, sfTypeCheck);
+          end;
 
           // statement pragmas:
           wHint: liMessage(it.info, hintUser, expectStrLit(c, it));
@@ -478,6 +489,9 @@ begin
           wCompile: processCompile(c, it);
           wLink: processCommonLink(c, it, linkNormal);
           wLinkSys: processCommonLink(c, it, linkSys);
+          wPassL: extccomp.addLinkOption(expectStrLit(c, it));
+          wPassC: extccomp.addCompileOption(expectStrLit(c, it));
+
           // fixupSystem not even documented:
           wFixupSystem: begin
             if c.module = magicSys.SystemModule then
@@ -485,12 +499,13 @@ begin
             else
               invalidPragma(it)
           end;
-          wBreakpoint: Breakpoint(c, it);
-          wCheckpoint: Checkpoint(c, it);
+          wBreakpoint: PragmaBreakpoint(c, it);
+          wCheckpoint: PragmaCheckpoint(c, it);
 
           wPush: begin processPush(c, n, i+1); break end;
           wPop: processPop(c, it);
-          wChecks, wRangechecks, wBoundchecks, wOverflowchecks, wNilchecks,
+          wChecks, wObjChecks, wFieldChecks,
+          wRangechecks, wBoundchecks, wOverflowchecks, wNilchecks,
           wAssertions, wWarnings, wHints, wLinedir, wStacktrace,
           wLinetrace, wOptimization, wByRef, wCallConv, wDebugger:
             processOption(c, it);
@@ -528,20 +543,28 @@ begin
     wCppMethod, wDeprecated, wVarargs]);
 end;
 
+procedure pragmaMacro(c: PContext; s: PSym; n: PNode);
+begin
+  pragma(c, s, n, {@set}[FirstCallConv..LastCallConv,
+    wImportc, wExportc, wNostatic, wNodecl, wMagic, wNosideEffect,
+    wCompilerProc, wDeprecated, wTypeCheck]);
+end;
+
 procedure pragmaIterator(c: PContext; s: PSym; n: PNode);
 begin
   pragma(c, s, n, {@set}[FirstCallConv..LastCallConv,
          wImportc, wExportc, wNodecl, wMagic, wDeprecated]);
 end;
 
-procedure pragmaStmt(c: PContext; n: PNode);
+procedure pragmaStmt(c: PContext; s: PSym; n: PNode);
 begin
-  pragma(c, nil, n, {@set}[wChecks, wRangechecks, wBoundchecks,
-      wOverflowchecks, wNilchecks, wAssertions, wWarnings,
+  pragma(c, s, n, {@set}[wChecks, wObjChecks, wFieldChecks, wRangechecks,
+      wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings,
       wHints, wLinedir, wStacktrace, wLinetrace, wOptimization,
       wHint, wWarning, wError, wFatal, wDefine, wUndef,
-      wCompile, wLink, wLinkSys,
-      wPush, wPop, wFixupSystem, wBreakpoint, wCheckpoint]);
+      wCompile, wLink, wLinkSys, wPure,
+      wPush, wPop, wFixupSystem, wBreakpoint, wCheckpoint,
+      wPassL, wPassC]);
 end;
 
 procedure pragmaLambda(c: PContext; s: PSym; n: PNode);
@@ -554,7 +577,7 @@ end;
 procedure pragmaType(c: PContext; s: PSym; n: PNode);
 begin
   pragma(c, s, n, {@set}[wImportc, wExportc, wDeprecated, wMagic,
-                         wNodecl, wPure, wHeader, wCompilerProc]);
+                         wNodecl, wPure, wHeader, wCompilerProc, wFinal]);
 end;
 
 procedure pragmaField(c: PContext; s: PSym; n: PNode);
diff --git a/nim/rnimsyn.pas b/nim/rnimsyn.pas
index b4f97e82c..b4ba928fb 100644
--- a/nim/rnimsyn.pas
+++ b/nim/rnimsyn.pas
@@ -16,20 +16,20 @@ unit rnimsyn;
 interface
 
 uses
-  nsystem, charsets, lexbase, scanner, options, idents, strutils, ast, msgs, 
+  nsystem, charsets, lexbase, scanner, options, idents, strutils, ast, msgs,
   lists;
 
 type
   TRenderFlag = (renderNone, renderNoBody, renderNoComments,
                  renderNoPragmas, renderIds);
   TRenderFlags = set of TRenderFlag;
-  
+
   TRenderTok = record
     kind: TTokType;
     len: int16;
   end;
   TRenderTokSeq = array of TRenderTok;
-  
+
   TSrcGen = record
     indent: int;
     lineLen: int;
@@ -390,16 +390,10 @@ function lsub(n: PNode): int; forward;
 
 function litAux(n: PNode; x: biggestInt; size: int): string;
 begin
-  case n.base of
-    base10: result := toString(x);
-    base2:  result := '0b' + toBin(x, size*8);
-    base8:  result := '0o' + toOct(x, size*3);
-    base16: result := '0x' + toHex(x, size*2);
-    else begin
-      assert(false);
-      result := toString(x);
-    end
-  end
+  if nfBase2 in n.flags then result := '0b' + toBin(x, size*8)
+  else if nfBase8 in n.flags then result := '0o' + toOct(x, size*3)
+  else if nfBase16 in n.flags then result := '0x' + toHex(x, size*2)
+  else result := toString(x)
 end;
 
 function atom(n: PNode): string;
@@ -414,18 +408,19 @@ begin
     nkRStrLit:      result := 'r"' + n.strVal + '"';
     nkTripleStrLit: result := '"""' + n.strVal + '"""';
     nkCharLit:      result := '''' + toNimChar(chr(int(n.intVal))) + '''';
-    nkRCharLit:     result := 'r''' + chr(int(n.intVal)) + '''';
     nkIntLit:       result := litAux(n, n.intVal, 4);
     nkInt8Lit:      result := litAux(n, n.intVal, 1) + '''i8';
     nkInt16Lit:     result := litAux(n, n.intVal, 2) + '''i16';
     nkInt32Lit:     result := litAux(n, n.intVal, 4) + '''i32';
     nkInt64Lit:     result := litAux(n, n.intVal, 8) + '''i64';
     nkFloatLit:     begin
-      if n.base = base10 then result := toStringF(n.floatVal)
-      else result := litAux(n, ({@cast}PInt64(addr(n.floatVal)))^, 8);
+      if n.flags * [nfBase2, nfBase8, nfBase16] = [] then
+        result := toStringF(n.floatVal)
+      else
+        result := litAux(n, ({@cast}PInt64(addr(n.floatVal)))^, 8);
     end;
     nkFloat32Lit:   begin
-      if n.base = base10 then
+      if n.flags * [nfBase2, nfBase8, nfBase16] = [] then
         result := toStringF(n.floatVal) + '''f32'
       else begin
         f := n.floatVal;
@@ -433,7 +428,7 @@ begin
       end;
     end;
     nkFloat64Lit:   begin
-      if n.base = base10 then
+      if n.flags * [nfBase2, nfBase8, nfBase16] = [] then
         result := toStringF(n.floatVal) + '''f64'
       else
         result := litAux(n, ({@cast}PInt64(addr(n.floatVal)))^, 8) + '''f64';
@@ -474,43 +469,49 @@ end;
 function lsub(n: PNode): int;
 // computes the length of a tree
 var
-  len: int;
+  L: int;
 begin
   if n = nil then begin result := 0; exit end;
   if n.comment <> snil then begin result := maxLineLen+1; exit end;
-  len := sonsLen(n);
   case n.kind of
     nkTripleStrLit: begin
       if containsNL(n.strVal) then result := maxLineLen+1
       else result := length(atom(n));
     end;
-    nkEmpty..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit: 
+    nkEmpty..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit:
       result := length(atom(n));
     nkCall, nkBracketExpr, nkConv: result := lsub(n.sons[0])+lcomma(n, 1)+2;
     nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: begin
-      result := lsub(n.sons[0]);
-    end;
-    nkCast: begin
-      if sonsLen(n) = 2 then
-        result := lsub(n.sons[0])+lsub(n.sons[1])+length('cast[]()')
-      else
-        result := lsub(n.sons[0]) + length('cast()');
+      result := lsub(n.sons[1]);
     end;
+    nkCast: result := lsub(n.sons[0])+lsub(n.sons[1])+length('cast[]()');
     nkAddr: result := lsub(n.sons[0])+length('addr()');
+    nkHiddenAddr, nkHiddenDeref: result := lsub(n.sons[0]);
     nkCommand: result := lsub(n.sons[0])+lcomma(n, 1)+1;
-    nkExprEqExpr, nkDefaultTypeParam, nkAsgn:
-      result := lsons(n)+3;
-    nkPar, nkRecordConstr, nkConstRecordConstr,
-    nkCurly, nkSetConstr, nkConstSetConstr,
-    nkBracket, nkArrayConstr, nkConstArrayConstr: result := lcomma(n)+2;
+    nkExprEqExpr, nkDefaultTypeParam, nkAsgn: result := lsons(n)+3;
+    nkPar, nkCurly, nkBracket: result := lcomma(n)+2;
+    nkTupleTy: result := lcomma(n)+length('tuple[]');
     nkQualified, nkDotExpr: result := lsons(n)+1;
+    nkCheckedFieldExpr: result := lsub(n.sons[0]);
     nkLambda: result := lsons(n)+length('lambda__=_');
     nkConstDef, nkIdentDefs: begin
       result := lcomma(n, 0, -3);
-      if n.sons[len-2] <> nil then
-        result := result + lsub(n.sons[len-2]) + 2;
-      if n.sons[len-1] <> nil then
-        result := result + lsub(n.sons[len-1]) + 3;
+      L := sonsLen(n);
+      if n.sons[L-2] <> nil then
+        result := result + lsub(n.sons[L-2]) + 2;
+      if n.sons[L-1] <> nil then
+        result := result + lsub(n.sons[L-1]) + 3;
+    end;
+    nkChckRangeF: result := length('chckRangeF') + 2 + lcomma(n);
+    nkChckRange64: result := length('chckRange64') + 2 + lcomma(n);
+    nkChckRange: result := length('chckRange') + 2 + lcomma(n);
+    
+    nkObjDownConv, nkObjUpConv, 
+    nkStringToCString, nkCStringToString, nkPassAsOpenArray: begin
+      result := 2;
+      if sonsLen(n) >= 1 then
+        result := result + lsub(n.sons[0]);
+      result := result + lcomma(n, 1);
     end;
     nkExprColonExpr:  result := lsons(n) + 2;
     nkInfix:          result := lsons(n) + 2;
@@ -539,7 +540,7 @@ begin
     nkEnumTy:         result := lsub(n.sons[0])+lcomma(n,1)+length('enum_');
     nkEnumFieldDef:   result := lsons(n)+3;
 
-    nkVarSection:     if len > 1 then result := maxLineLen+1
+    nkVarSection:     if sonsLen(n) > 1 then result := maxLineLen+1
                       else result := lsons(n) + length('var_');
     nkReturnStmt:     result := lsub(n.sons[0])+length('return_');
     nkRaiseStmt:      result := lsub(n.sons[0])+length('raise_');
@@ -550,7 +551,7 @@ begin
     nkPragma:         result := lcomma(n) + 4;
     nkCommentStmt:    result := length(n.comment);
 
-    nkOfBranch:       result := lcomma(n, 0, -2) + lsub(n.sons[len-1])
+    nkOfBranch:       result := lcomma(n, 0, -2) + lsub(lastSon(n))
                               + length('of_:_');
     nkElifBranch:     result := lsons(n)+length('elif_:_');
     nkElse:           result := lsub(n.sons[0]) + length('else:_');
@@ -560,7 +561,7 @@ begin
       result := lcomma(n, 1) + 2;
       if n.sons[0] <> nil then result := result + lsub(n.sons[0]) + 2
     end;
-    nkExceptBranch:   result := lcomma(n, 0, -2) + lsub(n.sons[len-1])
+    nkExceptBranch:   result := lcomma(n, 0, -2) + lsub(lastSon(n))
                               + length('except_:_');
     else result := maxLineLen+1
   end
@@ -576,7 +577,7 @@ end;
 type
   TSubFlag = (rfLongMode, rfNoIndent, rfInConstExpr);
   TSubFlags = set of TSubFlag;
-  TContext = record
+  TContext = record{@tuple}
     spacing: int;
     flags: TSubFlags;
   end;
@@ -895,7 +896,7 @@ procedure gident(var g: TSrcGen; n: PNode);
 var
   s: string;
   t: TTokType;
-begin 
+begin
   s := atom(n);
   if (s[strStart] in scanner.SymChars) then begin
     if (n.kind = nkIdent) then begin
@@ -917,12 +918,11 @@ end;
 
 procedure gsub(var g: TSrcGen; n: PNode; const c: TContext);
 var
-  len, i: int;
+  L, i: int;
   a: TContext;
 begin
   if n = nil then exit;
   if n.comment <> snil then pushCom(g, n);
-  len := sonsLen(n);
   case n.kind of
     // atoms:
     nkTripleStrLit: putRawStr(g, tkTripleStrLit, n.strVal);
@@ -939,11 +939,10 @@ begin
     nkStrLit: put(g, tkStrLit, atom(n));
     nkRStrLit: put(g, tkRStrLit, atom(n));
     nkCharLit: put(g, tkCharLit, atom(n));
-    nkRCharLit: put(g, tkRCharLit, atom(n));
     nkNilLit: put(g, tkNil, atom(n));
     // complex expressions
     nkCall, nkConv, nkDotCall: begin
-      if sonsLen(n) >= 1 then 
+      if sonsLen(n) >= 1 then
         gsub(g, n.sons[0]);
       put(g, tkParLe, '('+'');
       gcomma(g, n, 1);
@@ -955,14 +954,10 @@ begin
     nkCast: begin
       put(g, tkCast, 'cast');
       put(g, tkBracketLe, '['+'');
-      if sonsLen(n) = 2 then begin
-        gsub(g, n.sons[0]);
-        put(g, tkBracketRi, ']'+'');
-        put(g, tkParLe, '('+'');
-        gsub(g, n.sons[1]);
-      end
-      else
-        gsub(g, n.sons[0]);
+      gsub(g, n.sons[0]);
+      put(g, tkBracketRi, ']'+'');
+      put(g, tkParLe, '('+'');
+      gsub(g, n.sons[1]);
       put(g, tkParRi, ')'+'');
     end;
     nkAddr: begin
@@ -992,17 +987,43 @@ begin
       putWithSpace(g, tkEquals, '='+'');
       gsub(g, n.sons[1]);
     end;
-    nkPar, nkRecordConstr, nkConstRecordConstr: begin
+    nkChckRangeF: begin
+      put(g, tkSymbol, 'chckRangeF');
+      put(g, tkParLe, '('+'');
+      gcomma(g, n);
+      put(g, tkParRi, ')'+'');
+    end;
+    nkChckRange64: begin
+      put(g, tkSymbol, 'chckRange64');
+      put(g, tkParLe, '('+'');
+      gcomma(g, n);
+      put(g, tkParRi, ')'+'');    
+    end;
+    nkChckRange: begin
+      put(g, tkSymbol, 'chckRange');
+      put(g, tkParLe, '('+'');
+      gcomma(g, n);
+      put(g, tkParRi, ')'+'');
+    end;
+    nkObjDownConv, nkObjUpConv, 
+    nkStringToCString, nkCStringToString, nkPassAsOpenArray: begin
+      if sonsLen(n) >= 1 then
+        gsub(g, n.sons[0]);
+      put(g, tkParLe, '('+'');
+      gcomma(g, n, 1);
+      put(g, tkParRi, ')'+'');      
+    end;
+    nkPar: begin
       put(g, tkParLe, '('+'');
       gcomma(g, n, c);
       put(g, tkParRi, ')'+'');
     end;
-    nkCurly, nkSetConstr, nkConstSetConstr: begin
+    nkCurly: begin
       put(g, tkCurlyLe, '{'+'');
       gcomma(g, n, c);
       put(g, tkCurlyRi, '}'+'');
     end;
-    nkBracket, nkArrayConstr, nkConstArrayConstr: begin
+    nkBracket: begin
       put(g, tkBracketLe, '['+'');
       gcomma(g, n, c);
       put(g, tkBracketRi, ']'+'');
@@ -1012,6 +1033,7 @@ begin
       put(g, tkDot, '.'+'');
       gsub(g, n.sons[1]);
     end;
+    nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref: gsub(g, n.sons[0]);
     nkLambda: begin
       assert(n.sons[genericParamsPos] = nil);
       putWithSpace(g, tkLambda, 'lambda');
@@ -1023,14 +1045,15 @@ begin
     end;
     nkConstDef, nkIdentDefs: begin
       gcomma(g, n, 0, -3);
-      if n.sons[len-2] <> nil then begin
+      L := sonsLen(n);
+      if n.sons[L-2] <> nil then begin
         putWithSpace(g, tkColon, ':'+'');
-        gsub(g, n.sons[len-2])
+        gsub(g, n.sons[L-2])
       end;
-      if n.sons[len-1] <> nil then begin
+      if n.sons[L-1] <> nil then begin
         put(g, tkSpaces, Space);
         putWithSpace(g, tkEquals, '='+'');
-        gsub(g, n.sons[len-1], c)
+        gsub(g, n.sons[L-1], c)
       end;
     end;
     nkExprColonExpr: begin
@@ -1063,7 +1086,7 @@ begin
     end;
     nkDerefExpr: begin
       gsub(g, n.sons[0]);
-      putWithSpace(g, tkHat, '^'+''); 
+      putWithSpace(g, tkHat, '^'+'');
       // unfortunately this requires a space, because ^. would be
       // only one operator
     end;
@@ -1128,13 +1151,6 @@ begin
         gsub(g, n.sons[2]);
       end
     end;
-    nkRecordTy: begin
-      putWithSpace(g, tkRecord, 'record');
-      gsub(g, n.sons[0]);
-      gsub(g, n.sons[1]);
-      gcoms(g);
-      gsub(g, n.sons[2]);
-    end;
     nkObjectTy: begin
       putWithSpace(g, tkObject, 'object');
       gsub(g, n.sons[0]);
@@ -1144,7 +1160,7 @@ begin
     end;
     nkRecList: begin
       indentNL(g);
-      for i := 0 to len-1 do begin
+      for i := 0 to sonsLen(n)-1 do begin
         optNL(g);
         gsub(g, n.sons[i], c);
         gcoms(g);
@@ -1214,12 +1230,13 @@ begin
       gsection(g, n, a, tkConst, 'const')
     end;
     nkVarSection: begin
-      if len = 0 then exit;
+      L := sonsLen(n);
+      if L = 0 then exit;
       putWithSpace(g, tkVar, 'var');
-      if len > 1 then begin
+      if L > 1 then begin
         gcoms(g);
         indentNL(g);
-        for i := 0 to len-1 do begin
+        for i := 0 to L-1 do begin
           optNL(g);
           gsub(g, n.sons[i]);
           gcoms(g);
@@ -1294,7 +1311,7 @@ begin
       gcomma(g, n, c, 0, -2);
       putWithSpace(g, tkColon, ':'+'');
       gcoms(g);
-      gstmts(g, n.sons[len-1], c);
+      gstmts(g, lastSon(n), c);
     end;
     nkElifBranch: begin
       optNL(g);
@@ -1324,7 +1341,7 @@ begin
       gcomma(g, n, 0, -2);
       putWithSpace(g, tkColon, ':'+'');
       gcoms(g);
-      gstmts(g, n.sons[len-1], c)
+      gstmts(g, lastSon(n), c)
     end;
     nkGenericParams: begin
       put(g, tkBracketLe, '['+'');
@@ -1341,6 +1358,13 @@ begin
       end;
       // XXX: gcomma(g, n, 1, -2);
     end;
+    nkTupleTy: begin
+      put(g, tkTuple, 'tuple');
+      put(g, tkBracketLe, '['+'');
+      assert(n.sons[0].kind = nkIdentDefs);
+      gcomma(g, n);
+      put(g, tkBracketRi, ']'+'');
+    end;
     else begin
       InternalError(n.info, 'rnimsyn.gsub(' +{&} nodeKindToStr[n.kind] +{&} ')')
     end
diff --git a/nim/rodgen.pas b/nim/rodgen.pas
index a9bb17b49..8ef71dcb3 100644
--- a/nim/rodgen.pas
+++ b/nim/rodgen.pas
@@ -40,7 +40,7 @@ type
   TRodReaderFlags = set of TRodReaderFlag;
 
 const
-  FileVersion = '02'; // modify this if the MO2-format changes!
+  FileVersion = '04'; // modify this if the rod-format changes!
 
 procedure generateRod(module: PNode; const filename: string);
 function readRod(const filename: string; const flags: TRodReaderFlags): PNode;
@@ -191,7 +191,7 @@ begin
   if n.comment <> snil then begin
     com := encode(n.comment);
     if ropeLen(com) >= 128 then
-      appRopeFormat(result, '@$1$2', [toBase62(ropeLen(com)), com])
+      appf(result, '@$1$2', [toBase62(ropeLen(com)), com])
     else
       result := com
     // do not emit comments to the string table as this would only increase
@@ -200,33 +200,31 @@ begin
   // Line information takes easily 50% or more of the filesize! Therefore we
   // omit line information if it is the same as the father's line information:
   if (finfo.line <> int(n.info.line)) then
-    appRopeFormat(result, '?$1,$2', [toBase62(n.info.col),
+    appf(result, '?$1,$2', [toBase62(n.info.col),
                                      toBase62(n.info.line)])
   else if (finfo.col <> int(n.info.col)) then
-    appRopeFormat(result, '?$1', [toBase62(n.info.col)]);
+    appf(result, '?$1', [toBase62(n.info.col)]);
     // No need to output the file index, as this is the serialization of one
     // file.
-  if n.base <> base10 then
-    appRopeFormat(result, '$$$1', [toBase62(ord(n.base))]);
+  if n.flags <> {@set}[] then
+    appf(result, '$$$1', [toBase62({@cast}int(n.flags))]);
   case n.kind of
     nkCharLit..nkInt64Lit:
-      appRopeFormat(result, '!$1', [toBase62(n.intVal)]);
+      appf(result, '!$1', [toBase62(n.intVal)]);
     nkFloatLit..nkFloat64Lit:
-      appRopeFormat(result, '!$1', [toRopeF(n.floatVal)]);
+      appf(result, '!$1', [toRopeF(n.floatVal)]);
     nkStrLit..nkTripleStrLit:
-      appRopeFormat(result, '!$1', [encode(n.strVal)]);
+      appf(result, '!$1', [encode(n.strVal)]);
     nkSym: assert(false);
     nkIdent:
-      appRopeFormat(result, '!$1', [encodeIdent(g, n.ident)]);
+      appf(result, '!$1', [encodeIdent(g, n.ident)]);
     else begin
       for i := 0 to sonsLen(n)-1 do
         app(result, encodeNode(g, n.info, n.sons[i]));
     end
   end;
   len := ropeLen(result);
-  result := ropeFormat('$1$2$3', [toRope(chr(ord(n.kind)+128)+''), 
-                                  toBase62(len), result]);
-  assert(ord(n.kind)+128 < 256);
+  result := ropef('$1$2$3', [toBase62(ord(n.kind)), toBase62(len), result]);
 end;
 
 procedure generateRod(module: PNode; const filename: string);
@@ -235,16 +233,15 @@ var
   ast: PRope;
   info: TLineInfo;
 begin
-  assert(ord(high(TNodeKind))+1 < 127);
   initTable(g.identTab);
   g.idents := nil;
   info := newLineInfo(changeFileExt(filename, '.nim'), -1, -1);
   ast := encodeNode(g, info, module);
 
-  writeRope(ropeFormat('AA02 $1 $2,$3 $4 $5',
-                       [toRope(FileVersion),
-                        toBase62(ropeLen(g.idents)), toBase62(ropeLen(ast)),
-                        g.idents, ast]), filename);
+  writeRope(ropef('AA02 $1 $2,$3 $4 $5',
+                 [toRope(FileVersion),
+                  toBase62(ropeLen(g.idents)), toBase62(ropeLen(ast)),
+                  g.idents, ast]), filename);
 end;
 
 // ----------------------- reader ---------------------------------------------
@@ -344,8 +341,8 @@ begin
   if r.s[i] = #255 then begin
     inc(r.pos); exit // nil node
   end;
-  assert(r.s[i] >= #128);
-  kind := TNodeKind(ord(r.s[i])-int(128));
+  i := fromBase62i(r.s, i, x);
+  kind := TNodeKind(x);
   assert((kind >= low(TNodeKind)) and (kind <= high(TNodeKind)));
   inc(i); // skip kind
   i := fromBase62i(r.s, i, len);
@@ -386,7 +383,7 @@ begin
     if r.s[i] = '$' then begin
       inc(i);
       i := fromBase62i(r.s, i, x);
-      result.base := TNumericalBase(x);
+      result.flags := {@cast}TNodeFlags(x);
     end;
     // atom:
     if r.s[i] = '!' then begin
@@ -413,7 +410,7 @@ begin
     end
     else if r.s[i] >= #128 then begin
       case kind of
-        nkCharLit..nkInt64Lit, nkFloatLit..nkFloat64Lit, 
+        nkCharLit..nkInt64Lit, nkFloatLit..nkFloat64Lit,
         nkStrLit..nkTripleStrLit, nkSym, nkIdent: assert(false);
         else begin end;
       end;
diff --git a/nim/ropes.pas b/nim/ropes.pas
index 48a38d7b4..0e4b4981b 100644
--- a/nim/ropes.pas
+++ b/nim/ropes.pas
@@ -111,9 +111,9 @@ function writeRopeIfNotEqual(r: PRope; const filename: string): boolean;
 
 function ropeToStr(p: PRope): string;
 
-function ropeFormat(const frmt: TFormatStr; const args: array of PRope): PRope;
+function ropef(const frmt: TFormatStr; const args: array of PRope): PRope;
 
-procedure appRopeFormat(var c: PRope; const frmt: TFormatStr;
+procedure appf(var c: PRope; const frmt: TFormatStr;
   const args: array of PRope);
 
 procedure RopeSeqInsert(var rs: TRopeSeq; r: PRope; at: Natural);
@@ -123,6 +123,9 @@ function getCacheStats: string;
 function RopeEqualsFile(r: PRope; const f: string): Boolean;
 // returns true if the rope r is the same as the contents of file f
 
+function RopeInvariant(r: PRope): Boolean;
+// exported for debugging
+
 implementation
 
 function ropeLen(a: PRope): int;
@@ -137,8 +140,10 @@ begin
   {@ignore}
   fillChar(result^, sizeof(TRope), 0);
   {@emit}
-  result.len := length(data);
-  result.data := data;
+  if data <> snil then begin
+    result.len := length(data);
+    result.data := data;
+  end
 end;
 
 // -------------- leaf cache: ---------------------------------------
@@ -221,6 +226,23 @@ begin
   end
 end;
 
+function RopeInvariant(r: PRope): Boolean;
+begin
+  if r = nil then
+    result := true
+  else begin
+    result := true
+  (*
+    if r.data <> snil then
+      result := true
+    else begin
+      result := (r.left <> nil) and (r.right <> nil);
+      if result then result := ropeInvariant(r.left);
+      if result then result := ropeInvariant(r.right);
+    end *)
+  end
+end;
+
 function toRope(const s: string): PRope;
 begin
   if s = '' then
@@ -230,7 +252,8 @@ begin
     cache := result;
   end
   else
-    result := newRope(s)
+    result := newRope(s);
+  assert(RopeInvariant(result));
 end;
 
 // ------------------------------------------------------------------
@@ -251,14 +274,6 @@ begin
   rs[at] := r
 end;
 
-function RopeInvariant(r: PRope): Boolean;
-begin
-  if r = nil then
-    result := true
-  else
-    result := true
-end;
-
 function con(a, b: PRope): PRope; overload;
 begin
   assert(RopeInvariant(a));
@@ -325,7 +340,8 @@ var
   i: int;
 begin
   result := nil;
-  for i := 0 to high(a) do result := con(result, a[i])
+  for i := 0 to high(a) do result := con(result, a[i]);
+  assert(RopeInvariant(result));
 end;
 
 function toRope(i: BiggestInt): PRope;
@@ -340,17 +356,45 @@ end;
 
 procedure app(var a: PRope; b: PRope); overload;
 begin
-  a := con(a, b)
+  a := con(a, b);
+  assert(RopeInvariant(a));
 end;
 
 procedure app(var a: PRope; const b: string); overload;
 begin
   a := con(a, b);
+  assert(RopeInvariant(a));
 end;
 
 procedure prepend(var a: PRope; b: PRope);
 begin
-  a := con(b, a)
+  a := con(b, a);
+  assert(RopeInvariant(a));
+end;
+
+procedure InitStack(var stack: TRopeSeq);
+begin
+  {@ignore}
+  setLength(stack, 0);
+  {@emit stack := [];}
+end;
+
+procedure push(var stack: TRopeSeq; r: PRope);
+var
+  len: int;
+begin
+  len := length(stack);
+  setLength(stack, len+1);
+  stack[len] := r;
+end;
+
+function pop(var stack: TRopeSeq): PRope;
+var
+  len: int;
+begin
+  len := length(stack);
+  result := stack[len-1];
+  setLength(stack, len-1);
 end;
 
 procedure WriteRopeRec(var f: TTextFile; c: PRope);
@@ -367,12 +411,32 @@ begin
   end
 end;
 
+procedure newWriteRopeRec(var f: TTextFile; c: PRope);
+var
+  stack: TRopeSeq;
+  it: PRope;
+begin
+  assert(RopeInvariant(c));
+  initStack(stack);
+  push(stack, c);
+  while length(stack) > 0 do begin
+    it := pop(stack);
+    while it.data = snil do begin
+      push(stack, it.right);
+      it := it.left;
+      assert(it <> nil);
+    end;
+    assert(it.data <> snil);
+    nimWrite(f, it.data);
+  end
+end;
+
 procedure WriteRope(head: PRope; const filename: string);
 var
   f: TTextFile; // we use a textfile for automatic buffer handling
 begin
   if OpenFile(f, filename, fmWrite) then begin
-    writeRopeRec(f, head);
+    if head <> nil then newWriteRopeRec(f, head);
     nimCloseFile(f);
   end
 end;
@@ -391,17 +455,42 @@ begin
   end
 end;
 
+procedure newRecRopeToStr(var result: string; var resultLen: int;
+                          r: PRope);
+var
+  stack: TRopeSeq;
+  it: PRope;
+begin
+  initStack(stack);
+  push(stack, r);
+  while length(stack) > 0 do begin
+    it := pop(stack);
+    while it.data = snil do begin
+      push(stack, it.right);
+      it := it.left;
+    end;
+    assert(it.data <> snil);
+    CopyMem(@result[resultLen+StrStart], @it.data[strStart], it.len);
+    Inc(resultLen, it.len);
+    assert(resultLen <= length(result));
+  end
+end;
+
 function ropeToStr(p: PRope): string;
 var
   resultLen: int;
 begin
   assert(RopeInvariant(p));
-  result := newString(p.len);
-  resultLen := 0;
-  recRopeToStr(result, resultLen, p);
+  if p = nil then
+    result := ''
+  else begin
+    result := newString(p.len);
+    resultLen := 0;
+    newRecRopeToStr(result, resultLen, p);
+  end
 end;
 
-function ropeFormat(const frmt: TFormatStr; const args: array of PRope): PRope;
+function ropef(const frmt: TFormatStr; const args: array of PRope): PRope;
 var
   i, j, len, start: int;
 begin
@@ -424,7 +513,7 @@ begin
           app(result, args[j-1]);
         end;
         'N', 'n': begin app(result, tnl); inc(i); end;
-        else InternalError('ropes: invalid format string$' + frmt[i]);
+        else InternalError('ropes: invalid format string $' + frmt[i]);
       end
     end;
     start := i;
@@ -435,10 +524,10 @@ begin
   assert(RopeInvariant(result));
 end;
 
-procedure appRopeFormat(var c: PRope; const frmt: TFormatStr;
+procedure appf(var c: PRope; const frmt: TFormatStr;
   const args: array of PRope);
 begin
-  app(c, ropeformat(frmt, args))
+  app(c, ropef(frmt, args))
 end;
 
 const
@@ -495,9 +584,30 @@ begin
   end
 end;
 
+function newCrcFromRopeAux(r: PRope; startVal: TCrc32): TCrc32;
+var
+  stack: TRopeSeq;
+  it: PRope;
+  i: int;
+begin
+  initStack(stack);
+  push(stack, r);
+  result := startVal;
+  while length(stack) > 0 do begin
+    it := pop(stack);
+    while it.data = snil do begin
+      push(stack, it.right);
+      it := it.left;
+    end;
+    assert(it.data <> snil);
+    for i := strStart to length(it.data)+strStart-1 do
+      result := updateCrc32(it.data[i], result);
+  end
+end;
+
 function crcFromRope(r: PRope): TCrc32;
 begin
-  result := crcFromRopeAux(r, initCrc32)
+  result := newCrcFromRopeAux(r, initCrc32)
 end;
 
 function writeRopeIfNotEqual(r: PRope; const filename: string): boolean;
diff --git a/nim/rst.pas b/nim/rst.pas
index d6452ceae..54958aff2 100644
--- a/nim/rst.pas
+++ b/nim/rst.pas
@@ -102,17 +102,17 @@ type
   );
 const
   rstnodekindToStr: array [TRstNodeKind] of string = (
-    'Inner', 'Headline', 'Overline', 'Transition', 'Paragraph', 
-    'BulletList', 'BulletItem', 'EnumList', 'EnumItem', 'DefList', 'DefItem', 
-    'DefName', 'DefBody', 'FieldList', 'Field', 'FieldName', 'FieldBody', 
-    'OptionList', 'OptionListItem', 'OptionGroup', 'Option', 'OptionString', 
-    'OptionArgument', 'Description', 'LiteralBlock', 'QuotedLiteralBlock', 
-    'LineBlock', 'LineBlockItem', 'BlockQuote', 'Table', 'GridTable', 
-    'TableRow', 'TableHeaderCell', 'TableDataCell', 'Label', 'Footnote', 
-    'Citation', 'StandaloneHyperlink', 'Hyperlink', 'Ref', 'Directive', 
-    'DirArg', 'Raw', 'Title', 'Contents', 'Image', 'Figure', 'CodeBlock', 
+    'Inner', 'Headline', 'Overline', 'Transition', 'Paragraph',
+    'BulletList', 'BulletItem', 'EnumList', 'EnumItem', 'DefList', 'DefItem',
+    'DefName', 'DefBody', 'FieldList', 'Field', 'FieldName', 'FieldBody',
+    'OptionList', 'OptionListItem', 'OptionGroup', 'Option', 'OptionString',
+    'OptionArgument', 'Description', 'LiteralBlock', 'QuotedLiteralBlock',
+    'LineBlock', 'LineBlockItem', 'BlockQuote', 'Table', 'GridTable',
+    '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', 
+    'Emphasis', 'StrongEmphasis', 'InterpretedText', 'InlineLiteral',
     'SubstitutionReferences', 'Leaf'
   );
 
@@ -144,7 +144,7 @@ function rstnodeToRefname(n: PRstNode): string;
 function getFieldValue(n: PRstNode; const fieldname: string): string;
 function getArgument(n: PRstNode): string;
 
-// index handling: 
+// index handling:
 procedure setIndexPair(index, key, val: PRstNode);
 procedure sortIndex(a: PRstNode);
 procedure clearIndex(index: PRstNode; const filename: string);
@@ -329,7 +329,7 @@ begin
   end;
   if tokens[0].kind = tkWhite then begin // BUGFIX
     tokens[0].ival := length(tokens[0].symbol);
-    tokens[0].kind := tkIndent 
+    tokens[0].kind := tkIndent
   end
 end;
 
@@ -359,7 +359,9 @@ begin
   new(result);
 {@ignore}
   fillChar(result^, sizeof(result^), 0);
-{@emit}
+{@emit
+  result.sons := [];
+}
   result.kind := kind;
 end;
 
@@ -457,6 +459,10 @@ begin
   p.indentStack := [0];}
   {@emit
   p.tok := [];}
+  p.idx := 0;
+  p.filename := '';
+  p.hasToc := false;
+  p.col := 0;
   p.line := 1;
   p.s := sharedState;
 end;
@@ -581,7 +587,7 @@ end;
 
 procedure sortIndex(a: PRstNode);
 // we use shellsort here; fast and simple
-var 
+var
   N, i, j, h: int;
   v: PRstNode;
 begin
@@ -589,7 +595,7 @@ begin
   N := rsonsLen(a);
   h := 1; repeat h := 3*h+1; until h > N;
   repeat
-    h := h div 3; 
+    h := h div 3;
     for i := h to N-1 do begin
       v := a.sons[i]; j := i;
       while cmpNodes(a.sons[j-h], v) >= 0 do begin
@@ -607,11 +613,11 @@ var
 begin
   result := false;
   if a.kind <> b.kind then exit;
-  if a.kind = rnLeaf then 
+  if a.kind = rnLeaf then
     result := a.text = b.text
   else begin
     if rsonsLen(a) <> rsonsLen(b) then exit;
-    for i := 0 to rsonsLen(a)-1 do 
+    for i := 0 to rsonsLen(a)-1 do
       if not eqRstNodes(a.sons[i], b.sons[i]) then exit;
     result := true
   end
@@ -627,7 +633,7 @@ begin
   end
   else if h.kind = rnHyperlink then begin
     s := addNodes(h.sons[1]);
-    if startsWith(s, filename) and (s[length(filename)+strStart] = '#') then 
+    if startsWith(s, filename) and (s[length(filename)+strStart] = '#') then
       result := true
     else
       result := false
@@ -650,7 +656,7 @@ begin
       items := rsonsLen(val);
       lastItem := -1; // save the last valid item index
       for j := 0 to rsonsLen(val)-1 do begin
-        if val.sons[j] = nil then 
+        if val.sons[j] = nil then
           dec(items)
         else if matchesHyperlink(val.sons[j].sons[0], filename) then begin
           val.sons[j] := nil;
@@ -663,7 +669,7 @@ begin
       else if items = 0 then
         index.sons[i] := nil
     end
-    else if matchesHyperlink(val, filename) then 
+    else if matchesHyperlink(val, filename) then
       index.sons[i] := nil
   end;
   // remove nil nodes:
@@ -702,14 +708,14 @@ begin
       b := newRstNode(rnBulletItem);
       addSon(b, val);
       addSon(e, b);
-      
+
       exit // key already exists
     end
   end;
   e := newRstNode(rnDefItem);
   assert(val.kind <> rnDefBody);
   b := newRstNode(rnDefBody);
-  addSon(b, val); 
+  addSon(b, val);
   addSon(e, a);
   addSon(e, b);
   addSon(index, e);
@@ -730,7 +736,7 @@ begin
   while true do begin
     case p.tok[p.idx].kind of
       tkWord, tkOther, tkWhite: addSon(res, newLeaf(p));
-      tkPunct: 
+      tkPunct:
         if p.tok[p.idx].symbol = endStr then begin inc(p.idx); break end
         else addSon(res, newLeaf(p));
       else begin
@@ -746,13 +752,13 @@ end;
 function untilEol(var p: TRstParser): PRstNode;
 begin
   result := newRstNode(rnInner);
-  while not (p.tok[p.idx].kind in [tkIndent, tkEof]) do begin 
+  while not (p.tok[p.idx].kind in [tkIndent, tkEof]) do begin
     addSon(result, newLeaf(p)); inc(p.idx);
   end
 end;
 
 procedure expect(var p: TRstParser; const tok: string);
-begin 
+begin
   if p.tok[p.idx].symbol = tok then inc(p.idx)
   else rstMessage(p, errXexpected, tok)
 end;
@@ -953,7 +959,7 @@ begin
   end
   else if match(p, p.idx, ':w:') then begin
     // a role:
-    if p.tok[p.idx+1].symbol = 'idx' then 
+    if p.tok[p.idx+1].symbol = 'idx' then
       n.kind := rnIdx
     else if p.tok[p.idx+1].symbol = 'literal' then
       n.kind := rnInlineLiteral
@@ -1345,14 +1351,14 @@ var
   j: int;
 begin
   j := tokenAfterNewline(p);
-  result := (p.tok[p.idx].col < p.tok[j].col) 
+  result := (p.tok[p.idx].col < p.tok[j].col)
     and (p.tok[j].kind in [tkWord, tkOther, tkPunct])
     and (p.tok[j-2].symbol <> '::');
 end;
 
 function whichSection(const p: TRstParser): TRstNodeKind;
 begin
-  case p.tok[p.idx].kind of 
+  case p.tok[p.idx].kind of
     tkAdornment: begin
       if match(p, p.idx+1, 'ii') then result := rnTransition
       else if match(p, p.idx+1, ' a') then result := rnTable
@@ -1362,21 +1368,21 @@ begin
     tkPunct: begin
       if match(p, tokenAfterNewLine(p), 'ai') then
         result := rnHeadline
-      else if p.tok[p.idx].symbol = '::' then 
+      else if p.tok[p.idx].symbol = '::' then
         result := rnLiteralBlock
       else if predNL(p)
           and ((p.tok[p.idx].symbol = '+'+'') or
           (p.tok[p.idx].symbol = '*'+'') or
-          (p.tok[p.idx].symbol = '-'+'')) 
-          and (p.tok[p.idx+1].kind = tkWhite) then 
+          (p.tok[p.idx].symbol = '-'+''))
+          and (p.tok[p.idx+1].kind = tkWhite) then
         result := rnBulletList
       else if (p.tok[p.idx].symbol = '|'+'') and isLineBlock(p) then
         result := rnLineBlock
-      else if (p.tok[p.idx].symbol = '..') and predNL(p) then 
+      else if (p.tok[p.idx].symbol = '..') and predNL(p) then
         result := rnDirective
-      else if (p.tok[p.idx].symbol = ':'+'') and predNL(p) then 
+      else if (p.tok[p.idx].symbol = ':'+'') and predNL(p) then
         result := rnFieldList
-      else if match(p, p.idx, '(e) ') then 
+      else if match(p, p.idx, '(e) ') then
         result := rnEnumList
       else if match(p, p.idx, '+a+') then begin
         result := rnGridTable;
@@ -1384,14 +1390,14 @@ begin
       end
       else if isDefList(p) then
         result := rnDefList
-      else if match(p, p.idx, '-w') or match(p, p.idx, '--w') 
-           or match(p, p.idx, '/w') then 
+      else if match(p, p.idx, '-w') or match(p, p.idx, '--w')
+           or match(p, p.idx, '/w') then
         result := rnOptionList
       else
         result := rnParagraph
     end;
     tkWord, tkOther, tkWhite: begin
-      if match(p, tokenAfterNewLine(p), 'ai') then 
+      if match(p, tokenAfterNewLine(p), 'ai') then
         result := rnHeadline
       else if isDefList(p) then
         result := rnDefList
@@ -1440,7 +1446,7 @@ begin
         else if (p.tok[p.idx].ival = currInd(p)) then begin
           inc(p.idx);
           case whichSection(p) of
-            rnParagraph, rnLeaf, rnHeadline, rnOverline, rnDirective: 
+            rnParagraph, rnLeaf, rnHeadline, rnOverline, rnDirective:
               addSon(result, newRstNode(rnLeaf, ' '+''));
             rnLineBlock: addSonIfNotNil(result, parseLineBlock(p));
             else break;
@@ -1509,7 +1515,7 @@ begin
     if p.tok[p.idx].kind <> tkAdornment then break
   end;
   if p.tok[p.idx].kind = tkIndent then inc(p.idx);
-  // last column has no limit: 
+  // last column has no limit:
   cols[L-1] := 32000;
 end;
 
@@ -1543,12 +1549,12 @@ begin
       end;
       getColumns(p, cols);
       setLength(row, length(cols));
-      if a <> nil then 
+      if a <> nil then
         for j := 0 to rsonsLen(a)-1 do a.sons[j].kind := rnTableHeaderCell;
     end;
     if p.tok[p.idx].kind = tkEof then break;
     for j := 0 to high(row) do row[j] := '';
-    // the following while loop iterates over the lines a single cell may span: 
+    // the following while loop iterates over the lines a single cell may span:
     line := p.tok[p.idx].line;
     while true do begin
       i := 0;
@@ -1602,7 +1608,7 @@ begin
     parseLine(p, result);
     if p.tok[p.idx].kind = tkIndent then begin
       inc(p.idx);
-      if p.tok[p.idx-1].ival > currInd(p) then 
+      if p.tok[p.idx-1].ival > currInd(p) then
         addSon(result, newRstNode(rnLeaf, ' '+''))
       else
         break
@@ -1649,22 +1655,22 @@ var
 begin
   result := newRstNode(rnOptionList);
   while true do begin
-    if match(p, p.idx, '-w')  
-    or match(p, p.idx, '--w')  
+    if match(p, p.idx, '-w')
+    or match(p, p.idx, '--w')
     or match(p, p.idx, '/w') then begin
       a := newRstNode(rnOptionGroup);
       b := newRstNode(rnDescription);
       c := newRstNode(rnOptionListItem);
       while not (p.tok[p.idx].kind in [tkIndent, tkEof]) do begin
-        if (p.tok[p.idx].kind = tkWhite) 
-        and (length(p.tok[p.idx].symbol) > 1) then begin 
-          inc(p.idx); break 
+        if (p.tok[p.idx].kind = tkWhite)
+        and (length(p.tok[p.idx].symbol) > 1) then begin
+          inc(p.idx); break
         end;
         addSon(a, newLeaf(p));
         inc(p.idx);
       end;
       j := tokenAfterNewline(p);
-      if (j > 0) and (p.tok[j-1].kind = tkIndent) 
+      if (j > 0) and (p.tok[j-1].kind = tkIndent)
       and (p.tok[j-1].ival > currInd(p)) then begin
         pushInd(p, p.tok[j-1].ival);
         parseSection(p, b);
@@ -1719,8 +1725,8 @@ begin
         inc(p.idx);
         j := tokenAfterNewLine(p)-1;
         if (j >= 1) and (p.tok[j].kind = tkIndent)
-        and (p.tok[j].ival > col) 
-        and (p.tok[j-1].symbol <> '::') 
+        and (p.tok[j].ival > col)
+        and (p.tok[j-1].symbol <> '::')
         and (p.tok[j+1].kind <> tkIndent) then begin end
         else break
       end
@@ -1784,6 +1790,7 @@ var
 begin
   while true do begin
     leave := false;
+    assert(p.idx >= 0);
     while p.tok[p.idx].kind = tkIndent do begin
       if currInd(p) = p.tok[p.idx].ival then begin
         inc(p.idx);
@@ -1837,12 +1844,12 @@ begin
     addSonIfNotNil(result, a);
   end;
   //if (result.kind in [rnBulletItem]) and
-  if (sonKind(result, 0) = rnParagraph) 
-  and (sonKind(result, 1) <> rnParagraph) then 
+  if (sonKind(result, 0) = rnParagraph)
+  and (sonKind(result, 1) <> rnParagraph) then
     result.sons[0].kind := rnInner;
   (*
   if (result.kind <> rnInner) and (rsonsLen(result) = 1)
-  and (result.sons[0].kind = rnParagraph) then 
+  and (result.sons[0].kind = rnParagraph) then
     result.sons[0].kind := rnInner; *)
 end;
 
@@ -1857,7 +1864,7 @@ end;
 function parseDoc(var p: TRstParser): PRstNode;
 begin
   result := parseSectionWrapper(p);
-  if p.tok[p.idx].kind <> tkEof then 
+  if p.tok[p.idx].kind <> tkEof then
     rstMessage(p, errGeneralParseError);
 end;
 
@@ -1865,14 +1872,14 @@ type
   TDirFlag = (hasArg, hasOptions, argIsFile);
   TDirFlags = set of TDirFlag;
   TSectionParser = function (var p: TRstParser): PRstNode;
-  
+
 {@emit
 function assigned(contentParser: TSectionParser): bool;
 begin
   result := contentParser <> nil;
 end;
 }
-  
+
 function parseDirective(var p: TRstParser; flags: TDirFlags;
                         contentParser: TSectionParser): PRstNode;
 var
@@ -1905,7 +1912,7 @@ begin
       options := parseFields(p);
   end;
   addSon(result, options);
-  if (assigned(contentParser)) and (p.tok[p.idx].kind = tkIndent) 
+  if (assigned(contentParser)) and (p.tok[p.idx].kind = tkIndent)
   and (p.tok[p.idx].ival > currInd(p)) then begin
     pushInd(p, p.tok[p.idx].ival);
     //while p.tok[p.idx].kind = tkIndent do inc(p.idx);
@@ -1985,7 +1992,7 @@ end;
 
 function dirFigure(var p: TRstParser): PRstNode;
 begin
-  result := parseDirective(p, {@set}[hasOptions, hasArg, argIsFile], 
+  result := parseDirective(p, {@set}[hasOptions, hasArg, argIsFile],
                            parseSectionWrapper);
   result.kind := rnFigure
 end;
diff --git a/nim/scanner.pas b/nim/scanner.pas
index 8e5bc3fc5..b9a61f95d 100644
--- a/nim/scanner.pas
+++ b/nim/scanner.pas
@@ -62,15 +62,15 @@ type
     tkMacro, tkMethod, tkMod, tkNil, 
     tkNot, tkNotin, tkObject, tkOf, 
     tkOr, tkOut, tkProc, tkPtr, 
-    tkRaise, tkRecord, tkRef, tkReturn, 
-    tkShl, tkShr, tkTemplate, tkTry, 
+    tkRaise, tkRef, tkReturn, tkShl, 
+    tkShr, tkTemplate, tkTry, tkTuple, 
     tkType, tkVar, tkWhen, tkWhere, 
     tkWhile, tkWith, tkWithout, tkXor, 
     tkYield, 
     //[[[end]]]
     tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit,
     tkFloatLit, tkFloat32Lit, tkFloat64Lit,
-    tkStrLit, tkRStrLit, tkTripleStrLit, tkCharLit, tkRCharLit,
+    tkStrLit, tkRStrLit, tkTripleStrLit, tkCharLit,
     tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
     tkBracketDotLe, tkBracketDotRi, // [. and  .]
     tkCurlyDotLe, tkCurlyDotRi, // {.  and  .}
@@ -106,15 +106,15 @@ const
     'macro', 'method', 'mod', 'nil', 
     'not', 'notin', 'object', 'of', 
     'or', 'out', 'proc', 'ptr', 
-    'raise', 'record', 'ref', 'return', 
-    'shl', 'shr', 'template', 'try', 
+    'raise', 'ref', 'return', 'shl', 
+    'shr', 'template', 'try', 'tuple', 
     'type', 'var', 'when', 'where', 
     'while', 'with', 'without', 'xor', 
     'yield', 
     //[[[end]]]
     'tkIntLit', 'tkInt8Lit', 'tkInt16Lit', 'tkInt32Lit', 'tkInt64Lit',
     'tkFloatLit', 'tkFloat32Lit', 'tkFloat64Lit',
-    'tkStrLit', 'tkRStrLit', 'tkTripleStrLit', 'tkCharLit', 'tkRCharLit',
+    'tkStrLit', 'tkRStrLit', 'tkTripleStrLit', 'tkCharLit',
     '('+'', ')'+'', '['+'', ']'+'', '{'+'', '}'+'',
     '[.', '.]', '{.', '.}', '(.', '.)', ','+'', ';'+'', ':'+'',
     '='+'', '.'+'', '..', '^'+'', 'tkOpr',
@@ -124,6 +124,11 @@ const
   );
 
 type
+  TNumericalBase = (base10, // base10 is listed as the first element,
+                            // so that it is the correct default value
+                    base2,
+                    base8,
+                    base16);
   PToken = ^TToken;
   TToken = object          // a Nimrod token
     tokType: TTokType;     // the type of the token
@@ -210,7 +215,7 @@ begin
       result := toString(tok.iNumber);
     tkFloatLit..tkFloat64Lit:
       result := toStringF(tok.fNumber);
-    tkInvalid, tkStrLit..tkRCharLit, tkComment:
+    tkInvalid, tkStrLit..tkCharLit, tkComment:
       result := tok.literal;
     tkParLe..tkColon, tkEof, tkInd, tkSad, tkDed, tkAccent:
       result := tokTypeToStr[tok.tokType];
@@ -510,7 +515,13 @@ begin
       if result.tokType = tkIntLit then result.tokType := tkFloatLit;
     end
     else begin
-      result.iNumber := ParseInt(result.literal)
+      result.iNumber := ParseBiggestInt(result.literal);
+      if (result.iNumber < low(int32)) or (result.iNumber > high(int32)) then
+      begin
+        if result.tokType = tkIntLit then result.tokType := tkInt64Lit
+        else if result.tokType <> tkInt64Lit then
+          lexMessage(L, errInvalidNumber, result.literal);
+      end
     end;
   except
     on EInvalidValue do
@@ -682,7 +693,7 @@ begin
   end
 end;
 
-procedure getCharacter(var L: TLexer; var tok: TToken; rawMode: Boolean);
+procedure getCharacter(var L: TLexer; var tok: TToken);
 var
   c: Char;
 begin
@@ -690,13 +701,7 @@ begin
   c := L.buf[L.bufpos];
   case c of
     #0..Pred(' '), '''': lexMessage(L, errInvalidCharacterConstant);
-    '\': begin
-      if not rawMode then
-        getEscapedChar(L, tok)
-      else begin
-        tok.literal := '\'+''; Inc(L.bufpos);
-      end
-    end
+    '\': getEscapedChar(L, tok);
     else begin
       tok.literal := c + '';
       Inc(L.bufpos);
@@ -923,18 +928,11 @@ begin
         getSymbol(L, tok);
       end;
       'r', 'R': begin
-        case L.buf[L.bufPos+1] of
-          '''': begin
-            Inc(L.bufPos);
-            getCharacter(L, tok, true);
-            tok.tokType := tkRCharLit;
-          end;
-          '"': begin
-            Inc(L.bufPos);
-            getString(L, tok, true);
-          end;
-          else getSymbol(L, tok);
+        if L.buf[L.bufPos+1] = '"' then begin
+          Inc(L.bufPos);
+          getString(L, tok, true);
         end
+        else getSymbol(L, tok);
       end;
       '(': begin
         Inc(L.bufpos);
@@ -1004,7 +1002,7 @@ begin
       end;
       '"': getString(L, tok, false);
       '''': begin
-        getCharacter(L, tok, false);
+        getCharacter(L, tok);
         tok.tokType := tkCharLit;
       end;
       lexbase.EndOfFile: tok.toktype := tkEof;
diff --git a/nim/sem.pas b/nim/sem.pas
index 48a967d35..d57af7be6 100644
--- a/nim/sem.pas
+++ b/nim/sem.pas
@@ -21,7 +21,7 @@ uses
   extccomp, nmath, magicsys, nversion, nimsets, pnimsyn, ntime, backends;
 
 const
-  genPrefix = '::'+''; // prefix for generated names
+  genPrefix = '::'; // prefix for generated names
 
 type
   TOptionEntry = object(lists.TListEntry)
@@ -48,6 +48,7 @@ type
     owner: PSym;        // current owner
     forStmt: PNode;    // current for stmt
     next: PTransCon;
+    params: TNodeSeq;  // parameters passed to the proc
   end;
 
   PContext = ^TContext;
@@ -65,6 +66,7 @@ type
     b: PBackend;
     p: PProcCon; // procedure context
     transCon: PTransCon; // top of a TransCon stack
+    lastException: PNode; // last exception
     importModule: function (const filename: string; backend: PBackend): PSym;
     includeFile: function (const filename: string): PNode;
   end;
@@ -87,6 +89,7 @@ begin
   fillChar(result^, sizeof(result^), 0);
 {@emit}
   initIdNodeTable(result.mapping);
+{@emit result.params := [];}
 end;
 
 procedure pushTransCon(c: PContext; t: PTransCon);
@@ -140,13 +143,26 @@ begin
   append(result.optionStack, newOptionEntry());
   result.module := nil;
   result.generics := newNode(nkStmtList);
+{@emit result.converters := [];}
+end;
+
+procedure addConverter(c: PContext; conv: PSym);
+var
+  i, L: int;
+begin
+  L := length(c.converters);
+  for i := 0 to L-1 do
+    if c.converters[i].id = conv.id then exit;
+  setLength(c.converters, L+1);
+  c.converters[L] := conv;
 end;
 
 // -------------------- embedded debugger ------------------------------------
 
 procedure embeddedDbg(c: PContext; n: PNode);
 begin
-  {@discard} inCheckpoint(n.info)
+  if optVerbose in gGlobalOptions then liMessage(n.info, hintProcessing);
+  //{@discard} inCheckpoint(n.info)
 end;
 
 // ---------------------------------------------------------------------------
@@ -207,10 +223,13 @@ var
 begin
   x := n;
   if x.kind = nkAccQuoted then x := x.sons[0];
-  if x.kind = nkIdent then result := x.ident
-  else begin
-    liMessage(n.info, errIdentifierExpected);
-    result := nil
+  case x.kind of
+    nkIdent: result := x.ident;
+    nkSym: result := x.sym.name;
+    else begin
+      liMessage(n.info, errIdentifierExpected, renderTree(n));
+      result := nil
+    end
   end
 end;
 
@@ -251,6 +270,13 @@ begin
   addSon(result, baseType);
 end;
 
+function makeVarType(c: PContext; baseType: PType): PType;
+begin
+  assert(baseType <> nil);
+  result := newTypeS(tyVar, c);
+  addSon(result, baseType);
+end;
+
 {$include 'lookup.pas'}
 
 function semIdentVis(c: PContext; kind: TSymKind; n: PNode;
@@ -261,10 +287,15 @@ function semIdentWithPragma(c: PContext; kind: TSymKind;
 
 function semStmt(c: PContext; n: PNode): PNode; forward;
 function semStmtScope(c: PContext; n: PNode): PNode; forward;
+
+type
+  TExprFlag = (efAllowType, efLValue);
+  TExprFlags = set of TExprFlag;
+
 function semExpr(c: PContext; n: PNode;
-                 typeAllowed: bool = false): PNode; forward;
+                 flags: TExprFlags = {@set}[]): PNode; forward;
 function semExprWithType(c: PContext; n: PNode;
-                         typeAllowed: bool): PNode; forward;
+                         flags: TExprFlags = {@set}[]): PNode; forward;
 function semLambda(c: PContext; n: PNode): PNode; forward;
 function semTypeNode(c: PContext; n: PNode; prev: PType): PType; forward;
 
@@ -275,6 +306,11 @@ function getConstExpr(c: PContext; n: PNode): PNode; forward;
   // evaluates the constant expression or returns nil if it is no constant
   // expression
 
+function eval(c: PContext; n: PNode): PNode; forward;
+// eval never returns nil! This simplifies the code a lot and
+// makes it faster too.
+
+
 {$include 'semtempl.pas'}
 {$include 'instgen.pas'}
 {$include 'sigmatch.pas'}
@@ -303,6 +339,11 @@ begin
   if (n = nil) or (sonsLen(n) <> len) then illFormedAst(n);
 end;
 
+procedure checkMinSonsLen(n: PNode; len: int);
+begin
+  if (n = nil) or (sonsLen(n) < len) then illFormedAst(n);
+end;
+
 procedure typeMismatch(n: PNode; formal, actual: PType);
 begin
   liMessage(n.Info, errGenerated,
@@ -315,6 +356,7 @@ end;
 {$include 'transf.pas'}
 {$include 'semstmts.pas'}
 {$include 'semfold.pas'}
+{$include 'eval.pas'}
 
 function semp(c: PContext; n: PNode): PNode;
 begin
@@ -329,7 +371,7 @@ begin
   for i := 0 to sonsLen(c.generics)-1 do begin
     assert(c.generics.sons[i].sons[1].kind = nkSym);
     prc := c.generics.sons[i].sons[1].sym;
-    if (prc.kind = skProc) and (prc.magic = mNone) then begin
+    if (prc.kind in [skProc, skConverter]) and (prc.magic = mNone) then begin
       addSon(n, prc.ast);
     end
   end
@@ -350,4 +392,7 @@ begin
   c.p := nil;
 end;
 
+initialization
+  new(emptyNode);
+  emptyNode.kind := nkEmpty;
 end.
diff --git a/nim/semexprs.pas b/nim/semexprs.pas
index 66f9b1e3f..699998a94 100644
--- a/nim/semexprs.pas
+++ b/nim/semexprs.pas
@@ -10,32 +10,34 @@
 
 // this module does the semantic checking for expressions
 
-function semDotExpr(c: PContext; n: PNode; typeAllowed: bool): PNode; forward;
+function semDotExpr(c: PContext; n: PNode;
+                    flags: TExprFlags = {@set}[]): PNode; forward;
 
 function semExprWithType(c: PContext; n: PNode;
-                         typeAllowed: bool): PNode;
+                         flags: TExprFlags = {@set}[]): PNode;
+var
+  d: PNode;
 begin
-  result := semExpr(c, n, typeAllowed);
+  result := semExpr(c, n, flags);
   if result.typ = nil then
     liMessage(n.info, errExprXHasNoType,
               renderTree(result, {@set}[renderNoComments]));
+  if result.typ.kind = tyVar then begin
+    d := newNodeIT(nkHiddenDeref, result.info, result.typ.sons[0]);
+    addSon(d, result);
+    result := d
+  end
 end;
 
 procedure checkConversionBetweenObjects(const info: TLineInfo;
                                         castDest, src: PType);
 var
-  d, s: PType;
+  diff: int;
 begin
-  // conversion to superclass?
-  d := castDest;
-  while (d <> src) and (d <> nil) do d := base(d);
-  if d = src then exit; // is ok
-  // conversion to baseclass?
-  s := src;
-  while (castDest <> s) and (s <> nil) do s := base(s);
-  if (castDest = s) then
+  diff := inheritanceDiff(castDest, src);
+  if diff = 0 then
     liMessage(info, hintConvToBaseNotNeeded)
-  else
+  else if diff = high(int) then
     liMessage(info, errGenerated,
       format(MsgKindToString(errIllegalConvFromXtoY),
         [typeToString(src), typeToString(castDest)]));
@@ -95,35 +97,29 @@ begin
   else if ss < 0 then result := false
   else
     result := (ds >= ss) or
-      (castDest.kind in [tyInt..tyFloat128]) and // BUGFIX
+      (castDest.kind in [tyInt..tyFloat128]) or
       (src.kind in [tyInt..tyFloat128])
 end;
 
 function semConv(c: PContext; n: PNode; s: PSym): PNode;
 begin
-  if sonsLen(n) = 2 then begin
-    result := newNode(nkConv);
-    result.info := n.info;
-    result.typ := semTypeNode(c, n.sons[0], nil);
-    addSon(result, semExprWithType(c, n.sons[1], false));
-    checkConvertible(result.info, result.typ, result.sons[0].typ);
-  end
-  else begin
-    liMessage(n.info, errConvNeedsOneArg);
-    result := nil
-  end
+  if sonsLen(n) <> 2 then liMessage(n.info, errConvNeedsOneArg);
+  result := newNodeI(nkConv, n.info);
+  result.typ := semTypeNode(c, n.sons[0], nil);
+  addSon(result, copyTree(n.sons[0]));
+  addSon(result, semExprWithType(c, n.sons[1]));
+  checkConvertible(result.info, result.typ, result.sons[1].typ);
 end;
 
 function semCast(c: PContext; n: PNode): PNode;
 begin
-  if optSafeCode in gGlobalOptions then
-    liMessage(n.info, errCastNotInSafeMode);
-  assert(sonsLen(n) = 2);
-  result := newNode(nkCast);
-  result.info := n.info;
+  if optSafeCode in gGlobalOptions then liMessage(n.info, errCastNotInSafeMode);
+  checkSonsLen(n, 2);
+  result := newNodeI(nkCast, n.info);
   result.typ := semTypeNode(c, n.sons[0], nil);
-  addSon(result, semExprWithType(c, n.sons[1], false));
-  if not isCastable(result.typ, result.sons[0].Typ) then
+  addSon(result, copyTree(n.sons[0]));
+  addSon(result, semExprWithType(c, n.sons[1]));
+  if not isCastable(result.typ, result.sons[1].Typ) then
     liMessage(result.info, errExprCannotBeCastedToX, typeToString(result.Typ));
 end;
 
@@ -136,7 +132,7 @@ begin
   if sonsLen(n) <> 2 then
     liMessage(n.info, errXExpectsTypeOrValue, opToStr[m])
   else begin
-    n.sons[1] := semExprWithType(c, n.sons[1], true);
+    n.sons[1] := semExprWithType(c, n.sons[1], {@set}[efAllowType]);
     typ := skipVarGenericRange(n.sons[1].typ);
     case typ.Kind of
       tySequence, tyString, tyOpenArray: begin
@@ -160,11 +156,31 @@ begin
   if sonsLen(n) <> 2 then
     liMessage(n.info, errXExpectsTypeOrValue, 'sizeof')
   else
-    n.sons[1] := semExprWithType(c, n.sons[1], true);
+    n.sons[1] := semExprWithType(c, n.sons[1], {@set}[efAllowType]);
   n.typ := getSysType(tyInt);
   result := n
 end;
 
+function semIs(c: PContext; n: PNode): PNode;
+var
+  a, b: PType;
+begin
+  if sonsLen(n) = 3 then begin
+    n.sons[1] := semExprWithType(c, n.sons[1], {@set}[efAllowType]);
+    n.sons[2] := semExprWithType(c, n.sons[2], {@set}[efAllowType]);
+    a := n.sons[1].typ;
+    b := n.sons[2].typ;
+    if (b.kind <> tyObject) or (a.kind <> tyObject) then
+      liMessage(n.info, errIsExpectsObjectTypes);
+    while (b <> nil) and (b.id <> a.id) do b := b.sons[0];
+    if b = nil then
+      liMessage(n.info, errXcanNeverBeOfThisSubtype, typeToString(a));
+  end
+  else
+    liMessage(n.info, errIsExpectsTwoArguments);
+  result := n;
+end;
+
 procedure semOpAux(c: PContext; n: PNode);
 var
   i: int;
@@ -174,14 +190,14 @@ begin
   for i := 1 to sonsLen(n)-1 do begin
     a := n.sons[i];
     if a.kind = nkExprEqExpr then begin
+      checkSonsLen(a, 2);
       info := a.sons[0].info;
-      a.sons[0] := newIdentNode(considerAcc(a.sons[0]));
-      a.sons[0].info := info;
-      a.sons[1] := semExprWithType(c, a.sons[1], false);
+      a.sons[0] := newIdentNode(considerAcc(a.sons[0]), info);
+      a.sons[1] := semExprWithType(c, a.sons[1]);
       a.typ := a.sons[1].typ;
     end
     else
-      n.sons[i] := semExprWithType(c, a, false);
+      n.sons[i] := semExprWithType(c, a);
   end
 end;
 
@@ -196,9 +212,8 @@ begin
     result := nil
   end
   else begin
-    result := newNode(nkCall);
-    result.info := n.info;
-    addSon(result, newIdentNode(par));
+    result := newNodeI(nkCall, n.info);
+    addSon(result, newIdentNode(par, n.info));
     for i := 0 to sonsLen(n)-1 do addSon(result, n.sons[i]);
     result := semExpr(c, result)
   end
@@ -208,43 +223,72 @@ procedure changeType(n: PNode; newType: PType);
 var
   i: int;
   f: PSym;
-  m: PNode;
+  a, m: PNode;
 begin
   case n.kind of
-    nkSetConstr, nkConstSetConstr,
-    nkArrayConstr, nkConstArrayConstr: begin
-      for i := 0 to sonsLen(n)-1 do
-        changeType(n.sons[i], elemType(newType));
-    end;
-    nkRecordConstr, nkConstRecordConstr: begin
-      for i := 0 to sonsLen(n)-1 do begin
-        m := n.sons[i].sons[0];
-        if m.kind <> nkSym then
-          internalError(m.info, 'changeType(): invalid record constr');
-        if not (newType.kind in [tyRecord, tyObject]) then
-          internalError(m.info, 'changeType(): invalid type');
-        f := lookupInRecord(newType.n, m.sym.name);
-        if f = nil then
-          internalError(m.info, 'changeType(): invalid identifier');
-        changeType(n.sons[i].sons[1], f.typ);
-      end
+    nkCurly, nkBracket: begin
+      for i := 0 to sonsLen(n)-1 do changeType(n.sons[i], elemType(newType));
     end;
     nkPar: begin
       if newType.kind <> tyTuple then
-        internalError(n.info, 'changeType(): no tuple type');
-      for i := 0 to sonsLen(n)-1 do
-        changeType(n.sons[i], newType.sons[i]);
+        InternalError(n.info, 'changeType: no tuple type for constructor');
+      if newType.n = nil then
+        InternalError(n.info, 'changeType: no tuple fields');
+      if (sonsLen(n) > 0) and (n.sons[0].kind = nkExprColonExpr) then begin
+        for i := 0 to sonsLen(n)-1 do begin
+          m := n.sons[i].sons[0];
+          if m.kind <> nkSym then
+            internalError(m.info, 'changeType(): invalid tuple constr');
+          f := getSymFromList(newType.n, m.sym.name);
+          if f = nil then
+            internalError(m.info, 'changeType(): invalid identifier');
+          changeType(n.sons[i].sons[1], f.typ);
+        end
+      end
+      else begin
+        for i := 0 to sonsLen(n)-1 do begin
+          m := n.sons[i];
+          a := newNodeIT(nkExprColonExpr, m.info, newType.sons[i]);
+          addSon(a, newSymNode(newType.n.sons[i].sym));
+          addSon(a, m);
+          changeType(m, newType.sons[i]);
+          n.sons[i] := a;
+        end;
+      end
     end;
     else begin end
   end;
   n.typ := newType;
 end;
 
+function semArrayConstr(c: PContext; n: PNode): PNode;
+var
+  typ: PType;
+  i: int;
+begin
+  result := newNode(nkBracket);
+  result.info := n.info;
+  result.typ := newTypeS(tyArrayConstr, c);
+  addSon(result.typ, nil); // index type
+  if sonsLen(n) = 0 then
+    // empty array
+    addSon(result.typ, nil) // needs an empty basetype!
+  else begin
+    addSon(result, semExprWithType(c, n.sons[0]));
+    typ := skipVar(result.sons[0].typ);
+    for i := 1 to sonsLen(n)-1 do begin
+      n.sons[i] := semExprWithType(c, n.sons[i]);
+      addSon(result, fitNode(c, typ, n.sons[i]));
+    end;
+    addSon(result.typ, typ)
+  end;
+  result.typ.sons[0] := makeRangeType(c, 0, sonsLen(result)-1);
+end;
+
 const
   ConstAbstractTypes = {@set}[tyNil, tyChar, tyInt..tyInt64,
                               tyFloat..tyFloat128,
-                              tyArrayConstr, tyRecordConstr, tyTuple,
-                              tyEmptySet, tySet];
+                              tyArrayConstr, tyTuple, tyEmptySet, tySet];
 
 procedure fixAbstractType(c: PContext; n: PNode);
 var
@@ -254,30 +298,162 @@ var
 begin
   for i := 1 to sonsLen(n)-1 do begin
     it := n.sons[i];
-    if it.kind in [nkHiddenStdConv, nkHiddenSubConv] then begin
-      if skipVarGeneric(it.typ).kind = tyOpenArray then begin
-        s := skipVarGeneric(it.sons[0].typ);
-        if (s.kind = tyArrayConstr) and (s.sons[1] = nil) then begin
-          s := copyType(s, getCurrOwner(c));
-          s.id := getID();
-          skipVarGeneric(s).sons[1] := elemType(skipVarGeneric(it.typ));
-          it.sons[0].typ := s;
+    case it.kind of
+      nkHiddenStdConv, nkHiddenSubConv: begin
+        if it.sons[1].kind = nkBracket then
+          it.sons[1] := semArrayConstr(c, it.sons[1]);
+        if skipVarGeneric(it.typ).kind = tyOpenArray then begin
+          s := skipVarGeneric(it.sons[1].typ);
+          if (s.kind = tyArrayConstr) and (s.sons[1] = nil) then begin
+            s := copyType(s, getCurrOwner(c));
+            s.id := getID();
+            skipVarGeneric(s).sons[1] := elemType(skipVarGeneric(it.typ));
+            it.sons[1].typ := s;
+          end
+        end
+        else if skipVarGeneric(it.sons[1].typ).kind in [tyNil, tyArrayConstr,
+                      tyTuple, tyEmptySet, tySet] then begin
+          s := skipVarGeneric(it.typ);
+          if s.kind = tyEmptySet then InternalError(it.info, 'fixAbstractType');
+          changeType(it.sons[1], s);
+          n.sons[i] := it.sons[1];
         end
+      end;
+      nkBracket: begin
+        // an implicitely constructed array (passed to an open array):
+        n.sons[i] := semArrayConstr(c, it);
+      end;
+      else if (it.typ = nil) or (it.typ.kind = tyEmptySet) then
+        InternalError(it.info, 'fixAbstractType: ' + renderTree(it));
+    end
+  end
+end;
+
+function skipObjConv(n: PNode): PNode;
+begin
+  case n.kind of
+    nkHiddenStdConv, nkHiddenSubConv, nkConv: begin
+      if skipPtrsGeneric(n.sons[1].typ).kind in [tyTuple, tyObject] then
+        result := n.sons[1]
+      else
+        result := n
+    end;
+    nkObjUpConv, nkObjDownConv: result := n.sons[0];
+    else result := n
+  end
+end;
+
+function isAssignable(n: PNode): bool;
+begin
+  result := false;
+  case n.kind of
+    nkSym: result := n.sym.kind in [skVar, skTemp];
+    nkDotExpr, nkQualified, nkBracketExpr: begin
+      checkMinSonsLen(n, 1);
+      if skipGeneric(n.sons[0].typ).kind in [tyVar, tyPtr, tyRef] then
+        result := true
+      else
+        result := isAssignable(n.sons[0]);
+    end;
+    nkHiddenStdConv, nkHiddenSubConv, nkConv: begin
+      // Object and tuple conversions are still addressable, so we skip them
+      if skipPtrsGeneric(n.sons[1].typ).kind in [tyOpenArray,
+                                                 tyTuple, tyObject] then
+        result := isAssignable(n.sons[1])
+    end;
+    nkHiddenDeref, nkDerefExpr: result := true;
+    nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
+      result := isAssignable(n.sons[0]);
+    else begin end
+  end
+end;
+
+function newHiddenAddrTaken(c: PContext; n: PNode): PNode;
+begin
+  if n.kind = nkHiddenDeref then begin
+    checkSonsLen(n, 1);
+    result := n.sons[0]
+  end
+  else begin
+    result := newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ));
+    addSon(result, n);
+    if not isAssignable(n) then liMessage(n.info, errVarForOutParamNeeded);
+  end
+end;
+
+function analyseIfAddressTaken(c: PContext; n: PNode): PNode;
+begin
+  result := n;
+  case n.kind of
+    nkSym: begin
+      if skipGeneric(n.sym.typ).kind <> tyVar then begin
+        include(n.sym.flags, sfAddrTaken);
+        result := newHiddenAddrTaken(c, n);
       end
-      else if skipVarGeneric(it.sons[0].typ).kind in [tyNil, tyArrayConstr,
-                                                 tyRecordConstr, tyTuple,
-                                                 tyEmptySet, tySet] then begin
-        s := skipVarGeneric(it.typ);
-        if s.kind = tyEmptySet then InternalError(it.info, 'fixAbstractType');
-        changeType(it.sons[0], s);
-        n.sons[i] := it.sons[0];
+    end;
+    nkDotExpr, nkQualified: begin
+      checkSonsLen(n, 2);
+      if n.sons[1].kind <> nkSym then
+        internalError(n.info, 'analyseIfAddressTaken');
+      if skipGeneric(n.sons[1].sym.typ).kind <> tyVar then begin
+        include(n.sons[1].sym.flags, sfAddrTaken);
+        result := newHiddenAddrTaken(c, n);
       end
-    end
-    else if it.typ.kind = tyEmptySet then
-      InternalError(it.info, 'fixAbstractType: 2');
+    end;
+    nkBracketExpr: begin
+      checkMinSonsLen(n, 1);
+      if skipGeneric(n.sons[0].typ).kind <> tyVar then begin
+        if n.sons[0].kind = nkSym then
+          include(n.sons[0].sym.flags, sfAddrTaken);
+        result := newHiddenAddrTaken(c, n);
+      end
+    end;
+    else result := newHiddenAddrTaken(c, n);  // BUGFIX!
   end
 end;
 
+procedure analyseIfAddressTakenInCall(c: PContext; n: PNode);
+const
+  FakeVarParams = {@set}[mNew, mNewFinalize, mInc, mDec, mIncl,
+                         mExcl, mSetLengthStr, mSetLengthSeq,
+                         mAppendStrCh, mAppendStrStr, mSwap,
+                         mAppendSeqElem, mAppendSeqSeq];
+var
+  i: int;
+  t: PType;
+begin
+  checkMinSonsLen(n, 1);
+  t := n.sons[0].typ;
+  if (n.sons[0].kind = nkSym)
+      and (n.sons[0].sym.magic in FakeVarParams) then exit;
+  for i := 1 to sonsLen(n)-1 do
+    if (i < sonsLen(t)) and (skipGeneric(t.sons[i]).kind = tyVar) then
+      n.sons[i] := analyseIfAddressTaken(c, n.sons[i]);
+end;
+(*
+function lastPassOverArg(c: PContext; n: PNode; fakeVar: bool): PNode;
+// this pass does various things:
+// - it checks whether an address has been taken (needed for the ECMAScript
+//   code generator)
+// - it changes the type of the argument (if it is not a concrete type)
+begin
+
+end;
+
+procedure lastPassOverCall(c: PContext; n: PNode);
+var
+  i: int;
+  fakeVar: bool;
+begin
+  checkMinSonsLen(n, 1);
+  t := n.sons[0].typ;
+  fakeVar := (n.sons[0].kind = nkSym)
+      and (n.sons[0].sym.magic in FakeVarParams);
+  for i := 1 to sonsLen(n)-1 do begin
+    n.sons[i] := lastPassOverArg(c, n);
+  end
+end;*)
+
 function semIndirectOp(c: PContext; n: PNode): PNode;
 var
   m: TCandidate;
@@ -285,19 +461,21 @@ var
   i: int;
 begin
   result := nil;
+  checkMinSonsLen(n, 1);
   case n.sons[0].kind of
     nkDotExpr, nkQualified: begin
-      n.sons[0] := semDotExpr(c, n.sons[0], false);
+      checkSonsLen(n.sons[0], 2);
+      n.sons[0] := semDotExpr(c, n.sons[0]);
       if n.sons[0].kind = nkDotCall then begin // it is a static call!
         result := n.sons[0];
         result.kind := nkCall;
         for i := 1 to sonsLen(n)-1 do
           addSon(result, n.sons[i]);
-        result := semExpr(c, result, false);
+        result := semExpr(c, result);
         exit
       end
     end;
-    else n.sons[0] := semExpr(c, n.sons[0], false);
+    else n.sons[0] := semExpr(c, n.sons[0]);
   end;
   if n.sons[0].typ = nil then
     liMessage(n.sons[0].info, errExprXHasNoType,
@@ -325,6 +503,7 @@ begin
     if result = nil then liMessage(n.info, errExprCannotBeCalled);
   end;
   fixAbstractType(c, result);
+  analyseIfAddressTakenInCall(c, result);
 end;
 
 function semDirectOp(c: PContext; n: PNode): PNode;
@@ -337,6 +516,7 @@ begin
       liMessage(n.Info, errGenerated, getNotFoundError(c, n))
   end;
   fixAbstractType(c, result);
+  analyseIfAddressTakenInCall(c, result);
 end;
 
 function semIncSucc(c: PContext; n: PNode; const opr: string): PNode;
@@ -345,14 +525,14 @@ var
   a: PNode;
   typ: PType;
 begin
-  n.sons[1] := semExprWithType(c, n.sons[1], false);
+  checkMinSonsLen(n, 1);
+  n.sons[1] := semExprWithType(c, n.sons[1]);
   typ := skipVar(n.sons[1].Typ);
   if not isOrdinalType(typ) or enumHasWholes(typ) then
     liMessage(n.sons[1].Info, errOrdinalTypeExpected);
   if sonsLen(n) = 3 then begin
-    n.sons[2] := semExprWithType(c, n.sons[2], false);
-    a := IndexTypesMatch(c, getSysType(tyInt), n.sons[2].typ,
-                                 n.sons[2]);
+    n.sons[2] := semExprWithType(c, n.sons[2]);
+    a := IndexTypesMatch(c, getSysType(tyInt), n.sons[2].typ, n.sons[2]);
     if a = nil then
       typeMismatch(n.sons[2], getSysType(tyInt), n.sons[2].typ);
     n.sons[2] := a;
@@ -370,7 +550,8 @@ end;
 
 function semOrd(c: PContext; n: PNode): PNode;
 begin
-  n.sons[1] := semExprWithType(c, n.sons[1], false);
+  checkSonsLen(n, 2);
+  n.sons[1] := semExprWithType(c, n.sons[1]);
   if not isOrdinalType(skipVar(n.sons[1].Typ)) then
     liMessage(n.Info, errOrdinalTypeExpected);
   n.typ := getSysType(tyInt);
@@ -385,6 +566,7 @@ begin
   case n.kind of
     nkIdent: result := SymtabGet(c.Tab, n.ident);
     nkDotExpr, nkQualified: begin
+      checkSonsLen(n, 2);
       result := nil;
       m := LookupForDefined(c, n.sons[0]);
       if (m <> nil) and (m.kind = skModule) then begin
@@ -400,10 +582,12 @@ begin
           liMessage(n.sons[1].info, errIdentifierExpected, '');
       end
     end;
-    nkAccQuoted:
+    nkAccQuoted: begin
+      checkSonsLen(n, 1);
       result := lookupForDefined(c, n.sons[0]);
+    end
     else begin
-      liMessage(n.info, errIdentifierExpected, '');
+      liMessage(n.info, errIdentifierExpected, renderTree(n));
       result := nil;
     end
   end
@@ -411,6 +595,7 @@ end;
 
 function semDefined(c: PContext; n: PNode): PNode;
 begin
+  checkSonsLen(n, 2);
   result := newIntNode(nkIntLit, 0);
   // we replace this node by a 'true' or 'false' node
   if LookUpForDefined(c, n.sons[1]) <> nil then
@@ -437,6 +622,7 @@ begin
     mLow:     result := semLowHigh(c, setMs(n, s), mLow);
     mHigh:    result := semLowHigh(c, setMs(n, s), mHigh);
     mSizeOf:  result := semSizeof(c, setMs(n, s));
+    mIs:      result := semIs(c, setMs(n, s));
     mSucc:    begin
       result := semIncSucc(c, setMs(n, s), 'succ');
       result.typ := n.sons[1].typ;
@@ -452,13 +638,13 @@ begin
   end;
 end;
 
-function semSym(c: PContext; n: PNode; s: PSym; typeAllowed: bool): PNode;
+function semSym(c: PContext; n: PNode; s: PSym; flags: TExprFlags): PNode;
 begin
   result := newSymNode(s);
   result.info := n.info;
   result.typ := s.typ;
   include(s.flags, sfUsed);
-  if (s.kind = skType) and not typeAllowed then
+  if (s.kind = skType) and not (efAllowType in flags) then
     liMessage(n.info, errATypeHasNoValue);
   case s.kind of
     skProc, skIterator, skConverter:
@@ -496,17 +682,115 @@ begin
   end
 end;
 
-function semFieldAccess(c: PContext; n: PNode; typeAllowed: bool): PNode;
+function lookupInRecordAndBuildCheck(c: PContext; n, r: PNode;
+                                     field: PIdent;
+                                     var check: PNode): PSym;
+// transform in a node that contains the runtime check for the
+// field, if it is in a case-part...
+var
+  i, j: int;
+  s, it, inExpr, notExpr: PNode;
+begin
+  result := nil;
+  case r.kind of
+    nkRecList: begin
+      for i := 0 to sonsLen(r)-1 do begin
+        result := lookupInRecordAndBuildCheck(c, n, r.sons[i], field, check);
+        if result <> nil then exit
+      end
+    end;
+    nkRecCase: begin
+      checkMinSonsLen(r, 2);
+      if (r.sons[0].kind <> nkSym) then IllFormedAst(r);
+      result := lookupInRecordAndBuildCheck(c, n, r.sons[0], field, check);
+      if result <> nil then exit;
+      s := newNodeI(nkCurly, r.info);
+      for i := 1 to sonsLen(r)-1 do begin
+        it := r.sons[i];
+        case it.kind of
+          nkOfBranch: begin
+            result := lookupInRecordAndBuildCheck(c, n, lastSon(it),
+                                                  field, check);
+            if result = nil then begin
+              for j := 0 to sonsLen(it)-2 do addSon(s, copyTree(it.sons[j]));
+            end
+            else begin
+              if check = nil then begin
+                check := newNodeI(nkCheckedFieldExpr, n.info);
+                addSon(check, nil); // make space for access node
+              end;
+              s := newNodeI(nkCurly, n.info);
+              for j := 0 to sonsLen(it)-2 do addSon(s, copyTree(it.sons[j]));
+              inExpr := newNodeI(nkCall, n.info);
+              addSon(inExpr, newIdentNode(getIdent('in'), n.info));
+              addSon(inExpr, copyTree(r.sons[0]));
+              addSon(inExpr, s);
+              //writeln(output, renderTree(inExpr));
+              addSon(check, semExpr(c, inExpr));
+              exit
+            end
+          end;
+          nkElse: begin
+            result := lookupInRecordAndBuildCheck(c, n, lastSon(it),
+                                                  field, check);
+            if result <> nil then begin
+              if check = nil  then begin
+                check := newNodeI(nkCheckedFieldExpr, n.info);
+                addSon(check, nil); // make space for access node
+              end;
+              inExpr := newNodeI(nkCall, n.info);
+              addSon(inExpr, newIdentNode(getIdent('in'), n.info));
+              addSon(inExpr, copyTree(r.sons[0]));
+              addSon(inExpr, s);
+              notExpr := newNodeI(nkCall, n.info);
+              addSon(notExpr, newIdentNode(getIdent('not'), n.info));
+              addSon(notExpr, inExpr);
+              addSon(check, semExpr(c, notExpr));
+              exit
+            end
+          end;
+          else
+            illFormedAst(it);
+        end
+      end
+    end;
+    nkSym: begin
+      if r.sym.name.id = field.id then result := r.sym;
+    end;
+    else illFormedAst(n);
+  end
+end;
+
+function makeDeref(n: PNode): PNode;
+var
+  t: PType;
+  a: PNode;
+begin
+  t := n.typ;
+  result := n;
+  if t.kind = tyVar then begin
+    result := newNodeIT(nkHiddenDeref, n.info, t.sons[0]);
+    addSon(result, n);
+    t := t.sons[0];
+  end;
+  if t.kind in [tyPtr, tyRef] then begin
+    a := result;
+    result := newNodeIT(nkDerefExpr, n.info, t.sons[0]);
+    addSon(result, a);
+  end
+end;
+
+function semFieldAccess(c: PContext; n: PNode; flags: TExprFlags): PNode;
 var
   f: PSym;
   ty: PType;
   i: PIdent;
-  asgn: bool;
+  check: PNode;
 begin
-  asgn := false;
   // this is difficult, because the '.' is used in many different contexts
   // in Nimrod. We first allow types in the semantic checking.
-  n.sons[0] := semExprWithType(c, n.sons[0], true);
+  checkSonsLen(n, 2);
+  n.sons[0] := semExprWithType(c, n.sons[0], [efAllowType]+flags);
   i := considerAcc(n.sons[1]);
   ty := n.sons[0].Typ;
   f := nil;
@@ -527,34 +811,47 @@ begin
       liMessage(n.sons[1].info, errEnumHasNoValueX, i.s);
     exit;
   end
-  else if not typeAllowed and isTypeExpr(n.sons[0]) then begin
+  else if not (efAllowType in flags) and isTypeExpr(n.sons[0]) then begin
     liMessage(n.sons[0].info, errATypeHasNoValue);
     exit
   end;
 
-  while ty.kind = tyVar do begin ty := ty.sons[0]; asgn := true; end;
-  if ty.Kind in [tyRef, tyPtr] then begin ty := ty.sons[0]; asgn := true; end;
-  if (ty.kind in [tyRecord, tyObject]) then begin
-    while ty <> nil do begin
-      f := lookupInRecord(ty.n, i);
+  ty := skipPtrsGeneric(ty);
+  if ty.kind = tyObject then begin
+    while true do begin
+      check := nil;
+      f := lookupInRecordAndBuildCheck(c, n, ty.n, i, check);
+      //f := lookupInRecord(ty.n, i);
       if f <> nil then break;
-      ty := ty.sons[0];
+      if ty.sons[0] = nil then break;
+      ty := skipGeneric(ty.sons[0]);
     end;
     if f <> nil then begin
       if ([sfStar, sfMinus] * f.flags <> [])
       or (getModule(f).id = c.module.id) then begin
         // is the access to a public field or in the same module?
-        if not asgn then begin
-          if not (sfMinus in f.flags) or (getModule(f).id = c.module.id) then
-            asgn := tfAssignable in ty.flags;
-        end;
-
+        n.sons[0] := makeDeref(n.sons[0]);
         n.sons[1] := newSymNode(f); // we now have the correct field
-        n.typ := inheritAssignable(f.typ, asgn);
-        result := n;
+        n.typ := f.typ;
+        if check = nil then result := n
+        else begin
+          check.sons[0] := n;
+          check.typ := n.typ;
+          result := check
+        end;
         exit
       end
     end
+  end
+  else if ty.kind = tyTuple then begin
+    f := getSymFromList(ty.n, i);
+    if f <> nil then begin
+      n.sons[0] := makeDeref(n.sons[0]);
+      n.sons[1] := newSymNode(f);
+      n.typ := f.typ;
+      result := n;
+      exit
+    end
   end;
   // allow things like "".replace(...)
   // --> replace("", ...)
@@ -563,7 +860,7 @@ begin
     result := newNode(nkDotCall);
     // This special node kind is to merge with the call handler in `semExpr`.
     result.info := n.info;
-    addSon(result, newIdentNode(i));
+    addSon(result, newIdentNode(i, n.info));
     addSon(result, copyTree(n.sons[0]));
   end
   else begin
@@ -571,28 +868,32 @@ begin
   end
 end;
 
-function semArrayAccess(c: PContext; n: PNode): PNode;
+function whichSliceOpr(n: PNode): string;
+begin
+  if (n.sons[0] = nil) then
+    if (n.sons[1] = nil) then result := '[..]'
+    else result := '[..$]'
+  else if (n.sons[1] = nil) then result := '[$..]'
+  else result := '[$..$]'
+end;
+
+function semArrayAccess(c: PContext; n: PNode; flags: TExprFlags): PNode;
 var
   arr, indexType: PType;
   i: int;
-  asgn: bool;
   arg: PNode;
   idx: biggestInt;
 begin
-  asgn := false;
   // check if array type:
-  n.sons[0] := semExprWithType(c, n.sons[0], false);
-  arr := n.sons[0].typ;
-  while arr.kind = tyVar do begin arr := arr.sons[0]; asgn := true; end;
-  if arr.kind in [tyRef, tyPtr] then begin
-    arr := arr.sons[0]; asgn := true
-  end;
+  checkMinSonsLen(n, 2);
+  n.sons[0] := semExprWithType(c, n.sons[0], flags-[efAllowType]);
+  arr := skipPtrsGeneric(n.sons[0].typ);
   case arr.kind of
     tyArray, tyOpenArray, tyArrayConstr, tySequence, tyString,
     tyCString: begin
-      asgn := asgn or (tfAssignable in arr.flags) or (arr.kind = tyCString);
+      n.sons[0] := makeDeref(n.sons[0]);
       for i := 1 to sonsLen(n)-1 do
-        n.sons[i] := semExprWithType(c, n.sons[i], false);
+        n.sons[i] := semExprWithType(c, n.sons[i], flags-[efAllowType]);
       if arr.kind = tyArray then indexType := arr.sons[0]
       else indexType := getSysType(tyInt);
       arg := IndexTypesMatch(c, indexType, n.sons[1].typ, n.sons[1]);
@@ -601,9 +902,10 @@ begin
       else
         liMessage(n.info, errIndexTypesDoNotMatch);
       result := n;
-      result.typ := inheritAssignable(elemType(arr), asgn); // BUGFIX
+      result.typ := elemType(arr);
     end;
     tyTuple: begin
+      n.sons[0] := makeDeref(n.sons[0]);
       // [] operator for tuples requires constant expression
       n.sons[1] := semConstExpr(c, n.sons[1]);
       if skipRange(n.sons[1].typ).kind in [tyInt..tyInt64] then begin
@@ -618,42 +920,24 @@ begin
       result := n;
     end
     else begin // overloaded [] operator:
-      result := newNode(nkCall);
-      if n.sons[1].kind = nkRange then
-        addSon(result, newIdentNode(getIdent('[..]')))
-      else
-        addSon(result, newIdentNode(getIdent('[]')));
-      for i := 0 to sonsLen(n)-1 do
-        addSon(result, n.sons[i]);
+      result := newNodeI(nkCall, n.info);
+      if n.sons[1].kind = nkRange then begin
+        checkSonsLen(n.sons[1], 2);
+        addSon(result, newIdentNode(getIdent(whichSliceOpr(n.sons[1])), n.info));
+        addSon(result, n.sons[0]);
+        addSonIfNotNil(result, n.sons[1].sons[0]);
+        addSonIfNotNil(result, n.sons[1].sons[1]);
+      end
+      else begin
+        addSon(result, newIdentNode(getIdent('[]'), n.info));
+        addSon(result, n.sons[0]);
+        addSon(result, n.sons[1]);
+      end;
       result := semExpr(c, result);
     end
   end
 end;
 
-function semArrayConstr(c: PContext; n: PNode): PNode;
-var
-  typ: PType;
-  i: int;
-begin
-  result := newNode(nkArrayConstr);
-  result.info := n.info;
-  result.typ := newTypeS(tyArrayConstr, c);
-  addSon(result.typ, nil); // index type
-  if sonsLen(n) = 0 then
-    // empty array
-    addSon(result.typ, nil) // needs an empty basetype!
-  else begin
-    addSon(result, semExprWithType(c, n.sons[0], false));
-    typ := skipVar(result.sons[0].typ);
-    for i := 1 to sonsLen(n)-1 do begin
-      n.sons[i] := semExprWithType(c, n.sons[i], false);
-      addSon(result, fitNode(c, typ, n.sons[i]));
-    end;
-    addSon(result.typ, typ)
-  end;
-  result.typ.sons[0] := makeRangeType(c, 0, sonsLen(result)-1);
-end;
-
 function semIfExpr(c: PContext; n: PNode): PNode;
 var
   typ: PType;
@@ -661,23 +945,26 @@ var
   it: PNode;
 begin
   result := n;
+  checkSonsLen(n, 2);
   typ := nil;
   for i := 0 to sonsLen(n) - 1 do begin
     it := n.sons[i];
     case it.kind of
       nkElifExpr: begin
-        it.sons[0] := semExprWithType(c, it.sons[0], false);
+        checkSonsLen(it, 2);
+        it.sons[0] := semExprWithType(c, it.sons[0]);
         checkBool(it.sons[0]);
-        it.sons[1] := semExprWithType(c, it.sons[1], false);
+        it.sons[1] := semExprWithType(c, it.sons[1]);
         if typ = nil then typ := it.sons[1].typ
         else it.sons[1] := fitNode(c, typ, it.sons[1])
       end;
       nkElseExpr: begin
-        it.sons[0] := semExprWithType(c, it.sons[0], false);
+        checkSonsLen(it, 1);
+        it.sons[0] := semExprWithType(c, it.sons[0]);
         assert(typ <> nil);
         it.sons[0] := fitNode(c, typ, it.sons[0]);
       end;
-      else internalError(it.info, 'semIfExpr()');
+      else illFormedAst(n);
     end
   end;
   result.typ := typ;
@@ -689,7 +976,7 @@ var
   i: int;
   m: PNode;
 begin
-  result := newNode(nkSetConstr);
+  result := newNode(nkCurly);
   result.info := n.info;
   if sonsLen(n) = 0 then
     result.typ := newTypeS(tyEmptySet, c)
@@ -698,13 +985,14 @@ begin
     typ := nil;
     for i := 0 to sonsLen(n)-1 do begin
       if n.sons[i].kind = nkRange then begin
-        n.sons[i].sons[0] := semExprWithType(c, n.sons[i].sons[0], false);
-        n.sons[i].sons[1] := semExprWithType(c, n.sons[i].sons[1], false);
+        checkSonsLen(n.sons[i], 2);
+        n.sons[i].sons[0] := semExprWithType(c, n.sons[i].sons[0]);
+        n.sons[i].sons[1] := semExprWithType(c, n.sons[i].sons[1]);
         if typ = nil then typ := skipVar(n.sons[i].sons[0].typ);
         n.sons[i].typ := n.sons[i].sons[1].typ; // range node needs type too
       end
       else begin
-        n.sons[i] := semExprWithType(c, n.sons[i], false);
+        n.sons[i] := semExprWithType(c, n.sons[i]);
         if typ = nil then typ := skipVar(n.sons[i].typ)
       end
     end;
@@ -734,20 +1022,20 @@ begin
 end;
 
 type
-  TParKind = (paNone, paSingle, paRecord, paTuple);
+  TParKind = (paNone, paSingle, paTupleFields, paTuplePositions);
 
 function checkPar(n: PNode): TParKind;
 var
   i, len: int;
 begin
   len := sonsLen(n);
-  if len = 0 then result := paTuple // ()
+  if len = 0 then result := paTuplePositions // ()
   else if len = 1 then result := paSingle // (expr)
   else begin
-    if n.sons[0].kind = nkExprColonExpr then result := paRecord
-    else result := paTuple;
+    if n.sons[0].kind = nkExprColonExpr then result := paTupleFields
+    else result := paTuplePositions;
     for i := 0 to len-1 do begin
-      if result = paRecord then begin
+      if result = paTupleFields then begin
         if (n.sons[i].kind <> nkExprColonExpr)
         or (n.sons[i].sons[0].kind <> nkIdent) then begin
           liMessage(n.sons[i].info, errNamedExprExpected);
@@ -764,7 +1052,7 @@ begin
   end
 end;
 
-function semRecordConstr(c: PContext; n: PNode): PNode;
+function semTupleFieldsConstr(c: PContext; n: PNode): PNode;
 var
   i: int;
   typ: PType;
@@ -772,9 +1060,9 @@ var
   id: PIdent;
   f: PSym;
 begin
-  result := newNode(nkRecordConstr);
+  result := newNode(nkPar);
   result.info := n.info;
-  typ := newTypeS(tyRecordConstr, c);
+  typ := newTypeS(tyTuple, c);
   typ.n := newNode(nkRecList); // nkIdentDefs
   IntSetInit(ids);
   for i := 0 to sonsLen(n)-1 do begin
@@ -784,9 +1072,10 @@ begin
     id := n.sons[i].sons[0].ident;
     if IntSetContainsOrIncl(ids, id.id) then
       liMessage(n.sons[i].info, errFieldInitTwice, id.s);
-    n.sons[i].sons[1] := semExprWithType(c, n.sons[i].sons[1], false);
+    n.sons[i].sons[1] := semExprWithType(c, n.sons[i].sons[1]);
     f := newSymS(skField, n.sons[i].sons[0], c);
     f.typ := n.sons[i].sons[1].typ;
+    addSon(typ, f.typ);
     addSon(typ.n, newSymNode(f));
     n.sons[i].sons[0] := newSymNode(f);
     addSon(result, n.sons[i]);
@@ -794,15 +1083,16 @@ begin
   result.typ := typ;
 end;
 
-function semTupleConstr(c: PContext; n: PNode): PNode;
+function semTuplePositionsConstr(c: PContext; n: PNode): PNode;
 var
   i: int;
   typ: PType;
 begin
   result := n; // we don't modify n, but compute the type:
   typ := newTypeS(tyTuple, c);
+  // leave typ.n nil!
   for i := 0 to sonsLen(n)-1 do begin
-    n.sons[i] := semExprWithType(c, n.sons[i], false);
+    n.sons[i] := semExprWithType(c, n.sons[i]);
     addSon(typ, n.sons[i].typ);
   end;
   result.typ := typ;
@@ -813,12 +1103,13 @@ var
   len, i: int;
 begin
   result := n;
+  checkMinSonsLen(n, 1);
   len := sonsLen(n);
   for i := 0 to len-2 do begin
     n.sons[i] := semStmt(c, n.sons[i]);
   end;
   if len > 0 then begin
-    n.sons[len-1] := semExprWithType(c, n.sons[len-1], false);
+    n.sons[len-1] := semExprWithType(c, n.sons[len-1]);
     n.typ := n.sons[len-1].typ
   end
 end;
@@ -827,51 +1118,49 @@ function semBlockExpr(c: PContext; n: PNode): PNode;
 begin
   result := n;
   Inc(c.p.nestedBlockCounter);
-  if sonsLen(n) = 2 then begin
-    openScope(c.tab); // BUGFIX: label is in the scope of block!
-    if n.sons[0] <> nil then begin
-      addDecl(c, newSymS(skLabel, n.sons[0], c))
-    end;
-    n.sons[1] := semStmtListExpr(c, n.sons[1]);
-    n.typ := n.sons[1].typ;
-    closeScope(c.tab);
-  end
-  else
-    illFormedAst(n);
+  checkSonsLen(n, 2);
+  openScope(c.tab); // BUGFIX: label is in the scope of block!
+  if n.sons[0] <> nil then begin
+    addDecl(c, newSymS(skLabel, n.sons[0], c))
+  end;
+  n.sons[1] := semStmtListExpr(c, n.sons[1]);
+  n.typ := n.sons[1].typ;
+  closeScope(c.tab);
   Dec(c.p.nestedBlockCounter);
 end;
 
-function semDotExpr(c: PContext; n: PNode; typeAllowed: bool): PNode;
+function semDotExpr(c: PContext; n: PNode; flags: TExprFlags): PNode;
 var
   s: PSym;
 begin
   s := qualifiedLookup(c, n, true); // check for ambiguity
   if s <> nil then
-    result := semSym(c, n, s, typeAllowed)
+    result := semSym(c, n, s, flags)
   else
-    // record access: if the field does not exist, check for a proc:
-    result := semFieldAccess(c, n, typeAllowed);
+    // test!
+    result := semFieldAccess(c, n, flags);
 end;
 
-function semExpr(c: PContext; n: PNode; typeAllowed: bool = false): PNode;
+function semMacroExpr(c: PContext; n: PNode; sym: PSym): PNode; forward;
+
+function semExpr(c: PContext; n: PNode; flags: TExprFlags = {@set}[]): PNode;
 var
   s: PSym;
 begin
   result := n;
   if n = nil then exit;
-  embeddedDbg(c, n);
   case n.kind of
     // atoms:
     nkIdent: begin
       // lookup the symbol:
       s := SymtabGet(c.Tab, n.ident);
-      if s <> nil then result := semSym(c, n, s, typeAllowed)
+      if s <> nil then result := semSym(c, n, s, flags)
       else liMessage(n.info, errUndeclaredIdentifier, n.ident.s);
     end;
     nkSym: begin
       s := n.sym;
       include(s.flags, sfUsed);
-      if (s.kind = skType) and not typeAllowed then
+      if (s.kind = skType) and not (efAllowType in flags) then
         liMessage(n.info, errATypeHasNoValue);
       if s.magic <> mNone then
         liMessage(n.info, errInvalidContextForBuiltinX, s.name.s);
@@ -879,30 +1168,32 @@ begin
     nkEmpty, nkNone: begin end;
     nkNilLit: result.typ := getSysType(tyNil);
     nkType: begin
-      if not typeAllowed then liMessage(n.info, errATypeHasNoValue);
+      if not (efAllowType in flags) then liMessage(n.info, errATypeHasNoValue);
       n.typ := semTypeNode(c, n, nil);
     end;
-    nkIntLit: result.typ := getSysType(tyInt);
-    nkInt8Lit: result.typ := getSysType(tyInt8);
-    nkInt16Lit: result.typ := getSysType(tyInt16);
-    nkInt32Lit: result.typ := getSysType(tyInt32);
-    nkInt64Lit: result.typ := getSysType(tyInt64);
-    nkFloatLit: result.typ := getSysType(tyFloat);
-    nkFloat32Lit: result.typ := getSysType(tyFloat32);
-    nkFloat64Lit: result.typ := getSysType(tyFloat64);
-    nkStrLit..nkTripleStrLit: result.typ := getSysType(tyString);
-    nkCharLit, nkRCharLit: result.typ := getSysType(tyChar);
-
+    nkIntLit: if result.typ = nil then result.typ := getSysType(tyInt);
+    nkInt8Lit: if result.typ = nil then result.typ := getSysType(tyInt8);
+    nkInt16Lit: if result.typ = nil then result.typ := getSysType(tyInt16);
+    nkInt32Lit: if result.typ = nil then result.typ := getSysType(tyInt32);
+    nkInt64Lit: if result.typ = nil then result.typ := getSysType(tyInt64);
+    nkFloatLit: if result.typ = nil then result.typ := getSysType(tyFloat);
+    nkFloat32Lit: if result.typ = nil then result.typ := getSysType(tyFloat32);
+    nkFloat64Lit: if result.typ = nil then result.typ := getSysType(tyFloat64);
+    nkStrLit..nkTripleStrLit:
+      if result.typ = nil then result.typ := getSysType(tyString);
+    nkCharLit:
+      if result.typ = nil then result.typ := getSysType(tyChar);
     nkQualified, nkDotExpr: begin
-      result := semDotExpr(c, n, typeAllowed);
+      result := semDotExpr(c, n, flags);
       if result.kind = nkDotCall then begin
         result.kind := nkCall;
-        result := semExpr(c, result, typeAllowed)
+        result := semExpr(c, result, flags)
       end;
     end;
     // complex expressions
     nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand: begin
       // check if it is an expression macro:
+      checkMinSonsLen(n, 1);
       s := qualifiedLookup(c, n.sons[0], false);
       if (s <> nil) then begin
         case s.kind of
@@ -918,9 +1209,9 @@ begin
           end;
           skType: begin
             include(s.flags, sfUsed);
-            result := semConv(c, n, s);
             if n.kind <> nkCall then
-              liMessage(n.info, errXisNotCallable, s.name.s)
+              liMessage(n.info, errXisNotCallable, s.name.s);
+            result := semConv(c, n, s);
           end;
           skProc, skConverter, skIterator: begin
             if s.magic = mNone then result := semDirectOp(c, n)
@@ -932,6 +1223,7 @@ begin
       else result := semIndirectOp(c, n);
     end;
     nkBracketExpr: begin
+      checkMinSonsLen(n, 1);
       s := qualifiedLookup(c, n.sons[0], false);
       if (s <> nil) and (s.kind in [skProc, skConverter, skIterator]) then begin
         // type parameters: partial generic specialization
@@ -940,7 +1232,7 @@ begin
         result := partialSpecialization(c, n, s);
       end
       else begin
-        result := semArrayAccess(c, n);
+        result := semArrayAccess(c, n, flags);
       end
     end;
     nkPragmaExpr: begin
@@ -948,53 +1240,45 @@ begin
       internalError(n.info, 'semExpr() to implement');
       // XXX: to implement
     end;
-    nkPar, nkRecordConstr, nkConstRecordConstr: begin
+    nkPar: begin
       case checkPar(n) of
         paNone: result := nil;
-        paTuple:  result := semTupleConstr(c, n);
-        paRecord: result := semRecordConstr(c, n);
-        paSingle: result := semExpr(c, n.sons[0], typeAllowed);
+        paTuplePositions:  result := semTuplePositionsConstr(c, n);
+        paTupleFields: result := semTupleFieldsConstr(c, n);
+        paSingle: result := semExpr(c, n.sons[0]);
       end;
     end;
-    nkCurly, nkSetConstr, nkConstSetConstr: begin
-      result := semSetConstr(c, n);
-    end;
-    nkBracket, nkArrayConstr, nkConstArrayConstr: begin
-      result := semArrayConstr(c, n);
-    end;
-    nkLambda: begin
-      result := semLambda(c, n); // handled in semstmts
-    end;
+    nkCurly: result := semSetConstr(c, n);
+    nkBracket: result := semArrayConstr(c, n);
+    nkLambda: result := semLambda(c, n); // handled in semstmts
     nkExprColonExpr: begin
       internalError(n.info, 'semExpr() to implement');
       // XXX: to implement for array constructors!
     end;
     nkDerefExpr: begin
-      if sonsLen(n) = 1 then begin
-        n.sons[0] := semExprWithType(c, n.sons[0], typeAllowed);
-        result := n;
-        case n.sons[0].typ.kind of
-          tyRef, tyPtr: n.typ := n.sons[0].typ.sons[0];
-          else liMessage(n.sons[0].info, errCircumNeedsPointer);
-        end;
-        result := n;
-        result.typ := inheritAssignable(result.typ, true);
-      end
-      else
-        illFormedAst(n)
+      checkSonsLen(n, 1);
+      n.sons[0] := semExprWithType(c, n.sons[0]);
+      result := n;
+      case skipVarGeneric(n.sons[0].typ).kind of
+        tyRef, tyPtr: n.typ := n.sons[0].typ.sons[0];
+        else liMessage(n.sons[0].info, errCircumNeedsPointer);
+      end;
+      result := n;
     end;
     nkAddr: begin
       result := n;
-      n.sons[0] := semExprWithType(c, n.sons[0], false);
-      //if not (tfAssignable in n.sons[0].typ.flags) then
-      //  liMessage(n.info, errExprHasNoAddress);
-      // XXX: the above check is not correct for parameters
+      checkSonsLen(n, 1);
+      n.sons[0] := semExprWithType(c, n.sons[0]);
+      if not isAssignable(n.sons[0]) then liMessage(n.info, errExprHasNoAddress);
       n.typ := makePtrType(c, n.sons[0].typ);
     end;
-    nkCast: begin
-      result := semCast(c, n);
+    nkHiddenAddr, nkHiddenDeref: begin
+      checkSonsLen(n, 1);
+      n.sons[0] := semExpr(c, n.sons[0], flags);
     end;
+    nkCast: result := semCast(c, n);
     nkAccQuoted: begin
+      checkSonsLen(n, 1);
       result := semExpr(c, n.sons[0]);
     end;
     nkHeaderQuoted: begin
@@ -1002,16 +1286,20 @@ begin
       internalError(n.info, 'semExpr() to implement');
       // XXX: to implement
     end;
-    nkIfExpr: begin
-      result := semIfExpr(c, n);
-    end;
-    nkStmtListExpr: begin
-      result := semStmtListExpr(c, n);
-    end;
-    nkBlockExpr: begin
-      result := semBlockExpr(c, n);
-    end;
+    nkIfExpr: result := semIfExpr(c, n);
+    nkStmtListExpr: result := semStmtListExpr(c, n);
+    nkBlockExpr: result := semBlockExpr(c, n);
+    nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv:
+      checkSonsLen(n, 2);
+    nkStringToCString, nkCStringToString, nkPassAsOpenArray, nkObjDownConv,
+    nkObjUpConv:
+      checkSonsLen(n, 1);
+    nkChckRangeF, nkChckRange64, nkChckRange:
+      checkSonsLen(n, 3);
+    nkCheckedFieldExpr:
+      checkMinSonsLen(n, 2);
     else begin
+      //InternalError(n.info, nodeKindToStr[n.kind]);
       liMessage(n.info, errInvalidExpressionX,
                 renderTree(n, {@set}[renderNoComments]));
       result := nil
diff --git a/nim/semfold.pas b/nim/semfold.pas
index 2edc2e7a0..00d84f836 100644
--- a/nim/semfold.pas
+++ b/nim/semfold.pas
@@ -62,7 +62,7 @@ function getStrOrChar(a: PNode): string;
 begin
   case a.kind of
     nkStrLit..nkTripleStrLit: result := a.strVal;
-    nkCharLit, nkRCharLit: result := chr(int(a.intVal))+'';
+    nkCharLit: result := chr(int(a.intVal))+'';
     else begin internalError(a.info, 'getStrOrChar'); result := '' end;
   end
 end;
@@ -81,11 +81,11 @@ begin
     mBitnotI, mBitnotI64: result := newIntNodeT(not getInt(a), n);
 
     mLengthStr: result := newIntNodeT(length(getStr(a)), n);
-    mLengthSeq, mLengthArray, 
+    mLengthSeq, mLengthArray,
     mLengthOpenArray: result := newIntNodeT(lengthOrd(a.typ), n);
-    
+
     mUnaryPlusI, mUnaryPlusI64, mUnaryPlusF64: result := a; // throw `+` away
-    mToFloat, mToBiggestFloat: 
+    mToFloat, mToBiggestFloat:
       result := newFloatNodeT(toFloat(int(getInt(a))), n);
     mToInt, mToBiggestInt: result := newIntNodeT(nsystem.toInt(getFloat(a)), n);
     mAbsF64: result := newFloatNodeT(abs(getFloat(a)), n);
@@ -93,11 +93,13 @@ begin
       if getInt(a) >= 0 then result := a
       else result := newIntNodeT(-getInt(a), n);
     end;
-    mZe, mZe64:
+    mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64: begin
+      // byte(-128) = 1...1..1000_0000'64 --> 0...0..1000_0000'64
       result := newIntNodeT(getInt(a) and (1 shl a.typ.size*8 - 1), n);
+    end;
     mToU8:  result := newIntNodeT(getInt(a) and $ff, n);
     mToU16: result := newIntNodeT(getInt(a) and $ffff, n);
-    mToU32: result := newIntNodeT(getInt(a) and $ffffffff, n);
+    mToU32: result := newIntNodeT(getInt(a) and $00000000ffffffff, n);
 
     mSucc: result := newIntNodeT(getOrdValue(a)+getInt(b), n);
     mPred: result := newIntNodeT(getOrdValue(a)-getInt(b), n);
@@ -121,7 +123,16 @@ begin
     mAddF64: result := newFloatNodeT(getFloat(a)+getFloat(b), n);
     mSubF64: result := newFloatNodeT(getFloat(a)-getFloat(b), n);
     mMulF64: result := newFloatNodeT(getFloat(a)*getFloat(b), n);
-    mDivF64: result := newFloatNodeT(getFloat(a)/getFloat(b), n);
+    mDivF64: begin
+      if getFloat(b) = 0.0 then begin
+        if getFloat(a) = 0.0 then
+          result := newFloatNodeT(NaN, n)
+        else
+          result := newFloatNodeT(Inf, n);
+      end
+      else
+        result := newFloatNodeT(getFloat(a)/getFloat(b), n);
+    end;
     mMaxF64: begin
       if getFloat(a) > getFloat(b) then result := newFloatNodeT(getFloat(a), n)
       else result := newFloatNodeT(getFloat(b), n);
@@ -130,7 +141,7 @@ begin
       if getFloat(a) > getFloat(b) then result := newFloatNodeT(getFloat(b), n)
       else result := newFloatNodeT(getFloat(a), n);
     end;
-
+    mIsNil: result := newIntNodeT(ord(a.kind = nkNilLit), n);
     mLtI, mLtI64, mLtB, mLtEnum, mLtCh:
       result := newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n);
     mLeI, mLeI64, mLeB, mLeEnum, mLeCh:
@@ -185,9 +196,15 @@ begin
     end;
     mInSet: result := newIntNodeT(Ord(inSet(a, b)), n);
     mConStrStr: result := newStrNodeT(getStrOrChar(a)+{&}getStrOrChar(b), n);
-    mExit, mInc, ast.mDec, mAssert, mSwap, 
+    mRepr: result := newStrNodeT(renderTree(a, {@set}[renderNoComments]), n);
+    mIntToStr, mInt64ToStr, mBoolToStr, mCharToStr:
+      result := newStrNodeT(toString(getOrdValue(a)), n);
+    mFloatToStr: result := newStrNodeT(toStringF(getFloat(a)), n);
+    mCStrToStr: result := newStrNodeT(getStrOrChar(a), n);
+    mStrToStr: result := a;
+    mExit, mInc, ast.mDec, mAssert, mSwap,
     mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendSeqSeq,
-    mSetLengthStr, mSetLengthSeq: begin end;
+    mSetLengthStr, mSetLengthSeq, mNLen..mNError: begin end;
     else InternalError(a.info, 'evalOp(' +{&} magicToStr[m] +{&} ')');
   end
 end;
@@ -228,13 +245,13 @@ begin
   a := getConstExpr(c, n.sons[1]);
   b := getConstExpr(c, n.sons[2]);
   if a <> nil then begin
-    assert(a.kind in [nkIntLit..nkInt64Lit]); 
+    assert(a.kind in [nkIntLit..nkInt64Lit]);
     if a.intVal = 0 then result := a
-    else if b <> nil then result := b 
+    else if b <> nil then result := b
     else result := n.sons[2]
   end
   else if b <> nil then begin
-    assert(b.kind in [nkIntLit..nkInt64Lit]); 
+    assert(b.kind in [nkIntLit..nkInt64Lit]);
     if b.intVal = 0 then result := b
     else result := n.sons[1]
   end
@@ -249,18 +266,38 @@ begin
   a := getConstExpr(c, n.sons[1]);
   b := getConstExpr(c, n.sons[2]);
   if a <> nil then begin
-    assert(a.kind in [nkIntLit..nkInt64Lit]); 
+    assert(a.kind in [nkIntLit..nkInt64Lit]);
     if a.intVal <> 0 then result := a
     else if b <> nil then result := b
     else result := n.sons[2]
   end
   else if b <> nil then begin
-    assert(b.kind in [nkIntLit..nkInt64Lit]); 
+    assert(b.kind in [nkIntLit..nkInt64Lit]);
     if b.intVal <> 0 then result := b
     else result := n.sons[1]
   end
 end;
 
+function leValueConv(a, b: PNode): Boolean;
+begin
+  result := false;
+  case a.kind of
+    nkCharLit..nkInt64Lit:
+      case b.kind of
+        nkCharLit..nkInt64Lit: result := a.intVal <= b.intVal;
+        nkFloatLit..nkFloat64Lit: result := a.intVal <= round(b.floatVal);
+        else InternalError(a.info, 'leValueConv');
+      end;
+    nkFloatLit..nkFloat64Lit:
+      case b.kind of
+        nkFloatLit..nkFloat64Lit: result := a.floatVal <= b.floatVal;
+        nkCharLit..nkInt64Lit: result := a.floatVal <= toFloat(int(b.intVal));
+        else InternalError(a.info, 'leValueConv');
+      end;
+    else InternalError(a.info, 'leValueConv');
+  end
+end;
+
 function getConstExpr(c: PContext; n: PNode): PNode;
 var
   s: PSym;
@@ -271,7 +308,7 @@ begin
   case n.kind of
     nkSym: begin
       s := n.sym;
-      if s.kind = skEnumField then 
+      if s.kind = skEnumField then
         result := newIntNodeT(s.position, n)
       else if (s.kind = skConst) then begin
         case s.magic of
@@ -282,6 +319,9 @@ begin
           mNimrodMinor:   result := newIntNodeT(VersionMinor, n);
           mNimrodPatch:   result := newIntNodeT(VersionPatch, n);
           mCpuEndian:     result := newIntNodeT(ord(CPU[targetCPU].endian), n);
+          mNaN:           result := newFloatNodeT(NaN, n);
+          mInf:           result := newFloatNodeT(Inf, n);
+          mNegInf:        result := newFloatNodeT(NegInf, n);
           else            result := copyTree(s.ast); // BUGFIX
         end
       end
@@ -301,17 +341,17 @@ begin
           mSizeOf: begin
             a := n.sons[1];
             if computeSize(a.typ) < 0 then
-              liMessage(a.info, errCannotEvalXBecauseIncompletelyDefined, 
+              liMessage(a.info, errCannotEvalXBecauseIncompletelyDefined,
                         'sizeof');
-            if a.typ.kind in [tyArray, tyRecord, tyObject, tyTuple] then
-              result := nil // XXX: size computation for complex types 
+            if a.typ.kind in [tyArray, tyObject, tyTuple] then
+              result := nil // XXX: size computation for complex types
                             // is still wrong
             else
               result := newIntNodeT(a.typ.size, n);
           end;
           mLow:  result := newIntNodeT(firstOrd(n.sons[1].typ), n);
           mHigh: begin
-            if not (skipVarGeneric(n.sons[1].typ).kind in [tyOpenArray, 
+            if not (skipVarGeneric(n.sons[1].typ).kind in [tyOpenArray,
                                      tySequence, tyString]) then
               result := newIntNodeT(lastOrd(skipVarGeneric(n.sons[1].typ)), n);
           end;
@@ -337,61 +377,73 @@ begin
         result := n;
         n.sons[0] := a
       end;
-    end;(*
-    nkHiddenSubConv: begin
-      // subtype conversion is ok:
-      // XXX: range check!
-      result := getConstExpr(c, n.sons[0]);
-      if result <> nil then
-        result.typ := n.typ;
-    end;*)
-    nkArrayConstr, nkConstArrayConstr: begin
+    end;
+    nkBracket: begin
       result := copyTree(n);
       for i := 0 to sonsLen(n)-1 do begin
         a := getConstExpr(c, n.sons[i]);
         if a = nil then begin result := nil; exit end;
         result.sons[i] := a;
       end;
-      result.kind := nkConstArrayConstr;
+      include(result.flags, nfAllConst);
     end;
     nkRange: begin
       a := getConstExpr(c, n.sons[0]);
       if a = nil then exit;
       b := getConstExpr(c, n.sons[1]);
-      if b = nil then exit;      
+      if b = nil then exit;
       result := copyNode(n);
       addSon(result, a);
       addSon(result, b);
     end;
-    nkSetConstr, nkConstSetConstr: begin
+    nkCurly: begin
       result := copyTree(n);
       for i := 0 to sonsLen(n)-1 do begin
         a := getConstExpr(c, n.sons[i]);
         if a = nil then begin result := nil; exit end;
         result.sons[i] := a;
       end;
-      result.kind := nkConstSetConstr;
+      include(result.flags, nfAllConst);
     end;
     nkPar: begin // tuple constructor
       result := copyTree(n);
-      for i := 0 to sonsLen(n)-1 do begin
-        a := getConstExpr(c, n.sons[i]);
-        if a = nil then begin result := nil; exit end;
-        result.sons[i] := a;
+      if (sonsLen(n) > 0) and (n.sons[0].kind = nkExprColonExpr) then begin
+        for i := 0 to sonsLen(n)-1 do begin
+          a := getConstExpr(c, n.sons[i].sons[1]);
+          if a = nil then begin result := nil; exit end;
+          result.sons[i].sons[1] := a;
+        end
+      end
+      else begin
+        for i := 0 to sonsLen(n)-1 do begin
+          a := getConstExpr(c, n.sons[i]);
+          if a = nil then begin result := nil; exit end;
+          result.sons[i] := a;
+        end
       end;
+      include(result.flags, nfAllConst);
     end;
-    nkRecordConstr: begin
-      result := copyTree(n);
-      for i := 0 to sonsLen(n)-1 do begin
-        a := getConstExpr(c, n.sons[i].sons[1]);
-        if a = nil then begin result := nil; exit end;
-        result.sons[i].sons[1] := a;
-      end;
-      result.kind := nkConstRecordConstr;
+    nkChckRangeF, nkChckRange64, nkChckRange: begin
+      a := getConstExpr(c, n.sons[0]);
+      if a = nil then exit;
+      if leValueConv(n.sons[1], a) and leValueConv(a, n.sons[2]) then begin
+        result := a; // a <= x and x <= b
+        result.typ := n.typ
+      end
+      else
+        liMessage(n.info, errGenerated,
+          format(msgKindToString(errIllegalConvFromXtoY),
+            [typeToString(n.sons[0].typ), typeToString(n.typ)]));
     end;
-    nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast: begin
+    nkStringToCString, nkCStringToString: begin
       a := getConstExpr(c, n.sons[0]);
       if a = nil then exit;
+      result := a;
+      result.typ := n.typ;
+    end;
+    nkHiddenStdConv, nkHiddenSubConv, nkConv, nkCast: begin
+      a := getConstExpr(c, n.sons[1]);
+      if a = nil then exit;
       case skipRange(n.typ).kind of
         tyInt..tyInt64: begin
           case skipRange(a.typ).kind of
@@ -430,14 +482,14 @@ function semConstExpr(c: PContext; n: PNode): PNode;
 var
   e: PNode;
 begin
-  e := semExprWithType(c, n, false);
+  e := semExprWithType(c, n);
   if e = nil then begin
     liMessage(n.info, errConstExprExpected);
     result := nil; exit
   end;
   result := getConstExpr(c, e);
-  if result = nil then begin  
+  if result = nil then begin
     //writeln(output, renderTree(n));
-    liMessage(n.info, errConstExprExpected);  
+    liMessage(n.info, errConstExprExpected);
   end
 end;
diff --git a/nim/semstmts.pas b/nim/semstmts.pas
index 66db7b802..4d8372a19 100644
--- a/nim/semstmts.pas
+++ b/nim/semstmts.pas
@@ -50,7 +50,7 @@ begin
     case it.kind of
       nkElifBranch: begin
         checkSonsLen(it, 2);
-        it.sons[0] := semExpr(c, it.sons[0]);
+        it.sons[0] := semExprWithType(c, it.sons[0]);
         checkBool(it.sons[0]);
         it.sons[1] := semStmtScope(c, it.sons[1])
       end;
@@ -66,12 +66,9 @@ end;
 function semDiscard(c: PContext; n: PNode): PNode;
 begin
   result := n;
-  if sonsLen(n) = 1 then begin
-    n.sons[0] := semExpr(c, n.sons[0]);
-    if n.sons[0].typ = nil then liMessage(n.info, errInvalidDiscard);
-  end
-  else
-    illFormedAst(n);
+  checkSonsLen(n, 1);
+  n.sons[0] := semExprWithType(c, n.sons[0]);
+  if n.sons[0].typ = nil then liMessage(n.info, errInvalidDiscard);
 end;
 
 function semBreakOrContinue(c: PContext; n: PNode): PNode;
@@ -80,32 +77,29 @@ var
   x: PNode;
 begin
   result := n;
-  if sonsLen(n) = 1 then begin
-    if n.sons[0] <> nil then begin
-      if n.sons[0].kind = nkIdent then begin
-        // lookup the symbol:
-        s := SymtabGet(c.Tab, n.sons[0].ident);
-        if s <> nil then begin
-          if (s.kind = skLabel) and (s.owner.id = c.p.owner.id) then begin
-            x := newSymNode(s);
-            x.info := n.info;
-            include(s.flags, sfUsed);
-            n.sons[0] := x
-          end
-          else
-            liMessage(n.info, errInvalidControlFlowX, s.name.s)
+  checkSonsLen(n, 1);
+  if n.sons[0] <> nil then begin
+    if n.sons[0].kind = nkIdent then begin
+      // lookup the symbol:
+      s := SymtabGet(c.Tab, n.sons[0].ident);
+      if s <> nil then begin
+        if (s.kind = skLabel) and (s.owner.id = c.p.owner.id) then begin
+          x := newSymNode(s);
+          x.info := n.info;
+          include(s.flags, sfUsed);
+          n.sons[0] := x
         end
         else
-          liMessage(n.info, errUndeclaredIdentifier, n.sons[0].ident.s);
+          liMessage(n.info, errInvalidControlFlowX, s.name.s)
       end
-      else illFormedAst(n)
+      else
+        liMessage(n.info, errUndeclaredIdentifier, n.sons[0].ident.s);
     end
-    else if (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0) then
-      liMessage(n.info, errInvalidControlFlowX,
-               renderTree(n, {@set}[renderNoComments]))
+    else illFormedAst(n)
   end
-  else
-    illFormedAst(n);
+  else if (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0) then
+    liMessage(n.info, errInvalidControlFlowX,
+              renderTree(n, {@set}[renderNoComments]))
 end;
 
 function semBlock(c: PContext; n: PNode): PNode;
@@ -114,18 +108,15 @@ var
 begin
   result := n;
   Inc(c.p.nestedBlockCounter);
-  if sonsLen(n) = 2 then begin
-    openScope(c.tab); // BUGFIX: label is in the scope of block!
-    if n.sons[0] <> nil then begin
-      labl := newSymS(skLabel, n.sons[0], c);
-      addDecl(c, labl);
-      n.sons[0] := newSymNode(labl); // BUGFIX
-    end;
-    n.sons[1] := semStmt(c, n.sons[1]);
-    closeScope(c.tab);
-  end
-  else
-    illFormedAst(n);
+  checkSonsLen(n, 2);
+  openScope(c.tab); // BUGFIX: label is in the scope of block!
+  if n.sons[0] <> nil then begin
+    labl := newSymS(skLabel, n.sons[0], c);
+    addDecl(c, labl);
+    n.sons[0] := newSymNode(labl); // BUGFIX
+  end;
+  n.sons[1] := semStmt(c, n.sons[1]);
+  closeScope(c.tab);
   Dec(c.p.nestedBlockCounter);
 end;
 
@@ -137,59 +128,55 @@ var
   marker: Char;
 begin
   result := n;
-  if sonsLen(n) = 2 then begin
-    marker := pragmaAsm(con, n.sons[0]);
-    if marker = #0 then marker := '`'; // default marker
-    case n.sons[1].kind of
-      nkStrLit, nkRStrLit, nkTripleStrLit: begin
-        result := copyNode(n);
-        str := n.sons[1].strVal;
-        if str = '' then liMessage(n.info, errEmptyAsm);
-        // now parse the string literal and substitute symbols:
-        a := strStart;
-        repeat
-          b := findSubStr(marker, str, a);
-          if b < strStart then
-            sub := ncopy(str, a)
-          else
-            sub := ncopy(str, a, b-1);
-          if sub = '' then break;
+  checkSonsLen(n, 2);
+  marker := pragmaAsm(con, n.sons[0]);
+  if marker = #0 then marker := '`'; // default marker
+  case n.sons[1].kind of
+    nkStrLit, nkRStrLit, nkTripleStrLit: begin
+      result := copyNode(n);
+      str := n.sons[1].strVal;
+      if str = '' then liMessage(n.info, errEmptyAsm);
+      // now parse the string literal and substitute symbols:
+      a := strStart;
+      repeat
+        b := findSubStr(marker, str, a);
+        if b < strStart then
+          sub := ncopy(str, a)
+        else
+          sub := ncopy(str, a, b-1);
+        if sub <> '' then
           addSon(result, newStrNode(nkStrLit, sub));
 
-          if b < strStart then break;
-          c := findSubStr(marker, str, b+1);
-          if c < strStart then
-            sub := ncopy(str, b+1)
-          else
-            sub := ncopy(str, b+1, c-1);
+        if b < strStart then break;
+        c := findSubStr(marker, str, b+1);
+        if c < strStart then
+          sub := ncopy(str, b+1)
+        else
+          sub := ncopy(str, b+1, c-1);
+        if sub <> '' then begin
           e := SymtabGet(con.tab, getIdent(sub));
           if e <> nil then
             addSon(result, newSymNode(e))
           else
             addSon(result, newStrNode(nkStrLit, sub));
-          if c < strStart then break;
-          a := c+1;
-        until false;
-      end;
-      else illFormedAst(n)
-    end
+        end;
+        if c < strStart then break;
+        a := c+1;
+      until false;
+    end;
+    else illFormedAst(n)
   end
-  else
-    illFormedAst(n);
 end;
 
 function semWhile(c: PContext; n: PNode): PNode;
 begin
   result := n;
-  if sonsLen(n) = 2 then begin
-    n.sons[0] := semExpr(c, n.sons[0]);
-    CheckBool(n.sons[0]);
-    inc(c.p.nestedLoopCounter);
-    n.sons[1] := semStmtScope(c, n.sons[1]);
-    dec(c.p.nestedLoopCounter);
-  end
-  else
-    illFormedAst(n);
+  checkSonsLen(n, 2);
+  n.sons[0] := semExprWithType(c, n.sons[0]);
+  CheckBool(n.sons[0]);
+  inc(c.p.nestedLoopCounter);
+  n.sons[1] := semStmtScope(c, n.sons[1]);
+  dec(c.p.nestedLoopCounter);
 end;
 
 function semCase(c: PContext; n: PNode): PNode;
@@ -202,7 +189,8 @@ var
 begin
   // check selector:
   result := n;
-  n.sons[0] := semExprWithType(c, n.sons[0], false);
+  checkMinSonsLen(n, 2);
+  n.sons[0] := semExprWithType(c, n.sons[0]);
   chckCovered := false;
   covered := 0;
   case skipVarGenericRange(n.sons[0].Typ).Kind of
@@ -214,6 +202,7 @@ begin
     x := n.sons[i];
     case x.kind of
       nkOfBranch: begin
+        checkMinSonsLen(x, 2);
         semCaseBranch(c, n, x, i, covered);
         len := sonsLen(x);
         x.sons[len-1] := semStmtScope(c, x.sons[len-1]);
@@ -221,14 +210,14 @@ begin
       nkElifBranch: begin
         chckCovered := false;
         checkSonsLen(n, 2);
-        x.sons[0] := semExpr(c, x.sons[0]);
+        x.sons[0] := semExprWithType(c, x.sons[0]);
         checkBool(x.sons[0]);
         x.sons[1] := semStmtScope(c, x.sons[1])
       end;
       nkElse: begin
         chckCovered := false;
-        if sonsLen(x) = 1 then x.sons[0] := semStmtScope(c, x.sons[0])
-        else illFormedAst(x)
+        checkSonsLen(x, 1);
+        x.sons[0] := semStmtScope(c, x.sons[0])
       end;
       else illFormedAst(x);
     end;
@@ -240,19 +229,75 @@ end;
 function semAsgn(c: PContext; n: PNode): PNode;
 var
   le: PType;
+  a: PNode;
+  id: PIdent;
 begin
-  result := n;
-  n.sons[0] := semExprWithType(c, n.sons[0], false);
-  n.sons[1] := semExprWithType(c, n.sons[1], false);
+  checkSonsLen(n, 2);
+  a := n.sons[0];
+  case a.kind of
+    nkDotExpr, nkQualified: begin
+      // r.f = x
+      // --> `f=` (r, x)
+      checkSonsLen(a, 2);
+      id := considerAcc(a.sons[1]);
+      result := newNodeI(nkCall, n.info);
+      addSon(result, newIdentNode(getIdent(id.s+'='), n.info));
+      addSon(result, semExpr(c, a.sons[0]));
+      addSon(result, semExpr(c, n.sons[1]));
+      result := semDirectCall(c, result);
+      if result <> nil then begin
+        fixAbstractType(c, result);
+        analyseIfAddressTakenInCall(c, result);
+        exit;
+      end
+    end;
+    nkBracketExpr: begin
+      // a[i..j] = x
+      // --> `[..]=`(a, i, j, x)
+      result := newNodeI(nkCall, n.info);
+      checkSonsLen(a, 2);
+      if a.sons[1].kind = nkRange then begin
+        checkSonsLen(a.sons[1], 2);
+        addSon(result, newIdentNode(getIdent(whichSliceOpr(a.sons[1])+'='),
+                                    n.info));
+        addSon(result, semExpr(c, a.sons[0]));
+        addSonIfNotNil(result, semExpr(c, a.sons[1].sons[0]));
+        addSonIfNotNil(result, semExpr(c, a.sons[1].sons[1]));
+        addSon(result, semExpr(c, n.sons[1]));
+        result := semDirectCall(c, result);
+        if result <> nil then begin
+          fixAbstractType(c, result);
+          analyseIfAddressTakenInCall(c, result);
+          exit;
+        end
+      end
+      else begin
+        addSon(result, newIdentNode(getIdent('[]='), n.info));
+        addSon(result, semExpr(c, a.sons[0]));
+        addSon(result, semExpr(c, a.sons[1]));
+        addSon(result, semExpr(c, n.sons[1]));
+        result := semDirectCall(c, result);
+        if result <> nil then begin
+          fixAbstractType(c, result);
+          analyseIfAddressTakenInCall(c, result);
+          exit;
+        end
+      end;
+    end;
+    else begin end;
+  end;
+  n.sons[0] := semExprWithType(c, n.sons[0], {@set}[efLValue]);
+  n.sons[1] := semExprWithType(c, n.sons[1]);
   le := n.sons[0].typ;
-  if not (tfAssignable in le.flags) and (le.kind <> tyVar) then begin
+  if (skipGeneric(le).kind <> tyVar) and not IsAssignable(n.sons[0]) then begin
     liMessage(n.sons[0].info, errXCannotBeAssignedTo,
               renderTree(n.sons[0], {@set}[renderNoComments]));
   end
   else begin
     n.sons[1] := fitNode(c, le, n.sons[1]);
-    fixAbstractType(c, n); 
-  end
+    fixAbstractType(c, n);
+  end;
+  result := n;
 end;
 
 function SemReturn(c: PContext; n: PNode): PNode;
@@ -261,10 +306,11 @@ var
   a: PNode; // temporary assignment for code generator
 begin
   result := n;
-  if not (c.p.owner.kind in [skConverter, skProc]) then
+  checkSonsLen(n, 1);
+  if not (c.p.owner.kind in [skConverter, skProc, skMacro]) then
     liMessage(n.info, errReturnNotAllowedHere);
   if (n.sons[0] <> nil) then begin
-    n.sons[0] := SemExprWithType(c, n.sons[0], false);
+    n.sons[0] := SemExprWithType(c, n.sons[0]);
     // check for type compatibility:
     restype := c.p.owner.typ.sons[0];
     if (restype <> nil) then begin
@@ -280,7 +326,7 @@ begin
       end
       else begin
         assert(c.p.resultSym <> nil);
-        addSon(a, semExprWithType(c, newSymNode(c.p.resultSym), false));
+        addSon(a, semExprWithType(c, newSymNode(c.p.resultSym)));
         addSon(a, n.sons[0]);
         n.sons[0] := a;
       end
@@ -295,10 +341,11 @@ var
   restype: PType;
 begin
   result := n;
+  checkSonsLen(n, 1);
   if (c.p.owner = nil) or (c.p.owner.kind <> skIterator) then
     liMessage(n.info, errYieldNotAllowedHere);
   if (n.sons[0] <> nil) then begin
-    n.sons[0] := SemExprWithType(c, n.sons[0], false);
+    n.sons[0] := SemExprWithType(c, n.sons[0]);
     // check for type compatibility:
     restype := c.p.owner.typ.sons[0];
     if (restype <> nil) then begin
@@ -311,11 +358,11 @@ begin
 end;
 
 function fitRemoveHiddenConv(c: PContext; typ: Ptype; n: PNode): PNode;
-begin 
+begin
   result := fitNode(c, typ, n);
   if (result.kind in [nkHiddenStdConv, nkHiddenSubConv]) then begin
-    changeType(result.sons[0], typ);
-    result := result.sons[0];
+    changeType(result.sons[1], typ);
+    result := result.sons[1];
   end
   else if not sameType(result.typ, typ) then
     changeType(result, typ)
@@ -332,22 +379,21 @@ begin
   for i := 0 to sonsLen(n)-1 do begin
     a := n.sons[i];
     if a.kind = nkCommentStmt then continue;
-    assert(a.kind = nkIdentDefs);
+    if (a.kind <> nkIdentDefs) then IllFormedAst(a);
+    checkMinSonsLen(a, 3);
     len := sonsLen(a);
     if a.sons[len-2] <> nil then
       typ := semTypeNode(c, a.sons[len-2], nil)
     else
       typ := nil;
     if a.sons[len-1] <> nil then begin
-      def := semExprWithType(c, a.sons[len-1], false);
+      def := semExprWithType(c, a.sons[len-1]);
       // check type compability between def.typ and typ:
       if (typ <> nil) then def := fitRemoveHiddenConv(c, typ, def)
       else typ := def.typ;
     end
     else
       def := nil;
-    typ := copyType(typ, typ.owner);
-    include(typ.flags, tfAssignable);
     for j := 0 to len-3 do begin
       if (c.p.owner = nil) then begin
         v := semIdentWithPragma(c, skVar, a.sons[j], {@set}[sfStar, sfMinus]);
@@ -366,7 +412,7 @@ begin
       addSon(b, copyTree(def));
       addSon(result, b);
     end
-  end;
+  end
 end;
 
 function semConst(c: PContext; n: PNode): PNode;
@@ -380,8 +426,8 @@ begin
   for i := 0 to sonsLen(n)-1 do begin
     a := n.sons[i];
     if a.kind = nkCommentStmt then continue;
-    assert(a.kind = nkConstDef);
-    assert(sonsLen(a) = 3);
+    if (a.kind <> nkConstDef) then IllFormedAst(a);
+    checkSonsLen(a, 3);
     if (c.p.owner = nil) then begin
       v := semIdentWithPragma(c, skConst, a.sons[0], {@set}[sfStar, sfMinus]);
       include(v.flags, sfGlobal);
@@ -420,8 +466,10 @@ var
   countupNode, m: PNode;
 begin
   result := n;
+  checkMinSonsLen(n, 3);
   len := sonsLen(n);
   if n.sons[len-2].kind = nkRange then begin
+    checkSonsLen(n.sons[len-2], 2);
     // convert ``in 3..5`` to ``in countup(3, 5)``
     // YYY: if the programmer overrides system.countup in a local scope
     // this leads to wrong code. This is extremely hard to fix! But it may
@@ -430,18 +478,16 @@ begin
     newSons(countupNode, 3);
     countupNode.sons[0] := newNodeI(nkQualified, n.sons[len-2].info);
     newSons(countupNode.sons[0], 2);
-    m := newIdentNode(getIdent('system'));
-    m.info := n.sons[len-2].info;
+    m := newIdentNode(getIdent('system'), n.sons[len-2].info);
     countupNode.sons[0].sons[0] := m;
-    m := newIdentNode(getIdent('countup'));
-    m.info := n.sons[len-2].info;
+    m := newIdentNode(getIdent('countup'), n.sons[len-2].info);
     countupNode.sons[0].sons[1] := m;
     countupNode.sons[1] := n.sons[len-2].sons[0];
     countupNode.sons[2] := n.sons[len-2].sons[1];
     n.sons[len-2] := countupNode;
   end;
-  n.sons[len-2] := semExprWithType(c, n.sons[len-2], false);
-  iter := n.sons[len-2].typ;
+  n.sons[len-2] := semExprWithType(c, n.sons[len-2]);
+  iter := skipGeneric(n.sons[len-2].typ);
   openScope(c.tab);
   if iter.kind <> tyTuple then begin
     if len <> 3 then liMessage(n.info, errWrongNumberOfLoopVariables);
@@ -472,8 +518,9 @@ var
   typ: PType;
 begin
   result := n;
+  checkSonsLen(n, 1);
   if n.sons[0] <> nil then begin
-    n.sons[0] := semExprWithType(c, n.sons[0], false);
+    n.sons[0] := semExprWithType(c, n.sons[0]);
     typ := n.sons[0].typ;
     if (typ.kind <> tyRef) or (typ.sons[0].kind <> tyObject) then
       liMessage(n.info, errExprCannotBeRaised)
@@ -488,10 +535,12 @@ var
   check: TIntSet;
 begin
   result := n;
+  checkMinSonsLen(n, 2);
   n.sons[0] := semStmtScope(c, n.sons[0]);
   IntSetInit(check);
   for i := 1 to sonsLen(n)-1 do begin
     a := n.sons[i];
+    checkMinSonsLen(a, 1);
     len := sonsLen(a);
     if a.kind = nkExceptBranch then begin
       for j := 0 to len-2 do begin
@@ -504,7 +553,9 @@ begin
         if IntSetContainsOrIncl(check, typ.id) then
           liMessage(a.sons[j].info, errExceptionAlreadyHandled);
       end
-    end;
+    end
+    else if a.kind <> nkFinally then
+      illFormedAst(n);
     // last child of an nkExcept/nkFinally branch is a statement:
     a.sons[len-1] := semStmtScope(c, a.sons[len-1]);
   end;
@@ -534,7 +585,6 @@ end;
 
 function resolveGenericParams(c: PContext; n: PNode): PNode;
 begin
-  //result := resolveTemplateParams(c, n); // we can use the same algorithm
   result := n;
 end;
 
@@ -551,8 +601,8 @@ begin
   for i := 0 to sonsLen(n)-1 do begin
     a := n.sons[i];
     if a.kind = nkCommentStmt then continue;
-    assert(a.kind = nkTypeDef);
-    assert(sonsLen(a) = 3);
+    if (a.kind <> nkTypeDef) then IllFormedAst(a);
+    checkSonsLen(a, 3);
     if (c.p.owner = nil) then begin
       s := semIdentWithPragma(c, skType, a.sons[0], {@set}[sfStar, sfMinus]);
       include(s.flags, sfGlobal);
@@ -563,6 +613,8 @@ begin
       include(s.flags, sfInInterface);
     s.typ := newTypeS(tyForward, c);
     s.typ.sym := s;
+    // process pragmas:
+    if a.sons[0].kind = nkPragmaExpr then pragmaType(c, s, a.sons[0].sons[1]);
     // add it here, so that recursive types are possible:
     addInterfaceDecl(c, s);
     a.sons[0] := newSymNode(s);
@@ -572,9 +624,9 @@ begin
   for i := 0 to sonsLen(n)-1 do begin
     a := n.sons[i];
     if a.kind = nkCommentStmt then continue;
-    assert(a.kind = nkTypeDef);
-    assert(a.sons[0].kind = nkSym);
-    assert(sonsLen(a) = 3);
+    if (a.kind <> nkTypeDef) then IllFormedAst(a);
+    checkSonsLen(a, 3);
+    if (a.sons[0].kind <> nkSym) then IllFormedAst(a);
     s := a.sons[0].sym;
     if (s.magic = mNone) and (a.sons[2] = nil) then
       liMessage(a.info, errTypeXNeedsImplementation, s.name.s);
@@ -583,9 +635,11 @@ begin
       // type's body:
       openScope(c.tab);
       pushOwner(c, s);
+      s.typ.kind := tyGeneric;
       semGenericParamList(c, a.sons[1]);
-      // process the type body for symbol lookup of generic params:
-      a.sons[2] := resolveGenericParams(c, a.sons[2]);
+      // process the type body for symbol lookup of generic params
+      // we can use the same algorithm as for template parameters:
+      a.sons[2] := resolveTemplateParams(c, a.sons[2]);
       s.ast := a;
       assert(s.typ.containerID = 0);
       s.typ.containerID := getID();
@@ -617,7 +671,7 @@ var
   i: int;
 begin
   for i := 1 to sonsLen(n)-1 do begin
-    assert(n.sons[i].kind = nkSym);
+    if (n.sons[i].kind <> nkSym) then InternalError(n.info, 'addParams');
     addDecl(c, n.sons[i].sym);
   end
 end;
@@ -628,6 +682,7 @@ var
   oldP: PProcCon;
 begin
   result := n;
+  checkSonsLen(n, codePos+1);
   if c.p.owner <> nil then
     liMessage(n.info, errIteratorNotAllowed);
   oldP := c.p; // restore later
@@ -682,7 +737,7 @@ begin
   if t <> nil then begin
     s := newSym(skVar, getIdent('result'), getCurrOwner(c));
     s.info := info;
-    s.typ := inheritAssignable(t, true);
+    s.typ := t;
     Include(s.flags, sfResult);
     addDecl(c, s);
     c.p.resultSym := s;
@@ -700,6 +755,7 @@ var
   oldP: PProcCon;
 begin
   result := n;
+  checkSonsLen(n, codePos+1);
   s := newSym(skProc, getIdent(genPrefix + 'anonymous'), getCurrOwner(c));
   s.info := n.info;
 
@@ -744,18 +800,19 @@ begin
   c.p := oldP; // restore
 end;
 
-function semProc(c: PContext; n: PNode): PNode;
+function semProcAux(c: PContext; n: PNode; kind: TSymKind): PNode;
 var
   s, proto: PSym;
   oldP: PProcCon;
 begin
   result := n;
+  checkSonsLen(n, codePos+1);
   if c.p.owner = nil then begin
-    s := semIdentVis(c, skProc, n.sons[0], {@set}[sfStar]);
+    s := semIdentVis(c, kind, n.sons[0], {@set}[sfStar]);
     include(s.flags, sfGlobal);
   end
   else
-    s := semIdentVis(c, skProc, n.sons[0], {@set}[]);
+    s := semIdentVis(c, kind, n.sons[0], {@set}[]);
   n.sons[namePos] := newSymNode(s);
   oldP := c.p; // restore later
   if sfStar in s.flags then include(s.flags, sfInInterface);
@@ -784,9 +841,13 @@ begin
       s.typ.callConv := lastOptionEntry(c).defaultCC;
     // add it here, so that recursive procs are possible:
     // -2 because we have a scope open for parameters
-    addInterfaceOverloadableSymAt(c, s, c.tab.tos-2);
+    if kind in OverloadableSyms then
+      addInterfaceOverloadableSymAt(c, s, c.tab.tos-2)
+    else
+      addDeclAt(c, s, c.tab.tos-2);
     if n.sons[pragmasPos] <> nil then
-      pragmaProc(c, s, n.sons[pragmasPos]);
+      if kind = skMacro then pragmaMacro(c, s, n.sons[pragmasPos])
+      else pragmaProc(c, s, n.sons[pragmasPos]);
   end
   else begin
     if n.sons[pragmasPos] <> nil then
@@ -825,48 +886,64 @@ begin
   else begin
     if proto <> nil then
       liMessage(n.info, errImplOfXexpected, proto.name.s);
-    if not (sfImportc in s.flags) then
-      Include(s.flags, sfForward);
+    if not (sfImportc in s.flags) then Include(s.flags, sfForward);
   end;
   closeScope(c.tab); // close scope for parameters
   popOwner(c);
   c.p := oldP; // restore
 end;
 
+function semProc(c: PContext; n: PNode): PNode;
+begin
+  result := semProcAux(c, n, skProc);
+end;
+
 function isTopLevel(c: PContext): bool;
 begin
   result := c.tab.tos <= 2
 end;
 
-{$include 'importer.pas'}
-(*
-function isConcreteStmt(n: PNode): bool;
+function semConverterDef(c: PContext; n: PNode): PNode;
+var
+  t: PType;
+  s: PSym;
 begin
-  case n.kind of
-    nkProcDef, nkIteratorDef: result := n.sons[genericParamsPos] = nil;
-    nkCommentStmt, nkTemplateDef, nkMacroDef: result := false;
-    else result := true
-  end
+  checkSonsLen(n, codePos+1);
+  if n.sons[genericParamsPos] <> nil then
+    liMessage(n.info, errNoGenericParamsAllowedForX, 'converter');
+  result := semProcAux(c, n, skConverter);
+  s := result.sons[namePos].sym;
+  t := s.typ;
+  if t.sons[0] = nil then
+    liMessage(n.info, errXNeedsReturnType, 'converter');
+  if sonsLen(t) <> 2 then
+    liMessage(n.info, errXRequiresOneArgument, 'converter');
+  addConverter(c, s);
 end;
 
-function TopLevelEvent(c: PContext; n: PNode): PNode;
+function semMacroDef(c: PContext; n: PNode): PNode;
+var
+  t: PType;
+  s: PSym;
 begin
-  result := n;
-  if isTopLevel(c) and (eTopLevel in c.b.eventMask) then begin
-    if isConcreteStmt(result) then begin
-      if optVerbose in gGlobalOptions then
-        MessageOut('compiling: ' + renderTree(result, {@set}[renderNoBody,
-                                                        renderNoComments]));
-      result := transform(c, result);
-      result := c.b.topLevelEvent(c.b, result);
-    end
-  end
-end; *)
+  checkSonsLen(n, codePos+1);
+  if n.sons[genericParamsPos] <> nil then
+    liMessage(n.info, errNoGenericParamsAllowedForX, 'macro');
+  result := semProcAux(c, n, skMacro);
+  s := result.sons[namePos].sym;
+  t := s.typ;
+  if t.sons[0] = nil then
+    liMessage(n.info, errXNeedsReturnType, 'macro');
+  if sonsLen(t) <> 2 then
+    liMessage(n.info, errXRequiresOneArgument, 'macro');
+end;
+
+{$include 'importer.pas'}
 
 function SemStmt(c: PContext; n: PNode): PNode;
 const
   // must be last statements in a block:
-  LastBlockStmts = {@set}[nkRaiseStmt, nkReturnStmt, nkBreakStmt, 
+  LastBlockStmts = {@set}[nkRaiseStmt, nkReturnStmt, nkBreakStmt,
                           nkContinueStmt];
 var
   len, i, j: int;
@@ -910,9 +987,11 @@ begin
     nkReturnStmt: result := semReturn(c, n);
     nkAsmStmt: result := semAsm(c, n);
     nkYieldStmt: result := SemYield(c, n);
-    nkPragma: pragmaStmt(c, n);
+    nkPragma: pragmaStmt(c, c.p.owner, n);
     nkIteratorDef: result := semIterator(c, n);
     nkProcDef: result := semProc(c, n);
+    nkConverterDef: result := semConverterDef(c, n);
+    nkMacroDef: result := semMacroDef(c, n);
     nkTemplateDef: result := semTemplateDef(c, n);
     nkImportStmt: begin
       if not isTopLevel(c) then
@@ -930,7 +1009,8 @@ begin
       result := evalInclude(c, n);
     end;
     else liMessage(n.info, errStmtExpected);
-  end
+  end;
+  if result = nil then InternalError(n.info, 'SemStmt: result = nil');
 end;
 
 function semStmtScope(c: PContext; n: PNode): PNode;
diff --git a/nim/semtempl.pas b/nim/semtempl.pas
index f7f0cadd5..b861949c9 100644
--- a/nim/semtempl.pas
+++ b/nim/semtempl.pas
@@ -15,7 +15,7 @@ begin
   if n = nil then begin result := false; exit end;
   case n.kind of
     nkIdent..nkNilLit: result := true;
-    nkCall..nkCast: begin
+    nkCall..nkPassAsOpenArray: begin
       for i := 0 to sonsLen(n)-1 do
         if not isExpr(n.sons[i]) then begin
           result := false; exit
@@ -27,7 +27,7 @@ begin
 end;
 
 function isTypeDesc(n: PNode): bool;
-// returns true if ``n`` looks like an type desc
+// returns true if ``n`` looks like a type desc
 var
   i: int;
 begin
@@ -46,15 +46,6 @@ begin
   end
 end;
 
-function semMacroExpr(c: PContext; n: PNode; sym: PSym): PNode;
-begin
-  // macros can be overloaded by the number of arguments?
-  // no: would make variable number of arguments more
-  // complicated!
-  // XXX
-  result := n;
-end;
-
 function evalTemplateAux(c: PContext; templ, actual: PNode;
                          sym: PSym): PNode;
 var
@@ -88,7 +79,7 @@ var
   r: PNode;
 begin
   inc(evalTemplateCounter);
-  if evalTemplateCounter > 100 then 
+  if evalTemplateCounter > 100 then
     liMessage(n.info, errTemplateInstantiationTooNested);
   // replace each param by the corresponding node:
   r := sym.ast.sons[paramsPos].sons[0];
@@ -156,7 +147,7 @@ begin
           end
         end
       end;
-      if realStmt >= 0 then 
+      if realStmt >= 0 then
         result := transformToExpr(n.sons[realStmt])
       else
         n.kind := nkStmtListExpr;
@@ -213,7 +204,7 @@ begin
     n.sons[codePos] := transformToExpr(n.sons[codePos]);
 
   // only parameters are resolved, no type checking is performed
-  closeScope(c.tab);  
+  closeScope(c.tab);
   popOwner(c);
   s.ast := n;
 
diff --git a/nim/semtypes.pas b/nim/semtypes.pas
index e402b9864..e0a3f59b9 100644
--- a/nim/semtypes.pas
+++ b/nim/semtypes.pas
@@ -38,6 +38,7 @@ begin
   base := nil;
   result := newOrPrevType(tyEnum, prev, c);
   result.n := newNode(nkEnumTy);
+  checkMinSonsLen(n, 1);
   if n.sons[0] <> nil then begin
     base := semTypeNode(c, n.sons[0].sons[0], nil);
     if base.kind <> tyEnum then
@@ -71,7 +72,7 @@ begin
       StrTableAdd(c.module.tab, e); // BUGFIX
     end;
     addSon(result.n, newSymNode(e));
-    addOverloadableSymAt(c, e, c.tab.tos-1);
+    addDeclAt(c, e, c.tab.tos-1);
     inc(counter);
   end;
 end;
@@ -123,11 +124,26 @@ begin
     liMessage(n.info, errXExpectsOneTypeParam, kindStr);
 end;
 
+function semVarType(c: PContext; n: PNode; prev: PType): PType;
+var
+  base: PType;
+begin
+  result := newOrPrevType(tyVar, prev, c);
+  if sonsLen(n) = 1 then begin
+    base := semTypeNode(c, n.sons[0], nil);
+    if base.kind = tyVar then liMessage(n.info, errVarVarTypeNotAllowed);
+    addSon(result, base);
+  end
+  else
+    liMessage(n.info, errXExpectsOneTypeParam, 'var');
+end;
+
 function semRangeAux(c: PContext; n: PNode; prev: PType): PType;
 var
   a, b: PNode;
 begin
   assert(n.kind = nkRange);
+  checkSonsLen(n, 2);
   result := newOrPrevType(tyRange, prev, c);
   result.n := copyTree(n);
   result.n := newNode(nkRange);
@@ -197,13 +213,37 @@ end;
 
 function semTuple(c: PContext; n: PNode; prev: PType): PType;
 var
-  i: int;
-  elem: PType;
+  i, j, len, counter: int;
+  typ: PType;
+  check: TIntSet;
+  a: PNode;
+  field: PSym;
 begin
   result := newOrPrevType(tyTuple, prev, c);
-  for i := 1 to sonsLen(n)-1 do begin // BUGFIX: start from 1
-    elem := semTypeNode(c, n.sons[i], nil);
-    addSon(result, elem);
+  result.n := newNodeI(nkRecList, n.info);
+  IntSetInit(check);
+  counter := 0;
+  for i := 0 to sonsLen(n)-1 do begin
+    a := n.sons[i];
+    if (a.kind <> nkIdentDefs) then IllFormedAst(a);
+    checkMinSonsLen(a, 3);
+    len := sonsLen(a);
+    if a.sons[len-2] <> nil then
+      typ := semTypeNode(c, a.sons[len-2], nil)
+    else
+      liMessage(a.info, errTypeExpected);
+    if a.sons[len-1] <> nil then
+      liMessage(a.sons[len-1].info, errInitHereNotAllowed);
+    for j := 0 to len-3 do begin
+      field := newSymS(skField, a.sons[j], c);
+      field.typ := typ;
+      field.position := counter;
+      inc(counter);
+      if IntSetContainsOrIncl(check, field.name.id) then
+        liMessage(a.sons[j].info, errAttemptToRedefine, field.name.s);
+      addSon(result.n, newSymNode(field));
+      addSon(result, typ);
+    end
   end
 end;
 
@@ -212,6 +252,7 @@ function instGenericAux(c: PContext; templ, actual: PNode;
 var
   i: int;
 begin
+  if templ = nil then begin result := nil; exit end;
   case templ.kind of
     nkSym: begin
       if (templ.sym.kind = skTypeParam)
@@ -237,20 +278,27 @@ var
   elem: PType;
   inst: PNode;
 begin
-  if (s.typ = nil) or (s.typ.kind <> tyGeneric) then
+  if (s.typ = nil) or (s.typ.kind <> tyGeneric) then 
     liMessage(n.info, errCannotInstantiateX, s.name.s);
   result := newOrPrevType(tyGenericInst, prev, c);
   result.containerID := s.typ.containerID;
+  result.sym := s;
   assert(s.typ.containerID <> 0);
   for i := 1 to sonsLen(n)-1 do begin
     elem := semTypeNode(c, n.sons[i], nil);
+    if elem.kind = tyGenericParam then result.kind := tyGeneric;
     addSon(result, elem);
   end;
   if s.ast <> nil then begin
     inst := instGenericAux(c, s.ast.sons[2], n, s);
-    elem := semTypeNode(c, inst, nil);
-    // does checking of instantiated type for us!
-    addSon(result, elem);
+    if result.kind = tyGenericInst then begin
+      // does checking of instantiated type for us:
+      elem := semTypeNode(c, inst, nil);
+      elem.id := result.containerID;
+      addSon(result, elem);
+    end
+    else
+      addSon(result, nil);
   end
   else
     liMessage(n.info, errCannotInstantiateX, s.name.s);
@@ -285,9 +333,12 @@ function semIdentWithPragma(c: PContext; kind: TSymKind;
                             n: PNode; const allowed: TSymFlags): PSym;
 begin
   if n.kind = nkPragmaExpr then begin
+    checkSonsLen(n, 2);
     result := semIdentVis(c, kind, n.sons[0], allowed);
     case kind of
-      skType: pragmaType(c, result, n.sons[1]);
+      skType: begin
+        // process pragmas later, because result.typ has not been set yet
+      end;
       skField: pragmaField(c, result, n.sons[1]);
       skVar: pragmaVar(c, result, n.sons[1]);
       skConst: pragmaConst(c, result, n.sons[1]);
@@ -311,6 +362,7 @@ end;
 procedure semBranchExpr(c: PContext; t: PNode; var ex: PNode);
 begin
   ex := semConstExpr(c, ex);
+  checkMinSonsLen(t, 1);
   if (cmpTypes(t.sons[0].typ, ex.typ) <= isConvertible) then begin
     typeMismatch(ex, t.sons[0].typ, ex.typ);
   end;
@@ -325,6 +377,7 @@ begin
   for i := 0 to sonsLen(branch)-2 do begin
     b := branch.sons[i];
     if b.kind = nkRange then begin
+      checkSonsLen(b, 2);
       semBranchExpr(c, t, b.sons[0]);
       semBranchExpr(c, t, b.sons[1]);
       if emptyRange(b.sons[0], b.sons[1]) then
@@ -341,11 +394,12 @@ end;
 
 procedure semRecordNodeAux(c: PContext; n: PNode;
                            var check: TIntSet;
-                           var pos: int; father: PNode); forward;
+                           var pos: int; father: PNode;
+                           rectype: PSym); forward;
 
 procedure semRecordCase(c: PContext; n: PNode;
                         var check: TIntSet;
-                        var pos: int; father: PNode);
+                        var pos: int; father: PNode; rectype: PSym);
 var
   i: int;
   covered: biggestint;
@@ -354,7 +408,8 @@ var
   typ: PType;
 begin
   a := copyNode(n);
-  semRecordNodeAux(c, n.sons[0], check, pos, a);
+  checkMinSonsLen(n, 2);
+  semRecordNodeAux(c, n.sons[0], check, pos, a, rectype);
   if a.sons[0].kind <> nkSym then
     internalError('semRecordCase: dicriminant is no symbol');
   include(a.sons[0].sym.flags, sfDiscriminant);
@@ -370,12 +425,18 @@ begin
   for i := 1 to sonsLen(n)-1 do begin
     b := copyTree(n.sons[i]);
     case n.sons[i].kind of
-      nkOfBranch: semCaseBranch(c, a, b, i, covered);
-      nkElse: chckCovered := false;
-      else internalError(n.info, 'semRecordAux(record case branch)');
+      nkOfBranch: begin
+        checkMinSonsLen(b, 2);
+        semCaseBranch(c, a, b, i, covered);
+      end;
+      nkElse: begin
+        chckCovered := false;
+        checkSonsLen(b, 1);
+      end;
+      else illFormedAst(n);
     end;
     delSon(b, sonsLen(b)-1);
-    semRecordNodeAux(c, lastSon(n.sons[i]), check, pos, b);
+    semRecordNodeAux(c, lastSon(n.sons[i]), check, pos, b, rectype);
     addSon(a, b);
   end;
   if chckCovered and (covered <> lengthOrd(a.sons[0].typ)) then
@@ -385,7 +446,7 @@ end;
 
 procedure semRecordNodeAux(c: PContext; n: PNode;
                            var check: TIntSet;
-                           var pos: int; father: PNode);
+                           var pos: int; father: PNode; rectype: PSym);
 var
   i, len: int;
   f: PSym; // new field
@@ -416,22 +477,23 @@ begin
         end
       end;
       if branch <> nil then
-        semRecordNodeAux(c, branch, check, pos, father);
+        semRecordNodeAux(c, branch, check, pos, father, rectype);
     end;
     nkRecCase: begin
-      semRecordCase(c, n, check, pos, father);
+      semRecordCase(c, n, check, pos, father, rectype);
     end;
     nkRecList: begin
       // attempt to keep the nesting at a sane level:
       if father.kind = nkRecList then a := father
       else a := copyNode(n);
       for i := 0 to sonsLen(n)-1 do begin
-        semRecordNodeAux(c, n.sons[i], check, pos, a);
+        semRecordNodeAux(c, n.sons[i], check, pos, a, rectype);
       end;
       if a <> father then
         addSon(father, a);
     end;
     nkIdentDefs: begin
+      checkMinSonsLen(n, 3);
       len := sonsLen(n);
       if (father.kind <> nkRecList) and (len >= 4) then a := newNode(nkRecList)
       else a := nil;
@@ -444,6 +506,12 @@ begin
         f := semIdentWithPragma(c, skField, n.sons[i], {@set}[sfStar, sfMinus]);
         f.typ := typ;
         f.position := pos;
+        if (rectype <> nil)
+        and ([sfImportc, sfExportc] * rectype.flags <> [])
+        and (f.loc.r = nil) then begin
+          f.loc.r := toRope(f.name.s);
+          f.flags := f.flags + ([sfImportc, sfExportc] * rectype.flags);
+        end;
         inc(pos);
         if IntSetContainsOrIncl(check, f.name.id) then
           liMessage(n.sons[i].info, errAttemptToRedefine, f.name.s);
@@ -452,9 +520,7 @@ begin
       end;
       if a <> nil then addSon(father, a);
     end;
-    else begin
-      InternalError(n.info, 'semRecordAux(' +{&} nodeKindToStr[n.kind] +{&} ')')
-    end
+    else illFormedAst(n);
   end
 end;
 
@@ -508,22 +574,25 @@ begin
   IntSetInit(check);
   pos := 0;
   // n.sons[0] contains the pragmas (if any). We process these later...
+  checkSonsLen(n, 3);
   if n.sons[1] <> nil then begin
     base := semTypeNode(c, n.sons[1].sons[0], nil);
     if base.kind = tyObject then
       addInheritedFields(c, check, pos, base)
     else
-      liMessage(n.sons[1].info, errInheritanceOnlyWithObjects);
+      liMessage(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects);
   end
   else
     base := nil;
   if n.kind = nkObjectTy then
     result := newOrPrevType(tyObject, prev, c)
   else
-    result := newOrPrevType(tyRecord, prev, c);
+    InternalError(n.info, 'semObjectNode');
   addSon(result, base);
   result.n := newNode(nkRecList);
-  semRecordNodeAux(c, n.sons[2], check, pos, result.n);
+  semRecordNodeAux(c, n.sons[2], check, pos, result.n, result.sym);
+  if (tfFinal in result.flags) and (base <> nil) then
+    liMessage(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects);
 end;
 
 function semProcTypeNode(c: PContext; n: PNode; prev: PType): PType;
@@ -534,6 +603,7 @@ var
   arg: PSym;
   check: TIntSet;
 begin
+  checkMinSonsLen(n, 1);
   result := newOrPrevType(tyProc, prev, c);
   result.callConv := lastOptionEntry(c).defaultCC;
   result.n := newNode(nkFormalParams);
@@ -551,17 +621,18 @@ begin
   counter := 0;
   for i := 1 to sonsLen(n)-1 do begin
     a := n.sons[i];
-    assert(a.kind = nkIdentDefs);
+    if (a.kind <> nkIdentDefs) then IllFormedAst(a);
+    checkMinSonsLen(a, 3);
     len := sonsLen(a);
     if a.sons[len-2] <> nil then
       typ := semTypeNode(c, a.sons[len-2], nil)
     else
       typ := nil;
     if a.sons[len-1] <> nil then begin
-      def := semExprWithType(c, a.sons[len-1], false);
+      def := semExprWithType(c, a.sons[len-1]);
       // check type compability between def.typ and typ:
       if (typ <> nil) then begin
-        if (cmpTypes(typ, def.typ) <= isConvertible) then begin
+        if (cmpTypes(typ, def.typ) < isConvertible) then begin
           typeMismatch(a.sons[len-1], typ, def.typ);
         end;
         def := fitNode(c, typ, def);
@@ -593,15 +664,15 @@ begin
   embeddedDbg(c, n);
   case n.kind of
     nkTypeOfExpr: begin
-      result := semExprWithType(c, n, true).typ;
+      result := semExprWithType(c, n, {@set}[efAllowType]).typ;
     end;
     nkBracketExpr: begin
+      checkMinSonsLen(n, 2);
       s := semTypeIdent(c, n.sons[0]);
       case s.magic of
         mArray: result := semArray(c, n, prev);
         mOpenArray: result := semContainer(c, n, tyOpenArray, 'openarray', prev);
         mRange: result := semRange(c, n, prev);
-        mTuple: result := semTuple(c, n, prev);
         mSet: result := semSet(c, n, prev);
         mSeq: result := semContainer(c, n, tySequence, 'seq', prev);
         else result := semGeneric(c, n, s, prev);
@@ -617,7 +688,6 @@ begin
         assignType(prev, s.typ);
         result := prev;
       end
-      // result :=  copyType(s.typ, s.owner);
     end;
     nkSym: begin
       if (n.sym.kind in [skTypeParam, skType]) and (n.sym.typ <> nil) then begin
@@ -627,22 +697,21 @@ begin
           assignType(prev, s.typ);
           result := prev;
         end;
-        //  result := copyType(n.sym.typ, n.sym.owner);
         include(n.sym.flags, sfUsed); // BUGFIX
       end
       else
         liMessage(n.info, errTypeExpected);
     end;
-    nkRecordTy, nkObjectTy: begin
-      result := semObjectNode(c, n, prev);
-    end;
+    nkObjectTy: result := semObjectNode(c, n, prev);
+    nkTupleTy: result := semTuple(c, n, prev);
     nkRefTy: result := semAnyRef(c, n, tyRef, 'ref', prev);
     nkPtrTy: result := semAnyRef(c, n, tyPtr, 'ptr', prev);
-    nkVarTy: result := semAnyRef(c, n, tyVar, 'var', prev);
+    nkVarTy: result := semVarType(c, n, prev);
     nkProcTy: begin
+      checkSonsLen(n, 2);
       result := semProcTypeNode(c, n.sons[0], prev);
       // dummy symbol for `pragma`:
-      s := newSymS(skProc, newIdentNode(getIdent('dummy')), c);
+      s := newSymS(skProc, newIdentNode(getIdent('dummy'), n.info), c);
       s.typ := result;
       pragmaProcType(c, s, n.sons[1]);
     end;
diff --git a/nim/sigmatch.pas b/nim/sigmatch.pas
index 69ffdbb43..6257d5178 100644
--- a/nim/sigmatch.pas
+++ b/nim/sigmatch.pas
@@ -96,12 +96,9 @@ function typeRel(var mapping: TIdTable; f, a: PType): TTypeRelation; overload;
 function concreteType(t: PType): PType;
 begin
   case t.kind of
-    tyRecordConstr: begin
-      result := newType(tyRecord, t.owner);
-      // XXX semantic checking for the type?
-    end;
-    tyArrayConstr: begin  // make it an open array
-      result := newType(tyOpenArray, t.owner);
+    tyArrayConstr: begin  // make it an array
+      result := newType(tyArray, t.owner);
+      addSon(result, t.sons[0]); // XXX: t.owner is wrong for ID!
       addSon(result, t.sons[1]); // XXX: semantic checking for the type?
     end;
     tyEmptySet, tyNil: result := nil; // what should it be?
@@ -140,99 +137,35 @@ begin
   if a <= b then result := a else result := b
 end;
 
-function recordRelAux(var mapping: TIdTable; f, a: PType;
-                      var fields: TIntSet): TTypeRelation;
+function tupleRel(var mapping: TIdTable; f, a: PType): TTypeRelation;
 var
-  i, j: int;
-  field: PSym;
-  found: bool;
+  i: int;
+  x, y: PSym;
+  m: TTypeRelation;
 begin
-  result := isEqual;
-  if (f.kind <> tyRecordConstr) and (f.sons[0] <> nil) then begin
-    // basetype of object
-    result := recordRelAux(mapping, f.sons[0], a, fields);
-    if result = isNone then exit;
-  end;
-  for i := 0 to sonsLen(f.n)-1 do begin
-    if f.n.sons[i].kind = nkSym then begin
-      found := false;
-      for j := 0 to sonsLen(a.n)-1 do begin
-        field := a.n.sons[j].sym;
-        if field.name.id = f.n.sons[i].sym.name.id then begin
-          found := true;
-          if IntSetContainsOrIncl(fields, field.name.id) then begin
-            result := isNone; exit
-          end;
-          result := minRel(result, typeRel(mapping, f.n.sons[i].typ,
-                                           field.typ));
-          if result = isNone then exit
+  result := isNone;
+  if sonsLen(a) = sonsLen(f) then begin
+    result := isEqual;
+    for i := 0 to sonsLen(f)-1 do begin
+      m := typeRel(mapping, f.sons[i], a.sons[i]);
+      if m < isSubtype then begin result := isNone; exit end;
+      result := minRel(result, m);
+    end;
+    if (f.n <> nil) and (a.n <> nil) then begin
+      for i := 0 to sonsLen(f.n)-1 do begin
+        // check field names:
+        if f.n.sons[i].kind <> nkSym then InternalError(f.n.info, 'tupleRel');
+        if a.n.sons[i].kind <> nkSym then InternalError(a.n.info, 'tupleRel');
+        x := f.n.sons[i].sym;
+        y := a.n.sons[i].sym;
+        if x.name.id <> y.name.id then begin
+          result := isNone; exit
         end
-      end;
-      if not found and (f.n.sons[i].sym.ast = nil) then begin
-        // needs default value, but has none
-        result := isNone; exit
       end
     end
-    else begin
-      // case in record?
-      result := isNone; exit
-    end
-  end;
-  for i := 0 to sonsLen(a.n)-1 do begin
-    if not IntSetContainsOrIncl(fields, a.n.sons[i].sym.name.id) then begin
-      result := isNone; exit
-    end
   end
 end;
 
-function recordRel(var mapping: TIdTable; f, a: PType): TTypeRelation;
-var
-  fields: TIntSet;
-begin
-  assert(a.kind = tyRecordConstr);
-  IntSetInit(fields);
-  result := recordRelAux(mapping, f, a, fields);
-end;
-
-function tupleRelAux(var mapping: TIdTable; f, a: PType;
-                     var start: int): TTypeRelation;
-var
-  i: int;
-begin
-  result := isEqual;
-  assert(a.kind = tyTuple);
-  if f.sons[0] <> nil then begin // basetype of object
-    result := tupleRelAux(mapping, f.sons[0], a, start);
-    if result = isNone then exit;
-  end;
-  for i := 0 to sonsLen(f.n)-1 do begin
-    if f.n.sons[i].kind = nkSym then begin
-      if i+start < sonsLen(a) then begin
-        result := minRel(result, typeRel(mapping, f.n.sons[i].typ,
-                                         a.sons[i+start]));
-        if result = isNone then exit
-      end
-      else if f.n.sons[i].sym.ast = nil then begin
-        // needs default value, but has none
-        result := isNone; exit
-      end
-    end
-    else begin
-      // case in record?
-      result := isNone; exit
-    end
-  end;
-  inc(start, sonsLen(f));
-end;
-
-function tupleRel(var mapping: TIdTable; f, a: PType): TTypeRelation;
-var
-  start: int;
-begin
-  start := 0;
-  result := tupleRelAux(mapping, f, a, start);
-end;
-
 function typeRel(var mapping: TIdTable; f, a: PType): TTypeRelation;
 var
   x, concrete: PType;
@@ -242,7 +175,7 @@ begin // is a subtype of f?
   result := isNone;
   assert(f <> nil);
   assert(a <> nil);
-  if (a.kind = tyGenericInst) and (f.kind <> tyGeneric) then begin
+  if (a.kind = tyGenericInst) and (skipVar(f).kind <> tyGeneric) then begin
     result := typeRel(mapping, f, lastSon(a));
     exit
   end;
@@ -280,7 +213,7 @@ begin // is a subtype of f?
     tyVar: begin
       if (a.kind = f.kind) then
         result := typeRel(mapping, base(f), base(a))
-      else //if tfAssignable in a.flags then
+      else
         result := typeRel(mapping, base(f), a)
     end;
     tyArray, tyArrayConstr: begin // tyArrayConstr cannot happen really, but
@@ -347,64 +280,12 @@ begin // is a subtype of f?
       if a.kind = f.kind then result := isEqual
     end;
     tyTuple: begin
-      case a.kind of
-        tyTuple: begin
-          if sonsLen(a) >= sonsLen(f) then begin
-            result := isEqual;
-            for i := 0 to sonsLen(f)-1 do begin
-              m := typeRel(mapping, f.sons[i], a.sons[i]);
-              if m < isGeneric then begin result := isNone; exit end;
-              result := minRel(result, m);
-            end;
-            if sonsLen(a) > sonsLen(f) then result := isSubtype;
-          end
-        end;
-        tyRecord, tyRecordConstr: begin
-          if sonsLen(a.n) >= sonsLen(f) then begin
-            result := isEqual;
-            for i := 0 to sonsLen(f)-1 do begin
-              m := typeRel(mapping, f.sons[i], a.n.sons[i].sym.typ);
-              if m < isGeneric then begin result := isNone; exit end;
-              result := minRel(result, m);
-            end;
-            if sonsLen(a.n) > sonsLen(f) then result := isSubtype;
-          end
-        end;
-        else begin end
-      end
-    end;
-    tyRecordConstr: begin // can happen for array constr of record constr
-      case a.kind of
-        tyRecord, tyRecordConstr: result := recordRel(mapping, f, a);
-        tyTuple: result := tupleRel(mapping, f, a);
-        else begin end
-      end
-    end;
-    tyRecord: begin
-      // structural equivalence is enough for constructors!
-      case a.kind of
-        tyRecord: begin
-          if a.id = f.id then result := isEqual
-        end;
-        tyRecordConstr: begin
-          result := recordRel(mapping, f, a);
-        end;
-        tyTuple: begin
-          result := tupleRel(mapping, f, a);
-        end;
-        else begin end
-      end
+      if a.kind = tyTuple then result := tupleRel(mapping, f, a);
     end;
     tyObject: begin
-      // easy:
-      case a.kind of
-        tyObject: begin
-          if a.id = f.id then result := isEqual
-          else if isObjectSubtype(a, f) then result := isSubtype
-        end;
-        tyRecordConstr: result := recordRel(mapping, f, a);
-        tyTuple: result := tupleRel(mapping, f, a);
-        else begin end
+      if a.kind = tyObject then begin
+        if a.id = f.id then result := isEqual
+        else if isObjectSubtype(a, f) then result := isSubtype
       end
     end;
     tySet: begin
@@ -414,7 +295,7 @@ begin // is a subtype of f?
         end;
         tySet: begin
           result := typeRel(mapping, base(f), base(a));
-          if result <= isConvertible then result := isEqual
+          if result <= isConvertible then result := isNone // BUGFIX!
         end;
         else begin end
       end
@@ -519,15 +400,16 @@ begin // is a subtype of f?
         else begin end
       end
     end;
-    tyGenericInst:
+    tyGenericInst: begin
       result := typeRel(mapping, lastSon(f), a);
+    end;
     tyGeneric: begin
       x := PType(idTableGet(mapping, f));
       if x = nil then begin
         assert(f.containerID <> 0);
-        if (f.containerID = a.containerID) and
-           (sonsLen(a) >= sonsLen(f)) then begin
-          // >= for partial generic matching!
+        assert(lastSon(f) = nil);
+        if (a.kind = tyGenericInst) and (f.containerID = a.containerID) and
+           (sonsLen(a) = sonsLen(f)) then begin
           for i := 0 to sonsLen(f)-2 do begin
             if typeRel(mapping, f.sons[i], a.sons[i]) < isGeneric then exit;
           end;
@@ -583,21 +465,23 @@ function getInstantiatedType(c: PContext; arg: PNode; const m: TCandidate;
                              f: PType): PType;
 begin
   result := PType(idTableGet(m.bindings, f));
-  if result = nil then
+  if result = nil then begin
     result := generateTypeInstance(c, m.bindings, arg.info, f);
+  end;
   if result = nil then InternalError(arg.info, 'getInstantiatedType');
 end;
 
-function implicitConv(kind: TNodeKind; f: PType; arg: PNode; 
+function implicitConv(kind: TNodeKind; f: PType; arg: PNode;
                       const m: TCandidate; c: PContext): PNode;
 begin
-  result := newNode(kind);
-  result.info := arg.info;
-  if containsGenericType(f) then 
+  result := newNodeI(kind, arg.info);
+  if containsGenericType(f) then
     result.typ := getInstantiatedType(c, arg, m, f)
   else
     result.typ := f;
-  addSon(result, copyTree(arg));
+  if result.typ = nil then InternalError(arg.info, 'implicitConv');
+  addSon(result, nil);
+  addSon(result, arg);
 end;
 
 function userConvMatch(c: PContext; var m: TCandidate; f, a: PType;
@@ -613,11 +497,10 @@ begin
     dest := c.converters[i].typ.sons[0];
     if (typeRel(m.bindings, f, dest) = isEqual) and
        (typeRel(m.bindings, src, a) = isEqual) then begin
-      result := newNode(nkHiddenCallConv);
-      result.info := arg.info;
       s := newSymNode(c.converters[i]);
       s.typ := c.converters[i].typ;
       s.info := arg.info;
+      result := newNodeIT(nkHiddenCallConv, arg.info, s.typ.sons[0]);
       addSon(result, s);
       addSon(result, copyTree(arg));
       inc(m.convMatches);
@@ -635,44 +518,44 @@ begin
   case r of
     isConvertible: begin
       inc(m.convMatches);
-      result := implicitConv(nkHiddenStdConv, f, arg, m, c);
+      result := implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c);
     end;
     isSubtype: begin
       inc(m.subtypeMatches);
-      result := implicitConv(nkHiddenSubConv, f, arg, m, c);
+      result := implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c);
     end;
     isGeneric: begin
       inc(m.genericMatches);
       result := copyTree(arg);
       result.typ := getInstantiatedType(c, arg, m, f);
       // BUG: f may not be the right key!
+      if (skipVarGeneric(f).kind in [tyTuple, tyOpenArray]) then
+        // BUGFIX: must pass length implicitely
+        result := implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c);
     end;
     isEqual: begin
       inc(m.exactMatches);
       result := copyTree(arg);
-      if (skipVarGeneric(f).kind = tyOpenArray) then 
+      if (skipVarGeneric(f).kind in [tyTuple, tyOpenArray]) then
         // BUGFIX: must pass length implicitely
-        result := implicitConv(nkHiddenStdConv, f, arg, m, c);
+        result := implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c);
     end;
     isNone: begin
       result := userConvMatch(c, m, f, a, arg);
       // check for a base type match, which supports openarray[T] without []
       // constructor in a call:
-      (*
-      if (result = nil) and
-          ((f.kind = tyOpenArray) or (f.kind = tySequence)) then begin
+      if (result = nil) and (f.kind = tyOpenArray) then begin
         r := typeRel(m.bindings, base(f), a);
-        if r > isGeneric then begin
+        if r >= isGeneric then begin
           inc(m.convMatches);
           result := copyTree(arg);
           if r = isGeneric then
             result.typ := getInstantiatedType(c, arg, m, base(f));
           m.baseTypeMatch := true;
-          exit
         end
         else
           result := userConvMatch(c, m, base(f), a, arg);
-      end *)
+      end
     end
   end
 end;
@@ -711,6 +594,7 @@ begin
   addSon(m.call, copyTree(n.sons[0]));
   IntSetInit(marker);
   container := nil;
+  formal := nil;
   while a < sonsLen(n) do begin
     if n.sons[a].kind = nkExprEqExpr then begin
       // named param
@@ -733,13 +617,12 @@ begin
         exit
       end;
       m.baseTypeMatch := false;
-      arg := ParamTypesMatch(c, m, formal.typ, n.sons[a].typ, 
+      arg := ParamTypesMatch(c, m, formal.typ, n.sons[a].typ,
                              n.sons[a].sons[1]);
       if (arg = nil) then begin m.state := csNoMatch; exit end;
       if m.baseTypeMatch then begin
         assert(container = nil);
-        container := newNode(nkBracket);
-        container.info := n.sons[a].info;
+        container := newNodeI(nkBracket, n.sons[a].info);
         addSon(container, arg);
         setSon(m.call, formal.position+1, container);
         if f <> formalLen-1 then container := nil;
@@ -753,14 +636,14 @@ begin
       if f >= formalLen then begin // too many arguments?
         if tfVarArgs in m.callee.flags then begin
           // is ok... but don't increment any counters...
-          if skipVarGeneric(n.sons[a].typ).kind = tyString then 
+          if skipVarGeneric(n.sons[a].typ).kind = tyString then
             // conversion to cstring
-            addSon(m.call, implicitConv(nkHiddenStdConv, 
-              getSysType(tyCString), n.sons[a], m, c))
+            addSon(m.call, implicitConv(nkHiddenStdConv,
+              getSysType(tyCString), copyTree(n.sons[a]), m, c))
           else
             addSon(m.call, copyTree(n.sons[a]));
         end
-        else begin
+        else if formal <> nil then begin
           m.baseTypeMatch := false;
           arg := ParamTypesMatch(c, m, formal.typ, n.sons[a].typ, n.sons[a]);
           if (arg <> nil) and m.baseTypeMatch and (container <> nil) then begin
@@ -771,9 +654,14 @@ begin
             exit
           end;
         end
+        else begin
+          m.state := csNoMatch;
+          exit
+        end
       end
       else begin
-        assert(m.callee.n.sons[f].kind = nkSym);
+        if m.callee.n.sons[f].kind <> nkSym then
+          InternalError(n.sons[a].info, 'matches');
         formal := m.callee.n.sons[f].sym;
         if IntSetContainsOrIncl(marker, formal.position) then begin
           // already in namedParams:
@@ -786,10 +674,10 @@ begin
         if (arg = nil) then begin m.state := csNoMatch; exit end;
         if m.baseTypeMatch then begin
           assert(container = nil);
-          container := newNode(nkBracket);
-          container.info := n.sons[a].info;
+          container := newNodeI(nkBracket, n.sons[a].info);
           addSon(container, arg);
-          setSon(m.call, formal.position+1, container);
+          setSon(m.call, formal.position+1,
+            implicitConv(nkHiddenStdConv, formal.typ, container, m, c));
           if f <> formalLen-1 then container := nil;
         end
         else begin
@@ -825,6 +713,8 @@ var
   cmp: int;
 begin
   sym := initOverloadIter(o, c, n.sons[0]);
+  result := nil;
+  if sym = nil then exit;
   initCandidate(x, sym.typ);
   x.calleeSym := sym;
   initCandidate(y, sym.typ);
@@ -848,14 +738,14 @@ begin
     end;
     sym := nextOverloadIter(o, c, n.sons[0])
   end;
-  result := nil;
   if x.state = csEmpty then begin
     // no overloaded proc found
     // do not generate an error yet; the semantic checking will check for
     // an overloaded () operator
   end
   else if (y.state = csMatch) and (cmpCandidates(x, y) = 0) then begin
-    assert((x.state = csMatch));
+    if x.state <> csMatch then
+      InternalError(n.info, 'x.state is not csMatch');
     //writeMatches(x);
     //writeMatches(y);
     liMessage(n.Info, errGenerated,
diff --git a/nim/strtabs.pas b/nim/strtabs.pas
new file mode 100644
index 000000000..1df147f08
--- /dev/null
+++ b/nim/strtabs.pas
@@ -0,0 +1,295 @@
+//
+//
+//            Nimrod's Runtime Library
+//        (c) Copyright 2008 Andreas Rumpf
+//
+//    See the file "copying.txt", included in this
+//    distribution, for details about the copyright.
+//
+unit strtabs;
+
+// A configuration file parser; the Nimrod version of this file
+// will become part of the standard library.
+
+interface
+
+{$include 'config.inc'}
+
+uses
+  nsystem, nos, hashes, strutils;
+
+type
+  TStringTableMode = (
+    modeCaseSensitive,   // the table is case sensitive
+    modeCaseInsensitive, // the table is case insensitive
+    modeStyleInsensitive // the table is style insensitive
+  );
+  TKeyValuePair = record{@tuple}
+    key, val: string;
+  end;
+  TKeyValuePairSeq = array of TKeyValuePair;
+  TStringTable = object(NObject)
+    counter: int;
+    data: TKeyValuePairSeq;
+    mode: TStringTableMode;
+  end;
+  PStringTable = ^TStringTable;
+
+function newStringTable(const keyValuePairs: array of string;
+            mode: TStringTableMode = modeCaseSensitive): PStringTable;
+
+procedure put(t: PStringTable; const key, val: string);
+function get(t: PStringTable; const key: string): string;
+function hasKey(t: PStringTable; const key: string): bool;
+function len(t: PStringTable): int;
+
+type
+  TFormatFlag = (
+    useEnvironment, // use environment variable if the ``$key``
+                    // is not found in the table
+    useEmpty,       // use the empty string as a default, thus it
+                    // won't throw an exception if ``$key`` is not
+                    // in the table
+    useKey          // do not replace ``$key`` if it is not found
+                    // in the table (or in the environment)
+  );
+  TFormatFlags = set of TFormatFlag;
+
+function format(const f: string; t: PStringTable;
+                flags: TFormatFlags = {@set}[]): string;
+
+implementation
+
+const
+  growthFactor = 2;
+  startSize = 64;
+
+{@ignore}
+function isNil(const s: string): bool;
+begin
+  result := s = ''
+end;
+{@emit}
+
+function newStringTable(const keyValuePairs: array of string;
+            mode: TStringTableMode = modeCaseSensitive): PStringTable;
+var
+  i: int;
+begin
+  new(result);
+  result.mode := mode;
+  result.counter := 0;
+{@emit
+  result.data := []; }
+  setLength(result.data, startSize);
+{@ignore}
+  fillChar(result.data[0], length(result.data)*sizeof(result.data[0]), 0);
+{@emit}
+  i := 0;
+  while i < high(keyValuePairs) do begin
+    put(result, keyValuePairs[i], keyValuePairs[i+1]);
+    inc(i, 2);
+  end
+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);
+  end
+end;
+
+function myCmp(t: PStringTable; const a, b: string): bool;
+begin
+  case t.mode of
+    modeCaseSensitive: result := cmp(a, b) = 0;
+    modeCaseInsensitive: result := cmpIgnoreCase(a, b) = 0;
+    modeStyleInsensitive: result := cmpIgnoreStyle(a, b) = 0;
+  end
+end;
+
+function mustRehash(len, counter: int): bool;
+begin
+  assert(len > counter);
+  result := (len * 2 < counter * 3) or (len-counter < 4);
+end;
+
+function len(t: PStringTable): int;
+begin
+  result := t.counter
+end;
+
+{@ignore}
+const
+  EmptySeq = nil;
+{@emit
+const
+  EmptySeq = [];
+}
+
+function nextTry(h, maxHash: THash): THash;
+begin
+  result := ((5*h) + 1) and maxHash;
+  // For any initial h in range(maxHash), repeating that maxHash times
+  // generates each int in range(maxHash) exactly once (see any text on
+  // random-number generation for proof).
+end;
+
+function RawGet(t: PStringTable; const key: string): int;
+var
+  h: THash;
+begin
+  h := myhash(t, key) and high(t.data); // start with real hash value
+  while not isNil(t.data[h].key) do begin
+    if mycmp(t, t.data[h].key, key) then begin
+      result := h; exit
+    end;
+    h := nextTry(h, high(t.data))
+  end;
+  result := -1
+end;
+
+function get(t: PStringTable; const key: string): string;
+var
+  index: int;
+begin
+  index := RawGet(t, key);
+  if index >= 0 then result := t.data[index].val
+  else result := ''
+end;
+
+function hasKey(t: PStringTable; const key: string): bool;
+begin
+  result := rawGet(t, key) >= 0
+end;
+
+procedure RawInsert(t: PStringTable;
+                    var data: TKeyValuePairSeq;
+                    const key, val: string);
+var
+  h: THash;
+begin
+  h := myhash(t, key) and high(data);
+  while not isNil(data[h].key) do begin
+    h := nextTry(h, high(data))
+  end;
+  data[h].key := key;
+  data[h].val := val;
+end;
+
+procedure Enlarge(t: PStringTable);
+var
+  n: TKeyValuePairSeq;
+  i: int;
+begin
+  n := emptySeq;
+  setLength(n, length(t.data) * growthFactor);
+{@ignore}
+  fillChar(n[0], length(n)*sizeof(n[0]), 0);
+{@emit}
+  for i := 0 to high(t.data) do
+    if not isNil(t.data[i].key) then
+      RawInsert(t, n, t.data[i].key, t.data[i].val);
+{@ignore}
+  t.data := n;
+{@emit
+  swap(t.data, n);
+}
+end;
+
+procedure Put(t: PStringTable; const key, val: string);
+var
+  index: int;
+begin
+  index := RawGet(t, key);
+  if index >= 0 then
+    t.data[index].val := val
+  else begin
+    if mustRehash(length(t.data), t.counter) then Enlarge(t);
+    RawInsert(t, t.data, key, val);
+    inc(t.counter)
+  end;
+end;
+
+{@ignore}
+type
+  EInvalidValue = int; // dummy for the Pascal compiler
+{@emit}
+
+procedure RaiseFormatException(const s: string);
+var
+  e: ^EInvalidValue;
+begin
+{@ignore}
+  raise EInvalidFormatStr.create(s);
+{@emit
+  new(e);}
+{@emit
+  e.msg := 'format string: key not found: ' + s;}
+{@emit
+  raise e;}
+end;
+
+function getValue(t: PStringTable; flags: TFormatFlags;
+                  const key: string): string;
+begin
+  if hasKey(t, key) then begin
+    result := get(t, key); exit
+  end;
+  if useEnvironment in flags then
+    result := nos.getEnv(key)
+  else
+    result := '';
+  if (result = '') then begin
+    if useKey in flags then result := '$' + key
+    else if not (useEmpty in flags) then
+      raiseFormatException(key)
+  end
+end;
+
+function format(const f: string; t: PStringTable;
+                flags: TFormatFlags = {@set}[]): string;
+const
+  PatternChars = ['a'..'z', 'A'..'Z', '0'..'9', '_', #128..#255];
+var
+  i, j: int;
+  key: string;
+begin
+  result := '';
+  i := strStart;
+  while i <= length(f)+strStart-1 do
+    if f[i] = '$' then begin
+      case f[i+1] of
+        '$': begin
+          addChar(result, '$');
+          inc(i, 2);
+        end;
+        '{': begin
+          j := i+1;
+          while (j <= length(f)+strStart-1) and (f[j] <> '}') do inc(j);
+          key := ncopy(f, i+2+strStart-1, j-1+strStart-1);
+          result := result +{&} getValue(t, flags, key);
+          i := j+1
+        end;
+        'a'..'z', 'A'..'Z', #128..#255, '_': begin
+          j := i+1;
+          while (j <= length(f)+strStart-1) and (f[j] in PatternChars) do inc(j);
+          key := ncopy(f, i+1+strStart-1, j-1+strStart-1);
+          result := result +{&} getValue(t, flags, key);
+          i := j
+        end
+        else begin
+          addChar(result, f[i]);
+          inc(i)
+        end
+      end
+    end
+    else begin
+      addChar(result, f[i]);
+      inc(i)
+    end
+end;
+
+end.
diff --git a/nim/strutils.pas b/nim/strutils.pas
index b654b7868..d70fdd8c3 100644
--- a/nim/strutils.pas
+++ b/nim/strutils.pas
@@ -56,6 +56,7 @@ function toUpper(c: Char): Char; overload;
 function toUpper(s: string): string; overload;
 
 function parseInt(const s: string): int;
+function parseBiggestInt(const s: string): BiggestInt;
 function ParseFloat(const s: string; checkEnd: Boolean = True): Real;
 
 function repeatChar(count: int; c: Char = ' '): string;
@@ -74,8 +75,18 @@ const
 function strip(const s: string; const chars: TCharSet = WhiteSpace): string;
 function allCharsInSet(const s: string; const theSet: TCharSet): bool;
 
+function quoteIfSpaceExists(const s: string): string;
+
 implementation
 
+function quoteIfSpaceExists(const s: string): string;
+begin
+  if (findSubStr(' ', s) >= strStart) and (s[strStart] <> '"') then
+    result := '"' +{&} s +{&} '"'
+  else
+    result := s
+end;
+
 function allCharsInSet(const s: string; const theSet: TCharSet): bool;
 var
   i: int;
@@ -511,7 +522,7 @@ begin
           while (j <= length(f)) and (f[j] in PatternChars) do inc(j);
           x := find(ncopy(f, i+1, j-1), args);
           if (x >= 0) and (x < high(args)) then result := result + args[x+1]
-          else raise EInvalidFormatStr.create('');
+          else raise EInvalidFormatStr.create(ncopy(f, i+1, j-1));
           i := j
         end
         else raise EInvalidFormatStr.create('');
@@ -584,6 +595,16 @@ begin
     result := int(res) // convert to smaller int type
 end;
 
+function parseBiggestInt(const s: string): BiggestInt;
+var
+  index: int;
+  res: BiggestInt;
+begin
+  index := strStart;
+  result := rawParseInt(s, index);
+  if index = -1 then raise EInvalidValue.create('')
+end;
+
 {@ignore}
 {$ifopt Q+} {$Q-}
 {$else}     {$define Q_on}
diff --git a/nim/transf.pas b/nim/transf.pas
index 33ece8116..97ad31540 100644
--- a/nim/transf.pas
+++ b/nim/transf.pas
@@ -12,9 +12,6 @@
 //
 // * inlines iterators
 // * looks up constants
-// * transforms lambdas and makes closures explicit
-// * transforms `&`(a, `&` (b, c)) to `&`(a, b, c)
-// * generates type information
 
 // ------------ helpers -----------------------------------------------------
 
@@ -27,7 +24,7 @@ begin
   result := newSym(skTemp, getIdent(genPrefix +{&} ToString(gTmpId)),
                    c.transCon.owner);
   result.info := info;
-  result.typ := typ;
+  result.typ := skipGeneric(typ);
 end;
 
 // --------------------------------------------------------------------------
@@ -96,7 +93,7 @@ function transformSym(c: PContext; n: PNode): PNode;
 var
   tc: PTransCon;
 begin
-  assert(n.kind = nkSym);
+  if (n.kind <> nkSym) then internalError(n.info, 'transformSym');
   tc := c.transCon;
   //writeln('transformSym', n.sym.id : 5);
   while tc <> nil do begin
@@ -106,15 +103,19 @@ begin
     //writeIdNodeTable(tc.mapping);
     tc := tc.next
   end;
-  if (n.sym.kind = skConst) and not (n.sym.typ.kind in ConstantDataTypes) then begin
-    result := getConstExpr(c, n);
-    assert(result <> nil);
+  result := n;
+  case n.sym.kind of
+    skConst, skEnumField: begin // BUGFIX: skEnumField was missing
+      if not (skipGeneric(n.sym.typ).kind in ConstantDataTypes) then begin
+        result := getConstExpr(c, n);
+        if result = nil then InternalError(n.info, 'transformSym: const');
+      end
+    end
+    else begin end
   end
-  else
-    result := n;
 end;
 
-procedure transformContinueAux(c: PContext; n: PNode; labl: PSym; 
+procedure transformContinueAux(c: PContext; n: PNode; labl: PSym;
                                var counter: int);
 var
   i: int;
@@ -128,7 +129,7 @@ begin
       inc(counter);
     end;
     else begin
-      for i := 0 to sonsLen(n)-1 do 
+      for i := 0 to sonsLen(n)-1 do
         transformContinueAux(c, n.sons[i], labl, counter);
     end
   end
@@ -136,7 +137,7 @@ end;
 
 function transformContinue(c: PContext; n: PNode): PNode;
 // we transform the continue statement into a block statement
-var 
+var
   i, counter: int;
   x: PNode;
   labl: PSym;
@@ -151,13 +152,24 @@ begin
   labl.info := result.info;
   transformContinueAux(c, result, labl, counter);
   if counter > 0 then begin
-    x := newNodeI(nkBlockStmt, result.info); 
+    x := newNodeI(nkBlockStmt, result.info);
     addSon(x, newSymNode(labl));
     addSon(x, result);
     result := x
   end
 end;
 
+function skipConv(n: PNode): PNode;
+begin
+  case n.kind of
+    nkObjUpConv, nkObjDownConv, nkPassAsOpenArray, nkChckRange,
+    nkChckRangeF, nkChckRange64:
+      result := n.sons[0];
+    nkHiddenStdConv, nkHiddenSubConv, nkConv: result := n.sons[1];
+    else result := n
+  end
+end;
+
 function transformYield(c: PContext; n: PNode): PNode;
 var
   e: PNode;
@@ -165,7 +177,8 @@ var
 begin
   result := newNodeI(nkStmtList, n.info);
   e := n.sons[0];
-  if e.typ.kind = tyTuple then begin
+  if skipGeneric(e.typ).kind = tyTuple then begin
+    e := skipConv(e);
     if e.kind = nkPar then begin
       for i := 0 to sonsLen(e)-1 do begin
         addSon(result, newAsgnStmt(c, c.transCon.forStmt.sons[i],
@@ -202,16 +215,15 @@ begin
       result := copyTree(n);
       for i := 0 to sonsLen(result)-1 do begin
         it := result.sons[i];
-        assert(it.kind = nkIdentDefs);
-        assert(it.sons[0].kind = nkSym);
-        if it.sons[0].sym.kind <> skTemp then begin
-          newVar := copySym(it.sons[0].sym, getCurrOwner(c));
-          IdNodeTablePut(c.transCon.mapping, it.sons[0].sym,
-                         newSymNode(newVar));
-          it.sons[0] := newSymNode(newVar);
-        end;
+        if it.kind = nkCommentStmt then continue;
+        if (it.kind <> nkIdentDefs) or (it.sons[0].kind <> nkSym) then
+          InternalError(it.info, 'inlineIter');
+        newVar := copySym(it.sons[0].sym);
+        newVar.owner := getCurrOwner(c);
+        IdNodeTablePut(c.transCon.mapping, it.sons[0].sym,
+                       newSymNode(newVar));
+        it.sons[0] := newSymNode(newVar);
         it.sons[2] := transform(c, it.sons[2]);
-        //writeIdNodeTable(c.transCon.mapping);
       end
     end
     else begin
@@ -233,6 +245,131 @@ begin
   addSon(father, vpart);
 end;
 
+function transformAddrDeref(c: PContext; n: PNode; a, b: TNodeKind): PNode;
+var
+  m: PNode;
+begin
+  case n.sons[0].kind of
+    nkObjUpConv, nkObjDownConv, nkPassAsOpenArray, nkChckRange,
+    nkChckRangeF, nkChckRange64: begin
+      m := n.sons[0].sons[0];
+      if (m.kind = a) or (m.kind = b) then begin
+        // addr ( nkPassAsOpenArray ( deref ( x ) ) ) --> nkPassAsOpenArray(x)
+        n.sons[0].sons[0] := m.sons[0];
+        result := transform(c, n.sons[0]);
+        exit
+      end
+    end;
+    nkHiddenStdConv, nkHiddenSubConv, nkConv: begin
+      m := n.sons[0].sons[1];
+      if (m.kind = a) or (m.kind = b) then begin
+        // addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
+        n.sons[0].sons[1] := m.sons[0];
+        result := transform(c, n.sons[0]);
+        exit
+      end
+    end;
+    else begin
+      if (n.sons[0].kind = a) or (n.sons[0].kind = b) then begin
+        // addr ( deref ( x )) --> x
+        result := transform(c, n.sons[0].sons[0]);
+        exit
+      end
+    end
+  end;
+  n.sons[0] := transform(c, n.sons[0]);
+  result := n;
+end;
+
+function transformConv(c: PContext; n: PNode): PNode;
+var
+  source, dest: PType;
+  diff: int;
+begin
+  n.sons[1] := transform(c, n.sons[1]);
+  result := n;
+  // numeric types need range checks:
+  dest := skipVarGenericRange(n.typ);
+  source := skipVarGenericRange(n.sons[1].typ);
+  case dest.kind of
+    tyInt..tyInt64, tyEnum, tyChar, tyBool: begin
+      if (firstOrd(dest) <= firstOrd(source)) and
+          (lastOrd(source) <= lastOrd(dest)) then begin
+        // BUGFIX: simply leave n as it is; we need a nkConv node,
+        // but no range check:
+        result := n;
+      end
+      else begin // generate a range check:
+        if (dest.kind = tyInt64) or (source.kind = tyInt64) then
+          result := newNodeIT(nkChckRange64, n.info, n.typ)
+        else
+          result := newNodeIT(nkChckRange, n.info, n.typ);
+        dest := skipVarGeneric(n.typ);
+        addSon(result, n.sons[1]);
+        addSon(result, newIntTypeNode(nkIntLit, firstOrd(dest), source));
+        addSon(result, newIntTypeNode(nkIntLit,  lastOrd(dest), source));
+      end
+    end;
+    tyFloat..tyFloat128: begin
+      if skipVarGeneric(n.typ).kind = tyRange then begin
+        result := newNodeIT(nkChckRangeF, n.info, n.typ);
+        dest := skipVarGeneric(n.typ);
+        addSon(result, n.sons[1]);
+        addSon(result, copyTree(dest.n.sons[0]));
+        addSon(result, copyTree(dest.n.sons[1]));
+      end
+    end;
+    tyOpenArray: begin
+      result := newNodeIT(nkPassAsOpenArray, n.info, n.typ);
+      addSon(result, n.sons[1]);
+    end;
+    tyCString: begin
+      if source.kind = tyString then begin
+        result := newNodeIT(nkStringToCString, n.info, n.typ);
+        addSon(result, n.sons[1]);
+      end;
+    end;
+    tyString: begin
+      if source.kind = tyCString then begin
+        result := newNodeIT(nkCStringToString, n.info, n.typ);
+        addSon(result, n.sons[1]);
+      end;
+    end;
+    tyRef, tyPtr: begin
+      dest := skipPtrsGeneric(dest);
+      source := skipPtrsGeneric(source);
+      if source.kind = tyObject then begin
+        diff := inheritanceDiff(dest, source);
+        if diff < 0 then begin
+          result := newNodeIT(nkObjUpConv, n.info, n.typ);
+          addSon(result, n.sons[1]);
+        end
+        else if diff > 0 then begin
+          result := newNodeIT(nkObjDownConv, n.info, n.typ);
+          addSon(result, n.sons[1]);
+        end
+        else result := n.sons[1];
+      end
+    end;
+    // conversions between different object types:
+    tyObject: begin
+      diff := inheritanceDiff(dest, source);
+      if diff < 0 then begin
+        result := newNodeIT(nkObjUpConv, n.info, n.typ);
+        addSon(result, n.sons[1]);
+      end
+      else if diff > 0 then begin
+        result := newNodeIT(nkObjDownConv, n.info, n.typ);
+        addSon(result, n.sons[1]);
+      end
+      else result := n.sons[1];
+    end;
+    tyGenericParam, tyAnyEnum: result := n.sons[1];
+      // happens sometimes for generated assignments, etc.
+    else begin end
+  end;
+end;
+
 function transformFor(c: PContext; n: PNode): PNode;
 // generate access statements for the parameters (unless they are constant)
 // put mapping from formal parameters to actual parameters
@@ -247,8 +384,7 @@ begin
   len := sonsLen(n);
   n.sons[len-1] := transformContinue(c, n.sons[len-1]);
   v := newNodeI(nkVarSection, n.info);
-  for i := 0 to len-3 do
-    addVar(v, copyTree(n.sons[i])); // declare new variables
+  for i := 0 to len-3 do addVar(v, copyTree(n.sons[i])); // declare new vars
   addSon(result, v);
   newC := newTransCon();
   call := n.sons[len-2];
@@ -261,10 +397,10 @@ begin
   pushTransCon(c, newC);
   for i := 1 to sonsLen(call)-1 do begin
     e := getConstExpr(c, call.sons[i]);
-    formal := newC.owner.typ.n.sons[i].sym;
+    formal := skipGeneric(newC.owner.typ).n.sons[i].sym;
     if e <> nil then
       IdNodeTablePut(newC.mapping, formal, e)
-    else if (call.sons[i].kind = nkSym) then begin
+    else if (skipConv(call.sons[i]).kind = nkSym) then begin
       // since parameters cannot be modified, we can identify the formal and
       // the actual params
       IdNodeTablePut(newC.mapping, formal, call.sons[i]);
@@ -278,14 +414,14 @@ begin
     end
   end;
   body := newC.owner.ast.sons[codePos];
-  //writeln(renderTree(body, {@set}[renderIds]));
   addSon(result, inlineIter(c, body));
   popTransCon(c);
 end;
 
 function getMagicOp(call: PNode): TMagic;
 begin
-  if (call.sons[0].kind = nkSym) and (call.sons[0].sym.kind = skProc) then
+  if (call.sons[0].kind = nkSym)
+  and (call.sons[0].sym.kind in [skProc, skConverter]) then
     result := call.sons[0].sym.magic
   else
     result := mNone
@@ -422,7 +558,7 @@ begin
   closure := newNodeI(nkRecList, n.sons[codePos].info);
   gatherVars(c, n.sons[codePos], marked, s, closure);
   // add closure type to the param list (even if closure is empty!):
-  cl := newType(tyRecord, s);
+  cl := newType(tyObject, s);
   cl.n := closure;
   addSon(cl, nil); // no super class
   p := newType(tyRef, s);
@@ -464,19 +600,18 @@ begin
     n.sons[i+1] := ifs;
   end;
   result := n;
-  for j := 0 to sonsLen(n)-1 do
-    result.sons[j] := transform(c, n.sons[j]);
+  for j := 0 to sonsLen(n)-1 do result.sons[j] := transform(c, n.sons[j]);
 end;
 
 function transformArrayAccess(c: PContext; n: PNode): PNode;
 var
-  j: int;
+  i: int;
 begin
   result := copyTree(n);
-  if result.sons[1].kind in [nkHiddenSubConv, nkHiddenStdConv] then
-    result.sons[1] := result.sons[1].sons[0];
-  for j := 0 to sonsLen(result)-1 do
-    result.sons[j] := transform(c, result.sons[j]);
+  result.sons[0] := skipConv(result.sons[0]);
+  result.sons[1] := skipConv(result.sons[1]);
+  for i := 0 to sonsLen(result)-1 do
+    result.sons[i] := transform(c, result.sons[i]);
 end;
 
 function transform(c: PContext; n: PNode): PNode;
@@ -510,6 +645,12 @@ begin
       n.sons[0] := transform(c, n.sons[0]);
       n.sons[1] := transformContinue(c, n.sons[1]);
     end;
+    nkAddr, nkHiddenAddr:
+      result := transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref);
+    nkDerefExpr, nkHiddenDeref:
+      result := transformAddrDeref(c, n, nkAddr, nkHiddenAddr);
+    nkHiddenStdConv, nkHiddenSubConv, nkConv:
+      result := transformConv(c, n);
     nkCommentStmt, nkTemplateDef, nkMacroDef: exit;
     nkConstSection: exit; // do not replace ``const c = 3`` with ``const 3 = 3``
     else begin
diff --git a/nim/transtmp.pas b/nim/transtmp.pas
index df61aa00d..cfec21c98 100644
--- a/nim/transtmp.pas
+++ b/nim/transtmp.pas
@@ -9,7 +9,8 @@
 
 // This module implements a transformator. It transforms the syntax tree 
 // to ease the work of the code generators. Does the transformation to 
-// introduce temporaries to split up complex expressions. 
+// introduce temporaries to split up complex expressions.
+// THIS MODULE IS NOT USED!
 
 procedure transInto(c: PContext; var dest: PNode; father, src: PNode); forward;
 // transforms the expression `src` into the destination `dest`. Uses `father`
diff --git a/nim/trees.pas b/nim/trees.pas
index bd4137083..a50b8f6cb 100644
--- a/nim/trees.pas
+++ b/nim/trees.pas
@@ -21,7 +21,7 @@ function getMagic(op: PNode): TMagic;
 
 // function getConstExpr(const t: TNode; out res: TNode): Boolean;
 
-function isConstExpr(node: PNode): Boolean;
+function isConstExpr(n: PNode): Boolean;
 
 
 function flattenTree(root: PNode; op: TMagic): PNode;
@@ -36,9 +36,44 @@ function getProcSym(call: PNode): PSym;
 function ExprStructuralEquivalent(a, b: PNode): Boolean;
 
 function sameTree(a, b: PNode): boolean;
+function cyclicTree(n: PNode): boolean;
 
 implementation
 
+function hasSon(father, son: PNode): boolean;
+var
+  i: int;
+begin
+  for i := 0 to sonsLen(father)-1 do 
+    if father.sons[i] = son then begin result := true; exit end;
+  result := false
+end;
+
+function cyclicTreeAux(n, s: PNode): boolean;
+var
+  i, m: int;
+begin
+  if n = nil then begin result := false; exit end;
+  if hasSon(s, n) then begin result := true; exit end;
+  m := sonsLen(s);
+  addSon(s, n);
+  if not (n.kind in [nkEmpty..nkNilLit]) then 
+    for i := 0 to sonsLen(n)-1 do 
+      if cyclicTreeAux(n.sons[i], s) then begin  
+        result := true; exit 
+      end;
+  result := false;
+  delSon(s, m);
+end;
+
+function cyclicTree(n: PNode): boolean;
+var
+  s: PNode;
+begin
+  s := newNode(nkEmpty);
+  result := cyclicTreeAux(n, s);
+end;
+
 function ExprStructuralEquivalent(a, b: PNode): Boolean;
 var
   i: int;
@@ -77,7 +112,7 @@ begin
     result := true
   end
   else if (a <> nil) and (b <> nil) and (a.kind = b.kind) then begin
-    if a.base <> b.base then exit;
+    if a.flags <> b.flags then exit;
     if a.info.line <> int(b.info.line) then exit;
     if a.info.col <> int(b.info.col) then exit;
     //if a.info.fileIndex <> b.info.fileIndex then exit;
@@ -109,7 +144,7 @@ end;
 
 function getOpSym(op: PNode): PSym;
 begin
-  if not (op.kind in [nkCall, nkGenericCall]) then
+  if not (op.kind in [nkCall, nkGenericCall, nkHiddenCallConv]) then
     result := nil
   else begin
     assert(sonsLen(op) > 0);
@@ -123,7 +158,7 @@ end;
 function getMagic(op: PNode): TMagic;
 begin
   case op.kind of
-    nkCall: begin
+    nkCall, nkHiddenCallConv: begin
       case op.sons[0].Kind of
         nkSym, nkQualified: begin
           assert(op.sons[0].sym <> nil); // BUGFIX
@@ -145,12 +180,10 @@ begin
   result := t.sym
 end;
 
-function isConstExpr(node: PNode): Boolean;
+function isConstExpr(n: PNode): Boolean;
 begin
-  result := (node.kind in [nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
-                           nkFloatLit..nkFloat64Lit,
-                           nkConstSetConstr,
-                           nkConstArrayConstr, nkConstRecordConstr])
+  result := (n.kind in [nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
+                       nkFloatLit..nkFloat64Lit]) or (nfAllConst in n.flags)
 end;
 
 procedure flattenTreeAux(d, a: PNode; op: TMagic);
diff --git a/nim/types.pas b/nim/types.pas
index 5719d181a..c63913baa 100644
--- a/nim/types.pas
+++ b/nim/types.pas
@@ -48,7 +48,7 @@ function mutateType(t: PType; iter: TTypeMutator; closure: PObject): PType;
 
 
 
-function SameType(a, b: PType): Boolean;
+function SameType(x, y: PType): Boolean;
 function SameTypeOrNil(a, b: PType): Boolean;
 
 type
@@ -67,16 +67,15 @@ function isOrdinalType(t: PType): Boolean;
 function enumHasWholes(t: PType): Boolean;
 
 function skipRange(t: PType): PType;
-function skipAbstract(t: PType): PType;
 function skipGeneric(t: PType): PType;
+function skipGenericRange(t: PType): PType;
 function skipVar(t: PType): PType;
 function skipVarGeneric(t: PType): PType;
 function skipVarGenericRange(t: PType): PType;
+function skipPtrsGeneric(t: PType): PType;
 
 function elemType(t: PType): PType;
 
-function inheritAssignable(toCopy: PType; isAssignable: bool): PType;
-
 function containsObject(t: PType): bool;
 function containsGarbageCollectedRef(typ: PType): Boolean;
 function containsHiddenPointer(typ: PType): Boolean;
@@ -89,8 +88,57 @@ function getOrdValue(n: PNode): biggestInt;
 function computeSize(typ: PType): biggestInt;
 function getSize(typ: PType): biggestInt;
 
+function isPureObject(typ: PType): boolean;
+
+function inheritanceDiff(a, b: PType): int;
+// | returns: 0 iff `a` == `b`
+// | returns: -x iff `a` is the x'th direct superclass of `b`
+// | returns: +x iff `a` is the x'th direct subclass of `b`
+// | returns: `maxint` iff `a` and `b` are not compatible at all
+
+
+function InvalidGenericInst(f: PType): bool;
+// for debugging
+
 implementation
 
+function InvalidGenericInst(f: PType): bool;
+begin
+  result := (f.kind = tyGenericInst) and (lastSon(f) = nil);
+end;
+
+function inheritanceDiff(a, b: PType): int;
+var
+  x, y: PType;
+begin
+  // conversion to superclass?
+  x := a;
+  result := 0;
+  while (x <> nil) do begin
+    if x.id = b.id then exit;
+    x := x.sons[0];
+    dec(result);
+  end;
+  // conversion to baseclass?
+  y := b;
+  result := 0;
+  while (y <> nil) do begin
+    if y.id = a.id then exit;
+    y := y.sons[0];
+    inc(result);
+  end;
+  result := high(int);
+end;
+
+function isPureObject(typ: PType): boolean;
+var
+  t: PType;
+begin
+  t := typ;
+  while t.sons[0] <> nil do t := t.sons[0];
+  result := (t.sym <> nil) and (sfPure in t.sym.flags);
+end;
+
 function getOrdValue(n: PNode): biggestInt;
 begin
   case n.kind of
@@ -131,24 +179,11 @@ begin
     result := result +{&} ': ' +{&} typeToString(n.sons[0].typ);
 end;
 
-function inheritAssignable(toCopy: PType; isAssignable: bool): PType;
-begin
-  if isAssignable then begin
-    if tfAssignable in toCopy.flags then result := toCopy
-    else begin
-      result := copyType(toCopy, toCopy.owner); // same ID!
-      include(result.flags, tfAssignable);
-    end
-  end
-  else
-    result := toCopy // no need to copy
-end;
-
 function elemType(t: PType): PType;
 begin
   assert(t <> nil);
   case t.kind of
-    tyGenericInst: result := lastSon(t);
+    tyGenericInst: result := elemType(lastSon(t));
     tyArray, tyArrayConstr: result := t.sons[1];
     else result := t.sons[0];
   end;
@@ -186,6 +221,13 @@ begin
   while result.kind in [tyGenericInst, tyVar] do result := lastSon(result);
 end;
 
+function skipPtrsGeneric(t: PType): PType;
+begin
+  result := t;
+  while result.kind in [tyGenericInst, tyVar, tyPtr, tyRef] do
+    result := lastSon(result);
+end;
+
 function skipVarGenericRange(t: PType): PType;
 begin
   result := t;
@@ -193,6 +235,13 @@ begin
     result := lastSon(result);
 end;
 
+function skipGenericRange(t: PType): PType;
+begin
+  result := t;
+  while result.kind in [tyGenericInst, tyVar, tyRange] do
+    result := lastSon(result);
+end;
+
 function isOrdinalType(t: PType): Boolean;
 begin
   assert(t <> nil);
@@ -309,13 +358,13 @@ begin
   result := Predicate(t);
   if result then exit;
   case t.kind of
-    tyObject, tyRecord: begin
+    tyObject: begin
       result := searchTypeForAux(t.sons[0], predicate, marker);
       if not result then
         result := searchTypeNodeForAux(t.n, predicate, marker);
     end;
     tyGenericInst: result := searchTypeForAux(lastSon(t), predicate, marker);
-    tyArray, tyArrayConstr, tyTuple, tySet: begin
+    tyArray, tyArrayConstr, tySet, tyTuple: begin
       for i := 0 to sonsLen(t)-1 do begin
         result := searchTypeForAux(t.sons[i], predicate, marker);
         if result then exit
@@ -400,11 +449,14 @@ begin
   result := iter(t, closure);
   if not IntSetContainsOrIncl(marker, t.id) then begin
     for i := 0 to sonsLen(t)-1 do begin
-      result.sons[i] := mutateTypeAux(marker, t.sons[i], iter, closure);
+      result.sons[i] := mutateTypeAux(marker, result.sons[i], iter, closure);
+      if (result.sons[i] = nil) and (result.kind = tyGenericInst) then
+        assert(false);
     end;
     if t.n <> nil then
       result.n := mutateNode(marker, t.n, iter, closure)
-  end
+  end;
+  assert(result <> nil);
 end;
 
 function mutateType(t: PType; iter: TTypeMutator; closure: PObject): PType;
@@ -425,9 +477,9 @@ function TypeToString(typ: PType; prefer: TPreferedDesc = preferName): string;
 const
   typeToStr: array [TTypeKind] of string = (
     'None', 'bool', 'Char', '{}', 'Array Constructor [$1]', 'nil',
-    'Record Constructor [$1]', 'Generic', 'GenericInst', 'GenericParam',
+    'Generic', 'GenericInst', 'GenericParam',
     'enum', 'anyenum',
-    'array[$1, $2]', 'record', 'object', 'tuple', 'set[$1]', 'range[$1]',
+    'array[$1, $2]', 'object', 'tuple', 'set[$1]', 'range[$1]',
     'ptr ', 'ref ', 'var ', 'seq[$1]', 'proc', 'pointer',
     'OpenArray[$1]', 'string', 'CString', 'Forward',
     'int', 'int8', 'int16', 'int32', 'int64',
@@ -462,21 +514,22 @@ begin
     tySet: result := 'set[' +{&} typeToString(t.sons[0]) +{&} ']';
     tyOpenArray: result := 'openarray[' +{&} typeToString(t.sons[0]) +{&} ']';
     tyTuple: begin
-      assert(t.n = nil);
+      // we iterate over t.sons here, because t.n may be nil
       result := 'tuple[';
-      for i := 0 to sonsLen(t)-1 do begin
-        result := result +{&} typeToString(t.sons[i]);
-        if i < sonsLen(t)-1 then result := result +{&} ', ';
-      end;
-      addChar(result, ']')
-    end;
-    tyRecordConstr: begin
-      assert(t.n <> nil);
-      result := 'record[';
-      for i := 0 to sonsLen(t.n)-1 do begin
-        result := result +{&} t.n.sons[i].sym.name.s +{&} ': '
-                         +{&} typeToString(t.n.sons[i].sym.typ);
-        if i < sonsLen(t.n)-1 then result := result +{&} ', ';
+      if t.n <> nil then begin
+        assert(sonsLen(t.n) = sonsLen(t));
+        for i := 0 to sonsLen(t.n)-1 do begin
+          assert(t.n.sons[i].kind = nkSym);
+          result := result +{&} t.n.sons[i].sym.name.s +{&} ': '
+                  +{&} typeToString(t.sons[i]);
+          if i < sonsLen(t.n)-1 then result := result +{&} ', ';
+        end
+      end
+      else begin
+        for i := 0 to sonsLen(t)-1 do begin
+          result := result +{&} typeToString(t.sons[i]);
+          if i < sonsLen(t)-1 then result := result +{&} ', ';
+        end
       end;
       addChar(result, ']')
     end;
@@ -545,6 +598,7 @@ begin
         result := t.n.sons[0].sym.position;
       end;
     end;
+    tyGenericInst: result := firstOrd(lastSon(t));
     else begin
       InternalError('invalid kind for first(' +{&}
         typeKindToStr[t.kind] +{&} ')');
@@ -580,6 +634,7 @@ begin
       assert(t.n.sons[sonsLen(t.n)-1].kind = nkSym);
       result := t.n.sons[sonsLen(t.n)-1].sym.position;
     end;
+    tyGenericInst: result := firstOrd(lastSon(t));
     else begin
       InternalError('invalid kind for last(' +{&}
         typeKindToStr[t.kind] +{&} ')');
@@ -680,46 +735,67 @@ begin
     SameLiteral(a.sons[1], b.sons[1])
 end;
 
-function sameRecordConstr(a, b: PType): Boolean;
+function sameTuple(a, b: PType): boolean;
+// two tuples are equivalent iff the names, types and positions are the same;
+// however, both types may not have any field names (t.n may be nil) which
+// complicates the matter a bit.
 var
   i: int;
   x, y: PSym;
 begin
-  if sonsLen(a.n) <> sonsLen(b.n) then begin
-    result := false; exit
-  end;
-  for i := 0 to sonsLen(a.n)-1 do begin
-    x := a.n.sons[i].sym;
-    y := getSymFromList(b.n, x.name);
-    if (y = nil) or not SameType(x.typ, y.typ) then begin
-      result := false; exit
+  if sonsLen(a) = sonsLen(b) then begin
+    result := true;
+    for i := 0 to sonsLen(a)-1 do begin
+      result := SameType(a.sons[i], b.sons[i]);
+      if not result then exit
+    end;
+    if (a.n <> nil) and (b.n <> nil) then begin
+      for i := 0 to sonsLen(a.n)-1 do begin
+        // check field names: 
+        if a.n.sons[i].kind <> nkSym then InternalError(a.n.info, 'sameTuple');
+        if b.n.sons[i].kind <> nkSym then InternalError(b.n.info, 'sameTuple');
+        x := a.n.sons[i].sym;
+        y := b.n.sons[i].sym;
+        result := x.name.id = y.name.id;
+        if not result then break
+      end
     end
-  end;
-  result := true
+  end
+  else
+    result := false;
 end;
 
-function SameType(a, b: PType): Boolean;
+function SameType(x, y: PType): Boolean;
 var
   i: int;
+  a, b: PType;
 begin
+  a := skipGeneric(x);
+  b := skipGeneric(y);
   assert(a <> nil);
   assert(b <> nil);
   if a.kind <> b.kind then begin result := false; exit end;
   case a.Kind of
-    tyRecord, tyEnum, tyForward, tyObject:
+    tyEnum, tyForward, tyObject:
       result := (a.id = b.id);
-    tyGenericParam, tyGeneric, tyGenericInst, tySequence,
+    tyTuple: 
+      result := sameTuple(a, b);
+    tyGenericInst:
+      result := sameType(lastSon(a), lastSon(b));
+    tyGenericParam, tyGeneric, tySequence,
     tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
-    tyArray, tyTuple, tyProc: begin
+    tyArray, tyProc: begin
       if sonsLen(a) = sonsLen(b) then begin
         result := true;
         for i := 0 to sonsLen(a)-1 do begin
           result := SameTypeOrNil(a.sons[i], b.sons[i]); // BUGFIX
           if not result then exit
-        end
+        end;
+        if result and (a.kind = tyProc) then 
+          result := a.callConv = b.callConv // BUGFIX
       end
       else
-        result := false
+        result := false;
     end;
     tyRange: begin
       result := SameTypeOrNil(a.sons[0], b.sons[0])
@@ -728,7 +804,6 @@ begin
     end;
     tyChar, tyBool, tyNil, tyPointer, tyString, tyCString, tyInt..tyFloat128:
       result := true;
-    tyRecordConstr: result := sameRecordConstr(a, b); // BUGFIX
     else begin
       InternalError('sameType(' +{&} typeKindToStr[a.kind] +{&} ', '
         +{&} typeKindToStr[b.kind] +{&} ')');
@@ -833,10 +908,10 @@ begin
       if firstOrd(typ) < 0 then
         result := 4 // use signed int32
       else begin
-        len := lengthOrd(typ);
-        if len < 2 shl 8 then result := 1
-        else if len < 2 shl 16 then result := 2
-        else if len < 2 shl 32 then result := 4
+        len := lastOrd(typ); // BUGFIX: use lastOrd!
+        if len+1 < 1 shl 8 then result := 1
+        else if len+1 < 1 shl 16 then result := 2
+        else if len+1 < 1 shl 32 then result := 4
         else result := 8;
       end;
       a := result;
@@ -863,7 +938,7 @@ begin
       result := align(result, maxAlign);
       a := maxAlign;
     end;
-    tyRecord, tyObject: begin
+    tyObject: begin
       if typ.sons[0] <> nil then begin
         result := computeSizeAux(typ.sons[0], a);
         maxAlign := a
@@ -879,7 +954,7 @@ begin
       if a < maxAlign then a := maxAlign;
       result := align(result, a);
     end;
-    tyGeneric: begin
+    tyGenericInst: begin
       result := computeSizeAux(lastSon(typ), a);
     end;
     else begin
diff --git a/nim/vis.pas b/nim/vis.pas
deleted file mode 100644
index 7f59abaec..000000000
--- a/nim/vis.pas
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-//
-//           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
-//
-//    See the file "copying.txt", included in this
-//    distribution, for details about the copyright.
-//
-
-// Virtual instruction set for Nimrod. Has been designed to support: 
-// * efficient C code generation (most important goal)
-// * efficient LLVM code generation (second goal)
-// * interpretation 
-// So it supports a typed virtual instruction set.
-
-type
-  TInstrKind = (
-    insNone,      // invalid instruction
-    insLabel,     // a label
-    insTemp,      
-    insGoto,      // a goto
-    insTjmp,
-    insFjmp, 
-    insBin,       // ordinary binary operator
-    insLast
-  
-  );
-  TInstr = record
-    Kind: TInstrKind;
-    
-  end;
-  
-  
diff --git a/nim/wordrecg.pas b/nim/wordrecg.pas
index da709a8f3..2849c1d05 100644
--- a/nim/wordrecg.pas
+++ b/nim/wordrecg.pas
@@ -47,8 +47,8 @@ type
     wMacro, wMethod, wMod, wNil, 
     wNot, wNotin, wObject, wOf, 
     wOr, wOut, wProc, wPtr, 
-    wRaise, wRecord, wRef, wReturn, 
-    wShl, wShr, wTemplate, wTry, 
+    wRaise, wRef, wReturn, wShl, 
+    wShr, wTemplate, wTry, wTuple, 
     wType, wVar, wWhen, wWhere, 
     wWhile, wWith, wWithout, wXor, 
     wYield, 
@@ -57,8 +57,8 @@ type
     wColon, wEquals, wDot, wDotDot, wHat,
     wStar, wMinus,
     // pragmas and command line options:
-    wMagic, wPrefix, wInfix, wPostfix, wAssign,
-    wIsnegationof, wImportc, wExportc, wAlign, wNodecl, wPure,
+    wMagic, wTypeCheck, wFinal, wPostfix,
+    wObjChecks, wImportc, wExportc, wAlign, wNodecl, wPure,
     wVolatile, wRegister, wNostatic, wHeader, wNosideeffect, wNoreturn,
     wLib, wDynlib, wReturnsnew, wCompilerproc, wCppmethod, wFatal,
     wError, wWarning, wHint, wLine, wPush, wPop,
@@ -76,12 +76,13 @@ type
     wL, wListcmd, wGendoc, wGenmapping,
     wOs, wCpu, wGenerate, wG, wC, wCpp,
     wYaml, wRun, wR, wVerbose, wV, wHelp,
-    wH, wCompilesys, wS, wX, wVersion, wAdvanced, wMergeoutput,
+    wH, wCompilesys, wFieldChecks, wX, wVersion, wAdvanced, wMergeoutput,
     wSkipcfg, wSkipProjCfg, wCc, wGenscript, wCheckPoint, wCheckPoints,
     wMaxErr, wExpr, wStmt, wTypeDesc,
     wAsmQuote, wAstCache, wCFileCache, wIndex,
     // commands:
-    wCompileToC, wCompileToCpp, wPretty, wDoc, wPas,
+    wCompileToC, wCompileToCpp, wCompileToEcmaScript,
+    wPretty, wDoc, wPas,
     wGenDepend, wListDef, wCheck, wParse, wScan, wBoot, wDebugTrans,
     wRst2html,
     // special for the preprocessor of configuration files:
@@ -92,7 +93,7 @@ type
     wExports, wFinalization, wFunction, wGoto,
     wImplementation, wInherited, wInitialization, wInterface,
     wLabel, wLibrary, wPacked,
-    wProcedure, wProgram, wProperty, wRepeat, wResourcestring,
+    wProcedure, wProgram, wProperty, wRecord, wRepeat, wResourcestring,
     wSet, wThen, wThreadvar, wTo, wUnit, wUntil,
     wUses,
     // Pascal special tokens:
@@ -120,8 +121,8 @@ const
     'macro', 'method', 'mod', 'nil', 
     'not', 'notin', 'object', 'of', 
     'or', 'out', 'proc', 'ptr', 
-    'raise', 'record', 'ref', 'return', 
-    'shl', 'shr', 'template', 'try', 
+    'raise', 'ref', 'return', 'shl', 
+    'shr', 'template', 'try', 'tuple', 
     'type', 'var', 'when', 'where', 
     'while', 'with', 'without', 'xor', 
     'yield', 
@@ -130,8 +131,8 @@ const
     ':'+'', '='+'', '.'+'', '..', '^'+'',
     '*'+'', '-'+'',
     // pragmas and command line options:
-    'magic', 'prefix', 'infix', 'postfix', 'assign',
-    'isnegationof', 'importc', 'exportc', 'align', 'nodecl', 'pure',
+    'magic', 'typecheck', 'final', 'postfix',
+    'objchecks', 'importc', 'exportc', 'align', 'nodecl', 'pure',
     'volatile', 'register', 'nostatic', 'header', 'nosideeffect', 'noreturn',
     'lib', 'dynlib', 'returnsnew', 'compilerproc', 'cppmethod', 'fatal',
     'error', 'warning', 'hint', 'line', 'push', 'pop',
@@ -149,14 +150,15 @@ const
     'l'+'', 'listcmd', 'gendoc', 'genmapping',
     'os', 'cpu', 'generate', 'g'+'', 'c'+'', 'cpp',
     'yaml', 'run', 'r'+'', 'verbose', 'v'+'', 'help',
-    'h'+'', 'compilesys', 's'+'', 'x'+'', 'version', 'advanced', 'mergeoutput',
+    'h'+'', 'compilesys', 'fieldchecks', 'x'+'', 'version', 'advanced',
+    'mergeoutput',
     'skipcfg', 'skipprojcfg', 'cc', 'genscript', 'checkpoint', 'checkpoints',
     'maxerr', 'expr', 'stmt', 'typedesc',
     'asmquote', 'astcache', 'cfilecache', 'index',
     // commands:
-    'compiletoc', 'compiletocpp', 'pretty', 'doc', 'pas',
-    'gendepend', 'listdef', 'check', 'parse', 'scan', 'boot', 'debugtrans',
-    'rst2html',
+    'compiletoc', 'compiletocpp', 'compiletoecmascript',
+    'pretty', 'doc', 'pas', 'gendepend', 'listdef', 'check', 'parse',
+    'scan', 'boot', 'debugtrans', 'rst2html',
 
     // special for the preprocessor of configuration files:
     'write', 'putenv', 'prependenv', 'appendenv',
@@ -166,7 +168,7 @@ const
     'exports', 'finalization', 'function', 'goto',
     'implementation', 'inherited', 'initialization', 'interface',
     'label', 'library', 'packed',
-    'procedure', 'program', 'property', 'repeat', 'resourcestring',
+    'procedure', 'program', 'property', 'record', 'repeat', 'resourcestring',
     'set', 'then', 'threadvar', 'to', 'unit', 'until',
     'uses',
 
diff --git a/nimrod.aip b/nimrod.aip
deleted file mode 100644
index 4d1439db4..000000000
--- a/nimrod.aip
+++ /dev/null
@@ -1,639 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

-<DOCUMENT type="Advanced Installer" CreateVersion="6.1" version="6.1" modules="freeware" RootPath="." Language="en">

-  <COMPONENT cid="caphyon.advinst.msicomp.MsiPropsComponent">

-    <ROW Property="ALLUSERS" Value="2"/>

-    <ROW Property="ARPCOMMENTS" Value="This installer database contains the logic and data required to install [|ProductName]." ValueLocId="*"/>

-    <ROW Property="BannerBitmap" Value="default_banner.bmp" Type="1"/>

-    <ROW Property="DialogBitmap" Value="default_dialog.bmp" Type="1"/>

-    <ROW Property="Manufacturer" Value="Nimrod Open Source Corp." ValueLocId="*"/>

-    <ROW Property="ProductCode" Value="1033:{C7A3075E-BA70-4C40-BC1E-A19C0BD58D9C} "/>

-    <ROW Property="ProductLanguage" Value="1033"/>

-    <ROW Property="ProductName" Value="Nimrod" ValueLocId="*"/>

-    <ROW Property="ProductVersion" Value="1.0.0"/>

-    <ROW Property="SecureCustomProperties" Value="OLDPRODUCTS;AI_NEWERPRODUCTFOUND"/>

-    <ROW Property="UpgradeCode" Value="{DE5FF820-F405-44B6-9653-F3F71BF71129}"/>

-  </COMPONENT>

-  <COMPONENT cid="caphyon.advinst.msicomp.MsiDirsComponent">

-    <ROW Directory="APPDIR" Directory_Parent="TARGETDIR" DefaultDir="APPDIR:." IsPseudoRoot="1"/>

-    <ROW Directory="SHORTCUTDIR" Directory_Parent="TARGETDIR" DefaultDir="SHORTC~1|SHORTCUTDIR" IsPseudoRoot="1"/>

-    <ROW Directory="TARGETDIR" DefaultDir="SourceDir"/>

-    <ROW Directory="base_1_DIR" Directory_Parent="lib_1_DIR" DefaultDir="base"/>

-    <ROW Directory="base_DIR" Directory_Parent="lib_DIR" DefaultDir="base"/>

-    <ROW Directory="bin_1_DIR" Directory_Parent="pristine_DIR" DefaultDir="bin"/>

-    <ROW Directory="bin_DIR" Directory_Parent="APPDIR" DefaultDir="bin"/>

-    <ROW Directory="config_1_DIR" Directory_Parent="pristine_DIR" DefaultDir="config"/>

-    <ROW Directory="config_DIR" Directory_Parent="APPDIR" DefaultDir="config"/>

-    <ROW Directory="darcs_DIR" Directory_Parent="APPDIR" DefaultDir="_darcs"/>

-    <ROW Directory="data_1_DIR" Directory_Parent="pristine_DIR" DefaultDir="data"/>

-    <ROW Directory="data_DIR" Directory_Parent="APPDIR" DefaultDir="data"/>

-    <ROW Directory="dist_1_DIR" Directory_Parent="APPDIR" DefaultDir="dist"/>

-    <ROW Directory="dist_DIR" Directory_Parent="pristine_DIR" DefaultDir="dist"/>

-    <ROW Directory="doc_1_DIR" Directory_Parent="pristine_DIR" DefaultDir="doc"/>

-    <ROW Directory="doc_DIR" Directory_Parent="APPDIR" DefaultDir="doc"/>

-    <ROW Directory="html_1_DIR" Directory_Parent="doc_1_DIR" DefaultDir="html"/>

-    <ROW Directory="html_DIR" Directory_Parent="doc_DIR" DefaultDir="html"/>

-    <ROW Directory="koch_1_DIR" Directory_Parent="pristine_DIR" DefaultDir="koch"/>

-    <ROW Directory="koch_DIR" Directory_Parent="APPDIR" DefaultDir="koch"/>

-    <ROW Directory="lib_1_DIR" Directory_Parent="pristine_DIR" DefaultDir="lib"/>

-    <ROW Directory="lib_DIR" Directory_Parent="APPDIR" DefaultDir="lib"/>

-    <ROW Directory="nim_1_DIR" Directory_Parent="pristine_DIR" DefaultDir="nim"/>

-    <ROW Directory="nim_DIR" Directory_Parent="APPDIR" DefaultDir="nim"/>

-    <ROW Directory="obj_1_DIR" Directory_Parent="pristine_DIR" DefaultDir="obj"/>

-    <ROW Directory="obj_DIR" Directory_Parent="APPDIR" DefaultDir="obj"/>

-    <ROW Directory="patches_DIR" Directory_Parent="darcs_DIR" DefaultDir="patches"/>

-    <ROW Directory="posix_1_DIR" Directory_Parent="lib_1_DIR" DefaultDir="posix"/>

-    <ROW Directory="posix_DIR" Directory_Parent="lib_DIR" DefaultDir="posix"/>

-    <ROW Directory="prefs_DIR" Directory_Parent="darcs_DIR" DefaultDir="prefs"/>

-    <ROW Directory="pristine_DIR" Directory_Parent="darcs_DIR" DefaultDir="pristine"/>

-    <ROW Directory="rod_1_DIR" Directory_Parent="pristine_DIR" DefaultDir="rod"/>

-    <ROW Directory="rod_DIR" Directory_Parent="APPDIR" DefaultDir="rod"/>

-    <ROW Directory="style_1_DIR" Directory_Parent="web_1_DIR" DefaultDir="style"/>

-    <ROW Directory="style_DIR" Directory_Parent="web_DIR" DefaultDir="style"/>

-    <ROW Directory="web_1_DIR" Directory_Parent="pristine_DIR" DefaultDir="web"/>

-    <ROW Directory="web_DIR" Directory_Parent="APPDIR" DefaultDir="web"/>

-    <ROW Directory="windows_1_DIR" Directory_Parent="lib_1_DIR" DefaultDir="windows"/>

-    <ROW Directory="windows_DIR" Directory_Parent="lib_DIR" DefaultDir="windows"/>

-  </COMPONENT>

-  <COMPONENT cid="caphyon.advinst.msicomp.MsiCompsComponent">

-    <ROW Component="New_Value" ComponentId="{E0A1624D-3910-4F4F-A5C4-3001849D9FFB}" Directory_="APPDIR" Attributes="4" KeyPath="New_Value" FullKeyPath="HK_UM\Software\[Manufacturer]\[ProductName]\AppPath"/>

-    <ROW Component="SHORTCUTDIR" ComponentId="{9BF01AB4-3574-4F5E-8781-BCF3A3DE0935}" Directory_="SHORTCUTDIR" Attributes="0"/>

-    <ROW Component="a8_01cde1f1fa5331e5489db1d7905c55b6376a54a6.gz" ComponentId="{38D88DDF-1407-49F6-AFD1-C5AA44388389}" Directory_="patches_DIR" Attributes="0" KeyPath="a8_01cde1f1fa5331e5489db1d7905c55b6376a54a6.gz" FullKeyPath="APPDIR\_darcs\patches"/>

-    <ROW Component="advopt.txt" ComponentId="{B2E72F57-176B-4C4B-A203-A184B923A4DE}" Directory_="data_DIR" Attributes="0" KeyPath="advopt.txt" FullKeyPath="APPDIR\data"/>

-    <ROW Component="amd64.asm.in" ComponentId="{9FCD6047-C378-414B-A6E5-A0F99F065D45}" Directory_="lib_1_DIR" Attributes="0" KeyPath="amd64.asm.in_1" FullKeyPath="APPDIR\_darcs\pristine\lib"/>

-    <ROW Component="back.png" ComponentId="{AB2ECAA6-A015-4267-A60E-90157DF3DA86}" Directory_="style_1_DIR" Attributes="0" KeyPath="back.png_1" FullKeyPath="APPDIR\_darcs\pristine\web\style"/>

-    <ROW Component="boring" ComponentId="{A6D5EB86-D153-42F8-B314-E745B909327B}" Directory_="prefs_DIR" Attributes="0" KeyPath="boring" FullKeyPath="APPDIR\_darcs\prefs"/>

-    <ROW Component="ccomps.txt" ComponentId="{2738CBBE-97AD-4B37-AC78-C36C20BFE45F}" Directory_="data_1_DIR" Attributes="0" KeyPath="ccomps.txt_1" FullKeyPath="APPDIR\_darcs\pristine\data"/>

-    <ROW Component="charsets.pas" ComponentId="{28CD86F0-3533-4BCE-A549-5FF8B3AE65BC}" Directory_="nim_1_DIR" Attributes="0" KeyPath="charsets.pas_1" FullKeyPath="APPDIR\_darcs\pristine\nim"/>

-    <ROW Component="charsets.txt" ComponentId="{ACFCF1CB-E4AF-485C-8661-C9B9A57FCF1E}" Directory_="doc_1_DIR" Attributes="0" KeyPath="charsets.txt_1" FullKeyPath="APPDIR\_darcs\pristine\doc"/>

-    <ROW Component="cog.py" ComponentId="{921E068E-D9E3-4204-B346-6595271DAF7C}" Directory_="pristine_DIR" Attributes="0" KeyPath="cog.py_1" FullKeyPath="APPDIR\_darcs\pristine"/>

-    <ROW Component="config.inc" ComponentId="{C2F80900-64F8-4BF0-A792-C5A8954967DB}" Directory_="nim_DIR" Attributes="0" KeyPath="config.inc" FullKeyPath="APPDIR\nim"/>

-    <ROW Component="configure" ComponentId="{38FDAE22-F37B-40EB-8472-4F9A3EB333C4}" Directory_="APPDIR" Attributes="0" KeyPath="configure" FullKeyPath="APPDIR"/>

-    <ROW Component="dlmalloc.h" ComponentId="{B42F637B-2DF4-4F66-BFB9-BC247D7B3F39}" Directory_="lib_DIR" Attributes="0" KeyPath="dlmalloc.h" FullKeyPath="APPDIR\lib"/>

-    <ROW Component="doctempl.cfg" ComponentId="{ADC4B245-0967-483D-9DB2-B46D3FD38E1D}" Directory_="config_DIR" Attributes="0" KeyPath="doctempl.cfg" FullKeyPath="APPDIR\config"/>

-    <ROW Component="doctempl.cfg_1" ComponentId="{980CE23D-0544-427A-9E3D-502C63090244}" Directory_="config_1_DIR" Attributes="0" KeyPath="doctempl.cfg_1" FullKeyPath="APPDIR\_darcs\pristine\config"/>

-    <ROW Component="documentation.txt" ComponentId="{A8A16517-C1D0-45EB-86E3-97EDC7474955}" Directory_="web_1_DIR" Attributes="0" KeyPath="documentation.txt_1" FullKeyPath="APPDIR\_darcs\pristine\web"/>

-    <ROW Component="empty.txt" ComponentId="{E724D6D6-B900-4ACF-9342-952800C1AB30}" Directory_="html_DIR" Attributes="0" KeyPath="empty.txt" FullKeyPath="APPDIR\doc\html"/>

-    <ROW Component="empty.txt_1" ComponentId="{F2D191EF-6BC2-4036-9398-4A69D90250F8}" Directory_="bin_DIR" Attributes="0" KeyPath="empty.txt_1" FullKeyPath="APPDIR\bin"/>

-    <ROW Component="empty.txt_2" ComponentId="{CC32A642-1A55-4FB8-8C5E-200384EC9495}" Directory_="windows_DIR" Attributes="0" KeyPath="empty.txt_2" FullKeyPath="APPDIR\lib\windows"/>

-    <ROW Component="empty.txt_3" ComponentId="{52E17D83-0E10-44BB-AD10-F3E775E0B13B}" Directory_="obj_DIR" Attributes="0" KeyPath="empty.txt_3" FullKeyPath="APPDIR\obj"/>

-    <ROW Component="empty.txt_4" ComponentId="{E1358394-6021-4EF4-BB36-09958EDD0677}" Directory_="bin_1_DIR" Attributes="0" KeyPath="empty.txt_4" FullKeyPath="APPDIR\_darcs\pristine\bin"/>

-    <ROW Component="empty.txt_5" ComponentId="{581B8F55-37D6-41CF-8533-A3DA5EDCBF79}" Directory_="html_1_DIR" Attributes="0" KeyPath="empty.txt_5" FullKeyPath="APPDIR\_darcs\pristine\doc\html"/>

-    <ROW Component="empty.txt_6" ComponentId="{E133FE98-8008-49A1-9301-F30ACCF60713}" Directory_="windows_1_DIR" Attributes="0" KeyPath="empty.txt_6" FullKeyPath="APPDIR\_darcs\pristine\lib\windows"/>

-    <ROW Component="empty.txt_7" ComponentId="{78A65849-4CDE-4834-8F64-77BEFD51340E}" Directory_="obj_1_DIR" Attributes="0" KeyPath="empty.txt_7" FullKeyPath="APPDIR\_darcs\pristine\obj"/>

-    <ROW Component="empty.txt_8" ComponentId="{4947B227-08BF-4201-8E0A-AE3723ED948C}" Directory_="dist_DIR" Attributes="0" KeyPath="empty.txt_8" FullKeyPath="APPDIR\_darcs\pristine\dist"/>

-    <ROW Component="empty.txt_9" ComponentId="{EEC30761-18E0-4F88-8770-DDF971F94E37}" Directory_="dist_1_DIR" Attributes="0" KeyPath="empty.txt_9" FullKeyPath="APPDIR\dist"/>

-    <ROW Component="genweb.py" ComponentId="{E32EF054-4048-4C1C-A87C-6D6B394047F9}" Directory_="web_DIR" Attributes="0" KeyPath="genweb.py" FullKeyPath="APPDIR\web"/>

-    <ROW Component="graphic.jpg" ComponentId="{AA7F0506-4E81-47F4-9D52-CE32FAAF3BD9}" Directory_="style_DIR" Attributes="0" KeyPath="graphic.jpg" FullKeyPath="APPDIR\web\style"/>

-    <ROW Component="inventory" ComponentId="{F14C8A23-B801-4C16-B4BA-FD0A9565F21E}" Directory_="darcs_DIR" Attributes="0" KeyPath="inventory" FullKeyPath="APPDIR\_darcs"/>

-    <ROW Component="koch.ico" ComponentId="{25BE9B5A-653A-41CB-85C4-1A24155560E5}" Directory_="koch_DIR" Attributes="0" KeyPath="koch.ico" FullKeyPath="APPDIR\koch"/>

-    <ROW Component="koch.ico_1" ComponentId="{F028A653-C62E-4622-8E8B-20BF53442B95}" Directory_="koch_1_DIR" Attributes="0" KeyPath="koch.ico_1" FullKeyPath="APPDIR\_darcs\pristine\koch"/>

-    <ROW Component="nim.exe" ComponentId="{B354F2FB-0032-4B45-AE60-E0A478C0CD3A}" Directory_="bin_DIR" Attributes="0" KeyPath="nim.exe" FullKeyPath="APPDIR\bin\nim.exe"/>

-    <ROW Component="nimdoc.css" ComponentId="{550E15F6-9C44-4D9B-9989-D40FE2A554F9}" Directory_="doc_DIR" Attributes="0" KeyPath="nimdoc.css" FullKeyPath="APPDIR\doc"/>

-    <ROW Component="pcre.nim" ComponentId="{0C64A5CB-AA70-419F-B8C5-86E523520BC0}" Directory_="base_1_DIR" Attributes="0" KeyPath="pcre.nim_1" FullKeyPath="APPDIR\_darcs\pristine\lib\base"/>

-    <ROW Component="pcre_all.c" ComponentId="{35532080-9C0A-4C03-8692-0A2BA8360119}" Directory_="base_DIR" Attributes="0" KeyPath="pcre_all.c" FullKeyPath="APPDIR\lib\base"/>

-    <ROW Component="posix.nim" ComponentId="{8883E2F1-3D13-44B2-83A1-09F343DF59AB}" Directory_="posix_DIR" Attributes="0" KeyPath="posix.nim" FullKeyPath="APPDIR\lib\posix"/>

-    <ROW Component="posix.nim_1" ComponentId="{3B10CD45-5638-4F28-8E3D-EADCD6522562}" Directory_="posix_1_DIR" Attributes="0" KeyPath="posix.nim_1" FullKeyPath="APPDIR\_darcs\pristine\lib\posix"/>

-    <ROW Component="readme.txt" ComponentId="{605DB1E3-7102-4374-A9D2-3A87489CB215}" Directory_="rod_DIR" Attributes="0" KeyPath="readme.txt_3" FullKeyPath="APPDIR\rod"/>

-    <ROW Component="readme.txt_1" ComponentId="{4CE9D8A2-F874-4B87-A86F-8E8FF34E8EDE}" Directory_="rod_1_DIR" Attributes="0" KeyPath="readme.txt_8" FullKeyPath="APPDIR\_darcs\pristine\rod"/>

-  </COMPONENT>

-  <COMPONENT cid="caphyon.advinst.msicomp.MsiFeatsComponent">

-    <ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" Level="1" Directory_="APPDIR" Attributes="0" Components="nimdoc.css empty.txt koch.ico genweb.py graphic.jpg configure empty.txt_1 nim.exe doctempl.cfg advopt.txt dlmalloc.h empty.txt_2 posix.nim pcre_all.c empty.txt_3 config.inc readme.txt empty.txt_4 doctempl.cfg_1 ccomps.txt empty.txt_5 charsets.txt koch.ico_1 pcre.nim posix.nim_1 empty.txt_6 amd64.asm.in charsets.pas empty.txt_7 readme.txt_1 back.png documentation.txt cog.py empty.txt_8 a8_01cde1f1fa5331e5489db1d7905c55b6376a54a6.gz boring inventory empty.txt_9 SHORTCUTDIR New_Value"/>

-    <ATTRIBUTE name="CurrentFeature" value="MainFeature"/>

-  </COMPONENT>

-  <COMPONENT cid="caphyon.advinst.msicomp.MsiFilesComponent">

-    <ROW File="a8_01cde1f1fa5331e5489db1d7905c55b6376a54a6.gz" Component_="a8_01cde1f1fa5331e5489db1d7905c55b6376a54a6.gz" FileName="200801~1.gz|20080123010050-125a8-01cde1f1fa5331e5489db1d7905c55b6376a54a6.gz" Attributes="0" SourcePath="_darcs\patches\20080123010050-125a8-01cde1f1fa5331e5489db1d7905c55b6376a54a6.gz" SelfReg="false" Sequence="447"/>

-    <ROW File="a8_2d60ab7b41c42e1a59ba80373a70cc3bca0a001b.gz" Component_="a8_01cde1f1fa5331e5489db1d7905c55b6376a54a6.gz" FileName="200801~9.gz|20080123212849-125a8-2d60ab7b41c42e1a59ba80373a70cc3bca0a001b.gz" Attributes="0" SourcePath="_darcs\patches\20080123212849-125a8-2d60ab7b41c42e1a59ba80373a70cc3bca0a001b.gz" SelfReg="false" Sequence="455"/>

-    <ROW File="a8_4c2cc46743f2f6497208159db89419e46e0a4ee3.gz" Component_="a8_01cde1f1fa5331e5489db1d7905c55b6376a54a6.gz" FileName="200801~5.gz|20080123102409-125a8-4c2cc46743f2f6497208159db89419e46e0a4ee3.gz" Attributes="0" SourcePath="_darcs\patches\20080123102409-125a8-4c2cc46743f2f6497208159db89419e46e0a4ee3.gz" SelfReg="false" Sequence="451"/>

-    <ROW File="a8_4d7269c5e2d49de241e2cd93e6f13be8ffd2cab4.gz" Component_="a8_01cde1f1fa5331e5489db1d7905c55b6376a54a6.gz" FileName="200801~7.gz|20080123111343-125a8-4d7269c5e2d49de241e2cd93e6f13be8ffd2cab4.gz" Attributes="0" SourcePath="_darcs\patches\20080123111343-125a8-4d7269c5e2d49de241e2cd93e6f13be8ffd2cab4.gz" SelfReg="false" Sequence="453"/>

-    <ROW File="a8_53c09be8b4d3469a75adeccc12b2469da94b485d.gz" Component_="a8_01cde1f1fa5331e5489db1d7905c55b6376a54a6.gz" FileName="200801~6.gz|20080123103128-125a8-53c09be8b4d3469a75adeccc12b2469da94b485d.gz" Attributes="0" SourcePath="_darcs\patches\20080123103128-125a8-53c09be8b4d3469a75adeccc12b2469da94b485d.gz" SelfReg="false" Sequence="452"/>

-    <ROW File="a8_7036b391a085ece2cd0850b9bc45172cd91fb6a2.gz" Component_="a8_01cde1f1fa5331e5489db1d7905c55b6376a54a6.gz" FileName="20080~11.gz|20080125010833-125a8-7036b391a085ece2cd0850b9bc45172cd91fb6a2.gz" Attributes="0" SourcePath="_darcs\patches\20080125010833-125a8-7036b391a085ece2cd0850b9bc45172cd91fb6a2.gz" SelfReg="false" Sequence="457"/>

-    <ROW File="a8_72ed3709b8acc603994dc248a7d82d90dc200182.gz" Component_="a8_01cde1f1fa5331e5489db1d7905c55b6376a54a6.gz" FileName="200801~2.gz|20080123010501-125a8-72ed3709b8acc603994dc248a7d82d90dc200182.gz" Attributes="0" SourcePath="_darcs\patches\20080123010501-125a8-72ed3709b8acc603994dc248a7d82d90dc200182.gz" SelfReg="false" Sequence="448"/>

-    <ROW File="a8_9195dc6a56064748b2673a5b5e5ecb8b6c9b8b1c.gz" Component_="a8_01cde1f1fa5331e5489db1d7905c55b6376a54a6.gz" FileName="20080~10.gz|20080124001312-125a8-9195dc6a56064748b2673a5b5e5ecb8b6c9b8b1c.gz" Attributes="0" SourcePath="_darcs\patches\20080124001312-125a8-9195dc6a56064748b2673a5b5e5ecb8b6c9b8b1c.gz" SelfReg="false" Sequence="456"/>

-    <ROW File="a8_ac998eca3b521b07f95b29c0df17dd631adaa3ec.gz" Component_="a8_01cde1f1fa5331e5489db1d7905c55b6376a54a6.gz" FileName="200801~8.gz|20080123200632-125a8-ac998eca3b521b07f95b29c0df17dd631adaa3ec.gz" Attributes="0" SourcePath="_darcs\patches\20080123200632-125a8-ac998eca3b521b07f95b29c0df17dd631adaa3ec.gz" SelfReg="false" Sequence="454"/>

-    <ROW File="a8_c9559cbdc5fae7db42e46469de5db0cbcc7455af.gz" Component_="a8_01cde1f1fa5331e5489db1d7905c55b6376a54a6.gz" FileName="200801~4.gz|20080123101954-125a8-c9559cbdc5fae7db42e46469de5db0cbcc7455af.gz" Attributes="0" SourcePath="_darcs\patches\20080123101954-125a8-c9559cbdc5fae7db42e46469de5db0cbcc7455af.gz" SelfReg="false" Sequence="450"/>

-    <ROW File="a8_f8aa72f3ee66cf7f43d90e5f26735ec21f32da18.gz" Component_="a8_01cde1f1fa5331e5489db1d7905c55b6376a54a6.gz" FileName="200801~3.gz|20080123101839-125a8-f8aa72f3ee66cf7f43d90e5f26735ec21f32da18.gz" Attributes="0" SourcePath="_darcs\patches\20080123101839-125a8-f8aa72f3ee66cf7f43d90e5f26735ec21f32da18.gz" SelfReg="false" Sequence="449"/>

-    <ROW File="advopt.txt" Component_="advopt.txt" FileName="advopt.txt" Attributes="0" SourcePath="data\advopt.txt" SelfReg="false" Sequence="57"/>

-    <ROW File="advopt.txt_1" Component_="ccomps.txt" FileName="advopt.txt" Attributes="0" SourcePath="_darcs\pristine\data\advopt.txt" SelfReg="false" Sequence="276"/>

-    <ROW File="amd64.asm.in" Component_="dlmalloc.h" FileName="amd64a~1.in|amd64.asm.in" Attributes="0" SourcePath="lib\amd64.asm.in" SelfReg="false" Sequence="71"/>

-    <ROW File="amd64.asm.in_1" Component_="amd64.asm.in" FileName="amd64a~1.in|amd64.asm.in" Attributes="0" SourcePath="_darcs\pristine\lib\amd64.asm.in" SelfReg="false" Sequence="311"/>

-    <ROW File="ansi_c.nim" Component_="dlmalloc.h" FileName="ansi_c.nim" Attributes="0" SourcePath="lib\ansi_c.nim" SelfReg="false" Sequence="74"/>

-    <ROW File="ansi_c.nim_1" Component_="amd64.asm.in" FileName="ansi_c.nim" Attributes="0" SourcePath="_darcs\pristine\lib\ansi_c.nim" SelfReg="false" Sequence="312"/>

-    <ROW File="arithm.nim" Component_="dlmalloc.h" FileName="arithm.nim" Attributes="0" SourcePath="lib\arithm.nim" SelfReg="false" Sequence="75"/>

-    <ROW File="arithm.nim_1" Component_="amd64.asm.in" FileName="arithm.nim" Attributes="0" SourcePath="_darcs\pristine\lib\arithm.nim" SelfReg="false" Sequence="313"/>

-    <ROW File="assign.nim" Component_="dlmalloc.h" FileName="assign.nim" Attributes="0" SourcePath="lib\assign.nim" SelfReg="false" Sequence="76"/>

-    <ROW File="assign.nim_1" Component_="amd64.asm.in" FileName="assign.nim" Attributes="0" SourcePath="_darcs\pristine\lib\assign.nim" SelfReg="false" Sequence="314"/>

-    <ROW File="ast.nim" Component_="readme.txt" FileName="ast.nim" Attributes="0" SourcePath="rod\ast.nim" SelfReg="false" Sequence="264"/>

-    <ROW File="ast.o" Component_="empty.txt_3" FileName="ast.o" Attributes="0" SourcePath="obj\ast.o" SelfReg="false" Sequence="135"/>

-    <ROW File="ast.pas" Component_="config.inc" FileName="ast.pas" Attributes="0" SourcePath="nim\ast.pas" SelfReg="false" Sequence="171"/>

-    <ROW File="ast.pas_1" Component_="charsets.pas" FileName="ast.pas" Attributes="0" SourcePath="_darcs\pristine\nim\ast.pas" SelfReg="false" Sequence="401"/>

-    <ROW File="ast.ppu" Component_="empty.txt_3" FileName="ast.ppu" Attributes="0" SourcePath="obj\ast.ppu" SelfReg="false" Sequence="136"/>

-    <ROW File="ast.rod" Component_="config.inc" FileName="ast.rod" Attributes="0" SourcePath="nim\ast.rod" SelfReg="false" Sequence="250"/>

-    <ROW File="astalgo.nim" Component_="readme.txt" FileName="astalgo.nim" Attributes="0" SourcePath="rod\astalgo.nim" SelfReg="false" Sequence="267"/>

-    <ROW File="astalgo.o" Component_="empty.txt_3" FileName="astalgo.o" Attributes="0" SourcePath="obj\astalgo.o" SelfReg="false" Sequence="137"/>

-    <ROW File="astalgo.pas" Component_="config.inc" FileName="astalgo.pas" Attributes="0" SourcePath="nim\astalgo.pas" SelfReg="false" Sequence="172"/>

-    <ROW File="astalgo.pas_1" Component_="charsets.pas" FileName="astalgo.pas" Attributes="0" SourcePath="_darcs\pristine\nim\astalgo.pas" SelfReg="false" Sequence="409"/>

-    <ROW File="astalgo.ppu" Component_="empty.txt_3" FileName="astalgo.ppu" Attributes="0" SourcePath="obj\astalgo.ppu" SelfReg="false" Sequence="138"/>

-    <ROW File="astalgo.rod" Component_="config.inc" FileName="astalgo.rod" Attributes="0" SourcePath="nim\astalgo.rod" SelfReg="false" Sequence="253"/>

-    <ROW File="author" Component_="boring" FileName="author" Attributes="0" SourcePath="_darcs\prefs\author" SelfReg="false" Sequence="462"/>

-    <ROW File="back.png" Component_="graphic.jpg" FileName="back.png" Attributes="0" SourcePath="web\style\back.png" SelfReg="false" Sequence="35"/>

-    <ROW File="back.png_1" Component_="back.png" FileName="back.png" Attributes="0" SourcePath="_darcs\pristine\web\style\back.png" SelfReg="false" Sequence="418"/>

-    <ROW File="basicopt.txt" Component_="advopt.txt" FileName="basicopt.txt" Attributes="0" SourcePath="data\basicopt.txt" SelfReg="false" Sequence="58"/>

-    <ROW File="basicopt.txt_1" Component_="ccomps.txt" FileName="basicopt.txt" Attributes="0" SourcePath="_darcs\pristine\data\basicopt.txt" SelfReg="false" Sequence="277"/>

-    <ROW File="bignums.pas" Component_="config.inc" FileName="bignums.pas" Attributes="0" SourcePath="nim\bignums.pas" SelfReg="false" Sequence="173"/>

-    <ROW File="bignums.pas_1" Component_="charsets.pas" FileName="bignums.pas" Attributes="0" SourcePath="_darcs\pristine\nim\bignums.pas" SelfReg="false" Sequence="410"/>

-    <ROW File="binaries" Component_="boring" FileName="binaries" Attributes="0" SourcePath="_darcs\prefs\binaries" SelfReg="false" Sequence="460"/>

-    <ROW File="bitsets.pas" Component_="config.inc" FileName="bitsets.pas" Attributes="0" SourcePath="nim\bitsets.pas" SelfReg="false" Sequence="174"/>

-    <ROW File="bitsets.pas_1" Component_="charsets.pas" FileName="bitsets.pas" Attributes="0" SourcePath="_darcs\pristine\nim\bitsets.pas" SelfReg="false" Sequence="411"/>

-    <ROW File="boring" Component_="boring" FileName="boring" Attributes="0" SourcePath="_darcs\prefs\boring" SelfReg="false" Sequence="459"/>

-    <ROW File="ccgexprs.pas" Component_="config.inc" FileName="ccgexprs.pas" Attributes="0" SourcePath="nim\ccgexprs.pas" SelfReg="false" Sequence="207"/>

-    <ROW File="ccgexprs.pas_1" Component_="charsets.pas" FileName="ccgexprs.pas" Attributes="0" SourcePath="_darcs\pristine\nim\ccgexprs.pas" SelfReg="false" Sequence="412"/>

-    <ROW File="ccgstmts.pas" Component_="config.inc" FileName="ccgstmts.pas" Attributes="0" SourcePath="nim\ccgstmts.pas" SelfReg="false" Sequence="208"/>

-    <ROW File="ccgstmts.pas_1" Component_="charsets.pas" FileName="ccgstmts.pas" Attributes="0" SourcePath="_darcs\pristine\nim\ccgstmts.pas" SelfReg="false" Sequence="413"/>

-    <ROW File="ccgtypes.pas" Component_="config.inc" FileName="ccgtypes.pas" Attributes="0" SourcePath="nim\ccgtypes.pas" SelfReg="false" Sequence="209"/>

-    <ROW File="ccgtypes.pas_1" Component_="charsets.pas" FileName="ccgtypes.pas" Attributes="0" SourcePath="_darcs\pristine\nim\ccgtypes.pas" SelfReg="false" Sequence="414"/>

-    <ROW File="ccgutils.pas" Component_="config.inc" FileName="ccgutils.pas" Attributes="0" SourcePath="nim\ccgutils.pas" SelfReg="false" Sequence="175"/>

-    <ROW File="ccgutils.pas_1" Component_="charsets.pas" FileName="ccgutils.pas" Attributes="0" SourcePath="_darcs\pristine\nim\ccgutils.pas" SelfReg="false" Sequence="415"/>

-    <ROW File="ccomps.txt" Component_="advopt.txt" FileName="ccomps.txt" Attributes="0" SourcePath="data\ccomps.txt" SelfReg="false" Sequence="59"/>

-    <ROW File="ccomps.txt_1" Component_="ccomps.txt" FileName="ccomps.txt" Attributes="0" SourcePath="_darcs\pristine\data\ccomps.txt" SelfReg="false" Sequence="274"/>

-    <ROW File="cgen.pas" Component_="config.inc" FileName="cgen.pas" Attributes="0" SourcePath="nim\cgen.pas" SelfReg="false" Sequence="186"/>

-    <ROW File="cgen.pas_1" Component_="charsets.pas" FileName="cgen.pas" Attributes="0" SourcePath="_darcs\pristine\nim\cgen.pas" SelfReg="false" Sequence="346"/>

-    <ROW File="changes.txt" Component_="advopt.txt" FileName="changes.txt" Attributes="0" SourcePath="data\changes.txt" SelfReg="false" Sequence="60"/>

-    <ROW File="changes.txt_1" Component_="ccomps.txt" FileName="changes.txt" Attributes="0" SourcePath="_darcs\pristine\data\changes.txt" SelfReg="false" Sequence="278"/>

-    <ROW File="charsets.o" Component_="empty.txt_3" FileName="charsets.o" Attributes="0" SourcePath="obj\charsets.o" SelfReg="false" Sequence="109"/>

-    <ROW File="charsets.pas" Component_="config.inc" FileName="charsets.pas" Attributes="0" SourcePath="nim\charsets.pas" SelfReg="false" Sequence="176"/>

-    <ROW File="charsets.pas_1" Component_="charsets.pas" FileName="charsets.pas" Attributes="0" SourcePath="_darcs\pristine\nim\charsets.pas" SelfReg="false" Sequence="344"/>

-    <ROW File="charsets.ppu" Component_="empty.txt_3" FileName="charsets.ppu" Attributes="0" SourcePath="obj\charsets.ppu" SelfReg="false" Sequence="110"/>

-    <ROW File="charsets.txt" Component_="nimdoc.css" FileName="charsets.txt" Attributes="0" SourcePath="doc\charsets.txt" SelfReg="false" Sequence="2"/>

-    <ROW File="charsets.txt_1" Component_="charsets.txt" FileName="charsets.txt" Attributes="0" SourcePath="_darcs\pristine\doc\charsets.txt" SelfReg="false" Sequence="284"/>

-    <ROW File="cntbits.nim" Component_="dlmalloc.h" FileName="cntbits.nim" Attributes="0" SourcePath="lib\cntbits.nim" SelfReg="false" Sequence="77"/>

-    <ROW File="cntbits.nim_1" Component_="amd64.asm.in" FileName="cntbits.nim" Attributes="0" SourcePath="_darcs\pristine\lib\cntbits.nim" SelfReg="false" Sequence="315"/>

-    <ROW File="codegen.pas" Component_="config.inc" FileName="codegen.pas" Attributes="0" SourcePath="nim\codegen.pas" SelfReg="false" Sequence="177"/>

-    <ROW File="codegen.pas_1" Component_="charsets.pas" FileName="codegen.pas" Attributes="0" SourcePath="_darcs\pristine\nim\codegen.pas" SelfReg="false" Sequence="345"/>

-    <ROW File="cog.py" Component_="configure" FileName="cog.py" Attributes="0" SourcePath="cog.py" SelfReg="false" Sequence="47"/>

-    <ROW File="cog.py_1" Component_="cog.py" FileName="cog.py" Attributes="0" SourcePath="_darcs\pristine\cog.py" SelfReg="false" Sequence="434"/>

-    <ROW File="commands.nim" Component_="readme.txt" FileName="commands.nim" Attributes="0" SourcePath="rod\commands.nim" SelfReg="false" Sequence="266"/>

-    <ROW File="commands.o" Component_="empty.txt_3" FileName="commands.o" Attributes="0" SourcePath="obj\commands.o" SelfReg="false" Sequence="151"/>

-    <ROW File="commands.pas" Component_="config.inc" FileName="commands.pas" Attributes="0" SourcePath="nim\commands.pas" SelfReg="false" Sequence="178"/>

-    <ROW File="commands.pas_1" Component_="charsets.pas" FileName="commands.pas" Attributes="0" SourcePath="_darcs\pristine\nim\commands.pas" SelfReg="false" Sequence="350"/>

-    <ROW File="commands.ppu" Component_="empty.txt_3" FileName="commands.ppu" Attributes="0" SourcePath="obj\commands.ppu" SelfReg="false" Sequence="152"/>

-    <ROW File="commands.rod" Component_="config.inc" FileName="commands.rod" Attributes="0" SourcePath="nim\commands.rod" SelfReg="false" Sequence="252"/>

-    <ROW File="complex.nim" Component_="dlmalloc.h" FileName="complex.nim" Attributes="0" SourcePath="lib\complex.nim" SelfReg="false" Sequence="78"/>

-    <ROW File="complex.nim_1" Component_="amd64.asm.in" FileName="complex.nim" Attributes="0" SourcePath="_darcs\pristine\lib\complex.nim" SelfReg="false" Sequence="316"/>

-    <ROW File="complex.txt" Component_="nimdoc.css" FileName="complex.txt" Attributes="0" SourcePath="doc\complex.txt" SelfReg="false" Sequence="3"/>

-    <ROW File="complex.txt_1" Component_="charsets.txt" FileName="complex.txt" Attributes="0" SourcePath="_darcs\pristine\doc\complex.txt" SelfReg="false" Sequence="285"/>

-    <ROW File="condsyms.o" Component_="empty.txt_3" FileName="condsyms.o" Attributes="0" SourcePath="obj\condsyms.o" SelfReg="false" Sequence="139"/>

-    <ROW File="condsyms.pas" Component_="config.inc" FileName="condsyms.pas" Attributes="0" SourcePath="nim\condsyms.pas" SelfReg="false" Sequence="179"/>

-    <ROW File="condsyms.pas_1" Component_="charsets.pas" FileName="condsyms.pas" Attributes="0" SourcePath="_darcs\pristine\nim\condsyms.pas" SelfReg="false" Sequence="351"/>

-    <ROW File="condsyms.ppu" Component_="empty.txt_3" FileName="condsyms.ppu" Attributes="0" SourcePath="obj\condsyms.ppu" SelfReg="false" Sequence="140"/>

-    <ROW File="config.inc" Component_="config.inc" FileName="config.inc" Attributes="0" SourcePath="nim\config.inc" SelfReg="false" Sequence="170"/>

-    <ROW File="config.inc_1" Component_="charsets.pas" FileName="config.inc" Attributes="0" SourcePath="_darcs\pristine\nim\config.inc" SelfReg="false" Sequence="403"/>

-    <ROW File="configure" Component_="configure" FileName="config~1|configure" Attributes="0" SourcePath="configure" SelfReg="false" Sequence="45"/>

-    <ROW File="configure_1" Component_="cog.py" FileName="config~1|configure" Attributes="0" SourcePath="_darcs\pristine\configure" SelfReg="false" Sequence="435"/>

-    <ROW File="copying.txt" Component_="dlmalloc.h" FileName="copying.txt" Attributes="0" SourcePath="lib\copying.txt" SelfReg="false" Sequence="69"/>

-    <ROW File="copying.txt_1" Component_="config.inc" FileName="copying.txt" Attributes="0" SourcePath="nim\copying.txt" SelfReg="false" Sequence="235"/>

-    <ROW File="copying.txt_2" Component_="amd64.asm.in" FileName="copying.txt" Attributes="0" SourcePath="_darcs\pristine\lib\copying.txt" SelfReg="false" Sequence="317"/>

-    <ROW File="copying.txt_3" Component_="charsets.pas" FileName="copying.txt" Attributes="0" SourcePath="_darcs\pristine\nim\copying.txt" SelfReg="false" Sequence="349"/>

-    <ROW File="crc.o" Component_="empty.txt_3" FileName="crc.o" Attributes="0" SourcePath="obj\crc.o" SelfReg="false" Sequence="127"/>

-    <ROW File="crc.pas" Component_="config.inc" FileName="crc.pas" Attributes="0" SourcePath="nim\crc.pas" SelfReg="false" Sequence="180"/>

-    <ROW File="crc.pas_1" Component_="charsets.pas" FileName="crc.pas" Attributes="0" SourcePath="_darcs\pristine\nim\crc.pas" SelfReg="false" Sequence="352"/>

-    <ROW File="crc.ppu" Component_="empty.txt_3" FileName="crc.ppu" Attributes="0" SourcePath="obj\crc.ppu" SelfReg="false" Sequence="128"/>

-    <ROW File="debugger.nim" Component_="dlmalloc.h" FileName="debugger.nim" Attributes="0" SourcePath="lib\debugger.nim" SelfReg="false" Sequence="79"/>

-    <ROW File="debugger.nim_1" Component_="amd64.asm.in" FileName="debugger.nim" Attributes="0" SourcePath="_darcs\pristine\lib\debugger.nim" SelfReg="false" Sequence="318"/>

-    <ROW File="dlmalloc.c" Component_="dlmalloc.h" FileName="dlmalloc.c" Attributes="0" SourcePath="lib\dlmalloc.c" SelfReg="false" Sequence="68"/>

-    <ROW File="dlmalloc.c_1" Component_="amd64.asm.in" FileName="dlmalloc.c" Attributes="0" SourcePath="_darcs\pristine\lib\dlmalloc.c" SelfReg="false" Sequence="319"/>

-    <ROW File="dlmalloc.h" Component_="dlmalloc.h" FileName="dlmalloc.h" Attributes="0" SourcePath="lib\dlmalloc.h" SelfReg="false" Sequence="66"/>

-    <ROW File="dlmalloc.h_1" Component_="amd64.asm.in" FileName="dlmalloc.h" Attributes="0" SourcePath="_darcs\pristine\lib\dlmalloc.h" SelfReg="false" Sequence="320"/>

-    <ROW File="docgen.pas" Component_="config.inc" FileName="docgen.pas" Attributes="0" SourcePath="nim\docgen.pas" SelfReg="false" Sequence="181"/>

-    <ROW File="docgen.pas_1" Component_="charsets.pas" FileName="docgen.pas" Attributes="0" SourcePath="_darcs\pristine\nim\docgen.pas" SelfReg="false" Sequence="353"/>

-    <ROW File="docmacro.py" Component_="configure" FileName="docmacro.py" Attributes="0" SourcePath="docmacro.py" SelfReg="false" Sequence="48"/>

-    <ROW File="docmacro.py_1" Component_="cog.py" FileName="docmacro.py" Attributes="0" SourcePath="_darcs\pristine\docmacro.py" SelfReg="false" Sequence="439"/>

-    <ROW File="docmacro.pyc" Component_="configure" FileName="docmacro.pyc" Attributes="0" SourcePath="docmacro.pyc" SelfReg="false" Sequence="467"/>

-    <ROW File="doctempl.cfg" Component_="doctempl.cfg" FileName="doctempl.cfg" Attributes="0" SourcePath="config\doctempl.cfg" SelfReg="false" Sequence="55"/>

-    <ROW File="doctempl.cfg_1" Component_="doctempl.cfg_1" FileName="doctempl.cfg" Attributes="0" SourcePath="_darcs\pristine\config\doctempl.cfg" SelfReg="false" Sequence="272"/>

-    <ROW File="documentation.html" Component_="genweb.py" FileName="docume~1.htm|documentation.html" Attributes="0" SourcePath="web\documentation.html" SelfReg="false" Sequence="42"/>

-    <ROW File="documentation.txt" Component_="genweb.py" FileName="docume~1.txt|documentation.txt" Attributes="0" SourcePath="web\documentation.txt" SelfReg="false" Sequence="26"/>

-    <ROW File="documentation.txt_1" Component_="documentation.txt" FileName="docume~1.txt|documentation.txt" Attributes="0" SourcePath="_darcs\pristine\web\documentation.txt" SelfReg="false" Sequence="426"/>

-    <ROW File="docutils.tmpl" Component_="genweb.py" FileName="docuti~1.tmp|docutils.tmpl" Attributes="0" SourcePath="web\docutils.tmpl" SelfReg="false" Sequence="31"/>

-    <ROW File="docutils.tmpl_1" Component_="documentation.txt" FileName="docuti~1.tmp|docutils.tmpl" Attributes="0" SourcePath="_darcs\pristine\web\docutils.tmpl" SelfReg="false" Sequence="427"/>

-    <ROW File="dos2unix.py" Component_="cog.py" FileName="dos2unix.py" Attributes="0" SourcePath="_darcs\pristine\dos2unix.py" SelfReg="false" Sequence="443"/>

-    <ROW File="dos2unix.py_1" Component_="configure" FileName="dos2unix.py" Attributes="0" SourcePath="dos2unix.py" SelfReg="false" Sequence="465"/>

-    <ROW File="download.html" Component_="genweb.py" FileName="downlo~1.htm|download.html" Attributes="0" SourcePath="web\download.html" SelfReg="false" Sequence="43"/>

-    <ROW File="download.txt" Component_="genweb.py" FileName="download.txt" Attributes="0" SourcePath="web\download.txt" SelfReg="false" Sequence="27"/>

-    <ROW File="download.txt_1" Component_="documentation.txt" FileName="download.txt" Attributes="0" SourcePath="_darcs\pristine\web\download.txt" SelfReg="false" Sequence="428"/>

-    <ROW File="dyncalls.nim" Component_="dlmalloc.h" FileName="dyncalls.nim" Attributes="0" SourcePath="lib\dyncalls.nim" SelfReg="false" Sequence="80"/>

-    <ROW File="dyncalls.nim_1" Component_="amd64.asm.in" FileName="dyncalls.nim" Attributes="0" SourcePath="_darcs\pristine\lib\dyncalls.nim" SelfReg="false" Sequence="321"/>

-    <ROW File="easygui.py" Component_="configure" FileName="easygui.py" Attributes="0" SourcePath="easygui.py" SelfReg="false" Sequence="49"/>

-    <ROW File="easygui.py_1" Component_="cog.py" FileName="easygui.py" Attributes="0" SourcePath="_darcs\pristine\easygui.py" SelfReg="false" Sequence="440"/>

-    <ROW File="empty.txt" Component_="empty.txt" FileName="empty.txt" Attributes="0" SourcePath="doc\html\empty.txt" SelfReg="false" Sequence="19"/>

-    <ROW File="empty.txt_1" Component_="empty.txt_1" FileName="empty.txt" Attributes="0" SourcePath="bin\empty.txt" SelfReg="false" Sequence="53"/>

-    <ROW File="empty.txt_2" Component_="empty.txt_2" FileName="empty.txt" Attributes="0" SourcePath="lib\windows\empty.txt" SelfReg="false" Sequence="99"/>

-    <ROW File="empty.txt_3" Component_="empty.txt_3" FileName="empty.txt" Attributes="0" SourcePath="obj\empty.txt" SelfReg="false" Sequence="104"/>

-    <ROW File="empty.txt_4" Component_="empty.txt_4" FileName="empty.txt" Attributes="0" SourcePath="_darcs\pristine\bin\empty.txt" SelfReg="false" Sequence="271"/>

-    <ROW File="empty.txt_5" Component_="empty.txt_5" FileName="empty.txt" Attributes="0" SourcePath="_darcs\pristine\doc\html\empty.txt" SelfReg="false" Sequence="283"/>

-    <ROW File="empty.txt_6" Component_="empty.txt_6" FileName="empty.txt" Attributes="0" SourcePath="_darcs\pristine\lib\windows\empty.txt" SelfReg="false" Sequence="310"/>

-    <ROW File="empty.txt_7" Component_="empty.txt_7" FileName="empty.txt" Attributes="0" SourcePath="_darcs\pristine\obj\empty.txt" SelfReg="false" Sequence="416"/>

-    <ROW File="empty.txt_8" Component_="empty.txt_8" FileName="empty.txt" Attributes="0" SourcePath="_darcs\pristine\dist\empty.txt" SelfReg="false" Sequence="445"/>

-    <ROW File="empty.txt_9" Component_="empty.txt_9" FileName="empty.txt" Attributes="0" SourcePath="dist\empty.txt" SelfReg="false" Sequence="466"/>

-    <ROW File="endb.txt" Component_="nimdoc.css" FileName="endb.txt" Attributes="0" SourcePath="doc\endb.txt" SelfReg="false" Sequence="5"/>

-    <ROW File="endb.txt_1" Component_="charsets.txt" FileName="endb.txt" Attributes="0" SourcePath="_darcs\pristine\doc\endb.txt" SelfReg="false" Sequence="286"/>

-    <ROW File="eval.pas" Component_="config.inc" FileName="eval.pas" Attributes="0" SourcePath="nim\eval.pas" SelfReg="false" Sequence="241"/>

-    <ROW File="eval.pas_1" Component_="charsets.pas" FileName="eval.pas" Attributes="0" SourcePath="_darcs\pristine\nim\eval.pas" SelfReg="false" Sequence="386"/>

-    <ROW File="excpt.nim" Component_="dlmalloc.h" FileName="excpt.nim" Attributes="0" SourcePath="lib\excpt.nim" SelfReg="false" Sequence="81"/>

-    <ROW File="excpt.nim_1" Component_="amd64.asm.in" FileName="excpt.nim" Attributes="0" SourcePath="_darcs\pristine\lib\excpt.nim" SelfReg="false" Sequence="322"/>

-    <ROW File="extccomp.o" Component_="empty.txt_3" FileName="extccomp.o" Attributes="0" SourcePath="obj\extccomp.o" SelfReg="false" Sequence="149"/>

-    <ROW File="extccomp.pas" Component_="config.inc" FileName="extccomp.pas" Attributes="0" SourcePath="nim\extccomp.pas" SelfReg="false" Sequence="182"/>

-    <ROW File="extccomp.pas_1" Component_="charsets.pas" FileName="extccomp.pas" Attributes="0" SourcePath="_darcs\pristine\nim\extccomp.pas" SelfReg="false" Sequence="347"/>

-    <ROW File="extccomp.ppu" Component_="empty.txt_3" FileName="extccomp.ppu" Attributes="0" SourcePath="obj\extccomp.ppu" SelfReg="false" Sequence="150"/>

-    <ROW File="filelist.txt" Component_="nimdoc.css" FileName="filelist.txt" Attributes="0" SourcePath="doc\filelist.txt" SelfReg="false" Sequence="6"/>

-    <ROW File="filelist.txt_1" Component_="charsets.txt" FileName="filelist.txt" Attributes="0" SourcePath="_darcs\pristine\doc\filelist.txt" SelfReg="false" Sequence="287"/>

-    <ROW File="gc.nim" Component_="dlmalloc.h" FileName="gc.nim" Attributes="0" SourcePath="lib\gc.nim" SelfReg="false" Sequence="82"/>

-    <ROW File="gc.nim_1" Component_="amd64.asm.in" FileName="gc.nim" Attributes="0" SourcePath="_darcs\pristine\lib\gc.nim" SelfReg="false" Sequence="323"/>

-    <ROW File="gc.pas" Component_="config.inc" FileName="gc.pas" Attributes="0" SourcePath="nim\gc.pas" SelfReg="false" Sequence="183"/>

-    <ROW File="gc.pas_1" Component_="charsets.pas" FileName="gc.pas" Attributes="0" SourcePath="_darcs\pristine\nim\gc.pas" SelfReg="false" Sequence="404"/>

-    <ROW File="gendot.pas" Component_="config.inc" FileName="gendot.pas" Attributes="0" SourcePath="nim\gendot.pas" SelfReg="false" Sequence="184"/>

-    <ROW File="gendot.pas_1" Component_="charsets.pas" FileName="gendot.pas" Attributes="0" SourcePath="_darcs\pristine\nim\gendot.pas" SelfReg="false" Sequence="348"/>

-    <ROW File="genhelp.pas" Component_="config.inc" FileName="genhelp.pas" Attributes="0" SourcePath="nim\genhelp.pas" SelfReg="false" Sequence="185"/>

-    <ROW File="genhelp.pas_1" Component_="charsets.pas" FileName="genhelp.pas" Attributes="0" SourcePath="_darcs\pristine\nim\genhelp.pas" SelfReg="false" Sequence="356"/>

-    <ROW File="genweb.py" Component_="genweb.py" FileName="genweb.py" Attributes="0" SourcePath="web\genweb.py" SelfReg="false" Sequence="25"/>

-    <ROW File="genweb.py_1" Component_="documentation.txt" FileName="genweb.py" Attributes="0" SourcePath="_darcs\pristine\web\genweb.py" SelfReg="false" Sequence="429"/>

-    <ROW File="gpl.html" Component_="config.inc" FileName="gpl~1.htm|gpl.html" Attributes="0" SourcePath="nim\gpl.html" SelfReg="false" Sequence="234"/>

-    <ROW File="gpl.html_1" Component_="charsets.pas" FileName="gpl~1.htm|gpl.html" Attributes="0" SourcePath="_darcs\pristine\nim\gpl.html" SelfReg="false" Sequence="405"/>

-    <ROW File="grammar.txt" Component_="nimdoc.css" FileName="grammar.txt" Attributes="0" SourcePath="doc\grammar.txt" SelfReg="false" Sequence="7"/>

-    <ROW File="grammar.txt_1" Component_="charsets.txt" FileName="grammar.txt" Attributes="0" SourcePath="_darcs\pristine\doc\grammar.txt" SelfReg="false" Sequence="288"/>

-    <ROW File="graphic.jpg" Component_="graphic.jpg" FileName="graphic.jpg" Attributes="0" SourcePath="web\style\graphic.jpg" SelfReg="false" Sequence="33"/>

-    <ROW File="graphic.jpg_1" Component_="back.png" FileName="graphic.jpg" Attributes="0" SourcePath="_darcs\pristine\web\style\graphic.jpg" SelfReg="false" Sequence="419"/>

-    <ROW File="hashes.o" Component_="empty.txt_3" FileName="hashes.o" Attributes="0" SourcePath="obj\hashes.o" SelfReg="false" Sequence="125"/>

-    <ROW File="hashes.pas" Component_="config.inc" FileName="hashes.pas" Attributes="0" SourcePath="nim\hashes.pas" SelfReg="false" Sequence="187"/>

-    <ROW File="hashes.pas_1" Component_="charsets.pas" FileName="hashes.pas" Attributes="0" SourcePath="_darcs\pristine\nim\hashes.pas" SelfReg="false" Sequence="357"/>

-    <ROW File="hashes.ppu" Component_="empty.txt_3" FileName="hashes.ppu" Attributes="0" SourcePath="obj\hashes.ppu" SelfReg="false" Sequence="126"/>

-    <ROW File="helptype.pas" Component_="config.inc" FileName="helptype.pas" Attributes="0" SourcePath="nim\helptype.pas" SelfReg="false" Sequence="188"/>

-    <ROW File="helptype.pas_1" Component_="charsets.pas" FileName="helptype.pas" Attributes="0" SourcePath="_darcs\pristine\nim\helptype.pas" SelfReg="false" Sequence="354"/>

-    <ROW File="hti.nim" Component_="dlmalloc.h" FileName="hti.nim" Attributes="0" SourcePath="lib\hti.nim" SelfReg="false" Sequence="83"/>

-    <ROW File="hti.nim_1" Component_="amd64.asm.in" FileName="hti.nim" Attributes="0" SourcePath="_darcs\pristine\lib\hti.nim" SelfReg="false" Sequence="324"/>

-    <ROW File="i386.asm.in" Component_="dlmalloc.h" FileName="i386as~1.in|i386.asm.in" Attributes="0" SourcePath="lib\i386.asm.in" SelfReg="false" Sequence="72"/>

-    <ROW File="i386.asm.in_1" Component_="amd64.asm.in" FileName="i386as~1.in|i386.asm.in" Attributes="0" SourcePath="_darcs\pristine\lib\i386.asm.in" SelfReg="false" Sequence="325"/>

-    <ROW File="idents.nim" Component_="readme.txt" FileName="idents.nim" Attributes="0" SourcePath="rod\idents.nim" SelfReg="false" Sequence="260"/>

-    <ROW File="idents.o" Component_="empty.txt_3" FileName="idents.o" Attributes="0" SourcePath="obj\idents.o" SelfReg="false" Sequence="133"/>

-    <ROW File="idents.pas" Component_="config.inc" FileName="idents.pas" Attributes="0" SourcePath="nim\idents.pas" SelfReg="false" Sequence="189"/>

-    <ROW File="idents.pas_1" Component_="charsets.pas" FileName="idents.pas" Attributes="0" SourcePath="_darcs\pristine\nim\idents.pas" SelfReg="false" Sequence="355"/>

-    <ROW File="idents.ppu" Component_="empty.txt_3" FileName="idents.ppu" Attributes="0" SourcePath="obj\idents.ppu" SelfReg="false" Sequence="134"/>

-    <ROW File="idents.rod" Component_="config.inc" FileName="idents.rod" Attributes="0" SourcePath="nim\idents.rod" SelfReg="false" Sequence="246"/>

-    <ROW File="ind.txt" Component_="nimdoc.css" FileName="ind.txt" Attributes="0" SourcePath="doc\ind.txt" SelfReg="false" Sequence="20"/>

-    <ROW File="ind.txt_1" Component_="charsets.txt" FileName="ind.txt" Attributes="0" SourcePath="_darcs\pristine\doc\ind.txt" SelfReg="false" Sequence="289"/>

-    <ROW File="index.html" Component_="genweb.py" FileName="index~1.htm|index.html" Attributes="0" SourcePath="web\index.html" SelfReg="false" Sequence="41"/>

-    <ROW File="index.html.in" Component_="nimdoc.css" FileName="indexh~1.in|index.html.in" Attributes="0" SourcePath="doc\index.html.in" SelfReg="false" Sequence="18"/>

-    <ROW File="index.html.in_1" Component_="charsets.txt" FileName="indexh~1.in|index.html.in" Attributes="0" SourcePath="_darcs\pristine\doc\index.html.in" SelfReg="false" Sequence="290"/>

-    <ROW File="index.txt" Component_="genweb.py" FileName="index.txt" Attributes="0" SourcePath="web\index.txt" SelfReg="false" Sequence="28"/>

-    <ROW File="index.txt_1" Component_="documentation.txt" FileName="index.txt" Attributes="0" SourcePath="_darcs\pristine\web\index.txt" SelfReg="false" Sequence="433"/>

-    <ROW File="inliner.pas" Component_="config.inc" FileName="inliner.pas" Attributes="0" SourcePath="nim\inliner.pas" SelfReg="false" Sequence="190"/>

-    <ROW File="inliner.pas_1" Component_="charsets.pas" FileName="inliner.pas" Attributes="0" SourcePath="_darcs\pristine\nim\inliner.pas" SelfReg="false" Sequence="360"/>

-    <ROW File="install.txt" Component_="configure" FileName="install.txt" Attributes="0" SourcePath="install.txt" SelfReg="false" Sequence="270"/>

-    <ROW File="install.txt_1" Component_="cog.py" FileName="install.txt" Attributes="0" SourcePath="_darcs\pristine\install.txt" SelfReg="false" Sequence="441"/>

-    <ROW File="instgen.pas" Component_="config.inc" FileName="instgen.pas" Attributes="0" SourcePath="nim\instgen.pas" SelfReg="false" Sequence="191"/>

-    <ROW File="instgen.pas_1" Component_="charsets.pas" FileName="instgen.pas" Attributes="0" SourcePath="_darcs\pristine\nim\instgen.pas" SelfReg="false" Sequence="361"/>

-    <ROW File="int64s.nim" Component_="dlmalloc.h" FileName="int64s.nim" Attributes="0" SourcePath="lib\int64s.nim" SelfReg="false" Sequence="84"/>

-    <ROW File="int64s.nim_1" Component_="amd64.asm.in" FileName="int64s.nim" Attributes="0" SourcePath="_darcs\pristine\lib\int64s.nim" SelfReg="false" Sequence="326"/>

-    <ROW File="intern.txt" Component_="nimdoc.css" FileName="intern.txt" Attributes="0" SourcePath="doc\intern.txt" SelfReg="false" Sequence="8"/>

-    <ROW File="intern.txt_1" Component_="charsets.txt" FileName="intern.txt" Attributes="0" SourcePath="_darcs\pristine\doc\intern.txt" SelfReg="false" Sequence="291"/>

-    <ROW File="interrno.txt" Component_="config.inc" FileName="interrno.txt" Attributes="0" SourcePath="nim\interrno.txt" SelfReg="false" Sequence="236"/>

-    <ROW File="interrno.txt_1" Component_="charsets.pas" FileName="interrno.txt" Attributes="0" SourcePath="_darcs\pristine\nim\interrno.txt" SelfReg="false" Sequence="358"/>

-    <ROW File="inventory" Component_="inventory" FileName="invent~1|inventory" Attributes="0" SourcePath="_darcs\inventory" SelfReg="false" Sequence="463"/>

-    <ROW File="io.nim" Component_="dlmalloc.h" FileName="io.nim" Attributes="0" SourcePath="lib\io.nim" SelfReg="false" Sequence="85"/>

-    <ROW File="io.nim_1" Component_="amd64.asm.in" FileName="io.nim" Attributes="0" SourcePath="_darcs\pristine\lib\io.nim" SelfReg="false" Sequence="327"/>

-    <ROW File="io.o" Component_="empty.txt_3" FileName="io.o" Attributes="0" SourcePath="obj\io.o" SelfReg="false" Sequence="119"/>

-    <ROW File="io.pas" Component_="config.inc" FileName="io.pas" Attributes="0" SourcePath="nim\io.pas" SelfReg="false" Sequence="192"/>

-    <ROW File="io.pas_1" Component_="charsets.pas" FileName="io.pas" Attributes="0" SourcePath="_darcs\pristine\nim\io.pas" SelfReg="false" Sequence="359"/>

-    <ROW File="io.ppu" Component_="empty.txt_3" FileName="io.ppu" Attributes="0" SourcePath="obj\io.ppu" SelfReg="false" Sequence="120"/>

-    <ROW File="itertype.pas" Component_="config.inc" FileName="itertype.pas" Attributes="0" SourcePath="nim\itertype.pas" SelfReg="false" Sequence="193"/>

-    <ROW File="itertype.pas_1" Component_="charsets.pas" FileName="itertype.pas" Attributes="0" SourcePath="_darcs\pristine\nim\itertype.pas" SelfReg="false" Sequence="365"/>

-    <ROW File="keywords.yml" Component_="advopt.txt" FileName="keywords.yml" Attributes="0" SourcePath="data\keywords.yml" SelfReg="false" Sequence="62"/>

-    <ROW File="keywords.yml_1" Component_="ccomps.txt" FileName="keywords.yml" Attributes="0" SourcePath="_darcs\pristine\data\keywords.yml" SelfReg="false" Sequence="279"/>

-    <ROW File="koch.dat" Component_="configure" FileName="koch.dat" Attributes="0" SourcePath="koch.dat" SelfReg="false" Sequence="468"/>

-    <ROW File="koch.ico" Component_="koch.ico" FileName="koch.ico" Attributes="0" SourcePath="koch\koch.ico" SelfReg="false" Sequence="21"/>

-    <ROW File="koch.ico_1" Component_="koch.ico_1" FileName="koch.ico" Attributes="0" SourcePath="_darcs\pristine\koch\koch.ico" SelfReg="false" Sequence="303"/>

-    <ROW File="koch.py" Component_="configure" FileName="koch.py" Attributes="0" SourcePath="koch.py" SelfReg="false" Sequence="50"/>

-    <ROW File="koch.py_1" Component_="cog.py" FileName="koch.py" Attributes="0" SourcePath="_darcs\pristine\koch.py" SelfReg="false" Sequence="446"/>

-    <ROW File="koch.pyc" Component_="configure" FileName="koch.pyc" Attributes="0" SourcePath="koch.pyc" SelfReg="false" Sequence="469"/>

-    <ROW File="koch.txt" Component_="koch.ico" FileName="koch.txt" Attributes="0" SourcePath="koch\koch.txt" SelfReg="false" Sequence="23"/>

-    <ROW File="koch.txt_1" Component_="koch.ico_1" FileName="koch.txt" Attributes="0" SourcePath="_darcs\pristine\koch\koch.txt" SelfReg="false" Sequence="304"/>

-    <ROW File="kochmod.py" Component_="koch.ico" FileName="kochmod.py" Attributes="0" SourcePath="koch\kochmod.py" SelfReg="false" Sequence="22"/>

-    <ROW File="kochmod.py_1" Component_="koch.ico_1" FileName="kochmod.py" Attributes="0" SourcePath="_darcs\pristine\koch\kochmod.py" SelfReg="false" Sequence="305"/>

-    <ROW File="kochmod.pyc" Component_="koch.ico" FileName="kochmod.pyc" Attributes="0" SourcePath="koch\kochmod.pyc" SelfReg="false" Sequence="24"/>

-    <ROW File="lexbase.o" Component_="empty.txt_3" FileName="lexbase.o" Attributes="0" SourcePath="obj\lexbase.o" SelfReg="false" Sequence="141"/>

-    <ROW File="lexbase.pas" Component_="config.inc" FileName="lexbase.pas" Attributes="0" SourcePath="nim\lexbase.pas" SelfReg="false" Sequence="194"/>

-    <ROW File="lexbase.pas_1" Component_="charsets.pas" FileName="lexbase.pas" Attributes="0" SourcePath="_darcs\pristine\nim\lexbase.pas" SelfReg="false" Sequence="364"/>

-    <ROW File="lexbase.ppu" Component_="empty.txt_3" FileName="lexbase.ppu" Attributes="0" SourcePath="obj\lexbase.ppu" SelfReg="false" Sequence="142"/>

-    <ROW File="lgpl.txt" Component_="dlmalloc.h" FileName="lgpl.txt" Attributes="0" SourcePath="lib\lgpl.txt" SelfReg="false" Sequence="70"/>

-    <ROW File="lgpl.txt_1" Component_="amd64.asm.in" FileName="lgpl.txt" Attributes="0" SourcePath="_darcs\pristine\lib\lgpl.txt" SelfReg="false" Sequence="328"/>

-    <ROW File="lib.txt" Component_="nimdoc.css" FileName="lib.txt" Attributes="0" SourcePath="doc\lib.txt" SelfReg="false" Sequence="9"/>

-    <ROW File="lib.txt_1" Component_="charsets.txt" FileName="lib.txt" Attributes="0" SourcePath="_darcs\pristine\doc\lib.txt" SelfReg="false" Sequence="292"/>

-    <ROW File="link.png" Component_="graphic.jpg" FileName="link.png" Attributes="0" SourcePath="web\style\link.png" SelfReg="false" Sequence="36"/>

-    <ROW File="link.png_1" Component_="back.png" FileName="link.png" Attributes="0" SourcePath="_darcs\pristine\web\style\link.png" SelfReg="false" Sequence="420"/>

-    <ROW File="links.html" Component_="genweb.py" FileName="links~1.htm|links.html" Attributes="0" SourcePath="web\links.html" SelfReg="false" Sequence="44"/>

-    <ROW File="links.txt" Component_="genweb.py" FileName="links.txt" Attributes="0" SourcePath="web\links.txt" SelfReg="false" Sequence="29"/>

-    <ROW File="links.txt_1" Component_="documentation.txt" FileName="links.txt" Attributes="0" SourcePath="_darcs\pristine\web\links.txt" SelfReg="false" Sequence="430"/>

-    <ROW File="lists.o" Component_="empty.txt_3" FileName="lists.o" Attributes="0" SourcePath="obj\lists.o" SelfReg="false" Sequence="115"/>

-    <ROW File="lists.pas" Component_="config.inc" FileName="lists.pas" Attributes="0" SourcePath="nim\lists.pas" SelfReg="false" Sequence="195"/>

-    <ROW File="lists.pas_1" Component_="charsets.pas" FileName="lists.pas" Attributes="0" SourcePath="_darcs\pristine\nim\lists.pas" SelfReg="false" Sequence="366"/>

-    <ROW File="lists.ppu" Component_="empty.txt_3" FileName="lists.ppu" Attributes="0" SourcePath="obj\lists.ppu" SelfReg="false" Sequence="116"/>

-    <ROW File="logo.jpg" Component_="graphic.jpg" FileName="logo.jpg" Attributes="0" SourcePath="web\style\logo.jpg" SelfReg="false" Sequence="34"/>

-    <ROW File="logo.jpg_1" Component_="back.png" FileName="logo.jpg" Attributes="0" SourcePath="_darcs\pristine\web\style\logo.jpg" SelfReg="false" Sequence="421"/>

-    <ROW File="lookup.pas" Component_="config.inc" FileName="lookup.pas" Attributes="0" SourcePath="nim\lookup.pas" SelfReg="false" Sequence="239"/>

-    <ROW File="lookup.pas_1" Component_="charsets.pas" FileName="lookup.pas" Attributes="0" SourcePath="_darcs\pristine\nim\lookup.pas" SelfReg="false" Sequence="367"/>

-    <ROW File="magic.yml" Component_="advopt.txt" FileName="magic.yml" Attributes="0" SourcePath="data\magic.yml" SelfReg="false" Sequence="63"/>

-    <ROW File="magic.yml_1" Component_="ccomps.txt" FileName="magic.yml" Attributes="0" SourcePath="_darcs\pristine\data\magic.yml" SelfReg="false" Sequence="275"/>

-    <ROW File="magicsys.pas" Component_="config.inc" FileName="magicsys.pas" Attributes="0" SourcePath="nim\magicsys.pas" SelfReg="false" Sequence="196"/>

-    <ROW File="magicsys.pas_1" Component_="charsets.pas" FileName="magicsys.pas" Attributes="0" SourcePath="_darcs\pristine\nim\magicsys.pas" SelfReg="false" Sequence="362"/>

-    <ROW File="makefile" Component_="configure" FileName="makefile" Attributes="0" SourcePath="makefile" SelfReg="false" Sequence="46"/>

-    <ROW File="makefile_1" Component_="cog.py" FileName="makefile" Attributes="0" SourcePath="_darcs\pristine\makefile" SelfReg="false" Sequence="436"/>

-    <ROW File="math.nim" Component_="dlmalloc.h" FileName="math.nim" Attributes="0" SourcePath="lib\math.nim" SelfReg="false" Sequence="86"/>

-    <ROW File="math.nim_1" Component_="amd64.asm.in" FileName="math.nim" Attributes="0" SourcePath="_darcs\pristine\lib\math.nim" SelfReg="false" Sequence="329"/>

-    <ROW File="memman.o" Component_="empty.txt_3" FileName="memman.o" Attributes="0" SourcePath="obj\memman.o" SelfReg="false" Sequence="107"/>

-    <ROW File="memman.pas" Component_="config.inc" FileName="memman.pas" Attributes="0" SourcePath="nim\memman.pas" SelfReg="false" Sequence="197"/>

-    <ROW File="memman.pas_1" Component_="charsets.pas" FileName="memman.pas" Attributes="0" SourcePath="_darcs\pristine\nim\memman.pas" SelfReg="false" Sequence="363"/>

-    <ROW File="memman.ppu" Component_="empty.txt_3" FileName="memman.ppu" Attributes="0" SourcePath="obj\memman.ppu" SelfReg="false" Sequence="108"/>

-    <ROW File="menu.png" Component_="graphic.jpg" FileName="menu.png" Attributes="0" SourcePath="web\style\menu.png" SelfReg="false" Sequence="37"/>

-    <ROW File="menu.png_1" Component_="back.png" FileName="menu.png" Attributes="0" SourcePath="_darcs\pristine\web\style\menu.png" SelfReg="false" Sequence="422"/>

-    <ROW File="menu_hover.png" Component_="graphic.jpg" FileName="menu_h~1.png|menu_hover.png" Attributes="0" SourcePath="web\style\menu_hover.png" SelfReg="false" Sequence="38"/>

-    <ROW File="menu_hover.png_1" Component_="back.png" FileName="menu_h~1.png|menu_hover.png" Attributes="0" SourcePath="_darcs\pristine\web\style\menu_hover.png" SelfReg="false" Sequence="423"/>

-    <ROW File="messages.yml" Component_="advopt.txt" FileName="messages.yml" Attributes="0" SourcePath="data\messages.yml" SelfReg="false" Sequence="64"/>

-    <ROW File="messages.yml_1" Component_="ccomps.txt" FileName="messages.yml" Attributes="0" SourcePath="_darcs\pristine\data\messages.yml" SelfReg="false" Sequence="280"/>

-    <ROW File="motd" Component_="boring" FileName="motd" Attributes="0" SourcePath="_darcs\prefs\motd" SelfReg="false" Sequence="461"/>

-    <ROW File="msgs.o" Component_="empty.txt_3" FileName="msgs.o" Attributes="0" SourcePath="obj\msgs.o" SelfReg="false" Sequence="121"/>

-    <ROW File="msgs.pas" Component_="config.inc" FileName="msgs.pas" Attributes="0" SourcePath="nim\msgs.pas" SelfReg="false" Sequence="203"/>

-    <ROW File="msgs.pas_1" Component_="charsets.pas" FileName="msgs.pas" Attributes="0" SourcePath="_darcs\pristine\nim\msgs.pas" SelfReg="false" Sequence="370"/>

-    <ROW File="msgs.ppu" Component_="empty.txt_3" FileName="msgs.ppu" Attributes="0" SourcePath="obj\msgs.ppu" SelfReg="false" Sequence="122"/>

-    <ROW File="news.txt" Component_="genweb.py" FileName="news.txt" Attributes="0" SourcePath="web\news.txt" SelfReg="false" Sequence="30"/>

-    <ROW File="news.txt_1" Component_="documentation.txt" FileName="news.txt" Attributes="0" SourcePath="_darcs\pristine\web\news.txt" SelfReg="false" Sequence="431"/>

-    <ROW File="nim.dpr" Component_="config.inc" FileName="nim.dpr" Attributes="0" SourcePath="nim\nim.dpr" SelfReg="false" Sequence="238"/>

-    <ROW File="nim.dpr_1" Component_="charsets.pas" FileName="nim.dpr" Attributes="0" SourcePath="_darcs\pristine\nim\nim.dpr" SelfReg="false" Sequence="406"/>

-    <ROW File="nim.exe" Component_="nim.exe" FileName="nim.exe" Attributes="0" SourcePath="bin\nim.exe" SelfReg="false" Sequence="54"/>

-    <ROW File="nim.o" Component_="empty.txt_3" FileName="nim.o" Attributes="0" SourcePath="obj\nim.o" SelfReg="false" Sequence="167"/>

-    <ROW File="nim.rod" Component_="config.inc" FileName="nim.rod" Attributes="0" SourcePath="nim\nim.rod" SelfReg="false" Sequence="254"/>

-    <ROW File="nimbase.h" Component_="dlmalloc.h" FileName="nimbase.h" Attributes="0" SourcePath="lib\nimbase.h" SelfReg="false" Sequence="67"/>

-    <ROW File="nimbase.h_1" Component_="amd64.asm.in" FileName="nimbase.h" Attributes="0" SourcePath="_darcs\pristine\lib\nimbase.h" SelfReg="false" Sequence="330"/>

-    <ROW File="nimconf.o" Component_="empty.txt_3" FileName="nimconf.o" Attributes="0" SourcePath="obj\nimconf.o" SelfReg="false" Sequence="147"/>

-    <ROW File="nimconf.pas" Component_="config.inc" FileName="nimconf.pas" Attributes="0" SourcePath="nim\nimconf.pas" SelfReg="false" Sequence="200"/>

-    <ROW File="nimconf.pas_1" Component_="charsets.pas" FileName="nimconf.pas" Attributes="0" SourcePath="_darcs\pristine\nim\nimconf.pas" SelfReg="false" Sequence="371"/>

-    <ROW File="nimconf.ppu" Component_="empty.txt_3" FileName="nimconf.ppu" Attributes="0" SourcePath="obj\nimconf.ppu" SelfReg="false" Sequence="148"/>

-    <ROW File="nimdoc.css" Component_="nimdoc.css" FileName="nimdoc.css" Attributes="0" SourcePath="doc\nimdoc.css" SelfReg="false" Sequence="1"/>

-    <ROW File="nimdoc.css_1" Component_="charsets.txt" FileName="nimdoc.css" Attributes="0" SourcePath="_darcs\pristine\doc\nimdoc.css" SelfReg="false" Sequence="293"/>

-    <ROW File="nimrod.cfg" Component_="doctempl.cfg" FileName="nimrod.cfg" Attributes="0" SourcePath="config\nimrod.cfg" SelfReg="false" Sequence="56"/>

-    <ROW File="nimrod.cfg_1" Component_="doctempl.cfg_1" FileName="nimrod.cfg" Attributes="0" SourcePath="_darcs\pristine\config\nimrod.cfg" SelfReg="false" Sequence="273"/>

-    <ROW File="nimrod.nim" Component_="readme.txt" FileName="nimrod.nim" Attributes="0" SourcePath="rod\nimrod.nim" SelfReg="false" Sequence="268"/>

-    <ROW File="nimrodc.txt" Component_="nimdoc.css" FileName="nimrodc.txt" Attributes="0" SourcePath="doc\nimrodc.txt" SelfReg="false" Sequence="4"/>

-    <ROW File="nimrodc.txt_1" Component_="charsets.txt" FileName="nimrodc.txt" Attributes="0" SourcePath="_darcs\pristine\doc\nimrodc.txt" SelfReg="false" Sequence="294"/>

-    <ROW File="nimsets.pas" Component_="config.inc" FileName="nimsets.pas" Attributes="0" SourcePath="nim\nimsets.pas" SelfReg="false" Sequence="201"/>

-    <ROW File="nimsets.pas_1" Component_="charsets.pas" FileName="nimsets.pas" Attributes="0" SourcePath="_darcs\pristine\nim\nimsets.pas" SelfReg="false" Sequence="372"/>

-    <ROW File="nimsys.nim" Component_="dlmalloc.h" FileName="nimsys.nim" Attributes="0" SourcePath="lib\nimsys.nim" SelfReg="false" Sequence="87"/>

-    <ROW File="nimsys.nim_1" Component_="amd64.asm.in" FileName="nimsys.nim" Attributes="0" SourcePath="_darcs\pristine\lib\nimsys.nim" SelfReg="false" Sequence="331"/>

-    <ROW File="nmath.pas" Component_="config.inc" FileName="nmath.pas" Attributes="0" SourcePath="nim\nmath.pas" SelfReg="false" Sequence="198"/>

-    <ROW File="nmath.pas_1" Component_="charsets.pas" FileName="nmath.pas" Attributes="0" SourcePath="_darcs\pristine\nim\nmath.pas" SelfReg="false" Sequence="373"/>

-    <ROW File="nos.o" Component_="empty.txt_3" FileName="nos.o" Attributes="0" SourcePath="obj\nos.o" SelfReg="false" Sequence="113"/>

-    <ROW File="nos.pas" Component_="config.inc" FileName="nos.pas" Attributes="0" SourcePath="nim\nos.pas" SelfReg="false" Sequence="202"/>

-    <ROW File="nos.pas_1" Component_="charsets.pas" FileName="nos.pas" Attributes="0" SourcePath="_darcs\pristine\nim\nos.pas" SelfReg="false" Sequence="374"/>

-    <ROW File="nos.ppu" Component_="empty.txt_3" FileName="nos.ppu" Attributes="0" SourcePath="obj\nos.ppu" SelfReg="false" Sequence="114"/>

-    <ROW File="nsystem.o" Component_="empty.txt_3" FileName="nsystem.o" Attributes="0" SourcePath="obj\nsystem.o" SelfReg="false" Sequence="105"/>

-    <ROW File="nsystem.pas" Component_="config.inc" FileName="nsystem.pas" Attributes="0" SourcePath="nim\nsystem.pas" SelfReg="false" Sequence="204"/>

-    <ROW File="nsystem.pas_1" Component_="charsets.pas" FileName="nsystem.pas" Attributes="0" SourcePath="_darcs\pristine\nim\nsystem.pas" SelfReg="false" Sequence="375"/>

-    <ROW File="nsystem.ppu" Component_="empty.txt_3" FileName="nsystem.ppu" Attributes="0" SourcePath="obj\nsystem.ppu" SelfReg="false" Sequence="106"/>

-    <ROW File="ntime.o" Component_="empty.txt_3" FileName="ntime.o" Attributes="0" SourcePath="obj\ntime.o" SelfReg="false" Sequence="168"/>

-    <ROW File="ntime.pas" Component_="config.inc" FileName="ntime.pas" Attributes="0" SourcePath="nim\ntime.pas" SelfReg="false" Sequence="205"/>

-    <ROW File="ntime.pas_1" Component_="charsets.pas" FileName="ntime.pas" Attributes="0" SourcePath="_darcs\pristine\nim\ntime.pas" SelfReg="false" Sequence="376"/>

-    <ROW File="ntime.ppu" Component_="empty.txt_3" FileName="ntime.ppu" Attributes="0" SourcePath="obj\ntime.ppu" SelfReg="false" Sequence="169"/>

-    <ROW File="nversion.o" Component_="empty.txt_3" FileName="nversion.o" Attributes="0" SourcePath="obj\nversion.o" SelfReg="false" Sequence="123"/>

-    <ROW File="nversion.pas" Component_="config.inc" FileName="nversion.pas" Attributes="0" SourcePath="nim\nversion.pas" SelfReg="false" Sequence="206"/>

-    <ROW File="nversion.pas_1" Component_="charsets.pas" FileName="nversion.pas" Attributes="0" SourcePath="_darcs\pristine\nim\nversion.pas" SelfReg="false" Sequence="397"/>

-    <ROW File="nversion.ppu" Component_="empty.txt_3" FileName="nversion.ppu" Attributes="0" SourcePath="obj\nversion.ppu" SelfReg="false" Sequence="124"/>

-    <ROW File="options.nim" Component_="readme.txt" FileName="options.nim" Attributes="0" SourcePath="rod\options.nim" SelfReg="false" Sequence="259"/>

-    <ROW File="options.o" Component_="empty.txt_3" FileName="options.o" Attributes="0" SourcePath="obj\options.o" SelfReg="false" Sequence="117"/>

-    <ROW File="options.pas" Component_="config.inc" FileName="options.pas" Attributes="0" SourcePath="nim\options.pas" SelfReg="false" Sequence="210"/>

-    <ROW File="options.pas_1" Component_="charsets.pas" FileName="options.pas" Attributes="0" SourcePath="_darcs\pristine\nim\options.pas" SelfReg="false" Sequence="369"/>

-    <ROW File="options.ppu" Component_="empty.txt_3" FileName="options.ppu" Attributes="0" SourcePath="obj\options.ppu" SelfReg="false" Sequence="118"/>

-    <ROW File="options.rod" Component_="config.inc" FileName="options.rod" Attributes="0" SourcePath="nim\options.rod" SelfReg="false" Sequence="245"/>

-    <ROW File="optparse.nim" Component_="dlmalloc.h" FileName="optparse.nim" Attributes="0" SourcePath="lib\optparse.nim" SelfReg="false" Sequence="88"/>

-    <ROW File="optparse.nim_1" Component_="amd64.asm.in" FileName="optparse.nim" Attributes="0" SourcePath="_darcs\pristine\lib\optparse.nim" SelfReg="false" Sequence="332"/>

-    <ROW File="os.nim" Component_="dlmalloc.h" FileName="os.nim" Attributes="0" SourcePath="lib\os.nim" SelfReg="false" Sequence="89"/>

-    <ROW File="os.nim_1" Component_="amd64.asm.in" FileName="os.nim" Attributes="0" SourcePath="_darcs\pristine\lib\os.nim" SelfReg="false" Sequence="333"/>

-    <ROW File="pas_keyw.yml" Component_="advopt.txt" FileName="pas_keyw.yml" Attributes="0" SourcePath="data\pas_keyw.yml" SelfReg="false" Sequence="65"/>

-    <ROW File="pas_keyw.yml_1" Component_="ccomps.txt" FileName="pas_keyw.yml" Attributes="0" SourcePath="_darcs\pristine\data\pas_keyw.yml" SelfReg="false" Sequence="281"/>

-    <ROW File="paslex.nim" Component_="readme.txt" FileName="paslex.nim" Attributes="0" SourcePath="rod\paslex.nim" SelfReg="false" Sequence="257"/>

-    <ROW File="paslex.o" Component_="empty.txt_3" FileName="paslex.o" Attributes="0" SourcePath="obj\paslex.o" SelfReg="false" Sequence="157"/>

-    <ROW File="paslex.pas" Component_="config.inc" FileName="paslex.pas" Attributes="0" SourcePath="nim\paslex.pas" SelfReg="false" Sequence="211"/>

-    <ROW File="paslex.pas_1" Component_="charsets.pas" FileName="paslex.pas" Attributes="0" SourcePath="_darcs\pristine\nim\paslex.pas" SelfReg="false" Sequence="379"/>

-    <ROW File="paslex.ppu" Component_="empty.txt_3" FileName="paslex.ppu" Attributes="0" SourcePath="obj\paslex.ppu" SelfReg="false" Sequence="158"/>

-    <ROW File="paslex.rod" Component_="config.inc" FileName="paslex.rod" Attributes="0" SourcePath="nim\paslex.rod" SelfReg="false" Sequence="243"/>

-    <ROW File="pasparse.nim" Component_="readme.txt" FileName="pasparse.nim" Attributes="0" SourcePath="rod\pasparse.nim" SelfReg="false" Sequence="256"/>

-    <ROW File="pasparse.o" Component_="empty.txt_3" FileName="pasparse.o" Attributes="0" SourcePath="obj\pasparse.o" SelfReg="false" Sequence="159"/>

-    <ROW File="pasparse.pas" Component_="config.inc" FileName="pasparse.pas" Attributes="0" SourcePath="nim\pasparse.pas" SelfReg="false" Sequence="212"/>

-    <ROW File="pasparse.pas_1" Component_="charsets.pas" FileName="pasparse.pas" Attributes="0" SourcePath="_darcs\pristine\nim\pasparse.pas" SelfReg="false" Sequence="377"/>

-    <ROW File="pasparse.ppu" Component_="empty.txt_3" FileName="pasparse.ppu" Attributes="0" SourcePath="obj\pasparse.ppu" SelfReg="false" Sequence="160"/>

-    <ROW File="pasparse.rod" Component_="config.inc" FileName="pasparse.rod" Attributes="0" SourcePath="nim\pasparse.rod" SelfReg="false" Sequence="242"/>

-    <ROW File="patmatch.pas" Component_="charsets.pas" FileName="patmatch.pas" Attributes="0" SourcePath="_darcs\pristine\nim\patmatch.pas" SelfReg="false" Sequence="378"/>

-    <ROW File="pcre.nim" Component_="pcre_all.c" FileName="pcre.nim" Attributes="0" SourcePath="lib\base\pcre.nim" SelfReg="false" Sequence="102"/>

-    <ROW File="pcre.nim_1" Component_="pcre.nim" FileName="pcre.nim" Attributes="0" SourcePath="_darcs\pristine\lib\base\pcre.nim" SelfReg="false" Sequence="306"/>

-    <ROW File="pcre_all.c" Component_="pcre_all.c" FileName="pcre_all.c" Attributes="0" SourcePath="lib\base\pcre_all.c" SelfReg="false" Sequence="101"/>

-    <ROW File="pcre_all.c_1" Component_="pcre.nim" FileName="pcre_all.c" Attributes="0" SourcePath="_darcs\pristine\lib\base\pcre_all.c" SelfReg="false" Sequence="307"/>

-    <ROW File="pending" Component_="a8_01cde1f1fa5331e5489db1d7905c55b6376a54a6.gz" FileName="pending" Attributes="0" SourcePath="_darcs\patches\pending" SelfReg="false" Sequence="458"/>

-    <ROW File="pipeline.o" Component_="empty.txt_3" FileName="pipeline.o" Attributes="0" SourcePath="obj\pipeline.o" SelfReg="false" Sequence="165"/>

-    <ROW File="pipeline.pas" Component_="config.inc" FileName="pipeline.pas" Attributes="0" SourcePath="nim\pipeline.pas" SelfReg="false" Sequence="214"/>

-    <ROW File="pipeline.pas_1" Component_="charsets.pas" FileName="pipeline.pas" Attributes="0" SourcePath="_darcs\pristine\nim\pipeline.pas" SelfReg="false" Sequence="383"/>

-    <ROW File="pipeline.ppu" Component_="empty.txt_3" FileName="pipeline.ppu" Attributes="0" SourcePath="obj\pipeline.ppu" SelfReg="false" Sequence="166"/>

-    <ROW File="platform.o" Component_="empty.txt_3" FileName="platform.o" Attributes="0" SourcePath="obj\platform.o" SelfReg="false" Sequence="129"/>

-    <ROW File="platform.pas" Component_="config.inc" FileName="platform.pas" Attributes="0" SourcePath="nim\platform.pas" SelfReg="false" Sequence="215"/>

-    <ROW File="platform.pas_1" Component_="charsets.pas" FileName="platform.pas" Attributes="0" SourcePath="_darcs\pristine\nim\platform.pas" SelfReg="false" Sequence="384"/>

-    <ROW File="platform.ppu" Component_="empty.txt_3" FileName="platform.ppu" Attributes="0" SourcePath="obj\platform.ppu" SelfReg="false" Sequence="130"/>

-    <ROW File="pnimsyn.nim" Component_="readme.txt" FileName="pnimsyn.nim" Attributes="0" SourcePath="rod\pnimsyn.nim" SelfReg="false" Sequence="263"/>

-    <ROW File="pnimsyn.o" Component_="empty.txt_3" FileName="pnimsyn.o" Attributes="0" SourcePath="obj\pnimsyn.o" SelfReg="false" Sequence="153"/>

-    <ROW File="pnimsyn.pas" Component_="config.inc" FileName="pnimsyn.pas" Attributes="0" SourcePath="nim\pnimsyn.pas" SelfReg="false" Sequence="218"/>

-    <ROW File="pnimsyn.pas_1" Component_="charsets.pas" FileName="pnimsyn.pas" Attributes="0" SourcePath="_darcs\pristine\nim\pnimsyn.pas" SelfReg="false" Sequence="382"/>

-    <ROW File="pnimsyn.ppu" Component_="empty.txt_3" FileName="pnimsyn.ppu" Attributes="0" SourcePath="obj\pnimsyn.ppu" SelfReg="false" Sequence="154"/>

-    <ROW File="pnimsyn.rod" Component_="config.inc" FileName="pnimsyn.rod" Attributes="0" SourcePath="nim\pnimsyn.rod" SelfReg="false" Sequence="249"/>

-    <ROW File="posix.nim" Component_="posix.nim" FileName="posix.nim" Attributes="0" SourcePath="lib\posix\posix.nim" SelfReg="false" Sequence="100"/>

-    <ROW File="posix.nim_1" Component_="posix.nim_1" FileName="posix.nim" Attributes="0" SourcePath="_darcs\pristine\lib\posix\posix.nim" SelfReg="false" Sequence="309"/>

-    <ROW File="posix.txt" Component_="nimdoc.css" FileName="posix.txt" Attributes="0" SourcePath="doc\posix.txt" SelfReg="false" Sequence="10"/>

-    <ROW File="posix.txt_1" Component_="charsets.txt" FileName="posix.txt" Attributes="0" SourcePath="_darcs\pristine\doc\posix.txt" SelfReg="false" Sequence="295"/>

-    <ROW File="powerpc.asm.in" Component_="dlmalloc.h" FileName="powerp~1.in|powerpc.asm.in" Attributes="0" SourcePath="lib\powerpc.asm.in" SelfReg="false" Sequence="73"/>

-    <ROW File="powerpc.asm.in_1" Component_="amd64.asm.in" FileName="powerp~1.in|powerpc.asm.in" Attributes="0" SourcePath="_darcs\pristine\lib\powerpc.asm.in" SelfReg="false" Sequence="334"/>

-    <ROW File="pragmas.pas" Component_="config.inc" FileName="pragmas.pas" Attributes="0" SourcePath="nim\pragmas.pas" SelfReg="false" Sequence="216"/>

-    <ROW File="pragmas.pas_1" Component_="charsets.pas" FileName="pragmas.pas" Attributes="0" SourcePath="_darcs\pristine\nim\pragmas.pas" SelfReg="false" Sequence="385"/>

-    <ROW File="process.nim" Component_="dlmalloc.h" FileName="process.nim" Attributes="0" SourcePath="lib\process.nim" SelfReg="false" Sequence="90"/>

-    <ROW File="process.nim_1" Component_="amd64.asm.in" FileName="process.nim" Attributes="0" SourcePath="_darcs\pristine\lib\process.nim" SelfReg="false" Sequence="335"/>

-    <ROW File="procfind.pas" Component_="config.inc" FileName="procfind.pas" Attributes="0" SourcePath="nim\procfind.pas" SelfReg="false" Sequence="217"/>

-    <ROW File="procfind.pas_1" Component_="charsets.pas" FileName="procfind.pas" Attributes="0" SourcePath="_darcs\pristine\nim\procfind.pas" SelfReg="false" Sequence="380"/>

-    <ROW File="pygepp.py" Component_="configure" FileName="pygepp.py" Attributes="0" SourcePath="pygepp.py" SelfReg="false" Sequence="51"/>

-    <ROW File="pygepp.py_1" Component_="cog.py" FileName="pygepp.py" Attributes="0" SourcePath="_darcs\pristine\pygepp.py" SelfReg="false" Sequence="437"/>

-    <ROW File="question.txt" Component_="nimdoc.css" FileName="question.txt" Attributes="0" SourcePath="doc\question.txt" SelfReg="false" Sequence="11"/>

-    <ROW File="question.txt_1" Component_="charsets.txt" FileName="question.txt" Attributes="0" SourcePath="_darcs\pristine\doc\question.txt" SelfReg="false" Sequence="296"/>

-    <ROW File="readme.txt" Component_="nimdoc.css" FileName="readme.txt" Attributes="0" SourcePath="doc\readme.txt" SelfReg="false" Sequence="12"/>

-    <ROW File="readme.txt_1" Component_="advopt.txt" FileName="readme.txt" Attributes="0" SourcePath="data\readme.txt" SelfReg="false" Sequence="61"/>

-    <ROW File="readme.txt_2" Component_="config.inc" FileName="readme.txt" Attributes="0" SourcePath="nim\readme.txt" SelfReg="false" Sequence="237"/>

-    <ROW File="readme.txt_3" Component_="readme.txt" FileName="readme.txt" Attributes="0" SourcePath="rod\readme.txt" SelfReg="false" Sequence="255"/>

-    <ROW File="readme.txt_4" Component_="configure" FileName="readme.txt" Attributes="0" SourcePath="readme.txt" SelfReg="false" Sequence="269"/>

-    <ROW File="readme.txt_5" Component_="ccomps.txt" FileName="readme.txt" Attributes="0" SourcePath="_darcs\pristine\data\readme.txt" SelfReg="false" Sequence="282"/>

-    <ROW File="readme.txt_6" Component_="charsets.txt" FileName="readme.txt" Attributes="0" SourcePath="_darcs\pristine\doc\readme.txt" SelfReg="false" Sequence="297"/>

-    <ROW File="readme.txt_7" Component_="charsets.pas" FileName="readme.txt" Attributes="0" SourcePath="_darcs\pristine\nim\readme.txt" SelfReg="false" Sequence="381"/>

-    <ROW File="readme.txt_8" Component_="readme.txt_1" FileName="readme.txt" Attributes="0" SourcePath="_darcs\pristine\rod\readme.txt" SelfReg="false" Sequence="417"/>

-    <ROW File="readme.txt_9" Component_="cog.py" FileName="readme.txt" Attributes="0" SourcePath="_darcs\pristine\readme.txt" SelfReg="false" Sequence="442"/>

-    <ROW File="regexprs.nim" Component_="pcre_all.c" FileName="regexprs.nim" Attributes="0" SourcePath="lib\base\regexprs.nim" SelfReg="false" Sequence="103"/>

-    <ROW File="regexprs.nim_1" Component_="pcre.nim" FileName="regexprs.nim" Attributes="0" SourcePath="_darcs\pristine\lib\base\regexprs.nim" SelfReg="false" Sequence="308"/>

-    <ROW File="regexprs.txt" Component_="nimdoc.css" FileName="regexprs.txt" Attributes="0" SourcePath="doc\regexprs.txt" SelfReg="false" Sequence="13"/>

-    <ROW File="regexprs.txt_1" Component_="charsets.txt" FileName="regexprs.txt" Attributes="0" SourcePath="_darcs\pristine\doc\regexprs.txt" SelfReg="false" Sequence="298"/>

-    <ROW File="repr.nim" Component_="dlmalloc.h" FileName="repr.nim" Attributes="0" SourcePath="lib\repr.nim" SelfReg="false" Sequence="91"/>

-    <ROW File="repr.nim_1" Component_="amd64.asm.in" FileName="repr.nim" Attributes="0" SourcePath="_darcs\pristine\lib\repr.nim" SelfReg="false" Sequence="336"/>

-    <ROW File="rnimsyn.nim" Component_="readme.txt" FileName="rnimsyn.nim" Attributes="0" SourcePath="rod\rnimsyn.nim" SelfReg="false" Sequence="262"/>

-    <ROW File="rnimsyn.o" Component_="empty.txt_3" FileName="rnimsyn.o" Attributes="0" SourcePath="obj\rnimsyn.o" SelfReg="false" Sequence="155"/>

-    <ROW File="rnimsyn.pas" Component_="config.inc" FileName="rnimsyn.pas" Attributes="0" SourcePath="nim\rnimsyn.pas" SelfReg="false" Sequence="220"/>

-    <ROW File="rnimsyn.pas_1" Component_="charsets.pas" FileName="rnimsyn.pas" Attributes="0" SourcePath="_darcs\pristine\nim\rnimsyn.pas" SelfReg="false" Sequence="368"/>

-    <ROW File="rnimsyn.ppu" Component_="empty.txt_3" FileName="rnimsyn.ppu" Attributes="0" SourcePath="obj\rnimsyn.ppu" SelfReg="false" Sequence="156"/>

-    <ROW File="rnimsyn.rod" Component_="config.inc" FileName="rnimsyn.rod" Attributes="0" SourcePath="nim\rnimsyn.rod" SelfReg="false" Sequence="248"/>

-    <ROW File="rodgen.o" Component_="empty.txt_3" FileName="rodgen.o" Attributes="0" SourcePath="obj\rodgen.o" SelfReg="false" Sequence="161"/>

-    <ROW File="rodgen.pas" Component_="config.inc" FileName="rodgen.pas" Attributes="0" SourcePath="nim\rodgen.pas" SelfReg="false" Sequence="199"/>

-    <ROW File="rodgen.pas_1" Component_="charsets.pas" FileName="rodgen.pas" Attributes="0" SourcePath="_darcs\pristine\nim\rodgen.pas" SelfReg="false" Sequence="388"/>

-    <ROW File="rodgen.ppu" Component_="empty.txt_3" FileName="rodgen.ppu" Attributes="0" SourcePath="obj\rodgen.ppu" SelfReg="false" Sequence="162"/>

-    <ROW File="ropes.nim" Component_="readme.txt" FileName="ropes.nim" Attributes="0" SourcePath="rod\ropes.nim" SelfReg="false" Sequence="261"/>

-    <ROW File="ropes.o" Component_="empty.txt_3" FileName="ropes.o" Attributes="0" SourcePath="obj\ropes.o" SelfReg="false" Sequence="131"/>

-    <ROW File="ropes.pas" Component_="config.inc" FileName="ropes.pas" Attributes="0" SourcePath="nim\ropes.pas" SelfReg="false" Sequence="219"/>

-    <ROW File="ropes.pas_1" Component_="charsets.pas" FileName="ropes.pas" Attributes="0" SourcePath="_darcs\pristine\nim\ropes.pas" SelfReg="false" Sequence="389"/>

-    <ROW File="ropes.ppu" Component_="empty.txt_3" FileName="ropes.ppu" Attributes="0" SourcePath="obj\ropes.ppu" SelfReg="false" Sequence="132"/>

-    <ROW File="ropes.rod" Component_="config.inc" FileName="ropes.rod" Attributes="0" SourcePath="nim\ropes.rod" SelfReg="false" Sequence="247"/>

-    <ROW File="sbi_header.png" Component_="graphic.jpg" FileName="sbi_he~1.png|sbi_header.png" Attributes="0" SourcePath="web\style\sbi_header.png" SelfReg="false" Sequence="39"/>

-    <ROW File="sbi_header.png_1" Component_="back.png" FileName="sbi_he~1.png|sbi_header.png" Attributes="0" SourcePath="_darcs\pristine\web\style\sbi_header.png" SelfReg="false" Sequence="424"/>

-    <ROW File="scanner.nim" Component_="readme.txt" FileName="scanner.nim" Attributes="0" SourcePath="rod\scanner.nim" SelfReg="false" Sequence="258"/>

-    <ROW File="scanner.o" Component_="empty.txt_3" FileName="scanner.o" Attributes="0" SourcePath="obj\scanner.o" SelfReg="false" Sequence="145"/>

-    <ROW File="scanner.pas" Component_="config.inc" FileName="scanner.pas" Attributes="0" SourcePath="nim\scanner.pas" SelfReg="false" Sequence="221"/>

-    <ROW File="scanner.pas_1" Component_="charsets.pas" FileName="scanner.pas" Attributes="0" SourcePath="_darcs\pristine\nim\scanner.pas" SelfReg="false" Sequence="390"/>

-    <ROW File="scanner.ppu" Component_="empty.txt_3" FileName="scanner.ppu" Attributes="0" SourcePath="obj\scanner.ppu" SelfReg="false" Sequence="146"/>

-    <ROW File="scanner.rod" Component_="config.inc" FileName="scanner.rod" Attributes="0" SourcePath="nim\scanner.rod" SelfReg="false" Sequence="244"/>

-    <ROW File="sem.pas" Component_="config.inc" FileName="sem.pas" Attributes="0" SourcePath="nim\sem.pas" SelfReg="false" Sequence="227"/>

-    <ROW File="sem.pas_1" Component_="charsets.pas" FileName="sem.pas" Attributes="0" SourcePath="_darcs\pristine\nim\sem.pas" SelfReg="false" Sequence="391"/>

-    <ROW File="semfold.pas" Component_="config.inc" FileName="semfold.pas" Attributes="0" SourcePath="nim\semfold.pas" SelfReg="false" Sequence="222"/>

-    <ROW File="semfold.pas_1" Component_="charsets.pas" FileName="semfold.pas" Attributes="0" SourcePath="_darcs\pristine\nim\semfold.pas" SelfReg="false" Sequence="402"/>

-    <ROW File="semsectn.pas" Component_="config.inc" FileName="semsectn.pas" Attributes="0" SourcePath="nim\semsectn.pas" SelfReg="false" Sequence="223"/>

-    <ROW File="semsectn.pas_1" Component_="charsets.pas" FileName="semsectn.pas" Attributes="0" SourcePath="_darcs\pristine\nim\semsectn.pas" SelfReg="false" Sequence="407"/>

-    <ROW File="semstmts.pas" Component_="config.inc" FileName="semstmts.pas" Attributes="0" SourcePath="nim\semstmts.pas" SelfReg="false" Sequence="224"/>

-    <ROW File="semstmts.pas_1" Component_="charsets.pas" FileName="semstmts.pas" Attributes="0" SourcePath="_darcs\pristine\nim\semstmts.pas" SelfReg="false" Sequence="408"/>

-    <ROW File="semtempl.pas" Component_="config.inc" FileName="semtempl.pas" Attributes="0" SourcePath="nim\semtempl.pas" SelfReg="false" Sequence="240"/>

-    <ROW File="semtempl.pas_1" Component_="charsets.pas" FileName="semtempl.pas" Attributes="0" SourcePath="_darcs\pristine\nim\semtempl.pas" SelfReg="false" Sequence="387"/>

-    <ROW File="semtypes.pas" Component_="config.inc" FileName="semtypes.pas" Attributes="0" SourcePath="nim\semtypes.pas" SelfReg="false" Sequence="225"/>

-    <ROW File="semtypes.pas_1" Component_="charsets.pas" FileName="semtypes.pas" Attributes="0" SourcePath="_darcs\pristine\nim\semtypes.pas" SelfReg="false" Sequence="395"/>

-    <ROW File="sets.nim" Component_="dlmalloc.h" FileName="sets.nim" Attributes="0" SourcePath="lib\sets.nim" SelfReg="false" Sequence="92"/>

-    <ROW File="sets.nim_1" Component_="amd64.asm.in" FileName="sets.nim" Attributes="0" SourcePath="_darcs\pristine\lib\sets.nim" SelfReg="false" Sequence="337"/>

-    <ROW File="sigmatch.pas" Component_="config.inc" FileName="sigmatch.pas" Attributes="0" SourcePath="nim\sigmatch.pas" SelfReg="false" Sequence="213"/>

-    <ROW File="spec.txt" Component_="nimdoc.css" FileName="spec.txt" Attributes="0" SourcePath="doc\spec.txt" SelfReg="false" Sequence="14"/>

-    <ROW File="spec.txt_1" Component_="charsets.txt" FileName="spec.txt" Attributes="0" SourcePath="_darcs\pristine\doc\spec.txt" SelfReg="false" Sequence="299"/>

-    <ROW File="statstr.nim" Component_="dlmalloc.h" FileName="statstr.nim" Attributes="0" SourcePath="lib\statstr.nim" SelfReg="false" Sequence="93"/>

-    <ROW File="statstr.nim_1" Component_="amd64.asm.in" FileName="statstr.nim" Attributes="0" SourcePath="_darcs\pristine\lib\statstr.nim" SelfReg="false" Sequence="338"/>

-    <ROW File="strutils.nim" Component_="dlmalloc.h" FileName="strutils.nim" Attributes="0" SourcePath="lib\strutils.nim" SelfReg="false" Sequence="94"/>

-    <ROW File="strutils.nim_1" Component_="amd64.asm.in" FileName="strutils.nim" Attributes="0" SourcePath="_darcs\pristine\lib\strutils.nim" SelfReg="false" Sequence="339"/>

-    <ROW File="strutils.o" Component_="empty.txt_3" FileName="strutils.o" Attributes="0" SourcePath="obj\strutils.o" SelfReg="false" Sequence="111"/>

-    <ROW File="strutils.pas" Component_="config.inc" FileName="strutils.pas" Attributes="0" SourcePath="nim\strutils.pas" SelfReg="false" Sequence="226"/>

-    <ROW File="strutils.pas_1" Component_="charsets.pas" FileName="strutils.pas" Attributes="0" SourcePath="_darcs\pristine\nim\strutils.pas" SelfReg="false" Sequence="396"/>

-    <ROW File="strutils.ppu" Component_="empty.txt_3" FileName="strutils.ppu" Attributes="0" SourcePath="obj\strutils.ppu" SelfReg="false" Sequence="112"/>

-    <ROW File="style.css" Component_="graphic.jpg" FileName="style.css" Attributes="0" SourcePath="web\style\style.css" SelfReg="false" Sequence="40"/>

-    <ROW File="style.css_1" Component_="back.png" FileName="style.css" Attributes="0" SourcePath="_darcs\pristine\web\style\style.css" SelfReg="false" Sequence="425"/>

-    <ROW File="sunset.tmpl" Component_="genweb.py" FileName="sunset~1.tmp|sunset.tmpl" Attributes="0" SourcePath="web\sunset.tmpl" SelfReg="false" Sequence="32"/>

-    <ROW File="sunset.tmpl_1" Component_="documentation.txt" FileName="sunset~1.tmp|sunset.tmpl" Attributes="0" SourcePath="_darcs\pristine\web\sunset.tmpl" SelfReg="false" Sequence="432"/>

-    <ROW File="symrepr.pas" Component_="config.inc" FileName="symrepr.pas" Attributes="0" SourcePath="nim\symrepr.pas" SelfReg="false" Sequence="228"/>

-    <ROW File="symrepr.pas_1" Component_="charsets.pas" FileName="symrepr.pas" Attributes="0" SourcePath="_darcs\pristine\nim\symrepr.pas" SelfReg="false" Sequence="394"/>

-    <ROW File="syntaxes.pas" Component_="config.inc" FileName="syntaxes.pas" Attributes="0" SourcePath="nim\syntaxes.pas" SelfReg="false" Sequence="229"/>

-    <ROW File="syntaxes.pas_1" Component_="charsets.pas" FileName="syntaxes.pas" Attributes="0" SourcePath="_darcs\pristine\nim\syntaxes.pas" SelfReg="false" Sequence="392"/>

-    <ROW File="sysstr.nim" Component_="dlmalloc.h" FileName="sysstr.nim" Attributes="0" SourcePath="lib\sysstr.nim" SelfReg="false" Sequence="95"/>

-    <ROW File="sysstr.nim_1" Component_="amd64.asm.in" FileName="sysstr.nim" Attributes="0" SourcePath="_darcs\pristine\lib\sysstr.nim" SelfReg="false" Sequence="340"/>

-    <ROW File="system.nim" Component_="dlmalloc.h" FileName="system.nim" Attributes="0" SourcePath="lib\system.nim" SelfReg="false" Sequence="96"/>

-    <ROW File="system.nim_1" Component_="amd64.asm.in" FileName="system.nim" Attributes="0" SourcePath="_darcs\pristine\lib\system.nim" SelfReg="false" Sequence="341"/>

-    <ROW File="system.txt" Component_="nimdoc.css" FileName="system.txt" Attributes="0" SourcePath="doc\system.txt" SelfReg="false" Sequence="15"/>

-    <ROW File="system.txt_1" Component_="charsets.txt" FileName="system.txt" Attributes="0" SourcePath="_darcs\pristine\doc\system.txt" SelfReg="false" Sequence="300"/>

-    <ROW File="times.nim" Component_="dlmalloc.h" FileName="times.nim" Attributes="0" SourcePath="lib\times.nim" SelfReg="false" Sequence="97"/>

-    <ROW File="times.nim_1" Component_="amd64.asm.in" FileName="times.nim" Attributes="0" SourcePath="_darcs\pristine\lib\times.nim" SelfReg="false" Sequence="342"/>

-    <ROW File="times.txt" Component_="nimdoc.css" FileName="times.txt" Attributes="0" SourcePath="doc\times.txt" SelfReg="false" Sequence="16"/>

-    <ROW File="times.txt_1" Component_="charsets.txt" FileName="times.txt" Attributes="0" SourcePath="_darcs\pristine\doc\times.txt" SelfReg="false" Sequence="301"/>

-    <ROW File="todo.txt" Component_="configure" FileName="todo.txt" Attributes="0" SourcePath="todo.txt" SelfReg="false" Sequence="52"/>

-    <ROW File="todo.txt_1" Component_="cog.py" FileName="todo.txt" Attributes="0" SourcePath="_darcs\pristine\todo.txt" SelfReg="false" Sequence="438"/>

-    <ROW File="trees.o" Component_="empty.txt_3" FileName="trees.o" Attributes="0" SourcePath="obj\trees.o" SelfReg="false" Sequence="163"/>

-    <ROW File="trees.pas" Component_="config.inc" FileName="trees.pas" Attributes="0" SourcePath="nim\trees.pas" SelfReg="false" Sequence="230"/>

-    <ROW File="trees.pas_1" Component_="charsets.pas" FileName="trees.pas" Attributes="0" SourcePath="_darcs\pristine\nim\trees.pas" SelfReg="false" Sequence="393"/>

-    <ROW File="trees.ppu" Component_="empty.txt_3" FileName="trees.ppu" Attributes="0" SourcePath="obj\trees.ppu" SelfReg="false" Sequence="164"/>

-    <ROW File="tutorial.txt" Component_="nimdoc.css" FileName="tutorial.txt" Attributes="0" SourcePath="doc\tutorial.txt" SelfReg="false" Sequence="17"/>

-    <ROW File="tutorial.txt_1" Component_="charsets.txt" FileName="tutorial.txt" Attributes="0" SourcePath="_darcs\pristine\doc\tutorial.txt" SelfReg="false" Sequence="302"/>

-    <ROW File="typechck.pas" Component_="config.inc" FileName="typechck.pas" Attributes="0" SourcePath="nim\typechck.pas" SelfReg="false" Sequence="231"/>

-    <ROW File="typechck.pas_1" Component_="charsets.pas" FileName="typechck.pas" Attributes="0" SourcePath="_darcs\pristine\nim\typechck.pas" SelfReg="false" Sequence="399"/>

-    <ROW File="typeinfo.nim" Component_="dlmalloc.h" FileName="typeinfo.nim" Attributes="0" SourcePath="lib\typeinfo.nim" SelfReg="false" Sequence="98"/>

-    <ROW File="typeinfo.nim_1" Component_="amd64.asm.in" FileName="typeinfo.nim" Attributes="0" SourcePath="_darcs\pristine\lib\typeinfo.nim" SelfReg="false" Sequence="343"/>

-    <ROW File="unix2dos.py" Component_="cog.py" FileName="unix2dos.py" Attributes="0" SourcePath="_darcs\pristine\unix2dos.py" SelfReg="false" Sequence="444"/>

-    <ROW File="unix2dos.py_1" Component_="configure" FileName="unix2dos.py" Attributes="0" SourcePath="unix2dos.py" SelfReg="false" Sequence="464"/>

-    <ROW File="wordrecg.nim" Component_="readme.txt" FileName="wordrecg.nim" Attributes="0" SourcePath="rod\wordrecg.nim" SelfReg="false" Sequence="265"/>

-    <ROW File="wordrecg.o" Component_="empty.txt_3" FileName="wordrecg.o" Attributes="0" SourcePath="obj\wordrecg.o" SelfReg="false" Sequence="143"/>

-    <ROW File="wordrecg.pas" Component_="config.inc" FileName="wordrecg.pas" Attributes="0" SourcePath="nim\wordrecg.pas" SelfReg="false" Sequence="232"/>

-    <ROW File="wordrecg.pas_1" Component_="charsets.pas" FileName="wordrecg.pas" Attributes="0" SourcePath="_darcs\pristine\nim\wordrecg.pas" SelfReg="false" Sequence="400"/>

-    <ROW File="wordrecg.ppu" Component_="empty.txt_3" FileName="wordrecg.ppu" Attributes="0" SourcePath="obj\wordrecg.ppu" SelfReg="false" Sequence="144"/>

-    <ROW File="wordrecg.rod" Component_="config.inc" FileName="wordrecg.rod" Attributes="0" SourcePath="nim\wordrecg.rod" SelfReg="false" Sequence="251"/>

-    <ROW File="yamlgen.pas" Component_="config.inc" FileName="yamlgen.pas" Attributes="0" SourcePath="nim\yamlgen.pas" SelfReg="false" Sequence="233"/>

-    <ROW File="yamlgen.pas_1" Component_="charsets.pas" FileName="yamlgen.pas" Attributes="0" SourcePath="_darcs\pristine\nim\yamlgen.pas" SelfReg="false" Sequence="398"/>

-  </COMPONENT>

-  <COMPONENT cid="caphyon.advinst.msicomp.BuildComponent">

-    <ROW BuildKey="DefaultBuild" BuildName="DefaultBuild" BuildOrder="1" BuildType="0" InstallationType="4"/>

-    <ATTRIBUTE name="CurrentBuild" value="DefaultBuild"/>

-  </COMPONENT>

-  <COMPONENT cid="caphyon.advinst.msicomp.DictionaryComponent">

-    <ROW Path="&lt;ui.ail&gt;"/>

-    <ROW Path="&lt;ui_en.ail&gt;"/>

-  </COMPONENT>

-  <COMPONENT cid="caphyon.advinst.msicomp.FragmentComponent">

-    <ROW Fragment="FolderDlg.aip" Path="&lt;FolderDlg.aip&gt;"/>

-    <ROW Fragment="StaticUIStrings.aip" Path="&lt;StaticUIStrings.aip&gt;"/>

-    <ROW Fragment="UI.aip" Path="&lt;UI.aip&gt;"/>

-  </COMPONENT>

-  <COMPONENT cid="caphyon.advinst.msicomp.MsiBinaryComponent">

-    <ROW Name="aicustact.dll" SourcePath="&lt;aicustact.dll&gt;"/>

-    <ROW Name="default_banner.bmp" SourcePath="&lt;default-banner.bmp&gt;"/>

-    <ROW Name="default_dialog.bmp" SourcePath="&lt;default-dialog.bmp&gt;"/>

-  </COMPONENT>

-  <COMPONENT cid="caphyon.advinst.msicomp.MsiControlComponent">

-    <ATTRIBUTE name="FixedSizeBitmaps" value="0"/>

-  </COMPONENT>

-  <COMPONENT cid="caphyon.advinst.msicomp.MsiControlEventComponent">

-    <ROW Dialog_="FolderDlg" Control_="Back" Event="NewDialog" Argument="WelcomeDlg" Condition="AI_INSTALL" Ordering="1"/>

-    <ROW Dialog_="WelcomeDlg" Control_="Next" Event="NewDialog" Argument="FolderDlg" Condition="AI_INSTALL" Ordering="1"/>

-    <ROW Dialog_="VerifyReadyDlg" Control_="Back" Event="NewDialog" Argument="FolderDlg" Condition="AI_INSTALL" Ordering="1"/>

-    <ROW Dialog_="FolderDlg" Control_="Next" Event="NewDialog" Argument="VerifyReadyDlg" Condition="AI_INSTALL" Ordering="3"/>

-    <ROW Dialog_="MaintenanceTypeDlg" Control_="Back" Event="NewDialog" Argument="MaintenanceWelcomeDlg" Condition="AI_MAINT" Ordering="1"/>

-    <ROW Dialog_="MaintenanceWelcomeDlg" Control_="Next" Event="NewDialog" Argument="MaintenanceTypeDlg" Condition="AI_MAINT" Ordering="2"/>

-    <ROW Dialog_="VerifyReadyDlg" Control_="Back" Event="NewDialog" Argument="PatchWelcomeDlg" Condition="AI_PATCH" Ordering="1"/>

-    <ROW Dialog_="PatchWelcomeDlg" Control_="Next" Event="NewDialog" Argument="VerifyReadyDlg" Condition="AI_PATCH" Ordering="3"/>

-  </COMPONENT>

-  <COMPONENT cid="caphyon.advinst.msicomp.MsiCreateFolderComponent">

-    <ROW Directory_="SHORTCUTDIR" Component_="SHORTCUTDIR"/>

-  </COMPONENT>

-  <COMPONENT cid="caphyon.advinst.msicomp.MsiCustActComponent">

-    <ROW Action="AI_DOWNGRADE" Type="19" Target="4010"/>

-    <ROW Action="AI_PREPARE_UPGRADE" Type="65" Source="aicustact.dll" Target="PrepareUpgrade"/>

-    <ROW Action="AI_RESTORE_LOCATION" Type="65" Source="aicustact.dll" Target="RestoreLocation"/>

-    <ROW Action="AI_STORE_LOCATION" Type="51" Source="ARPINSTALLLOCATION" Target="[APPDIR]"/>

-    <ROW Action="SET_APPDIR" Type="307" Source="APPDIR" Target="[ProgramFilesFolder][Manufacturer]\[ProductName]"/>

-    <ROW Action="SET_SHORTCUTDIR" Type="307" Source="SHORTCUTDIR" Target="[ProgramMenuFolder][ProductName]"/>

-    <ROW Action="SET_TARGETDIR_TO_APPDIR" Type="51" Source="TARGETDIR" Target="[APPDIR]"/>

-  </COMPONENT>

-  <COMPONENT cid="caphyon.advinst.msicomp.MsiEnvComponent">

-    <ROW Environment="Path" Name="=Path" Value="[~];[bin_DIR]" Component_="SHORTCUTDIR"/>

-  </COMPONENT>

-  <COMPONENT cid="caphyon.advinst.msicomp.MsiInstExSeqComponent">

-    <ROW Action="AI_DOWNGRADE" Condition="AI_NEWERPRODUCTFOUND AND (UILevel &lt;&gt; 5)" Sequence="210"/>

-    <ROW Action="AI_RESTORE_LOCATION" Condition="APPDIR=&quot;&quot;" Sequence="740"/>

-    <ROW Action="AI_STORE_LOCATION" Condition="Not Installed" Sequence="1545"/>

-    <ROW Action="AI_PREPARE_UPGRADE" Condition="AI_UPGRADE=&quot;No&quot; AND (Not Installed)" Sequence="1300"/>

-  </COMPONENT>

-  <COMPONENT cid="caphyon.advinst.msicomp.MsiInstallUISequenceComponent">

-    <ROW Action="AI_RESTORE_LOCATION" Condition="APPDIR=&quot;&quot;" Sequence="740"/>

-  </COMPONENT>

-  <COMPONENT cid="caphyon.advinst.msicomp.MsiRegsComponent">

-    <ROW Registry="New_Value" Root="-1" Key="Software\[Manufacturer]\[ProductName]" Name="AppPath" Value="[APPDIR]" Component_="New_Value"/>

-  </COMPONENT>

-  <COMPONENT cid="caphyon.advinst.msicomp.MsiShortsComponent">

-    <ROW Shortcut="nim.exe" Directory_="SHORTCUTDIR" Name="nim.exe" Component_="nim.exe" Target="[#nim.exe]" Description="nim.exe" Hotkey="0" IconIndex="0" ShowCmd="1" WkDir="bin_DIR"/>

-  </COMPONENT>

-  <COMPONENT cid="caphyon.advinst.msicomp.MsiUpgradeComponent">

-    <ROW UpgradeCode="[|UpgradeCode]" VersionMax="[|ProductVersion]" Attributes="1025" ActionProperty="OLDPRODUCTS"/>

-    <ROW UpgradeCode="[|UpgradeCode]" VersionMin="[|ProductVersion]" Attributes="2" ActionProperty="AI_NEWERPRODUCTFOUND"/>

-  </COMPONENT>

-</DOCUMENT>

diff --git a/tests/bench/GCBench.c b/tests/bench/GCBench.c
deleted file mode 100644
index c9e77d191..000000000
--- a/tests/bench/GCBench.c
+++ /dev/null
@@ -1,296 +0,0 @@
-// This is adapted from a benchmark written by John Ellis and Pete Kovac
-// of Post Communications.
-// It was modified by Hans Boehm of Silicon Graphics.
-// Translated to C++ 30 May 1997 by William D Clinger of Northeastern Univ.
-// Translated to C 15 March 2000 by Hans Boehm, now at HP Labs.
-//
-//      This is no substitute for real applications.  No actual application
-//      is likely to behave in exactly this way.  However, this benchmark was
-//      designed to be more representative of real applications than other
-//      Java GC benchmarks of which we are aware.
-//      It attempts to model those properties of allocation requests that
-//      are important to current GC techniques.
-//      It is designed to be used either to obtain a single overall performance
-//      number, or to give a more detailed estimate of how collector
-//      performance varies with object lifetimes.  It prints the time
-//      required to allocate and collect balanced binary trees of various
-//      sizes.  Smaller trees result in shorter object lifetimes.  Each cycle
-//      allocates roughly the same amount of memory.
-//      Two data structures are kept around during the entire process, so
-//      that the measured performance is representative of applications
-//      that maintain some live in-memory data.  One of these is a tree
-//      containing many pointers.  The other is a large array containing
-//      double precision floating point numbers.  Both should be of comparable
-//      size.
-//
-//      The results are only really meaningful together with a specification
-//      of how much memory was used.  It is possible to trade memory for
-//      better time performance.  This benchmark should be run in a 32 MB
-//      heap, though we don't currently know how to enforce that uniformly.
-//
-//      Unlike the original Ellis and Kovac benchmark, we do not attempt
-//      measure pause times.  This facility should eventually be added back
-//      in.  There are several reasons for omitting it for now.  The original
-//      implementation depended on assumptions about the thread scheduler
-//      that don't hold uniformly.  The results really measure both the
-//      scheduler and GC.  Pause time measurements tend to not fit well with
-//      current benchmark suites.  As far as we know, none of the current
-//      commercial Java implementations seriously attempt to minimize GC pause
-//      times.
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/time.h>
-
-#ifdef GC
-#  include "gc.h"
-#endif
-
-#ifdef PROFIL
-  extern void init_profiling();
-  extern dump_profile();
-#endif
-
-//  These macros were a quick hack for the Macintosh.
-//
-//  #define currentTime() clock()
-//  #define elapsedTime(x) ((1000*(x))/CLOCKS_PER_SEC)
-
-#define currentTime() stats_rtclock()
-#define elapsedTime(x) (x)
-
-/* Get the current time in milliseconds */
-
-unsigned
-stats_rtclock( void )
-{
-  struct timeval t;
-  struct timezone tz;
-
-  if (gettimeofday( &t, &tz ) == -1)
-    return 0;
-  return (t.tv_sec * 1000 + t.tv_usec / 1000);
-}
-
-static const int kStretchTreeDepth    = 18;      // about 16Mb
-static const int kLongLivedTreeDepth  = 16;  // about 4Mb
-static const int kArraySize  = 500000;  // about 4Mb
-static const int kMinTreeDepth = 4;
-static const int kMaxTreeDepth = 16;
-
-typedef struct Node0_struct {
-        struct Node0_struct * left;
-        struct Node0_struct * right;
-        int i, j;
-} Node0;
-
-#ifdef HOLES
-#   define HOLE() GC_NEW(Node0);
-#else
-#   define HOLE()
-#endif
-
-typedef Node0 *Node;
-
-void init_Node(Node me, Node l, Node r) {
-    me -> left = l;
-    me -> right = r;
-}
-
-#ifndef GC
-  void destroy_Node(Node me) {
-    if (me -> left) {
-	destroy_Node(me -> left);
-    }
-    if (me -> right) {
-	destroy_Node(me -> right);
-    }
-    free(me);
-  }
-#endif
-
-// Nodes used by a tree of a given size
-static int TreeSize(int i) {
-        return ((1 << (i + 1)) - 1);
-}
-
-// Number of iterations to use for a given tree depth
-static int NumIters(int i) {
-        return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i);
-}
-
-// Build tree top down, assigning to older objects.
-static void Populate(int iDepth, Node thisNode) {
-        if (iDepth<=0) {
-                return;
-        } else {
-                iDepth--;
-#		ifdef GC
-                  thisNode->left  = GC_NEW(Node0); HOLE();
-                  thisNode->right = GC_NEW(Node0); HOLE();
-#		else
-                  thisNode->left  = calloc(1, sizeof(Node0));
-                  thisNode->right = calloc(1, sizeof(Node0));
-#		endif
-                Populate (iDepth, thisNode->left);
-                Populate (iDepth, thisNode->right);
-        }
-}
-
-// Build tree bottom-up
-static Node MakeTree(int iDepth) {
-	Node result;
-        if (iDepth<=0) {
-#	    ifndef GC
-		result = calloc(1, sizeof(Node0));
-#	    else
-		result = GC_NEW(Node0); HOLE();
-#	    endif
-	    /* result is implicitly initialized in both cases. */
-	    return result;
-        } else {
-	    Node left = MakeTree(iDepth-1);
-	    Node right = MakeTree(iDepth-1);
-#	    ifndef GC
-		result = malloc(sizeof(Node0));
-#	    else
-		result = GC_NEW(Node0); HOLE();
-#	    endif
-	    init_Node(result, left, right);
-	    return result;
-        }
-}
-
-static void PrintDiagnostics() {
-#if 0
-        long lFreeMemory = Runtime.getRuntime().freeMemory();
-        long lTotalMemory = Runtime.getRuntime().totalMemory();
-
-        System.out.print(" Total memory available="
-                         + lTotalMemory + " bytes");
-        System.out.println("  Free memory=" + lFreeMemory + " bytes");
-#endif
-}
-
-static void TimeConstruction(int depth) {
-        long    tStart, tFinish;
-        int     iNumIters = NumIters(depth);
-        Node    tempTree;
-	int 	i;
-
-	printf("Creating %d trees of depth %d\n", iNumIters, depth);
-        
-        tStart = currentTime();
-        for (i = 0; i < iNumIters; ++i) {
-#		ifndef GC
-                  tempTree = calloc(1, sizeof(Node0));
-#		else
-                  tempTree = GC_NEW(Node0);
-#		endif
-                Populate(depth, tempTree);
-#		ifndef GC
-                  destroy_Node(tempTree);
-#		endif
-                tempTree = 0;
-        }
-        tFinish = currentTime();
-        printf("\tTop down construction took %d msec\n",
-               elapsedTime(tFinish - tStart));
-             
-        tStart = currentTime();
-        for (i = 0; i < iNumIters; ++i) {
-                tempTree = MakeTree(depth);
-#		ifndef GC
-                  destroy_Node(tempTree);
-#		endif
-                tempTree = 0;
-        }
-        tFinish = currentTime();
-        printf("\tBottom up construction took %d msec\n",
-               elapsedTime(tFinish - tStart));
-
-}
-
-int main() {
-        Node    root;
-        Node    longLivedTree;
-        Node    tempTree;
-        long    tStart, tFinish;
-        long    tElapsed;
-  	int	i, d;
-	double 	*array;
-
-#ifdef GC
- // GC_full_freq = 30;
- // GC_free_space_divisor = 16;
- // GC_enable_incremental();
-#endif
-	printf("Garbage Collector Test\n");
- 	printf(" Live storage will peak at %d bytes.\n\n",
-               2 * sizeof(Node0) * TreeSize(kLongLivedTreeDepth) +
-               sizeof(double) * kArraySize);
-        printf(" Stretching memory with a binary tree of depth %d\n",
-               kStretchTreeDepth);
-        PrintDiagnostics();
-#	ifdef PROFIL
-	    init_profiling();
-#	endif
-       
-        tStart = currentTime();
-        
-        // Stretch the memory space quickly
-        tempTree = MakeTree(kStretchTreeDepth);
-#	ifndef GC
-          destroy_Node(tempTree);
-#	endif
-        tempTree = 0;
-
-        // Create a long lived object
-        printf(" Creating a long-lived binary tree of depth %d\n",
-               kLongLivedTreeDepth);
-#	ifndef GC
-          longLivedTree = calloc(1, sizeof(Node0));
-#	else 
-          longLivedTree = GC_NEW(Node0);
-#	endif
-        Populate(kLongLivedTreeDepth, longLivedTree);
-
-        // Create long-lived array, filling half of it
-	printf(" Creating a long-lived array of %d doubles\n", kArraySize);
-#	ifndef GC
-          array = malloc(kArraySize * sizeof(double));
-#	else
-#	  ifndef NO_PTRFREE
-            array = GC_MALLOC_ATOMIC(sizeof(double) * kArraySize);
-#	  else
-            array = GC_MALLOC(sizeof(double) * kArraySize);
-#	  endif
-#	endif
-        for (i = 0; i < kArraySize/2; ++i) {
-                array[i] = 1.0/i;
-        }
-        PrintDiagnostics();
-
-        for (d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2) {
-                TimeConstruction(d);
-        }
-
-        if (longLivedTree == 0 || array[1000] != 1.0/1000)
-		fprintf(stderr, "Failed\n");
-                                // fake reference to LongLivedTree
-                                // and array
-                                // to keep them from being optimized away
-
-        tFinish = currentTime();
-        tElapsed = elapsedTime(tFinish-tStart);
-        PrintDiagnostics();
-        printf("Completed in %d msec\n", tElapsed);
-#	ifdef GC
-	  printf("Completed %d collections\n", GC_gc_no);
-	  printf("Heap size is %d\n", GC_get_heap_size());
-#       endif
-#	ifdef PROFIL
-	  dump_profile();
-#	endif
-}
-
diff --git a/tests/bench/GCBench.cpp b/tests/bench/GCBench.cpp
deleted file mode 100644
index bd5e286a7..000000000
--- a/tests/bench/GCBench.cpp
+++ /dev/null
@@ -1,266 +0,0 @@
-// This is adapted from a benchmark written by John Ellis and Pete Kovac
-// of Post Communications.
-// It was modified by Hans Boehm of Silicon Graphics.
-// Translated to C++ 30 May 1997 by William D Clinger of Northeastern Univ.
-//
-//      This is no substitute for real applications.  No actual application
-//      is likely to behave in exactly this way.  However, this benchmark was
-//      designed to be more representative of real applications than other
-//      Java GC benchmarks of which we are aware.
-//      It attempts to model those properties of allocation requests that
-//      are important to current GC techniques.
-//      It is designed to be used either to obtain a single overall performance
-//      number, or to give a more detailed estimate of how collector
-//      performance varies with object lifetimes.  It prints the time
-//      required to allocate and collect balanced binary trees of various
-//      sizes.  Smaller trees result in shorter object lifetimes.  Each cycle
-//      allocates roughly the same amount of memory.
-//      Two data structures are kept around during the entire process, so
-//      that the measured performance is representative of applications
-//      that maintain some live in-memory data.  One of these is a tree
-//      containing many pointers.  The other is a large array containing
-//      double precision floating point numbers.  Both should be of comparable
-//      size.
-//
-//      The results are only really meaningful together with a specification
-//      of how much memory was used.  It is possible to trade memory for
-//      better time performance.  This benchmark should be run in a 32 MB
-//      heap, though we don't currently know how to enforce that uniformly.
-//
-//      Unlike the original Ellis and Kovac benchmark, we do not attempt
-//      measure pause times.  This facility should eventually be added back
-//      in.  There are several reasons for omitting it for now.  The original
-//      implementation depended on assumptions about the thread scheduler
-//      that don't hold uniformly.  The results really measure both the
-//      scheduler and GC.  Pause time measurements tend to not fit well with
-//      current benchmark suites.  As far as we know, none of the current
-//      commercial Java implementations seriously attempt to minimize GC pause
-//      times.
-
-#include <new.h>
-#include <iostream.h>
-#include <sys/time.h>
-
-#ifdef GC
-#  include "gc.h"
-#endif
-
-//  These macros were a quick hack for the Macintosh.
-//
-//  #define currentTime() clock()
-//  #define elapsedTime(x) ((1000*(x))/CLOCKS_PER_SEC)
-
-#define currentTime() stats_rtclock()
-#define elapsedTime(x) (x)
-
-/* Get the current time in milliseconds */
-
-unsigned
-stats_rtclock( void )
-{
-  struct timeval t;
-  struct timezone tz;
-
-  if (gettimeofday( &t, &tz ) == -1)
-    return 0;
-  return (t.tv_sec * 1000 + t.tv_usec / 1000);
-}
-
-static const int kStretchTreeDepth    = 18;      // about 16Mb
-static const int kLongLivedTreeDepth  = 16;  // about 4Mb
-static const int kArraySize  = 500000;  // about 4Mb
-static const int kMinTreeDepth = 4;
-static const int kMaxTreeDepth = 16;
-
-typedef struct Node0 *Node;
-
-struct Node0 {
-        Node left;
-        Node right;
-        int i, j;
-        Node0(Node l, Node r) { left = l; right = r; }
-        Node0() { left = 0; right = 0; }
-#       ifndef GC
-          ~Node0() { if (left) delete left; if (right) delete right; }
-#	endif
-};
-
-struct GCBench {
-
-        // Nodes used by a tree of a given size
-        static int TreeSize(int i) {
-                return ((1 << (i + 1)) - 1);
-        }
-
-        // Number of iterations to use for a given tree depth
-        static int NumIters(int i) {
-                return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i);
-        }
-
-        // Build tree top down, assigning to older objects.
-        static void Populate(int iDepth, Node thisNode) {
-                if (iDepth<=0) {
-                        return;
-                } else {
-                        iDepth--;
-#			ifndef GC
-                          thisNode->left  = new Node0();
-                          thisNode->right = new Node0();
-#			else
-                          thisNode->left  = new (GC_NEW(Node0)) Node0();
-                          thisNode->right = new (GC_NEW(Node0)) Node0();
-#			endif
-                        Populate (iDepth, thisNode->left);
-                        Populate (iDepth, thisNode->right);
-                }
-        }
-
-        // Build tree bottom-up
-        static Node MakeTree(int iDepth) {
-                if (iDepth<=0) {
-#		     ifndef GC
-                        return new Node0();
-#		     else
-                        return new (GC_NEW(Node0)) Node0();
-#		     endif
-                } else {
-#		     ifndef GC
-                        return new Node0(MakeTree(iDepth-1),
-                                         MakeTree(iDepth-1));
-#		     else
-                        return new (GC_NEW(Node0)) Node0(MakeTree(iDepth-1),
-                                         		 MakeTree(iDepth-1));
-#		     endif
-                }
-        }
-
-        static void PrintDiagnostics() {
-#if 0
-                long lFreeMemory = Runtime.getRuntime().freeMemory();
-                long lTotalMemory = Runtime.getRuntime().totalMemory();
-
-                System.out.print(" Total memory available="
-                                 + lTotalMemory + " bytes");
-                System.out.println("  Free memory=" + lFreeMemory + " bytes");
-#endif
-        }
-
-        static void TimeConstruction(int depth) {
-                long    tStart, tFinish;
-                int     iNumIters = NumIters(depth);
-                Node    tempTree;
-
-                cout << "Creating " << iNumIters
-                     << " trees of depth " << depth << endl;
-                
-                tStart = currentTime();
-                for (int i = 0; i < iNumIters; ++i) {
-#			ifndef GC
-                          tempTree = new Node0();
-#			else
-                          tempTree = new (GC_NEW(Node0)) Node0();
-#			endif
-                        Populate(depth, tempTree);
-#		        ifndef GC
-                          delete tempTree;
-#			endif
-                        tempTree = 0;
-                }
-                tFinish = currentTime();
-                cout << "\tTop down construction took "
-                     << elapsedTime(tFinish - tStart) << " msec" << endl;
-                     
-                tStart = currentTime();
-                for (int i = 0; i < iNumIters; ++i) {
-                        tempTree = MakeTree(depth);
-#			ifndef GC
-                          delete tempTree;
-#			endif
-                        tempTree = 0;
-                }
-                tFinish = currentTime();
-                cout << "\tBottom up construction took "
-                     << elapsedTime(tFinish - tStart) << " msec" << endl;
-
-        }
-
-        void main() {
-                Node    root;
-                Node    longLivedTree;
-                Node    tempTree;
-                long    tStart, tFinish;
-                long    tElapsed;
-
-#ifdef GC
-// GC_full_freq = 30;
-GC_enable_incremental();
-#endif
-                cout << "Garbage Collector Test" << endl;
-                cout << " Live storage will peak at "
-                     << 2 * sizeof(Node0) * TreeSize(kLongLivedTreeDepth) +
-                        sizeof(double) * kArraySize
-                     << " bytes." << endl << endl;
-                cout << " Stretching memory with a binary tree of depth "
-                     << kStretchTreeDepth << endl;
-                PrintDiagnostics();
-               
-                tStart = currentTime();
-                
-                // Stretch the memory space quickly
-                tempTree = MakeTree(kStretchTreeDepth);
-#		ifndef GC
-                  delete tempTree;
-#		endif
-                tempTree = 0;
-
-                // Create a long lived object
-                cout << " Creating a long-lived binary tree of depth "
-                     << kLongLivedTreeDepth << endl;
-#		ifndef GC
-                  longLivedTree = new Node0();
-#		else 
-                  longLivedTree = new (GC_NEW(Node0)) Node0();
-#		endif
-                Populate(kLongLivedTreeDepth, longLivedTree);
-
-                // Create long-lived array, filling half of it
-                cout << " Creating a long-lived array of "
-                     << kArraySize << " doubles" << endl;
-#		ifndef GC
-                  double *array = new double[kArraySize];
-#		else
-                  double *array = (double *)
-				GC_MALLOC_ATOMIC(sizeof(double) * kArraySize);
-#		endif
-                for (int i = 0; i < kArraySize/2; ++i) {
-                        array[i] = 1.0/i;
-                }
-                PrintDiagnostics();
-
-                for (int d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2)
-{
-                        TimeConstruction(d);
-                }
-
-                if (longLivedTree == 0 || array[1000] != 1.0/1000)
-                        cout << "Failed" << endl;
-                                        // fake reference to LongLivedTree
-                                        // and array
-                                        // to keep them from being optimized away
-
-                tFinish = currentTime();
-                tElapsed = elapsedTime(tFinish-tStart);
-                PrintDiagnostics();
-                cout << "Completed in " << tElapsed << " msec" << endl;
-#		ifdef GC
-		  cout << "Completed " << GC_gc_no << " collections" <<endl;
-		  cout << "Heap size is " << GC_get_heap_size() << endl;
-#		endif
-        }
-};
-
-main () {
-    GCBench x;
-    x.main();
-}
-
diff --git a/tests/bench/GCBench.java b/tests/bench/GCBench.java
deleted file mode 100644
index ec9b93de8..000000000
--- a/tests/bench/GCBench.java
+++ /dev/null
@@ -1,182 +0,0 @@
-// This is adapted from a benchmark written by John Ellis and Pete Kovac
-// of Post Communications.
-// It was modified by Hans Boehm of Silicon Graphics.
-//
-// 	This is no substitute for real applications.  No actual application
-//	is likely to behave in exactly this way.  However, this benchmark was
-//	designed to be more representative of real applications than other
-//	Java GC benchmarks of which we are aware.
-//	It attempts to model those properties of allocation requests that
-//	are important to current GC techniques.
-//	It is designed to be used either to obtain a single overall performance
-//	number, or to give a more detailed estimate of how collector
-//	performance varies with object lifetimes.  It prints the time
-//	required to allocate and collect balanced binary trees of various
-//	sizes.  Smaller trees result in shorter object lifetimes.  Each cycle
-//	allocates roughly the same amount of memory.
-//	Two data structures are kept around during the entire process, so
-//	that the measured performance is representative of applications
-//	that maintain some live in-memory data.  One of these is a tree
-//	containing many pointers.  The other is a large array containing
-//	double precision floating point numbers.  Both should be of comparable
-//	size.
-//
-//	The results are only really meaningful together with a specification
-//	of how much memory was used.  It is possible to trade memory for
-//	better time performance.  This benchmark should be run in a 32 MB
-//	heap, though we don't currently know how to enforce that uniformly.
-//
-//	Unlike the original Ellis and Kovac benchmark, we do not attempt
-// 	measure pause times.  This facility should eventually be added back
-//	in.  There are several reasons for omitting it for now.  The original
-//	implementation depended on assumptions about the thread scheduler
-//	that don't hold uniformly.  The results really measure both the
-//	scheduler and GC.  Pause time measurements tend to not fit well with
-//	current benchmark suites.  As far as we know, none of the current
-//	commercial Java implementations seriously attempt to minimize GC pause
-//	times.
-//
-//	Known deficiencies:
-//		- No way to check on memory use
-//		- No cyclic data structures
-//		- No attempt to measure variation with object size
-//		- Results are sensitive to locking cost, but we dont
-//		  check for proper locking
-
-class Node {
-	Node left, right;
-	int i, j;
-	Node(Node l, Node r) { left = l; right = r; }
-	Node() { }
-}
-
-public class GCBench {
-
-	public static final int kStretchTreeDepth    = 18;	// about 16Mb
-	public static final int kLongLivedTreeDepth  = 16;  // about 4Mb
-	public static final int kArraySize  = 500000;  // about 4Mb
-	public static final int kMinTreeDepth = 4;
-	public static final int kMaxTreeDepth = 16;
-
-	// Nodes used by a tree of a given size
-	static int TreeSize(int i) {
-	    	return ((1 << (i + 1)) - 1);
-	}
-
-	// Number of iterations to use for a given tree depth
-	static int NumIters(int i) {
-                return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i);
-        }
-
-	// Build tree top down, assigning to older objects. 
-	static void Populate(int iDepth, Node thisNode) {
-		if (iDepth<=0) {
-			return;
-		} else {
-			iDepth--;
-			thisNode.left  = new Node();
-			thisNode.right = new Node();
-			Populate (iDepth, thisNode.left);
-			Populate (iDepth, thisNode.right);
-		}
-	}
-
-	// Build tree bottom-up
-	static Node MakeTree(int iDepth) {
-		if (iDepth<=0) {
-			return new Node();
-		} else {
-			return new Node(MakeTree(iDepth-1),
-					MakeTree(iDepth-1));
-		}
-	}
-
-	static void PrintDiagnostics() {
-		long lFreeMemory = Runtime.getRuntime().freeMemory();
-		long lTotalMemory = Runtime.getRuntime().totalMemory();
-
-		System.out.print(" Total memory available="
-				 + lTotalMemory + " bytes");
-		System.out.println("  Free memory=" + lFreeMemory + " bytes");
-	}
-
-	static void TimeConstruction(int depth) {
-		Node    root;
-		long    tStart, tFinish;
-		int 	iNumIters = NumIters(depth);
-		Node	tempTree;
-
-		System.out.println("Creating " + iNumIters +
-				   " trees of depth " + depth);
-		tStart = System.currentTimeMillis();
-		for (int i = 0; i < iNumIters; ++i) {
-			tempTree = new Node();
-			Populate(depth, tempTree);
-			tempTree = null;
-		}
-		tFinish = System.currentTimeMillis();
-		System.out.println("\tTop down construction took "
-				   + (tFinish - tStart) + "msecs");
-		tStart = System.currentTimeMillis();
-                for (int i = 0; i < iNumIters; ++i) {
-                        tempTree = MakeTree(depth);
-                        tempTree = null;
-                }
-                tFinish = System.currentTimeMillis();
-                System.out.println("\tBottom up construction took "
-                                   + (tFinish - tStart) + "msecs");
-		
-	}
-
-	public static void main(String args[]) {
-		Node	root;
-		Node	longLivedTree;
-		Node	tempTree;
-		long	tStart, tFinish;
-		long	tElapsed;
-
-
-		System.out.println("Garbage Collector Test");
-		System.out.println(
-			" Stretching memory with a binary tree of depth "
-			+ kStretchTreeDepth);
-		PrintDiagnostics();
-		tStart = System.currentTimeMillis();
-
-		// Stretch the memory space quickly
-		tempTree = MakeTree(kStretchTreeDepth);
-		tempTree = null;
-
-		// Create a long lived object
-		System.out.println(
-			" Creating a long-lived binary tree of depth " +
-  			kLongLivedTreeDepth);
-		longLivedTree = new Node();
-		Populate(kLongLivedTreeDepth, longLivedTree);
-
-		// Create long-lived array, filling half of it
-		System.out.println(
-                        " Creating a long-lived array of "
-			+ kArraySize + " doubles");
-		double array[] = new double[kArraySize];
-		for (int i = 0; i < kArraySize/2; ++i) {
-			array[i] = 1.0/i;
-		}
-		PrintDiagnostics();
-
-		for (int d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2) {
-			TimeConstruction(d);
-		}
-
-		if (longLivedTree == null || array[1000] != 1.0/1000)
-			System.out.println("Failed");
-					// fake reference to LongLivedTree
-					// and array
-					// to keep them from being optimized away
-
-		tFinish = System.currentTimeMillis();
-		tElapsed = tFinish-tStart;
-		PrintDiagnostics();
-		System.out.println("Completed in " + tElapsed + "ms.");
-	}
-} // class JavaGC
diff --git a/tests/bench/GCBench_OGC.cpp b/tests/bench/GCBench_OGC.cpp
deleted file mode 100644
index 2669da603..000000000
--- a/tests/bench/GCBench_OGC.cpp
+++ /dev/null
@@ -1,301 +0,0 @@
-// This is adapted from a benchmark written by John Ellis and Pete Kovac
-// of Post Communications.
-// It was modified by Hans Boehm of Silicon Graphics.
-// Translated to C++ 30 May 1997 by William D Clinger of Northeastern Univ.
-//
-//      This is no substitute for real applications.  No actual application
-//      is likely to behave in exactly this way.  However, this benchmark was
-//      designed to be more representative of real applications than other
-//      Java GC benchmarks of which we are aware.
-//      It attempts to model those properties of allocation requests that
-//      are important to current GC techniques.
-//      It is designed to be used either to obtain a single overall performance
-//      number, or to give a more detailed estimate of how collector
-//      performance varies with object lifetimes.  It prints the time
-//      required to allocate and collect balanced binary trees of various
-//      sizes.  Smaller trees result in shorter object lifetimes.  Each cycle
-//      allocates roughly the same amount of memory.
-//      Two data structures are kept around during the entire process, so
-//      that the measured performance is representative of applications
-//      that maintain some live in-memory data.  One of these is a tree
-//      containing many pointers.  The other is a large array containing
-//      double precision floating point numbers.  Both should be of comparable
-//      size.
-//
-//      The results are only really meaningful together with a specification
-//      of how much memory was used.  It is possible to trade memory for
-//      better time performance.  This benchmark should be run in a 32 MB
-//      heap, though we don't currently know how to enforce that uniformly.
-//
-//      Unlike the original Ellis and Kovac benchmark, we do not attempt
-//      measure pause times.  This facility should eventually be added back
-//      in.  There are several reasons for omitting it for now.  The original
-//      implementation depended on assumptions about the thread scheduler
-//      that don't hold uniformly.  The results really measure both the
-//      scheduler and GC.  Pause time measurements tend to not fit well with
-//      current benchmark suites.  As far as we know, none of the current
-//      commercial Java implementations seriously attempt to minimize GC pause
-//      times.
-
-#include <new.h>
-#include <iostream.h>
-#include <sys/time.h>
-
-#ifdef GC
-#  include "gc.h"
-#endif
-#ifdef OGC
-#  include "ogc.h"
-#endif
-
-//  These macros were a quick hack for the Macintosh.
-//
-//  #define currentTime() clock()
-//  #define elapsedTime(x) ((1000*(x))/CLOCKS_PER_SEC)
-
-#define currentTime() stats_rtclock()
-#define elapsedTime(x) (x)
-
-/* Get the current time in milliseconds */
-
-unsigned
-stats_rtclock( void )
-{
-  struct timeval t;
-  struct timezone tz;
-
-  if (gettimeofday( &t, &tz ) == -1)
-    return 0;
-  return (t.tv_sec * 1000 + t.tv_usec / 1000);
-}
-
-static const int kStretchTreeDepth    = 18;      // about 16Mb
-static const int kLongLivedTreeDepth  = 16;  // about 4Mb
-static const int kArraySize  = 500000;  // about 4Mb
-static const int kMinTreeDepth = 4;
-static const int kMaxTreeDepth = 16;
-
-struct Node0 {
-#       ifdef OGC
-          gc_ptr<Node0> left;
-          gc_ptr<Node0> right;
-          Node0(gc_ptr<Node0> l, gc_ptr<Node0> r) { left = l; right = r; }
-#	else
-          Node0 * left;
-          Node0 * right;
-          Node0(Node0 *l, Node0 *r) { left = l; right = r; }
-#	endif
-        int i, j;
-        Node0() { left = 0; right = 0; }
-#       if !defined(GC) && !defined(OGC)
-          ~Node0() { if (left) delete left; if (right) delete right; }
-#	endif
-};
-
-#ifdef OGC
-typedef gc_ptr<Node0> Node;
-#else
-typedef struct Node0 *Node;
-#endif
-
-struct GCBench {
-
-        // Nodes used by a tree of a given size
-        static int TreeSize(int i) {
-                return ((1 << (i + 1)) - 1);
-        }
-
-        // Number of iterations to use for a given tree depth
-        static int NumIters(int i) {
-                return 2 * TreeSize(kStretchTreeDepth) / TreeSize(i);
-        }
-
-        // Build tree top down, assigning to older objects.
-        static void Populate(int iDepth, Node thisNode) {
-                if (iDepth<=0) {
-                        return;
-                } else {
-                        iDepth--;
-#			if defined(GC)
-                          thisNode->left  = new (GC_NEW(Node0)) Node0();
-                          thisNode->right = new (GC_NEW(Node0)) Node0();
-#			elif defined(OGC)
-                          thisNode->left  = gc_new Node0();
-                          thisNode->right = gc_new Node0();
-#			else
-                          thisNode->left  = new Node0();
-                          thisNode->right = new Node0();
-#			endif
-                        Populate (iDepth, thisNode->left);
-                        Populate (iDepth, thisNode->right);
-                }
-        }
-
-        // Build tree bottom-up
-        static Node MakeTree(int iDepth) {
-                if (iDepth<=0) {
-#		     if defined(GC)
-                        return new (GC_NEW(Node0)) Node0();
-#		     elif defined(OGC)
-                        return gc_new Node0();
-#		     else
-                        return new Node0();
-#		     endif
-                } else {
-#		     if defined(GC)
-                        return new (GC_NEW(Node0)) Node0(MakeTree(iDepth-1),
-                                         		 MakeTree(iDepth-1));
-#		     elif defined(OGC)
-#			ifdef BROKEN_SMART_PTRS
-			  Node left = MakeTree(iDepth-1);
-			  Node right = MakeTree(iDepth-1);
-                          return gc_new Node0(left, right);
-#			else
-                          return gc_new Node0(MakeTree(iDepth-1),
-                                         		 MakeTree(iDepth-1));
-#			endif
-#		     else
-                        return new Node0(MakeTree(iDepth-1),
-                                         MakeTree(iDepth-1));
-#		     endif
-                }
-        }
-
-        static void PrintDiagnostics() {
-#if 0
-                long lFreeMemory = Runtime.getRuntime().freeMemory();
-                long lTotalMemory = Runtime.getRuntime().totalMemory();
-
-                System.out.print(" Total memory available="
-                                 + lTotalMemory + " bytes");
-                System.out.println("  Free memory=" + lFreeMemory + " bytes");
-#endif
-        }
-
-        static void TimeConstruction(int depth) {
-                long    tStart, tFinish;
-                int     iNumIters = NumIters(depth);
-                Node    tempTree;
-
-                cout << "Creating " << iNumIters
-                     << " trees of depth " << depth << endl;
-                
-                tStart = currentTime();
-                for (int i = 0; i < iNumIters; ++i) {
-#			if defined(GC)
-                          tempTree = new (GC_NEW(Node0)) Node0();
-#			elif defined(OGC)
-                          tempTree = gc_new Node0();
-#			else
-                          tempTree = new Node0();
-#			endif
-                        Populate(depth, tempTree);
-#		        if !defined(GC) && !defined(OGC)
-                          delete tempTree;
-#			endif
-                        tempTree = 0;
-                }
-                tFinish = currentTime();
-                cout << "\tTop down construction took "
-                     << elapsedTime(tFinish - tStart) << " msec" << endl;
-                     
-                tStart = currentTime();
-                for (int i = 0; i < iNumIters; ++i) {
-                        tempTree = MakeTree(depth);
-#			if !defined(GC) && !defined(OGC)
-                          delete tempTree;
-#			endif
-                        tempTree = 0;
-                }
-                tFinish = currentTime();
-                cout << "\tBottom up construction took "
-                     << elapsedTime(tFinish - tStart) << " msec" << endl;
-
-        }
-
-        void main() {
-                Node    root;
-                Node    longLivedTree;
-                Node    tempTree;
-                long    tStart, tFinish;
-                long    tElapsed;
-
-#ifdef GC
-// GC_full_freq = 30;
-GC_enable_incremental();
-#endif
-
-#	        ifdef OGC
-		  GC::SetPolicy(100);
-#		endif
-                cout << "Garbage Collector Test" << endl;
-                cout << " Live storage will peak at "
-                     << 2 * sizeof(Node0) * TreeSize(kLongLivedTreeDepth) +
-                        sizeof(double) * kArraySize
-                     << " bytes." << endl << endl;
-                cout << " Stretching memory with a binary tree of depth "
-                     << kStretchTreeDepth << endl;
-                PrintDiagnostics();
-               
-                tStart = currentTime();
-                
-                // Stretch the memory space quickly
-                tempTree = MakeTree(kStretchTreeDepth);
-#		if !defined(GC) && !defined(OGC)
-                  delete tempTree;
-#		endif
-                tempTree = 0;
-
-                // Create a long lived object
-                cout << " Creating a long-lived binary tree of depth "
-                     << kLongLivedTreeDepth << endl;
-#		if defined(GC)
-                  longLivedTree = new (GC_NEW(Node0)) Node0();
-#	        elif defined(OGC)
-                  longLivedTree = gc_new Node0();
-#		else 
-                  longLivedTree = new Node0();
-#		endif
-                Populate(kLongLivedTreeDepth, longLivedTree);
-
-                // Create long-lived array, filling half of it
-                cout << " Creating a long-lived array of "
-                     << kArraySize << " doubles" << endl;
-#		if defined(GC)
-                  double *array = (double *)
-				GC_MALLOC(sizeof(double) * kArraySize);
-#		else
-                  double *array = new double[kArraySize];
-#		endif
-                for (int i = 0; i < kArraySize/2; ++i) {
-                        array[i] = 1.0/i;
-                }
-                PrintDiagnostics();
-
-                for (int d = kMinTreeDepth; d <= kMaxTreeDepth; d += 2)
-{
-                        TimeConstruction(d);
-                }
-
-                if (longLivedTree == 0 || array[1000] != 1.0/1000)
-                        cout << "Failed" << endl;
-                                        // fake reference to LongLivedTree
-                                        // and array
-                                        // to keep them from being optimized away
-
-                tFinish = currentTime();
-                tElapsed = elapsedTime(tFinish-tStart);
-                PrintDiagnostics();
-                cout << "Completed in " << tElapsed << " msec" << endl;
-#		ifdef GC
-		  cout << "Completed " << GC_gc_no << " collections" <<endl;
-		  cout << "Heap size is " << GC_get_heap_size() << endl;
-#		endif
-        }
-};
-
-main () {
-    GCBench x;
-    x.main();
-}
-
diff --git a/tests/bench/gcbench.nim b/tests/bench/gcbench.nim
deleted file mode 100644
index 9f69b0cdc..000000000
--- a/tests/bench/gcbench.nim
+++ /dev/null
@@ -1,172 +0,0 @@
-# This is adapted from a benchmark written by John Ellis and Pete Kovac

-#   of Post Communications.

-#   It was modified by Hans Boehm of Silicon Graphics.

-#

-# 	This is no substitute for real applications.  No actual application

-#	is likely to behave in exactly this way.  However, this benchmark was

-#	designed to be more representative of real applications than other

-#	Java GC benchmarks of which we are aware.

-#	It attempts to model those properties of allocation requests that

-#	are important to current GC techniques.

-#	It is designed to be used either to obtain a single overall performance

-#	number, or to give a more detailed estimate of how collector

-#	performance varies with object lifetimes.  It prints the time

-#	required to allocate and collect balanced binary trees of various

-#	sizes.  Smaller trees result in shorter object lifetimes.  Each cycle

-#	allocates roughly the same amount of memory.

-#	Two data structures are kept around during the entire process, so

-#	that the measured performance is representative of applications

-#	that maintain some live in-memory data.  One of these is a tree

-#	containing many pointers.  The other is a large array containing

-#	double precision floating point numbers.  Both should be of comparable

-#	size.

-#

-#	The results are only really meaningful together with a specification

-#	of how much memory was used.  It is possible to trade memory for

-#	better time performance.  This benchmark should be run in a 32 MB

-#	heap, though we don't currently know how to enforce that uniformly.

-#

-#	Unlike the original Ellis and Kovac benchmark, we do not attempt

-# 	measure pause times.  This facility should eventually be added back

-#	in.  There are several reasons for omitting it for now.  The original

-#	implementation depended on assumptions about the thread scheduler

-#	that don't hold uniformly.  The results really measure both the

-#	scheduler and GC.  Pause time measurements tend to not fit well with

-#	current benchmark suites.  As far as we know, none of the current

-#	commercial Java implementations seriously attempt to minimize GC pause

-#	times.

-#

-#	Known deficiencies:

-#		- No way to check on memory use

-#		- No cyclic data structures

-#		- No attempt to measure variation with object size

-#		- Results are sensitive to locking cost, but we dont

-#		  check for proper locking

-#

-

-import

-  io, strutils, times

-

-type

-  PNode = ref TNode

-  TNode = record

-    left, right: PNode

-    i, j: int

-

-proc newNode(l, r: PNode): PNode =

-  new(result)

-  result.left = l

-  result.right = r

-

-const

-  kStretchTreeDepth = 18 # about 16Mb

-  kLongLivedTreeDepth = 16  # about 4Mb

-  kArraySize  = 500000  # about 4Mb

-  kMinTreeDepth = 4

-  kMaxTreeDepth = 16

-

-# Nodes used by a tree of a given size

-proc TreeSize(i: int): int = return ((1 shl (i + 1)) - 1)

-

-# Number of iterations to use for a given tree depth

-proc NumIters(i: int): int =

-  return 2 * TreeSize(kStretchTreeDepth) div TreeSize(i)

-

-# Build tree top down, assigning to older objects.

-proc Populate(iDepth: int, thisNode: PNode) =

-  if iDepth <= 0:

-    return

-  else:

-    new(thisNode.left)

-    new(thisNode.right)

-    Populate(iDepth-1, thisNode.left)

-    Populate(iDepth-1, thisNode.right)

-

-# Build tree bottom-up

-proc MakeTree(iDepth: int): PNode =

-  if iDepth <= 0:

-    new(result)

-  else:

-    return newNode(MakeTree(iDepth-1),

-                   MakeTree(iDepth-1))

-

-proc PrintDiagnostics() =

-  var

-    FreeMemory = getFreeMem()

-    TotalMemory = getTotalMem()

-

-  echo("Total memory available: " & $TotalMemory & " bytes")

-  echo("Free memory: " & $FreeMemory & " bytes")

-

-proc TimeConstruction(depth: int) =

-  var

-    root, tempTree: PNode

-    t: int

-    iNumIters: int

-

-  iNumIters = NumIters(depth)

-

-  echo("Creating " & $iNumIters & " trees of depth " & $depth)

-  t = getStartMilsecs()

-  for i in 0..iNumIters-1:

-    new(tempTree)

-    Populate(depth, tempTree)

-    tempTree = nil

-  echo("\tTop down construction took " &

-                     $(getStartMilsecs() - t) & "msecs")

-  t = getStartMilsecs()

-  for i in 0..iNumIters-1:

-    tempTree = MakeTree(depth)

-    tempTree = nil

-  echo("\tBottom up construction took " &

-                     $(getStartMilsecs() - t) & "msecs")

-

-type

-  tMyArray = seq[float]

-

-proc main() =

-  var

-    root, longLivedTree, tempTree: PNode

-    t: int

-    myarray: tMyArray

-

-  echo("Garbage Collector Test")

-  echo(" Stretching memory with a binary tree of depth " &

-       $kStretchTreeDepth)

-  PrintDiagnostics()

-  t = getStartMilsecs()

-

-  # Stretch the memory space quickly

-  tempTree = MakeTree(kStretchTreeDepth)

-  tempTree = nil

-

-  # Create a long lived object

-  echo(" Creating a long-lived binary tree of depth " &

-        $kLongLivedTreeDepth)

-  new(longLivedTree)

-  Populate(kLongLivedTreeDepth, longLivedTree)

-

-  # Create long-lived array, filling half of it

-  echo(" Creating a long-lived array of " & $kArraySize & " doubles")

-  myarray = []

-  setlength(myarray, kArraySize)

-  for i in 0..kArraySize div 2 -1:

-    myarray[i] = 1.0 / toFloat(i)

-

-  PrintDiagnostics()

-

-  var d = kMinTreeDepth

-  while d <= kMaxTreeDepth:

-    TimeConstruction(d)

-    inc(d, 2)

-

-  if longLivedTree == nil or myarray[1000] != 1.0/1000.0:

-    echo("Failed")

-    # fake reference to LongLivedTree

-    # and array to keep them from being optimized away

-

-  var elapsed = getStartMilsecs() - t

-  PrintDiagnostics()

-  echo("Completed in " & $elapsed & "ms.")

-

-main()

diff --git a/tests/bench/prof.c b/tests/bench/prof.c
deleted file mode 100644
index cd91fa339..000000000
--- a/tests/bench/prof.c
+++ /dev/null
@@ -1,63 +0,0 @@
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-/* A very simple profiler.  Note that it should be possible to	*/
-/* get function level information by concatenating this with nm	*/
-/* output and running the result through the sort utility.	*/
-/* This assumes that all interesting parts of the executable	*/
-/* are statically linked.					*/
-
-static size_t buf_size;
-static u_short *profil_buf;
-
-# ifdef __i386__
-#   ifndef COMPRESSION
-#     define COMPRESSION 1
-#   endif
-#   define TEXT_START 0x08000000
-#   define PTR_DIGS 8
-# endif
-# ifdef __ia64__
-#   ifndef COMPRESSION
-#     define COMPRESSION 8
-#   endif
-#   define TEXT_START 0x4000000000000000
-#   define PTR_DIGS 16 
-# endif
-
-extern int etext;
-
-/*
- * Note that the ith entry in the profile buffer corresponds to
- * a PC value of TEXT_START + i * COMPRESSION * 2.
- * The extra factor of 2 is not apparent from the documentation,
- * but it is explicit in the glibc source.
- */
-
-void init_profiling()
-{
-    buf_size = ((size_t)(&etext) - TEXT_START + 0x10)/COMPRESSION/2;
-    profil_buf = calloc(buf_size, sizeof(u_short));
-    if (profil_buf == 0) {
-	fprintf(stderr, "Could not allocate profile buffer\n");
-    }
-    profil(profil_buf, buf_size * sizeof(u_short),
-	   TEXT_START, 65536/COMPRESSION);
-}
-
-void dump_profile()
-{
-    size_t i;
-    size_t sum = 0;
-    for (i = 0; i < buf_size; ++i) {
-	if (profil_buf[i] != 0) {
-	    fprintf(stderr, "%0*lx\t%d !PROF!\n",
-		    PTR_DIGS,
-		    TEXT_START + i * COMPRESSION * 2,
-		    profil_buf[i]);
-	    sum += profil_buf[i];
-	}
-    }
-    fprintf(stderr, "Total number of samples was %ld !PROF!\n", sum);
-}
diff --git a/tests/gc.bpf b/tests/gc.bpf
deleted file mode 100644
index e56372389..000000000
--- a/tests/gc.bpf
+++ /dev/null
@@ -1,9 +0,0 @@
-USEUNIT("morc_gen\gctest.c");

-USEUNIT("..\lib\dlmalloc.c");

-USEUNIT("..\lib\morc_gen\io.c");

-USEUNIT("..\lib\morc_gen\strutils.c");

-USEUNIT("..\lib\morc_gen\system.c");

-//---------------------------------------------------------------------------

-This file is used by the project manager only and should be treated like the project file

-
-
main
\ No newline at end of file
diff --git a/tests/gc.bpr b/tests/gc.bpr
deleted file mode 100644
index 8e72b1d86..000000000
--- a/tests/gc.bpr
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version='1.0' encoding='utf-8' ?>

-<!-- C++Builder XML Project -->

-<PROJECT>

-  <MACROS>

-    <VERSION value="BCB.05.03"/>

-    <PROJECT value="gc.exe"/>

-    <OBJFILES value="morc_gen\gctest.obj ..\lib\dlmalloc.obj ..\lib\morc_gen\io.obj 

-      ..\lib\morc_gen\strutils.obj ..\lib\morc_gen\system.obj"/>

-    <RESFILES value=""/>

-    <DEFFILE value=""/>

-    <RESDEPEN value="$(RESFILES)"/>

-    <LIBFILES value=""/>

-    <LIBRARIES value=""/>

-    <SPARELIBS value=""/>

-    <PACKAGES value="Vcl50.bpi Vclx50.bpi bcbsmp50.bpi dclocx50.bpi bcb2kaxserver50.bpi"/>

-    <PATHCPP value=".;morc_gen;..\lib;..\lib\morc_gen"/>

-    <PATHPAS value=".;"/>

-    <PATHRC value=".;"/>

-    <PATHASM value=".;"/>

-    <DEBUGLIBPATH value="$(BCB)\lib\debug"/>

-    <RELEASELIBPATH value="$(BCB)\lib\release"/>

-    <LINKER value="tlink32"/>

-    <USERDEFINES value="_DEBUG"/>

-    <SYSDEFINES value="NO_STRICT;_NO_VCL;_RTLDLL;USEPACKAGES"/>

-    <MAINSOURCE value="gc.bpf"/>

-    <INCLUDEPATH value="..\lib\morc_gen;..\lib;morc_gen;$(BCB)\include;$(BCB)\include\vcl"/>

-    <LIBPATH value="..\lib\morc_gen;..\lib;morc_gen;$(BCB)\lib\obj;$(BCB)\lib"/>

-    <WARNINGS value="-w-par"/>

-  </MACROS>

-  <OPTIONS>

-    <CFLAG1 value="-tWC -tWM- -Od -H=$(BCB)\lib\vcl50.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y 

-      -v -vi- -c"/>

-    <PFLAGS value="-$YD -$W -$O- -v -JPHNE -M"/>

-    <RFLAGS value=""/>

-    <AFLAGS value="/mx /w2 /zd"/>

-    <LFLAGS value="-Tpe -ap -D&quot;&quot; -x -Gn -v"/>

-  </OPTIONS>

-  <LINKER>

-    <ALLOBJ value="c0x32.obj $(PACKAGES) $(OBJFILES)"/>

-    <ALLRES value="$(RESFILES)"/>

-    <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cw32i.lib"/>

-  </LINKER>

-  <IDEOPTIONS>

-[Version Info]

-IncludeVerInfo=0

-AutoIncBuild=0

-MajorVer=1

-MinorVer=0

-Release=0

-Build=0

-Debug=0

-PreRelease=0

-Special=0

-Private=0

-DLL=0

-Locale=1031

-CodePage=1252

-

-[Version Info Keys]

-CompanyName=

-FileDescription=

-FileVersion=1.0.0.0

-InternalName=

-LegalCopyright=

-LegalTrademarks=

-OriginalFilename=

-ProductName=

-ProductVersion=1.0.0.0

-Comments=

-

-[Debugging]

-DebugSourceDirs=$(BCB)\source\vcl

-

-[Parameters]

-RunParams=

-HostApplication=

-RemoteHost=

-RemotePath=

-RemoteDebug=0

-

-[Compiler]

-ShowInfoMsgs=0

-LinkDebugVcl=0

-  </IDEOPTIONS>

-</PROJECT>
\ No newline at end of file
diff --git a/tests/gctest.nim b/tests/gctest.nim
index b0f5ff8ce..60845033c 100644
--- a/tests/gctest.nim
+++ b/tests/gctest.nim
@@ -6,31 +6,40 @@ import
 
 type
   PNode = ref TNode
-  TNode = record
+  TNode {.final.} = object
     le, ri: PNode
     data: string
 
-  TTable = record
+  TTable {.final.} = object
     counter, max: int
     data: seq[string]
 
-  TBNode = record
+  TBNode {.final.} = object
     other: PNode  # a completely different tree
     data: string
     sons: seq[TBNode] # directly embedded!
     t: TTable
     
-  TCaseKind = enum nkStr, nkList
+  TCaseKind = enum nkStr, nkWhole, nkList
   PCaseNode = ref TCaseNode
-  TCaseNode = record
+  TCaseNode {.final.} = object
     case kind: TCaseKind
     of nkStr: data: string
     of nkList: sons: seq[PCaseNode]
+    else: unused: seq[string]
+
+var
+  flip: int
 
 proc newCaseNode(data: string): PCaseNode =
   new(result)
-  result.kind = nkStr
-  result.data = data
+  if flip == 0:
+    result.kind = nkStr
+    result.data = data
+  else:
+    result.kind = nkWhole
+    result.unused = ["", "abc", "abdc"]
+  flip = 1 - flip
   
 proc newCaseNode(a, b: PCaseNode): PCaseNode =
   new(result)
@@ -44,7 +53,8 @@ proc caseTree(lvl: int = 0): PCaseNode =
 proc finalizeBNode(n: TBNode) = writeln(stdout, n.data)
 proc finalizeNode(n: PNode) =
   assert(n != nil)
-  writeln(stdout, n.data)
+  if isNil(n.data): writeln(stdout, "nil!")
+  else: writeln(stdout, n.data)
 
 var
   id: int = 1
diff --git a/tests/hallo.bpf b/tests/hallo.bpf
deleted file mode 100644
index 530b73a54..000000000
--- a/tests/hallo.bpf
+++ /dev/null
@@ -1,10 +0,0 @@
-USEUNIT("rod_gen\thallo.c");

-USEUNIT("..\lib\rod_gen\os.c");

-USEUNIT("..\lib\rod_gen\strutils.c");

-USEUNIT("..\lib\rod_gen\system.c");

-USEUNIT("..\lib\rod_gen\times.c");

-USEUNIT("..\lib\dlmalloc.c");

-//---------------------------------------------------------------------------

-This file is used by the project manager only and should be treated like the project file

-
-
main
\ No newline at end of file
diff --git a/tests/hallo.bpr b/tests/hallo.bpr
deleted file mode 100644
index 9ba49b99c..000000000
--- a/tests/hallo.bpr
+++ /dev/null
@@ -1,102 +0,0 @@
-<?xml version='1.0' encoding='utf-8' ?>

-<!-- C++Builder XML Project -->

-<PROJECT>

-  <MACROS>

-    <VERSION value="BCB.05.03"/>

-    <PROJECT value="hallo.exe"/>

-    <OBJFILES value="rod_gen\thallo.obj ..\lib\rod_gen\os.obj ..\lib\rod_gen\strutils.obj 

-      ..\lib\rod_gen\system.obj ..\lib\rod_gen\times.obj ..\lib\dlmalloc.obj"/>

-    <RESFILES value=""/>

-    <DEFFILE value=""/>

-    <RESDEPEN value="$(RESFILES)"/>

-    <LIBFILES value=""/>

-    <LIBRARIES value=""/>

-    <SPARELIBS value=""/>

-    <PACKAGES value="Vcl50.bpi Vclx50.bpi bcbsmp50.bpi dclocx50.bpi bcb2kaxserver50.bpi"/>

-    <PATHCPP value=".;rod_gen;..\lib\rod_gen;..\lib"/>

-    <PATHPAS value=".;"/>

-    <PATHRC value=".;"/>

-    <PATHASM value=".;"/>

-    <DEBUGLIBPATH value="$(BCB)\lib\debug"/>

-    <RELEASELIBPATH value="$(BCB)\lib\release"/>

-    <LINKER value="tlink32"/>

-    <USERDEFINES value="_DEBUG"/>

-    <SYSDEFINES value="NO_STRICT;_NO_VCL;_RTLDLL;USEPACKAGES"/>

-    <MAINSOURCE value="hallo.bpf"/>

-    <INCLUDEPATH value="..\lib\rod_gen;rod_gen;$(BCB)\include;$(BCB)\include\vcl;..\lib"/>

-    <LIBPATH value="..\lib;..\lib\rod_gen;rod_gen;$(BCB)\lib\obj;$(BCB)\lib"/>

-    <WARNINGS value="-w-par"/>

-  </MACROS>

-  <OPTIONS>

-    <CFLAG1 value="-Od -H=$(BCB)\lib\vcl50.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- -tWC 

-      -tWM- -c"/>

-    <PFLAGS value="-$YD -$W -$O- -v -JPHNE -M"/>

-    <RFLAGS value=""/>

-    <AFLAGS value="/mx /w2 /zd"/>

-    <LFLAGS value="-D&quot;&quot; -ap -Tpe -x -Gn -v"/>

-  </OPTIONS>

-  <LINKER>

-    <ALLOBJ value="c0x32.obj $(PACKAGES) $(OBJFILES)"/>

-    <ALLRES value="$(RESFILES)"/>

-    <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cw32i.lib"/>

-  </LINKER>

-  <IDEOPTIONS>

-[Version Info]

-IncludeVerInfo=0

-AutoIncBuild=0

-MajorVer=1

-MinorVer=0

-Release=0

-Build=0

-Debug=0

-PreRelease=0

-Special=0

-Private=0

-DLL=0

-Locale=1031

-CodePage=1252

-

-[Version Info Keys]

-CompanyName=

-FileDescription=

-FileVersion=1.0.0.0

-InternalName=

-LegalCopyright=

-LegalTrademarks=

-OriginalFilename=

-ProductName=

-ProductVersion=1.0.0.0

-Comments=

-

-[HistoryLists\hlIncludePath]

-Count=2

-Item0=..\lib\rod_gen;rod_gen;$(BCB)\include;$(BCB)\include\vcl;E:\nimrod\lib

-Item1=..\lib\rod_gen;rod_gen;$(BCB)\include;$(BCB)\include\vcl

-

-[HistoryLists\hlLibraryPath]

-Count=1

-Item0=..\lib\rod_gen;rod_gen;$(BCB)\lib\obj;$(BCB)\lib

-

-[HistoryLists\hlDebugSourcePath]

-Count=1

-Item0=$(BCB)\source\vcl

-

-[HistoryLists\hlConditionals]

-Count=1

-Item0=_DEBUG

-

-[Debugging]

-DebugSourceDirs=$(BCB)\source\vcl

-

-[Parameters]

-RunParams=

-HostApplication=

-RemoteHost=

-RemotePath=

-RemoteDebug=0

-

-[Compiler]

-ShowInfoMsgs=0

-LinkDebugVcl=0

-  </IDEOPTIONS>

-</PROJECT>
\ No newline at end of file
diff --git a/tests/iotest.bpf b/tests/iotest.bpf
deleted file mode 100644
index 2294271cc..000000000
--- a/tests/iotest.bpf
+++ /dev/null
@@ -1,10 +0,0 @@
-USEUNIT("tio.c");

-USEUNIT("..\lib\refcgc.c");

-USEUNIT("..\lib\io.c");

-USEUNIT("..\lib\morbase.c");

-USEUNIT("..\lib\morlib.c");

-//---------------------------------------------------------------------------

-This file is used by the project manager only and should be treated like the project file

-

-

-main
\ No newline at end of file
diff --git a/tests/iotest.bpr b/tests/iotest.bpr
deleted file mode 100644
index 187918550..000000000
--- a/tests/iotest.bpr
+++ /dev/null
@@ -1,84 +0,0 @@
-<?xml version='1.0' encoding='utf-8' ?>

-<!-- C++Builder XML Project -->

-<PROJECT>

-  <MACROS>

-    <VERSION value="BCB.05.03"/>

-    <PROJECT value="iotest.exe"/>

-    <OBJFILES value="tio.obj ..\lib\refcgc.obj ..\lib\io.obj ..\lib\morbase.obj ..\lib\morlib.obj"/>

-    <RESFILES value=""/>

-    <DEFFILE value=""/>

-    <RESDEPEN value="$(RESFILES)"/>

-    <LIBFILES value=""/>

-    <LIBRARIES value=""/>

-    <SPARELIBS value=""/>

-    <PACKAGES value="Vcl50.bpi Vclx50.bpi bcbsmp50.bpi dclocx50.bpi bcb2kaxserver50.bpi"/>

-    <PATHCPP value=".;..\lib"/>

-    <PATHPAS value=".;"/>

-    <PATHRC value=".;"/>

-    <PATHASM value=".;"/>

-    <DEBUGLIBPATH value="$(BCB)\lib\debug"/>

-    <RELEASELIBPATH value="$(BCB)\lib\release"/>

-    <LINKER value="tlink32"/>

-    <USERDEFINES value="_DEBUG"/>

-    <SYSDEFINES value="NO_STRICT;_NO_VCL;_RTLDLL;USEPACKAGES"/>

-    <MAINSOURCE value="iotest.bpf"/>

-    <INCLUDEPATH value="..\lib;$(BCB)\include;$(BCB)\include\vcl"/>

-    <LIBPATH value="..\lib;$(BCB)\lib\obj;$(BCB)\lib"/>

-    <WARNINGS value="-w-par"/>

-  </MACROS>

-  <OPTIONS>

-    <CFLAG1 value="-Od -H=$(BCB)\lib\vcl50.csm -Hc -w- -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- 

-      -tWC -tWM- -c"/>

-    <PFLAGS value="-$YD -$W -$O- -v -JPHNE -M"/>

-    <RFLAGS value=""/>

-    <AFLAGS value="/mx /w2 /zd"/>

-    <LFLAGS value="-D&quot;&quot; -ap -Tpe -x -Gn -v"/>

-  </OPTIONS>

-  <LINKER>

-    <ALLOBJ value="c0x32.obj $(PACKAGES) $(OBJFILES)"/>

-    <ALLRES value="$(RESFILES)"/>

-    <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cw32i.lib"/>

-  </LINKER>

-  <IDEOPTIONS>

-[Version Info]

-IncludeVerInfo=0

-AutoIncBuild=0

-MajorVer=1

-MinorVer=0

-Release=0

-Build=0

-Debug=0

-PreRelease=0

-Special=0

-Private=0

-DLL=0

-Locale=1031

-CodePage=1252

-

-[Version Info Keys]

-CompanyName=

-FileDescription=

-FileVersion=1.0.0.0

-InternalName=

-LegalCopyright=

-LegalTrademarks=

-OriginalFilename=

-ProductName=

-ProductVersion=1.0.0.0

-Comments=

-

-[Debugging]

-DebugSourceDirs=$(BCB)\source\vcl

-

-[Parameters]

-RunParams=

-HostApplication=

-RemoteHost=

-RemotePath=

-RemoteDebug=0

-

-[Compiler]

-ShowInfoMsgs=0

-LinkDebugVcl=0

-  </IDEOPTIONS>

-</PROJECT>
\ No newline at end of file
diff --git a/tests/minit.nim b/tests/minit.nim
index ce4cd23fa..d3b4b0be1 100644
--- a/tests/minit.nim
+++ b/tests/minit.nim
@@ -1,6 +1,2 @@
 # Test the new initialization for modules

-

-import

-  io

-

 write(stdout, "Hallo from module! ")

diff --git a/tests/mopaque.nim b/tests/mopaque.nim
index 17b8bba62..b7c5180fd 100644
--- a/tests/mopaque.nim
+++ b/tests/mopaque.nim
@@ -1,5 +1,5 @@
 type

-  TLexer* = record

+  TLexer* {.final.} = object

     line*: int

     filename*: string

     buffer: cstring

diff --git a/tests/rectest/rectest.nim b/tests/rectest/rectest.nim
deleted file mode 100644
index f08306cfd..000000000
--- a/tests/rectest/rectest.nim
+++ /dev/null
@@ -1,6 +0,0 @@
-# Test the error message

-

-proc main() =

-  main()

-

-main()

diff --git a/tests/scantest.nim b/tests/scantest.nim
index 559938d8e..c9779c762 100644
--- a/tests/scantest.nim
+++ b/tests/scantest.nim
@@ -12,7 +12,7 @@ import
   lexbase, os, strutils

 

 type

-  TMyRec = record # describes a record

+  TMyRec {.final.} = object

     x, y: int     # coordinates

     c: char       # a character

     a: int32      # an integer

diff --git a/tests/seqcon.bpf b/tests/seqcon.bpf
deleted file mode 100644
index 0f4cad131..000000000
--- a/tests/seqcon.bpf
+++ /dev/null
@@ -1,8 +0,0 @@
-USEUNIT("tseqcon.c");

-USEUNIT("..\lib\io.c");

-USEUNIT("..\lib\morsys.c");

-//---------------------------------------------------------------------------

-This file is used by the project manager only and should be treated like the project file

-

-

-main
\ No newline at end of file
diff --git a/tests/seqcon.bpr b/tests/seqcon.bpr
deleted file mode 100644
index 9160b20ee..000000000
--- a/tests/seqcon.bpr
+++ /dev/null
@@ -1,84 +0,0 @@
-<?xml version='1.0' encoding='utf-8' ?>

-<!-- C++Builder XML Project -->

-<PROJECT>

-  <MACROS>

-    <VERSION value="BCB.05.03"/>

-    <PROJECT value="seqcon.exe"/>

-    <OBJFILES value="tseqcon.obj ..\lib\io.obj ..\lib\morsys.obj"/>

-    <RESFILES value=""/>

-    <DEFFILE value=""/>

-    <RESDEPEN value="$(RESFILES)"/>

-    <LIBFILES value=""/>

-    <LIBRARIES value=""/>

-    <SPARELIBS value=""/>

-    <PACKAGES value="Vcl50.bpi Vclx50.bpi bcbsmp50.bpi dclocx50.bpi bcb2kaxserver50.bpi"/>

-    <PATHCPP value=".;..\lib"/>

-    <PATHPAS value=".;"/>

-    <PATHRC value=".;"/>

-    <PATHASM value=".;"/>

-    <DEBUGLIBPATH value="$(BCB)\lib\debug"/>

-    <RELEASELIBPATH value="$(BCB)\lib\release"/>

-    <LINKER value="tlink32"/>

-    <USERDEFINES value="_DEBUG"/>

-    <SYSDEFINES value="NO_STRICT;_NO_VCL;_RTLDLL;USEPACKAGES"/>

-    <MAINSOURCE value="seqcon.bpf"/>

-    <INCLUDEPATH value="..\lib;$(BCB)\include;$(BCB)\include\vcl"/>

-    <LIBPATH value="..\lib;$(BCB)\lib\obj;$(BCB)\lib"/>

-    <WARNINGS value="-w-par"/>

-  </MACROS>

-  <OPTIONS>

-    <CFLAG1 value="-Od -H=$(BCB)\lib\vcl50.csm -Hc -Vx -Ve -X- -r- -pr -a8 -b- -k -y -v -vi- 

-      -tWC -tWM- -c"/>

-    <PFLAGS value="-$YD -$W -$O- -v -JPHNE -M"/>

-    <RFLAGS value=""/>

-    <AFLAGS value="/mx /w2 /zd"/>

-    <LFLAGS value="-D&quot;&quot; -ap -Tpe -x -Gn -v"/>

-  </OPTIONS>

-  <LINKER>

-    <ALLOBJ value="c0x32.obj $(PACKAGES) $(OBJFILES)"/>

-    <ALLRES value="$(RESFILES)"/>

-    <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cw32i.lib"/>

-  </LINKER>

-  <IDEOPTIONS>

-[Version Info]

-IncludeVerInfo=0

-AutoIncBuild=0

-MajorVer=1

-MinorVer=0

-Release=0

-Build=0

-Debug=0

-PreRelease=0

-Special=0

-Private=0

-DLL=0

-Locale=1031

-CodePage=1252

-

-[Version Info Keys]

-CompanyName=

-FileDescription=

-FileVersion=1.0.0.0

-InternalName=

-LegalCopyright=

-LegalTrademarks=

-OriginalFilename=

-ProductName=

-ProductVersion=1.0.0.0

-Comments=

-

-[Debugging]

-DebugSourceDirs=$(BCB)\source\vcl

-

-[Parameters]

-RunParams=

-HostApplication=

-RemoteHost=

-RemotePath=

-RemoteDebug=0

-

-[Compiler]

-ShowInfoMsgs=0

-LinkDebugVcl=0

-  </IDEOPTIONS>

-</PROJECT>
\ No newline at end of file
diff --git a/tests/tack.nim b/tests/tack.nim
index 254f37d3c..59535e547 100644
--- a/tests/tack.nim
+++ b/tests/tack.nim
@@ -1,8 +1,5 @@
 # the Ackermann function

 

-import

-  io

-

 proc ack(x, y: int): int =

   if x != 0:

     if y != 0:

diff --git a/tests/tarray.nim b/tests/tarray.nim
index b2a6f0011..5eca2cfa1 100644
--- a/tests/tarray.nim
+++ b/tests/tarray.nim
@@ -1,13 +1,8 @@
 # simple check for one dimensional arrays

 

-import

-  io

-

 type

   TMyArray = array[0..2, int]

-  TMyRecord = record

-    x, y: int

-

+  TMyRecord = tuple[x, y: int]

 

 proc sum(a: TMyarray): int =

   result = 0

diff --git a/tests/tassert.nim b/tests/tassert.nim
index cb53153be..1eff23502 100644
--- a/tests/tassert.nim
+++ b/tests/tassert.nim
@@ -1,8 +1,5 @@
 # test assert and exception handling

 

-import

-  io

-

 proc callB() = assert(False)

 proc callA() = callB()

 proc callC() = callA()

@@ -10,10 +7,10 @@ proc callC() = callA()
 try:

   callC()

 except EAssertionFailed:

-  io.write(stdout, "assertion failure!\n")

+  write(stdout, "assertion failure!\n")

 except:

-  io.write(stdout, "unknown exception!\n")

+  write(stdout, "unknown exception!\n")

 finally:

-  io.write(stdout, "this shall be always written\n")

+  system.write(stdout, "this shall be always written\n")

 

 assert(false)

diff --git a/tests/tassign.nim b/tests/tassign.nim
index 8f98ad0f3..d5f846502 100644
--- a/tests/tassign.nim
+++ b/tests/tassign.nim
@@ -1,10 +1,7 @@
 # Test the assignment operator for complex types which need RTTI

 

-import

-  io

-

 type

-  TRec = record

+  TRec = object

     x, y: int

     s: string

     seq: seq[string]

@@ -19,15 +16,15 @@ proc test() =
   a.s = "Hallo!"

   a.seq = ["abc", "def", "ghi", "jkl"]

   a.arr = []

-  setLength(a.arr, 4)

+  setLen(a.arr, 4)

   a.arr[0] = []

   a.arr[1] = []

 

   b = a # perform a deep copy here!

   b.seq = ["xyz", "huch", "was", "soll"]

-  writeln(stdout, length(a.seq))

+  writeln(stdout, len(a.seq))

   writeln(stdout, a.seq[3])

-  writeln(stdout, length(b.seq))

+  writeln(stdout, len(b.seq))

   writeln(stdout, b.seq[3])

   writeln(stdout, b.y)

 

diff --git a/tests/tblock1.nim b/tests/tblock1.nim
index 3119be9c1..729bfd3e7 100644
--- a/tests/tblock1.nim
+++ b/tests/tblock1.nim
@@ -1,9 +1,6 @@
 # check for forward label and

 # for failure when label is not declared

 

-import

-  io

-

 proc main =

   block endLess:

     break endLess

diff --git a/tests/tconstr1.nim b/tests/tconstr1.nim
index 0ff7def97..994e55b86 100644
--- a/tests/tconstr1.nim
+++ b/tests/tconstr1.nim
@@ -1,14 +1,12 @@
 # Test array, record constructors

 

-import

-  io

-

 type

-  TComplexRecord = record

-    s: string

-    x, y: int

-    z: float

+  TComplexRecord = tuple[

+    s: string,

+    x, y: int,

+    z: float,

     chars: set[Char]

+  ]

 

 proc testSem =

   var

diff --git a/tests/tconstr2.nim b/tests/tconstr2.nim
index 9dc64e59d..4c27bd833 100644
--- a/tests/tconstr2.nim
+++ b/tests/tconstr2.nim
@@ -1,11 +1,12 @@
 # Test array, record constructors

 

 type

-  TComplexRecord = record

-    s: string

-    x, y: int

-    z: float

-    chars: set[char]

+  TComplexRecord = tuple[

+    s: string,

+    x, y: int,

+    z: float,

+    chars: set[char],

+  ]

 

 const

   things: array [0.., TComplexRecord] = [

diff --git a/tests/tcopy.nim b/tests/tcopy.nim
index efbe65ea4..81d72c7f2 100644
--- a/tests/tcopy.nim
+++ b/tests/tcopy.nim
@@ -1,7 +1,7 @@
 # tests the copy proc

 

 import

-  strutils, io

+  strutils

 

 proc main() =

   const

diff --git a/tests/tformat.nim b/tests/tformat.nim
index 01be0df3a..aba35504b 100644
--- a/tests/tformat.nim
+++ b/tests/tformat.nim
@@ -1,6 +1,6 @@
 # Tests the new format proc (including the & and &= operators)

 

-import strutils, io

+import strutils

 

 echo("Hi $1! How do you feel, $2?\n" % ["Andreas", "Rumpf"])

 #OUT Hi Andreas! How do you feel, Rumpf?

diff --git a/tests/tforwty.nim b/tests/tforwty.nim
index 3c43819aa..0f1d3697f 100644
--- a/tests/tforwty.nim
+++ b/tests/tforwty.nim
@@ -3,7 +3,7 @@
 type

   PSym = ref TSym

 

-  TSym = record

+  TSym = object

     next: PSym

 

 var s: PSym

diff --git a/tests/tforwty2.nim b/tests/tforwty2.nim
index 1e1bb7f55..32f86f135 100644
--- a/tests/tforwty2.nim
+++ b/tests/tforwty2.nim
@@ -6,14 +6,14 @@
 when defined(windows):

   type

     PSDL_semaphore = ptr TSDL_semaphore

-    TSDL_semaphore = record

+    TSDL_semaphore {.final.} = object

       id: uint32

       count: UInt32

 

 elif defined(linux):

   type

     PSDL_semaphore = ptr TSDL_semaphore

-    TSDL_semaphore = record

+    TSDL_semaphore {.final.} = object

       sem: Pointer             #PSem_t;

       when not defined(USE_NAMED_SEMAPHORES):

         sem_data: int

diff --git a/tests/tgeneric.nim b/tests/tgeneric.nim
deleted file mode 100644
index 276fe810d..000000000
--- a/tests/tgeneric.nim
+++ /dev/null
@@ -1,96 +0,0 @@
-struct vector3d
-{
-    float V[3];
-    inline float Evaluate( const int I ) const { return V[I]; }
-
-    template< class ta >
-    inline const vector3d& operator = ( const ta& Exp )
-    {
-        V[0] = Exp.Evaluate( 0 );
-        V[1] = Exp.Evaluate( 1 );
-        V[2] = Exp.Evaluate( 2 );
-    }
-};
-
-type
-  TVector3D = record
-    v: array [0..2, float]
-    
-  TSum[A, B] = record
-  TVecExpr2[A, B, op] = record
-    
-proc eval(a: TVector3d, i: int): float = a.v[i]
-proc eval[T, S](a: T, b: S, i: int): float = eval(a, i) + eval(b, i)
-
-proc `+` [T, S](a, b: TVector3d): TSum[T, S] = return vecExpr2[a, b, TSum]
-
-proc `=` [T](a: var TVector3d, b: T) =
-  a.v[0] = eval(b, 0)
-  a.v[1] = eval(b, 1)
-  a.v[2] = eval(b, 2)
-
-macro `=` (a: var TVector3d, b: expr) =
-  
-proc doSomething(a, b: TVector3d): TVector3d =
-  eliminateTemps:
-    result = a +^ b +^ a *^ a *^ 7
-  # result = a
-  # result +^= b
-  # tmp = a
-  # tmp *^= a
-  # tmp *^= 7
-  # result +^= tmp
-  
-macro vectorOptimizeExpr(n: expr): stmt =
-  # load the expr n[1] into n[0]
-  var e = n[1]
-  if binOp(e) and Operator(e) == "+^":
-    var m = flattenTree(n[1])
-    result = newAst(nkStmtList) # ``newAst`` is built-in for any macro
-    add(result, newAst(nkAsgn, n[0], m[1]))
-    var tmp: PNode = nil
-    for i in 2..m.len-1:
-      if BinOp(m[i]):
-        if tmp = nil: tmp = getTemp() # reuse temporary if possible
-        vectorOptimizeExpr(newAst(nkAsgn, tmp, m[i]))
-        add(result, newAst(nkCall, Operator(m) & "=", n[0], tmp))
-      else:
-        add(result, newAst(nkCall, Operator(m) & "=", n[0], m[i]))
-  
-macro eliminateTemps(s) {.check.} =
-  case s.kind
-  of nkAsgnStmt:
-    result = vectorOptimizeExpr(s)
-  else:
-    result = s
-    for i in 0..s.sons.len-1: result[i] = eliminateTemps(s[i])
- 
-struct sum
-{
-    template< class ta, class tb >
-    static inline float Evaluate( const int I, const ta& A, const tb& B )
-    { return A.Evaluate( I ) + B.Evaluate( I ); }
-};
-
- 
-
-template< class ta_a, class ta_b, class ta_eval >
-class vecexp_2
-{
-   const ta_a   Arg1;
-   const ta_b   Arg2;
-
-public:
-    inline vecexp_2( const ta_a& A1, const ta_b& A2 ) 
-     : Arg1( A1 ), Arg2( A2 ) {}
-    inline const float Evaluate ( const int I ) const
-    { return ta_eval::Evaluate( I, Arg1, Arg2 ); }
-};
- 
-
-template< class ta, class tb > inline
-vecexp_2< ta, tb, sum > 
-inline operator + ( const ta& A, const tb& B )
-{
-    return vecexp_2< const ta, const tb, sum >( A, B );
-}
\ No newline at end of file
diff --git a/tests/thallo.dot b/tests/thallo.dot
deleted file mode 100644
index d75155a10..000000000
--- a/tests/thallo.dot
+++ /dev/null
@@ -1,6 +0,0 @@
-digraph thallo {
-times -> strutils;
-os -> strutils;
-os -> times;
-thallo -> os;
-}
diff --git a/tests/thallo.nim b/tests/thallo.nim
index d8c6b3bef..b804dba1e 100644
--- a/tests/thallo.nim
+++ b/tests/thallo.nim
@@ -11,9 +11,28 @@ proc fac[T](x: T): T =
   if x <= 1: return 1
   else: return x * fac(x-1)
 
+macro macrotest(n: expr): stmt =
+  expectKind(n, nnkCall)
+  expectMinLen(n, 2)
+  result = newNimNode(nnkStmtList, n)
+  for i in 2..n.len-1:
+    result.add(newCall("write", n[1], n[i]))
+  result.add(newCall("writeln", n[1], newStrLitNode("")))
+
+macro debug(n: expr): stmt =
+  result = newNimNode(nnkStmtList, n)
+  for i in 1..n.len-1:
+    result.add(newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
+    result.add(newCall("write", newIdentNode("stdout"), newStrLitNode(": ")))
+    result.add(newCall("writeln", newIdentNode("stdout"), n[i]))
+
+macrotest(stdout, "finally", 4, 5, "variable", "argument lists")
+macrotest(stdout)
+
 #GC_disable()
 
 echo("This was compiled by Nimrod version " & system.nimrodVersion)
+writeln(stdout, "Hallo", " World", "!")
 
 echo(["a", "b", "c", "d"].len)
 for x in items(["What's", "your", "name", "?"]):
@@ -21,6 +40,13 @@ for x in items(["What's", "your", "name", "?"]):
 var `name` = readLine(stdin)
 {.breakpoint.}
 echo("Hi " & thallo.name & "!\n")
+debug(name)
+
+var testseq: seq[string] = [ "a", "b", "c", "d"]
+echo(repr(testseq))
+
+var dummy = "hallo"
+echo(copy(dummy, 2, 3))
 
 for i in 2..6:
   for j in countdown(i+4, 2):
diff --git a/tests/tillrec.nim b/tests/tillrec.nim
index 7c3e5f628..eba04a96a 100644
--- a/tests/tillrec.nim
+++ b/tests/tillrec.nim
@@ -1,11 +1,11 @@
 # test illegal recursive types

 

 type

-  TLegal = record

+  TLegal {.final.} = object

     x: int

     kids: seq[TLegal]

 

-  TIllegal = record

+  TIllegal {.final.} = object

     y: Int

     x: array[0..3, TIllegal]

   #ERROR_MSG illegal recursion in type 'TIllegal'

diff --git a/tests/tinit.nim b/tests/tinit.nim
index e882fa921..85475ce94 100644
--- a/tests/tinit.nim
+++ b/tests/tinit.nim
@@ -1,6 +1,6 @@
 # Test the new init section in modules

 

-import minit, io

+import minit

 

 write(stdout, "Hallo from main module!\n")

 #OUT Hallo from module! Hallo from main module!

diff --git a/tests/tinout.nim b/tests/tinout.nim
index fb7f3b8fd..b4fe2fb10 100644
--- a/tests/tinout.nim
+++ b/tests/tinout.nim
@@ -1,6 +1,6 @@
 # Test in out checking for parameters

 

-proc abc(x: out int) =

+proc abc(x: var int) =

     x = 0

 

 proc b() =

diff --git a/tests/tio.nim b/tests/tio.nim
index ce024f754..014c32d9f 100644
--- a/tests/tio.nim
+++ b/tests/tio.nim
@@ -1,10 +1,7 @@
 # test the file-IO

 

-import

-  io

-

 proc main() =

-  for line in lines("thallo.mor"):

+  for line in lines("thallo.nim"):

     writeln(stdout, line)

 

 main()

diff --git a/tests/titer.nim b/tests/titer.nim
index 736ba3155..536e2f60d 100644
--- a/tests/titer.nim
+++ b/tests/titer.nim
@@ -1,8 +1,5 @@
 # Test the new iterators

 

-import

-  io

-

 iterator xrange(fromm, to: int, step = 1): (a: int) =

   a = fromm

   while a <= to:

diff --git a/tests/tlastmod.nim b/tests/tlastmod.nim
index af00e5bf4..b84147c62 100644
--- a/tests/tlastmod.nim
+++ b/tests/tlastmod.nim
@@ -1,7 +1,7 @@
 # test the new LastModificationTime() proc

 

 import

-  io, os, times

+  os, times

 

 proc main() =

   var

diff --git a/tests/tloops.nim b/tests/tloops.nim
index de3f4a777..3d03256ad 100644
--- a/tests/tloops.nim
+++ b/tests/tloops.nim
@@ -1,8 +1,5 @@
 # Test nested loops and some other things

 

-import

-  io

-

 proc andTest() =

   var a = 0 == 5 and 6 == 6

 

@@ -60,7 +57,7 @@ proc Foo(n: int): int =
     while b:

         a = a + 3

     a = a + 5

-    io.write(stdout, "Hallo!")

+    write(stdout, "Hallo!")

 

 

 # We should come till here :-)

diff --git a/tests/tlowhigh.nim b/tests/tlowhigh.nim
index 6553da2b5..79f5c5b95 100644
--- a/tests/tlowhigh.nim
+++ b/tests/tlowhigh.nim
@@ -1,8 +1,5 @@
 # Test the magic low() and high() procs

 

-import

-  io

-

 type

   myEnum = enum e1, e2, e3, e4, e5

 

diff --git a/tests/tmath.nim b/tests/tmath.nim
index d640f04d9..5a10cafb3 100644
--- a/tests/tmath.nim
+++ b/tests/tmath.nim
@@ -1,8 +1,5 @@
 # tests for the interpreter

 

-import

-  io

-

 proc loops(a: out int) =

   nil

   #var

diff --git a/tests/tnestif.nim b/tests/tnestif.nim
index 673aca062..558fe8d07 100644
--- a/tests/tnestif.nim
+++ b/tests/tnestif.nim
@@ -1,8 +1,5 @@
 # test nested ifs

 

-import

-  io

-

 var

     x, y: int

 x = 2

diff --git a/tests/tnew.bpf b/tests/tnew.bpf
deleted file mode 100644
index ab5aa4dbe..000000000
--- a/tests/tnew.bpf
+++ /dev/null
@@ -1,10 +0,0 @@
-USEUNIT("tnew.c");

-USEUNIT("..\lib\io.c");

-USEUNIT("..\lib\markstck.c");

-USEUNIT("..\lib\morsys.c");

-USEUNIT("..\lib\dlmalloc.c");

-//---------------------------------------------------------------------------

-This file is used by the project manager only and should be treated like the project file

-

-

-main
\ No newline at end of file
diff --git a/tests/tnew.bpr b/tests/tnew.bpr
deleted file mode 100644
index 3a7b2e0bf..000000000
--- a/tests/tnew.bpr
+++ /dev/null
@@ -1,84 +0,0 @@
-<?xml version='1.0' encoding='utf-8' ?>

-<!-- C++Builder XML Project -->

-<PROJECT>

-  <MACROS>

-    <VERSION value="BCB.05.03"/>

-    <PROJECT value="tnew.exe"/>

-    <OBJFILES value="tnew.obj ..\lib\io.obj ..\lib\markstck.obj ..\lib\morsys.obj 

-      ..\lib\dlmalloc.obj"/>

-    <RESFILES value=""/>

-    <DEFFILE value=""/>

-    <RESDEPEN value="$(RESFILES)"/>

-    <LIBFILES value=""/>

-    <LIBRARIES value=""/>

-    <SPARELIBS value=""/>

-    <PACKAGES value="Vcl50.bpi Vclx50.bpi bcbsmp50.bpi dclocx50.bpi bcb2kaxserver50.bpi"/>

-    <PATHCPP value=".;..\lib"/>

-    <PATHPAS value=".;"/>

-    <PATHRC value=".;"/>

-    <PATHASM value=".;"/>

-    <DEBUGLIBPATH value="$(BCB)\lib\debug"/>

-    <RELEASELIBPATH value="$(BCB)\lib\release"/>

-    <LINKER value="tlink32"/>

-    <USERDEFINES value="_DEBUG"/>

-    <SYSDEFINES value="NO_STRICT;_NO_VCL;_RTLDLL;USEPACKAGES"/>

-    <MAINSOURCE value="tnew.bpf"/>

-    <INCLUDEPATH value="..\lib;$(BCB)\include;$(BCB)\include\vcl"/>

-    <LIBPATH value="..\lib;$(BCB)\lib\obj;$(BCB)\lib"/>

-    <WARNINGS value="-w-par"/>

-  </MACROS>

-  <OPTIONS>

-    <CFLAG1 value="-Od -Vx -Ve -X- -r- -pr -a8 -b- -k -y -v -vi- -tWC -tWM- -c"/>

-    <PFLAGS value="-$YD -$W -$O- -v -JPHNE -M"/>

-    <RFLAGS value=""/>

-    <AFLAGS value="/mx /w2 /zd"/>

-    <LFLAGS value="-D&quot;&quot; -ap -Tpe -x -Gn -v"/>

-  </OPTIONS>

-  <LINKER>

-    <ALLOBJ value="c0x32.obj $(PACKAGES) $(OBJFILES)"/>

-    <ALLRES value="$(RESFILES)"/>

-    <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cw32i.lib"/>

-  </LINKER>

-  <IDEOPTIONS>

-[Version Info]

-IncludeVerInfo=0

-AutoIncBuild=0

-MajorVer=1

-MinorVer=0

-Release=0

-Build=0

-Debug=0

-PreRelease=0

-Special=0

-Private=0

-DLL=0

-Locale=1031

-CodePage=1252

-

-[Version Info Keys]

-CompanyName=

-FileDescription=

-FileVersion=1.0.0.0

-InternalName=

-LegalCopyright=

-LegalTrademarks=

-OriginalFilename=

-ProductName=

-ProductVersion=1.0.0.0

-Comments=

-

-[Debugging]

-DebugSourceDirs=$(BCB)\source\vcl

-

-[Parameters]

-RunParams=

-HostApplication=

-RemoteHost=

-RemotePath=

-RemoteDebug=0

-

-[Compiler]

-ShowInfoMsgs=0

-LinkDebugVcl=0

-  </IDEOPTIONS>

-</PROJECT>
\ No newline at end of file
diff --git a/tests/tobject2.nim b/tests/tobject2.nim
index 2853adc28..e8e932422 100644
--- a/tests/tobject2.nim
+++ b/tests/tobject2.nim
@@ -1,8 +1,5 @@
 # Tests the object implementation
 
-import
-  io
-
 type
   TPoint2d = object
     x, y: int
diff --git a/tests/tobjects.nim b/tests/tobjects.nim
index 54e1bd3ac..633c9d6af 100644
--- a/tests/tobjects.nim
+++ b/tests/tobjects.nim
@@ -1,6 +1,3 @@
-import

-  io

-

 type

   TBase = object

     x, y: int

diff --git a/tests/toverflw.nim b/tests/toverflw.nim
index 97234d702..c8f194e68 100644
--- a/tests/toverflw.nim
+++ b/tests/toverflw.nim
@@ -1,8 +1,5 @@
 # Tests emc's ability to detect overflows

 

-import

-  io

-

 {.push overflowChecks: on.}

 

 var

diff --git a/tests/toverl.nim b/tests/toverl.nim
index 469cfb934..1a571ce12 100644
--- a/tests/toverl.nim
+++ b/tests/toverl.nim
@@ -1,7 +1,7 @@
 # Test for overloading

 

 type

-  TNone {.export: "_NONE".} = record

+  TNone {.export: "_NONE", final.} = object

 

 proc

   TNone(a, b: int) = nil #ERROR_MSG attempt to redefine 'TNone'

diff --git a/tests/toverlop.nim b/tests/toverlop.nim
index 038760ae5..037da24ee 100644
--- a/tests/toverlop.nim
+++ b/tests/toverlop.nim
@@ -1,8 +1,5 @@
 # Test operator overloading

 

-import

-  io

-

 proc % (a, b: int): int =

   return a mod b

 

diff --git a/tests/tovfint.nim b/tests/tovfint.nim
index 223e78331..91eda8d0b 100644
--- a/tests/tovfint.nim
+++ b/tests/tovfint.nim
@@ -1,11 +1,8 @@
 # this tests the new overflow literals

 

-import

-  io

-

 var

   i: int

-i = cast[int](0xffffffff)

+i = int(0xffffffff)

 when defined(cpu64):

   if i == 4294967295:

     write(stdout, "works!\n")

diff --git a/tests/tpos.nim b/tests/tpos.nim
index 9d3223d24..114d39c05 100644
--- a/tests/tpos.nim
+++ b/tests/tpos.nim
@@ -1,8 +1,5 @@
 # test this particular function

 

-import

-  io

-

 proc mypos(sub, s: string, start: int = 0): int =

   var

     i, j, M, N: int

diff --git a/tests/tprep.nim b/tests/tprep.nim
index 3e8068872..999b2f57f 100644
--- a/tests/tprep.nim
+++ b/tests/tprep.nim
@@ -1,7 +1,7 @@
 # Test the features that used to belong to the preprocessor
 
 import
-  io, times
+  times
 
 {.warning: "This is only a test warning!".}
 
diff --git a/tests/tprocvar.nim b/tests/tprocvar.nim
index da757f682..ec23dcb1d 100644
--- a/tests/tprocvar.nim
+++ b/tests/tprocvar.nim
@@ -1,8 +1,5 @@
 # test variables of type proc

 

-import

-  io

-

 var

   x: proc (a, b: int): int {.cdecl.}

 

diff --git a/tests/tpush.nim b/tests/tpush.nim
index c1be04ec7..5fb411a79 100644
--- a/tests/tpush.nim
+++ b/tests/tpush.nim
@@ -1,8 +1,5 @@
 # test the new pragmas

 

-import

-  io

-

 {.push warnings: off, hints: off.}

 proc noWarning() =

   var

diff --git a/tests/tquit.nim b/tests/tquit.nim
index fedaa58b4..d4dc1522d 100644
--- a/tests/tquit.nim
+++ b/tests/tquit.nim
@@ -1,8 +1,5 @@
 # Test the new beforeQuit variable: 

 

-import

-  io

-

 proc myExit() {.noconv.} = 

   write(stdout, "just exiting...\n")

 

diff --git a/tests/treadln.nim b/tests/treadln.nim
index 3968f02d0..473eb1eaa 100644
--- a/tests/treadln.nim
+++ b/tests/treadln.nim
@@ -1,9 +1,6 @@
 # test the improved readline handling that does not care whether its
 # Macintosh, Unix or Windows text format.
 
-import
-  io
-
 var
   inp: tTextFile
   line: string
diff --git a/tests/trectype.nim b/tests/trectype.nim
index 4582d6d41..8e68767b5 100644
--- a/tests/trectype.nim
+++ b/tests/trectype.nim
@@ -6,7 +6,7 @@ type
   TA = array [0..2, PA]

 

   PRec = ref TRec

-  TRec = record

+  TRec {.final.} = object

     a, b: TA

 

   P1 = ref T1

diff --git a/tests/trefs.nim b/tests/trefs.nim
index 138d3eb93..ab3934088 100644
--- a/tests/trefs.nim
+++ b/tests/trefs.nim
@@ -1,8 +1,5 @@
 # test for ref types (including refs to procs)

 

-import

-  io

-

 type

   TProc = proc (a, b: int): int {.stdcall.}

 

diff --git a/tests/tregex.nim b/tests/tregex.nim
index 344f330df..48798aa4f 100644
--- a/tests/tregex.nim
+++ b/tests/tregex.nim
@@ -2,7 +2,7 @@
 # which is based on the PCRE library

 

 import

-  regexprs, io

+  regexprs

 

 if "Username" =~ "[A-Za-z]+":

   echo("Yes!")

diff --git a/tests/treguse.nim b/tests/treguse.nim
index 054866037..dc805fc70 100644
--- a/tests/treguse.nim
+++ b/tests/treguse.nim
@@ -1,9 +1,6 @@
 # Test the register usage of the virtual machine and

 # the blocks in var statements

 

-import

-  io

-

 proc main(a, b: int) =

   var x = 0

   write(stdout, x)

diff --git a/tests/trepr.nim b/tests/trepr.nim
index 9dd1c2b82..ec3731332 100644
--- a/tests/trepr.nim
+++ b/tests/trepr.nim
@@ -1,10 +1,7 @@
 # test the new "repr" built-in proc

 

-import

-  io

-

 type

-  TPoint = record

+  TPoint {.final.} = object

     x, y, z: int

     s: array [0..1, string]

 

diff --git a/tests/tseqcon.nim b/tests/tseqcon.nim
index dbeb6a4ef..f5d0346ae 100644
--- a/tests/tseqcon.nim
+++ b/tests/tseqcon.nim
@@ -1,10 +1,7 @@
 # Test the &= operator for sequences and strings

 

-import

-  io

-

 type

-  TRec = record

+  TRec {.final.} = object

     x, y: int

     s: string

     seq: seq[string]

diff --git a/tests/tsizeof.nim b/tests/tsizeof.nim
index cd29643a8..f7b70dd4d 100644
--- a/tests/tsizeof.nim
+++ b/tests/tsizeof.nim
@@ -1,10 +1,7 @@
 # Test the sizeof proc

 

-import

-  io

-

 type

-  TMyRecord = record

+  TMyRecord {.final.} = object

     x, y: int

     b: bool

     r: float

diff --git a/tests/tstrdesc.nim b/tests/tstrdesc.nim
index 58e8b7842..d25579ee2 100644
--- a/tests/tstrdesc.nim
+++ b/tests/tstrdesc.nim
@@ -4,12 +4,11 @@ var
 x = [0, 1, 2]

 

 type

-  TStringDesc = record

+  TStringDesc {.final.} = object

     len, space: int # len and space without counting the terminating zero

     data: array [0..0, char] # for the '\0' character

 

 var

-  emptyString {.export: "emptyString".}: TStringDesc = (

-    len: 0, space: 0, data: ['\0']

-  )

+  emptyString {.export: "emptyString".}: TStringDesc 

+

 

diff --git a/tests/tstrdist.nim b/tests/tstrdist.nim
index 99d685eab..482e363ef 100644
--- a/tests/tstrdist.nim
+++ b/tests/tstrdist.nim
@@ -1,8 +1,5 @@
 # compute the edit distance between two strings

 

-import

-  io

-

 proc editDistance(a, b: string): int =

   var c: seq[int] = []

   var

diff --git a/tests/tstrutil.nim b/tests/tstrutil.nim
index 9ed2ace3a..985656f2f 100644
--- a/tests/tstrutil.nim
+++ b/tests/tstrutil.nim
@@ -1,7 +1,7 @@
 # test the new strutils module

 

 import

-  strutils, io

+  strutils

 

 proc testStrip() =

   write(stdout, strip("  ha  "))

diff --git a/tests/tvarious.nim b/tests/tvarious.nim
index 1c15a87ba..52dd46184 100644
--- a/tests/tvarious.nim
+++ b/tests/tvarious.nim
@@ -1,16 +1,16 @@
 # Test various aspects

 

 import

-  mvarious, io

+  mvarious

 

 type

   PA = ref TA

   PB = ref TB

 

-  TB = record

+  TB = object

     a: PA

 

-  TA = record

+  TA = object

     b: TB

     x: int

 

diff --git a/tests/tvarnums.nim b/tests/tvarnums.nim
index f77478081..f57eeef41 100644
--- a/tests/tvarnums.nim
+++ b/tests/tvarnums.nim
@@ -1,7 +1,7 @@
 # Test variable length binary integers

 

 import

-  io, strutils

+  strutils

 

 type

   TBuffer = array [0..10, int8]

diff --git a/tests/twalker.nim b/tests/twalker.nim
index acdca9362..ba89ee7c6 100644
--- a/tests/twalker.nim
+++ b/tests/twalker.nim
@@ -1,7 +1,7 @@
 # iterate over all files with a given filter:

 

 import

-  io, os, times

+  os, times

 

 proc main(filter: string) =

   for filename in walkFiles(filter):

@@ -10,4 +10,4 @@ proc main(filter: string) =
   for key, val in iterOverEnvironment():

     writeln(stdout, key & '=' & val)

 

-main("*.mor")

+main("*.nim")

diff --git a/tests/walker.bpf b/tests/walker.bpf
deleted file mode 100644
index 819d6b63a..000000000
--- a/tests/walker.bpf
+++ /dev/null
@@ -1,13 +0,0 @@
-USEUNIT("twalker.c");

-USEUNIT("..\lib\morlib.c");

-USEUNIT("..\lib\os.c");

-USEUNIT("..\lib\refcgc.c");

-USEUNIT("..\lib\strutils.c");

-USEUNIT("..\lib\time.c");

-USEUNIT("..\lib\io.c");

-USEUNIT("..\lib\morbase.c");

-//---------------------------------------------------------------------------

-This file is used by the project manager only and should be treated like the project file

-

-

-main
\ No newline at end of file
diff --git a/tests/walker.bpr b/tests/walker.bpr
deleted file mode 100644
index 6b702f59f..000000000
--- a/tests/walker.bpr
+++ /dev/null
@@ -1,102 +0,0 @@
-<?xml version='1.0' encoding='utf-8' ?>

-<!-- C++Builder XML Project -->

-<PROJECT>

-  <MACROS>

-    <VERSION value="BCB.05.03"/>

-    <PROJECT value="walker.exe"/>

-    <OBJFILES value="twalker.obj ..\lib\morlib.obj ..\lib\os.obj ..\lib\refcgc.obj 

-      ..\lib\strutils.obj ..\lib\time.obj ..\lib\io.obj ..\lib\morbase.obj"/>

-    <RESFILES value=""/>

-    <DEFFILE value=""/>

-    <RESDEPEN value="$(RESFILES)"/>

-    <LIBFILES value=""/>

-    <LIBRARIES value=""/>

-    <SPARELIBS value=""/>

-    <PACKAGES value="Vcl50.bpi Vclx50.bpi bcbsmp50.bpi dclocx50.bpi bcb2kaxserver50.bpi"/>

-    <PATHCPP value=".;..\lib"/>

-    <PATHPAS value=".;"/>

-    <PATHRC value=".;"/>

-    <PATHASM value=".;"/>

-    <DEBUGLIBPATH value="$(BCB)\lib\debug"/>

-    <RELEASELIBPATH value="$(BCB)\lib\release"/>

-    <LINKER value="tlink32"/>

-    <USERDEFINES value="_DEBUG"/>

-    <SYSDEFINES value="NO_STRICT;_NO_VCL;_RTLDLL;USEPACKAGES"/>

-    <MAINSOURCE value="walker.bpf"/>

-    <INCLUDEPATH value="..\lib;$(BCB)\include;$(BCB)\include\vcl"/>

-    <LIBPATH value="..\lib;$(BCB)\lib\obj;$(BCB)\lib"/>

-    <WARNINGS value="-w-par"/>

-  </MACROS>

-  <OPTIONS>

-    <CFLAG1 value="-Od -H=$(BCB)\lib\vcl50.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- -tWC 

-      -tWM- -c"/>

-    <PFLAGS value="-$YD -$W -$O- -v -JPHNE -M"/>

-    <RFLAGS value=""/>

-    <AFLAGS value="/mx /w2 /zd"/>

-    <LFLAGS value="-D&quot;&quot; -ap -Tpe -x -Gn -v"/>

-  </OPTIONS>

-  <LINKER>

-    <ALLOBJ value="c0x32.obj $(PACKAGES) $(OBJFILES)"/>

-    <ALLRES value="$(RESFILES)"/>

-    <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cw32i.lib"/>

-  </LINKER>

-  <IDEOPTIONS>

-[Version Info]

-IncludeVerInfo=0

-AutoIncBuild=0

-MajorVer=1

-MinorVer=0

-Release=0

-Build=0

-Debug=0

-PreRelease=0

-Special=0

-Private=0

-DLL=0

-Locale=1031

-CodePage=1252

-

-[Version Info Keys]

-CompanyName=

-FileDescription=

-FileVersion=1.0.0.0

-InternalName=

-LegalCopyright=

-LegalTrademarks=

-OriginalFilename=

-ProductName=

-ProductVersion=1.0.0.0

-Comments=

-

-[HistoryLists\hlIncludePath]

-Count=2

-Item0=..\lib;$(BCB)\include;$(BCB)\include\vcl;C:\Eigenes\morpork\lib

-Item1=..\lib;$(BCB)\include;$(BCB)\include\vcl

-

-[HistoryLists\hlLibraryPath]

-Count=1

-Item0=..\lib;$(BCB)\lib\obj;$(BCB)\lib

-

-[HistoryLists\hlDebugSourcePath]

-Count=1

-Item0=$(BCB)\source\vcl

-

-[HistoryLists\hlConditionals]

-Count=1

-Item0=_DEBUG

-

-[Debugging]

-DebugSourceDirs=$(BCB)\source\vcl

-

-[Parameters]

-RunParams=

-HostApplication=

-RemoteHost=

-RemotePath=

-RemoteDebug=0

-

-[Compiler]

-ShowInfoMsgs=0

-LinkDebugVcl=0

-  </IDEOPTIONS>

-</PROJECT>
\ No newline at end of file
diff --git a/todo.txt b/todo.txt
index 8189f715d..dd7228356 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,8 +1,6 @@
 TO IMPLEMENT
 ============
 
-BPbRchqU
-
 RST
 ---
 - footnotes; prefix :i: whitespace before :i:, _reference, `reference`__
@@ -10,39 +8,50 @@ RST
 - don't generate <p></p> if it is not allowed by the HTML standard; switch to
   <br /> for those parts; this is pretty easy to fix
 
+Bugs
+----
+- BUG: bootstrapping does not work with LCC, PCC
+- BUG: aliasing of object types does not work properly (easy?)
+- BUG: lookup rules for overloadable symbols are wrong
+- BUG: addr/deref does not work when interpreting
+- BUG: Check that pure procs only consist of asm statements (and comments)
+- ``repr`` for ECMAScript target; other known bugs for the ECMAScript target
+
+
 High priority
 -------------
-- BUG: aliasing of record/object types does not work properly
-- BUG: repr from seq[string]
-- replace ``seq = []; setLen(seq, x)`` by something more efficient
-- disallow ``var var T``
-- replace appropriate asserts by internal errors!
-- type generation for tuples in the C code generator is difficult!
-- also check code generator for var-types
-- better code generation for const data
-- code generation for sets is wrong: &63
-- implement field checks for case records
-- evaluation + macros
+- implement two-phase lookup for generics (this is hard...): This is useful
+  for macros too!
+- replace ``seq = []; setLen(seq, x)`` by
+  built-in ``newSeq[T](s: var seq[T], len: int)``
+  or ``repeat[T](len: int, initVal: T): seq[T]``
 - ``is`` operator is missing
-- get assignable right!
+- implement closures for the C code generator; ECMAScript already has it
+
 
 Low priority
 ------------
-- macros: ``check`` pragma; this is really a good idea! This allows
+
+- ``nkTempAsgn``-node as optimization
+- better code generation for const data
+- make set optimizations part of the transformation (--> all backends profit
+  from it)
+- macros: ``typecheck`` pragma; this is really a good idea! This allows
   transformations based on types!
 - make callconv a set
 - pasparse.nim: fixVarSection() loses its comment!
 - partial generic instantation is missing
-- commas are not optional any longer as this may lead to bugs
+- commas are not optional any longer as this may lead to bugs (which?)
 - get code generation for C++ exception handling right!
 - implement the simple and cheap to implement module cache (default: disabled!)
-- remove r'c': it is pointless!
-- nkConv is not well-defined for rnimsyn; as are other node kinds;
-  separate them? But this way lies madness! Better make them consistent!
 - find a way for easy constructors and destructors; though constructors are
   flawed... destructors are not, however!
 - multiple dispatch
 - LIB: stream implementation - the compiler should use it too!
+- stress testing of ECMAScript code generator
+- rewrite sigmatch or fix it; generics and macros are somehow dumb. Who needs
+  generics if the power of macros lie at our feet?
+- replace appropriate asserts by internal errors!
 
 
 Changelog
@@ -58,14 +67,133 @@ Changelog
 - implicit conversion from pointer to other pointer type disallowed
 - $ifdef implemented for Pascal parser
 - fixed bug in types.pas concerning computation of set size (div rounds down!)
-- fixed a bug in ``sameFile`` in ``nos.pas``
+- fixed a bug in `sameFile` in ``nos.pas``
 - BUGFIX: Conversion from string to cstring
+- implemented field checks for case records
+- fixed code generation for sets of size 8
+- eliminated recursion in the ropes module; this increases efficiency a lot
+  and fixes the huge stack usage
+- fixed a bug in the exception handling; stack tracing
+- bugfix: mRepr was forgotten in semfold; we could evaluate this at compile
+  time!
+- BUGFIX: repr from seq[string]
+- implemented the `release` switch in the config file
+- change in extccomp.pas to provide `getCompileCFileCmd`. This is used by
+  the cgen module to include the used command. Thus a change in the C compiler
+  switches triggers a recompilation.
+- BUGFIX: returning from within a ``try`` context now works, thus we get a
+  proper stack trace again!
+- eliminated `skipAbstract`
+- disallowed ``var var T``
+- implemented checks for object conversions
+- renamed ``appRopeFormat`` to ``appf`` and ``ropeFormat`` to ``ropef``
+- field names are not mangled any longer if the containing record/object type
+  is ``importc``'ed or ``exportc``'ed
+- the engine now supports up to 254 node kinds; this is needed for future
+  enhancements
+- changed assignable handling
+- implemented better compile-time range checking and conv-transformation
+- object checks now work for ptr/ref
+- math and time library for the ECMAScript target
+- BUGFIX for long standing bug in semantic checking of asm statements
+- BUGFIX for long standing bug in reraiseException
+- removed r'c': it is pointless
+- cleaned up the AST
+- reworked tuple handling
+- implemented type converters
+- evaluation + macros
+- made nkConv and nkCast format consistent
+- syms are not copied any longer when importing them as this does not quite work
+  for the code generators
+- semantic checking now does lots of checks to prevent crashing with illegal
+  syntax trees caused by buggy macros
+- ``$`` is now magical
+- ccg: name mangling generates shorter names
+- r.a rewritten to r^.a if necessary (same for arrays); this should eliminate
+  some bugs and the C code generator already depends on it
+- fixed bugs in transf concerning inlining of iterators; tgeneric now works!
+- fixed enum symbol bug: enum symbols are not overloadable!
+- conversion transformation is now done in the semantic pass
+- conversion transformation is now done in the transf pass again
+- object conversions now may be addressable
+- removed addr(TClosure) hack in instgen module
+- fixed type description bugs in ccgtypes; should now be correct
+- added ``passl`` and ``passc`` pragmas and used it in the ``math`` module
+- changed handling of ZCT in the GC
+- added an optimization for arrays in forAllChildrenAux
+- fixed a bug in sigmatch; formal may be nil!
+- fixed a bug in the C code generator concerning the ``$`` operator
+- many commands of the debugger are now named as in GDB
+- fixed the GC: gctest now works again
+- fixed typedesc generation in the C code generator once again
+- BUGFIX: chckObj needs nil check if pointers are converted
+- BUGFIX: In lookup.pas: n.ident was accessed even though invalid
+- BUGFIX: loc.s was not initialized for temporaries
+- BUGFIX: index checking was not performed for openarr[const]
+  and sequence[const]
+- now no "intelligent" reuse of temporaries is done any longer; this should
+  avoid subtle bugs that may have been in the code generator
+- BUGFIX: int64 literals for the Pascal parser; this fixes the bug in the
+  generation of ``types.nim``
+- Finally long standing bug in mOrd of ccgexprs has been fixed!
+- BUGFIX: sonsLen is not attempted always in ``lsub`` and ``gsub``
+- BUGFIX: This code yielded invalid Nimrod code::
+
+    s := qualifiedLookup(c, n, true); // check for ambiguity
+    if s <> nil then
+      result := semSym(c, n, s, flags)
+    else
+      // THE COMMENT HERE IS INVALID!
+      result := semFieldAccess(c, n, flags);
+
+- bootstrapping now writes a diff.log file for easier debugging; first line is
+  ignored in the diff computation
+- ``volatile`` removed in ``excpt.nim`` to avoid VCC warnings
+- changed ``genAddr`` in ``ccgexprs`` module
+- BUGFIX: sameFile for ``os`` module under Windows was not working
+- BUGFIX: importing ``system`` as a module now generates a proper error
+- BUGFIX: ``ze`` built-in needs to be done differently
+- CHANGE: Do not include clock time in the executable! Otherwise bootstrapping
+  check does not work.
+- fixed the RstParser; initialization back to zero is not done in loop;
+  documentation generator now also work in the Nimrod version
+- BUGFIX: ``semExpr`` replaced by ``semExprWithType`` in semstmts
+- finally got tuples and objects right
+- BUGFIX: typo in sigmatch: tySet branch
+- BUGFIX: enums with 256 elements do not fit into a byte, because otherwise
+  overflow detection does not work!
+- 2008/8/14  first bootstrap with new tuple semantics
+- BUGFIX in repr; gctest now works again
+- tuned the GC
+- BUGFIX the scanner now accepts 64 bit integer literals
+- BUGFIX: ``getApplicationFilename`` on Mac OS X fixed; installation on
+  Mac OS X should work now
+- BUGFIX: reversed order of ``fixAbstractType`` and
+  ``analyseIfAddressTakenInCall`` again, because codegen otherwise
+  screws up
+- removed tfAssignable; this does not belong to a type!
+- ccgutils: merge types with the same ID in the code generators
+- ccgtypes: tySet now unsigned
+- fixed arith.nim overflow handling
+- implemented NIM_CONST for the C code generator, because it always made
+  problems with picky compilers like PCC
+- some fixes for Pelles C
+- BUGFIX: do not remove nkConv even if no range check is needed!
+- BUGFIX: genRangeCheck needs to cast!
+- BUGFIX: code generation for mInc, mDec, mChr
+- BUGFIX: spaces in the C compiler's path are finally possible
+- new strtabs module
+- new parseopt module used for parsing of command line
+- got rid of NU and NI in ``nimbase.h``; now the code generator deals with it
+  appropriately
+- parseopt, hashes, strtabs and parsecfg in the Standard library
+- introduced splitting for long entries in TOC
 
 
 For the next versions
 =====================
 
-- separate compilation
+- separate compilation!
 - multi-processor support
 - tuple assignment
 - more Parser/Renderer combinations
@@ -75,40 +203,11 @@ For the next versions
 - support for dynamic libraries
 
 
-Language features to be implemented
-===================================
-
-- sets of a basetype that is not starting at zero are broken
-- bit fields for ordinal types: {.bits: 9}
-- properties are the way to mimic OOP methods::
-
-  type
-    TFile = object
-      fx, fy: int
-      prop x: int in fx out fx
-      proc open
-
-  f.open(filename) is the same as open(f, filename)
-
-  open(f, filename)
-
-- this is the way to go::
-  type
-    TFile = object
-      ...
-  method open(f: TFile, mode: TFileMode) = # belongs to TFile!
-    ...
-  f.open(mode)
-
-- profiling support
-- yield statement warning/error
-
-
 Documentation to be written
 ===========================
 - document generics
 - document (anonymous) procs
-- cookbook: a[i|j] for example
+
 
 Implementation details
 ======================
@@ -119,14 +218,11 @@ Implementation details
 Optimizations
 =============
 
-- acyclic type detection; not needed; GC optimization does not work!
 - optimization of GC: types that cannot be involved in cycles should
   not be stored in the AT; this does not work because the AT is needed
   for stack checking!
 - better: generational GC for cycles
-- optimization for the GC: merge the refcount with the type info field
 - optimize range checks away (and out of bounds checks!)
-- merge set;string data (not critical; does C compiler for us)
 
 
 Further ideas/nice to have
@@ -138,8 +234,7 @@ Further ideas/nice to have
   to be executed, the command should end with #
 - multi-threaded programming
 - support for Boehm's GC
-- do finalizers right and add the built-in 'finalize'
-- built-in ``fast_assign``
+- add the built-in 'finalize'
 - implement packed arrays (bit arrays)/ packed records
 - implement tables (implement as library? - no! Builtin because of
   constructor syntax is nice to have)
@@ -154,14 +249,13 @@ Planned libraries
 - An Unicode library (UTF8)
 - Binding for Opengl library (should be easy)
 - Binding for Sockets library (which one?)
-- xml parser; cgi module; fast cgi module
+- XML parser; cgi module; fast cgi module
 - a good/extensive math library
 - neuronal network library; genetic algorithms
-- html parser
+- HTML parser
 - URL library
 - mySQL, sqlite interface
 - extensive platform independant AdvancedOS library
-- Lua, Python interface (almost done)
 - code generator for SQL-Schemes? ("Hibernate" done right)
 - mathematical expression parser (with lookup table for identifiers)
 - YAML parser (use generic AST for this)
diff --git a/web/download.txt b/web/download.txt
index e58af7840..424343a4b 100644
--- a/web/download.txt
+++ b/web/download.txt
@@ -1,11 +1,19 @@
-    "There are two major products that come out of Berkeley: LSD and UNIX.
-    We don't believe this to be a coincidence." -- Jeremy S. Anderson. 
-
-Here you can download the latest version of the Nimrod Compiler.
-Please choose your platform:
-
-* source for Unix (including MacOS X): `<download/nimrod_unix_0.5.1.zip>`_
-* binary and source for Windows (95, 98, XP): `<download/nimrod_windows_0.5.1.zip>`_
-  (includes LLVM and everything else you need)
-
-.. include:: ../install.txt
+    "There are two major products that come out of Berkeley: LSD and UNIX.

+    We don't believe this to be a coincidence." -- Jeremy S. Anderson.

+

+Here you can download the latest version of the Nimrod Compiler.

+Please choose your platform:

+* source for Linux (i386): `<download/nimrod_linux_i386_0.6.0.zip>`_

+* source for Linux (amd64): `<download/nimrod_linux_amd64_0.6.0.zip>`_

+* source for Linux (sparc, untested!): `<download/nimrod_linux_sparc_0.6.0.zip>`_

+* source for Mac OS X (i386): `<download/nimrod_macosx_i386_0.6.0.zip>`_

+* source for Mac OS X (amd64, untested!): `<download/nimrod_macosx_amd64_0.6.0.zip>`_

+* source for Solaris (i386, untested!): `<download/nimrod_solaris_i386_0.6.0.zip>`_

+* source for Solaris (amd64, untested!): `<download/nimrod_solaris_amd64_0.6.0.zip>`_

+* source for Solaris (sparc, untested!): `<download/nimrod_solaris_sparc_0.6.0.zip>`_

+* source for Windows (i386): `<download/nimrod_windows_i386_0.6.0.zip>`_

+* source for Windows (amd64, untested!): `<download/nimrod_windows_amd64_0.6.0.zip>`_

+* installer for Windows (i386): `<download/nimrod_windows_0.6.0.exe>`_

+  (includes LLVM and everything else you need)

+

+.. include:: ../install.txt

diff --git a/web/genweb.py b/web/genweb.py
deleted file mode 100644
index c3c1c93b1..000000000
--- a/web/genweb.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env python
-
-# Generates the beautiful webpage.
-# (c) 2007 Andreas Rumpf
-
-TABS = [ # Our tabs: (Menu entry, filename)
-  ("home", "index"),
-  ("documentation", "documentation"),
-  ("download", "download"),
-  ("Q&A", "question"), 
-  ("links", "links")
-]
-
-TEMPLATE_FILE = "sunset.tmpl"
-
-import sys, string, re, glob, os
-from Cheetah.Template import Template
-from time import gmtime, strftime
-
-def Exec(cmd):
-  print cmd
-  return os.system(cmd) == 0
-
-def Remove(f):
-  try:
-    os.remove(f)
-  except OSError:
-    Warn("could not remove: %s" % f)
-
-def main():
-  CMD = "rst2html.py --template=docutils.tmpl %s.txt %s.temp "
-  if not Exec(CMD % ("news","news")): return
-  newsText = file("news.temp").read()
-  for t in TABS:
-    if not Exec(CMD % (t[1],t[1]) ): return
-
-    tmpl = Template(file=TEMPLATE_FILE)
-    tmpl.content = file(t[1] + ".temp").read()
-    tmpl.news = newsText
-    tmpl.tab = t[1]
-    tmpl.tabs = TABS
-    tmpl.lastupdate = strftime("%Y-%m-%d %X", gmtime())
-    f = file(t[1] + ".html", "w+")
-    f.write(str(tmpl))
-    f.close()
-  # remove temporaries:
-  Remove("news.temp")
-  for t in TABS:
-    Remove(t[1] + ".temp")
-
-if __name__ == "__main__":
-  main()
diff --git a/web/index.txt b/web/index.txt
index c689a6ce7..82356c173 100644
--- a/web/index.txt
+++ b/web/index.txt
@@ -6,24 +6,24 @@ Home
   will not succeed without a good name. I have recently invented a very good
   name and now I am looking for a suitable language."
   -- D. E. Knuth
-  
+
 **This page is about the Nimrod programming language, which combines Lisp's
 power with Python's readability and C++'s performance.**
 
 Welcome to the Nimrod programming language
 ------------------------------------------
 
-**Nimrod** is a new statically typed, imperative 
-programming language, that supports procedural, functional, object oriented and 
-generic programming styles while remaining simple and efficient. A special 
+**Nimrod** is a new statically typed, imperative
+programming language, that supports procedural, functional, object oriented and
+generic programming styles while remaining simple and efficient. A special
 feature that Nimrod inherited from Lisp is that Nimrod's abstract syntax tree
-(*AST*) is part of the specification - this allows a powerful macro system which 
+(*AST*) is part of the specification - this allows a powerful macro system which
 can be used to create domain specific languages.
 
-*Nimrod* is a compiled, garbage-collected systems programming language 
-which has an excellent productivity/performance ratio. Nimrod's design 
-focuses on the 3E: efficiency, expressiveness, elegance (in the order of 
-priority). 
+*Nimrod* is a compiled, garbage-collected systems programming language
+which has an excellent productivity/performance ratio. Nimrod's design
+focuses on the 3E: efficiency, expressiveness, elegance (in the order of
+priority).
 
 
 Some more of Nimrod's highlights:
@@ -34,24 +34,29 @@ Some more of Nimrod's highlights:
   Porting to other platforms is easy.
 * System programming features: Ability to manage your own memory and access the
   hardware directly. You will never have to use C/C++ for that again!
-* Closures and iterators.
-* Exceptions.
+* Zero-overhead iterators.
 * Modern type system with local type inference, tuples, variants, etc.
-* User-defineable operators; new operators often easier to read than overloaded
-  ones.
+* User-defineable operators; new operators often easier to read than
+  overloaded ones.
 * High level datatypes: strings, sets, sequences, etc.
 * Compile time evaluation without resorting to meta-programming facilities.
-* *Forward* compability: If later versions of the language introduce new
+* Forward compability: If later versions of the language introduce new
   keywords old code won't break!
-* Bindings to GTK2, the Windows API, the POSIX API. New bindings are 
-  easily generated in a semi-atomatic way. 
-* A plugable parser system: If you don't like Nimrod's syntax, you can plug in
-  a parser and a source renderer for your own syntax!
+* Bindings to GTK2, the Windows API, the POSIX API. New bindings are easily
+  generated in a semi-atomatic way.
+* A plugable parser system: If you don't like Nimrod's syntax, you can plug
+  in a parser and a source renderer for your own syntax!
+* A documentation generator with an internal reStructuredText parser: This
+  can also be used to write documentation that is not embedded into the
+  source code. This makes documentation writing a joy (well, almost).
+* A Pascal to Nimrod conversion utility: This is particularly useful for
+  generating bindings to any library which has a Pascal binding
+  (these are many!).
 
-.. 
+..
   The Zen of Nimrod
   -----------------
-  
+
   * Faster computers are for solving bigger problems, not wasting cycles.
   * Static is better than dynamic: More efficient, more understandable,
     better verifyable.
diff --git a/web/news.txt b/web/news.txt
index d92bbfe40..575810c97 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -1,8 +1,31 @@
-| `2008-06-23`:newsdate:
-| Nimrod version |nimrodversion| has been released!
-  Get it `here <./download.html>`_.
-
-
-| `2008-06-22`:newsdate:
-| This page is finally online!
-
+====

+News

+====

+

+Developers needed

+=================

+Yes, this is nothing new. If you are interested to help designing and 

+implementing the new programming language Nimrod, visit our project page at 

+Launchpad: https://launchpad.net/nimrod and contact me.

+

+

+2008-08-22 Version 0.6.0 released

+=================================

+

+Nimrod version 0.6.0 has been released! Get it `here <./download.html>`_.

+**This is the first version of the compiler that is able to compile itself!**

+A nice side-effect from this is that a source-based installation does not 

+depend on FreePascal any longer.

+

+Changes:

+* various bug fixes, too many to list them here

+* cleaned up the type system: records are now superfluous and not

+  supported anymore

+* improved the performance of the garbage collector

+* new modules in the library: 

+  - ``parseopt``: a simple to use command line parser

+  - ``hashes``: efficient computation of hash values

+  - ``strtabs``: efficient mapping from strings to strings 

+  - ``parsecfg``: an efficient configuration file parser 

+* macros and compile-time evaluation implemented (however, still experimental)

+* generics implemented (however, still experimental)

diff --git a/web/question.txt b/web/question.txt
index 40f9ea67e..10250d1ac 100644
--- a/web/question.txt
+++ b/web/question.txt
@@ -1,112 +1,138 @@
-===========================================

-         Questions and Answers

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

-

-`How is Nimrod licensed?`:Q:

-

-The Nimrod compiler is GPL licensed, the runtime library is LGPL licensed. 

-This means that you can use any license for your own programs developed with 

-Nimrod. If I receive enough requests with good arguments, I may change the 

-license of Nimrod to the BSD license.

-

-

-`Why is compilation so slow?`:Q:

-

-*Compilation* is fast. The problem is that Nimrod always

-recompiles **everything**. In the next version, only modules that

-have changed will be recompiled.

-

-Another issue may be that the C compiler that is called by Nimrod is slow.

-Especially GCC's compile times are a bad joke. On Linux you may be able to get

-`Tiny C <http://fabrice.bellard.free.fr/tcc/>`_ to work. TCC has excellent

-compile times. You should not use TCC for producing the release version

-though, as it has no optimizer.

-

-An experimental feature is the *C file cache*. It is not

-activated. To activate, add to your ``nimrod.cfg`` file the following

-line::

-

-  --c_file_cache:on

-

-

-`Which version of Freepascal is needed to compile Nimrod?`:Q:

-

-Version 2.0.0 or later. Earlier development versions like 1.9.6 may work,

-but 1.0.10 won't. Note that I have never compiled Nimrod with FPC's

-optimizer turned on; it may break things due to bugs in FPC.

-

-

-`How do I build a shared library?`:Q:

-

-This is currently not supported. The GC that makes trouble.

-

-

-`How do I use a different C compiler than the default one?`:Q:

-

-Edit the ``config/nimrod.cfg`` file.

-Change the value of the ``cc`` variable to one of the following:

-

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

-Abbreviation    C/C++ Compiler

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

-``dmc``         Digital Mars C++

-``wcc``         Watcom C++

-``bcc``         Borland C++ (including Borland C++Builder)

-``vcc``         Microsoft's Visual C++

-``gcc``         Gnu C

-``pcc``         Pelles C

-``lcc``         Lcc-win32

-``tcc``         Tiny C

-``llvm_gcc``    LLVM-GCC compiler

-``icc``         Intel C++ compiler

-``ucc``         Generic UNIX C compiler

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

-

-If your C compiler is not in the above list, try using the

-*generic UNIX C compiler* (``ucc``). If the C compiler needs

-different command line arguments you have to edit the ``extccomp``

-module to add support for it and recompile the compiler. Please

-contribute a patch in this case.

+===========================================
+         Questions and Answers
+===========================================
+
+General
+=======
+
+`What is Nimrod?`:Q:
+**Nimrod** is a new statically typed, imperative
+programming language, that supports procedural, functional, object oriented and
+generic programming styles while remaining simple and efficient. A special
+feature that Nimrod inherited from Lisp is that Nimrod's abstract syntax tree
+(*AST*) is part of the specification - this allows a powerful macro system which
+can be used to create domain specific languages.
+
+`How is Nimrod licensed?`:Q:
+The Nimrod compiler is GPL licensed, the runtime library is LGPL licensed.
+This means that you can use any license for your own programs developed with
+Nimrod. If I receive enough requests with good arguments, I may change the
+license of Nimrod to the BSD license.
+
+
+Installation
+============
+
+`Is bootstrapping without Python possible?`:Q:
+Yes. You then have to compile by hand. It is not difficult (but it is not
+easy either). Please read the code in the ``koch.py`` script how this is can
+be accomplished (look for the ``cmd_boot`` routine).
+
+
+`A source-based download depending on the platform?`:Q:
+The reason is that the C code *generated* by Nimrod is not
+portable (the compiler itself is, of course!). The generated C
+code is used for the installation, so you have to pick the right package.
+
+
+`Why is compilation so slow?`:Q:
+
+*Compilation* is fast. The problem is that Nimrod always
+recompiles **everything**. In the next version, only modules that
+have changed will be recompiled.
+
+Another issue may be that the C compiler that is called by Nimrod is slow.
+Especially GCC's compile times are a bad joke. On Linux you may be able to get
+`Tiny C <http://fabrice.bellard.free.fr/tcc/>`_ to work. TCC has excellent
+compile times. You should not use TCC for producing the release version
+though, as it has no optimizer.
+
+
+`Which version of Freepascal is needed to compile Nimrod?`:Q:
+
+Version 2.0.0 or later. Earlier development versions like 1.9.6 may work,
+but 1.0.10 won't. Note that I have never compiled Nimrod with FPC's
+optimizer turned on; it may break things due to bugs in FPC (yes, this has
+happend!).
+
+
+`How do I build a shared library?`:Q:
+
+This is currently not supported.
+
+
+`How do I use a different C compiler than the default one?`:Q:
+
+Edit the ``config/nimrod.cfg`` file.
+Change the value of the ``cc`` variable to one of the following:
+
+==============  ============================================
+Abbreviation    C/C++ Compiler
+==============  ============================================
+``dmc``         Digital Mars C++
+``wcc``         Watcom C++ (now unsupported!)
+``bcc``         Borland C++ (including Borland C++Builder)
+``vcc``         Microsoft's Visual C++
+``gcc``         Gnu C
+``pcc``         Pelles C (now unsupported!)
+``lcc``         Lcc-win32 (now unsupported!)
+``tcc``         Tiny C (now unsupported!)
+``llvm_gcc``    LLVM-GCC compiler
+``icc``         Intel C++ compiler
+``ucc``         Generic UNIX C compiler
+==============  ============================================
+
+If your C compiler is not in the above list, try using the
+*generic UNIX C compiler* (``ucc``). If the C compiler needs
+different command line arguments try the ``--passc`` and ``--passl`` switches.
 
 `The linker outputs strange errors about missing symbols`:Q:
 
-I have seen this bug only with the GNU linker. The reason for this unknown. 
+I have seen this bug only with the GNU linker. The reason for this unknown.
 Try recompiling your code with the ``--c_file_cache:off`` command line switch.
-

-

-`Calling the C compiler fails - what's wrong?`:Q:

-

-Many C compilers need special environment variables to work

-properly. Although Nimrod tries hard to set them correctly (see

-``extccomp.pas`` for details), this may fail if you use a

-different version of the C compiler. The solution is to

-ensure that all environment variables are set correctly.

-

-You can set environment variables temporarily by using the

-``@putenv "key" "val"`` directive in the ``config/nimrod.cfg``

-configuration file. There are also ``@append_env`` and

-``@prepend_env`` directives for appending or prepending

-to environment variables.

-

-

-`Calling the C compiler still fails`:Q:

-

-Try to call the C compiler directly by doing the following::

-

-  nimrod --compile_only --gen_script your_path/your_file

-  sh ./your_path/rod_gen/compile_your_file.sh

-

-

-`How to overload the ``in`` operator?`:Q:

-

-The ``in`` and ``not_in`` operators are implemented as templates. The reason is

-that these operators need a reverse unification algorithm (don't ask). See the

-``system.nim`` module for a deeper explanation. The solution is to implement a

-simple ``in_Operator`` proc where the arguments are the other way round::

-

-  proc in_operator(s: string, c: char): bool =

-    for x in items(s):

-      if x == c: return True

-    return False

-    

-  writeln(stdout, 'z' in "abcdz") # now works!

+
+
+`Calling the C compiler fails - what's wrong?`:Q:
+
+First try to edit the path to your C compiler in the
+``config/nimrod.cfg`` file. For the Windows version bundled with
+LLVM search for the line containing ``llvm_gcc.path``. Set this
+variable to the ``bin`` directory of LLVM.
+
+Many C compilers need special environment variables to work
+properly. Although Nimrod tries hard to set them correctly (see
+``extccomp.pas`` for details), this may fail if you use a
+different version of the C compiler. The solution is to
+ensure that all environment variables are set correctly.
+
+You can set environment variables temporarily by using the
+``@putenv "key" "val"`` directive in the ``config/nimrod.cfg``
+configuration file. There are also ``@append_env`` and
+``@prepend_env`` directives for appending or prepending
+to environment variables.
+
+
+`Calling the C compiler still fails`:Q:
+
+Try to call the C compiler directly by doing the following::
+
+  nimrod --compile_only --gen_script your_path/your_file
+  sh ./your_path/rod_gen/compile_your_file.sh
+
+
+Questions about the Nimrod language
+===================================
+
+`How to overload the ``in`` operator?`:Q:
+
+The ``in`` and ``not_in`` operators are implemented as templates. The reason is
+that these operators need a reverse unification algorithm (don't ask). See the
+``system.nim`` module for a deeper explanation. The solution is to implement a
+simple ``in_Operator`` proc where the arguments are the other way round::
+
+  proc in_operator(s: string, c: char): bool =
+    for x in items(s):
+      if x == c: return True
+    return False
+
+  writeln(stdout, 'z' in "abcdz") # now works!
diff --git a/web/sunset.tmpl b/web/sunset.tmpl
index f5ef733e6..f6fa16d17 100644
--- a/web/sunset.tmpl
+++ b/web/sunset.tmpl
@@ -31,7 +31,7 @@
             <h1>latest news</h1>
           </div>
           <div class="sbicontent">
-            $news
+            $ticker
           </div>
         </div>
         <div class="sidebaritem">