summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--build.sh19
-rw-r--r--compiler.nimble11
-rw-r--r--compiler/ast.nim694
-rw-r--r--compiler/astalgo.nim696
-rw-r--r--compiler/canonicalizer.nim20
-rw-r--r--compiler/ccgcalls.nim395
-rw-r--r--compiler/ccgexprs.nim649
-rw-r--r--compiler/ccgmerge.nim76
-rw-r--r--compiler/ccgstmts.nim462
-rw-r--r--compiler/ccgthreadvars.nim28
-rw-r--r--compiler/ccgtrav.nim98
-rw-r--r--compiler/ccgtypes.nim1005
-rw-r--r--compiler/ccgutils.nim122
-rw-r--r--compiler/cgen.nim983
-rw-r--r--compiler/cgendata.nim42
-rw-r--r--compiler/commands.nim255
-rw-r--r--compiler/condsyms.nim152
-rw-r--r--compiler/depends.nim30
-rw-r--r--compiler/docgen.nim163
-rw-r--r--compiler/evalffi.nim495
-rw-r--r--compiler/evaltempl.nim14
-rw-r--r--compiler/extccomp.nim183
-rw-r--r--compiler/filter_tmpl.nim18
-rw-r--r--compiler/forloops.nim89
-rw-r--r--compiler/guards.nim142
-rw-r--r--compiler/idents.nim2
-rw-r--r--compiler/importer.nim26
-rw-r--r--compiler/installer.ini (renamed from compiler/nim.ini)31
-rw-r--r--compiler/jsgen.nim1015
-rw-r--r--compiler/jstypes.nim174
-rw-r--r--compiler/lambdalifting.nim146
-rw-r--r--compiler/lexer.nim425
-rw-r--r--compiler/llstream.nim41
-rw-r--r--compiler/lookups.nim97
-rw-r--r--compiler/lowerings.nim69
-rw-r--r--compiler/main.nim50
-rw-r--r--compiler/modules.nim17
-rw-r--r--compiler/msgs.nim846
-rw-r--r--compiler/nim.nim13
-rw-r--r--compiler/nim.nim.cfg (renamed from compiler/nim.nimrod.cfg)3
-rw-r--r--compiler/nimblecmd.nim2
-rw-r--r--compiler/nimconf.nim39
-rw-r--r--compiler/nimeval.nim2
-rw-r--r--compiler/nimfix/nimfix.nim8
-rw-r--r--compiler/nimfix/nimfix.nim.cfg2
-rw-r--r--compiler/nimfix/pretty.nim2
-rw-r--r--compiler/nimfix/prettybase.nim2
-rw-r--r--compiler/nimlexbase.nim2
-rw-r--r--compiler/nimsuggest/nimsuggest.nim197
-rw-r--r--compiler/nimsuggest/nimsuggest.nim.cfg17
-rw-r--r--compiler/nodejs.nim6
-rw-r--r--compiler/nversion.nim2
-rw-r--r--compiler/options.nim97
-rw-r--r--compiler/parampatterns.nim58
-rw-r--r--compiler/parser.nim563
-rw-r--r--compiler/passes.nim108
-rw-r--r--compiler/patterns.nim4
-rw-r--r--compiler/platform.nim296
-rw-r--r--compiler/plugins.nim43
-rw-r--r--compiler/plugins/active.nim13
-rw-r--r--compiler/plugins/locals/locals.nim42
-rw-r--r--compiler/pragmas.nim307
-rw-r--r--compiler/renderer.nim536
-rw-r--r--compiler/rodread.nim6
-rw-r--r--compiler/rodwrite.nim6
-rw-r--r--compiler/ropes.nim374
-rw-r--r--compiler/sem.nim99
-rw-r--r--compiler/semasgn.nim341
-rw-r--r--compiler/semcall.nim169
-rw-r--r--compiler/semdata.nim85
-rw-r--r--compiler/semdestruct.nim35
-rw-r--r--compiler/semexprs.nim727
-rw-r--r--compiler/semfields.nim164
-rw-r--r--compiler/semfold.nim311
-rw-r--r--compiler/semgnrc.nim71
-rw-r--r--compiler/seminst.nim85
-rw-r--r--compiler/semmacrosanity.nim2
-rw-r--r--compiler/semmagic.nim117
-rw-r--r--compiler/semparallel.nim45
-rw-r--r--compiler/sempass2.nim171
-rw-r--r--compiler/semstmts.nim576
-rw-r--r--compiler/semtempl.nim145
-rw-r--r--compiler/semtypes.nim544
-rw-r--r--compiler/semtypinst.nim119
-rw-r--r--compiler/service.nim25
-rw-r--r--compiler/sigmatch.nim733
-rw-r--r--compiler/suggest.nim229
-rw-r--r--compiler/syntaxes.nim4
-rw-r--r--compiler/transf.nim272
-rw-r--r--compiler/trees.nim84
-rw-r--r--compiler/treetab.nim5
-rw-r--r--compiler/types.nim660
-rw-r--r--compiler/typesrenderer.nim12
-rw-r--r--compiler/vm.nim144
-rw-r--r--compiler/vmdef.nim46
-rw-r--r--compiler/vmdeps.nim140
-rw-r--r--compiler/vmgen.nim154
-rw-r--r--compiler/vmhooks.nim2
-rw-r--r--compiler/vmops.nim4
-rw-r--r--compiler/wordrecg.nim118
-rw-r--r--config/nim.cfg58
-rw-r--r--config/nimdoc.cfg1319
-rw-r--r--config/nimrod.cfg136
-rw-r--r--copying.txt4
-rw-r--r--doc/advopt.txt21
-rw-r--r--doc/apis.txt7
-rw-r--r--doc/astspec.txt32
-rw-r--r--doc/backends.txt34
-rw-r--r--doc/basicopt.txt11
-rw-r--r--doc/docgen.txt12
-rw-r--r--doc/filters.txt2
-rw-r--r--doc/gc.txt14
-rw-r--r--doc/grammar.txt38
-rw-r--r--doc/idetools.txt36
-rw-r--r--doc/intern.txt21
-rw-r--r--doc/keywords.txt4
-rw-r--r--doc/lib.txt43
-rw-r--r--doc/manual/about.txt4
-rw-r--r--doc/manual/effects.txt4
-rw-r--r--doc/manual/exceptions.txt97
-rw-r--r--doc/manual/ffi.txt2
-rw-r--r--doc/manual/generics.txt139
-rw-r--r--doc/manual/lexing.txt6
-rw-r--r--doc/manual/modules.txt22
-rw-r--r--doc/manual/pragmas.txt91
-rw-r--r--doc/manual/procs.txt110
-rw-r--r--doc/manual/stmts.txt78
-rw-r--r--doc/manual/syntax.txt25
-rw-r--r--doc/manual/templates.txt14
-rw-r--r--doc/manual/threads.txt42
-rw-r--r--doc/manual/trmacros.txt26
-rw-r--r--doc/manual/type_bound_ops.txt70
-rw-r--r--doc/manual/type_rel.txt169
-rw-r--r--doc/manual/type_sections.txt16
-rw-r--r--doc/manual/typedesc.txt37
-rw-r--r--doc/manual/types.txt286
-rw-r--r--doc/nimc.txt1207
-rw-r--r--doc/nimgrep.txt8
-rw-r--r--doc/niminst.txt2
-rw-r--r--doc/pegdocs.txt2
-rw-r--r--doc/sets_fragment.txt4
-rw-r--r--doc/tut1.txt97
-rw-r--r--doc/tut2.txt174
-rw-r--r--examples/cross_calculator/android/readme.txt12
-rw-r--r--examples/cross_calculator/ios/readme.txt4
-rw-r--r--examples/cross_calculator/ios/src/NRViewController.m8
-rw-r--r--examples/cross_calculator/lazarus/readme.txt6
-rw-r--r--examples/cross_calculator/nim_backend/backend.nim (renamed from examples/cross_calculator/nimrod_backend/backend.nim)0
-rw-r--r--examples/cross_calculator/nim_commandline/nim.cfg (renamed from examples/cross_calculator/nimrod_commandline/nimrod.cfg)2
-rw-r--r--examples/cross_calculator/nim_commandline/nimcalculator.nim (renamed from examples/cross_calculator/nimrod_commandline/nimcalculator.nim)6
-rw-r--r--examples/cross_calculator/nim_commandline/readme.txt (renamed from examples/cross_calculator/nimrod_commandline/readme.txt)6
-rw-r--r--examples/cross_calculator/readme.txt6
-rw-r--r--examples/cross_todo/nim_backend/backend.nim (renamed from examples/cross_todo/nimrod_backend/backend.nim)16
-rw-r--r--examples/cross_todo/nim_backend/readme.txt (renamed from examples/cross_todo/nimrod_backend/readme.txt)4
-rw-r--r--examples/cross_todo/nim_backend/testbackend.nim (renamed from examples/cross_todo/nimrod_backend/testbackend.nim)0
-rw-r--r--examples/cross_todo/nim_commandline/nim.cfg (renamed from examples/cross_todo/nimrod_commandline/nimrod.cfg)2
-rw-r--r--examples/cross_todo/nim_commandline/nimtodo.nim (renamed from examples/cross_todo/nimrod_commandline/nimtodo.nim)10
-rw-r--r--examples/cross_todo/nim_commandline/readme.txt (renamed from examples/cross_todo/nimrod_commandline/readme.txt)6
-rw-r--r--examples/cross_todo/readme.txt4
-rw-r--r--examples/curlex.nim2
-rw-r--r--examples/talk/hoisting.nim2
-rw-r--r--icons/nim.ico (renamed from icons/nimrod.ico)bin30319 -> 30319 bytes
-rw-r--r--icons/nim.rc3
-rw-r--r--icons/nim.res (renamed from icons/nimrod.res)bin30830 -> 30830 bytes
-rw-r--r--icons/nim_icon.o (renamed from icons/nimrod_icon.o)bin30830 -> 30830 bytes
-rw-r--r--icons/nimrod.rc3
-rw-r--r--install.sh.template9
-rw-r--r--koch.nim122
-rw-r--r--koch.nim.cfg (renamed from koch.nimrod.cfg)0
-rw-r--r--lib/core/locks.nim2
-rw-r--r--lib/core/macros.nim421
-rw-r--r--lib/core/typeinfo.nim18
-rw-r--r--lib/core/unsigned.nim32
-rw-r--r--lib/impure/db_mysql.nim10
-rw-r--r--lib/impure/db_postgres.nim8
-rw-r--r--lib/impure/db_sqlite.nim19
-rw-r--r--lib/impure/graphics.nim2
-rw-r--r--lib/impure/osinfo_posix.nim79
-rw-r--r--lib/impure/osinfo_win.nim414
-rw-r--r--lib/impure/rdstdin.nim102
-rw-r--r--lib/impure/re.nim286
-rw-r--r--lib/impure/ssl.nim2
-rw-r--r--lib/js/dom.nim219
-rw-r--r--lib/nimbase.h33
-rw-r--r--lib/nimrtl.nim.cfg (renamed from lib/nimrtl.nimrod.cfg)0
-rw-r--r--lib/packages/docutils/highlite.nim447
-rw-r--r--lib/packages/docutils/rst.nim916
-rw-r--r--lib/packages/docutils/rstast.nim93
-rw-r--r--lib/packages/docutils/rstgen.nim298
-rw-r--r--lib/posix/posix.nim59
-rw-r--r--lib/posix/termios.nim261
-rw-r--r--lib/pure/actors.nim4
-rw-r--r--lib/pure/algorithm.nim142
-rw-r--r--lib/pure/asyncdispatch.nim212
-rw-r--r--lib/pure/asyncdispatch.nim.cfg (renamed from lib/pure/asyncdispatch.nimrod.cfg)0
-rw-r--r--lib/pure/asyncfile.nim44
-rw-r--r--lib/pure/asyncftpclient.nim14
-rw-r--r--lib/pure/asynchttpserver.nim81
-rw-r--r--lib/pure/asyncio.nim111
-rw-r--r--lib/pure/asyncnet.nim49
-rw-r--r--lib/pure/basic2d.nim6
-rw-r--r--lib/pure/basic3d.nim10
-rw-r--r--lib/pure/browsers.nim2
-rw-r--r--lib/pure/collections/LockFreeHash.nim4
-rw-r--r--lib/pure/collections/critbits.nim26
-rw-r--r--lib/pure/collections/intsets.nim86
-rw-r--r--lib/pure/collections/lists.nim44
-rw-r--r--lib/pure/collections/queues.nim13
-rw-r--r--lib/pure/collections/rtarrays.nim36
-rw-r--r--lib/pure/collections/sequtils.nim83
-rw-r--r--lib/pure/collections/sets.nim513
-rw-r--r--lib/pure/collections/tables.nim444
-rw-r--r--lib/pure/colors.nim4
-rw-r--r--lib/pure/complex.nim161
-rw-r--r--lib/pure/concurrency/cpuinfo.nim2
-rw-r--r--lib/pure/concurrency/cpuload.nim4
-rw-r--r--lib/pure/concurrency/threadpool.nim8
-rw-r--r--lib/pure/concurrency/threadpool.nim.cfg1
-rw-r--r--lib/pure/cookies.nim10
-rw-r--r--lib/pure/encodings.nim6
-rw-r--r--lib/pure/events.nim22
-rw-r--r--lib/pure/fenv.nim80
-rw-r--r--lib/pure/fsmonitor.nim36
-rw-r--r--lib/pure/ftpclient.nim136
-rw-r--r--lib/pure/future.nim23
-rw-r--r--lib/pure/gentabs.nim21
-rw-r--r--lib/pure/hashes.nim4
-rw-r--r--lib/pure/htmlgen.nim189
-rw-r--r--lib/pure/htmlparser.nim6
-rw-r--r--lib/pure/httpclient.nim290
-rw-r--r--lib/pure/httpserver.nim4
-rw-r--r--lib/pure/json.nim429
-rw-r--r--lib/pure/lexbase.nim2
-rw-r--r--lib/pure/logging.nim114
-rw-r--r--lib/pure/marshal.nim4
-rw-r--r--lib/pure/matchers.nim4
-rw-r--r--lib/pure/math.nim52
-rw-r--r--lib/pure/md5.nim274
-rw-r--r--lib/pure/memfiles.nim2
-rw-r--r--lib/pure/mersenne.nim2
-rw-r--r--lib/pure/mimetypes.nim4
-rw-r--r--lib/pure/net.nim165
-rw-r--r--lib/pure/nimprof.nim2
-rw-r--r--lib/pure/nimprof.nim.cfg (renamed from lib/pure/nimprof.nimrod.cfg)0
-rw-r--r--lib/pure/oids.nim2
-rw-r--r--lib/pure/os.nim123
-rw-r--r--lib/pure/osproc.nim45
-rw-r--r--lib/pure/parsecfg.nim2
-rw-r--r--lib/pure/parsecsv.nim2
-rw-r--r--lib/pure/parseopt.nim11
-rw-r--r--lib/pure/parseopt2.nim4
-rw-r--r--lib/pure/parsesql.nim2
-rw-r--r--lib/pure/parseurl.nim10
-rw-r--r--lib/pure/parseutils.nim21
-rw-r--r--lib/pure/parsexml.nim35
-rw-r--r--lib/pure/pegs.nim360
-rw-r--r--lib/pure/pegs.nimfix2
-rw-r--r--lib/pure/poly.nim2
-rw-r--r--lib/pure/rationals.nim289
-rw-r--r--lib/pure/rawsockets.nim5
-rw-r--r--lib/pure/redis.nim42
-rw-r--r--lib/pure/romans.nim9
-rw-r--r--lib/pure/ropes.nim170
-rw-r--r--lib/pure/scgi.nim4
-rw-r--r--lib/pure/selectors.nim30
-rw-r--r--lib/pure/smtp.nim4
-rw-r--r--lib/pure/smtp.nim.cfg (renamed from lib/pure/smtp.nimrod.cfg)0
-rw-r--r--lib/pure/sockets.nim14
-rw-r--r--lib/pure/streams.nim32
-rw-r--r--lib/pure/strtabs.nim4
-rw-r--r--lib/pure/strutils.nim129
-rw-r--r--lib/pure/subexes.nim28
-rw-r--r--lib/pure/terminal.nim43
-rw-r--r--lib/pure/times.nim597
-rw-r--r--lib/pure/unicode.nim2003
-rw-r--r--lib/pure/unidecode/unidecode.nim2
-rw-r--r--lib/pure/unittest.nim70
-rw-r--r--lib/pure/uri.nim107
-rw-r--r--lib/pure/xmldom.nim30
-rw-r--r--lib/pure/xmldomparser.nim2
-rw-r--r--lib/pure/xmlparser.nim6
-rw-r--r--lib/pure/xmltree.nim105
-rw-r--r--lib/system.nim652
-rw-r--r--lib/system/alloc.nim208
-rw-r--r--lib/system/ansi_c.nim9
-rw-r--r--lib/system/arithm.nim2
-rw-r--r--lib/system/assign.nim10
-rw-r--r--lib/system/atomics.nim113
-rw-r--r--lib/system/cgprocs.nim2
-rw-r--r--lib/system/channels.nim9
-rw-r--r--lib/system/chcks.nim4
-rw-r--r--lib/system/deepcopy.nim6
-rw-r--r--lib/system/dyncalls.nim17
-rw-r--r--lib/system/embedded.nim6
-rw-r--r--lib/system/excpt.nim20
-rw-r--r--lib/system/gc.nim180
-rw-r--r--lib/system/gc2.nim168
-rw-r--r--lib/system/gc_ms.nim70
-rw-r--r--lib/system/hti.nim8
-rw-r--r--lib/system/inclrtl.nim2
-rw-r--r--lib/system/jssys.nim20
-rw-r--r--lib/system/mmdisp.nim90
-rw-r--r--lib/system/platforms.nim2
-rw-r--r--lib/system/profiler.nim2
-rw-r--r--lib/system/repr.nim12
-rw-r--r--lib/system/sysio.nim129
-rw-r--r--lib/system/sysspawn.nim2
-rw-r--r--lib/system/sysstr.nim72
-rw-r--r--lib/system/threads.nim20
-rw-r--r--lib/system/timers.nim4
-rw-r--r--lib/windows/windows.nim12
-rw-r--r--lib/windows/winlean.nim52
-rw-r--r--lib/wrappers/claro.nim16
-rw-r--r--lib/wrappers/iup.nim234
-rw-r--r--lib/wrappers/libffi/msvc/win32.c2
-rw-r--r--lib/wrappers/libuv.nim58
-rw-r--r--lib/wrappers/mysql.nim24
-rw-r--r--lib/wrappers/openssl.nim70
-rw-r--r--lib/wrappers/pcre.nim762
-rw-r--r--lib/wrappers/readline/history.nim2
-rw-r--r--lib/wrappers/readline/tweaked/history.h2
-rw-r--r--lib/wrappers/sdl/sdl.nim10
-rw-r--r--lib/wrappers/sdl/sdl_mixer.nim2
-rw-r--r--lib/wrappers/zip/zlib.nim2
-rw-r--r--readme.md49
-rw-r--r--tests/actiontable/tactiontable2.nim3
-rw-r--r--tests/array/troof1.nim36
-rw-r--r--tests/array/troof2.nim10
-rw-r--r--tests/array/troof3.nim8
-rw-r--r--tests/array/troof4.nim37
-rw-r--r--tests/assert/tfailedassert.nim10
-rw-r--r--tests/assign/moverload_asgn2.nim10
-rw-r--r--tests/assign/toverload_asgn1.nim75
-rw-r--r--tests/assign/toverload_asgn2.nim22
-rw-r--r--tests/async/tasyncawait.nim4
-rw-r--r--tests/async/tasyncexceptions.nim1
-rw-r--r--tests/async/tasynciossl.nim4
-rw-r--r--tests/async/tasynctry.nim53
-rw-r--r--tests/async/tasynctry2.nim16
-rw-r--r--tests/async/tasyncudp.nim6
-rw-r--r--tests/bind/tnicerrorforsymchoice.nim6
-rw-r--r--tests/caas/idetools_api.nim2
-rw-r--r--tests/caas/issue_416_template_shift.txt2
-rw-r--r--tests/caas/its_full_of_procs.nim2
-rw-r--r--tests/casestmt/tcase_emptyset_when.nim24
-rw-r--r--tests/casestmt/tcomputedgoto.nim5
-rw-r--r--tests/ccgbugs/tarray_equality.nim15
-rw-r--r--tests/ccgbugs/tmissingderef.nim30
-rw-r--r--tests/ccgbugs/trecursive_closure.nim8
-rw-r--r--tests/ccgbugs/trecursive_table.nim17
-rw-r--r--tests/ccgbugs/tstringslice.nim24
-rw-r--r--tests/ccgbugs/tuple_canon.nim80
-rw-r--r--tests/ccgbugs/twrong_tupleconv.nim20
-rw-r--r--tests/clearmsg/ta.nim2
-rw-r--r--tests/clearmsg/tconsttypemismatch.nim8
-rw-r--r--tests/closure/tfib50.nim22
-rw-r--r--tests/closure/tinvalidclosure.nim4
-rw-r--r--tests/closure/tissue1642.nim7
-rw-r--r--tests/closure/ttimeinfo.nim15
-rw-r--r--tests/collections/tindexby.nim22
-rw-r--r--tests/collections/ttableconstr.nim (renamed from tests/table/ttableconstr.nim)0
-rw-r--r--tests/collections/ttables.nim172
-rw-r--r--tests/collections/ttables2.nim (renamed from tests/table/ttables2.nim)10
-rw-r--r--tests/collections/ttablesref.nim (renamed from tests/table/ptables.nim)13
-rw-r--r--tests/collections/ttablesref2.nim (renamed from tests/table/ptables2.nim)0
-rw-r--r--tests/concepts/mvarconcept.nim13
-rw-r--r--tests/concepts/tmanual.nim (renamed from tests/metatype/udtcmanual.nim)6
-rw-r--r--tests/concepts/tswizzle.nim (renamed from tests/metatype/swizzle.nim)51
-rw-r--r--tests/concepts/tusertypeclasses.nim68
-rw-r--r--tests/concepts/tusertypeclasses2.nim (renamed from tests/metatype/tusertypeclasses2.nim)4
-rw-r--r--tests/concepts/tvarconcept.nim9
-rw-r--r--tests/converter/ttypeconverter1.nim7
-rw-r--r--tests/cpp/tget_subsystem.nim23
-rw-r--r--tests/cpp/trawsockets.nim5
-rw-r--r--tests/cpp/tstaticvar_via_typedesc.nim20
-rw-r--r--tests/cpp/tthread_createthread.nim14
-rw-r--r--tests/cpp/ttypeinfo.nim5
-rw-r--r--tests/cpp/tvector_iterator.nim19
-rw-r--r--tests/cpp/tvectorseq.nim38
-rw-r--r--tests/deprecated/tdeprecated.nim6
-rw-r--r--tests/destructor/tdestructor.nim18
-rw-r--r--tests/destructor/tdestructor2.nim20
-rw-r--r--tests/dir with space/tspace.nim3
-rw-r--r--tests/dll/client.nim.cfg (renamed from tests/dll/client.nimrod.cfg)0
-rw-r--r--tests/dll/server.nim.cfg (renamed from tests/dll/server.nimrod.cfg)0
-rw-r--r--tests/effects/teffects1.nim1
-rw-r--r--tests/effects/tgcsafe.nim2
-rw-r--r--tests/enum/tenumitems.nim2
-rw-r--r--tests/exception/tdefer1.nim18
-rw-r--r--tests/exception/texceptions.nim6
-rw-r--r--tests/exception/treraise.nim4
-rw-r--r--tests/exprs/texprstmt.nim2
-rw-r--r--tests/exprs/thighCString.nim6
-rw-r--r--tests/exprs/tresultwarning.nim6
-rw-r--r--tests/fields/tfielditerator2.nim20
-rw-r--r--tests/fields/tfields_in_template.nim15
-rw-r--r--tests/fields/tfields_with_break.nim33
-rw-r--r--tests/gc/closureleak.nim4
-rw-r--r--tests/gc/cyclecollector.nim21
-rw-r--r--tests/gc/gcleak4.nim4
-rw-r--r--tests/gc/gctest.nim3
-rw-r--r--tests/gc/growobjcrash.nim29
-rw-r--r--tests/generics/mdotlookup.nim2
-rw-r--r--tests/generics/t1050.nim16
-rw-r--r--tests/generics/t1056.nim25
-rw-r--r--tests/generics/t1789.nim44
-rw-r--r--tests/generics/tableref_is_nil.nim9
-rw-r--r--tests/generics/tarray_with_somenumber.nim11
-rw-r--r--tests/generics/tconfusing_arrow.nim15
-rw-r--r--tests/generics/tdotlookup.nim2
-rw-r--r--tests/generics/tforwardgeneric.nim1
-rw-r--r--tests/generics/tgeneric3.nim2
-rw-r--r--tests/generics/tgeneric_closure.nim37
-rw-r--r--tests/generics/tgeneric_inheritance.nim19
-rw-r--r--tests/generics/tmetafield.nim2
-rw-r--r--tests/generics/tthread_generic.nim12
-rw-r--r--tests/generics/tunique_type.nim67
-rw-r--r--tests/generics/twrong_field_caching.nim68
-rw-r--r--tests/generics/twrong_floatlit_type.nim118
-rw-r--r--tests/generics/twrong_generic_object.nim21
-rw-r--r--tests/global/tglobal.nim2
-rw-r--r--tests/implicit/timplictderef.nim21
-rw-r--r--tests/init/tuninit2.nim54
-rw-r--r--tests/iter/tchainediterators.nim7
-rw-r--r--tests/iter/tconcat.nim24
-rw-r--r--tests/iter/timplicit_auto.nim18
-rw-r--r--tests/iter/tobj_iter.nim20
-rw-r--r--tests/iter/tscheduler.nim76
-rw-r--r--tests/iter/tshallowcopy_closures.nim31
-rw-r--r--tests/js/taddr.nim36
-rw-r--r--tests/js/tbyvar.nim7
-rw-r--r--tests/js/test1.nim4
-rw-r--r--tests/js/test2.nim11
-rw-r--r--tests/js/tfloatround.nim7
-rw-r--r--tests/js/tstringitems.nim24
-rw-r--r--tests/js/tunittests.nim7
-rw-r--r--tests/let/tlet2.nim2
-rw-r--r--tests/macros/macro_bug.nim17
-rw-r--r--tests/macros/tbugs.nim6
-rw-r--r--tests/macros/tclosuremacro.nim (renamed from tests/closure/tclosuremacro.nim)4
-rw-r--r--tests/macros/tdumpast.nim8
-rw-r--r--tests/macros/tdumpast2.nim14
-rw-r--r--tests/macros/tgensym.nim12
-rw-r--r--tests/macros/tgentemplates.nim4
-rw-r--r--tests/macros/tlexerex.nim16
-rw-r--r--tests/macros/tmacro1.nim6
-rw-r--r--tests/macros/tmacro3.nim4
-rw-r--r--tests/macros/tmacro4.nim2
-rw-r--r--tests/macros/tmacro5.nim8
-rw-r--r--tests/macros/tmacro_in_template.nim10
-rw-r--r--tests/macros/tmacros1.nim4
-rw-r--r--tests/macros/tmacrotypes.nim14
-rw-r--r--tests/macros/tnimnode_for_runtime.nim (renamed from tests/macros/tnimrodnode_for_runtime.nim)3
-rw-r--r--tests/macros/tsame_name_497.nim9
-rw-r--r--tests/macros/tstringinterp.nim12
-rw-r--r--tests/macros/ttryparseexpr.nim1
-rw-r--r--tests/macros/tvarnimnode.nim2
-rw-r--r--tests/macros/tvtable.nim4
-rw-r--r--tests/macros/typesapi.nim17
-rw-r--r--tests/macros/typesapi2.nim49
-rw-r--r--tests/manyloc/argument_parser/argument_parser.nim8
-rw-r--r--tests/manyloc/argument_parser/ex_wget.nim8
-rw-r--r--tests/manyloc/keineschweine/README.md6
-rw-r--r--tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim72
-rw-r--r--tests/manyloc/keineschweine/dependencies/enet/enet.nim2
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim50
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim61
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim26
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim6
-rw-r--r--tests/manyloc/keineschweine/dependencies/sfml/sfml.nim22
-rw-r--r--tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim6
-rw-r--r--tests/manyloc/keineschweine/enet_server/enet_client.nim1
-rw-r--r--tests/manyloc/keineschweine/enet_server/enet_server.nim2
-rw-r--r--tests/manyloc/keineschweine/enet_server/nim.cfg (renamed from tests/manyloc/keineschweine/enet_server/nimrod.cfg)0
-rw-r--r--tests/manyloc/keineschweine/keineschweine.nim26
-rw-r--r--tests/manyloc/keineschweine/lib/game_objects.nim2
-rw-r--r--tests/manyloc/keineschweine/lib/gl.nim64
-rw-r--r--tests/manyloc/keineschweine/lib/map_filter.nim14
-rw-r--r--tests/manyloc/keineschweine/lib/sg_assets.nim8
-rw-r--r--tests/manyloc/keineschweine/lib/sg_packets.nim6
-rw-r--r--tests/manyloc/keineschweine/lib/vehicles.nim8
-rw-r--r--tests/manyloc/keineschweine/lib/zlib_helpers.nim14
-rw-r--r--tests/manyloc/keineschweine/server/nim.cfg (renamed from tests/manyloc/keineschweine/server/nimrod.cfg)0
-rw-r--r--tests/manyloc/keineschweine/server/old_sg_server.nim2
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim3
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim2
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim8
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim10
-rw-r--r--tests/manyloc/standalone/barebone.nim3
-rw-r--r--tests/metatype/tautonotgeneric.nim15
-rw-r--r--tests/metatype/tautoproc.nim8
-rw-r--r--tests/metatype/tcompositetypeclasses.nim2
-rw-r--r--tests/metatype/tmatrix.nim (renamed from tests/matrix/tmatrix.nim)0
-rw-r--r--tests/metatype/tmatrix1.nim (renamed from tests/matrix/tmatrix1.nim)0
-rw-r--r--tests/metatype/tmatrix2.nim (renamed from tests/matrix/tmatrix2.nim)0
-rw-r--r--tests/metatype/tmatrix3.nim19
-rw-r--r--tests/metatype/tsemistatic.nim7
-rw-r--r--tests/metatype/tstatic_overloading.nim10
-rw-r--r--tests/metatype/tstaticparammacro.nim (renamed from tests/static/tstaticparammacro.nim)23
-rw-r--r--tests/metatype/tstaticparams.nim86
-rw-r--r--tests/metatype/tstaticvector.nim17
-rw-r--r--tests/metatype/ttypedesc2.nim37
-rw-r--r--tests/metatype/ttypetraits.nim1
-rw-r--r--tests/metatype/tusertypeclasses.nim43
-rw-r--r--tests/metatype/tymatrix.nim (renamed from tests/matrix/issue1013.nim)0
-rw-r--r--tests/metatype/typeclassinference.nim1
-rw-r--r--tests/metatype/typedesc_as_value.nim11
-rw-r--r--tests/method/temptybody.nim11
-rw-r--r--tests/misc/parsecomb.nim105
-rw-r--r--tests/misc/tcharinc.nim10
-rw-r--r--tests/misc/tcolonisproc.nim9
-rw-r--r--tests/misc/teventemitter.nim8
-rw-r--r--tests/misc/tgtk.nim53
-rw-r--r--tests/misc/tinc.nim2
-rw-r--r--tests/misc/tinout.nim2
-rw-r--r--tests/misc/tissue710.nim2
-rw-r--r--tests/misc/tlibs.nim28
-rw-r--r--tests/misc/tnewlibs.nim21
-rw-r--r--tests/misc/tnoinst.nim1
-rw-r--r--tests/misc/tnoop.nim7
-rw-r--r--tests/misc/tparsecombnum.nim55
-rw-r--r--tests/misc/trangechecks.nim43
-rw-r--r--tests/misc/tslices.nim6
-rw-r--r--tests/misc/tunsigned64mod.nim26
-rw-r--r--tests/misc/tunsignedcomp.nim136
-rw-r--r--tests/misc/tunsignedconv.nim43
-rw-r--r--tests/misc/tunsignedinc.nim14
-rw-r--r--tests/misc/tvarious.nim112
-rw-r--r--tests/module/trecinca.nim12
-rw-r--r--tests/module/trecincb.nim13
-rw-r--r--tests/modules/mnamspc1.nim (renamed from tests/namspc/mnamspc1.nim)0
-rw-r--r--tests/modules/mnamspc2.nim (renamed from tests/namspc/mnamspc2.nim)0
-rw-r--r--tests/modules/mopaque.nim (renamed from tests/module/mopaque.nim)0
-rw-r--r--tests/modules/mrecmod.nim (renamed from tests/module/mrecmod.nim)0
-rw-r--r--tests/modules/mrecmod2.nim (renamed from tests/module/mrecmod2.nim)0
-rw-r--r--tests/modules/tmismatchedvisibility.nim4
-rw-r--r--tests/modules/tnamspc.nim (renamed from tests/namspc/tnamspc.nim)0
-rw-r--r--tests/modules/topaque.nim (renamed from tests/module/topaque.nim)0
-rw-r--r--tests/modules/trecinca.nim12
-rw-r--r--tests/modules/trecincb.nim13
-rw-r--r--tests/modules/trecmod.nim (renamed from tests/module/trecmod.nim)0
-rw-r--r--tests/modules/trecmod2.nim (renamed from tests/module/trecmod2.nim)0
-rw-r--r--tests/notnil/tnotnil4.nim8
-rw-r--r--tests/notnil/tnotnil_in_generic.nim27
-rw-r--r--tests/notnil/tnotnil_in_objconstr.nim14
-rw-r--r--tests/objects/tillegal_recursion.nim7
-rw-r--r--tests/objects/tobjconstr.nim26
-rw-r--r--tests/objects/tobjloop.nim15
-rw-r--r--tests/objects/tobjpragma.nim3
-rw-r--r--tests/objects/trefobjsyntax.nim27
-rw-r--r--tests/objects/trefobjsyntax2.nim19
-rw-r--r--tests/objvariant/tadrdisc.nim13
-rw-r--r--tests/objvariant/treassign.nim27
-rw-r--r--tests/osproc/tstdin.nim9
-rw-r--r--tests/overload/toverprc.nim30
-rw-r--r--tests/overload/tparams_after_varargs.nim17
-rw-r--r--tests/overload/tprefer_specialized_generic.nim22
-rw-r--r--tests/overload/tprefer_tygenericinst.nim42
-rw-r--r--tests/overload/tspec.nim81
-rw-r--r--tests/overload/tstmtoverload.nim38
-rw-r--r--tests/overload/tsymtabchange_during_or.nim24
-rw-r--r--tests/overload/tsystemcmp.nim13
-rw-r--r--tests/parallel/t5000.nim3
-rw-r--r--tests/parallel/tarray_of_channels.nim26
-rw-r--r--tests/parallel/tconvexhull.nim2
-rw-r--r--tests/parallel/tdont_be_stupid.nim15
-rw-r--r--tests/parallel/tgc_unsafe.nim32
-rw-r--r--tests/parallel/tgc_unsafe2.nim39
-rw-r--r--tests/parallel/tmissing_deepcopy.nim40
-rw-r--r--tests/parallel/treadafterwrite.nim31
-rw-r--r--tests/parallel/tsimple_array_checks.nim41
-rw-r--r--tests/parallel/tuseafterdef.nim31
-rw-r--r--tests/parallel/twrong_refcounts.nim53
-rw-r--r--tests/parser/tcommand_as_expr.nim9
-rw-r--r--tests/parser/tinvcolonlocation1.nim12
-rw-r--r--tests/parser/tinvcolonlocation2.nim15
-rw-r--r--tests/parser/tinvcolonlocation3.nim12
-rw-r--r--tests/parser/tprecedence.nim8
-rw-r--r--tests/parser/tproctype_pragmas.nim19
-rw-r--r--tests/parser/tstrongspaces.nim33
-rw-r--r--tests/parser/ttupleunpack.nim35
-rw-r--r--tests/parser/ttypeof.nim26
-rw-r--r--tests/parser/twhen_in_enum.nim11
-rw-r--r--tests/rodfiles/nim.cfg (renamed from tests/rodfiles/nimrod.cfg)0
-rw-r--r--tests/seq/tsequtils.nim2
-rw-r--r--tests/showoff/tdrdobbs_examples.nim12
-rw-r--r--tests/stdlib/tcount.nim29
-rw-r--r--tests/stdlib/tdialogs.nim8
-rw-r--r--tests/stdlib/tgetfileinfo.nim17
-rw-r--r--tests/stdlib/tircbot.nim452
-rw-r--r--tests/stdlib/tmarshal.nim28
-rw-r--r--tests/stdlib/tmath2.nim4
-rw-r--r--tests/stdlib/tmitems.nim136
-rw-r--r--tests/stdlib/tnet.nim47
-rw-r--r--tests/stdlib/tparsefloat.nim3
-rw-r--r--tests/stdlib/tpegs.nim92
-rw-r--r--tests/stdlib/tpermutations.nim19
-rw-r--r--tests/stdlib/treloop.nim9
-rw-r--r--tests/stdlib/tsinglylinkedring.nim29
-rw-r--r--tests/stdlib/tsockets.nim12
-rw-r--r--tests/stdlib/tstrutil.nim61
-rw-r--r--tests/system/tsettostring.nim8
-rw-r--r--tests/table/ttables.nim128
-rw-r--r--tests/template/t2do.nim22
-rw-r--r--tests/template/t_otemplates.nim10
-rw-r--r--tests/template/texponential_eval.nim47
-rw-r--r--tests/template/tparams_gensymed.nim62
-rw-r--r--tests/template/tscope.nim12
-rw-r--r--tests/template/tstmt_semchecked_twice.nim30
-rw-r--r--tests/template/ttempl2.nim8
-rw-r--r--tests/template/twrongmapit.nim2
-rw-r--r--tests/template/utemplates.nim6
-rw-r--r--tests/testament/backend.nim2
-rw-r--r--tests/testament/caasdriver.nim15
-rw-r--r--tests/testament/categories.nim114
-rw-r--r--tests/testament/htmlgen.nim41
-rw-r--r--tests/testament/specs.nim12
-rw-r--r--tests/testament/tester.nim110
-rw-r--r--tests/testament/tester.nim.cfg1
-rw-r--r--tests/threads/ttryrecv.nim35
-rw-r--r--tests/trmacros/tor.nim2
-rw-r--r--tests/tuples/tanontuples.nim3
-rw-r--r--tests/tuples/tdifferent_instantiations.nim9
-rw-r--r--tests/tuples/tgeneric_tuple.nim9
-rw-r--r--tests/tuples/tgeneric_tuple2.nim17
-rw-r--r--tests/tuples/tuint_tuple.nim10
-rw-r--r--tests/typerel/trectuple.nim1
-rw-r--r--tests/typerel/tregionptrs2.nim23
-rw-r--r--tests/typerel/tsymchoice_for_expr.nim15
-rw-r--r--tests/typerel/typedescs.nim7
-rw-r--r--tests/types/tauto_canbe_void.nim9
-rw-r--r--tests/types/temptyseqs.nim26
-rw-r--r--tests/types/tforwty2.nim2
-rw-r--r--tests/types/tinfiniterecursion.nim8
-rw-r--r--tests/types/tisop.nim6
-rw-r--r--tests/types/tisopr.nim58
-rw-r--r--tests/usingstmt/tusingstatement.nim22
-rw-r--r--tests/vm/tconsteval.nim2
-rw-r--r--tests/vm/tconsttable.nim19
-rw-r--r--tests/vm/tldconst.nim14
-rw-r--r--tests/vm/triangle_array.nim17
-rw-r--r--tests/vm/tstringnil.nim50
-rw-r--r--tinyc/arm-gen.c2
-rw-r--r--tinyc/c67-gen.c2
-rw-r--r--tinyc/i386-asm.c2
-rw-r--r--tinyc/lib/bcheck.c2
-rw-r--r--tinyc/tcc-doc.html6
-rw-r--r--tinyc/tcc-doc.texi6
-rw-r--r--tinyc/tccasm.c2
-rw-r--r--tinyc/tccgen.c4
-rw-r--r--tinyc/tcctok.h2
-rw-r--r--tinyc/win32/include/fcntl.h2
-rw-r--r--todo.txt57
-rw-r--r--tools/nimgrep.nim4
-rw-r--r--tools/niminst/buildbat.tmpl2
-rw-r--r--tools/niminst/buildsh.tmpl14
-rw-r--r--tools/niminst/debcreation.nim2
-rw-r--r--tools/niminst/deinstall.tmpl2
-rw-r--r--tools/niminst/inno.tmpl4
-rw-r--r--tools/niminst/install.tmpl2
-rw-r--r--tools/niminst/makefile.tmpl168
-rw-r--r--tools/niminst/niminst.nim90
-rw-r--r--tools/niminst/nsis.tmpl10
-rw-r--r--tools/nimrepl.nim2
-rw-r--r--tools/nimweb.nim65
-rw-r--r--tools/website.tmpl250
-rw-r--r--web/assets/images/bg.pngbin0 -> 149129 bytes
-rw-r--r--web/assets/images/docs-articles.pngbin0 -> 381 bytes
-rw-r--r--web/assets/images/docs-examples.pngbin0 -> 596 bytes
-rw-r--r--web/assets/images/docs-internals.pngbin0 -> 621 bytes
-rw-r--r--web/assets/images/docs-libraries.pngbin0 -> 335 bytes
-rw-r--r--web/assets/images/docs-tools.pngbin0 -> 636 bytes
-rw-r--r--web/assets/images/docs-tutorials.pngbin0 -> 560 bytes
-rw-r--r--web/assets/images/favicon.icobin0 -> 1150 bytes
-rw-r--r--web/assets/images/foot.pngbin0 -> 784 bytes
-rw-r--r--web/assets/images/glow-arrow.pngbin0 -> 8657 bytes
-rw-r--r--web/assets/images/glow-line.pngbin0 -> 2261 bytes
-rw-r--r--web/assets/images/head-link.pngbin0 -> 203 bytes
-rw-r--r--web/assets/images/head-link_hover.pngbin0 -> 799 bytes
-rw-r--r--web/assets/images/head.pngbin0 -> 171 bytes
-rw-r--r--web/assets/images/logo.pngbin101053 -> 116562 bytes
-rw-r--r--web/assets/images/mascot.pngbin0 -> 18022 bytes
-rw-r--r--web/assets/images/more-links_editors.pngbin0 -> 852 bytes
-rw-r--r--web/assets/images/more-links_forum.pngbin0 -> 858 bytes
-rw-r--r--web/assets/images/more-links_github.pngbin0 -> 713 bytes
-rw-r--r--web/assets/images/more-links_nimbuild.pngbin0 -> 724 bytes
-rw-r--r--web/assets/images/nim-logo.svg500
-rw-r--r--web/assets/images/quotes.pngbin0 -> 979 bytes
-rw-r--r--web/assets/images/sidebar.pngbin971 -> 109579 bytes
-rw-r--r--web/assets/images/slideshow-nav.pngbin0 -> 416 bytes
-rw-r--r--web/assets/images/slideshow-nav_active.pngbin0 -> 673 bytes
-rw-r--r--web/assets/images/tabEnd.pngbin0 -> 194 bytes
-rw-r--r--web/assets/index.js34
-rw-r--r--web/assets/style.css740
-rw-r--r--web/community.txt171
-rw-r--r--web/documentation.txt57
-rw-r--r--web/download.txt32
-rw-r--r--web/index.txt52
-rw-r--r--web/learn.txt56
-rw-r--r--web/news.txt781
-rw-r--r--web/nimblepkglist.nim (renamed from web/babelpkglist.nim)5
-rw-r--r--web/question.txt215
-rw-r--r--web/support.txt39
-rw-r--r--web/ticker.txt54
-rw-r--r--web/website.ini (renamed from web/nim.ini)52
706 files changed, 30027 insertions, 19112 deletions
diff --git a/.gitignore b/.gitignore
index 462df4efc..d804fb8f5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,3 +41,4 @@ xcuserdata/
 /testresults.html
 /testresults.json
 testament.db
+/csources/
diff --git a/build.sh b/build.sh
new file mode 100644
index 000000000..139c28359
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+set -e
+set -x
+
+if [ ! -d "csources" ]; then
+	git clone --depth 1 https://github.com/nim-lang/csources.git
+fi
+
+cd "csources"
+sh build.sh
+cd ".."
+
+./bin/nim c koch
+./koch boot -d:release
+
+cp -f install.sh.template install.sh
+chmod +x install.sh
+
+exit 0
diff --git a/compiler.nimble b/compiler.nimble
new file mode 100644
index 000000000..52eb4083b
--- /dev/null
+++ b/compiler.nimble
@@ -0,0 +1,11 @@
+[Package]
+name = "compiler"
+version = "0.10.3"
+author = "Andreas Rumpf"
+description = "Compiler package providing the compiler sources as a library."
+license = "MIT"
+
+InstallDirs = "doc, compiler"
+
+[Deps]
+Requires: "nim >= 0.10.3"
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 8ebe5afa6..3798410e8 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2013 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -9,12 +9,12 @@
 
 # abstract syntax tree + symbol table
 
-import 
-  msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists, 
+import
+  msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists,
   intsets, idgen
 
 type
-  TCallingConvention* = enum 
+  TCallingConvention* = enum
     ccDefault,                # proc has no explicit calling convention
     ccStdCall,                # procedure is stdcall
     ccCDecl,                  # cdecl
@@ -26,12 +26,12 @@ type
     ccClosure,                # proc has a closure
     ccNoConvention            # needed for generating proper C procs sometimes
 
-const 
-  CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall", 
+const
+  CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall",
     "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall",
     "closure", "noconv"]
 
-type 
+type
   TNodeKind* = enum # order is extremely important, because ranges are used
                     # to check whether a node belongs to a certain class
     nkNone,               # unknown node kind: indicates an error
@@ -64,13 +64,13 @@ type
                           # end of atoms
     nkMetaNode_Obsolete,  # difficult to explain; represents itself
                           # (used for macros)
-    nkDotCall,            # used to temporarily flag a nkCall node; 
+    nkDotCall,            # used to temporarily flag a nkCall node;
                           # this is used
                           # for transforming ``s.len`` to ``len(s)``
 
     nkCommand,            # a call like ``p 2, 4`` without parenthesis
     nkCall,               # a call like p(x, y) or an operation like +(a, b)
-    nkCallStrLit,         # a call with a string literal 
+    nkCallStrLit,         # a call with a string literal
                           # x"abc" has two sons: nkIdent, nkRStrLit
                           # x"""abc""" has two sons: nkIdent, nkTripleStrLit
     nkInfix,              # a call like (a + b)
@@ -126,7 +126,7 @@ type
 
     nkAsgn,               # a = b
     nkFastAsgn,           # internal node for a fast ``a = b``
-                          # (no string copy) 
+                          # (no string copy)
     nkGenericParams,      # generic parameters
     nkFormalParams,       # formal parameters
     nkOfInherit,          # inherited from symbol
@@ -192,10 +192,11 @@ type
 
     nkWith,               # distinct with `foo`
     nkWithout,            # distinct without `foo`
-    
+
     nkTypeOfExpr,         # type(1+2)
     nkObjectTy,           # object body
     nkTupleTy,            # tuple body
+    nkTupleClassTy,       # tuple type class
     nkTypeClassTy,        # user-defined type class
     nkStaticTy,           # ``static[T]``
     nkRecList,            # list of object parts
@@ -226,7 +227,7 @@ type
   TSymFlag* = enum    # already 32 flags!
     sfUsed,           # read access of sym (for warnings) or simply used
     sfExported,       # symbol is exported from module
-    sfFromGeneric,    # symbol is instantiation of a generic; this is needed 
+    sfFromGeneric,    # symbol is instantiation of a generic; this is needed
                       # for symbol file generation; such symbols should always
                       # be written into the ROD file
     sfGlobal,         # symbol is at global scope
@@ -256,7 +257,7 @@ type
     sfThread,         # proc will run as a thread
                       # variable is a thread variable
     sfCompileTime,    # proc can be evaluated at compile time
-    sfMerge,          # proc can be merged with itself
+    sfConstructor,    # proc is a C++ constructor
     sfDeadCodeElim,   # dead code elimination for the module is turned on
     sfBorrow,         # proc is borrowed
     sfInfixCall,      # symbol needs infix call syntax in target language;
@@ -284,9 +285,9 @@ const
 
   sfAnon* = sfDiscardable
     # symbol name that was generated by the compiler
-    # the compiler will avoid printing such names 
+    # the compiler will avoid printing such names
     # in user messages.
-      
+
   sfNoForward* = sfRegister
     # forward declarations are not required (per module)
 
@@ -295,12 +296,13 @@ const
   sfCompileToCpp* = sfInfixCall       # compile the module as C++ code
   sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
   sfExperimental* = sfOverriden       # module uses the .experimental switch
+  sfGoto* = sfOverriden               # var is used for 'goto' code generation
 
 const
   # getting ready for the future expr/stmt merge
   nkWhen* = nkWhenStmt
   nkWhenExpr* = nkWhenStmt
-  nkEffectList* = nkArgList 
+  nkEffectList* = nkArgList
   # hacks ahead: an nkEffectList is a node with 4 children:
   exceptionEffects* = 0 # exceptions at position 0
   usesEffects* = 1      # read effects at position 1
@@ -314,14 +316,14 @@ type
                      # XXX put this into an include file to avoid this issue!
     tyNone, tyBool, tyChar,
     tyEmpty, tyArrayConstr, tyNil, tyExpr, tyStmt, tyTypeDesc,
-    tyGenericInvokation, # ``T[a, b]`` for types to invoke
+    tyGenericInvocation, # ``T[a, b]`` for types to invoke
     tyGenericBody,       # ``T[a, b, body]`` last parameter is the body
     tyGenericInst,       # ``T[a, b, realInstance]`` instantiated generic type
                          # realInstance will be a concrete type like tyObject
                          # unless this is an instance of a generic alias type.
                          # then realInstance will be the tyGenericInst of the
                          # completely (recursively) resolved alias.
-                         
+
     tyGenericParam,      # ``a`` in the above patterns
     tyDistinct,
     tyEnum,
@@ -340,14 +342,14 @@ type
     tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers
     tyFloat, tyFloat32, tyFloat64, tyFloat128,
     tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64,
-    tyBigNum, 
-    tyConst, tyMutable, tyVarargs, 
+    tyBigNum,
+    tyConst, tyMutable, tyVarargs,
     tyIter, # unused
     tyProxy # used as errornous type (for idetools)
-    
+
     tyBuiltInTypeClass #\
       # Type such as the catch-all object, tuple, seq, etc
-    
+
     tyUserTypeClass #\
       # the body of a user-defined type class
 
@@ -357,27 +359,27 @@ type
       # tyGenericInst represents concrete types, while
       # this is still a "generic param" that will bind types
       # and resolves them during sigmatch and instantiation.
-    
+
     tyCompositeTypeClass #\
       # Type such as seq[Number]
-      # The notes for tyUserTypeClassInst apply here as well 
+      # The notes for tyUserTypeClassInst apply here as well
       # sons[0]: the original expression used by the user.
       # sons[1]: fully expanded and instantiated meta type
       # (potentially following aliases)
-    
+
     tyAnd, tyOr, tyNot #\
       # boolean type classes such as `string|int`,`not seq`,
       # `Sortable and Enumable`, etc
-    
+
     tyAnything #\
       # a type class matching any type
-    
+
     tyStatic #\
       # a value known at compile type (the underlying type is .base)
-    
+
     tyFromExpr #\
       # This is a type representing an expression that depends
-      # on generic parameters (the exprsesion is stored in t.n)
+      # on generic parameters (the expression is stored in t.n)
       # It will be converted to a real type only during generic
       # instantiation and prior to this it has the potential to
       # be any type.
@@ -390,7 +392,7 @@ type
       # sons[0]: type of containing object or tuple
       # sons[1]: field type
       # .n: nkDotExpr storing the field name
-    
+
 static:
   # remind us when TTypeKind stops to fit in a single 64-bit word
   assert TTypeKind.high.ord <= 63
@@ -399,6 +401,7 @@ const
   tyPureObject* = tyTuple
   GcTypeKinds* = {tyRef, tySequence, tyString}
   tyError* = tyProxy # as an errornous node should match everything
+  tyUnknown* = tyFromExpr
 
   tyUnknownTypes* = {tyError, tyFromExpr}
 
@@ -407,7 +410,7 @@ const
                     tyAnd, tyOr, tyNot, tyAnything}
 
   tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyExpr} + tyTypeClasses
- 
+
 type
   TTypeKinds* = set[TTypeKind]
 
@@ -427,7 +430,8 @@ type
     nfExplicitCall # x.y() was used instead of x.y
     nfExprCall  # this is an attempt to call a regular expression
     nfIsRef     # this node is a 'ref' node; used for the VM
- 
+    nfIsCursor  # this node is attached a cursor; used for idetools
+
   TNodeFlags* = set[TNodeFlag]
   TTypeFlag* = enum   # keep below 32 for efficiency reasons (now: 28)
     tfVarargs,        # procedure has C styled varargs
@@ -446,7 +450,7 @@ type
                       # proc foo(L: static[int]): array[L, int]
                       # can be attached to ranges to indicate that the range
                       # depends on unresolved static params.
-    tfRetType,        # marks return types in proc (used to detect type classes 
+    tfRetType,        # marks return types in proc (used to detect type classes
                       # used as return types for return type inference)
     tfCapturesEnv,    # whether proc really captures some environment
     tfByCopy,         # pass object/tuple by copy (C backend)
@@ -454,10 +458,10 @@ type
     tfIterator,       # type is really an iterator, not a tyProc
     tfShared,         # type is 'shared'
     tfNotNil,         # type cannot be 'nil'
-    
+
     tfNeedsInit,      # type constains a "not nil" constraint somewhere or some
-                      # other type so that it requires inititalization
-    tfHasShared,      # type constains a "shared" constraint modifier somewhere
+                      # other type so that it requires initalization
+    tfVarIsPtr,       # 'var' type is translated like 'ptr' even in C++ mode
     tfHasMeta,        # type contains "wildcard" sub-types such as generic params
                       # or other type classes
     tfHasGCedMem,     # type contains GC'ed memory
@@ -469,7 +473,7 @@ type
                       # T and I here can bind to both typedesc and static types
                       # before this is determined, we'll consider them to be a
                       # wildcard type.
-    tfGuarded         # guarded pointer
+    tfHasAsgn         # type has overloaded assignment operator
     tfBorrowDot       # distinct type borrows '.'
 
   TTypeFlags* = set[TTypeFlag]
@@ -518,41 +522,44 @@ const
   tfGcSafe* = tfThread
   tfObjHasKids* = tfEnumHasHoles
   skError* = skUnknown
-  
+
   # type flags that are essential for type equality:
-  eqTypeFlags* = {tfIterator, tfShared, tfNotNil}
+  eqTypeFlags* = {tfIterator, tfShared, tfNotNil, tfVarIsPtr}
 
 type
   TMagic* = enum # symbols that require compiler magic:
     mNone,
     mDefined, mDefinedInScope, mCompiles,
-    mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf,
+    mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof, mPlugin,
     mEcho, mShallowCopy, mSlurp, mStaticExec,
     mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
-    mUnaryLt, mSucc, 
-    mPred, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray, 
-    mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref, 
-    mGCunref, mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64, 
-    mDivI64, mModI64,
+    mUnaryLt, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
+    mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq,
+    mIncl, mExcl, mCard, mChr,
+    mGCref, mGCunref,
+
+    mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
+    mDivI64, mModI64, mSucc, mPred,
     mAddF64, mSubF64, mMulF64, mDivF64,
-    mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI, 
-    mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
-    mMinF64, mMaxF64, mAddU, mSubU, mMulU, 
+
+    mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
+    mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64,
+    mMinF64, mMaxF64, mAddU, mSubU, mMulU,
     mDivU, mModU, mEqI, mLeI,
-    mLtI, 
-    mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64, 
-    mLeU, mLtU, mLeU64, mLtU64, 
-    mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef, 
+    mLtI,
+    mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
+    mLeU, mLtU, mLeU64, mLtU64,
+    mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
     mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mEqProc, mUnaryMinusI,
-    mUnaryMinusI64, mAbsI, mAbsI64, mNot, 
-    mUnaryPlusI, mBitnotI, mUnaryPlusI64, 
-    mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64, 
-    mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32, 
-    mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr, 
-    mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, 
-    mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, 
-    mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT, 
-    mConTArr, mConTT, mSlice,
+    mUnaryMinusI64, mAbsI, mAbsI64, mNot,
+    mUnaryPlusI, mBitnotI,
+    mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
+    mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
+    mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
+    mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
+    mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
+    mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mSlice,
+    mDotDot, # this one is only necessary to give nice compile time warnings
     mFields, mFieldPairs, mOmpParFor,
     mAppendStrCh, mAppendStrStr, mAppendSeqElem,
     mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq,
@@ -582,36 +589,36 @@ type
 
 # things that we can evaluate safely at compile time, even if not asked for it:
 const
-  ctfeWhitelist* = {mNone, mUnaryLt, mSucc, 
-    mPred, mInc, mDec, mOrd, mLengthOpenArray, 
-    mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, 
-    mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64, 
+  ctfeWhitelist* = {mNone, mUnaryLt, mSucc,
+    mPred, mInc, mDec, mOrd, mLengthOpenArray,
+    mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq,
+    mIncl, mExcl, mCard, mChr,
+    mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
     mDivI64, mModI64, mAddF64, mSubF64, mMulF64, mDivF64,
-    mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI, 
-    mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
-    mMinF64, mMaxF64, mAddU, mSubU, mMulU, 
+    mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
+    mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64,
+    mMinF64, mMaxF64, mAddU, mSubU, mMulU,
     mDivU, mModU, mEqI, mLeI,
-    mLtI, 
-    mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64, 
-    mLeU, mLtU, mLeU64, mLtU64, 
-    mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef, 
-    mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI, 
-    mUnaryMinusI64, mAbsI, mAbsI64, mNot, 
-    mUnaryPlusI, mBitnotI, mUnaryPlusI64, 
-    mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64, 
-    mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32, 
-    mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr, 
-    mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, 
-    mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, 
-    mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT, 
-    mConTArr, mConTT,
-    mAppendStrCh, mAppendStrStr, mAppendSeqElem, 
+    mLtI,
+    mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
+    mLeU, mLtU, mLeU64, mLtU64,
+    mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
+    mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI,
+    mUnaryMinusI64, mAbsI, mAbsI64, mNot,
+    mUnaryPlusI, mBitnotI,
+    mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
+    mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
+    mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
+    mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
+    mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
+    mPlusSet, mMinusSet, mSymDiffSet, mConStrStr,
+    mAppendStrCh, mAppendStrStr, mAppendSeqElem,
     mInRange, mInSet, mRepr,
     mCopyStr, mCopyStrLast}
   # magics that require special semantic checking and
   # thus cannot be overloaded (also documented in the spec!):
   SpecialSemMagics* = {
-    mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf, 
+    mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf,
     mEcho, mShallowCopy, mExpandToAst, mParallel, mSpawn, mAstToStr}
 
 type
@@ -632,79 +639,81 @@ type
       floatVal*: BiggestFloat
     of nkStrLit..nkTripleStrLit:
       strVal*: string
-    of nkSym: 
+    of nkSym:
       sym*: PSym
-    of nkIdent: 
+    of nkIdent:
       ident*: PIdent
     else:
       sons*: TNodeSeq
     comment*: string
-  
+
   TSymSeq* = seq[PSym]
   TStrTable* = object         # a table[PIdent] of PSym
     counter*: int
     data*: TSymSeq
-  
+
   # -------------- backend information -------------------------------
-  TLocKind* = enum 
+  TLocKind* = enum
     locNone,                  # no location
     locTemp,                  # temporary location
     locLocalVar,              # location is a local variable
     locGlobalVar,             # location is a global variable
     locParam,                 # location is a parameter
     locField,                 # location is a record field
-    locArrayElem,             # location is an array element
     locExpr,                  # "location" is really an expression
     locProc,                  # location is a proc (an address of a procedure)
     locData,                  # location is a constant
     locCall,                  # location is a call expression
     locOther                  # location is something other
-  TLocFlag* = enum 
+  TLocFlag* = enum
     lfIndirect,               # backend introduced a pointer
-    lfParamCopy,              # backend introduced a parameter copy (LLVM)
+    lfFullExternalName, # only used when 'gCmd == cmdPretty': Indicates
+      # that the symbol has been imported via 'importc: "fullname"' and
+      # no format string.
     lfNoDeepCopy,             # no need for a deep copy
     lfNoDecl,                 # do not declare it in C
     lfDynamicLib,             # link symbol to dynamic library
     lfExportLib,              # export symbol for dynamic library generation
     lfHeader,                 # include header file for symbol
-    lfImportCompilerProc      # ``importc`` of a compilerproc
-  TStorageLoc* = enum 
+    lfImportCompilerProc,     # ``importc`` of a compilerproc
+    lfSingleUse               # no location yet and will only be used once
+  TStorageLoc* = enum
     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[TLocFlag]
-  TLoc*{.final.} = object     
+  TLoc* = object
     k*: TLocKind              # kind of location
     s*: TStorageLoc
     flags*: TLocFlags         # location's flags
     t*: PType                 # type of location
-    r*: PRope                 # rope value of location (code generators)
-    heapRoot*: PRope          # keeps track of the enclosing heap object that
+    r*: Rope                 # rope value of location (code generators)
+    heapRoot*: Rope          # keeps track of the enclosing heap object that
                               # owns this location (required by GC algorithms
                               # employing heap snapshots or sliding views)
 
   # ---------------- end of backend information ------------------------------
 
-  TLibKind* = enum 
+  TLibKind* = enum
     libHeader, libDynamic
   TLib* = object of lists.TListEntry # also misused for headers!
     kind*: TLibKind
     generated*: bool          # needed for the backends:
     isOverriden*: bool
-    name*: PRope
+    name*: Rope
     path*: PNode              # can be a string literal!
-  
+
   TInstantiation* = object
     sym*: PSym
     concreteTypes*: seq[PType]
     usedBy*: seq[int32]       # list of modules using the generic
                               # needed in caas mode for purging the cache
-                              # XXX: it's possible to switch to a 
+                              # XXX: it's possible to switch to a
                               # simple ref count here
-  
+
   PInstantiation* = ref TInstantiation
- 
+
   TScope* = object
     depthLevel*: int
     symbols*: TStrTable
@@ -722,7 +731,8 @@ type
       typScope*: PScope
     of routineKinds:
       procInstCache*: seq[PInstantiation]
-      scope*: PScope          # the scope where the proc was defined
+      gcUnsafetyReason*: PSym  # for better error messages wrt gcsafe
+      #scope*: PScope          # the scope where the proc was defined
     of skModule:
       # modules keep track of the generic symbols they use from other modules.
       # this is because in incremental compilation, when a module is about to
@@ -735,7 +745,7 @@ type
       # check for the owner when touching 'usedGenerics'.
       usedGenerics*: seq[PInstantiation]
       tab*: TStrTable         # interface table for modules
-    of skLet, skVar, skField:
+    of skLet, skVar, skField, skForVar:
       guard*: PSym
     else: nil
     magic*: TMagic
@@ -771,7 +781,7 @@ type
     constraint*: PNode        # additional constraints like 'lit|result'; also
                               # misused for the codegenDecl pragma in the hope
                               # it won't cause problems
-  
+
   TTypeSeq* = seq[PType]
   TLockLevel* = distinct int16
   TType* {.acyclic.} = object of TIdObj # \
@@ -788,8 +798,8 @@ type
                               # for enum types a list of symbols
                               # for tyInt it can be the int literal
                               # for procs and tyGenericBody, it's the
-                              # the body of the user-defined type class
                               # formal param list
+                              # for concepts, the concept body
                               # else: unused
     owner*: PSym              # the 'owner' of the type
     sym*: PSym                # types have the sym associated with them
@@ -798,51 +808,52 @@ type
                               # mean that there is no destructor.
                               # see instantiateDestructor in semdestruct.nim
     deepCopy*: PSym           # overriden 'deepCopy' operation
+    assignment*: PSym         # overriden '=' operator
     size*: BiggestInt         # the size of the type in bytes
                               # -1 means that the size is unkwown
     align*: int16             # the type's alignment requirements
     lockLevel*: TLockLevel    # lock level as required for deadlock checking
     loc*: TLoc
 
-  TPair*{.final.} = object 
+  TPair* = object
     key*, val*: RootRef
 
   TPairSeq* = seq[TPair]
-  TTable*{.final.} = object   # the same as table[PObject] of PObject
+  TTable* = object   # the same as table[PObject] of PObject
     counter*: int
     data*: TPairSeq
 
-  TIdPair*{.final.} = object 
+  TIdPair* = object
     key*: PIdObj
     val*: RootRef
 
   TIdPairSeq* = seq[TIdPair]
-  TIdTable*{.final.} = object # the same as table[PIdent] of PObject
+  TIdTable* = object # the same as table[PIdent] of PObject
     counter*: int
     data*: TIdPairSeq
 
-  TIdNodePair*{.final.} = object 
+  TIdNodePair* = object
     key*: PIdObj
     val*: PNode
 
   TIdNodePairSeq* = seq[TIdNodePair]
-  TIdNodeTable*{.final.} = object # the same as table[PIdObj] of PNode
+  TIdNodeTable* = object # the same as table[PIdObj] of PNode
     counter*: int
     data*: TIdNodePairSeq
 
-  TNodePair*{.final.} = object 
+  TNodePair* = object
     h*: THash                 # because it is expensive to compute!
     key*: PNode
     val*: int
 
   TNodePairSeq* = seq[TNodePair]
-  TNodeTable*{.final.} = object # the same as table[PNode] of int;
+  TNodeTable* = object # the same as table[PNode] of int;
                                 # nodes are compared by structure!
     counter*: int
     data*: TNodePairSeq
 
   TObjectSeq* = seq[RootRef]
-  TObjectSet*{.final.} = object 
+  TObjectSet* = object
     counter*: int
     data*: TObjectSeq
 
@@ -853,27 +864,27 @@ type
 # same name as an imported module. This is necessary because of
 # the poor naming choices in the standard library.
 
-const 
+const
   OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator,
     skConverter, skModule, skTemplate, skMacro}
 
-  GenericTypes*: TTypeKinds = {tyGenericInvokation, tyGenericBody, 
+  GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody,
     tyGenericParam}
-  
-  StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray, 
+
+  StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray,
     tySet, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyOpenArray,
     tyVarargs}
-  
+
   ConcreteTypes*: TTypeKinds = { # types of the expr that may occur in::
                                  # var x = expr
-    tyBool, tyChar, tyEnum, tyArray, tyObject, 
+    tyBool, tyChar, tyEnum, tyArray, tyObject,
     tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc,
-    tyPointer, 
+    tyPointer,
     tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
     tyUInt..tyUInt64}
   IntegralTypes* = {tyBool, tyChar, tyEnum, tyInt..tyInt64,
     tyFloat..tyFloat128, tyUInt..tyUInt64}
-  ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet, 
+  ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet,
                                     tyTuple, tySequence}
   NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence,
     tyProc, tyString, tyError}
@@ -882,7 +893,7 @@ const
     skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
   PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
                                       nfDotSetter, nfDotField,
-                                      nfIsRef}
+                                      nfIsRef, nfIsCursor}
   namePos* = 0
   patternPos* = 1    # empty except for term rewriting macros
   genericParamsPos* = 2
@@ -912,53 +923,7 @@ const
 
   skIterators* = {skIterator, skClosureIterator}
 
-  lfFullExternalName* = lfParamCopy # \
-    # only used when 'gCmd == cmdPretty': Indicates that the symbol has been
-    # imported via 'importc: "fullname"' and no format string.
-
-# creator procs:
-proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
-             info: TLineInfo): PSym
-proc newType*(kind: TTypeKind, owner: PSym): PType
-proc newNode*(kind: TNodeKind): PNode
-proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode
-proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode
-proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode
-proc newStrNode*(kind: TNodeKind, strVal: string): PNode
-proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode
-proc newSymNode*(sym: PSym): PNode
-proc newNodeI*(kind: TNodeKind, info: TLineInfo): PNode
-proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode
-proc initStrTable*(x: var TStrTable)
-proc initTable*(x: var TTable)
-proc initIdTable*(x: var TIdTable)
-proc initObjectSet*(x: var TObjectSet)
-proc initIdNodeTable*(x: var TIdNodeTable)
-proc initNodeTable*(x: var TNodeTable)
-  
-# copy procs:
-proc copyType*(t: PType, owner: PSym, keepId: bool): PType
-proc copySym*(s: PSym, keepId: bool = false): PSym
-proc assignType*(dest, src: PType)
-proc copyStrTable*(dest: var TStrTable, src: TStrTable)
-proc copyTable*(dest: var TTable, src: TTable)
-proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet)
-proc copyIdTable*(dest: var TIdTable, src: TIdTable)
-proc sonsLen*(n: PNode): int {.inline.}
-proc sonsLen*(n: PType): int {.inline.}
-proc lastSon*(n: PNode): PNode {.inline.}
-proc lastSon*(n: PType): PType {.inline.}
-proc newSons*(father: PNode, length: int)
-proc newSons*(father: PType, length: int)
-proc addSon*(father, son: PNode)
-proc delSon*(father: PNode, idx: int)
-proc hasSonWith*(n: PNode, kind: TNodeKind): bool
-proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool
-proc replaceSons*(n: PNode, oldKind, newKind: TNodeKind)
-proc copyNode*(src: PNode): PNode
-  # does not copy its sons!
-proc copyTree*(src: PNode): PNode
-  # does copy its sons!
+var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things
 
 proc isCallExpr*(n: PNode): bool =
   result = n.kind in nkCallKinds
@@ -968,17 +933,17 @@ proc discardSons*(father: PNode)
 proc len*(n: PNode): int {.inline.} =
   if isNil(n.sons): result = 0
   else: result = len(n.sons)
-  
+
 proc safeLen*(n: PNode): int {.inline.} =
   ## works even for leaves.
   if n.kind in {nkNone..nkNilLit} or isNil(n.sons): result = 0
   else: result = len(n.sons)
-  
+
 proc add*(father, son: PNode) =
   assert son != nil
   if isNil(father.sons): father.sons = @[]
   add(father.sons, son)
-  
+
 proc `[]`*(n: PNode, i: int): PNode {.inline.} =
   result = n.sons[i]
 
@@ -986,7 +951,58 @@ proc `[]`*(n: PNode, i: int): PNode {.inline.} =
 template `{}`*(n: PNode, i: int): expr = n[i -| n]
 template `{}=`*(n: PNode, i: int, s: PNode): stmt =
   n.sons[i -| n] = s
-  
+
+when defined(useNodeIds):
+  const nodeIdToDebug* = -1 # 299750 # 300761 #300863 # 300879
+  var gNodeId: int
+
+proc newNode*(kind: TNodeKind): PNode =
+  new(result)
+  result.kind = kind
+  #result.info = UnknownLineInfo() inlined:
+  result.info.fileIndex = int32(- 1)
+  result.info.col = int16(- 1)
+  result.info.line = int16(- 1)
+  when defined(useNodeIds):
+    result.id = gNodeId
+    if result.id == nodeIdToDebug:
+      echo "KIND ", result.kind
+      writeStackTrace()
+    inc gNodeId
+
+proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
+  result = newNode(kind)
+  result.intVal = intVal
+
+proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode =
+  result = newIntNode(kind, intVal)
+  result.typ = typ
+
+proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode =
+  result = newNode(kind)
+  result.floatVal = floatVal
+
+proc newStrNode*(kind: TNodeKind, strVal: string): PNode =
+  result = newNode(kind)
+  result.strVal = strVal
+
+proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
+             info: TLineInfo): PSym =
+  # generates a symbol and initializes the hash field too
+  new(result)
+  result.name = name
+  result.kind = symKind
+  result.flags = {}
+  result.info = info
+  result.options = gOptions
+  result.owner = owner
+  result.offset = - 1
+  result.id = getID()
+  when debugIds:
+    registerId(result)
+  #if result.id < 2000:
+  #  MessageOut(name.s & " has id: " & toString(result.id))
+
 var emptyNode* = newNode(nkEmpty)
 # There is a single empty node that is shared! Do not overwrite it!
 
@@ -1024,97 +1040,60 @@ proc appendToModule*(m: PSym, n: PNode) =
   else:
     assert m.ast.kind == nkStmtList
     m.ast.sons.add(n)
-  
+
 const                         # for all kind of hash tables:
   GrowthFactor* = 2           # must be power of 2, > 0
   StartSize* = 8              # must be power of 2, > 0
 
-proc copyStrTable(dest: var TStrTable, src: TStrTable) = 
+proc copyStrTable*(dest: var TStrTable, src: TStrTable) =
   dest.counter = src.counter
-  if isNil(src.data): return 
+  if isNil(src.data): return
   setLen(dest.data, len(src.data))
   for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
-  
-proc copyIdTable(dest: var TIdTable, src: TIdTable) = 
+
+proc copyIdTable*(dest: var TIdTable, src: TIdTable) =
   dest.counter = src.counter
-  if isNil(src.data): return 
+  if isNil(src.data): return
   newSeq(dest.data, len(src.data))
   for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
-  
-proc copyTable(dest: var TTable, src: TTable) = 
+
+proc copyTable*(dest: var TTable, src: TTable) =
   dest.counter = src.counter
-  if isNil(src.data): return 
+  if isNil(src.data): return
   setLen(dest.data, len(src.data))
   for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
-  
-proc copyObjectSet(dest: var TObjectSet, src: TObjectSet) = 
+
+proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
   dest.counter = src.counter
-  if isNil(src.data): return 
+  if isNil(src.data): return
   setLen(dest.data, len(src.data))
   for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
-  
-proc discardSons(father: PNode) = 
-  father.sons = nil
-
-when defined(useNodeIds):
-  const nodeIdToDebug* = -1 # 884953 # 612794
-  #612840 # 612905 # 614635 # 614637 # 614641
-  # 423408
-  #429107 # 430443 # 441048 # 441090 # 441153
-  var gNodeId: int
-
-proc newNode(kind: TNodeKind): PNode = 
-  new(result)
-  result.kind = kind
-  #result.info = UnknownLineInfo() inlined:
-  result.info.fileIndex = int32(- 1)
-  result.info.col = int16(- 1)
-  result.info.line = int16(- 1)
-  when defined(useNodeIds):
-    result.id = gNodeId
-    if result.id == nodeIdToDebug:
-      echo "KIND ", result.kind
-      writeStackTrace()
-    inc gNodeId
 
-proc newIntNode(kind: TNodeKind, intVal: BiggestInt): PNode = 
-  result = newNode(kind)
-  result.intVal = intVal
-
-proc newIntTypeNode(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode = 
-  result = newIntNode(kind, intVal)
-  result.typ = typ
-
-proc newFloatNode(kind: TNodeKind, floatVal: BiggestFloat): PNode = 
-  result = newNode(kind)
-  result.floatVal = floatVal
-
-proc newStrNode(kind: TNodeKind, strVal: string): PNode = 
-  result = newNode(kind)
-  result.strVal = strVal
+proc discardSons*(father: PNode) =
+  father.sons = nil
 
 proc withInfo*(n: PNode, info: TLineInfo): PNode =
   n.info = info
   return n
 
-proc newIdentNode(ident: PIdent, info: TLineInfo): PNode = 
+proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode =
   result = newNode(nkIdent)
   result.ident = ident
   result.info = info
 
-proc newSymNode(sym: PSym): PNode = 
+proc newSymNode*(sym: PSym): PNode =
   result = newNode(nkSym)
   result.sym = sym
   result.typ = sym.typ
   result.info = sym.info
 
-proc newSymNode*(sym: PSym, info: TLineInfo): PNode = 
+proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
   result = newNode(nkSym)
   result.sym = sym
   result.typ = sym.typ
   result.info = info
 
-proc newNodeI(kind: TNodeKind, info: TLineInfo): PNode =
+proc newNodeI*(kind: TNodeKind, info: TLineInfo): PNode =
   new(result)
   result.kind = kind
   result.info = info
@@ -1153,11 +1132,16 @@ proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[],
       writeStackTrace()
     inc gNodeId
 
-proc newNodeIT(kind: TNodeKind, info: TLineInfo, typ: PType): PNode = 
+proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
   result = newNode(kind)
   result.info = info
   result.typ = typ
 
+proc addSon*(father, son: PNode) =
+  assert son != nil
+  if isNil(father.sons): father.sons = @[]
+  add(father.sons, son)
+
 var emptyParams = newNode(nkFormalParams)
 emptyParams.addSon(emptyNode)
 
@@ -1179,7 +1163,7 @@ proc `$`*(x: TLockLevel): string =
   elif x.ord == UnknownLockLevel.ord: result = "<unknown>"
   else: result = $int16(x)
 
-proc newType(kind: TTypeKind, owner: PSym): PType = 
+proc newType*(kind: TTypeKind, owner: PSym): PType =
   new(result)
   result.kind = kind
   result.owner = owner
@@ -1189,9 +1173,11 @@ proc newType(kind: TTypeKind, owner: PSym): PType =
   result.lockLevel = UnspecifiedLockLevel
   when debugIds:
     registerId(result)
-  #if result.id < 2000:
+  #if result.id == 92231:
+  #  echo "KNID ", kind
+  #  writeStackTrace()
   #  messageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
-  
+
 proc mergeLoc(a: var TLoc, b: TLoc) =
   if a.k == low(a.k): a.k = b.k
   if a.s == low(a.s): a.s = b.s
@@ -1199,8 +1185,38 @@ proc mergeLoc(a: var TLoc, b: TLoc) =
   if a.t == nil: a.t = b.t
   if a.r == nil: a.r = b.r
   #if a.a == 0: a.a = b.a
-  
-proc assignType(dest, src: PType) = 
+
+proc newSons*(father: PNode, length: int) =
+  if isNil(father.sons):
+    newSeq(father.sons, length)
+  else:
+    setLen(father.sons, length)
+
+proc newSons*(father: PType, length: int) =
+  if isNil(father.sons):
+    newSeq(father.sons, length)
+  else:
+    setLen(father.sons, length)
+
+proc sonsLen*(n: PType): int =
+  if isNil(n.sons): result = 0
+  else: result = len(n.sons)
+
+proc len*(n: PType): int =
+  if isNil(n.sons): result = 0
+  else: result = len(n.sons)
+
+proc sonsLen*(n: PNode): int =
+  if isNil(n.sons): result = 0
+  else: result = len(n.sons)
+
+proc lastSon*(n: PNode): PNode =
+  result = n.sons[sonsLen(n) - 1]
+
+proc lastSon*(n: PType): PType =
+  result = n.sons[sonsLen(n) - 1]
+
+proc assignType*(dest, src: PType) =
   dest.kind = src.kind
   dest.flags = src.flags
   dest.callConv = src.callConv
@@ -1209,6 +1225,7 @@ proc assignType(dest, src: PType) =
   dest.align = src.align
   dest.destructor = src.destructor
   dest.deepCopy = src.deepCopy
+  dest.assignment = src.assignment
   dest.lockLevel = src.lockLevel
   # this fixes 'type TLock = TSysLock':
   if src.sym != nil:
@@ -1220,23 +1237,23 @@ proc assignType(dest, src: PType) =
       dest.sym = src.sym
   newSons(dest, sonsLen(src))
   for i in countup(0, sonsLen(src) - 1): dest.sons[i] = src.sons[i]
-  
-proc copyType(t: PType, owner: PSym, keepId: bool): PType = 
+
+proc copyType*(t: PType, owner: PSym, keepId: bool): PType =
   result = newType(t.kind, owner)
   assignType(result, t)
-  if keepId: 
+  if keepId:
     result.id = t.id
-  else: 
+  else:
     when debugIds: registerId(result)
   result.sym = t.sym          # backend-info should not be copied
-  
-proc copySym(s: PSym, keepId: bool = false): PSym = 
+
+proc copySym*(s: PSym, keepId: bool = false): PSym =
   result = newSym(s.kind, s.name, s.owner, s.info)
   #result.ast = nil            # BUGFIX; was: s.ast which made problems
   result.typ = s.typ
   if keepId:
     result.id = s.id
-  else: 
+  else:
     result.id = getID()
     when debugIds: registerId(result)
   result.flags = s.flags
@@ -1263,74 +1280,39 @@ proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym =
   result.annex = s.annex
   # XXX once usedGenerics is used, ensure module aliases keep working!
   assert s.usedGenerics == nil
-  
-proc newSym(symKind: TSymKind, name: PIdent, owner: PSym,
-            info: TLineInfo): PSym = 
-  # generates a symbol and initializes the hash field too
-  new(result)
-  result.name = name
-  result.kind = symKind
-  result.flags = {}
-  result.info = info
-  result.options = gOptions
-  result.owner = owner
-  result.offset = - 1
-  result.id = getID()
-  when debugIds: 
-    registerId(result)
-  #if result.id < 2000:
-  #  MessageOut(name.s & " has id: " & toString(result.id))
-  
-proc initStrTable(x: var TStrTable) = 
+
+proc initStrTable*(x: var TStrTable) =
   x.counter = 0
   newSeq(x.data, StartSize)
 
 proc newStrTable*: TStrTable =
   initStrTable(result)
 
-proc initTable(x: var TTable) = 
+proc initTable(x: var TTable) =
   x.counter = 0
   newSeq(x.data, StartSize)
 
-proc initIdTable(x: var TIdTable) = 
+proc initIdTable*(x: var TIdTable) =
   x.counter = 0
   newSeq(x.data, StartSize)
 
-proc initObjectSet(x: var TObjectSet) = 
+proc resetIdTable*(x: var TIdTable) =
   x.counter = 0
-  newSeq(x.data, StartSize)
+  # clear and set to old initial size:
+  setLen(x.data, 0)
+  setLen(x.data, StartSize)
 
-proc initIdNodeTable(x: var TIdNodeTable) = 
+proc initObjectSet*(x: var TObjectSet) =
   x.counter = 0
   newSeq(x.data, StartSize)
 
-proc initNodeTable(x: var TNodeTable) = 
+proc initIdNodeTable*(x: var TIdNodeTable) =
   x.counter = 0
   newSeq(x.data, StartSize)
 
-proc sonsLen(n: PType): int = 
-  if isNil(n.sons): result = 0
-  else: result = len(n.sons)
-
-proc len*(n: PType): int = 
-  if isNil(n.sons): result = 0
-  else: result = len(n.sons)
-  
-proc newSons(father: PType, length: int) = 
-  if isNil(father.sons): 
-    newSeq(father.sons, length)
-  else:
-    setLen(father.sons, length)
-
-proc sonsLen(n: PNode): int = 
-  if isNil(n.sons): result = 0
-  else: result = len(n.sons)
-  
-proc newSons(father: PNode, length: int) = 
-  if isNil(father.sons): 
-    newSeq(father.sons, length)
-  else:
-    setLen(father.sons, length)
+proc initNodeTable*(x: var TNodeTable) =
+  x.counter = 0
+  newSeq(x.data, StartSize)
 
 proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
   ## Used throughout the compiler code to test whether a type tree contains or
@@ -1340,31 +1322,46 @@ proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
   result = t
   while result.kind in kinds: result = lastSon(result)
 
+proc skipTypesOrNil*(t: PType, kinds: TTypeKinds): PType =
+  ## same as skipTypes but handles 'nil'
+  result = t
+  while result != nil and result.kind in kinds:
+    if result.len == 0: return nil
+    result = lastSon(result)
+
 proc isGCedMem*(t: PType): bool {.inline.} =
   result = t.kind in {tyString, tyRef, tySequence} or
            t.kind == tyProc and t.callConv == ccClosure
 
 proc propagateToOwner*(owner, elem: PType) =
-  const HaveTheirOwnEmpty = {tySequence, tySet}
-  owner.flags = owner.flags + (elem.flags * {tfHasShared, tfHasMeta})
+  const HaveTheirOwnEmpty = {tySequence, tySet, tyPtr, tyRef, tyProc}
+  owner.flags = owner.flags + (elem.flags * {tfHasMeta})
   if tfNotNil in elem.flags:
-    if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvokation}:
+    if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}:
       owner.flags.incl tfNotNil
     elif owner.kind notin HaveTheirOwnEmpty:
       owner.flags.incl tfNeedsInit
-  
+
   if tfNeedsInit in elem.flags:
     if owner.kind in HaveTheirOwnEmpty: discard
     else: owner.flags.incl tfNeedsInit
-    
-  if tfShared in elem.flags:
-    owner.flags.incl tfHasShared
 
   if elem.isMetaType:
     owner.flags.incl tfHasMeta
 
-  if owner.kind != tyProc:
-    if elem.isGCedMem or tfHasGCedMem in elem.flags:
+  if tfHasAsgn in elem.flags:
+    let o2 = elem.skipTypes({tyGenericInst})
+    if o2.kind in {tyTuple, tyObject, tyArray, tyArrayConstr,
+                   tySequence, tySet, tyDistinct}:
+      o2.flags.incl tfHasAsgn
+      owner.flags.incl tfHasAsgn
+
+  if owner.kind notin {tyProc, tyGenericInst, tyGenericBody,
+                       tyGenericInvocation}:
+    let elemB = elem.skipTypes({tyGenericInst})
+    if elemB.isGCedMem or tfHasGCedMem in elemB.flags:
+      # for simplicity, we propagate this flag even to generics. We then
+      # ensure this doesn't bite us in sempass2.
       owner.flags.incl tfHasGCedMem
 
 proc rawAddSon*(father, son: PType) =
@@ -1372,24 +1369,19 @@ proc rawAddSon*(father, son: PType) =
   add(father.sons, son)
   if not son.isNil: propagateToOwner(father, son)
 
-proc addSon(father, son: PNode) = 
-  assert son != nil
-  if isNil(father.sons): father.sons = @[]
-  add(father.sons, son)
-
 proc addSonNilAllowed*(father, son: PNode) =
   if isNil(father.sons): father.sons = @[]
   add(father.sons, son)
 
-proc delSon(father: PNode, idx: int) = 
-  if isNil(father.sons): return 
+proc delSon*(father: PNode, idx: int) =
+  if isNil(father.sons): return
   var length = sonsLen(father)
   for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1]
   setLen(father.sons, length - 1)
 
-proc copyNode(src: PNode): PNode = 
+proc copyNode*(src: PNode): PNode =
   # does not copy its sons!
-  if src == nil: 
+  if src == nil:
     return nil
   result = newNode(src.kind)
   result.info = src.info
@@ -1406,7 +1398,7 @@ proc copyNode(src: PNode): PNode =
   of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
   else: discard
 
-proc shallowCopy*(src: PNode): PNode = 
+proc shallowCopy*(src: PNode): PNode =
   # does not copy its sons, but provides space for them:
   if src == nil: return nil
   result = newNode(src.kind)
@@ -1424,9 +1416,9 @@ proc shallowCopy*(src: PNode): PNode =
   of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
   else: newSeq(result.sons, sonsLen(src))
 
-proc copyTree(src: PNode): PNode = 
+proc copyTree*(src: PNode): PNode =
   # copy a whole syntax tree; performs deep copying
-  if src == nil: 
+  if src == nil:
     return nil
   result = newNode(src.kind)
   result.info = src.info
@@ -1441,26 +1433,20 @@ proc copyTree(src: PNode): PNode =
   of nkSym: result.sym = src.sym
   of nkIdent: result.ident = src.ident
   of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
-  else: 
+  else:
     newSeq(result.sons, sonsLen(src))
-    for i in countup(0, sonsLen(src) - 1): 
+    for i in countup(0, sonsLen(src) - 1):
       result.sons[i] = copyTree(src.sons[i])
-  
-proc lastSon(n: PNode): PNode = 
-  result = n.sons[sonsLen(n) - 1]
 
-proc lastSon(n: PType): PType = 
-  result = n.sons[sonsLen(n) - 1]
-
-proc hasSonWith(n: PNode, kind: TNodeKind): bool = 
-  for i in countup(0, sonsLen(n) - 1): 
-    if n.sons[i].kind == kind: 
+proc hasSonWith*(n: PNode, kind: TNodeKind): bool =
+  for i in countup(0, sonsLen(n) - 1):
+    if n.sons[i].kind == kind:
       return true
   result = false
 
-proc hasNilSon*(n: PNode): bool = 
-  for i in countup(0, safeLen(n) - 1): 
-    if n.sons[i] == nil: 
+proc hasNilSon*(n: PNode): bool =
+  for i in countup(0, safeLen(n) - 1):
+    if n.sons[i] == nil:
       return true
     elif hasNilSon(n.sons[i]):
       return true
@@ -1474,55 +1460,55 @@ proc containsNode*(n: PNode, kinds: TNodeKinds): bool =
     for i in countup(0, sonsLen(n) - 1):
       if n.kind in kinds or containsNode(n.sons[i], kinds): return true
 
-proc hasSubnodeWith(n: PNode, kind: TNodeKind): bool = 
+proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool =
   case n.kind
   of nkEmpty..nkNilLit: result = n.kind == kind
-  else: 
-    for i in countup(0, sonsLen(n) - 1): 
-      if (n.sons[i].kind == kind) or hasSubnodeWith(n.sons[i], kind): 
+  else:
+    for i in countup(0, sonsLen(n) - 1):
+      if (n.sons[i].kind == kind) or hasSubnodeWith(n.sons[i], kind):
         return true
     result = false
 
-proc replaceSons(n: PNode, oldKind, newKind: TNodeKind) = 
-  for i in countup(0, sonsLen(n) - 1): 
+proc replaceSons(n: PNode, oldKind, newKind: TNodeKind) =
+  for i in countup(0, sonsLen(n) - 1):
     if n.sons[i].kind == oldKind: n.sons[i].kind = newKind
-  
-proc sonsNotNil(n: PNode): bool = 
-  for i in countup(0, sonsLen(n) - 1): 
-    if n.sons[i] == nil: 
+
+proc sonsNotNil(n: PNode): bool =
+  for i in countup(0, sonsLen(n) - 1):
+    if n.sons[i] == nil:
       return false
   result = true
 
-proc getInt*(a: PNode): BiggestInt = 
+proc getInt*(a: PNode): BiggestInt =
   case a.kind
   of nkIntLit..nkUInt64Lit: result = a.intVal
-  else: 
+  else:
     internalError(a.info, "getInt")
     result = 0
 
-proc getFloat*(a: PNode): BiggestFloat = 
+proc getFloat*(a: PNode): BiggestFloat =
   case a.kind
   of nkFloatLit..nkFloat128Lit: result = a.floatVal
-  else: 
+  else:
     internalError(a.info, "getFloat")
     result = 0.0
 
-proc getStr*(a: PNode): string = 
+proc getStr*(a: PNode): string =
   case a.kind
   of nkStrLit..nkTripleStrLit: result = a.strVal
-  else: 
+  else:
     internalError(a.info, "getStr")
     result = ""
 
-proc getStrOrChar*(a: PNode): string = 
+proc getStrOrChar*(a: PNode): string =
   case a.kind
   of nkStrLit..nkTripleStrLit: result = a.strVal
-  of nkCharLit: result = $chr(int(a.intVal))
-  else: 
+  of nkCharLit..nkUInt64Lit: result = $chr(int(a.intVal))
+  else:
     internalError(a.info, "getStrOrChar")
     result = ""
 
-proc isGenericRoutine*(s: PSym): bool = 
+proc isGenericRoutine*(s: PSym): bool =
   case s.kind
   of skProcKinds:
     result = sfFromGeneric in s.flags or
@@ -1560,3 +1546,17 @@ proc isEmptyType*(t: PType): bool {.inline.} =
   ## 'void' and 'stmt' types are often equivalent to 'nil' these days:
   result = t == nil or t.kind in {tyEmpty, tyStmt}
 
+proc makeStmtList*(n: PNode): PNode =
+  if n.kind == nkStmtList:
+    result = n
+  else:
+    result = newNodeI(nkStmtList, n.info)
+    result.add n
+
+proc createMagic*(name: string, m: TMagic): PSym =
+  result = newSym(skProc, getIdent(name), nil, unknownLineInfo())
+  result.magic = m
+
+let
+  opNot* = createMagic("not", mNot)
+  opContains* = createMagic("contains", mInSet)
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index e66158e8d..1707718d7 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -11,18 +11,18 @@
 # and sets of nodes are supported. Efficiency is important as
 # the data structures here are used in various places of the compiler.
 
-import 
+import
   ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils
 
 proc hashNode*(p: RootRef): THash
-proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope
+proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope
   # Convert a tree into its YAML representation; this is used by the
   # YAML code generator and it is invaluable for debugging purposes.
   # If maxRecDepht <> -1 then it won't print the whole graph.
-proc typeToYaml*(n: PType, indent: int = 0, maxRecDepth: int = - 1): PRope
-proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope
-proc lineInfoToStr*(info: TLineInfo): PRope
-  
+proc typeToYaml*(n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope
+proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope
+proc lineInfoToStr*(info: TLineInfo): Rope
+
 # ----------------------- node sets: ---------------------------------------
 proc objectSetContains*(t: TObjectSet, obj: RootRef): bool
   # returns true whether n is in t
@@ -34,10 +34,10 @@ proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool
 # ----------------------- (key, val)-Hashtables ----------------------------
 proc tablePut*(t: var TTable, key, val: RootRef)
 proc tableGet*(t: TTable, key: RootRef): RootRef
-type 
+type
   TCmpProc* = proc (key, closure: RootRef): bool {.nimcall.} # true if found
 
-proc tableSearch*(t: TTable, key, closure: RootRef, 
+proc tableSearch*(t: TTable, key, closure: RootRef,
                   comparator: TCmpProc): RootRef
   # return val as soon as comparator returns true; if this never happens,
   # nil is returned
@@ -45,16 +45,16 @@ proc tableSearch*(t: TTable, key, closure: RootRef,
 # ----------------------- str table -----------------------------------------
 proc strTableContains*(t: TStrTable, n: PSym): bool
 proc strTableAdd*(t: var TStrTable, n: PSym)
-proc strTableGet*(t: TStrTable, name: PIdent): PSym  
-  
-type 
+proc strTableGet*(t: TStrTable, name: PIdent): PSym
+
+type
   TTabIter*{.final.} = object # consider all fields here private
     h*: THash                 # current hash
 
 proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym
 proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
   # usage:
-  # var 
+  # var
   #   i: TTabIter
   #   s: PSym
   # s = InitTabIter(i, table)
@@ -63,7 +63,7 @@ proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
   #   s = NextIter(i, table)
   #
 
-type 
+type
   TIdentIter*{.final.} = object # iterator over all syms with same identifier
     h*: THash                   # current hash
     name*: PIdent
@@ -97,11 +97,11 @@ proc mustRehash*(length, counter: int): bool
 proc nextTry*(h, maxHash: THash): THash {.inline.}
 
 # ------------- table[int, int] ---------------------------------------------
-const 
+const
   InvalidKey* = low(int)
 
-type 
-  TIIPair*{.final.} = object 
+type
+  TIIPair*{.final.} = object
     key*, val*: int
 
   TIIPairSeq* = seq[TIIPair]
@@ -127,31 +127,31 @@ proc skipConvAndClosure*(n: PNode): PNode =
       result = result.sons[1]
     else: break
 
-proc sameValue*(a, b: PNode): bool = 
+proc sameValue*(a, b: PNode): bool =
   result = false
   case a.kind
-  of nkCharLit..nkInt64Lit: 
-    if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal == b.intVal
-  of nkFloatLit..nkFloat64Lit: 
+  of nkCharLit..nkUInt64Lit:
+    if b.kind in {nkCharLit..nkUInt64Lit}: result = a.intVal == b.intVal
+  of nkFloatLit..nkFloat64Lit:
     if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal
-  of nkStrLit..nkTripleStrLit: 
+  of nkStrLit..nkTripleStrLit:
     if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal
   else:
     # don't raise an internal error for 'nimrod check':
     #InternalError(a.info, "SameValue")
     discard
 
-proc leValue*(a, b: PNode): bool = 
+proc leValue*(a, b: PNode): bool =
   # a <= b?
   result = false
   case a.kind
-  of nkCharLit..nkInt64Lit: 
-    if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal <= b.intVal
-  of nkFloatLit..nkFloat64Lit: 
+  of nkCharLit..nkUInt32Lit:
+    if b.kind in {nkCharLit..nkUInt32Lit}: result = a.intVal <= b.intVal
+  of nkFloatLit..nkFloat64Lit:
     if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal
-  of nkStrLit..nkTripleStrLit: 
+  of nkStrLit..nkTripleStrLit:
     if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal <= b.strVal
-  else: 
+  else:
     # don't raise an internal error for 'nimrod check':
     #InternalError(a.info, "leValue")
     discard
@@ -162,313 +162,316 @@ proc weakLeValue*(a, b: PNode): TImplication =
   else:
     result = if leValue(a, b): impYes else: impNo
 
-proc lookupInRecord(n: PNode, field: PIdent): PSym = 
+proc lookupInRecord(n: PNode, field: PIdent): PSym =
   result = nil
   case n.kind
-  of nkRecList: 
-    for i in countup(0, sonsLen(n) - 1): 
+  of nkRecList:
+    for i in countup(0, sonsLen(n) - 1):
       result = lookupInRecord(n.sons[i], field)
-      if result != nil: return 
-  of nkRecCase: 
+      if result != nil: return
+  of nkRecCase:
     if (n.sons[0].kind != nkSym): internalError(n.info, "lookupInRecord")
     result = lookupInRecord(n.sons[0], field)
-    if result != nil: return 
-    for i in countup(1, sonsLen(n) - 1): 
+    if result != nil: return
+    for i in countup(1, sonsLen(n) - 1):
       case n.sons[i].kind
-      of nkOfBranch, nkElse: 
+      of nkOfBranch, nkElse:
         result = lookupInRecord(lastSon(n.sons[i]), field)
-        if result != nil: return 
+        if result != nil: return
       else: internalError(n.info, "lookupInRecord(record case branch)")
-  of nkSym: 
+  of nkSym:
     if n.sym.name.id == field.id: result = n.sym
   else: internalError(n.info, "lookupInRecord()")
-  
-proc getModule(s: PSym): PSym = 
+
+proc getModule(s: PSym): PSym =
   result = s
   assert((result.kind == skModule) or (result.owner != result))
   while result != nil and result.kind != skModule: result = result.owner
-  
-proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym = 
-  for i in countup(start, sonsLen(list) - 1): 
+
+proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
+  for i in countup(start, sonsLen(list) - 1):
     if list.sons[i].kind == nkSym:
       result = list.sons[i].sym
-      if result.name.id == ident.id: return 
+      if result.name.id == ident.id: return
     else: internalError(list.info, "getSymFromList")
   result = nil
 
-proc hashNode(p: RootRef): THash = 
+proc hashNode(p: RootRef): THash =
   result = hash(cast[pointer](p))
 
-proc mustRehash(length, counter: int): bool = 
+proc mustRehash(length, counter: int): bool =
   assert(length > counter)
   result = (length * 2 < counter * 3) or (length - counter < 4)
 
-proc spaces(x: int): PRope = 
+proc rspaces(x: int): Rope =
   # returns x spaces
-  result = toRope(repeatChar(x))
+  result = rope(spaces(x))
 
-proc toYamlChar(c: char): string = 
+proc toYamlChar(c: char): string =
   case c
   of '\0'..'\x1F', '\x80'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4)
   of '\'', '\"', '\\': result = '\\' & c
   else: result = $c
-  
-proc makeYamlString*(s: string): PRope = 
+
+proc makeYamlString*(s: string): Rope =
   # We have to split long strings into many ropes. Otherwise
   # this could trigger InternalError(111). See the ropes module for
   # further information.
   const MaxLineLength = 64
   result = nil
   var res = "\""
-  for i in countup(0, if s.isNil: -1 else: (len(s)-1)): 
-    if (i + 1) mod MaxLineLength == 0: 
+  for i in countup(0, if s.isNil: -1 else: (len(s)-1)):
+    if (i + 1) mod MaxLineLength == 0:
       add(res, '\"')
       add(res, "\n")
-      app(result, toRope(res))
+      add(result, rope(res))
       res = "\""              # reset
     add(res, toYamlChar(s[i]))
   add(res, '\"')
-  app(result, toRope(res))
+  add(result, rope(res))
 
-proc flagsToStr[T](flags: set[T]): PRope = 
-  if flags == {}: 
-    result = toRope("[]")
-  else: 
+proc flagsToStr[T](flags: set[T]): Rope =
+  if flags == {}:
+    result = rope("[]")
+  else:
     result = nil
-    for x in items(flags): 
-      if result != nil: app(result, ", ")
-      app(result, makeYamlString($x))
-    result = con("[", con(result, "]"))
-
-proc lineInfoToStr(info: TLineInfo): PRope = 
-  result = ropef("[$1, $2, $3]", [makeYamlString(toFilename(info)), 
-                                  toRope(toLinenumber(info)), 
-                                  toRope(toColumn(info))])
-
-proc treeToYamlAux(n: PNode, marker: var IntSet, 
-                   indent, maxRecDepth: int): PRope
-proc symToYamlAux(n: PSym, marker: var IntSet, 
-                  indent, maxRecDepth: int): PRope
-proc typeToYamlAux(n: PType, marker: var IntSet, 
-                   indent, maxRecDepth: int): PRope
-proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int, 
-                    maxRecDepth: int): PRope = 
-  var istr = spaces(indent + 2)
-  result = toRope("[")
+    for x in items(flags):
+      if result != nil: add(result, ", ")
+      add(result, makeYamlString($x))
+    result = "[" & result & "]"
+
+proc lineInfoToStr(info: TLineInfo): Rope =
+  result = "[$1, $2, $3]" % [makeYamlString(toFilename(info)),
+                             rope(toLinenumber(info)),
+                             rope(toColumn(info))]
+
+proc treeToYamlAux(n: PNode, marker: var IntSet,
+                   indent, maxRecDepth: int): Rope
+proc symToYamlAux(n: PSym, marker: var IntSet,
+                  indent, maxRecDepth: int): Rope
+proc typeToYamlAux(n: PType, marker: var IntSet,
+                   indent, maxRecDepth: int): Rope
+proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
+                    maxRecDepth: int): Rope =
+  var istr = rspaces(indent + 2)
+  result = rope("[")
   var mycount = 0
-  for i in countup(0, high(n.data)): 
-    if n.data[i] != nil: 
-      if mycount > 0: app(result, ",")
-      appf(result, "$N$1$2", 
+  for i in countup(0, high(n.data)):
+    if n.data[i] != nil:
+      if mycount > 0: add(result, ",")
+      addf(result, "$N$1$2",
            [istr, symToYamlAux(n.data[i], marker, indent + 2, maxRecDepth - 1)])
       inc(mycount)
-  if mycount > 0: appf(result, "$N$1", [spaces(indent)])
-  app(result, "]")
+  if mycount > 0: addf(result, "$N$1", [rspaces(indent)])
+  add(result, "]")
   assert(mycount == n.counter)
 
-proc ropeConstr(indent: int, c: openArray[PRope]): PRope = 
+proc ropeConstr(indent: int, c: openArray[Rope]): Rope =
   # array of (name, value) pairs
-  var istr = spaces(indent + 2)
-  result = toRope("{")
+  var istr = rspaces(indent + 2)
+  result = rope("{")
   var i = 0
-  while i <= high(c): 
-    if i > 0: app(result, ",")
-    appf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]])
+  while i <= high(c):
+    if i > 0: add(result, ",")
+    addf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]])
     inc(i, 2)
-  appf(result, "$N$1}", [spaces(indent)])
-
-proc symToYamlAux(n: PSym, marker: var IntSet, indent: int, 
-                  maxRecDepth: int): PRope = 
-  if n == nil: 
-    result = toRope("null")
-  elif containsOrIncl(marker, n.id): 
-    result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope(
-        strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))])
-  else: 
+  addf(result, "$N$1}", [rspaces(indent)])
+
+proc symToYamlAux(n: PSym, marker: var IntSet, indent: int,
+                  maxRecDepth: int): Rope =
+  if n == nil:
+    result = rope("null")
+  elif containsOrIncl(marker, n.id):
+    result = "\"$1 @$2\"" % [rope(n.name.s), rope(
+        strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
+  else:
     var ast = treeToYamlAux(n.ast, marker, indent + 2, maxRecDepth - 1)
-    result = ropeConstr(indent, [toRope("kind"), 
-                                 makeYamlString($n.kind), 
-                                 toRope("name"), makeYamlString(n.name.s), 
-                                 toRope("typ"), typeToYamlAux(n.typ, marker, 
-                                   indent + 2, maxRecDepth - 1), 
-                                 toRope("info"), lineInfoToStr(n.info), 
-                                 toRope("flags"), flagsToStr(n.flags), 
-                                 toRope("magic"), makeYamlString($n.magic), 
-                                 toRope("ast"), ast, toRope("options"), 
-                                 flagsToStr(n.options), toRope("position"), 
-                                 toRope(n.position)])
-
-proc typeToYamlAux(n: PType, marker: var IntSet, indent: int, 
-                   maxRecDepth: int): PRope = 
-  if n == nil: 
-    result = toRope("null")
-  elif containsOrIncl(marker, n.id): 
-    result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope(
-        strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))])
-  else: 
-    if sonsLen(n) > 0: 
-      result = toRope("[")
-      for i in countup(0, sonsLen(n) - 1): 
-        if i > 0: app(result, ",")
-        appf(result, "$N$1$2", [spaces(indent + 4), typeToYamlAux(n.sons[i], 
+    result = ropeConstr(indent, [rope("kind"),
+                                 makeYamlString($n.kind),
+                                 rope("name"), makeYamlString(n.name.s),
+                                 rope("typ"), typeToYamlAux(n.typ, marker,
+                                   indent + 2, maxRecDepth - 1),
+                                 rope("info"), lineInfoToStr(n.info),
+                                 rope("flags"), flagsToStr(n.flags),
+                                 rope("magic"), makeYamlString($n.magic),
+                                 rope("ast"), ast, rope("options"),
+                                 flagsToStr(n.options), rope("position"),
+                                 rope(n.position)])
+
+proc typeToYamlAux(n: PType, marker: var IntSet, indent: int,
+                   maxRecDepth: int): Rope =
+  if n == nil:
+    result = rope("null")
+  elif containsOrIncl(marker, n.id):
+    result = "\"$1 @$2\"" % [rope($n.kind), rope(
+        strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
+  else:
+    if sonsLen(n) > 0:
+      result = rope("[")
+      for i in countup(0, sonsLen(n) - 1):
+        if i > 0: add(result, ",")
+        addf(result, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(n.sons[i],
             marker, indent + 4, maxRecDepth - 1)])
-      appf(result, "$N$1]", [spaces(indent + 2)])
-    else: 
-      result = toRope("null")
-    result = ropeConstr(indent, [toRope("kind"), 
-                                 makeYamlString($n.kind), 
-                                 toRope("sym"), symToYamlAux(n.sym, marker, 
-        indent + 2, maxRecDepth - 1), toRope("n"), treeToYamlAux(n.n, marker, 
-        indent + 2, maxRecDepth - 1), toRope("flags"), flagsToStr(n.flags), 
-                                 toRope("callconv"), 
-                                 makeYamlString(CallingConvToStr[n.callConv]), 
-                                 toRope("size"), toRope(n.size), 
-                                 toRope("align"), toRope(n.align), 
-                                 toRope("sons"), result])
-
-proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int, 
-                   maxRecDepth: int): PRope = 
-  if n == nil: 
-    result = toRope("null")
-  else: 
-    var istr = spaces(indent + 2)
-    result = ropef("{$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
-    if maxRecDepth != 0: 
-      appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
+      addf(result, "$N$1]", [rspaces(indent + 2)])
+    else:
+      result = rope("null")
+    result = ropeConstr(indent, [rope("kind"),
+                                 makeYamlString($n.kind),
+                                 rope("sym"), symToYamlAux(n.sym, marker,
+        indent + 2, maxRecDepth - 1), rope("n"), treeToYamlAux(n.n, marker,
+        indent + 2, maxRecDepth - 1), rope("flags"), flagsToStr(n.flags),
+                                 rope("callconv"),
+                                 makeYamlString(CallingConvToStr[n.callConv]),
+                                 rope("size"), rope(n.size),
+                                 rope("align"), rope(n.align),
+                                 rope("sons"), result])
+
+proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
+                   maxRecDepth: int): Rope =
+  if n == nil:
+    result = rope("null")
+  else:
+    var istr = rspaces(indent + 2)
+    result = "{$N$1\"kind\": $2" % [istr, makeYamlString($n.kind)]
+    if maxRecDepth != 0:
+      addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
       case n.kind
-      of nkCharLit..nkInt64Lit: 
-        appf(result, ",$N$1\"intVal\": $2", [istr, toRope(n.intVal)])
-      of nkFloatLit, nkFloat32Lit, nkFloat64Lit: 
-        appf(result, ",$N$1\"floatVal\": $2", 
-            [istr, toRope(n.floatVal.toStrMaxPrecision)])
-      of nkStrLit..nkTripleStrLit: 
+      of nkCharLit..nkInt64Lit:
+        addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
+      of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
+        addf(result, ",$N$1\"floatVal\": $2",
+            [istr, rope(n.floatVal.toStrMaxPrecision)])
+      of nkStrLit..nkTripleStrLit:
         if n.strVal.isNil:
-          appf(result, ",$N$1\"strVal\": null", [istr])
+          addf(result, ",$N$1\"strVal\": null", [istr])
         else:
-          appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
-      of nkSym: 
-        appf(result, ",$N$1\"sym\": $2", 
+          addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
+      of nkSym:
+        addf(result, ",$N$1\"sym\": $2",
              [istr, symToYamlAux(n.sym, marker, indent + 2, maxRecDepth)])
-      of nkIdent: 
-        if n.ident != nil: 
-          appf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
-        else: 
-          appf(result, ",$N$1\"ident\": null", [istr])
-      else: 
-        if sonsLen(n) > 0: 
-          appf(result, ",$N$1\"sons\": [", [istr])
-          for i in countup(0, sonsLen(n) - 1): 
-            if i > 0: app(result, ",")
-            appf(result, "$N$1$2", [spaces(indent + 4), treeToYamlAux(n.sons[i], 
+      of nkIdent:
+        if n.ident != nil:
+          addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
+        else:
+          addf(result, ",$N$1\"ident\": null", [istr])
+      else:
+        if sonsLen(n) > 0:
+          addf(result, ",$N$1\"sons\": [", [istr])
+          for i in countup(0, sonsLen(n) - 1):
+            if i > 0: add(result, ",")
+            addf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(n.sons[i],
                 marker, indent + 4, maxRecDepth - 1)])
-          appf(result, "$N$1]", [istr])
-      appf(result, ",$N$1\"typ\": $2", 
+          addf(result, "$N$1]", [istr])
+      addf(result, ",$N$1\"typ\": $2",
            [istr, typeToYamlAux(n.typ, marker, indent + 2, maxRecDepth)])
-    appf(result, "$N$1}", [spaces(indent)])
+    addf(result, "$N$1}", [rspaces(indent)])
 
-proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope = 
+proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope =
   var marker = initIntSet()
   result = treeToYamlAux(n, marker, indent, maxRecDepth)
 
-proc typeToYaml(n: PType, indent: int = 0, maxRecDepth: int = - 1): PRope = 
+proc typeToYaml(n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope =
   var marker = initIntSet()
   result = typeToYamlAux(n, marker, indent, maxRecDepth)
 
-proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope = 
+proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope =
   var marker = initIntSet()
   result = symToYamlAux(n, marker, indent, maxRecDepth)
 
-proc debugTree(n: PNode, indent: int, maxRecDepth: int; renderType=false): PRope
-proc debugType(n: PType, maxRecDepth=100): PRope = 
-  if n == nil: 
-    result = toRope("null")
+proc debugTree*(n: PNode, indent: int, maxRecDepth: int; renderType=false): Rope
+proc debugType(n: PType, maxRecDepth=100): Rope =
+  if n == nil:
+    result = rope("null")
   else:
-    result = toRope($n.kind)
-    if n.sym != nil: 
-      app(result, " ")
-      app(result, n.sym.name.s)
+    result = rope($n.kind)
+    if n.sym != nil:
+      add(result, " ")
+      add(result, n.sym.name.s)
+    if n.kind in IntegralTypes and n.n != nil:
+      add(result, ", node: ")
+      add(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true))
     if (n.kind != tyString) and (sonsLen(n) > 0) and maxRecDepth != 0:
-      app(result, "(")
+      add(result, "(")
       for i in countup(0, sonsLen(n) - 1):
-        if i > 0: app(result, ", ")
+        if i > 0: add(result, ", ")
         if n.sons[i] == nil:
-          app(result, "null")
+          add(result, "null")
         else:
-          app(result, debugType(n.sons[i], maxRecDepth-1))
+          add(result, debugType(n.sons[i], maxRecDepth-1))
       if n.kind == tyObject and n.n != nil:
-        app(result, ", node: ")
-        app(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true))
-      app(result, ")")
+        add(result, ", node: ")
+        add(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true))
+      add(result, ")")
 
 proc debugTree(n: PNode, indent: int, maxRecDepth: int;
-               renderType=false): PRope = 
-  if n == nil: 
-    result = toRope("null")
-  else: 
-    var istr = spaces(indent + 2)
-    result = ropef("{$N$1\"kind\": $2", 
-                   [istr, makeYamlString($n.kind)])
-    if maxRecDepth != 0: 
+               renderType=false): Rope =
+  if n == nil:
+    result = rope("null")
+  else:
+    var istr = rspaces(indent + 2)
+    result = "{$N$1\"kind\": $2" %
+             [istr, makeYamlString($n.kind)]
+    if maxRecDepth != 0:
       case n.kind
       of nkCharLit..nkUInt64Lit:
-        appf(result, ",$N$1\"intVal\": $2", [istr, toRope(n.intVal)])
-      of nkFloatLit, nkFloat32Lit, nkFloat64Lit: 
-        appf(result, ",$N$1\"floatVal\": $2", 
-            [istr, toRope(n.floatVal.toStrMaxPrecision)])
-      of nkStrLit..nkTripleStrLit: 
+        addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
+      of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
+        addf(result, ",$N$1\"floatVal\": $2",
+            [istr, rope(n.floatVal.toStrMaxPrecision)])
+      of nkStrLit..nkTripleStrLit:
         if n.strVal.isNil:
-          appf(result, ",$N$1\"strVal\": null", [istr])
+          addf(result, ",$N$1\"strVal\": null", [istr])
         else:
-          appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
-      of nkSym: 
-        appf(result, ",$N$1\"sym\": $2_$3", 
-            [istr, toRope(n.sym.name.s), toRope(n.sym.id)])
-        #     [istr, symToYaml(n.sym, indent, maxRecDepth), 
-        #     toRope(n.sym.id)])
+          addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
+      of nkSym:
+        addf(result, ",$N$1\"sym\": $2_$3",
+            [istr, rope(n.sym.name.s), rope(n.sym.id)])
+        #     [istr, symToYaml(n.sym, indent, maxRecDepth),
+        #     rope(n.sym.id)])
         if renderType and n.sym.typ != nil:
-          appf(result, ",$N$1\"typ\": $2", [istr, debugType(n.sym.typ, 2)])
-      of nkIdent: 
-        if n.ident != nil: 
-          appf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
-        else: 
-          appf(result, ",$N$1\"ident\": null", [istr])
-      else: 
-        if sonsLen(n) > 0: 
-          appf(result, ",$N$1\"sons\": [", [istr])
-          for i in countup(0, sonsLen(n) - 1): 
-            if i > 0: app(result, ",")
-            appf(result, "$N$1$2", [spaces(indent + 4), debugTree(n.sons[i], 
+          addf(result, ",$N$1\"typ\": $2", [istr, debugType(n.sym.typ, 2)])
+      of nkIdent:
+        if n.ident != nil:
+          addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
+        else:
+          addf(result, ",$N$1\"ident\": null", [istr])
+      else:
+        if sonsLen(n) > 0:
+          addf(result, ",$N$1\"sons\": [", [istr])
+          for i in countup(0, sonsLen(n) - 1):
+            if i > 0: add(result, ",")
+            addf(result, "$N$1$2", [rspaces(indent + 4), debugTree(n.sons[i],
                 indent + 4, maxRecDepth - 1, renderType)])
-          appf(result, "$N$1]", [istr])
-    appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
-    appf(result, "$N$1}", [spaces(indent)])
+          addf(result, "$N$1]", [istr])
+    addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
+    addf(result, "$N$1}", [rspaces(indent)])
 
 proc debug(n: PSym) =
   if n == nil:
-    writeln(stdout, "null")
+    msgWriteln("null")
   elif n.kind == skUnknown:
-    writeln(stdout, "skUnknown")
+    msgWriteln("skUnknown")
   else:
-    #writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
-    writeln(stdout, ropeToStr(ropef("$1_$2: $3, $4, $5", [
-      toRope(n.name.s), toRope(n.id), flagsToStr(n.flags), 
-      flagsToStr(n.loc.flags), lineInfoToStr(n.info)])))
+    #writeln(stdout, $symToYaml(n, 0, 1))
+    msgWriteln("$1_$2: $3, $4, $5, $6" % [
+      n.name.s, $n.id, $flagsToStr(n.flags), $flagsToStr(n.loc.flags),
+      $lineInfoToStr(n.info), $n.kind])
 
-proc debug(n: PType) = 
-  writeln(stdout, ropeToStr(debugType(n)))
+proc debug(n: PType) =
+  msgWriteln($debugType(n))
 
-proc debug(n: PNode) = 
-  writeln(stdout, ropeToStr(debugTree(n, 0, 100)))
+proc debug(n: PNode) =
+  msgWriteln($debugTree(n, 0, 100))
 
-const 
+const
   EmptySeq = @[]
 
-proc nextTry(h, maxHash: THash): THash = 
-  result = ((5 * h) + 1) and maxHash 
+proc nextTry(h, maxHash: THash): THash =
+  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).
-  
+
 proc objectSetContains(t: TObjectSet, obj: RootRef): bool =
   # returns true whether n is in t
   var h: THash = hashNode(obj) and high(t.data) # start with real hash value
@@ -486,94 +489,94 @@ proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
   assert(data[h] == nil)
   data[h] = obj
 
-proc objectSetEnlarge(t: var TObjectSet) = 
+proc objectSetEnlarge(t: var TObjectSet) =
   var n: TObjectSeq
   newSeq(n, len(t.data) * GrowthFactor)
   for i in countup(0, high(t.data)):
     if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
   swap(t.data, n)
 
-proc objectSetIncl(t: var TObjectSet, obj: RootRef) = 
+proc objectSetIncl(t: var TObjectSet, obj: RootRef) =
   if mustRehash(len(t.data), t.counter): objectSetEnlarge(t)
   objectSetRawInsert(t.data, obj)
   inc(t.counter)
 
-proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool = 
+proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool =
   # returns true if obj is already in the string table:
   var h: THash = hashNode(obj) and high(t.data)
-  while true: 
+  while true:
     var it = t.data[h]
-    if it == nil: break 
-    if it == obj: 
+    if it == nil: break
+    if it == obj:
       return true             # found it
     h = nextTry(h, high(t.data))
-  if mustRehash(len(t.data), t.counter): 
+  if mustRehash(len(t.data), t.counter):
     objectSetEnlarge(t)
     objectSetRawInsert(t.data, obj)
-  else: 
+  else:
     assert(t.data[h] == nil)
     t.data[h] = obj
   inc(t.counter)
   result = false
 
-proc tableRawGet(t: TTable, key: RootRef): int = 
+proc tableRawGet(t: TTable, key: RootRef): int =
   var h: THash = hashNode(key) and high(t.data) # start with real hash value
-  while t.data[h].key != nil: 
-    if t.data[h].key == key: 
+  while t.data[h].key != nil:
+    if t.data[h].key == key:
       return h
     h = nextTry(h, high(t.data))
   result = -1
 
-proc tableSearch(t: TTable, key, closure: RootRef, 
-                 comparator: TCmpProc): RootRef = 
+proc tableSearch(t: TTable, key, closure: RootRef,
+                 comparator: TCmpProc): RootRef =
   var h: THash = hashNode(key) and high(t.data) # start with real hash value
-  while t.data[h].key != nil: 
-    if t.data[h].key == key: 
-      if comparator(t.data[h].val, closure): 
+  while t.data[h].key != nil:
+    if t.data[h].key == key:
+      if comparator(t.data[h].val, closure):
         # BUGFIX 1
         return t.data[h].val
     h = nextTry(h, high(t.data))
   result = nil
 
-proc tableGet(t: TTable, key: RootRef): RootRef = 
+proc tableGet(t: TTable, key: RootRef): RootRef =
   var index = tableRawGet(t, key)
   if index >= 0: result = t.data[index].val
   else: result = nil
-  
-proc tableRawInsert(data: var TPairSeq, key, val: RootRef) = 
+
+proc tableRawInsert(data: var TPairSeq, key, val: RootRef) =
   var h: THash = hashNode(key) and high(data)
-  while data[h].key != nil: 
+  while data[h].key != nil:
     assert(data[h].key != key)
     h = nextTry(h, high(data))
   assert(data[h].key == nil)
   data[h].key = key
   data[h].val = val
 
-proc tableEnlarge(t: var TTable) = 
+proc tableEnlarge(t: var TTable) =
   var n: TPairSeq
   newSeq(n, len(t.data) * GrowthFactor)
-  for i in countup(0, high(t.data)): 
+  for i in countup(0, high(t.data)):
     if t.data[i].key != nil: tableRawInsert(n, t.data[i].key, t.data[i].val)
   swap(t.data, n)
 
-proc tablePut(t: var TTable, key, val: RootRef) = 
+proc tablePut(t: var TTable, key, val: RootRef) =
   var index = tableRawGet(t, key)
-  if index >= 0: 
+  if index >= 0:
     t.data[index].val = val
-  else: 
+  else:
     if mustRehash(len(t.data), t.counter): tableEnlarge(t)
     tableRawInsert(t.data, key, val)
     inc(t.counter)
 
-proc strTableContains(t: TStrTable, n: PSym): bool = 
+proc strTableContains(t: TStrTable, n: PSym): bool =
   var h: THash = n.name.h and high(t.data) # start with real hash value
-  while t.data[h] != nil: 
-    if (t.data[h] == n): 
+  while t.data[h] != nil:
+    if (t.data[h] == n):
       return true
     h = nextTry(h, high(t.data))
   result = false
 
-proc strTableRawInsert(data: var TSymSeq, n: PSym) = 
+proc strTableRawInsert(data: var TSymSeq, n: PSym) =
   var h: THash = n.name.h and high(data)
   if sfImmediate notin n.flags:
     # fast path:
@@ -610,18 +613,18 @@ proc symTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
       return
     h = nextTry(h, high(data))
   assert false
- 
+
 proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
   symTabReplaceRaw(t.data, prevSym, newSym)
 
-proc strTableEnlarge(t: var TStrTable) = 
+proc strTableEnlarge(t: var TStrTable) =
   var n: TSymSeq
   newSeq(n, len(t.data) * GrowthFactor)
-  for i in countup(0, high(t.data)): 
+  for i in countup(0, high(t.data)):
     if t.data[i] != nil: strTableRawInsert(n, t.data[i])
   swap(t.data, n)
 
-proc strTableAdd(t: var TStrTable, n: PSym) = 
+proc strTableAdd(t: var TStrTable, n: PSym) =
   if mustRehash(len(t.data), t.counter): strTableEnlarge(t)
   strTableRawInsert(t.data, n)
   inc(t.counter)
@@ -662,104 +665,103 @@ proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
   inc(t.counter)
   result = false
 
-proc strTableGet(t: TStrTable, name: PIdent): PSym = 
+proc strTableGet(t: TStrTable, name: PIdent): PSym =
   var h: THash = name.h and high(t.data)
-  while true: 
+  while true:
     result = t.data[h]
-    if result == nil: break 
-    if result.name.id == name.id: break 
+    if result == nil: break
+    if result.name.id == name.id: break
     h = nextTry(h, high(t.data))
 
-proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym = 
+proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
   ti.h = s.h
   ti.name = s
   if tab.counter == 0: result = nil
   else: result = nextIdentIter(ti, tab)
-  
-proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym = 
-  var h, start: THash
-  h = ti.h and high(tab.data)
-  start = h
+
+proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
+  var h = ti.h and high(tab.data)
+  var start = h
   result = tab.data[h]
-  while result != nil: 
-    if result.name.id == ti.name.id: break 
+  while result != nil:
+    if result.name.id == ti.name.id: break
     h = nextTry(h, high(tab.data))
-    if h == start: 
+    if h == start:
       result = nil
-      break 
+      break
     result = tab.data[h]
   ti.h = nextTry(h, high(tab.data))
-  
-proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable, 
+
+proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
                          excluding: IntSet): PSym =
   var h: THash = ti.h and high(tab.data)
   var start = h
   result = tab.data[h]
-  while result != nil: 
-    if result.name.id == ti.name.id and not contains(excluding, result.id): 
+  while result != nil:
+    if result.name.id == ti.name.id and not contains(excluding, result.id):
       break
     h = nextTry(h, high(tab.data))
-    if h == start: 
+    if h == start:
       result = nil
-      break 
+      break
     result = tab.data[h]
   ti.h = nextTry(h, high(tab.data))
   if result != nil and contains(excluding, result.id): result = nil
 
 proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
-                          excluding: IntSet): PSym = 
+                          excluding: IntSet): PSym =
   ti.h = s.h
   ti.name = s
   if tab.counter == 0: result = nil
   else: result = nextIdentExcluding(ti, tab, excluding)
 
-proc initTabIter(ti: var TTabIter, tab: TStrTable): PSym = 
+proc initTabIter(ti: var TTabIter, tab: TStrTable): PSym =
   ti.h = 0                    # we start by zero ...
-  if tab.counter == 0: 
+  if tab.counter == 0:
     result = nil              # FIX 1: removed endless loop
-  else: 
+  else:
     result = nextIter(ti, tab)
-  
-proc nextIter(ti: var TTabIter, tab: TStrTable): PSym = 
+
+proc nextIter(ti: var TTabIter, tab: TStrTable): PSym =
   result = nil
-  while (ti.h <= high(tab.data)): 
+  while (ti.h <= high(tab.data)):
     result = tab.data[ti.h]
     inc(ti.h)                 # ... and increment by one always
-    if result != nil: break 
+    if result != nil: break
 
-iterator items*(tab: TStrTable): PSym = 
+iterator items*(tab: TStrTable): PSym =
   var it: TTabIter
   var s = initTabIter(it, tab)
-  while s != nil: 
+  while s != nil:
     yield s
     s = nextIter(it, tab)
 
-proc hasEmptySlot(data: TIdPairSeq): bool = 
-  for h in countup(0, high(data)): 
-    if data[h].key == nil: 
+proc hasEmptySlot(data: TIdPairSeq): bool =
+  for h in countup(0, high(data)):
+    if data[h].key == nil:
       return true
   result = false
 
-proc idTableRawGet(t: TIdTable, key: int): int = 
+proc idTableRawGet(t: TIdTable, key: int): int =
   var h: THash
   h = key and high(t.data)    # start with real hash value
-  while t.data[h].key != nil: 
+  while t.data[h].key != nil:
     if t.data[h].key.id == key:
       return h
     h = nextTry(h, high(t.data))
   result = - 1
 
-proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool = 
+proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
   var index = idTableRawGet(t, key.id)
   if index >= 0: result = t.data[index].key == key
   else: result = false
-  
-proc idTableGet(t: TIdTable, key: PIdObj): RootRef = 
+
+proc idTableGet(t: TIdTable, key: PIdObj): RootRef =
   var index = idTableRawGet(t, key.id)
   if index >= 0: result = t.data[index].val
   else: result = nil
-  
-proc idTableGet(t: TIdTable, key: int): RootRef = 
+
+proc idTableGet(t: TIdTable, key: int): RootRef =
   var index = idTableRawGet(t, key)
   if index >= 0: result = t.data[index].val
   else: result = nil
@@ -768,30 +770,30 @@ iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] =
   for i in 0..high(t.data):
     if t.data[i].key != nil:
       yield (t.data[i].key.id, t.data[i].val)
-  
-proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) = 
+
+proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) =
   var h: THash
   h = key.id and high(data)
-  while data[h].key != nil: 
+  while data[h].key != nil:
     assert(data[h].key.id != key.id)
     h = nextTry(h, high(data))
   assert(data[h].key == nil)
   data[h].key = key
   data[h].val = val
 
-proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) = 
-  var 
+proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) =
+  var
     index: int
     n: TIdPairSeq
   index = idTableRawGet(t, key.id)
-  if index >= 0: 
+  if index >= 0:
     assert(t.data[index].key != nil)
     t.data[index].val = val
-  else: 
-    if mustRehash(len(t.data), t.counter): 
+  else:
+    if mustRehash(len(t.data), t.counter):
       newSeq(n, len(t.data) * GrowthFactor)
-      for i in countup(0, high(t.data)): 
-        if t.data[i].key != nil: 
+      for i in countup(0, high(t.data)):
+        if t.data[i].key != nil:
           idTableRawInsert(n, t.data[i].key, t.data[i].val)
       assert(hasEmptySlot(n))
       swap(t.data, n)
@@ -802,7 +804,7 @@ iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] =
   for i in 0 .. high(t.data):
     if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
 
-proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int = 
+proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
   var h: THash
   h = key.id and high(t.data) # start with real hash value
   while t.data[h].key != nil:
@@ -811,7 +813,7 @@ proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
     h = nextTry(h, high(t.data))
   result = - 1
 
-proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode = 
+proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
   var index: int
   index = idNodeTableRawGet(t, key)
   if index >= 0: result = t.data[index].val
@@ -820,28 +822,28 @@ proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
 proc idNodeTableGetLazy*(t: TIdNodeTable, key: PIdObj): PNode =
   if not isNil(t.data):
     result = idNodeTableGet(t, key)
-  
-proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) = 
+
+proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
   var h: THash
   h = key.id and high(data)
-  while data[h].key != nil: 
+  while data[h].key != nil:
     assert(data[h].key.id != key.id)
     h = nextTry(h, high(data))
   assert(data[h].key == nil)
   data[h].key = key
   data[h].val = val
 
-proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) = 
+proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
   var index = idNodeTableRawGet(t, key)
-  if index >= 0: 
+  if index >= 0:
     assert(t.data[index].key != nil)
     t.data[index].val = val
-  else: 
-    if mustRehash(len(t.data), t.counter): 
+  else:
+    if mustRehash(len(t.data), t.counter):
       var n: TIdNodePairSeq
       newSeq(n, len(t.data) * GrowthFactor)
-      for i in countup(0, high(t.data)): 
-        if t.data[i].key != nil: 
+      for i in countup(0, high(t.data)):
+        if t.data[i].key != nil:
           idNodeTableRawInsert(n, t.data[i].key, t.data[i].val)
       swap(t.data, n)
     idNodeTableRawInsert(t.data, key, val)
@@ -855,46 +857,46 @@ iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
   for i in 0 .. high(t.data):
     if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
 
-proc initIITable(x: var TIITable) = 
+proc initIITable(x: var TIITable) =
   x.counter = 0
   newSeq(x.data, StartSize)
   for i in countup(0, StartSize - 1): x.data[i].key = InvalidKey
-  
-proc iiTableRawGet(t: TIITable, key: int): int = 
+
+proc iiTableRawGet(t: TIITable, key: int): int =
   var h: THash
   h = key and high(t.data)    # start with real hash value
-  while t.data[h].key != InvalidKey: 
+  while t.data[h].key != InvalidKey:
     if t.data[h].key == key: return h
     h = nextTry(h, high(t.data))
   result = -1
 
-proc iiTableGet(t: TIITable, key: int): int = 
+proc iiTableGet(t: TIITable, key: int): int =
   var index = iiTableRawGet(t, key)
   if index >= 0: result = t.data[index].val
   else: result = InvalidKey
-  
-proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) = 
+
+proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) =
   var h: THash
   h = key and high(data)
-  while data[h].key != InvalidKey: 
+  while data[h].key != InvalidKey:
     assert(data[h].key != key)
     h = nextTry(h, high(data))
   assert(data[h].key == InvalidKey)
   data[h].key = key
   data[h].val = val
 
-proc iiTablePut(t: var TIITable, key, val: int) = 
+proc iiTablePut(t: var TIITable, key, val: int) =
   var index = iiTableRawGet(t, key)
-  if index >= 0: 
+  if index >= 0:
     assert(t.data[index].key != InvalidKey)
     t.data[index].val = val
-  else: 
-    if mustRehash(len(t.data), t.counter): 
+  else:
+    if mustRehash(len(t.data), t.counter):
       var n: TIIPairSeq
       newSeq(n, len(t.data) * GrowthFactor)
       for i in countup(0, high(n)): n[i].key = InvalidKey
-      for i in countup(0, high(t.data)): 
-        if t.data[i].key != InvalidKey: 
+      for i in countup(0, high(t.data)):
+        if t.data[i].key != InvalidKey:
           iiTableRawInsert(n, t.data[i].key, t.data[i].val)
       swap(t.data, n)
     iiTableRawInsert(t.data, key, val)
diff --git a/compiler/canonicalizer.nim b/compiler/canonicalizer.nim
index 14448f0e8..6fcc57a91 100644
--- a/compiler/canonicalizer.nim
+++ b/compiler/canonicalizer.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -119,8 +119,8 @@ proc hashType(c: var MD5Context, t: PType) =
     c.hashSym(t.sym)
     
   case t.kind
-  of tyGenericBody, tyGenericInst, tyGenericInvokation:
-    for i in countup(0, sonsLen(t) -1 -ord(t.kind != tyGenericInvokation)):
+  of tyGenericBody, tyGenericInst, tyGenericInvocation:
+    for i in countup(0, sonsLen(t) -1 -ord(t.kind != tyGenericInvocation)):
       c.hashType t.sons[i]
   of tyUserTypeClass:
     internalAssert t.sym != nil and t.sym.owner != nil
@@ -243,24 +243,24 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
       encodeNode(w, n.info, n.sons[i], result)
   add(result, ')')
 
-proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) = 
+proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
   var oldLen = result.len
   result.add('<')
   if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
-  if loc.s != low(loc.s): 
+  if loc.s != low(loc.s):
     add(result, '*')
     encodeVInt(ord(loc.s), result)
-  if loc.flags != {}: 
+  if loc.flags != {}:
     add(result, '$')
     encodeVInt(cast[int32](loc.flags), result)
   if loc.t != nil:
     add(result, '^')
     encodeVInt(cast[int32](loc.t.id), result)
     pushType(w, loc.t)
-  if loc.r != nil: 
+  if loc.r != nil:
     add(result, '!')
-    encodeStr(ropeToStr(loc.r), result)
-  if loc.a != 0: 
+    encodeStr($loc.r, result)
+  if loc.a != 0:
     add(result, '?')
     encodeVInt(loc.a, result)
   if oldLen + 1 == result.len:
@@ -317,7 +317,7 @@ proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
   add(result, '|')
   encodeVInt(ord(lib.kind), result)
   add(result, '|')
-  encodeStr(ropeToStr(lib.name), result)
+  encodeStr($lib.name, result)
   add(result, '|')
   encodeNode(w, info, lib.path, result)
 
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index b01a81c5e..2dacc25e9 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2013 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -19,13 +19,13 @@ proc hasNoInit(call: PNode): bool {.inline.} =
   result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags
 
 proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
-               callee, params: PRope) =
-  var pl = con(callee, ~"(", params)
+               callee, params: Rope) =
+  var pl = callee & ~"(" & params
   # getUniqueType() is too expensive here:
   var typ = skipTypes(ri.sons[0].typ, abstractInst)
   if typ.sons[0] != nil:
     if isInvalidReturnType(typ.sons[0]):
-      if params != nil: pl.app(~", ")
+      if params != nil: pl.add(~", ")
       # beware of 'result = p(result)'. We may need to allocate a temporary:
       if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
         # Great, we can use 'd':
@@ -33,26 +33,34 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
         elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
           # reset before pass as 'result' var:
           resetLoc(p, d)
-        app(pl, addrLoc(d))
-        app(pl, ~");$n")
+        add(pl, addrLoc(d))
+        add(pl, ~");$n")
         line(p, cpsStmts, pl)
       else:
         var tmp: TLoc
         getTemp(p, typ.sons[0], tmp, needsInit=true)
-        app(pl, addrLoc(tmp))
-        app(pl, ~");$n")
+        add(pl, addrLoc(tmp))
+        add(pl, ~");$n")
         line(p, cpsStmts, pl)
         genAssignment(p, d, tmp, {}) # no need for deep copying
     else:
-      app(pl, ~")")
-      if d.k == locNone: getTemp(p, typ.sons[0], d)
-      assert(d.t != nil)        # generate an assignment to d:
-      var list: TLoc
-      initLoc(list, locCall, d.t, OnUnknown)
-      list.r = pl
-      genAssignment(p, d, list, {}) # no need for deep copying
+      add(pl, ~")")
+      if p.module.compileToCpp and lfSingleUse in d.flags:
+        # do not generate spurious temporaries for C++! For C we're better off
+        # with them to prevent undefined behaviour and because the codegen
+        # is free to emit expressions multiple times!
+        d.k = locCall
+        d.r = pl
+        excl d.flags, lfSingleUse
+      else:
+        if d.k == locNone: getTemp(p, typ.sons[0], d)
+        assert(d.t != nil)        # generate an assignment to d:
+        var list: TLoc
+        initLoc(list, locCall, d.t, OnUnknown)
+        list.r = pl
+        genAssignment(p, d, list, {}) # no need for deep copying
   else:
-    app(pl, ~");$n")
+    add(pl, ~");$n")
     line(p, cpsStmts, pl)
 
 proc isInCurrentFrame(p: BProc, n: PNode): bool =
@@ -75,7 +83,7 @@ proc isInCurrentFrame(p: BProc, n: PNode): bool =
     result = isInCurrentFrame(p, n.sons[0])
   else: discard
 
-proc openArrayLoc(p: BProc, n: PNode): PRope =
+proc openArrayLoc(p: BProc, n: PNode): Rope =
   var a: TLoc
 
   let q = skipConv(n)
@@ -90,33 +98,34 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
       of tyOpenArray, tyVarargs, tyArray, tyArrayConstr:
         "($1)+($2), ($3)-($2)+1"
       of tyString, tySequence:
-        if skipTypes(n.typ, abstractInst).kind == tyVar:
+        if skipTypes(n.typ, abstractInst).kind == tyVar and
+            not compileToCpp(p.module):
           "(*$1)->data+($2), ($3)-($2)+1"
         else:
           "$1->data+($2), ($3)-($2)+1"
       else: (internalError("openArrayLoc: " & typeToString(a.t)); "")
-    result = ropef(fmt, [rdLoc(a), rdLoc(b), rdLoc(c)])
+    result = fmt % [rdLoc(a), rdLoc(b), rdLoc(c)]
   else:
     initLocExpr(p, n, a)
     case skipTypes(a.t, abstractVar).kind
     of tyOpenArray, tyVarargs:
-      result = ropef("$1, $1Len0", [rdLoc(a)])
+      result = "$1, $1Len0" % [rdLoc(a)]
     of tyString, tySequence:
-      if skipTypes(n.typ, abstractInst).kind == tyVar:
-        result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)])
+      if skipTypes(n.typ, abstractInst).kind == tyVar and
+            not compileToCpp(p.module):
+        result = "(*$1)->data, (*$1)->$2" % [a.rdLoc, lenField(p)]
       else:
-        result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)])
+        result = "$1->data, $1->$2" % [a.rdLoc, lenField(p)]
     of tyArray, tyArrayConstr:
-      result = ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))])
+      result = "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))]
     else: internalError("openArrayLoc: " & typeToString(a.t))
 
-proc genArgStringToCString(p: BProc, 
-                           n: PNode): PRope {.inline.} =
+proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} =
   var a: TLoc
   initLocExpr(p, n.sons[0], a)
-  result = ropef("$1->data", [a.rdLoc])
-  
-proc genArg(p: BProc, n: PNode, param: PSym): PRope =
+  result = "$1->data" % [a.rdLoc]
+
+proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope =
   var a: TLoc
   if n.kind == nkStringToCString:
     result = genArgStringToCString(p, n)
@@ -126,23 +135,35 @@ proc genArg(p: BProc, n: PNode, param: PSym): PRope =
   elif ccgIntroducedPtr(param):
     initLocExpr(p, n, a)
     result = addrLoc(a)
+  elif p.module.compileToCpp and param.typ.kind == tyVar and
+      n.kind == nkHiddenAddr:
+    initLocExprSingleUse(p, n.sons[0], a)
+    # if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
+    # means '*T'. See posix.nim for lots of examples that do that in the wild.
+    let callee = call.sons[0]
+    if callee.kind == nkSym and
+        {sfImportC, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportC} and
+        {lfHeader, lfNoDecl} * callee.sym.loc.flags != {}:
+      result = addrLoc(a)
+    else:
+      result = rdLoc(a)
   else:
-    initLocExpr(p, n, a)
+    initLocExprSingleUse(p, n, a)
     result = rdLoc(a)
 
-proc genArgNoParam(p: BProc, n: PNode): PRope =
+proc genArgNoParam(p: BProc, n: PNode): Rope =
   var a: TLoc
   if n.kind == nkStringToCString:
     result = genArgStringToCString(p, n)
   else:
-    initLocExpr(p, n, a)
+    initLocExprSingleUse(p, n, a)
     result = rdLoc(a)
 
 proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
   var op: TLoc
   # this is a hotspot in the compiler
   initLocExpr(p, ri.sons[0], op)
-  var params: PRope
+  var params: Rope
   # getUniqueType() is too expensive here:
   var typ = skipTypes(ri.sons[0].typ, abstractInst)
   assert(typ.kind == tyProc)
@@ -150,48 +171,49 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
   var length = sonsLen(ri)
   for i in countup(1, length - 1):
     if ri.sons[i].typ.isCompileTimeOnly: continue
-    if params != nil: app(params, ~", ")
+    if params != nil: add(params, ~", ")
     if i < sonsLen(typ):
       assert(typ.n.sons[i].kind == nkSym)
-      app(params, genArg(p, ri.sons[i], typ.n.sons[i].sym))
+      add(params, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
     else:
-      app(params, genArgNoParam(p, ri.sons[i]))
+      add(params, genArgNoParam(p, ri.sons[i]))
   fixupCall(p, le, ri, d, op.r, params)
 
 proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
 
-  proc getRawProcType(p: BProc, t: PType): PRope =
+  proc getRawProcType(p: BProc, t: PType): Rope =
     result = getClosureType(p.module, t, clHalf)
 
-  proc addComma(r: PRope): PRope =
-    result = if r == nil: r else: con(r, ~", ")
+  proc addComma(r: Rope): Rope =
+    result = if r == nil: r else: r & ~", "
 
   const PatProc = "$1.ClEnv? $1.ClPrc($3$1.ClEnv):(($4)($1.ClPrc))($2)"
   const PatIter = "$1.ClPrc($3$1.ClEnv)" # we know the env exists
   var op: TLoc
   initLocExpr(p, ri.sons[0], op)
-  var pl: PRope
-  
+  var pl: Rope
+
   var typ = skipTypes(ri.sons[0].typ, abstractInst)
   assert(typ.kind == tyProc)
   var length = sonsLen(ri)
   for i in countup(1, length - 1):
     assert(sonsLen(typ) == sonsLen(typ.n))
+    if ri.sons[i].typ.isCompileTimeOnly: continue
     if i < sonsLen(typ):
       assert(typ.n.sons[i].kind == nkSym)
-      app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym))
+      add(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
     else:
-      app(pl, genArgNoParam(p, ri.sons[i]))
-    if i < length - 1: app(pl, ~", ")
-  
+      add(pl, genArgNoParam(p, ri.sons[i]))
+    if i < length - 1: add(pl, ~", ")
+
   template genCallPattern {.dirty.} =
-    lineF(p, cpsStmts, callPattern & ";$n", op.r, pl, pl.addComma, rawProc)
+    lineF(p, cpsStmts, callPattern & ";$n", [op.r, pl, pl.addComma, rawProc])
 
   let rawProc = getRawProcType(p, typ)
   let callPattern = if tfIterator in typ.flags: PatIter else: PatProc
   if typ.sons[0] != nil:
     if isInvalidReturnType(typ.sons[0]):
-      if sonsLen(ri) > 1: app(pl, ~", ")
+      if sonsLen(ri) > 1: add(pl, ~", ")
       # beware of 'result = p(result)'. We may need to allocate a temporary:
       if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
         # Great, we can use 'd':
@@ -200,12 +222,12 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
         elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
           # reset before pass as 'result' var:
           resetLoc(p, d)
-        app(pl, addrLoc(d))
+        add(pl, addrLoc(d))
         genCallPattern()
       else:
         var tmp: TLoc
         getTemp(p, typ.sons[0], tmp, needsInit=true)
-        app(pl, addrLoc(tmp))
+        add(pl, addrLoc(tmp))
         genCallPattern()
         genAssignment(p, d, tmp, {}) # no need for deep copying
     else:
@@ -213,37 +235,214 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
       assert(d.t != nil)        # generate an assignment to d:
       var list: TLoc
       initLoc(list, locCall, d.t, OnUnknown)
-      list.r = ropef(callPattern, op.r, pl, pl.addComma, rawProc)
+      list.r = callPattern % [op.r, pl, pl.addComma, rawProc]
       genAssignment(p, d, list, {}) # no need for deep copying
   else:
     genCallPattern()
-  
+
+proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
+  if ri.sons[i].typ.isCompileTimeOnly:
+    result = nil
+  elif i < sonsLen(typ):
+    # 'var T' is 'T&' in C++. This means we ignore the request of
+    # any nkHiddenAddr when it's a 'var T'.
+    assert(typ.n.sons[i].kind == nkSym)
+    if typ.sons[i].kind == tyVar and ri.sons[i].kind == nkHiddenAddr:
+      result = genArgNoParam(p, ri.sons[i][0])
+    else:
+      result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym)
+  else:
+    result = genArgNoParam(p, ri.sons[i])
+
+discard """
+Dot call syntax in C++
+======================
+
+so c2nim translates 'this' sometimes to 'T' and sometimes to 'var T'
+both of which are wrong, but often more convenient to use.
+For manual wrappers it can also be 'ptr T'
+
+Fortunately we know which parameter is the 'this' parameter and so can fix this
+mess in the codegen.
+now ... if the *argument* is a 'ptr' the codegen shall emit -> and otherwise .
+but this only depends on the argument and not on how the 'this' was declared
+however how the 'this' was declared affects whether we end up with
+wrong 'addr' and '[]' ops...
+
+Since I'm tired I'll enumerate all the cases here:
+
+var
+  x: ptr T
+  y: T
+
+proc t(x: T)
+x[].t()  --> (*x).t()  is correct.
+y.t()    --> y.t()  is correct
+
+proc u(x: ptr T)
+x.u()          --> needs to become  x->u()
+(addr y).u()   --> needs to become  y.u()
+
+proc v(x: var T)
+--> first skip the implicit 'nkAddr' node
+x[].v()        --> (*x).v()  is correct, but might have been eliminated due
+                   to the nkAddr node! So for this case we need to generate '->'
+y.v()          --> y.v() is correct
+
+"""
+
+proc skipAddrDeref(node: PNode): PNode =
+  var n = node
+  var isAddr = false
+  case n.kind
+  of nkAddr, nkHiddenAddr:
+    n = n.sons[0]
+    isAddr = true
+  of nkDerefExpr, nkHiddenDeref:
+    n = n.sons[0]
+  else: return n
+  if n.kind == nkObjDownConv: n = n.sons[0]
+  if isAddr and n.kind in {nkDerefExpr, nkHiddenDeref}:
+    result = n.sons[0]
+  elif n.kind in {nkAddr, nkHiddenAddr}:
+    result = n.sons[0]
+  else:
+    result = node
+
+proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
+  # for better or worse c2nim translates the 'this' argument to a 'var T'.
+  # However manual wrappers may also use 'ptr T'. In any case we support both
+  # for convenience.
+  internalAssert i < sonsLen(typ)
+  assert(typ.n.sons[i].kind == nkSym)
+  # if the parameter is lying (tyVar) and thus we required an additional deref,
+  # skip the deref:
+  var ri = ri[i]
+  while ri.kind == nkObjDownConv: ri = ri[0]
+  let t = typ.sons[i].skipTypes({tyGenericInst})
+  if t.kind == tyVar:
+    let x = if ri.kind == nkHiddenAddr: ri[0] else: ri
+    if x.typ.kind == tyPtr:
+      result = genArgNoParam(p, x)
+      result.add("->")
+    elif x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].typ.kind == tyPtr:
+      result = genArgNoParam(p, x[0])
+      result.add("->")
+    else:
+      result = genArgNoParam(p, x)
+      result.add(".")
+  elif t.kind == tyPtr:
+    if ri.kind in {nkAddr, nkHiddenAddr}:
+      result = genArgNoParam(p, ri[0])
+      result.add(".")
+    else:
+      result = genArgNoParam(p, ri)
+      result.add("->")
+  else:
+    ri = skipAddrDeref(ri)
+    if ri.kind in {nkAddr, nkHiddenAddr}: ri = ri[0]
+    result = genArgNoParam(p, ri) #, typ.n.sons[i].sym)
+    result.add(".")
+
+proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope =
+  var i = 0
+  var j = 1
+  while i < pat.len:
+    case pat[i]
+    of '@':
+      if j < ri.len:
+        result.add genOtherArg(p, ri, j, typ)
+        for k in j+1 .. < ri.len:
+          result.add(~", ")
+          result.add genOtherArg(p, ri, k, typ)
+      inc i
+    of '#':
+      if pat[i+1] in {'+', '@'}:
+        let ri = ri[j]
+        if ri.kind in nkCallKinds:
+          let typ = skipTypes(ri.sons[0].typ, abstractInst)
+          if pat[i+1] == '+': result.add genArgNoParam(p, ri.sons[0])
+          result.add(~"(")
+          if 1 < ri.len:
+            result.add genOtherArg(p, ri, 1, typ)
+          for k in j+1 .. < ri.len:
+            result.add(~", ")
+            result.add genOtherArg(p, ri, k, typ)
+          result.add(~")")
+        else:
+          localError(ri.info, "call expression expected for C++ pattern")
+        inc i
+      elif pat[i+1] == '.':
+        result.add genThisArg(p, ri, j, typ)
+        inc i
+      elif pat[i+1] == '[':
+        var arg = ri.sons[j].skipAddrDeref
+        while arg.kind in {nkAddr, nkHiddenAddr, nkObjDownConv}: arg = arg[0]
+        result.add genArgNoParam(p, arg)
+        #result.add debugTree(arg, 0, 10)
+      else:
+        result.add genOtherArg(p, ri, j, typ)
+      inc j
+      inc i
+    of '\'':
+      var idx, stars: int
+      if scanCppGenericSlot(pat, i, idx, stars):
+        var t = resolveStarsInCppType(typ, idx, stars)
+        if t == nil: result.add(~"void")
+        else: result.add(getTypeDesc(p.module, t))
+    else:
+      let start = i
+      while i < pat.len:
+        if pat[i] notin {'@', '#', '\''}: inc(i)
+        else: break
+      if i - 1 >= start:
+        add(result, substr(pat, start, i - 1))
+
 proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
   var op, a: TLoc
   initLocExpr(p, ri.sons[0], op)
-  var pl: PRope = nil
   # getUniqueType() is too expensive here:
   var typ = skipTypes(ri.sons[0].typ, abstractInst)
   assert(typ.kind == tyProc)
   var length = sonsLen(ri)
   assert(sonsLen(typ) == sonsLen(typ.n))
-  
-  var param = typ.n.sons[1].sym
-  app(pl, genArg(p, ri.sons[1], param))
-  
-  if skipTypes(param.typ, {tyGenericInst}).kind == tyPtr: app(pl, ~"->")
-  else: app(pl, ~".")
-  app(pl, op.r)
-  var params: PRope
-  for i in countup(2, length - 1):
-    if params != nil: params.app(~", ")
-    assert(sonsLen(typ) == sonsLen(typ.n))
-    if i < sonsLen(typ):
-      assert(typ.n.sons[i].kind == nkSym)
-      app(params, genArg(p, ri.sons[i], typ.n.sons[i].sym))
+  # don't call '$' here for efficiency:
+  let pat = ri.sons[0].sym.loc.r.data
+  internalAssert pat != nil
+  if pat.contains({'#', '(', '@', '\''}):
+    var pl = genPatternCall(p, ri, pat, typ)
+    # simpler version of 'fixupCall' that works with the pl+params combination:
+    var typ = skipTypes(ri.sons[0].typ, abstractInst)
+    if typ.sons[0] != nil:
+      if p.module.compileToCpp and lfSingleUse in d.flags:
+        # do not generate spurious temporaries for C++! For C we're better off
+        # with them to prevent undefined behaviour and because the codegen
+        # is free to emit expressions multiple times!
+        d.k = locCall
+        d.r = pl
+        excl d.flags, lfSingleUse
+      else:
+        if d.k == locNone: getTemp(p, typ.sons[0], d)
+        assert(d.t != nil)        # generate an assignment to d:
+        var list: TLoc
+        initLoc(list, locCall, d.t, OnUnknown)
+        list.r = pl
+        genAssignment(p, d, list, {}) # no need for deep copying
     else:
-      app(params, genArgNoParam(p, ri.sons[i]))
-  fixupCall(p, le, ri, d, pl, params)
+      add(pl, ~";$n")
+      line(p, cpsStmts, pl)
+  else:
+    var pl: Rope = nil
+    #var param = typ.n.sons[1].sym
+    if 1 < ri.len:
+      add(pl, genThisArg(p, ri, 1, typ))
+    add(pl, op.r)
+    var params: Rope
+    for i in countup(2, length - 1):
+      if params != nil: params.add(~", ")
+      assert(sonsLen(typ) == sonsLen(typ.n))
+      add(params, genOtherArg(p, ri, i, typ))
+    fixupCall(p, le, ri, d, pl, params)
 
 proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
   # generates a crappy ObjC call
@@ -255,44 +454,56 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
   assert(typ.kind == tyProc)
   var length = sonsLen(ri)
   assert(sonsLen(typ) == sonsLen(typ.n))
-  
-  if length > 1:
-    app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym))
-    app(pl, ~" ")
-  app(pl, op.r)
-  if length > 2:
-    app(pl, ~": ")
-    app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym))
-  for i in countup(3, length-1):
+
+  # don't call '$' here for efficiency:
+  let pat = ri.sons[0].sym.loc.r.data
+  internalAssert pat != nil
+  var start = 3
+  if ' ' in pat:
+    start = 1
+    add(pl, op.r)
+    if length > 1:
+      add(pl, ~": ")
+      add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
+      start = 2
+  else:
+    if length > 1:
+      add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
+      add(pl, ~" ")
+    add(pl, op.r)
+    if length > 2:
+      add(pl, ~": ")
+      add(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri))
+  for i in countup(start, length-1):
     assert(sonsLen(typ) == sonsLen(typ.n))
     if i >= sonsLen(typ):
       internalError(ri.info, "varargs for objective C method?")
     assert(typ.n.sons[i].kind == nkSym)
     var param = typ.n.sons[i].sym
-    app(pl, ~" ")
-    app(pl, param.name.s)
-    app(pl, ~": ")
-    app(pl, genArg(p, ri.sons[i], param))
+    add(pl, ~" ")
+    add(pl, param.name.s)
+    add(pl, ~": ")
+    add(pl, genArg(p, ri.sons[i], param, ri))
   if typ.sons[0] != nil:
     if isInvalidReturnType(typ.sons[0]):
-      if sonsLen(ri) > 1: app(pl, ~" ")
+      if sonsLen(ri) > 1: add(pl, ~" ")
       # beware of 'result = p(result)'. We always allocate a temporary:
       if d.k in {locTemp, locNone}:
         # We already got a temp. Great, special case it:
         if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true)
-        app(pl, ~"Result: ")
-        app(pl, addrLoc(d))
-        app(pl, ~"];$n")
+        add(pl, ~"Result: ")
+        add(pl, addrLoc(d))
+        add(pl, ~"];$n")
         line(p, cpsStmts, pl)
       else:
         var tmp: TLoc
         getTemp(p, typ.sons[0], tmp, needsInit=true)
-        app(pl, addrLoc(tmp))
-        app(pl, ~"];$n")
+        add(pl, addrLoc(tmp))
+        add(pl, ~"];$n")
         line(p, cpsStmts, pl)
         genAssignment(p, d, tmp, {}) # no need for deep copying
     else:
-      app(pl, ~"]")
+      add(pl, ~"]")
       if d.k == locNone: getTemp(p, typ.sons[0], d)
       assert(d.t != nil)        # generate an assignment to d:
       var list: TLoc
@@ -300,14 +511,13 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
       list.r = pl
       genAssignment(p, d, list, {}) # no need for deep copying
   else:
-    app(pl, ~"];$n")
+    add(pl, ~"];$n")
     line(p, cpsStmts, pl)
 
 proc genCall(p: BProc, e: PNode, d: var TLoc) =
   if e.sons[0].typ.callConv == ccClosure:
     genClosureCall(p, nil, e, d)
-  elif e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags and
-      e.len >= 2:
+  elif e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags:
     genInfixCall(p, nil, e, d)
   elif e.sons[0].kind == nkSym and sfNamedParamCall in e.sons[0].sym.flags:
     genNamedParamCall(p, e, d)
@@ -320,8 +530,7 @@ proc genCall(p: BProc, e: PNode, d: var TLoc) =
 proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
   if ri.sons[0].typ.callConv == ccClosure:
     genClosureCall(p, le, ri, d)
-  elif ri.sons[0].kind == nkSym and sfInfixCall in ri.sons[0].sym.flags and
-      ri.len >= 2:
+  elif ri.sons[0].kind == nkSym and sfInfixCall in ri.sons[0].sym.flags:
     genInfixCall(p, le, ri, d)
   elif ri.sons[0].kind == nkSym and sfNamedParamCall in ri.sons[0].sym.flags:
     genNamedParamCall(p, ri, d)
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 547d0d376..93a9dd65d 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -11,95 +11,92 @@
 
 # -------------------------- constant expressions ------------------------
 
-proc int64Literal(i: BiggestInt): PRope =
+proc int64Literal(i: BiggestInt): Rope =
   if i > low(int64):
-    result = rfmt(nil, "IL64($1)", toRope(i))
+    result = rfmt(nil, "IL64($1)", rope(i))
   else:
     result = ~"(IL64(-9223372036854775807) - IL64(1))"
 
-proc uint64Literal(i: uint64): PRope = toRope($i & "ULL")
+proc uint64Literal(i: uint64): Rope = rope($i & "ULL")
 
-proc intLiteral(i: BiggestInt): PRope =
+proc intLiteral(i: BiggestInt): Rope =
   if i > low(int32) and i <= high(int32):
-    result = toRope(i)
+    result = rope(i)
   elif i == low(int32):
     # Nim has the same bug for the same reasons :-)
     result = ~"(-2147483647 -1)"
   elif i > low(int64):
-    result = rfmt(nil, "IL64($1)", toRope(i))
+    result = rfmt(nil, "IL64($1)", rope(i))
   else:
     result = ~"(IL64(-9223372036854775807) - IL64(1))"
 
-proc int32Literal(i: int): PRope =
+proc int32Literal(i: int): Rope =
   if i == int(low(int32)):
     result = ~"(-2147483647 -1)"
   else:
-    result = toRope(i)
+    result = rope(i)
 
-proc genHexLiteral(v: PNode): PRope =
+proc genHexLiteral(v: PNode): Rope =
   # hex literals are unsigned in C
   # so we don't generate hex literals any longer.
   if v.kind notin {nkIntLit..nkUInt64Lit}:
     internalError(v.info, "genHexLiteral")
   result = intLiteral(v.intVal)
 
-proc getStrLit(m: BModule, s: string): PRope =
+proc getStrLit(m: BModule, s: string): Rope =
   discard cgsym(m, "TGenericSeq")
-  result = con("TMP", toRope(backendId()))
-  appf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
-       [result, makeCString(s), toRope(len(s))])
+  result = "TMP" & rope(backendId())
+  addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
+       [result, makeCString(s), rope(len(s))])
 
-proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
+proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
   if ty == nil: internalError(n.info, "genLiteral: ty is nil")
   case n.kind
   of nkCharLit..nkUInt64Lit:
     case skipTypes(ty, abstractVarRange).kind
     of tyChar, tyNil:
       result = intLiteral(n.intVal)
-    of tyInt:
-      if n.intVal >= low(int32) and n.intVal <= high(int32):
-        result = int32Literal(int32(n.intVal))
-      else:
-        result = intLiteral(n.intVal)
     of tyBool:
       if n.intVal != 0: result = ~"NIM_TRUE"
       else: result = ~"NIM_FALSE"
     of tyInt64: result = int64Literal(n.intVal)
     of tyUInt64: result = uint64Literal(uint64(n.intVal))
     else:
-      result = ropef("(($1) $2)", [getTypeDesc(p.module,
-          skipTypes(ty, abstractVarRange)), intLiteral(n.intVal)])
+      result = "(($1) $2)" % [getTypeDesc(p.module,
+          skipTypes(ty, abstractVarRange)), intLiteral(n.intVal)]
   of nkNilLit:
     let t = skipTypes(ty, abstractVarRange)
     if t.kind == tyProc and t.callConv == ccClosure:
       var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
-      result = con("TMP", toRope(id))
+      result = "TMP" & rope(id)
       if id == gBackendId:
         # not found in cache:
         inc(gBackendId)
-        appf(p.module.s[cfsData],
+        addf(p.module.s[cfsData],
              "static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n",
              [getTypeDesc(p.module, t), result])
     else:
-      result = toRope("NIM_NIL")
+      result = rope("NIM_NIL")
   of nkStrLit..nkTripleStrLit:
-    if skipTypes(ty, abstractVarRange).kind == tyString:
+    if n.strVal.isNil:
+      result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", [])
+    elif skipTypes(ty, abstractVarRange).kind == tyString:
       var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
       if id == gBackendId:
         # string literal not found in the cache:
-        result = ropecg(p.module, "((#NimStringDesc*) &$1)", 
+        result = ropecg(p.module, "((#NimStringDesc*) &$1)",
                         [getStrLit(p.module, n.strVal)])
       else:
-        result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [toRope(id)])
+        result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [rope(id)])
     else:
       result = makeCString(n.strVal)
   of nkFloatLit..nkFloat64Lit:
-    result = toRope(n.floatVal.toStrMaxPrecision)
+    result = rope(n.floatVal.toStrMaxPrecision)
   else:
     internalError(n.info, "genLiteral(" & $n.kind & ')')
     result = nil
 
-proc genLiteral(p: BProc, n: PNode): PRope =
+proc genLiteral(p: BProc, n: PNode): Rope =
   result = genLiteral(p, n, n.typ)
 
 proc bitSetToWord(s: TBitSet, size: int): BiggestInt =
@@ -116,10 +113,10 @@ proc bitSetToWord(s: TBitSet, size: int): BiggestInt =
       for j in countup(0, size - 1):
         if j < len(s): result = result or `shl`(Ze64(s[j]), (Size - 1 - j) * 8)
 
-proc genRawSetData(cs: TBitSet, size: int): PRope =
-  var frmt: TFormatStr
+proc genRawSetData(cs: TBitSet, size: int): Rope =
+  var frmt: FormatStr
   if size > 8:
-    result = ropef("{$n")
+    result = "{$n" % []
     for i in countup(0, size - 1):
       if i < size - 1:
         # not last iteration?
@@ -127,22 +124,22 @@ proc genRawSetData(cs: TBitSet, size: int): PRope =
         else: frmt = "0x$1, "
       else:
         frmt = "0x$1}$n"
-      appf(result, frmt, [toRope(toHex(ze64(cs[i]), 2))])
+      addf(result, frmt, [rope(toHex(ze64(cs[i]), 2))])
   else:
     result = intLiteral(bitSetToWord(cs, size))
-    #  result := toRope('0x' + ToHex(bitSetToWord(cs, size), size * 2))
+    #  result := rope('0x' + ToHex(bitSetToWord(cs, size), size * 2))
 
-proc genSetNode(p: BProc, n: PNode): PRope =
+proc genSetNode(p: BProc, n: PNode): Rope =
   var cs: TBitSet
   var size = int(getSize(n.typ))
   toBitSet(n, cs)
   if size > 8:
     var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
-    result = con("TMP", toRope(id))
+    result = "TMP" & rope(id)
     if id == gBackendId:
       # not found in cache:
       inc(gBackendId)
-      appf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n",
+      addf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n",
            [getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)])
   else:
     result = genRawSetData(cs, size)
@@ -156,7 +153,7 @@ proc getStorageLoc(n: PNode): TStorageLoc =
     of skVar, skForVar, skResult, skLet:
       if sfGlobal in n.sym.flags: result = OnHeap
       else: result = OnStack
-    of skConst: 
+    of skConst:
       if sfGlobal in n.sym.flags: result = OnHeap
       else: result = OnUnknown
     else: result = OnUnknown
@@ -214,11 +211,12 @@ proc asgnComplexity(n: PNode): int =
         result += asgnComplexity(t)
     else: discard
 
-proc optAsgnLoc(a: TLoc, t: PType, field: PRope): TLoc =
+proc optAsgnLoc(a: TLoc, t: PType, field: Rope): TLoc =
+  assert field != nil
   result.k = locField
   result.s = a.s
   result.t = t
-  result.r = rdLoc(a).con(".").con(field)
+  result.r = rdLoc(a) & "." & field
   result.heapRoot = a.heapRoot
 
 proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
@@ -229,10 +227,11 @@ proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
       flags - {needToCopy}
     else:
       flags
-  for i in 0 .. <dest.t.len:
-    let t = dest.t.sons[i]
-    let field = ropef("Field$1", i.toRope)
-    genAssignment(p, optAsgnLoc(dest, t, field), 
+  let t = skipTypes(dest.t, abstractInst).getUniqueType()
+  for i in 0 .. <t.len:
+    let t = t.sons[i]
+    let field = "Field$1" % [i.rope]
+    genAssignment(p, optAsgnLoc(dest, t, field),
                      optAsgnLoc(src, t, field), newflags)
 
 proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
@@ -248,20 +247,20 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
   case t.kind
   of nkSym:
     let field = t.sym
-    genAssignment(p, optAsgnLoc(dest, field.typ, field.loc.r), 
+    genAssignment(p, optAsgnLoc(dest, field.typ, field.loc.r),
                      optAsgnLoc(src, field.typ, field.loc.r), newflags)
   of nkRecList:
     for child in items(t): genOptAsgnObject(p, dest, src, newflags, child)
   else: discard
 
 proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
-  # Consider: 
+  # Consider:
   # type TMyFastString {.shallow.} = string
   # Due to the implementation of pragmas this would end up to set the
   # tfShallow flag for the built-in string type too! So we check only
   # here for this flag, where it is reasonably safe to do so
   # (for objects, etc.):
-  if needToCopy notin flags or 
+  if needToCopy notin flags or
       tfShallow in skipTypes(dest.t, abstractVarRange).flags:
     if dest.s == OnStack or not usesNativeGC():
       useStringh(p.module)
@@ -314,8 +313,8 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
   of tyProc:
     if needsComplexAssignment(dest.t):
       # optimize closure assignment:
-      let a = optAsgnLoc(dest, dest.t, "ClEnv".toRope)
-      let b = optAsgnLoc(src, dest.t, "ClEnv".toRope)
+      let a = optAsgnLoc(dest, dest.t, "ClEnv".rope)
+      let b = optAsgnLoc(src, dest.t, "ClEnv".rope)
       genRefAssign(p, a, b, flags)
       linefmt(p, cpsStmts, "$1.ClPrc = $2.ClPrc;$n", rdLoc(dest), rdLoc(src))
     else:
@@ -328,11 +327,14 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
       linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
   of tyObject:
     # XXX: check for subtyping?
-    if not isObjLackingTypeField(ty):
+    if ty.isImportedCppType:
+      linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
+    elif not isObjLackingTypeField(ty):
       genGenericAsgn(p, dest, src, flags)
     elif needsComplexAssignment(ty):
       if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4:
         discard getTypeDesc(p.module, ty)
+        ty = getUniqueType(ty)
         internalAssert ty.n != nil
         genOptAsgnObject(p, dest, src, flags, ty.n)
       else:
@@ -363,7 +365,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
     if mapType(ty) == ctArray:
       useStringh(p.module)
       linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n",
-              rdLoc(dest), rdLoc(src), toRope(getSize(dest.t)))
+              rdLoc(dest), rdLoc(src), rope(getSize(dest.t)))
     else:
       linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
   of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString,
@@ -389,7 +391,7 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) =
     if mapType(ty) == ctArray:
       useStringh(p.module)
       linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n",
-              rdLoc(dest), rdLoc(src), toRope(getSize(dest.t)))
+              rdLoc(dest), rdLoc(src), rope(getSize(dest.t)))
     else:
       linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
   of tyPointer, tyChar, tyBool, tyEnum, tyCString,
@@ -407,11 +409,11 @@ proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) =
   else:
     d = s # ``d`` is free, so fill it with ``s``
 
-proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
+proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: Rope) =
   var a: TLoc
   if d.k != locNone:
     # need to generate an assignment here
-    initLoc(a, locData, getUniqueType(t), OnUnknown)
+    initLoc(a, locData, t, OnUnknown)
     a.r = r
     if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {})
     else: genAssignment(p, d, a, {needToCopy})
@@ -419,14 +421,14 @@ proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
     # we cannot call initLoc() here as that would overwrite
     # the flags field!
     d.k = locData
-    d.t = getUniqueType(t)
+    d.t = t
     d.r = r
 
-proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
+proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: Rope) =
   var a: TLoc
   if d.k != locNone:
     # need to generate an assignment here
-    initLoc(a, locExpr, getUniqueType(t), OnUnknown)
+    initLoc(a, locExpr, t, OnUnknown)
     a.r = r
     if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {})
     else: genAssignment(p, d, a, {needToCopy})
@@ -434,7 +436,7 @@ proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
     # we cannot call initLoc() here as that would overwrite
     # the flags field!
     d.k = locExpr
-    d.t = getUniqueType(t)
+    d.t = t
     d.r = r
 
 proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
@@ -483,37 +485,48 @@ proc unaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
   initLocExpr(p, e.sons[1], a)
   putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [rdCharLoc(a)]))
 
+proc binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc;
+                            frmt: string): Rope =
+  var size = getSize(t)
+  let storage = if size < platform.intSize: rope("NI")
+                else: getTypeDesc(p.module, t)
+  result = getTempName()
+  linefmt(p, cpsLocals, "$1 $2;$n", storage, result)
+  lineCg(p, cpsStmts, frmt, result, rdCharLoc(a), rdCharLoc(b))
+  if size < platform.intSize or t.kind in {tyRange, tyEnum}:
+    linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseOverflow();$n",
+            result, intLiteral(firstOrd(t)), intLiteral(lastOrd(t)))
+
 proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
   const
-    prc: array[mAddI..mModI64, string] = ["addInt", "subInt", "mulInt",
-      "divInt", "modInt", "addInt64", "subInt64", "mulInt64", "divInt64",
-      "modInt64"]
-    opr: array[mAddI..mModI64, string] = ["+", "-", "*", "/", "%", "+", "-",
-      "*", "/", "%"]
+    prc: array[mAddI..mPred, string] = [
+      "$# = #addInt($#, $#);$n", "$# = #subInt($#, $#);$n",
+      "$# = #mulInt($#, $#);$n", "$# = #divInt($#, $#);$n",
+      "$# = #modInt($#, $#);$n",
+      "$# = #addInt64($#, $#);$n", "$# = #subInt64($#, $#);$n",
+      "$# = #mulInt64($#, $#);$n", "$# = #divInt64($#, $#);$n",
+      "$# = #modInt64($#, $#);$n",
+      "$# = #addInt($#, $#);$n", "$# = #subInt($#, $#);$n"]
+    opr: array[mAddI..mPred, string] = [
+      "($#)($# + $#)", "($#)($# - $#)", "($#)($# * $#)",
+      "($#)($# / $#)", "($#)($# % $#)",
+      "($#)($# + $#)", "($#)($# - $#)", "($#)($# * $#)",
+      "($#)($# / $#)", "($#)($# % $#)",
+      "($#)($# + $#)", "($#)($# - $#)"]
   var a, b: TLoc
   assert(e.sons[1].typ != nil)
   assert(e.sons[2].typ != nil)
   initLocExpr(p, e.sons[1], a)
   initLocExpr(p, e.sons[2], b)
-  var t = skipTypes(e.typ, abstractRange)
+  # skipping 'range' is correct here as we'll generate a proper range check
+  # later via 'chckRange'
+  let t = e.typ.skipTypes(abstractRange)
   if optOverflowCheck notin p.options:
-    putIntoDest(p, d, e.typ, ropef("(NI$4)($2 $1 $3)", [toRope(opr[m]),
-        rdLoc(a), rdLoc(b), toRope(getSize(t) * 8)]))
+    let res = opr[m] % [getTypeDesc(p.module, t), rdLoc(a), rdLoc(b)]
+    putIntoDest(p, d, e.typ, res)
   else:
-    var storage: PRope
-    var size = getSize(t)
-    if size < platform.intSize:
-      storage = toRope("NI") 
-    else:
-      storage = getTypeDesc(p.module, t)
-    var tmp = getTempName()
-    linefmt(p, cpsLocals, "$1 $2;$n", storage, tmp)
-    lineCg(p, cpsStmts, "$1 = #$2($3, $4);$n",
-                         tmp, toRope(prc[m]), rdLoc(a), rdLoc(b))
-    if size < platform.intSize or t.kind in {tyRange, tyEnum, tySet}:
-      linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseOverflow();$n",
-              tmp, intLiteral(firstOrd(t)), intLiteral(lastOrd(t)))
-    putIntoDest(p, d, e.typ, ropef("(NI$1)($2)", [toRope(getSize(t)*8), tmp]))
+    let res = binaryArithOverflowRaw(p, t, a, b, prc[m])
+    putIntoDest(p, d, e.typ, "($#)($#)" % [getTypeDesc(p.module, t), res])
 
 proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
   const
@@ -531,7 +544,7 @@ proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
   if optOverflowCheck in p.options:
     linefmt(p, cpsStmts, "if ($1 == $2) #raiseOverflow();$n",
             rdLoc(a), intLiteral(firstOrd(t)))
-  putIntoDest(p, d, e.typ, ropef(opr[m], [rdLoc(a), toRope(getSize(t) * 8)]))
+  putIntoDest(p, d, e.typ, opr[m] % [rdLoc(a), rope(getSize(t) * 8)])
 
 proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   const
@@ -540,7 +553,7 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       "(($4)($1) - ($4)($2))", # SubF64
       "(($4)($1) * ($4)($2))", # MulF64
       "(($4)($1) / ($4)($2))", # DivF64
-      
+
       "($4)((NU$3)($1) >> (NU$3)($2))", # ShrI
       "($4)((NU$3)($1) << (NU$3)($2))", # ShlI
       "($4)($1 & $2)",      # BitandI
@@ -553,8 +566,6 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       "($4)($1 & $2)",            # BitandI64
       "($4)($1 | $2)",            # BitorI64
       "($4)($1 ^ $2)",            # BitxorI64
-      "(($1 <= $2) ? $1 : $2)", # MinI64
-      "(($1 >= $2) ? $1 : $2)", # MaxI64
       "(($1 <= $2) ? $1 : $2)", # MinF64
       "(($1 >= $2) ? $1 : $2)", # MaxF64
       "($4)((NU$3)($1) + (NU$3)($2))", # AddU
@@ -600,8 +611,8 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   # BUGFIX: cannot use result-type here, as it may be a boolean
   s = max(getSize(a.t), getSize(b.t)) * 8
   putIntoDest(p, d, e.typ,
-              ropef(binArithTab[op], [rdLoc(a), rdLoc(b), toRope(s),
-                                      getSimpleTypeDesc(p.module, e.typ)]))
+              binArithTab[op] % [rdLoc(a), rdLoc(b), rope(s),
+                                      getSimpleTypeDesc(p.module, e.typ)])
 
 proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
   var a, b: TLoc
@@ -610,11 +621,10 @@ proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
   initLocExpr(p, e.sons[1], a)
   initLocExpr(p, e.sons[2], b)
   if a.t.callConv == ccClosure:
-    putIntoDest(p, d, e.typ, 
-      ropef("($1.ClPrc == $2.ClPrc && $1.ClEnv == $2.ClEnv)", [
-      rdLoc(a), rdLoc(b)]))
+    putIntoDest(p, d, e.typ,
+      "($1.ClPrc == $2.ClPrc && $1.ClEnv == $2.ClEnv)" % [rdLoc(a), rdLoc(b)])
   else:
-    putIntoDest(p, d, e.typ, ropef("($1 == $2)", [rdLoc(a), rdLoc(b)]))
+    putIntoDest(p, d, e.typ, "($1 == $2)" % [rdLoc(a), rdLoc(b)])
 
 proc genIsNil(p: BProc, e: PNode, d: var TLoc) =
   let t = skipTypes(e.sons[1].typ, abstractRange)
@@ -628,7 +638,6 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     unArithTab: array[mNot..mToBiggestInt, string] = ["!($1)", # Not
       "$1",                   # UnaryPlusI
       "($3)((NU$2) ~($1))",   # BitnotI
-      "$1",                   # UnaryPlusI64
       "($3)((NU$2) ~($1))",   # BitnotI64
       "$1",                   # UnaryPlusF64
       "-($1)",                # UnaryMinusF64
@@ -654,11 +663,17 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   initLocExpr(p, e.sons[1], a)
   t = skipTypes(e.typ, abstractRange)
   putIntoDest(p, d, e.typ,
-              ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8),
-                    getSimpleTypeDesc(p.module, e.typ)]))
+              unArithTab[op] % [rdLoc(a), rope(getSize(t) * 8),
+                getSimpleTypeDesc(p.module, e.typ)])
+
+proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
+  result = p.module.compileToCpp and
+      skipTypes(typ, abstractInst).kind == tyVar and
+      tfVarIsPtr notin skipTypes(typ, abstractInst).flags
 
 proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
-  if mapType(e.sons[0].typ) in {ctArray, ctPtrToArray} and not enforceDeref:
+  let mt = mapType(e.sons[0].typ)
+  if mt in {ctArray, ctPtrToArray} and not enforceDeref:
     # XXX the amount of hacks for C's arrays is incredible, maybe we should
     # simply wrap them in a struct? --> Losing auto vectorization then?
     #if e[0].kind != nkBracketExpr:
@@ -666,25 +681,48 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
     expr(p, e.sons[0], d)
   else:
     var a: TLoc
-    initLocExpr(p, e.sons[0], a)
-    case skipTypes(a.t, abstractInst).kind
-    of tyRef:
-      d.s = OnHeap
-    of tyVar:
-      d.s = OnUnknown
-    of tyPtr:
-      d.s = OnUnknown         # BUGFIX!
-    else: internalError(e.info, "genDeref " & $a.t.kind)
-    putIntoDest(p, d, a.t.sons[0], ropef("(*$1)", [rdLoc(a)]))
+    initLocExprSingleUse(p, e.sons[0], a)
+    if d.k == locNone:
+      let typ = skipTypes(a.t, abstractInst)
+      # dest = *a;  <-- We do not know that 'dest' is on the heap!
+      # It is completely wrong to set 'd.s' here, unless it's not yet
+      # been assigned to.
+      case typ.kind
+      of tyRef:
+        d.s = OnHeap
+      of tyVar:
+        d.s = OnUnknown
+        if tfVarIsPtr notin typ.flags and p.module.compileToCpp and
+            e.kind == nkHiddenDeref:
+          putIntoDest(p, d, e.typ, rdLoc(a))
+          return
+      of tyPtr:
+        d.s = OnUnknown         # BUGFIX!
+      else: internalError(e.info, "genDeref " & $a.t.kind)
+    elif p.module.compileToCpp:
+      let typ = skipTypes(a.t, abstractInst)
+      if typ.kind == tyVar and tfVarIsPtr notin typ.flags and
+           e.kind == nkHiddenDeref:
+        putIntoDest(p, d, e.typ, rdLoc(a))
+        return
+    if enforceDeref and mt == ctPtrToArray:
+      # we lie about the type for better C interop: 'ptr array[3,T]' is
+      # translated to 'ptr T', but for deref'ing this produces wrong code.
+      # See tmissingderef. So we get rid of the deref instead. The codegen
+      # ends up using 'memcpy' for the array assignment,
+      # so the '&' and '*' cancel out:
+      putIntoDest(p, d, a.t.sons[0], rdLoc(a))
+    else:
+      putIntoDest(p, d, e.typ, "(*$1)" % [rdLoc(a)])
 
 proc genAddr(p: BProc, e: PNode, d: var TLoc) =
   # careful  'addr(myptrToArray)' needs to get the ampersand:
   if e.sons[0].typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}:
     var a: TLoc
     initLocExpr(p, e.sons[0], a)
-    putIntoDest(p, d, e.typ, con("&", a.r))
+    putIntoDest(p, d, e.typ, "&" & a.r)
     #Message(e.info, warnUser, "HERE NEW &")
-  elif mapType(e.sons[0].typ) == ctArray:
+  elif mapType(e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ):
     expr(p, e.sons[0], d)
   else:
     var a: TLoc
@@ -695,13 +733,13 @@ template inheritLocation(d: var TLoc, a: TLoc) =
   if d.k == locNone: d.s = a.s
   if d.heapRoot == nil:
     d.heapRoot = if a.heapRoot != nil: a.heapRoot else: a.r
-  
+
 proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc): PType =
   initLocExpr(p, e.sons[0], a)
   if e.sons[1].kind != nkSym: internalError(e.info, "genRecordFieldAux")
   d.inheritLocation(a)
   discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
-  result = a.t
+  result = a.t.getUniqueType
 
 proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
   var
@@ -710,12 +748,12 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
   initLocExpr(p, e.sons[0], a)
   d.inheritLocation(a)
   discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
-  var ty = a.t
+  var ty = a.t.getUniqueType
   var r = rdLoc(a)
   case e.sons[1].kind
   of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal)
   else: internalError(e.info, "genTupleElem")
-  appf(r, ".Field$1", [toRope(i)])
+  addf(r, ".Field$1", [rope(i)])
   putIntoDest(p, d, ty.sons[i], r)
 
 proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
@@ -726,7 +764,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
   if ty.kind == tyTuple:
     # we found a unique tuple type which lacks field information
     # so we use Field$i
-    appf(r, ".Field$1", [toRope(f.position)])
+    addf(r, ".Field$1", [rope(f.position)])
     putIntoDest(p, d, f.typ, r)
   else:
     var field: PSym = nil
@@ -735,16 +773,17 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
         internalError(e.info, "genRecordField")
       field = lookupInRecord(ty.n, f.name)
       if field != nil: break
-      if not p.module.compileToCpp: app(r, ".Sup")
+      if not p.module.compileToCpp: add(r, ".Sup")
       ty = getUniqueType(ty.sons[0])
     if field == nil: internalError(e.info, "genRecordField 2 ")
     if field.loc.r == nil: internalError(e.info, "genRecordField 3")
-    appf(r, ".$1", [field.loc.r])
+    addf(r, ".$1", [field.loc.r])
     putIntoDest(p, d, field.typ, r)
+  #d.s = a.s
 
 proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc)
 
-proc genFieldCheck(p: BProc, e: PNode, obj: PRope, field: PSym) =
+proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
   var test, u, v: TLoc
   for i in countup(1, sonsLen(e) - 1):
     var it = e.sons[i]
@@ -757,12 +796,12 @@ proc genFieldCheck(p: BProc, e: PNode, obj: PRope, field: PSym) =
     initLoc(test, locNone, it.typ, OnStack)
     initLocExpr(p, it.sons[1], u)
     initLoc(v, locExpr, disc.typ, OnUnknown)
-    v.r = ropef("$1.$2", [obj, disc.sym.loc.r])
+    v.r = "$1.$2" % [obj, disc.sym.loc.r]
     genInExprAux(p, it, u, v, test)
     let id = nodeTableTestOrSet(p.module.dataCache,
                                newStrNode(nkStrLit, field.name.s), gBackendId)
     let strLit = if id == gBackendId: getStrLit(p.module, field.name.s)
-                 else: con("TMP", toRope(id))
+                 else: "TMP" & rope(id)
     if op.magic == mNot:
       linefmt(p, cpsStmts,
               "if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
@@ -778,7 +817,7 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
       a: TLoc
       f, field: PSym
       ty: PType
-      r: PRope
+      r: Rope
     ty = genRecordFieldAux(p, e.sons[0], d, a)
     r = rdLoc(a)
     f = e.sons[0].sons[1].sym
@@ -787,13 +826,13 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
       assert(ty.kind in {tyTuple, tyObject})
       field = lookupInRecord(ty.n, f.name)
       if field != nil: break
-      if not p.module.compileToCpp: app(r, ".Sup")
+      if not p.module.compileToCpp: add(r, ".Sup")
       ty = getUniqueType(ty.sons[0])
     if field == nil: internalError(e.info, "genCheckedRecordField")
     if field.loc.r == nil:
       internalError(e.info, "genCheckedRecordField") # generate the checks:
     genFieldCheck(p, e, r, field)
-    app(r, rfmt(nil, ".$1", field.loc.r))
+    add(r, rfmt(nil, ".$1", field.loc.r))
     putIntoDest(p, d, field.typ, r)
   else:
     genRecordField(p, e.sons[0], d)
@@ -902,6 +941,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
     L: TLabel
     tmp: TLoc
   getTemp(p, e.typ, tmp)      # force it into a temp!
+  inc p.splitDecls
   expr(p, e.sons[1], tmp)
   L = getLabel(p)
   if m == mOr:
@@ -914,19 +954,20 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
     d = tmp
   else:
     genAssignment(p, d, tmp, {}) # no need for deep copying
+  dec p.splitDecls
 
 proc genEcho(p: BProc, n: PNode) =
   # this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
   # is threadsafe.
   internalAssert n.kind == nkBracket
   discard lists.includeStr(p.module.headerFiles, "<stdio.h>")
-  var args: PRope = nil
+  var args: Rope = nil
   var a: TLoc
   for i in countup(0, n.len-1):
     initLocExpr(p, n.sons[i], a)
-    appf(args, ", ($1)->data", [rdLoc(a)])
+    addf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
   linefmt(p, cpsStmts, "printf($1$2);$n",
-          makeCString(repeatStr(n.len, "%s") & tnl), args)
+          makeCString(repeat("%s", n.len) & tnl), args)
 
 proc gcUsage(n: PNode) =
   if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
@@ -951,22 +992,22 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
   var a, tmp: TLoc
   getTemp(p, e.typ, tmp)
   var L = 0
-  var appends: PRope = nil
-  var lens: PRope = nil
+  var appends: Rope = nil
+  var lens: Rope = nil
   for i in countup(0, sonsLen(e) - 2):
     # compute the length expression:
     initLocExpr(p, e.sons[i + 1], a)
     if skipTypes(e.sons[i + 1].typ, abstractVarRange).kind == tyChar:
       inc(L)
-      app(appends, rfmt(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a)))
+      add(appends, rfmt(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a)))
     else:
       if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
         inc(L, len(e.sons[i + 1].strVal))
       else:
-        appf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
-      app(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
-  linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, toRope(L))
-  app(p.s(cpsStmts), appends)
+        addf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
+      add(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
+  linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, rope(L))
+  add(p.s(cpsStmts), appends)
   if d.k == locNone:
     d = tmp
     keepAlive(p, tmp)
@@ -988,7 +1029,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
   #  }
   var
     a, dest: TLoc
-    appends, lens: PRope
+    appends, lens: Rope
   assert(d.k == locNone)
   var L = 0
   initLocExpr(p, e.sons[1], dest)
@@ -997,19 +1038,19 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
     initLocExpr(p, e.sons[i + 2], a)
     if skipTypes(e.sons[i + 2].typ, abstractVarRange).kind == tyChar:
       inc(L)
-      app(appends, rfmt(p.module, "#appendChar($1, $2);$n",
+      add(appends, rfmt(p.module, "#appendChar($1, $2);$n",
                         rdLoc(dest), rdLoc(a)))
     else:
       if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
         inc(L, len(e.sons[i + 2].strVal))
       else:
-        appf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
-      app(appends, rfmt(p.module, "#appendString($1, $2);$n",
+        addf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
+      add(appends, rfmt(p.module, "#appendString($1, $2);$n",
                         rdLoc(dest), rdLoc(a)))
   linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
-          rdLoc(dest), lens, toRope(L))
+          rdLoc(dest), lens, rope(L))
   keepAlive(p, dest)
-  app(p.s(cpsStmts), appends)
+  add(p.s(cpsStmts), appends)
   gcUsage(e)
 
 proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
@@ -1033,20 +1074,20 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
   genAssignment(p, dest, b, {needToCopy, afDestIsNil})
   gcUsage(e)
 
-proc genReset(p: BProc, n: PNode) = 
+proc genReset(p: BProc, n: PNode) =
   var a: TLoc
   initLocExpr(p, n.sons[1], a)
   linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
           addrLoc(a), genTypeInfo(p.module, skipTypes(a.t, abstractVarRange)))
 
-proc rawGenNew(p: BProc, a: TLoc, sizeExpr: PRope) =
+proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
   var sizeExpr = sizeExpr
   let refType = skipTypes(a.t, abstractVarRange)
   var b: TLoc
   initLoc(b, locExpr, a.t, OnHeap)
   if sizeExpr.isNil:
-    sizeExpr = ropef("sizeof($1)",
-        getTypeDesc(p.module, skipTypes(refType.sons[0], abstractRange)))
+    sizeExpr = "sizeof($1)" %
+        [getTypeDesc(p.module, skipTypes(refType.sons[0], abstractRange))]
   let args = [getTypeDesc(p.module, refType),
               genTypeInfo(p.module, refType),
               sizeExpr]
@@ -1076,7 +1117,7 @@ proc genNew(p: BProc, e: PNode) =
     rawGenNew(p, a, nil)
   gcUsage(e)
 
-proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
+proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
   let seqtype = skipTypes(dest.t, abstractVarRange)
   let args = [getTypeDesc(p.module, seqtype),
               genTypeInfo(p.module, seqtype), length]
@@ -1092,14 +1133,14 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
   else:
     call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args)
     genAssignment(p, dest, call, {needToKeepAlive})
-  
+
 proc genNewSeq(p: BProc, e: PNode) =
   var a, b: TLoc
   initLocExpr(p, e.sons[1], a)
   initLocExpr(p, e.sons[2], b)
   genNewSeqAux(p, a, b.rdLoc)
   gcUsage(e)
-  
+
 proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
   var tmp: TLoc
   var t = e.typ.skipTypes(abstractInst)
@@ -1108,8 +1149,8 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
   var r = rdLoc(tmp)
   if isRef:
     rawGenNew(p, tmp, nil)
-    t = t.sons[0].skipTypes(abstractInst)
-    r = ropef("(*$1)", r)
+    t = t.lastSon.skipTypes(abstractInst)
+    r = "(*$1)" % [r]
     gcUsage(e)
   else:
     constructLoc(p, tmp)
@@ -1119,17 +1160,17 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
     var tmp2: TLoc
     tmp2.r = r
     var field: PSym = nil
-    var ty = t
+    var ty = getUniqueType(t)
     while ty != nil:
       field = lookupInRecord(ty.n, it.sons[0].sym.name)
       if field != nil: break
-      if not p.module.compileToCpp: app(tmp2.r, ".Sup")
+      if not p.module.compileToCpp: add(tmp2.r, ".Sup")
       ty = getUniqueType(ty.sons[0])
     if field == nil or field.loc.r == nil: internalError(e.info, "genObjConstr")
     if it.len == 3 and optFieldCheck in p.options:
       genFieldCheck(p, it.sons[2], tmp2.r, field)
-    app(tmp2.r, ".")
-    app(tmp2.r, field.loc.r)
+    add(tmp2.r, ".")
+    add(tmp2.r, field.loc.r)
     tmp2.k = locTemp
     tmp2.t = field.loc.t
     tmp2.s = if isRef: OnHeap else: OnStack
@@ -1140,7 +1181,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
     d = tmp
   else:
     genAssignment(p, d, tmp, {})
-  
+
 proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) =
   var arr: TLoc
   if d.k == locNone:
@@ -1164,7 +1205,7 @@ proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) =
     getTemp(p, t.typ, d)
   # generate call to newSeq before adding the elements per hand:
   var L = int(lengthOrd(t.sons[1].typ))
-  
+
   genNewSeqAux(p, d, intLiteral(L))
   initLocExpr(p, t.sons[1], a)
   for i in countup(0, L - 1):
@@ -1174,39 +1215,39 @@ proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) =
     initLoc(arr, locExpr, elemType(skipTypes(t.sons[1].typ, abstractInst)), a.s)
     arr.r = rfmt(nil, "$1[$2]", rdLoc(a), intLiteral(i))
     genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
-  
+
 proc genNewFinalize(p: BProc, e: PNode) =
   var
     a, b, f: TLoc
     refType, bt: PType
-    ti: PRope
+    ti: Rope
     oldModule: BModule
   refType = skipTypes(e.sons[1].typ, abstractVarRange)
   initLocExpr(p, e.sons[1], a)
   initLocExpr(p, e.sons[2], f)
   initLoc(b, locExpr, a.t, OnHeap)
   ti = genTypeInfo(p.module, refType)
-  appf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
+  addf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
   b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [
       getTypeDesc(p.module, refType),
-      ti, getTypeDesc(p.module, skipTypes(refType.sons[0], abstractRange))])
+      ti, getTypeDesc(p.module, skipTypes(refType.lastSon, abstractRange))])
   genAssignment(p, a, b, {needToKeepAlive})  # set the object type:
-  bt = skipTypes(refType.sons[0], abstractRange)
+  bt = skipTypes(refType.lastSon, abstractRange)
   genObjectInit(p, cpsStmts, bt, a, false)
   gcUsage(e)
 
-proc genOfHelper(p: BProc; dest: PType; a: PRope): PRope =
+proc genOfHelper(p: BProc; dest: PType; a: Rope): Rope =
   # unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we
   # have to call it here first:
   let ti = genTypeInfo(p.module, dest)
   if tfFinal in dest.flags or (p.module.objHasKidsValid and
                                tfObjHasKids notin dest.flags):
-    result = ropef("$1.m_type == $2", a, ti)
+    result = "$1.m_type == $2" % [a, ti]
   else:
     discard cgsym(p.module, "TNimType")
     inc p.module.labels
-    let cache = con("Nim_OfCheck_CACHE", p.module.labels.toRope)
-    appf(p.module.s[cfsVars], "static TNimType* $#[2];$n", cache)
+    let cache = "Nim_OfCheck_CACHE" & p.module.labels.rope
+    addf(p.module.s[cfsVars], "static TNimType* $#[2];$n", [cache])
     result = rfmt(p.module, "#isObjWithCache($#.m_type, $#, $#)", a, ti, cache)
   when false:
     # former version:
@@ -1218,18 +1259,19 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
   initLocExpr(p, x, a)
   var dest = skipTypes(typ, typedescPtrs)
   var r = rdLoc(a)
-  var nilCheck: PRope = nil
+  var nilCheck: Rope = nil
   var t = skipTypes(a.t, abstractInst)
   while t.kind in {tyVar, tyPtr, tyRef}:
     if t.kind != tyVar: nilCheck = r
-    r = rfmt(nil, "(*$1)", r)
+    if t.kind != tyVar or not p.module.compileToCpp:
+      r = rfmt(nil, "(*$1)", r)
     t = skipTypes(t.lastSon, typedescInst)
   if not p.module.compileToCpp:
     while t.kind == tyObject and t.sons[0] != nil:
-      app(r, ~".Sup")
+      add(r, ~".Sup")
       t = skipTypes(t.sons[0], typedescInst)
   if isObjLackingTypeField(t):
-    globalError(x.info, errGenerated, 
+    globalError(x.info, errGenerated,
       "no 'of' operator available for pure objects")
   if nilCheck != nil:
     r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r))
@@ -1246,7 +1288,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
   var t = skipTypes(e.sons[1].typ, abstractVarRange)
   case t.kind
   of tyInt..tyInt64, tyUInt..tyUInt64:
-    putIntoDest(p, d, e.typ, 
+    putIntoDest(p, d, e.typ,
                 ropecg(p.module, "#reprInt((NI64)$1)", [rdLoc(a)]))
   of tyFloat..tyFloat128:
     putIntoDest(p, d, e.typ, ropecg(p.module, "#reprFloat($1)", [rdLoc(a)]))
@@ -1267,15 +1309,15 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
     var b: TLoc
     case a.t.kind
     of tyOpenArray, tyVarargs:
-      putIntoDest(p, b, e.typ, ropef("$1, $1Len0", [rdLoc(a)]))
+      putIntoDest(p, b, e.typ, "$1, $1Len0" % [rdLoc(a)])
     of tyString, tySequence:
-      putIntoDest(p, b, e.typ, 
-                  ropef("$1->data, $1->$2", [rdLoc(a), lenField(p)]))
+      putIntoDest(p, b, e.typ,
+                  "$1->data, $1->$2" % [rdLoc(a), lenField(p)])
     of tyArray, tyArrayConstr:
       putIntoDest(p, b, e.typ,
-                  ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))]))
+                  "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))])
     else: internalError(e.sons[0].info, "genRepr()")
-    putIntoDest(p, d, e.typ, 
+    putIntoDest(p, d, e.typ,
         ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
         genTypeInfo(p.module, elemType(t))]))
   of tyCString, tyArray, tyArrayConstr, tyRef, tyPtr, tyPointer, tyNil,
@@ -1310,19 +1352,19 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     else: unaryExpr(p, e, d, "$1Len0")
   of tyCString:
     useStringh(p.module)
-    if op == mHigh: unaryExpr(p, e, d, "(strlen($1)-1)")
-    else: unaryExpr(p, e, d, "strlen($1)")
+    if op == mHigh: unaryExpr(p, e, d, "($1 ? (strlen($1)-1) : -1)")
+    else: unaryExpr(p, e, d, "($1 ? strlen($1) : 0)")
   of tyString, tySequence:
     if not p.module.compileToCpp:
-      if op == mHigh: unaryExpr(p, e, d, "($1->Sup.len-1)")
-      else: unaryExpr(p, e, d, "$1->Sup.len")
+      if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->Sup.len-1) : -1)")
+      else: unaryExpr(p, e, d, "($1 ? $1->Sup.len : 0)")
     else:
-      if op == mHigh: unaryExpr(p, e, d, "($1->len-1)")
-      else: unaryExpr(p, e, d, "$1->len")
+      if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->len-1) : -1)")
+      else: unaryExpr(p, e, d, "($1 ? $1->len : 0)")
   of tyArray, tyArrayConstr:
     # YYY: length(sideeffect) is optimized away incorrectly?
-    if op == mHigh: putIntoDest(p, d, e.typ, toRope(lastOrd(typ)))
-    else: putIntoDest(p, d, e.typ, toRope(lengthOrd(typ)))
+    if op == mHigh: putIntoDest(p, d, e.typ, rope(lastOrd(typ)))
+    else: putIntoDest(p, d, e.typ, rope(lengthOrd(typ)))
   else: internalError(e.info, "genArrayLen()")
 
 proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
@@ -1360,13 +1402,13 @@ proc genSwap(p: BProc, e: PNode, d: var TLoc) =
   genAssignment(p, a, b, {})
   genAssignment(p, b, tmp, {})
 
-proc rdSetElemLoc(a: TLoc, setType: PType): PRope =
-  # read a location of an set element; it may need a substraction operation
+proc rdSetElemLoc(a: TLoc, setType: PType): Rope =
+  # read a location of an set element; it may need a subtraction operation
   # before the set operation
   result = rdCharLoc(a)
   assert(setType.kind == tySet)
   if firstOrd(setType) != 0:
-    result = ropef("($1- $2)", [result, toRope(firstOrd(setType))])
+    result = "($1- $2)" % [result, rope(firstOrd(setType))]
 
 proc fewCmps(s: PNode): bool =
   # this function estimates whether it is better to emit code
@@ -1380,7 +1422,7 @@ proc fewCmps(s: PNode): bool =
     result = sonsLen(s) <= 8  # 8 seems to be a good value
 
 proc binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) =
-  putIntoDest(p, d, e.typ, ropef(frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]))
+  putIntoDest(p, d, e.typ, frmt % [rdLoc(a), rdSetElemLoc(b, a.t)])
 
 proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) =
   case int(getSize(skipTypes(e.sons[1].typ, abstractVar)))
@@ -1404,25 +1446,25 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
     # do not emit the set, but generate a bunch of comparisons; and if we do
     # so, we skip the unnecessary range check: This is a semantical extension
     # that code now relies on. :-/ XXX
-    let ea = if e.sons[2].kind in {nkChckRange, nkChckRange64}: 
+    let ea = if e.sons[2].kind in {nkChckRange, nkChckRange64}:
                e.sons[2].sons[0]
              else:
                e.sons[2]
     initLocExpr(p, ea, a)
     initLoc(b, locExpr, e.typ, OnUnknown)
-    b.r = toRope("(")
+    b.r = rope("(")
     var length = sonsLen(e.sons[1])
     for i in countup(0, length - 1):
       if e.sons[1].sons[i].kind == nkRange:
         initLocExpr(p, e.sons[1].sons[i].sons[0], x)
         initLocExpr(p, e.sons[1].sons[i].sons[1], y)
-        appf(b.r, "$1 >= $2 && $1 <= $3",
+        addf(b.r, "$1 >= $2 && $1 <= $3",
              [rdCharLoc(a), rdCharLoc(x), rdCharLoc(y)])
       else:
         initLocExpr(p, e.sons[1].sons[i], x)
-        appf(b.r, "$1 == $2", [rdCharLoc(a), rdCharLoc(x)])
-      if i < length - 1: app(b.r, " || ")
-    app(b.r, ")")
+        addf(b.r, "$1 == $2", [rdCharLoc(a), rdCharLoc(x)])
+      if i < length - 1: add(b.r, " || ")
+    add(b.r, ")")
     putIntoDest(p, d, e.typ, b.r)
   else:
     assert(e.sons[1].typ != nil)
@@ -1478,7 +1520,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       initLocExpr(p, e.sons[2], b)
       if d.k == locNone: getTemp(p, getSysType(tyBool), d)
       lineF(p, cpsStmts, lookupOpr[op],
-           [rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b)])
+           [rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b)])
     of mEqSet:
       useStringh(p.module)
       binaryExprChar(p, e, d, "(memcmp($1, $2, " & $(size) & ")==0)")
@@ -1489,10 +1531,10 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       initLocExpr(p, e.sons[2], b)
       if d.k == locNone: getTemp(p, a.t, d)
       lineF(p, cpsStmts,
-           "for ($1 = 0; $1 < $2; $1++) $n" & 
+           "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])])
+          rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b),
+          rope(lookupOpr[op])])
     of mInSet: genInOp(p, e, d)
     else: internalError(e.info, "genSetOp")
 
@@ -1509,26 +1551,26 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
   initLocExpr(p, e.sons[1], a)
   let etyp = skipTypes(e.typ, abstractRange)
   if etyp.kind in ValueTypes and lfIndirect notin a.flags:
-    putIntoDest(p, d, e.typ, ropef("(*($1*) ($2))",
-        [getTypeDesc(p.module, e.typ), addrLoc(a)]))
+    putIntoDest(p, d, e.typ, "(*($1*) ($2))" %
+        [getTypeDesc(p.module, e.typ), addrLoc(a)])
   elif etyp.kind == tyProc and etyp.callConv == ccClosure:
-    putIntoDest(p, d, e.typ, ropef("(($1) ($2))",
-        [getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)]))
+    putIntoDest(p, d, e.typ, "(($1) ($2))" %
+        [getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)])
   else:
-    putIntoDest(p, d, e.typ, ropef("(($1) ($2))",
-        [getTypeDesc(p.module, e.typ), rdCharLoc(a)]))
+    putIntoDest(p, d, e.typ, "(($1) ($2))" %
+        [getTypeDesc(p.module, e.typ), rdCharLoc(a)])
 
 proc genCast(p: BProc, e: PNode, d: var TLoc) =
   const floatTypes = {tyFloat..tyFloat128}
-  let 
+  let
     destt = skipTypes(e.typ, abstractRange)
     srct = skipTypes(e.sons[1].typ, abstractRange)
   if destt.kind in floatTypes or srct.kind in floatTypes:
     # 'cast' and some float type involved? --> use a union.
     inc(p.labels)
-    var lbl = p.labels.toRope
+    var lbl = p.labels.rope
     var tmp: TLoc
-    tmp.r = ropef("LOC$1.source", lbl)
+    tmp.r = "LOC$1.source" % [lbl]
     linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n",
       getTypeDesc(p.module, srct), getTypeDesc(p.module, destt), lbl)
     tmp.k = locExpr
@@ -1536,7 +1578,7 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
     tmp.s = OnStack
     tmp.flags = {}
     expr(p, e.sons[1], tmp)
-    putIntoDest(p, d, e.typ, ropef("LOC$#.dest", lbl))
+    putIntoDest(p, d, e.typ, "LOC$#.dest" % [lbl])
   else:
     # I prefer the shorter cast version for pointer types -> generate less
     # C code; plus it's the right thing to do for closures:
@@ -1548,19 +1590,18 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc, magic: string) =
   # range checks for unsigned turned out to be buggy and annoying:
   if optRangeCheck notin p.options or dest.kind in {tyUInt..tyUInt64}:
     initLocExpr(p, n.sons[0], a)
-    putIntoDest(p, d, n.typ, ropef("(($1) ($2))",
-        [getTypeDesc(p.module, dest), rdCharLoc(a)]))
+    putIntoDest(p, d, n.typ, "(($1) ($2))" %
+        [getTypeDesc(p.module, dest), rdCharLoc(a)])
   else:
     initLocExpr(p, n.sons[0], a)
-    if leValue(n.sons[2], n.sons[1]):
-      internalError(n.info, "range check will always fail; empty range")
     putIntoDest(p, d, dest, ropecg(p.module, "(($1)#$5($2, $3, $4))", [
         getTypeDesc(p.module, dest), rdCharLoc(a),
         genLiteral(p, n.sons[1], dest), genLiteral(p, n.sons[2], dest),
-        toRope(magic)]))
+        rope(magic)]))
 
 proc genConv(p: BProc, e: PNode, d: var TLoc) =
-  if compareTypes(e.typ, e.sons[1].typ, dcEqIgnoreDistinct):
+  let destType = e.typ.skipTypes({tyVar, tyGenericInst})
+  if compareTypes(destType, e.sons[1].typ, dcEqIgnoreDistinct):
     expr(p, e.sons[1], d)
   else:
     genSomeCast(p, e, d)
@@ -1568,8 +1609,7 @@ proc genConv(p: BProc, e: PNode, d: var TLoc) =
 proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) =
   var a: TLoc
   initLocExpr(p, n.sons[0], a)
-  putIntoDest(p, d, skipTypes(n.typ, abstractVar), ropef("$1->data",
-      [rdLoc(a)]))
+  putIntoDest(p, d, skipTypes(n.typ, abstractVar), "$1->data" % [rdLoc(a)])
 
 proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
   var a: TLoc
@@ -1604,7 +1644,7 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
     initLocExpr(p, e.sons[1], a)
     initLocExpr(p, e.sons[2], b)
     putIntoDest(p, d, e.typ, rfmt(nil, "(($4)($2) $1 ($4)($3))",
-                                  toRope(opr[m]), rdLoc(a), rdLoc(b),
+                                  rope(opr[m]), rdLoc(a), rdLoc(b),
                                   getSimpleTypeDesc(p.module, e[1].typ)))
     if optNaNCheck in p.options:
       linefmt(p, cpsStmts, "#nanCheck($1);$n", rdLoc(d))
@@ -1614,7 +1654,7 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
     binaryArith(p, e, d, m)
 
 proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
-  var line, filen: PRope
+  var line, filen: Rope
   case op
   of mOr, mAnd: genAndOr(p, e, d, op)
   of mNot..mToBiggestInt: unaryArith(p, e, d, op)
@@ -1622,35 +1662,35 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mAddF64..mDivF64: binaryFloatArith(p, e, d, op)
   of mShrI..mXor: binaryArith(p, e, d, op)
   of mEqProc: genEqProc(p, e, d)
-  of mAddI..mModI64: binaryArithOverflow(p, e, d, op)
+  of mAddI..mPred: binaryArithOverflow(p, e, d, op)
   of mRepr: genRepr(p, e, d)
   of mGetTypeInfo: genGetTypeInfo(p, e, d)
   of mSwap: genSwap(p, e, d)
-  of mUnaryLt: 
+  of mUnaryLt:
     if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)")
     else: unaryExpr(p, e, d, "#subInt($1, 1)")
-  of mPred:
-    # XXX: range checking?
-    if optOverflowCheck notin p.options: binaryExpr(p, e, d, "($1 - $2)")
-    else: binaryExpr(p, e, d, "#subInt($1, $2)")
-  of mSucc:
-    # XXX: range checking?
-    if optOverflowCheck notin p.options: binaryExpr(p, e, d, "($1 + $2)")
-    else: binaryExpr(p, e, d, "#addInt($1, $2)")
-  of mInc:
-    if optOverflowCheck notin p.options:
-      binaryStmt(p, e, d, "$1 += $2;$n")
-    elif skipTypes(e.sons[1].typ, abstractVar).kind == tyInt64:
-      binaryStmt(p, e, d, "$1 = #addInt64($1, $2);$n")
-    else:
-      binaryStmt(p, e, d, "$1 = #addInt($1, $2);$n")
-  of ast.mDec:
-    if optOverflowCheck notin p.options:
-      binaryStmt(p, e, d, "$1 -= $2;$n")
-    elif skipTypes(e.sons[1].typ, abstractVar).kind == tyInt64:
-      binaryStmt(p, e, d, "$1 = #subInt64($1, $2);$n")
+  of mInc, mDec:
+    const opr: array [mInc..mDec, string] = ["$1 += $2;$n", "$1 -= $2;$n"]
+    const fun64: array [mInc..mDec, string] = ["$# = #addInt64($#, $#);$n",
+                                               "$# = #subInt64($#, $#);$n"]
+    const fun: array [mInc..mDec, string] = ["$# = #addInt($#, $#);$n",
+                                             "$# = #subInt($#, $#);$n"]
+    let underlying = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar, tyRange})
+    if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}:
+      binaryStmt(p, e, d, opr[op])
     else:
-      binaryStmt(p, e, d, "$1 = #subInt($1, $2);$n")
+      var a, b: TLoc
+      assert(e.sons[1].typ != nil)
+      assert(e.sons[2].typ != nil)
+      initLocExpr(p, e.sons[1], a)
+      initLocExpr(p, e.sons[2], b)
+
+      let ranged = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar})
+      let res = binaryArithOverflowRaw(p, ranged, a, b,
+        if underlying.kind == tyInt64: fun64[op] else: fun[op])
+      putIntoDest(p, a, ranged, "($#)($#)" % [
+        getTypeDesc(p.module, ranged), res])
+
   of mConStrStr: genStrConcat(p, e, d)
   of mAppendStrCh:
     binaryStmt(p, e, d, "$1 = #addChar($1, $2);$n")
@@ -1676,12 +1716,16 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mNewSeq: genNewSeq(p, e)
   of mSizeOf:
     let t = e.sons[1].typ.skipTypes({tyTypeDesc})
-    putIntoDest(p, d, e.typ, ropef("((NI)sizeof($1))",
-                                   [getTypeDesc(p.module, t)]))
+    putIntoDest(p, d, e.typ, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)])
   of mChr: genSomeCast(p, e, d)
   of mOrd: genOrd(p, e, d)
   of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray:
     genArrayLen(p, e, d, op)
+  of mXLenStr, mXLenSeq:
+    if not p.module.compileToCpp:
+      unaryExpr(p, e, d, "($1->Sup.len-1)")
+    else:
+      unaryExpr(p, e, d, "$1->len")
   of mGCref: unaryStmt(p, e, d, "#nimGCref($1);$n")
   of mGCunref: unaryStmt(p, e, d, "#nimGCunref($1);$n")
   of mSetLengthStr: genSetLengthStr(p, e, d)
@@ -1693,14 +1737,12 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       mParseBiggestFloat:
     var opr = e.sons[0].sym
     if lfNoDecl notin opr.loc.flags:
-      discard cgsym(p.module, opr.loc.r.ropeToStr)
+      discard cgsym(p.module, $opr.loc.r)
     genCall(p, e, d)
   of mReset: genReset(p, e)
   of mEcho: genEcho(p, e[1].skipConv)
   of mArrToSeq: genArrToSeq(p, e, d)
-  of mNLen..mNError:
-    localError(e.info, errCannotGenerateCodeForX, e.sons[0].sym.name.s)
-  of mSlurp..mQuoteAst:
+  of mNLen..mNError, mSlurp..mQuoteAst:
     localError(e.info, errXMustBeCompileTime, e.sons[0].sym.name.s)
   of mSpawn:
     let n = lowerings.wrapProcForSpawn(p.module.module, e, e.typ, nil, nil)
@@ -1714,19 +1756,20 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     initLocExpr(p, x, a)
     initLocExpr(p, e.sons[2], b)
     genDeepCopy(p, a, b)
+  of mDotDot: genCall(p, e, d)
   else: internalError(e.info, "genMagicExpr: " & $op)
 
-proc genConstExpr(p: BProc, n: PNode): PRope
+proc genConstExpr(p: BProc, n: PNode): Rope
 proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
   if nfAllConst in n.flags and d.k == locNone and n.len > 0 and n.isDeepConstExpr:
     var t = getUniqueType(n.typ)
     discard getTypeDesc(p.module, t) # so that any fields are initialized
     var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
-    fillLoc(d, locData, t, con("TMP", toRope(id)), OnHeap)
+    fillLoc(d, locData, t, "TMP" & rope(id), OnHeap)
     if id == gBackendId:
       # expression not found in the cache:
       inc(gBackendId)
-      appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
+      addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
            [getTypeDesc(p.module, t), d.r, genConstExpr(p, n)])
     result = true
   else:
@@ -1788,26 +1831,25 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
       var it = n.sons[i]
       if it.kind == nkExprColonExpr: it = it.sons[1]
       initLoc(rec, locExpr, it.typ, d.s)
-      rec.r = ropef("$1.Field$2", [rdLoc(d), toRope(i)])
+      rec.r = "$1.Field$2" % [rdLoc(d), rope(i)]
       expr(p, it, rec)
       when false:
         initLoc(rec, locExpr, it.typ, d.s)
         if (t.n.sons[i].kind != nkSym): InternalError(n.info, "genTupleConstr")
-        rec.r = ropef("$1.$2",
-                      [rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)])
+        rec.r = "$1.$2" % [rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)]
         expr(p, it, rec)
 
 proc isConstClosure(n: PNode): bool {.inline.} =
   result = n.sons[0].kind == nkSym and isRoutine(n.sons[0].sym) and
       n.sons[1].kind == nkNilLit
-      
+
 proc genClosure(p: BProc, n: PNode, d: var TLoc) =
   assert n.kind == nkClosure
-  
+
   if isConstClosure(n):
     inc(p.labels)
-    var tmp = con("LOC", toRope(p.labels))
-    appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
+    var tmp = "LOC" & rope(p.labels)
+    addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
         [getTypeDesc(p.module, n.typ), tmp, genConstExpr(p, n)])
     putIntoDest(p, d, n.typ, tmp)
   else:
@@ -1825,7 +1867,7 @@ proc genArrayConstr(p: BProc, n: PNode, d: var TLoc) =
     if d.k == locNone: getTemp(p, n.typ, d)
     for i in countup(0, sonsLen(n) - 1):
       initLoc(arr, locExpr, elemType(skipTypes(n.typ, abstractInst)), d.s)
-      arr.r = ropef("$1[$2]", [rdLoc(d), intLiteral(i)])
+      arr.r = "$1[$2]" % [rdLoc(d), intLiteral(i)]
       expr(p, n.sons[i], arr)
 
 proc genComplexConst(p: BProc, sym: PSym, d: var TLoc) =
@@ -1844,15 +1886,16 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
   var dest = skipTypes(n.typ, abstractPtrs)
   if optObjCheck in p.options and not isObjLackingTypeField(dest):
     var r = rdLoc(a)
-    var nilCheck: PRope = nil
+    var nilCheck: Rope = nil
     var t = skipTypes(a.t, abstractInst)
     while t.kind in {tyVar, tyPtr, tyRef}:
       if t.kind != tyVar: nilCheck = r
-      r = ropef("(*$1)", [r])
+      if t.kind != tyVar or not p.module.compileToCpp:
+        r = "(*$1)" % [r]
       t = skipTypes(t.lastSon, abstractInst)
     if not p.module.compileToCpp:
       while t.kind == tyObject and t.sons[0] != nil:
-        app(r, ".Sup")
+        add(r, ".Sup")
         t = skipTypes(t.sons[0], abstractInst)
     if nilCheck != nil:
       linefmt(p, cpsStmts, "if ($1) #chckObj($2.m_type, $3);$n",
@@ -1862,10 +1905,10 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
               r, genTypeInfo(p.module, dest))
   if n.sons[0].typ.kind != tyObject:
     putIntoDest(p, d, n.typ,
-                ropef("(($1) ($2))", [getTypeDesc(p.module, n.typ), rdLoc(a)]))
+                "(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)])
   else:
-    putIntoDest(p, d, n.typ, ropef("(*($1*) ($2))",
-                                   [getTypeDesc(p.module, dest), addrLoc(a)]))
+    putIntoDest(p, d, n.typ, "(*($1*) ($2))" %
+                             [getTypeDesc(p.module, dest), addrLoc(a)])
 
 proc downConv(p: BProc, n: PNode, d: var TLoc) =
   if p.module.compileToCpp:
@@ -1882,21 +1925,21 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
     var r = rdLoc(a)
     let isRef = skipTypes(arg.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}
     if isRef:
-      app(r, "->Sup")
+      add(r, "->Sup")
     else:
-      app(r, ".Sup")
-    for i in countup(2, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
+      add(r, ".Sup")
+    for i in countup(2, abs(inheritanceDiff(dest, src))): add(r, ".Sup")
     if isRef:
       # it can happen that we end up generating '&&x->Sup' here, so we pack
       # the '&x->Sup' into a temporary and then those address is taken
-      # (see bug #837). However sometimes using a temporary is not correct: 
+      # (see bug #837). However sometimes using a temporary is not correct:
       # init(TFigure(my)) # where it is passed to a 'var TFigure'. We test
       # this by ensuring the destination is also a pointer:
       if d.k == locNone and skipTypes(n.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}:
         getTemp(p, n.typ, d)
         linefmt(p, cpsStmts, "$1 = &$2;$n", rdLoc(d), r)
       else:
-        r = con("&", r)
+        r = "&" & r
         putIntoDest(p, d, n.typ, r)
     else:
       putIntoDest(p, d, n.typ, r)
@@ -1905,14 +1948,14 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
   var t = getUniqueType(n.typ)
   discard getTypeDesc(p.module, t) # so that any fields are initialized
   var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
-  var tmp = con("TMP", toRope(id))
-  
+  var tmp = "TMP" & rope(id)
+
   if id == gBackendId:
     # expression not found in the cache:
     inc(gBackendId)
-    appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
+    addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
          [getTypeDesc(p.module, t), tmp, genConstExpr(p, n)])
-  
+
   if d.k == locNone:
     fillLoc(d, locData, t, tmp, OnHeap)
   else:
@@ -1924,7 +1967,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
     var sym = n.sym
     case sym.kind
     of skMethod:
-      if sym.getBody.kind == nkEmpty or sfDispatcher in sym.flags:
+      if {sfDispatcher, sfForward} * sym.flags != {}:
         # we cannot produce code for the dispatcher yet:
         fillProcLoc(sym)
         genProcPrototype(p.module, sym)
@@ -1945,7 +1988,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
       else:
         genComplexConst(p, sym, d)
     of skEnumField:
-      putIntoDest(p, d, n.typ, toRope(sym.position))
+      putIntoDest(p, d, n.typ, rope(sym.position))
     of skVar, skForVar, skResult, skLet:
       if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
       if sym.loc.r == nil or sym.loc.t == nil:
@@ -1953,8 +1996,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
         internalError n.info, "expr: var not init " & sym.name.s & "_" & $sym.id
       if sfThread in sym.flags:
         accessThreadLocalVar(p, sym)
-        if emulatedThreadVars(): 
-          putIntoDest(p, d, sym.loc.t, con("NimTV->", sym.loc.r))
+        if emulatedThreadVars():
+          putIntoDest(p, d, sym.loc.t, "NimTV->" & sym.loc.r)
         else:
           putLocIntoDest(p, d, sym.loc)
       else:
@@ -1968,6 +2011,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
     of skParam:
       if sym.loc.r == nil or sym.loc.t == nil:
         #echo "FAILED FOR PRCO ", p.prc.name.s
+        #debug p.prc.typ.n
+        #echo renderTree(p.prc.ast, {renderIds})
         internalError(n.info, "expr: param not init " & sym.name.s & "_" & $sym.id)
       putLocIntoDest(p, d, sym.loc)
     else: internalError(n.info, "expr(" & $sym.kind & "); unknown symbol")
@@ -2056,8 +2101,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
     genAsgn(p, n, fastAsgn=p.prc != nil)
   of nkDiscardStmt:
     if n.sons[0].kind != nkEmpty:
-      var a: TLoc
       genLineDir(p, n)
+      var a: TLoc
       initLocExpr(p, n.sons[0], a)
   of nkAsmStmt: genAsmStmt(p, n)
   of nkTryStmt:
@@ -2068,14 +2113,14 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
     # we have to emit the type information for object types here to support
     # separate compilation:
     genTypeSection(p.module, n)
-  of nkCommentStmt, nkIteratorDef, nkIncludeStmt, 
-     nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, 
-     nkFromStmt, nkTemplateDef, nkMacroDef: 
+  of nkCommentStmt, nkIteratorDef, nkIncludeStmt,
+     nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
+     nkFromStmt, nkTemplateDef, nkMacroDef:
     discard
   of nkPragma: genPragma(p, n)
   of nkPragmaBlock: expr(p, n.lastSon, d)
-  of nkProcDef, nkMethodDef, nkConverterDef: 
-    if (n.sons[genericParamsPos].kind == nkEmpty):
+  of nkProcDef, nkMethodDef, nkConverterDef:
+    if n.sons[genericParamsPos].kind == nkEmpty:
       var prc = n.sons[namePos].sym
       # due to a bug/limitation in the lambda lifting, unused inner procs
       # are not transformed correctly. We work around this issue (#411) here
@@ -2085,9 +2130,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
             sfDeadCodeElim notin getModule(prc).flags) or
             ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
             (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
-            (prc.kind == skMethod): 
-          # we have not only the header: 
-          if prc.getBody.kind != nkEmpty or lfDynamicLib in prc.loc.flags: 
+            (prc.kind == skMethod):
+          # we have not only the header:
+          if prc.getBody.kind != nkEmpty or lfDynamicLib in prc.loc.flags:
             genProc(p.module, prc)
   of nkParForStmt: genParForStmt(p, n)
   of nkState: genState(p, n)
@@ -2095,42 +2140,42 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
   of nkBreakState: genBreakState(p, n)
   else: internalError(n.info, "expr(" & $n.kind & "); unknown node kind")
 
-proc genNamedConstExpr(p: BProc, n: PNode): PRope =
+proc genNamedConstExpr(p: BProc, n: PNode): Rope =
   if n.kind == nkExprColonExpr: result = genConstExpr(p, n.sons[1])
   else: result = genConstExpr(p, n)
 
-proc genConstSimpleList(p: BProc, n: PNode): PRope =
+proc genConstSimpleList(p: BProc, n: PNode): Rope =
   var length = sonsLen(n)
-  result = toRope("{")
+  result = rope("{")
   for i in countup(0, length - 2):
-    appf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])])
-  if length > 0: app(result, genNamedConstExpr(p, n.sons[length - 1]))
-  appf(result, "}$n")
+    addf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])])
+  if length > 0: add(result, genNamedConstExpr(p, n.sons[length - 1]))
+  addf(result, "}$n", [])
 
-proc genConstSeq(p: BProc, n: PNode, t: PType): PRope =
-  var data = ropef("{{$1, $1}", n.len.toRope)
-  if n.len > 0: 
+proc genConstSeq(p: BProc, n: PNode, t: PType): Rope =
+  var data = "{{$1, $1}" % [n.len.rope]
+  if n.len > 0:
     # array part needs extra curlies:
-    data.app(", {")
+    data.add(", {")
     for i in countup(0, n.len - 1):
-      if i > 0: data.appf(",$n")
-      data.app genConstExpr(p, n.sons[i])
-    data.app("}")
-  data.app("}")
-  
+      if i > 0: data.addf(",$n", [])
+      data.add genConstExpr(p, n.sons[i])
+    data.add("}")
+  data.add("}")
+
   inc(gBackendId)
-  result = con("CNSTSEQ", gBackendId.toRope)
-  
+  result = "CNSTSEQ" & gBackendId.rope
+
   appcg(p.module, cfsData,
-        "NIM_CONST struct {$n" & 
+        "NIM_CONST struct {$n" &
         "  #TGenericSeq Sup;$n" &
-        "  $1 data[$2];$n" & 
+        "  $1 data[$2];$n" &
         "} $3 = $4;$n", [
-        getTypeDesc(p.module, t.sons[0]), n.len.toRope, result, data])
+        getTypeDesc(p.module, t.sons[0]), n.len.rope, result, data])
 
-  result = ropef("(($1)&$2)", [getTypeDesc(p.module, t), result])
+  result = "(($1)&$2)" % [getTypeDesc(p.module, t), result]
 
-proc genConstExpr(p: BProc, n: PNode): PRope =
+proc genConstExpr(p: BProc, n: PNode): Rope =
   case n.kind
   of nkHiddenStdConv, nkHiddenSubConv:
     result = genConstExpr(p, n.sons[1])
@@ -2138,7 +2183,7 @@ proc genConstExpr(p: BProc, n: PNode): PRope =
     var cs: TBitSet
     toBitSet(n, cs)
     result = genRawSetData(cs, int(getSize(n.typ)))
-  of nkBracket, nkPar, nkClosure:
+  of nkBracket, nkPar, nkClosure, nkObjConstr:
     var t = skipTypes(n.typ, abstractInst)
     if t.kind == tySequence:
       result = genConstSeq(p, n, t)
diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim
index 36da68d23..2a37257b6 100644
--- a/compiler/ccgmerge.nim
+++ b/compiler/ccgmerge.nim
@@ -45,29 +45,29 @@ const
   ]
   NimMergeEndMark = "/*\tNIM_merge_END:*/"
 
-proc genSectionStart*(fs: TCFileSection): PRope =
+proc genSectionStart*(fs: TCFileSection): Rope =
   if compilationCachePresent:
-    result = toRope(tnl)
-    app(result, "/*\t")
-    app(result, CFileSectionNames[fs])
-    app(result, ":*/")
-    app(result, tnl)
+    result = rope(tnl)
+    add(result, "/*\t")
+    add(result, CFileSectionNames[fs])
+    add(result, ":*/")
+    add(result, tnl)
 
-proc genSectionEnd*(fs: TCFileSection): PRope =
+proc genSectionEnd*(fs: TCFileSection): Rope =
   if compilationCachePresent:
-    result = toRope(NimMergeEndMark & tnl)
+    result = rope(NimMergeEndMark & tnl)
 
-proc genSectionStart*(ps: TCProcSection): PRope =
+proc genSectionStart*(ps: TCProcSection): Rope =
   if compilationCachePresent:
-    result = toRope(tnl)
-    app(result, "/*\t")
-    app(result, CProcSectionNames[ps])
-    app(result, ":*/")
-    app(result, tnl)
+    result = rope(tnl)
+    add(result, "/*\t")
+    add(result, CProcSectionNames[ps])
+    add(result, ":*/")
+    add(result, tnl)
 
-proc genSectionEnd*(ps: TCProcSection): PRope =
+proc genSectionEnd*(ps: TCProcSection): Rope =
   if compilationCachePresent:
-    result = toRope(NimMergeEndMark & tnl)
+    result = rope(NimMergeEndMark & tnl)
 
 proc writeTypeCache(a: TIdTable, s: var string) =
   var i = 0
@@ -79,7 +79,7 @@ proc writeTypeCache(a: TIdTable, s: var string) =
       s.add(' ')
     encodeVInt(id, s)
     s.add(':')
-    encodeStr(PRope(value).ropeToStr, s)
+    encodeStr($Rope(value), s)
     inc i
   s.add('}')
 
@@ -94,8 +94,8 @@ proc writeIntSet(a: IntSet, s: var string) =
     encodeVInt(x, s)
     inc i
   s.add('}')
-  
-proc genMergeInfo*(m: BModule): PRope =
+
+proc genMergeInfo*(m: BModule): Rope =
   if optSymbolFiles notin gGlobalOptions: return nil
   var s = "/*\tNIM_merge_INFO:"
   s.add(tnl)
@@ -111,9 +111,9 @@ proc genMergeInfo*(m: BModule): PRope =
   encodeVInt(ord(m.frameDeclared), s)
   s.add(tnl)
   s.add("*/")
-  result = s.toRope
+  result = s.rope
 
-template `^`(pos: expr): expr = L.buf[pos]
+template `^`(pos: int): expr = L.buf[pos]
 
 proc skipWhite(L: var TBaseLexer) =
   var pos = L.bufpos
@@ -132,7 +132,7 @@ proc skipUntilCmd(L: var TBaseLexer) =
     of CR: pos = nimlexbase.handleCR(L, pos)
     of LF: pos = nimlexbase.handleLF(L, pos)
     of '\0': break
-    of '/': 
+    of '/':
       if ^(pos+1) == '*' and ^(pos+2) == '\t':
         inc pos, 3
         break
@@ -145,7 +145,7 @@ proc atEndMark(buf: cstring, pos: int): bool =
   while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s
   result = s == NimMergeEndMark.len
 
-proc readVerbatimSection(L: var TBaseLexer): PRope = 
+proc readVerbatimSection(L: var TBaseLexer): Rope =
   var pos = L.bufpos
   var buf = L.buf
   var r = newStringOfCap(30_000)
@@ -162,14 +162,14 @@ proc readVerbatimSection(L: var TBaseLexer): PRope =
     of '\0':
       internalError("ccgmerge: expected: " & NimMergeEndMark)
       break
-    else: 
+    else:
       if atEndMark(buf, pos):
         inc pos, NimMergeEndMark.len
         break
       r.add(buf[pos])
       inc pos
   L.bufpos = pos
-  result = r.toRope
+  result = r.rope
 
 proc readKey(L: var TBaseLexer, result: var string) =
   var pos = L.bufpos
@@ -181,7 +181,7 @@ proc readKey(L: var TBaseLexer, result: var string) =
   if buf[pos] != ':': internalError("ccgmerge: ':' expected")
   L.bufpos = pos + 1 # skip ':'
 
-proc newFakeType(id: int): PType = 
+proc newFakeType(id: int): PType =
   new(result)
   result.id = id
 
@@ -197,7 +197,7 @@ proc readTypeCache(L: var TBaseLexer, result: var TIdTable) =
     # XXX little hack: we create a "fake" type object with the correct Id
     # better would be to adapt the data structure to not even store the
     # object as key, but only the Id
-    idTablePut(result, newFakeType(key), value.toRope)
+    idTablePut(result, newFakeType(key), value.rope)
   inc L.bufpos
 
 proc readIntSet(L: var TBaseLexer, result: var IntSet) =
@@ -223,12 +223,12 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) =
     of "typeInfo":  readIntSet(L, m.typeInfoMarker)
     of "labels":    m.labels = decodeVInt(L.buf, L.bufpos)
     of "hasframe":  m.frameDeclared = decodeVInt(L.buf, L.bufpos) != 0
-    else: internalError("ccgmerge: unkown key: " & k)
+    else: internalError("ccgmerge: unknown key: " & k)
 
 when not defined(nimhygiene):
   {.pragma: inject.}
-  
-template withCFile(cfilename: string, body: stmt) {.immediate.} = 
+
+template withCFile(cfilename: string, body: stmt) {.immediate.} =
   var s = llStreamOpen(cfilename, fmRead)
   if s == nil: return
   var L {.inject.}: TBaseLexer
@@ -239,7 +239,7 @@ template withCFile(cfilename: string, body: stmt) {.immediate.} =
     if ^L.bufpos == '\0': break
     body
   closeBaseLexer(L)
-  
+
 proc readMergeInfo*(cfilename: string, m: BModule) =
   ## reads the merge meta information into `m`.
   withCFile(cfilename):
@@ -257,7 +257,7 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) =
   ## reads the merge sections into `m`.
   withCFile(cfilename):
     readKey(L, k)
-    if k == "NIM_merge_INFO":   
+    if k == "NIM_merge_INFO":
       discard
     elif ^L.bufpos == '*' and ^(L.bufpos+1) == '/':
       inc(L.bufpos, 2)
@@ -280,19 +280,19 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) =
 proc mergeRequired*(m: BModule): bool =
   for i in cfsHeaders..cfsProcs:
     if m.s[i] != nil:
-      #echo "not empty: ", i, " ", ropeToStr(m.s[i])
+      #echo "not empty: ", i, " ", m.s[i]
       return true
   for i in low(TCProcSection)..high(TCProcSection):
-    if m.initProc.s(i) != nil: 
-      #echo "not empty: ", i, " ", ropeToStr(m.initProc.s[i])
+    if m.initProc.s(i) != nil:
+      #echo "not empty: ", i, " ", m.initProc.s[i]
       return true
 
 proc mergeFiles*(cfilename: string, m: BModule) =
   ## merges the C file with the old version on hard disc.
   var old: TMergeSections
   readMergeSections(cfilename, old)
-  # do the merge; old section before new section:    
+  # do the merge; old section before new section:
   for i in low(TCFileSection)..high(TCFileSection):
-    m.s[i] = con(old.f[i], m.s[i])
+    m.s[i] = old.f[i] & m.s[i]
   for i in low(TCProcSection)..high(TCProcSection):
-    m.initProc.s(i) = con(old.p[i], m.initProc.s(i))
+    m.initProc.s(i) = old.p[i] & m.initProc.s(i)
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index e5848f558..b6572d960 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -33,7 +33,7 @@ proc isAssignedImmediately(n: PNode): bool {.inline.} =
     return false
   result = true
 
-proc genVarTuple(p: BProc, n: PNode) = 
+proc genVarTuple(p: BProc, n: PNode) =
   var tup, field: TLoc
   if n.kind != nkVarTuple: internalError(n.info, "genVarTuple")
   var L = sonsLen(n)
@@ -48,8 +48,8 @@ proc genVarTuple(p: BProc, n: PNode) =
     return
   genLineDir(p, n)
   initLocExpr(p, n.sons[L-1], tup)
-  var t = tup.t
-  for i in countup(0, L-3): 
+  var t = tup.t.getUniqueType
+  for i in countup(0, L-3):
     var v = n.sons[i].sym
     if sfCompileTime in v.flags: continue
     if sfGlobal in v.flags:
@@ -60,12 +60,11 @@ proc genVarTuple(p: BProc, n: PNode) =
       assignLocalVar(p, v)
       initLocalVar(p, v, immediateAsgn=isAssignedImmediately(n[L-1]))
     initLoc(field, locExpr, t.sons[i], tup.s)
-    if t.kind == tyTuple: 
-      field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
-    else: 
+    if t.kind == tyTuple:
+      field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
+    else:
       if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple")
-      field.r = ropef("$1.$2", 
-                      [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
+      field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)]
     putLocIntoDest(p, v.loc, field)
 
 proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false)
@@ -86,8 +85,8 @@ proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
   else:
     expr(p, ri, a)
 
-proc startBlock(p: BProc, start: TFormatStr = "{$n",
-                args: varargs[PRope]): int {.discardable.} =
+proc startBlock(p: BProc, start: FormatStr = "{$n",
+                args: varargs[Rope]): int {.discardable.} =
   lineCg(p, cpsStmts, start, args)
   inc(p.labels)
   result = len(p.blocks)
@@ -96,35 +95,35 @@ proc startBlock(p: BProc, start: TFormatStr = "{$n",
   p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16
   p.blocks[result].nestedExceptStmts = p.inExceptBlock.int16
 
-proc assignLabel(b: var TBlock): PRope {.inline.} =
-  b.label = con("LA", b.id.toRope)
+proc assignLabel(b: var TBlock): Rope {.inline.} =
+  b.label = "LA" & b.id.rope
   result = b.label
 
-proc blockBody(b: var TBlock): PRope =
+proc blockBody(b: var TBlock): Rope =
   result = b.sections[cpsLocals]
   if b.frameLen > 0:
-    result.appf("F.len+=$1;$n", b.frameLen.toRope)
-  result.app(b.sections[cpsInit])
-  result.app(b.sections[cpsStmts])
+    result.addf("F.len+=$1;$n", [b.frameLen.rope])
+  result.add(b.sections[cpsInit])
+  result.add(b.sections[cpsStmts])
 
-proc endBlock(p: BProc, blockEnd: PRope) =
+proc endBlock(p: BProc, blockEnd: Rope) =
   let topBlock = p.blocks.len-1
   # the block is merged into the parent block
-  app(p.blocks[topBlock-1].sections[cpsStmts], p.blocks[topBlock].blockBody)
+  add(p.blocks[topBlock-1].sections[cpsStmts], p.blocks[topBlock].blockBody)
   setLen(p.blocks, topBlock)
   # this is done after the block is popped so $n is
   # properly indented when pretty printing is enabled
   line(p, cpsStmts, blockEnd)
 
 proc endBlock(p: BProc) =
-  let topBlock = p.blocks.len - 1  
+  let topBlock = p.blocks.len - 1
   var blockEnd = if p.blocks[topBlock].label != nil:
       rfmt(nil, "} $1: ;$n", p.blocks[topBlock].label)
     else:
       ~"}$n"
   let frameLen = p.blocks[topBlock].frameLen
   if frameLen > 0:
-    blockEnd.appf("F.len-=$1;$n", frameLen.toRope)
+    blockEnd.addf("F.len-=$1;$n", [frameLen.rope])
   endBlock(p, blockEnd)
 
 proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} =
@@ -145,7 +144,7 @@ template preserveBreakIdx(body: stmt): stmt {.immediate.} =
 proc genState(p: BProc, n: PNode) =
   internalAssert n.len == 1 and n.sons[0].kind == nkIntLit
   let idx = n.sons[0].intVal
-  linefmt(p, cpsStmts, "STATE$1: ;$n", idx.toRope)
+  linefmt(p, cpsStmts, "STATE$1: ;$n", idx.rope)
 
 proc genGotoState(p: BProc, n: PNode) =
   # we resist the temptation to translate it into duff's device as it later
@@ -159,7 +158,7 @@ proc genGotoState(p: BProc, n: PNode) =
   p.beforeRetNeeded = true
   lineF(p, cpsStmts, "case -1: goto BeforeRet;$n", [])
   for i in 0 .. lastOrd(n.sons[0].typ):
-    lineF(p, cpsStmts, "case $1: goto STATE$1;$n", [toRope(i)])
+    lineF(p, cpsStmts, "case $1: goto STATE$1;$n", [rope(i)])
   lineF(p, cpsStmts, "}$n", [])
 
 proc genBreakState(p: BProc, n: PNode) =
@@ -176,9 +175,18 @@ proc genBreakState(p: BProc, n: PNode) =
 
 proc genVarPrototypeAux(m: BModule, sym: PSym)
 
+proc genGotoVar(p: BProc; value: PNode) =
+  if value.kind notin {nkCharLit..nkUInt64Lit}:
+    localError(value.info, "'goto' target must be a literal value")
+  else:
+    lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope])
+
 proc genSingleVar(p: BProc, a: PNode) =
   var v = a.sons[0].sym
-  if sfCompileTime in v.flags: return
+  if {sfCompileTime, sfGoto} * v.flags != {}:
+    # translate 'var state {.goto.} = X' into 'goto LX':
+    if sfGoto in v.flags: genGotoVar(p, a.sons[2])
+    return
   var targetProc = p
   if sfGlobal in v.flags:
     if v.flags * {sfImportc, sfExportc} == {sfImportc} and
@@ -190,10 +198,10 @@ proc genSingleVar(p: BProc, a: PNode) =
       targetProc = p.module.preInitProc
     assignGlobalVar(targetProc, v)
     # XXX: be careful here.
-    # Global variables should not be zeromem-ed within loops 
+    # Global variables should not be zeromem-ed within loops
     # (see bug #20).
     # That's why we are doing the construction inside the preInitProc.
-    # genObjectInit relies on the C runtime's guarantees that 
+    # genObjectInit relies on the C runtime's guarantees that
     # global variables will be initialized to zero.
     genObjectInit(p.module.preInitProc, cpsInit, v.typ, v.loc, true)
     # Alternative construction using default constructor (which may zeromem):
@@ -202,8 +210,32 @@ proc genSingleVar(p: BProc, a: PNode) =
       genVarPrototypeAux(generatedHeader, v)
     registerGcRoot(p, v)
   else:
+    let value = a.sons[2]
+    let imm = isAssignedImmediately(value)
+    if imm and p.module.compileToCpp and p.splitDecls == 0 and
+        not containsHiddenPointer(v.typ):
+      # C++ really doesn't like things like 'Foo f; f = x' as that invokes a
+      # parameterless constructor followed by an assignment operator. So we
+      # generate better code here:
+      genLineDir(p, a)
+      let decl = localVarDecl(p, v)
+      var tmp: TLoc
+      if value.kind in nkCallKinds and value[0].kind == nkSym and
+           sfConstructor in value[0].sym.flags:
+        var params: Rope
+        let typ = skipTypes(value.sons[0].typ, abstractInst)
+        assert(typ.kind == tyProc)
+        for i in 1.. <value.len:
+          if params != nil: params.add(~", ")
+          assert(sonsLen(typ) == sonsLen(typ.n))
+          add(params, genOtherArg(p, value, i, typ))
+        lineF(p, cpsStmts, "$#($#);$n", [decl, params])
+      else:
+        initLocExprSingleUse(p, value, tmp)
+        lineF(p, cpsStmts, "$# = $#;$n", [decl, tmp.rdLoc])
+      return
     assignLocalVar(p, v)
-    initLocalVar(p, v, isAssignedImmediately(a.sons[2]))
+    initLocalVar(p, v, imm)
 
   if a.sons[2].kind != nkEmpty:
     genLineDir(targetProc, a)
@@ -217,10 +249,10 @@ proc genClosureVar(p: BProc, a: PNode) =
     genLineDir(p, a)
     loadInto(p, a.sons[0], a.sons[2], v)
 
-proc genVarStmt(p: BProc, n: PNode) = 
-  for i in countup(0, sonsLen(n) - 1): 
+proc genVarStmt(p: BProc, n: PNode) =
+  for i in countup(0, sonsLen(n) - 1):
     var a = n.sons[i]
-    if a.kind == nkCommentStmt: continue 
+    if a.kind == nkCommentStmt: continue
     if a.kind == nkIdentDefs:
       # can be a lifted var nowadays ...
       if a.sons[0].kind == nkSym:
@@ -230,28 +262,19 @@ proc genVarStmt(p: BProc, n: PNode) =
     else:
       genVarTuple(p, a)
 
-proc genConstStmt(p: BProc, t: PNode) = 
-  for i in countup(0, sonsLen(t) - 1): 
+proc genConstStmt(p: BProc, t: PNode) =
+  for i in countup(0, sonsLen(t) - 1):
     var it = t.sons[i]
-    if it.kind == nkCommentStmt: continue 
+    if it.kind == nkCommentStmt: continue
     if it.kind != nkConstDef: internalError(t.info, "genConstStmt")
-    var c = it.sons[0].sym 
+    var c = it.sons[0].sym
     if c.typ.containsCompileTimeOnly: continue
     if sfFakeConst in c.flags:
       genSingleVar(p, it)
     elif c.typ.kind in ConstantDataTypes and lfNoDecl notin c.loc.flags and
         c.ast.len != 0:
       if not emitLazily(c): requestConstImpl(p, c)
-      when false:
-        # generate the data:
-        fillLoc(c.loc, locData, c.typ, mangleName(c), OnUnknown)
-        if sfImportc in c.flags: 
-          appf(p.module.s[cfsData], "extern NIM_CONST $1 $2;$n", 
-               [getTypeDesc(p.module, c.typ), c.loc.r])
-        else: 
-          appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n", 
-               [getTypeDesc(p.module, c.typ), c.loc.r, genConstExpr(p, c.ast)])
-    
+
 proc genIf(p: BProc, n: PNode, d: var TLoc) =
   #
   #  { if (!expr1) goto L1;
@@ -271,21 +294,26 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
     getTemp(p, n.typ, d)
   genLineDir(p, n)
   let lend = getLabel(p)
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     let it = n.sons[i]
-    if it.len == 2: 
+    if it.len == 2:
       when newScopeForIf: startBlock(p)
-      initLocExpr(p, it.sons[0], a)
+      initLocExprSingleUse(p, it.sons[0], a)
       lelse = getLabel(p)
       inc(p.labels)
-      lineFF(p, cpsStmts, "if (!$1) goto $2;$n",
-            "br i1 $1, label %LOC$3, label %$2$nLOC$3: $n",
-            [rdLoc(a), lelse, toRope(p.labels)])
+      lineF(p, cpsStmts, "if (!$1) goto $2;$n",
+            [rdLoc(a), lelse])
       when not newScopeForIf: startBlock(p)
-      expr(p, it.sons[1], d)
+      if p.module.compileToCpp:
+        # avoid "jump to label crosses initialization" error:
+        add(p.s(cpsStmts), "{")
+        expr(p, it.sons[1], d)
+        add(p.s(cpsStmts), "}")
+      else:
+        expr(p, it.sons[1], d)
       endBlock(p)
       if sonsLen(n) > 1:
-        lineFF(p, cpsStmts, "goto $1;$n", "br label %$1$n", [lend])
+        lineF(p, cpsStmts, "goto $1;$n", [lend])
       fixLabel(p, lelse)
     elif it.len == 1:
       startBlock(p)
@@ -295,13 +323,13 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
   if sonsLen(n) > 1: fixLabel(p, lend)
 
 
-proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) = 
+proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
   # Called by return and break stmts.
   # Deals with issues faced when jumping out of try/except/finally stmts,
 
   var stack: seq[PNode]
   newSeq(stack, 0)
-  
+
   var alreadyPoppedCnt = p.inExceptBlock
   for i in countup(1, howManyTrys):
     if not p.module.compileToCpp:
@@ -319,11 +347,11 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
     # Find finally-stmt for this try-stmt
     # and generate a copy of its sons
     var finallyStmt = lastSon(tryStmt)
-    if finallyStmt.kind == nkFinally: 
+    if finallyStmt.kind == nkFinally:
       genStmts(p, finallyStmt.sons[0])
 
   # push old elements again:
-  for i in countdown(howManyTrys-1, 0): 
+  for i in countdown(howManyTrys-1, 0):
     p.nestedTryStmts.add(stack[i])
 
   if not p.module.compileToCpp:
@@ -336,15 +364,28 @@ proc genReturnStmt(p: BProc, t: PNode) =
   p.beforeRetNeeded = true
   genLineDir(p, t)
   if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
-  blockLeaveActions(p, 
+  blockLeaveActions(p,
     howManyTrys    = p.nestedTryStmts.len,
     howManyExcepts = p.inExceptBlock)
   if (p.finallySafePoints.len > 0):
     # If we're in a finally block, and we came here by exception
     # consume it before we return.
     var safePoint = p.finallySafePoints[p.finallySafePoints.len-1]
-    linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint)    
-  lineFF(p, cpsStmts, "goto BeforeRet;$n", "br label %BeforeRet$n", [])
+    linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint)
+  lineF(p, cpsStmts, "goto BeforeRet;$n", [])
+
+proc genGotoForCase(p: BProc; caseStmt: PNode) =
+  for i in 1 .. <caseStmt.len:
+    startBlock(p)
+    let it = caseStmt.sons[i]
+    for j in 0 .. it.len-2:
+      if it.sons[j].kind == nkRange:
+        localError(it.info, "range notation not available for computed goto")
+        return
+      let val = getOrdValue(it.sons[j])
+      lineF(p, cpsStmts, "NIMSTATE_$#:$n", [val.rope])
+    genStmts(p, it.lastSon)
+    endBlock(p)
 
 proc genComputedGoto(p: BProc; n: PNode) =
   # first pass: Generate array of computed labels:
@@ -369,17 +410,17 @@ proc genComputedGoto(p: BProc; n: PNode) =
     localError(n.info, "no case statement found for computed goto"); return
   var id = p.labels+1
   inc p.labels, arraySize+1
-  let tmp = ropef("TMP$1", id.toRope)
-  var gotoArray = ropef("static void* $#[$#] = {", tmp, arraySize.toRope)
+  let tmp = "TMP$1" % [id.rope]
+  var gotoArray = "static void* $#[$#] = {" % [tmp, arraySize.rope]
   for i in 1..arraySize-1:
-    gotoArray.appf("&&TMP$#, ", (id+i).toRope)
-  gotoArray.appf("&&TMP$#};$n", (id+arraySize).toRope)
+    gotoArray.addf("&&TMP$#, ", [(id+i).rope])
+  gotoArray.addf("&&TMP$#};$n", [(id+arraySize).rope])
   line(p, cpsLocals, gotoArray)
 
   let topBlock = p.blocks.len-1
   let oldBody = p.blocks[topBlock].sections[cpsStmts]
   p.blocks[topBlock].sections[cpsStmts] = nil
-  
+
   for j in casePos+1 .. <n.len: genStmts(p, n.sons[j])
   let tailB = p.blocks[topBlock].sections[cpsStmts]
 
@@ -387,14 +428,14 @@ proc genComputedGoto(p: BProc; n: PNode) =
   for j in 0 .. casePos-1: genStmts(p, n.sons[j])
   let tailA = p.blocks[topBlock].sections[cpsStmts]
 
-  p.blocks[topBlock].sections[cpsStmts] = oldBody.con(tailA)
+  p.blocks[topBlock].sections[cpsStmts] = oldBody & tailA
 
   let caseStmt = n.sons[casePos]
   var a: TLoc
   initLocExpr(p, caseStmt.sons[0], a)
   # first goto:
-  lineF(p, cpsStmts, "goto *$#[$#];$n", tmp, a.rdLoc)
-  
+  lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
+
   for i in 1 .. <caseStmt.len:
     startBlock(p)
     let it = caseStmt.sons[i]
@@ -403,22 +444,22 @@ proc genComputedGoto(p: BProc; n: PNode) =
         localError(it.info, "range notation not available for computed goto")
         return
       let val = getOrdValue(it.sons[j])
-      lineF(p, cpsStmts, "TMP$#:$n", intLiteral(val+id+1))
+      lineF(p, cpsStmts, "TMP$#:$n", [intLiteral(val+id+1)])
     genStmts(p, it.lastSon)
     #for j in casePos+1 .. <n.len: genStmts(p, n.sons[j]) # tailB
     #for j in 0 .. casePos-1: genStmts(p, n.sons[j])  # tailA
-    app(p.s(cpsStmts), tailB)
-    app(p.s(cpsStmts), tailA)
+    add(p.s(cpsStmts), tailB)
+    add(p.s(cpsStmts), tailA)
 
     var a: TLoc
     initLocExpr(p, caseStmt.sons[0], a)
-    lineF(p, cpsStmts, "goto *$#[$#];$n", tmp, a.rdLoc)
+    lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
     endBlock(p)
 
 proc genWhileStmt(p: BProc, t: PNode) =
   # we don't generate labels here as for example GCC would produce
   # significantly worse code
-  var 
+  var
     a: TLoc
     labl: TLabel
   assert(sonsLen(t) == 2)
@@ -429,7 +470,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
     p.breakIdx = startBlock(p, "while (1) {$n")
     p.blocks[p.breakIdx].isLoop = true
     initLocExpr(p, t.sons[0], a)
-    if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0): 
+    if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
       let label = assignLabel(p.blocks[p.breakIdx])
       lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), label])
     var loopBody = t.sons[1]
@@ -475,23 +516,23 @@ proc genParForStmt(p: BProc, t: PNode) =
     let call = t.sons[1]
     initLocExpr(p, call.sons[1], rangeA)
     initLocExpr(p, call.sons[2], rangeB)
-    
+
     lineF(p, cpsStmts, "#pragma omp parallel for $4$n" &
-                        "for ($1 = $2; $1 <= $3; ++$1)", 
-                        forLoopVar.loc.rdLoc,
+                        "for ($1 = $2; $1 <= $3; ++$1)",
+                        [forLoopVar.loc.rdLoc,
                         rangeA.rdLoc, rangeB.rdLoc,
-                        call.sons[3].getStr.toRope)
-    
+                        call.sons[3].getStr.rope])
+
     p.breakIdx = startBlock(p)
     p.blocks[p.breakIdx].isLoop = true
     genStmts(p, t.sons[2])
     endBlock(p)
 
   dec(p.withinLoop)
-  
-proc genBreakStmt(p: BProc, t: PNode) = 
+
+proc genBreakStmt(p: BProc, t: PNode) =
   var idx = p.breakIdx
-  if t.sons[0].kind != nkEmpty: 
+  if t.sons[0].kind != nkEmpty:
     # named break?
     assert(t.sons[0].kind == nkSym)
     var sym = t.sons[0].sym
@@ -503,13 +544,13 @@ proc genBreakStmt(p: BProc, t: PNode) =
     if idx < 0 or not p.blocks[idx].isLoop:
       internalError(t.info, "no loop to break")
   let label = assignLabel(p.blocks[idx])
-  blockLeaveActions(p, 
+  blockLeaveActions(p,
     p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts,
     p.inExceptBlock - p.blocks[idx].nestedExceptStmts)
   genLineDir(p, t)
   lineF(p, cpsStmts, "goto $1;$n", [label])
 
-proc getRaiseFrmt(p: BProc): string = 
+proc getRaiseFrmt(p: BProc): string =
   if p.module.compileToCpp:
     result = "throw NimException($1, $2);$n"
   elif getCompilerProc("Exception") != nil:
@@ -524,7 +565,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
     var finallyBlock = p.nestedTryStmts[p.nestedTryStmts.len - 1].lastSon
     if finallyBlock.kind == nkFinally:
       genSimpleBlock(p, finallyBlock.sons[0])
-  if t.sons[0].kind != nkEmpty: 
+  if t.sons[0].kind != nkEmpty:
     var a: TLoc
     initLocExpr(p, t.sons[0], a)
     var e = rdLoc(a)
@@ -539,26 +580,26 @@ proc genRaiseStmt(p: BProc, t: PNode) =
     else:
       linefmt(p, cpsStmts, "#reraiseException();$n")
 
-proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, 
-                          rangeFormat, eqFormat: TFormatStr, labl: TLabel) = 
-  var 
+proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
+                          rangeFormat, eqFormat: FormatStr, labl: TLabel) =
+  var
     x, y: TLoc
   var length = sonsLen(b)
-  for i in countup(0, length - 2): 
-    if b.sons[i].kind == nkRange: 
+  for i in countup(0, length - 2):
+    if b.sons[i].kind == nkRange:
       initLocExpr(p, b.sons[i].sons[0], x)
       initLocExpr(p, b.sons[i].sons[1], y)
-      lineCg(p, cpsStmts, rangeFormat, 
+      lineCg(p, cpsStmts, rangeFormat,
            [rdCharLoc(e), rdCharLoc(x), rdCharLoc(y), labl])
-    else: 
+    else:
       initLocExpr(p, b.sons[i], x)
       lineCg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl])
 
-proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc, 
-                       labId, until: int): TLabel = 
+proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
+                       labId, until: int): TLabel =
   var lend = getLabel(p)
   for i in 1..until:
-    lineF(p, cpsStmts, "LA$1: ;$n", [toRope(labId + i)])
+    lineF(p, cpsStmts, "LA$1: ;$n", [rope(labId + i)])
     if t.sons[i].kind == nkOfBranch:
       var length = sonsLen(t.sons[i])
       exprBlock(p, t.sons[i].sons[length - 1], d)
@@ -568,7 +609,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
   result = lend
 
 proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
-                       rangeFormat, eqFormat: TFormatStr,
+                       rangeFormat, eqFormat: FormatStr,
                        until: int, a: TLoc): TLabel =
   # generate a C-if statement for a Nim case statement
   var labId = p.labels
@@ -576,35 +617,35 @@ proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
     inc(p.labels)
     if t.sons[i].kind == nkOfBranch: # else statement
       genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat,
-                           con("LA", toRope(p.labels)))
+                           "LA" & rope(p.labels))
     else:
-      lineF(p, cpsStmts, "goto LA$1;$n", [toRope(p.labels)])
+      lineF(p, cpsStmts, "goto LA$1;$n", [rope(p.labels)])
   if until < t.len-1:
     inc(p.labels)
     var gotoTarget = p.labels
-    lineF(p, cpsStmts, "goto LA$1;$n", [toRope(gotoTarget)])
+    lineF(p, cpsStmts, "goto LA$1;$n", [rope(gotoTarget)])
     result = genCaseSecondPass(p, t, d, labId, until)
-    lineF(p, cpsStmts, "LA$1: ;$n", [toRope(gotoTarget)])
+    lineF(p, cpsStmts, "LA$1: ;$n", [rope(gotoTarget)])
   else:
     result = genCaseSecondPass(p, t, d, labId, until)
 
-proc genCaseGeneric(p: BProc, t: PNode, d: var TLoc, 
-                    rangeFormat, eqFormat: TFormatStr) = 
+proc genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
+                    rangeFormat, eqFormat: FormatStr) =
   var a: TLoc
   initLocExpr(p, t.sons[0], a)
   var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, sonsLen(t)-1, a)
   fixLabel(p, lend)
 
-proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel, 
-                         branches: var openArray[PRope]) = 
+proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
+                         branches: var openArray[Rope]) =
   var x: TLoc
   var length = sonsLen(b)
-  for i in countup(0, length - 2): 
+  for i in countup(0, length - 2):
     assert(b.sons[i].kind != nkRange)
     initLocExpr(p, b.sons[i], x)
     assert(b.sons[i].kind in {nkStrLit..nkTripleStrLit})
     var j = int(hashString(b.sons[i].strVal) and high(branches))
-    appcg(p.module, branches[j], "if (#eqStrings($1, $2)) goto $3;$n", 
+    appcg(p.module, branches[j], "if (#eqStrings($1, $2)) goto $3;$n",
          [rdLoc(e), rdLoc(x), labl])
 
 proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
@@ -614,40 +655,40 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
     if t.sons[i].kind == nkOfBranch: inc(strings, sonsLen(t.sons[i]) - 1)
   if strings > stringCaseThreshold:
     var bitMask = math.nextPowerOfTwo(strings) - 1
-    var branches: seq[PRope]
+    var branches: seq[Rope]
     newSeq(branches, bitMask + 1)
     var a: TLoc
     initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto:
     var labId = p.labels
-    for i in countup(1, sonsLen(t) - 1): 
+    for i in countup(1, sonsLen(t) - 1):
       inc(p.labels)
-      if t.sons[i].kind == nkOfBranch: 
-        genCaseStringBranch(p, t.sons[i], a, con("LA", toRope(p.labels)), 
+      if t.sons[i].kind == nkOfBranch:
+        genCaseStringBranch(p, t.sons[i], a, "LA" & rope(p.labels),
                             branches)
-      else: 
+      else:
         # else statement: nothing to do yet
         # but we reserved a label, which we use later
         discard
-    linefmt(p, cpsStmts, "switch (#hashString($1) & $2) {$n", 
-            rdLoc(a), toRope(bitMask))
+    linefmt(p, cpsStmts, "switch (#hashString($1) & $2) {$n",
+            rdLoc(a), rope(bitMask))
     for j in countup(0, high(branches)):
       if branches[j] != nil:
-        lineF(p, cpsStmts, "case $1: $n$2break;$n", 
+        lineF(p, cpsStmts, "case $1: $n$2break;$n",
              [intLiteral(j), branches[j]])
-    lineF(p, cpsStmts, "}$n") # else statement:
-    if t.sons[sonsLen(t)-1].kind != nkOfBranch: 
-      lineF(p, cpsStmts, "goto LA$1;$n", [toRope(p.labels)]) 
+    lineF(p, cpsStmts, "}$n", []) # else statement:
+    if t.sons[sonsLen(t)-1].kind != nkOfBranch:
+      lineF(p, cpsStmts, "goto LA$1;$n", [rope(p.labels)])
     # third pass: generate statements
     var lend = genCaseSecondPass(p, t, d, labId, sonsLen(t)-1)
     fixLabel(p, lend)
   else:
     genCaseGeneric(p, t, d, "", "if (#eqStrings($1, $2)) goto $3;$n")
-  
-proc branchHasTooBigRange(b: PNode): bool = 
-  for i in countup(0, sonsLen(b)-2): 
+
+proc branchHasTooBigRange(b: PNode): bool =
+  for i in countup(0, sonsLen(b)-2):
     # last son is block
     if (b.sons[i].kind == nkRange) and
-        b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit: 
+        b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit:
       return true
 
 proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
@@ -656,21 +697,21 @@ proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
     var stmtBlock = lastSon(branch)
     if stmtBlock.stmtsContainPragma(wLinearScanEnd):
       result = i
-    elif hasSwitchRange notin CC[cCompiler].props: 
-      if branch.kind == nkOfBranch and branchHasTooBigRange(branch): 
+    elif hasSwitchRange notin CC[cCompiler].props:
+      if branch.kind == nkOfBranch and branchHasTooBigRange(branch):
         result = i
 
 proc genCaseRange(p: BProc, branch: PNode) =
   var length = branch.len
-  for j in 0 .. length-2: 
-    if branch[j].kind == nkRange: 
-      if hasSwitchRange in CC[cCompiler].props: 
+  for j in 0 .. length-2:
+    if branch[j].kind == nkRange:
+      if hasSwitchRange in CC[cCompiler].props:
         lineF(p, cpsStmts, "case $1 ... $2:$n", [
-            genLiteral(p, branch[j][0]), 
+            genLiteral(p, branch[j][0]),
             genLiteral(p, branch[j][1])])
-      else: 
+      else:
         var v = copyNode(branch[j][0])
-        while v.intVal <= branch[j][1].intVal: 
+        while v.intVal <= branch[j][1].intVal:
           lineF(p, cpsStmts, "case $1:$n", [genLiteral(p, v)])
           inc(v.intVal)
     else:
@@ -679,53 +720,56 @@ proc genCaseRange(p: BProc, branch: PNode) =
 proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
   # analyse 'case' statement:
   var splitPoint = ifSwitchSplitPoint(p, n)
-  
+
   # generate if part (might be empty):
   var a: TLoc
   initLocExpr(p, n.sons[0], a)
   var lend = if splitPoint > 0: genIfForCaseUntil(p, n, d,
                     rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n",
-                    eqFormat = "if ($1 == $2) goto $3;$n", 
+                    eqFormat = "if ($1 == $2) goto $3;$n",
                     splitPoint, a) else: nil
-  
+
   # generate switch part (might be empty):
   if splitPoint+1 < n.len:
     lineF(p, cpsStmts, "switch ($1) {$n", [rdCharLoc(a)])
     var hasDefault = false
-    for i in splitPoint+1 .. < n.len: 
+    for i in splitPoint+1 .. < n.len:
       var branch = n[i]
-      if branch.kind == nkOfBranch: 
+      if branch.kind == nkOfBranch:
         genCaseRange(p, branch)
-      else: 
+      else:
         # else part of case statement:
-        lineF(p, cpsStmts, "default:$n")
+        lineF(p, cpsStmts, "default:$n", [])
         hasDefault = true
       exprBlock(p, branch.lastSon, d)
-      lineF(p, cpsStmts, "break;$n")
-    if (hasAssume in CC[cCompiler].props) and not hasDefault: 
-      lineF(p, cpsStmts, "default: __assume(0);$n")
-    lineF(p, cpsStmts, "}$n")
+      lineF(p, cpsStmts, "break;$n", [])
+    if (hasAssume in CC[cCompiler].props) and not hasDefault:
+      lineF(p, cpsStmts, "default: __assume(0);$n", [])
+    lineF(p, cpsStmts, "}$n", [])
   if lend != nil: fixLabel(p, lend)
-  
-proc genCase(p: BProc, t: PNode, d: var TLoc) = 
+
+proc genCase(p: BProc, t: PNode, d: var TLoc) =
   genLineDir(p, t)
   if not isEmptyType(t.typ) and d.k == locNone:
     getTemp(p, t.typ, d)
   case skipTypes(t.sons[0].typ, abstractVarRange).kind
   of tyString:
     genStringCase(p, t, d)
-  of tyFloat..tyFloat128: 
-    genCaseGeneric(p, t, d, "if ($1 >= $2 && $1 <= $3) goto $4;$n", 
+  of tyFloat..tyFloat128:
+    genCaseGeneric(p, t, d, "if ($1 >= $2 && $1 <= $3) goto $4;$n",
                             "if ($1 == $2) goto $3;$n")
   else:
-    genOrdinalCase(p, t, d)
-  
-proc hasGeneralExceptSection(t: PNode): bool = 
+    if t.sons[0].kind == nkSym and sfGoto in t.sons[0].sym.flags:
+      genGotoForCase(p, t)
+    else:
+      genOrdinalCase(p, t, d)
+
+proc hasGeneralExceptSection(t: PNode): bool =
   var length = sonsLen(t)
   var i = 1
-  while (i < length) and (t.sons[i].kind == nkExceptBranch): 
+  while (i < length) and (t.sons[i].kind == nkExceptBranch):
     var blen = sonsLen(t.sons[i])
-    if blen == 1: 
+    if blen == 1:
       return true
     inc(i)
   result = false
@@ -754,7 +798,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
   if not isEmptyType(t.typ) and d.k == locNone:
     getTemp(p, t.typ, d)
   var
-    exc: PRope
+    exc: Rope
     i, length, blen: int
   genLineDir(p, t)
   exc = getTempName()
@@ -774,42 +818,44 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
   var catchAllPresent = false
   while (i < length) and (t.sons[i].kind == nkExceptBranch):
     blen = sonsLen(t.sons[i])
-    if i > 1: appf(p.s(cpsStmts), "else ")
+    if i > 1: addf(p.s(cpsStmts), "else ", [])
     if blen == 1:
       # general except section:
       catchAllPresent = true
       exprBlock(p, t.sons[i].sons[0], d)
     else:
-      var orExpr: PRope = nil
+      var orExpr: Rope = nil
       for j in countup(0, blen - 2):
         assert(t.sons[i].sons[j].kind == nkType)
-        if orExpr != nil: app(orExpr, "||")
+        if orExpr != nil: add(orExpr, "||")
         appcg(p.module, orExpr,
               "#isObj($1.exp->m_type, $2)",
               [exc, genTypeInfo(p.module, t.sons[i].sons[j].typ)])
       lineF(p, cpsStmts, "if ($1) ", [orExpr])
       exprBlock(p, t.sons[i].sons[blen-1], d)
     inc(i)
-  
+
   # reraise the exception if there was no catch all
   # and none of the handlers matched
   if not catchAllPresent:
-    if i > 1: lineF(p, cpsStmts, "else ")
+    if i > 1: lineF(p, cpsStmts, "else ", [])
     startBlock(p)
     var finallyBlock = t.lastSon
     if finallyBlock.kind == nkFinally:
-      expr(p, finallyBlock.sons[0], d)
+      #expr(p, finallyBlock.sons[0], d)
+      genStmts(p, finallyBlock.sons[0])
+
     line(p, cpsStmts, ~"throw;$n")
     endBlock(p)
-  
-  lineF(p, cpsStmts, "}$n") # end of catch block
+
+  lineF(p, cpsStmts, "}$n", []) # end of catch block
   dec p.inExceptBlock
-  
+
   discard pop(p.nestedTryStmts)
   if (i < length) and (t.sons[i].kind == nkFinally):
-    exprBlock(p, t.sons[i].sons[0], d)
-  
-proc genTry(p: BProc, t: PNode, d: var TLoc) = 
+    genSimpleBlock(p, t.sons[i].sons[0])
+
+proc genTry(p: BProc, t: PNode, d: var TLoc) =
   # code to generate:
   #
   # XXX: There should be a standard dispatch algorithm
@@ -831,7 +877,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
   #      clearException();
   #    }
   #  }
-  #  { 
+  #  {
   #    /* finally: */
   #    printf('fin!\n');
   #  }
@@ -873,17 +919,17 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
     var blen = sonsLen(t.sons[i])
     if blen == 1:
       # general except section:
-      if i > 1: lineF(p, cpsStmts, "else")
+      if i > 1: lineF(p, cpsStmts, "else", [])
       startBlock(p)
       linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint)
       expr(p, t.sons[i].sons[0], d)
       linefmt(p, cpsStmts, "#popCurrentException();$n")
       endBlock(p)
     else:
-      var orExpr: PRope = nil
+      var orExpr: Rope = nil
       for j in countup(0, blen - 2):
         assert(t.sons[i].sons[j].kind == nkType)
-        if orExpr != nil: app(orExpr, "||")
+        if orExpr != nil: add(orExpr, "||")
         appcg(p.module, orExpr,
               "#isObj(#getCurrentException()->Sup.m_type, $1)",
               [genTypeInfo(p.module, t.sons[i].sons[j].typ)])
@@ -899,11 +945,11 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
   endBlock(p) # end of else block
   if i < length and t.sons[i].kind == nkFinally:
     p.finallySafePoints.add(safePoint)
-    exprBlock(p, t.sons[i].sons[0], d)
+    genSimpleBlock(p, t.sons[i].sons[0])
     discard pop(p.finallySafePoints)
   linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint)
 
-proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
+proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
   var res = ""
   for i in countup(0, sonsLen(t) - 1):
     case t.sons[i].kind
@@ -914,69 +960,81 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
       if sym.kind in {skProc, skIterator, skClosureIterator, skMethod}:
         var a: TLoc
         initLocExpr(p, t.sons[i], a)
-        res.add(rdLoc(a).ropeToStr)
+        res.add($rdLoc(a))
       else:
         var r = sym.loc.r
-        if r == nil: 
+        if r == nil:
           # if no name has already been given,
           # it doesn't matter much:
           r = mangleName(sym)
           sym.loc.r = r       # but be consequent!
-        res.add(r.ropeToStr)
+        res.add($r)
     else: internalError(t.sons[i].info, "genAsmOrEmitStmt()")
-  
+
   if isAsmStmt and hasGnuAsm in CC[cCompiler].props:
     for x in splitLines(res):
       var j = 0
       while x[j] in {' ', '\t'}: inc(j)
-      if x[j] == ':' and x[j+1] == '"' or x[j] == '"':
+      if x[j] in {'"', ':'}:
+        # don't modify the line if already in quotes or
         # some clobber register list:
-        app(result, x); app(result, tnl)
+        add(result, x); add(result, tnl)
       elif x[j] != '\0':
         # ignore empty lines
-        app(result, "\"")
-        app(result, x)
-        app(result, "\\n\"\n")
+        add(result, "\"")
+        add(result, x)
+        add(result, "\\n\"\n")
   else:
     res.add(tnl)
-    result = res.toRope
+    result = res.rope
 
-proc genAsmStmt(p: BProc, t: PNode) = 
+proc genAsmStmt(p: BProc, t: PNode) =
   assert(t.kind == nkAsmStmt)
   genLineDir(p, t)
   var s = genAsmOrEmitStmt(p, t, isAsmStmt=true)
+  # see bug #2362, "top level asm statements" seem to be a mis-feature
+  # but even if we don't do this, the example in #2362 cannot possibly
+  # work:
   if p.prc == nil:
     # top level asm statement?
-    appf(p.module.s[cfsProcHeaders], CC[cCompiler].asmStmtFrmt, [s])
+    addf(p.module.s[cfsProcHeaders], CC[cCompiler].asmStmtFrmt, [s])
   else:
     lineF(p, cpsStmts, CC[cCompiler].asmStmtFrmt, [s])
 
-proc genEmit(p: BProc, t: PNode) = 
-  genLineDir(p, t)
+proc determineSection(n: PNode): TCFileSection =
+  result = cfsProcHeaders
+  if n.len >= 1 and n.sons[0].kind in {nkStrLit..nkTripleStrLit}:
+    if n.sons[0].strVal.startsWith("/*TYPESECTION*/"): result = cfsTypes
+    elif n.sons[0].strVal.startsWith("/*VARSECTION*/"): result = cfsVars
+
+proc genEmit(p: BProc, t: PNode) =
   var s = genAsmOrEmitStmt(p, t.sons[1])
-  if p.prc == nil: 
+  if p.prc == nil:
     # top level emit pragma?
-    app(p.module.s[cfsProcHeaders], s)
+    let section = determineSection(t[1])
+    genCLineDir(p.module.s[section], t.info)
+    add(p.module.s[section], s)
   else:
+    genLineDir(p, t)
     line(p, cpsStmts, s)
 
-var 
+var
   breakPointId: int = 0
-  gBreakpoints: PRope # later the breakpoints are inserted into the main proc
+  gBreakpoints: Rope # later the breakpoints are inserted into the main proc
 
-proc genBreakPoint(p: BProc, t: PNode) = 
+proc genBreakPoint(p: BProc, t: PNode) =
   var name: string
   if optEndb in p.options:
-    if t.kind == nkExprColonExpr: 
+    if t.kind == nkExprColonExpr:
       assert(t.sons[1].kind in {nkStrLit..nkTripleStrLit})
       name = normalize(t.sons[1].strVal)
-    else: 
+    else:
       inc(breakPointId)
       name = "bp" & $breakPointId
     genLineDir(p, t)          # BUGFIX
-    appcg(p.module, gBreakpoints, 
+    appcg(p.module, gBreakpoints,
          "#dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n", [
-        toRope(toLinenumber(t.info)), makeCString(toFilename(t.info)),
+        rope(toLinenumber(t.info)), makeCString(toFilename(t.info)),
         makeCString(name)])
 
 proc genWatchpoint(p: BProc, n: PNode) =
@@ -995,14 +1053,14 @@ proc genPragma(p: BProc, n: PNode) =
     of wEmit: genEmit(p, it)
     of wBreakpoint: genBreakPoint(p, it)
     of wWatchPoint: genWatchpoint(p, it)
-    of wInjectStmt: 
+    of wInjectStmt:
       var p = newProc(nil, p.module)
       p.options = p.options - {optLineTrace, optStackTrace}
       genStmts(p, it.sons[1])
       p.module.injectStmt = p.s(cpsStmts)
     else: discard
 
-proc fieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool = 
+proc fieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
   if optFieldCheck in p.options:
     var le = asgn.sons[0]
     if le.kind == nkCheckedFieldExpr:
@@ -1010,23 +1068,23 @@ proc fieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
       result = sfDiscriminant in field.flags
     elif le.kind == nkDotExpr:
       var field = le.sons[1].sym
-      result = sfDiscriminant in field.flags      
+      result = sfDiscriminant in field.flags
 
-proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType, 
-                          field: PSym) = 
+proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
+                          field: PSym) =
   var t = skipTypes(objtype, abstractVar)
   assert t.kind == tyObject
   discard genTypeInfo(p.module, t)
   var L = lengthOrd(field.typ)
   if not containsOrIncl(p.module.declaredThings, field.id):
-    appcg(p.module, cfsVars, "extern $1", 
+    appcg(p.module, cfsVars, "extern $1",
           discriminatorTableDecl(p.module, t, field))
   lineCg(p, cpsStmts,
         "#FieldDiscriminantCheck((NI)(NU)($1), (NI)(NU)($2), $3, $4);$n",
         [rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
          intLiteral(L+1)])
 
-proc asgnFieldDiscriminant(p: BProc, e: PNode) = 
+proc asgnFieldDiscriminant(p: BProc, e: PNode) =
   var a, tmp: TLoc
   var dotExpr = e.sons[0]
   var d: PSym
@@ -1036,10 +1094,12 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
   expr(p, e.sons[1], tmp)
   genDiscriminantCheck(p, a, tmp, dotExpr.sons[0].typ, dotExpr.sons[1].sym)
   genAssignment(p, a, tmp, {})
-  
-proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = 
+
+proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
   genLineDir(p, e)
-  if not fieldDiscriminantCheckNeeded(p, e):
+  if e.sons[0].kind == nkSym and sfGoto in e.sons[0].sym.flags:
+    genGotoVar(p, e.sons[1])
+  elif not fieldDiscriminantCheckNeeded(p, e):
     var a: TLoc
     initLocExpr(p, e.sons[0], a)
     if fastAsgn: incl(a.flags, lfNoDeepCopy)
@@ -1048,7 +1108,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
   else:
     asgnFieldDiscriminant(p, e)
 
-proc genStmts(p: BProc, t: PNode) = 
+proc genStmts(p: BProc, t: PNode) =
   var a: TLoc
   expr(p, t, a)
   internalAssert a.k in {locNone, locTemp, locLocalVar}
diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim
index c24dd5c41..d741c47a9 100644
--- a/compiler/ccgthreadvars.nim
+++ b/compiler/ccgthreadvars.nim
@@ -7,7 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-## Thread var support for crappy architectures that lack native support for 
+## Thread var support for crappy architectures that lack native support for
 ## thread local storage. (**Thank you Mac OS X!**)
 
 # included from cgen.nim
@@ -19,12 +19,12 @@ proc accessThreadLocalVar(p: BProc, s: PSym) =
   if emulatedThreadVars() and not p.threadVarAccessed:
     p.threadVarAccessed = true
     p.module.usesThreadVars = true
-    appf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n")
-    app(p.procSec(cpsInit),
+    addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n", [])
+    add(p.procSec(cpsInit),
       ropecg(p.module, "\tNimTV = (NimThreadVars*) #GetThreadLocalVars();$n"))
-    
+
 var
-  nimtv: PRope                 # nimrod thread vars; the struct body
+  nimtv: Rope                 # nimrod thread vars; the struct body
   nimtvDeps: seq[PType] = @[]  # type deps: every module needs whole struct
   nimtvDeclared = initIntSet() # so that every var/field exists only once
                                # in the struct
@@ -43,23 +43,23 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
     # allocator for it :-(
     if not containsOrIncl(nimtvDeclared, s.id):
       nimtvDeps.add(s.loc.t)
-      appf(nimtv, "$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r])
+      addf(nimtv, "$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r])
   else:
-    if isExtern: app(m.s[cfsVars], "extern ")
-    if optThreads in gGlobalOptions: app(m.s[cfsVars], "NIM_THREADVAR ")
-    app(m.s[cfsVars], getTypeDesc(m, s.loc.t))
-    appf(m.s[cfsVars], " $1;$n", [s.loc.r])
-  
+    if isExtern: add(m.s[cfsVars], "extern ")
+    if optThreads in gGlobalOptions: add(m.s[cfsVars], "NIM_THREADVAR ")
+    add(m.s[cfsVars], getTypeDesc(m, s.loc.t))
+    addf(m.s[cfsVars], " $1;$n", [s.loc.r])
+
 proc generateThreadLocalStorage(m: BModule) =
   if nimtv != nil and (m.usesThreadVars or sfMainModule in m.module.flags):
     for t in items(nimtvDeps): discard getTypeDesc(m, t)
-    appf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv])
+    addf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv])
 
 proc generateThreadVarsSize(m: BModule) =
   if nimtv != nil:
     let externc = if gCmd != cmdCompileToCpp and
                        sfCompileToCpp in m.module.flags: "extern \"C\""
                   else: ""
-    appf(m.s[cfsProcs],
+    addf(m.s[cfsProcs],
       "$#NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}$n",
-      [externc.toRope])
+      [externc.rope])
diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim
index 8bb820283..5f59702e5 100644
--- a/compiler/ccgtrav.nim
+++ b/compiler/ccgtrav.nim
@@ -17,11 +17,11 @@ type
     p: BProc
     visitorFrmt: string
 
-proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType)
+proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType)
 proc genCaseRange(p: BProc, branch: PNode)
 proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false)
 
-proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
+proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, n: PNode) =
   if n == nil: return
   case n.kind
   of nkRecList:
@@ -31,31 +31,31 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
     if (n.sons[0].kind != nkSym): internalError(n.info, "genTraverseProc")
     var p = c.p
     let disc = n.sons[0].sym
-    lineF(p, cpsStmts, "switch ($1.$2) {$n", accessor, disc.loc.r)
+    lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
     for i in countup(1, sonsLen(n) - 1):
       let branch = n.sons[i]
       assert branch.kind in {nkOfBranch, nkElse}
       if branch.kind == nkOfBranch:
         genCaseRange(c.p, branch)
       else:
-        lineF(p, cpsStmts, "default:$n")
+        lineF(p, cpsStmts, "default:$n", [])
       genTraverseProc(c, accessor, lastSon(branch))
-      lineF(p, cpsStmts, "break;$n")
-    lineF(p, cpsStmts, "} $n")
+      lineF(p, cpsStmts, "break;$n", [])
+    lineF(p, cpsStmts, "} $n", [])
   of nkSym:
     let field = n.sym
     if field.loc.t == nil:
       internalError(n.info, "genTraverseProc()")
-    genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t)
+    genTraverseProc(c, "$1.$2" % [accessor, field.loc.r], field.loc.t)
   else: internalError(n.info, "genTraverseProc()")
 
-proc parentObj(accessor: PRope; m: BModule): PRope {.inline.} =
+proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
   if not m.compileToCpp:
-    result = ropef("$1.Sup", accessor)
+    result = "$1.Sup" % [accessor]
   else:
     result = accessor
 
-proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
+proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType) =
   if typ == nil: return
   var p = c.p
   case typ.kind
@@ -66,9 +66,9 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
     var i: TLoc
     getTemp(p, getSysType(tyInt), i)
     linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
-            i.r, arraySize.toRope)
+            i.r, arraySize.rope)
     genTraverseProc(c, rfmt(nil, "$1[$2]", accessor, i.r), typ.sons[1])
-    lineF(p, cpsStmts, "}$n")
+    lineF(p, cpsStmts, "}$n", [])
   of tyObject:
     for i in countup(0, sonsLen(typ) - 1):
       genTraverseProc(c, accessor.parentObj(c.p.module), typ.sons[i])
@@ -76,7 +76,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
   of tyTuple:
     let typ = getUniqueType(typ)
     for i in countup(0, sonsLen(typ) - 1):
-      genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.toRope), typ.sons[i])
+      genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.rope), typ.sons[i])
   of tyRef, tyString, tySequence:
     lineCg(p, cpsStmts, c.visitorFrmt, accessor)
   of tyProc:
@@ -85,67 +85,67 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
   else:
     discard
 
-proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) =
+proc genTraverseProcSeq(c: var TTraversalClosure, accessor: Rope, typ: PType) =
   var p = c.p
-  assert typ.kind == tySequence  
+  assert typ.kind == tySequence
   var i: TLoc
   getTemp(p, getSysType(tyInt), i)
   lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n",
-      i.r, accessor, toRope(if c.p.module.compileToCpp: "len" else: "Sup.len"))
-  genTraverseProc(c, ropef("$1->data[$2]", accessor, i.r), typ.sons[0])
-  lineF(p, cpsStmts, "}$n")
-  
-proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
+      [i.r, accessor, rope(if c.p.module.compileToCpp: "len" else: "Sup.len")])
+  genTraverseProc(c, "$1->data[$2]" % [accessor, i.r], typ.sons[0])
+  lineF(p, cpsStmts, "}$n", [])
+
+proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): Rope =
   var c: TTraversalClosure
   var p = newProc(nil, m)
   result = getGlobalTempName()
-  
+
   case reason
   of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"
   else: assert false
-  
-  let header = ropef("N_NIMCALL(void, $1)(void* p, NI op)", result)
-  
+
+  let header = "N_NIMCALL(void, $1)(void* p, NI op)" % [result]
+
   let t = getTypeDesc(m, typ)
-  lineF(p, cpsLocals, "$1 a;$n", t)
-  lineF(p, cpsInit, "a = ($1)p;$n", t)
-  
+  lineF(p, cpsLocals, "$1 a;$n", [t])
+  lineF(p, cpsInit, "a = ($1)p;$n", [t])
+
   c.p = p
   assert typ.kind != tyTypeDesc
   if typ.kind == tySequence:
-    genTraverseProcSeq(c, "a".toRope, typ)
+    genTraverseProcSeq(c, "a".rope, typ)
   else:
     if skipTypes(typ.sons[0], typedescInst).kind in {tyArrayConstr, tyArray}:
       # C's arrays are broken beyond repair:
-      genTraverseProc(c, "a".toRope, typ.sons[0])
+      genTraverseProc(c, "a".rope, typ.sons[0])
     else:
-      genTraverseProc(c, "(*a)".toRope, typ.sons[0])
-  
-  let generatedProc = ropef("$1 {$n$2$3$4}$n",
-        [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
-  
-  m.s[cfsProcHeaders].appf("$1;$n", header)
-  m.s[cfsProcs].app(generatedProc)
-
-proc genTraverseProcForGlobal(m: BModule, s: PSym): PRope =
+      genTraverseProc(c, "(*a)".rope, typ.sons[0])
+
+  let generatedProc = "$1 {$n$2$3$4}$n" %
+        [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
+
+  m.s[cfsProcHeaders].addf("$1;$n", [header])
+  m.s[cfsProcs].add(generatedProc)
+
+proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope =
   discard genTypeInfo(m, s.loc.t)
-  
+
   var c: TTraversalClosure
   var p = newProc(nil, m)
   var sLoc = s.loc.r
   result = getGlobalTempName()
-  
+
   if sfThread in s.flags and emulatedThreadVars():
     accessThreadLocalVar(p, s)
-    sLoc = con("NimTV->", sLoc)
-    
+    sLoc = "NimTV->" & sLoc
+
   c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
   c.p = p
-  let header = ropef("N_NIMCALL(void, $1)()", result)
+  let header = "N_NIMCALL(void, $1)()" % [result]
   genTraverseProc(c, sLoc, s.loc.t)
-  
-  let generatedProc = ropef("$1 {$n$2$3$4}$n",
-        [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
-  
-  m.s[cfsProcHeaders].appf("$1;$n", header)
-  m.s[cfsProcs].app(generatedProc)
+
+  let generatedProc = "$1 {$n$2$3$4}$n" %
+        [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
+
+  m.s[cfsProcHeaders].addf("$1;$n", [header])
+  m.s[cfsProcs].add(generatedProc)
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 460cb9297..60ebf591b 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -25,21 +25,11 @@ proc isKeyword(w: PIdent): bool =
      ord(wInline): return true
   else: return false
 
-proc mangleName(s: PSym): PRope = 
+proc mangleName(s: PSym): Rope =
   result = s.loc.r
-  if result == nil: 
-    if gCmd == cmdCompileToLLVM: 
-      case s.kind
-      of skProc, skMethod, skConverter, skConst, skIterators:
-        result = ~"@"
-      of skVar, skForVar, skResult, skLet: 
-        if sfGlobal in s.flags: result = ~"@"
-        else: result = ~"%"
-      of skTemp, skParam, skType, skEnumField, skModule: 
-        result = ~"%"
-      else: internalError(s.info, "mangleName")
+  if result == nil:
     when oKeepVariableNames:
-      let keepOrigName = s.kind in skLocalVars - {skForVar} and 
+      let keepOrigName = s.kind in skLocalVars - {skForVar} and
         {sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and
         not isKeyword(s.name)
       # XXX: This is still very experimental
@@ -87,32 +77,30 @@ proc mangleName(s: PSym): PRope =
       # These are not properly scoped now - we need to add blocks
       # around for loops in transf
       if keepOrigName:
-        result = s.name.s.mangle.newRope
+        result = s.name.s.mangle.rope
       else:
-        app(result, newRope(mangle(s.name.s)))
-        app(result, ~"_")
-        app(result, toRope(s.id))
+        add(result, rope(mangle(s.name.s)))
+        add(result, ~"_")
+        add(result, rope(s.id))
     else:
-      app(result, newRope(mangle(s.name.s)))
-      app(result, ~"_")
-      app(result, toRope(s.id))
+      add(result, rope(mangle(s.name.s)))
+      add(result, ~"_")
+      add(result, rope(s.id))
     s.loc.r = result
 
-proc typeName(typ: PType): PRope =
-  result = if typ.sym != nil: typ.sym.name.s.mangle.toRope
+proc typeName(typ: PType): Rope =
+  result = if typ.sym != nil: typ.sym.name.s.mangle.rope
            else: ~"TY"
 
-proc getTypeName(typ: PType): PRope = 
-  if (typ.sym != nil) and ({sfImportc, sfExportc} * typ.sym.flags != {}) and
-      (gCmd != cmdCompileToLLVM): 
+proc getTypeName(typ: PType): Rope =
+  if typ.sym != nil and {sfImportc, sfExportc} * typ.sym.flags != {}:
     result = typ.sym.loc.r
   else:
     if typ.loc.r == nil:
-      typ.loc.r = if gCmd != cmdCompileToLLVM: con(typ.typeName, typ.id.toRope)
-                  else: con([~"%", typ.typeName, typ.id.toRope])
+      typ.loc.r = typ.typeName & typ.id.rope
     result = typ.loc.r
   if result == nil: internalError("getTypeName: " & $typ.kind)
-  
+
 proc mapSetType(typ: PType): TCTypeKind =
   case int(getSize(typ))
   of 1: result = ctInt8
@@ -121,7 +109,7 @@ proc mapSetType(typ: PType): TCTypeKind =
   of 8: result = ctInt64
   else: result = ctArray
 
-proc mapType(typ: PType): TCTypeKind = 
+proc mapType(typ: PType): TCTypeKind =
   ## Maps a nimrod type to a C type
   case typ.kind
   of tyNone, tyStmt: result = ctVoid
@@ -133,10 +121,10 @@ proc mapType(typ: PType): TCTypeKind =
   of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
      tyConst, tyMutable, tyIter, tyTypeDesc:
     result = mapType(lastSon(typ))
-  of tyEnum: 
-    if firstOrd(typ) < 0: 
+  of tyEnum:
+    if firstOrd(typ) < 0:
       result = ctInt32
-    else: 
+    else:
       case int(getSize(typ))
       of 1: result = ctUInt8
       of 2: result = ctUInt16
@@ -157,445 +145,540 @@ proc mapType(typ: PType): TCTypeKind =
   of tyInt..tyUInt64:
     result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
   else: internalError("mapType")
-  
-proc mapReturnType(typ: PType): TCTypeKind = 
+
+proc mapReturnType(typ: PType): TCTypeKind =
   if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
   else: result = mapType(typ)
-  
-proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope
-proc needsComplexAssignment(typ: PType): bool = 
+
+proc isImportedType(t: PType): bool =
+  result = t.sym != nil and sfImportc in t.sym.flags
+
+proc isImportedCppType(t: PType): bool =
+  result = t.sym != nil and sfInfixCall in t.sym.flags
+
+proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope
+proc needsComplexAssignment(typ: PType): bool =
   result = containsGarbageCollectedRef(typ)
 
 proc isObjLackingTypeField(typ: PType): bool {.inline.} =
   result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
       (typ.sons[0] == nil) or isPureObject(typ))
 
-proc isInvalidReturnType(rettype: PType): bool = 
+proc isInvalidReturnType(rettype: PType): bool =
   # Arrays and sets cannot be returned by a C procedure, because C is
   # such a poor programming language.
   # We exclude records with refs too. This enhances efficiency and
   # is necessary for proper code generation of assignments.
   if rettype == nil: result = true
-  else: 
+  else:
     case mapType(rettype)
-    of ctArray: 
+    of ctArray:
       result = not (skipTypes(rettype, typedescInst).kind in
           {tyVar, tyRef, tyPtr})
     of ctStruct:
       let t = skipTypes(rettype, typedescInst)
+      if rettype.isImportedCppType or t.isImportedCppType: return false
       result = needsComplexAssignment(t) or
           (t.kind == tyObject and not isObjLackingTypeField(t))
     else: result = false
 
-const 
-  CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL", 
-    "N_STDCALL", "N_CDECL", "N_SAFECALL", 
+const
+  CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL",
+    "N_STDCALL", "N_CDECL", "N_SAFECALL",
     "N_SYSCALL", # this is probably not correct for all platforms,
-                 # but one can #define it to what one wants 
+                 # but one can #define it to what one wants
     "N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_CLOSURE", "N_NOCONV"]
-  CallingConvToStrLLVM: array[TCallingConvention, string] = ["fastcc $1", 
-    "stdcall $1", "ccc $1", "safecall $1", "syscall $1", "$1 alwaysinline", 
-    "$1 noinline", "fastcc $1", "ccc $1", "$1"]
 
-proc cacheGetType(tab: TIdTable, key: PType): PRope = 
+proc cacheGetType(tab: TIdTable, key: PType): Rope =
   # returns nil if we need to declare this type
-  # since types are now unique via the ``GetUniqueType`` mechanism, this slow
+  # since types are now unique via the ``getUniqueType`` mechanism, this slow
   # linear search is not necessary anymore:
-  result = PRope(idTableGet(tab, key))
+  result = Rope(idTableGet(tab, key))
 
-proc getTempName(): PRope = 
-  result = rfmt(nil, "TMP$1", toRope(backendId()))
+proc getTempName(): Rope =
+  result = rfmt(nil, "TMP$1", rope(backendId()))
 
-proc getGlobalTempName(): PRope = 
-  result = rfmt(nil, "TMP$1", toRope(backendId()))
+proc getGlobalTempName(): Rope =
+  result = rfmt(nil, "TMP$1", rope(backendId()))
 
-proc ccgIntroducedPtr(s: PSym): bool = 
+proc ccgIntroducedPtr(s: PSym): bool =
   var pt = skipTypes(s.typ, typedescInst)
   assert skResult != s.kind
   if tfByRef in pt.flags: return true
   elif tfByCopy in pt.flags: return false
   case pt.kind
   of tyObject:
-    if (optByRef in s.options) or (getSize(pt) > platform.floatSize * 2): 
+    if (optByRef in s.options) or (getSize(pt) > platform.floatSize * 2):
       result = true           # requested anyway
-    elif (tfFinal in pt.flags) and (pt.sons[0] == nil): 
+    elif (tfFinal in pt.flags) and (pt.sons[0] == nil):
       result = false          # no need, because no subtyping possible
-    else: 
+    else:
       result = true           # ordinary objects are always passed by reference,
                               # otherwise casting doesn't work
-  of tyTuple: 
+  of tyTuple:
     result = (getSize(pt) > platform.floatSize*2) or (optByRef in s.options)
   else: result = false
-  
-proc fillResult(param: PSym) = 
+
+proc fillResult(param: PSym) =
   fillLoc(param.loc, locParam, param.typ, ~"Result",
           OnStack)
-  if (mapReturnType(param.typ) != ctArray) and isInvalidReturnType(param.typ): 
+  if (mapReturnType(param.typ) != ctArray) and isInvalidReturnType(param.typ):
     incl(param.loc.flags, lfIndirect)
     param.loc.s = OnUnknown
 
-proc getParamTypeDesc(m: BModule, t: PType, check: var IntSet): PRope =
-  when false:
-    if t.Kind in {tyRef, tyPtr, tyVar}:
-      var b = skipTypes(t.lastson, typedescInst)
-      if b.kind == tySet and mapSetType(b) == ctArray:
-        return getTypeDescAux(m, b, check)
-  result = getTypeDescAux(m, t, check)
-
-proc paramStorageLoc(param: PSym): TStorageLoc =
-  if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin {tyArray, tyOpenArray}:
-    result = OnStack
+proc typeNameOrLiteral(t: PType, literal: string): Rope =
+  if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone:
+    result = getTypeName(t)
   else:
-    result = OnUnknown
+    result = rope(literal)
 
-proc genProcParams(m: BModule, t: PType, rettype, params: var PRope, 
-                   check: var IntSet, declareEnvironment=true) = 
-  params = nil
-  if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]): 
-    rettype = ~"void"
-  else: 
-    rettype = getTypeDescAux(m, t.sons[0], check)
-  for i in countup(1, sonsLen(t.n) - 1): 
-    if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams")
-    var param = t.n.sons[i].sym
-    if isCompileTimeOnly(param.typ): continue
-    if params != nil: app(params, ~", ")
-    fillLoc(param.loc, locParam, param.typ, mangleName(param),
-            param.paramStorageLoc)
-    app(params, getParamTypeDesc(m, param.typ, check))
-    if ccgIntroducedPtr(param): 
-      app(params, ~"*")
-      incl(param.loc.flags, lfIndirect)
-      param.loc.s = OnUnknown
-    app(params, ~" ")
-    app(params, param.loc.r)
-    # declare the len field for open arrays:
-    var arr = param.typ
-    if arr.kind == tyVar: arr = arr.sons[0]
-    var j = 0
-    while arr.kind in {tyOpenArray, tyVarargs}:
-      # this fixes the 'sort' bug:
-      if param.typ.kind == tyVar: param.loc.s = OnUnknown
-      # need to pass hidden parameter:
-      appff(params, ", NI $1Len$2", ", @NI $1Len$2", [param.loc.r, j.toRope])
-      inc(j)
-      arr = arr.sons[0]
-  if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]): 
-    var arr = t.sons[0]
-    if params != nil: app(params, ", ")
-    app(params, getTypeDescAux(m, arr, check))
-    if (mapReturnType(t.sons[0]) != ctArray) or (gCmd == cmdCompileToLLVM): 
-      app(params, "*")
-    appff(params, " Result", " @Result", [])
-  if t.callConv == ccClosure and declareEnvironment: 
-    if params != nil: app(params, ", ")
-    app(params, "void* ClEnv")
-  if tfVarargs in t.flags: 
-    if params != nil: app(params, ", ")
-    app(params, "...")
-  if params == nil and gCmd != cmdCompileToLLVM: app(params, "void)")
-  else: app(params, ")")
-  params = con("(", params)
-
-proc isImportedType(t: PType): bool = 
-  result = (t.sym != nil) and (sfImportc in t.sym.flags)
-
-proc typeNameOrLiteral(t: PType, literal: string): PRope = 
-  if (t.sym != nil) and (sfImportc in t.sym.flags) and (t.sym.magic == mNone): 
-    result = getTypeName(t)
-  else: 
-    result = toRope(literal)
-  
-proc getSimpleTypeDesc(m: BModule, typ: PType): PRope = 
-  const 
+proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
+  const
     NumericalTypeToStr: array[tyInt..tyUInt64, string] = [
       "NI", "NI8", "NI16", "NI32", "NI64",
       "NF", "NF32", "NF64", "NF128",
       "NU", "NU8", "NU16", "NU32", "NU64",]
   case typ.kind
-  of tyPointer: 
+  of tyPointer:
     result = typeNameOrLiteral(typ, "void*")
-  of tyEnum: 
-    if firstOrd(typ) < 0: 
+  of tyEnum:
+    if firstOrd(typ) < 0:
       result = typeNameOrLiteral(typ, "NI32")
-    else: 
+    else:
       case int(getSize(typ))
       of 1: result = typeNameOrLiteral(typ, "NU8")
       of 2: result = typeNameOrLiteral(typ, "NU16")
       of 4: result = typeNameOrLiteral(typ, "NI32")
       of 8: result = typeNameOrLiteral(typ, "NI64")
-      else: 
+      else:
         internalError(typ.sym.info, "getSimpleTypeDesc: " & $(getSize(typ)))
         result = nil
-  of tyString: 
+  of tyString:
     discard cgsym(m, "NimStringDesc")
     result = typeNameOrLiteral(typ, "NimStringDesc*")
   of tyCString: result = typeNameOrLiteral(typ, "NCSTRING")
   of tyBool: result = typeNameOrLiteral(typ, "NIM_BOOL")
   of tyChar: result = typeNameOrLiteral(typ, "NIM_CHAR")
   of tyNil: result = typeNameOrLiteral(typ, "0")
-  of tyInt..tyUInt64: 
+  of tyInt..tyUInt64:
     result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind])
-  of tyDistinct, tyRange: result = getSimpleTypeDesc(m, typ.sons[0])
+  of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0])
   else: result = nil
-  
-proc getTypePre(m: BModule, typ: PType): PRope = 
-  if typ == nil: result = toRope("void")
-  else: 
+
+proc pushType(m: BModule, typ: PType) =
+  add(m.typeStack, typ)
+
+proc getTypePre(m: BModule, typ: PType): Rope =
+  if typ == nil: result = rope("void")
+  else:
     result = getSimpleTypeDesc(m, typ)
     if result == nil: result = cacheGetType(m.typeCache, typ)
 
-proc structOrUnion(t: PType): PRope =
-  (if tfUnion in t.flags: toRope("union") else: toRope("struct"))
+proc structOrUnion(t: PType): Rope =
+  (if tfUnion in t.flags: rope("union") else: rope("struct"))
 
-proc getForwardStructFormat(m: BModule): string = 
+proc getForwardStructFormat(m: BModule): string =
   if m.compileToCpp: result = "$1 $2;$n"
   else: result = "typedef $1 $2 $2;$n"
-  
-proc getTypeForward(m: BModule, typ: PType): PRope = 
+
+proc getTypeForward(m: BModule, typ: PType): Rope =
   result = cacheGetType(m.forwTypeCache, typ)
-  if result != nil: return 
+  if result != nil: return
   result = getTypePre(m, typ)
-  if result != nil: return 
+  if result != nil: return
   case typ.kind
-  of tySequence, tyTuple, tyObject: 
+  of tySequence, tyTuple, tyObject:
     result = getTypeName(typ)
-    if not isImportedType(typ): 
-      appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
+    if not isImportedType(typ):
+      addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
           [structOrUnion(typ), result])
     idTablePut(m.forwTypeCache, typ, result)
   else: internalError("getTypeForward(" & $typ.kind & ')')
-  
-proc mangleRecFieldName(field: PSym, rectype: PType): PRope = 
+
+proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
+  ## like getTypeDescAux but creates only a *weak* dependency. In other words
+  ## we know we only need a pointer to it so we only generate a struct forward
+  ## declaration:
+  var etB = t.skipTypes(abstractInst)
+  case etB.kind
+  of tyObject, tyTuple:
+    if isImportedCppType(etB) and t.kind == tyGenericInst:
+      result = getTypeDescAux(m, t, check)
+    else:
+      let x = getUniqueType(etB)
+      result = getTypeForward(m, x)
+      pushType(m, x)
+  of tySequence:
+    let x = getUniqueType(etB)
+    result = getTypeForward(m, x) & "*"
+    pushType(m, x)
+  else:
+    result = getTypeDescAux(m, t, check)
+
+proc paramStorageLoc(param: PSym): TStorageLoc =
+  if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin {tyArray, tyOpenArray}:
+    result = OnStack
+  else:
+    result = OnUnknown
+
+proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
+                   check: var IntSet, declareEnvironment=true) =
+  params = nil
+  if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]):
+    rettype = ~"void"
+  else:
+    rettype = getTypeDescAux(m, t.sons[0], check)
+  for i in countup(1, sonsLen(t.n) - 1):
+    if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams")
+    var param = t.n.sons[i].sym
+    if isCompileTimeOnly(param.typ): continue
+    if params != nil: add(params, ~", ")
+    fillLoc(param.loc, locParam, param.typ, mangleName(param),
+            param.paramStorageLoc)
+    if ccgIntroducedPtr(param):
+      add(params, getTypeDescWeak(m, param.typ, check))
+      add(params, ~"*")
+      incl(param.loc.flags, lfIndirect)
+      param.loc.s = OnUnknown
+    else:
+      add(params, getTypeDescAux(m, param.typ, check))
+    add(params, ~" ")
+    add(params, param.loc.r)
+    # declare the len field for open arrays:
+    var arr = param.typ
+    if arr.kind == tyVar: arr = arr.sons[0]
+    var j = 0
+    while arr.kind in {tyOpenArray, tyVarargs}:
+      # this fixes the 'sort' bug:
+      if param.typ.kind == tyVar: param.loc.s = OnUnknown
+      # need to pass hidden parameter:
+      addf(params, ", NI $1Len$2", [param.loc.r, j.rope])
+      inc(j)
+      arr = arr.sons[0]
+  if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]):
+    var arr = t.sons[0]
+    if params != nil: add(params, ", ")
+    if (mapReturnType(t.sons[0]) != ctArray):
+      add(params, getTypeDescWeak(m, arr, check))
+      add(params, "*")
+    else:
+      add(params, getTypeDescAux(m, arr, check))
+    addf(params, " Result", [])
+  if t.callConv == ccClosure and declareEnvironment:
+    if params != nil: add(params, ", ")
+    add(params, "void* ClEnv")
+  if tfVarargs in t.flags:
+    if params != nil: add(params, ", ")
+    add(params, "...")
+  if params == nil: add(params, "void)")
+  else: add(params, ")")
+  params = "(" & params
+
+proc mangleRecFieldName(field: PSym, rectype: PType): Rope =
   if (rectype.sym != nil) and
-      ({sfImportc, sfExportc} * rectype.sym.flags != {}): 
+      ({sfImportc, sfExportc} * rectype.sym.flags != {}):
     result = field.loc.r
   else:
-    result = toRope(mangleField(field.name.s))
+    result = rope(mangleField(field.name.s))
   if result == nil: internalError(field.info, "mangleRecFieldName")
-  
-proc genRecordFieldsAux(m: BModule, n: PNode, 
-                        accessExpr: PRope, rectype: PType, 
-                        check: var IntSet): PRope = 
-  var 
-    ae, uname, sname, a: PRope
+
+proc genRecordFieldsAux(m: BModule, n: PNode,
+                        accessExpr: Rope, rectype: PType,
+                        check: var IntSet): Rope =
+  var
+    ae, uname, sname, a: Rope
     k: PNode
     field: PSym
   result = nil
   case n.kind
-  of nkRecList: 
-    for i in countup(0, sonsLen(n) - 1): 
-      app(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype, check))
-  of nkRecCase: 
-    if (n.sons[0].kind != nkSym): internalError(n.info, "genRecordFieldsAux")
-    app(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check))
-    uname = toRope(mangle(n.sons[0].sym.name.s) & 'U')
-    if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, uname])
+  of nkRecList:
+    for i in countup(0, sonsLen(n) - 1):
+      add(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype, check))
+  of nkRecCase:
+    if n.sons[0].kind != nkSym: internalError(n.info, "genRecordFieldsAux")
+    add(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check))
+    uname = rope(mangle(n.sons[0].sym.name.s) & 'U')
+    if accessExpr != nil: ae = "$1.$2" % [accessExpr, uname]
     else: ae = uname
-    app(result, "union {" & tnl)
-    for i in countup(1, sonsLen(n) - 1): 
+    var unionBody: Rope = nil
+    for i in countup(1, sonsLen(n) - 1):
       case n.sons[i].kind
-      of nkOfBranch, nkElse: 
+      of nkOfBranch, nkElse:
         k = lastSon(n.sons[i])
-        if k.kind != nkSym: 
-          sname = con("S", toRope(i))
-          a = genRecordFieldsAux(m, k, ropef("$1.$2", [ae, sname]), rectype, 
+        if k.kind != nkSym:
+          sname = "S" & rope(i)
+          a = genRecordFieldsAux(m, k, "$1.$2" % [ae, sname], rectype,
                                  check)
-          if a != nil: 
-            app(result, "struct {")
-            app(result, a)
-            appf(result, "} $1;$n", [sname])
-        else: 
-          app(result, genRecordFieldsAux(m, k, ae, rectype, check))
+          if a != nil:
+            add(unionBody, "struct {")
+            add(unionBody, a)
+            addf(unionBody, "} $1;$n", [sname])
+        else:
+          add(unionBody, genRecordFieldsAux(m, k, ae, rectype, check))
       else: internalError("genRecordFieldsAux(record case branch)")
-    appf(result, "} $1;$n", [uname])
+    if unionBody != nil:
+      addf(result, "union{$n$1} $2;$n", [unionBody, uname])
   of nkSym:
     field = n.sym
     if field.typ.kind == tyEmpty: return
     #assert(field.ast == nil)
     sname = mangleRecFieldName(field, rectype)
-    if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
+    if accessExpr != nil: ae = "$1.$2" % [accessExpr, sname]
     else: ae = sname
     fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
-    let fieldType = field.loc.t
-    if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
-      appf(result, "$1 $2[SEQ_DECL_SIZE];$n",
-          [getTypeDescAux(m, fieldType.elemType, check), sname])
-    else:
-      appf(result, "$1 $2;$n", [getTypeDescAux(m, fieldType, check), sname])
+    # for importcpp'ed objects, we only need to set field.loc, but don't
+    # have to recurse via 'getTypeDescAux'. And not doing so prevents problems
+    # with heavily templatized C++ code:
+    if not isImportedCppType(rectype):
+      let fieldType = field.loc.t.skipTypes(abstractInst)
+      if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
+        addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
+            [getTypeDescAux(m, fieldType.elemType, check), sname])
+      elif fieldType.kind == tySequence:
+        # we need to use a weak dependency here for trecursive_table.
+        addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
+      else:
+        # don't use fieldType here because we need the
+        # tyGenericInst for C++ template support
+        addf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
   else: internalError(n.info, "genRecordFieldsAux()")
-  
-proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope = 
+
+proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope =
   result = genRecordFieldsAux(m, typ.n, nil, typ, check)
 
-proc getRecordDesc(m: BModule, typ: PType, name: PRope, 
-                   check: var IntSet): PRope = 
+proc getRecordDesc(m: BModule, typ: PType, name: Rope,
+                   check: var IntSet): Rope =
   # declare the record:
   var hasField = false
 
-  var attribute: PRope =
-    if tfPacked in typ.flags: toRope(CC[cCompiler].packedPragma)
+  var attribute: Rope =
+    if tfPacked in typ.flags: rope(CC[cCompiler].packedPragma)
     else: nil
 
-  result = ropecg(m, CC[cCompiler].structStmtFmt, 
+  result = ropecg(m, CC[cCompiler].structStmtFmt,
     [structOrUnion(typ), name, attribute])
 
-  if typ.kind == tyObject: 
+  if typ.kind == tyObject:
 
-    if typ.sons[0] == nil: 
-      if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags: 
+    if typ.sons[0] == nil:
+      if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags:
         appcg(m, result, " {$n", [])
-      else: 
+      else:
         appcg(m, result, " {$n#TNimType* m_type;$n", [name, attribute])
         hasField = true
     elif m.compileToCpp:
-      appcg(m, result, " : public $1 {$n", 
+      appcg(m, result, " : public $1 {$n",
                       [getTypeDescAux(m, typ.sons[0], check)])
       hasField = true
-    else: 
-      appcg(m, result, " {$n  $1 Sup;$n", 
+    else:
+      appcg(m, result, " {$n  $1 Sup;$n",
                       [getTypeDescAux(m, typ.sons[0], check)])
       hasField = true
-  else: 
-    appf(result, " {$n", [name])
+  else:
+    addf(result, " {$n", [name])
 
   var desc = getRecordFields(m, typ, check)
-  if desc == nil and not hasField: 
-    appf(result, "char dummy;$n", [])
-  else: 
-    app(result, desc)
-  app(result, "};" & tnl)
-
-proc getTupleDesc(m: BModule, typ: PType, name: PRope, 
-                  check: var IntSet): PRope =
-  result = ropef("$1 $2 {$n", [structOrUnion(typ), name])
-  var desc: PRope = nil
-  for i in countup(0, sonsLen(typ) - 1): 
-    appf(desc, "$1 Field$2;$n", 
-         [getTypeDescAux(m, typ.sons[i], check), toRope(i)])
-  if (desc == nil): app(result, "char dummy;" & tnl)
-  else: app(result, desc)
-  app(result, "};" & tnl)
-
-proc pushType(m: BModule, typ: PType) = 
-  add(m.typeStack, typ)
+  if desc == nil and not hasField:
+    addf(result, "char dummy;$n", [])
+  else:
+    add(result, desc)
+  add(result, "};" & tnl)
+
+proc getTupleDesc(m: BModule, typ: PType, name: Rope,
+                  check: var IntSet): Rope =
+  result = "$1 $2 {$n" % [structOrUnion(typ), name]
+  var desc: Rope = nil
+  for i in countup(0, sonsLen(typ) - 1):
+    addf(desc, "$1 Field$2;$n",
+         [getTypeDescAux(m, typ.sons[i], check), rope(i)])
+  if desc == nil: add(result, "char dummy;" & tnl)
+  else: add(result, desc)
+  add(result, "};" & tnl)
+
+proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool =
+  # A helper proc for handling cppimport patterns, involving numeric
+  # placeholders for generic types (e.g. '0, '**2, etc).
+  # pre: the cursor must be placed at the ' symbol
+  # post: the cursor will be placed after the final digit
+  # false will returned if the input is not recognized as a placeholder
+  inc cursor
+  let begin = cursor
+  while pat[cursor] == '*': inc cursor
+  if pat[cursor] in Digits:
+    outIdx = pat[cursor].ord - '0'.ord
+    outStars = cursor - begin
+    inc cursor
+    return true
+  else:
+    return false
 
-proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = 
+proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
+  # XXX: we should catch this earlier and report it as a semantic error
+  if idx >= typ.len: internalError "invalid apostrophe type parameter index"
+
+  result = typ.sons[idx]
+  for i in 1..stars:
+    if result != nil and result.len > 0:
+      result = if result.kind == tyGenericInst: result.sons[1]
+               else: result.elemType
+
+proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
   # returns only the type's name
-  var 
-    name, rettype, desc, recdesc: PRope
-    n: BiggestInt
-    t, et: PType
-  t = getUniqueType(typ)
+  var t = getUniqueType(typ)
   if t == nil: internalError("getTypeDescAux: t == nil")
   if t.sym != nil: useHeader(m, t.sym)
   result = getTypePre(m, t)
-  if result != nil: return 
-  if containsOrIncl(check, t.id): 
-    internalError("cannot generate C type for: " & typeToString(typ)) 
+  if result != nil: return
+  if containsOrIncl(check, t.id):
+    if isImportedCppType(typ) or isImportedCppType(t): return
+    internalError("cannot generate C type for: " & typeToString(typ))
     # XXX: this BUG is hard to fix -> we need to introduce helper structs,
     # but determining when this needs to be done is hard. We should split
     # C type generation into an analysis and a code generation phase somehow.
   case t.kind
-  of tyRef, tyPtr, tyVar: 
-    et = getUniqueType(t.lastSon)
-    if et.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}: 
+  of tyRef, tyPtr, tyVar:
+    var star = if t.kind == tyVar and tfVarIsPtr notin typ.flags and
+                    compileToCpp(m): "&" else: "*"
+    var et = t.lastSon
+    var etB = et.skipTypes(abstractInst)
+    if etB.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}:
       # this is correct! sets have no proper base type, so we treat
       # ``var set[char]`` in `getParamTypeDesc`
-      et = getUniqueType(elemType(et))
-    case et.kind
-    of tyObject, tyTuple: 
-      # no restriction! We have a forward declaration for structs
-      name = getTypeForward(m, et)
-      result = con(name, "*")
-      idTablePut(m.typeCache, t, result)
-      pushType(m, et)
-    of tySequence: 
+      et = elemType(etB)
+      etB = et.skipTypes(abstractInst)
+      star[0] = '*'
+    case etB.kind
+    of tyObject, tyTuple:
+      if isImportedCppType(etB) and et.kind == tyGenericInst:
+        result = getTypeDescAux(m, et, check) & star
+      else:
+        # no restriction! We have a forward declaration for structs
+        let x = getUniqueType(etB)
+        let name = getTypeForward(m, x)
+        result = name & star
+        idTablePut(m.typeCache, t, result)
+        pushType(m, x)
+    of tySequence:
       # no restriction! We have a forward declaration for structs
-      name = getTypeForward(m, et)
-      result = con(name, "**")
+      let x = getUniqueType(etB)
+      let name = getTypeForward(m, x)
+      result = name & "*" & star
       idTablePut(m.typeCache, t, result)
-      pushType(m, et)
-    else: 
+      pushType(m, x)
+    else:
       # else we have a strong dependency  :-(
-      result = con(getTypeDescAux(m, et, check), "*")
+      result = getTypeDescAux(m, et, check) & star
       idTablePut(m.typeCache, t, result)
-  of tyOpenArray, tyVarargs: 
-    et = getUniqueType(t.sons[0])
-    result = con(getTypeDescAux(m, et, check), "*")
+  of tyOpenArray, tyVarargs:
+    result = getTypeDescAux(m, t.sons[0], check) & "*"
     idTablePut(m.typeCache, t, result)
-  of tyProc: 
+  of tyProc:
     result = getTypeName(t)
     idTablePut(m.typeCache, t, result)
+    var rettype, desc: Rope
     genProcParams(m, t, rettype, desc, check)
-    if not isImportedType(t): 
+    if not isImportedType(t):
       if t.callConv != ccClosure: # procedure vars may need a closure!
-        appf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n", 
-             [toRope(CallingConvToStr[t.callConv]), rettype, result, desc])
+        addf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
+             [rope(CallingConvToStr[t.callConv]), rettype, result, desc])
       else:
-        appf(m.s[cfsTypes], "typedef struct {$n" &
-            "N_NIMCALL_PTR($2, ClPrc) $3;$n" & 
+        addf(m.s[cfsTypes], "typedef struct {$n" &
+            "N_NIMCALL_PTR($2, ClPrc) $3;$n" &
             "void* ClEnv;$n} $1;$n",
              [result, rettype, desc])
-  of tySequence: 
+  of tySequence:
     # 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 = cacheGetType(m.forwTypeCache, t)
-    if result == nil: 
+    if result == nil:
       result = getTypeName(t)
-      if not isImportedType(t): 
-        appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
+      if not isImportedType(t):
+        addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
             [structOrUnion(t), result])
       idTablePut(m.forwTypeCache, t, result)
     assert(cacheGetType(m.typeCache, t) == nil)
-    idTablePut(m.typeCache, t, con(result, "*"))
-    if not isImportedType(t): 
-      if skipTypes(t.sons[0], typedescInst).kind != tyEmpty: 
+    idTablePut(m.typeCache, t, result & "*")
+    if not isImportedType(t):
+      if skipTypes(t.sons[0], typedescInst).kind != tyEmpty:
         const
           cppSeq = "struct $2 : #TGenericSeq {$n"
           cSeq = "struct $2 {$n" &
                  "  #TGenericSeq Sup;$n"
         appcg(m, m.s[cfsSeqTypes],
             (if m.compileToCpp: cppSeq else: cSeq) &
-            "  $1 data[SEQ_DECL_SIZE];$n" & 
+            "  $1 data[SEQ_DECL_SIZE];$n" &
             "};$n", [getTypeDescAux(m, t.sons[0], check), result])
-      else: 
-        result = toRope("TGenericSeq")
-    app(result, "*")
-  of tyArrayConstr, tyArray: 
-    n = lengthOrd(t)
-    if n <= 0: 
-      n = 1                   # make an array of at least one element
+      else:
+        result = rope("TGenericSeq")
+    add(result, "*")
+  of tyArrayConstr, tyArray:
+    var n: BiggestInt = lengthOrd(t)
+    if n <= 0: n = 1   # make an array of at least one element
     result = getTypeName(t)
     idTablePut(m.typeCache, t, result)
-    if not isImportedType(t): 
-      appf(m.s[cfsTypes], "typedef $1 $2[$3];$n", 
-           [getTypeDescAux(m, t.sons[1], check), result, toRope(n)])
-  of tyObject, tyTuple: 
-    result = cacheGetType(m.forwTypeCache, t)
-    if result == nil: 
-      result = getTypeName(t)
-      if not isImportedType(t): 
-        appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
-           [structOrUnion(t), result])
-      idTablePut(m.forwTypeCache, t, result)
-    idTablePut(m.typeCache, t, result) # always call for sideeffects:
-    if t.kind != tyTuple: recdesc = getRecordDesc(m, t, result, check)
-    else: recdesc = getTupleDesc(m, t, result, check)
-    if not isImportedType(t): app(m.s[cfsTypes], recdesc)
-  of tySet: 
+    if not isImportedType(t):
+      let foo = getTypeDescAux(m, t.sons[1], check)
+      addf(m.s[cfsTypes], "typedef $1 $2[$3];$n",
+           [foo, result, rope(n)])
+  of tyObject, tyTuple:
+    if isImportedCppType(t) and typ.kind == tyGenericInst:
+      # for instantiated templates we do not go through the type cache as the
+      # the type cache is not aware of 'tyGenericInst'.
+      let cppName = getTypeName(t)
+      var i = 0
+      var chunkStart = 0
+      while i < cppName.data.len:
+        if cppName.data[i] == '\'':
+          var chunkEnd = <i
+          var idx, stars: int
+          if scanCppGenericSlot(cppName.data, i, idx, stars):
+            result.add cppName.data.substr(chunkStart, chunkEnd)
+            chunkStart = i
+
+            let typeInSlot = resolveStarsInCppType(typ, idx + 1, stars)
+            if typeInSlot == nil or typeInSlot.kind == tyEmpty:
+              result.add(~"void")
+            else:
+              result.add getTypeDescAux(m, typeInSlot, check)
+        else:
+          inc i
+      
+      if chunkStart != 0:
+        result.add cppName.data.substr(chunkStart)
+      else:
+        result = cppName & "<"
+        for i in 1 .. typ.len-2:
+          if i > 1: result.add(", ")
+          result.add(getTypeDescAux(m, typ.sons[i], check))
+        result.add("> ")
+      # always call for sideeffects:
+      assert t.kind != tyTuple
+      discard getRecordDesc(m, t, result, check)
+    else:
+      result = cacheGetType(m.forwTypeCache, t)
+      if result == nil:
+        result = getTypeName(t)
+        if not isImportedType(t):
+          addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
+             [structOrUnion(t), result])
+        idTablePut(m.forwTypeCache, t, result)
+      idTablePut(m.typeCache, t, result) # always call for sideeffects:
+      let recdesc = if t.kind != tyTuple: getRecordDesc(m, t, result, check)
+                    else: getTupleDesc(m, t, result, check)
+      if not isImportedType(t): add(m.s[cfsTypes], recdesc)
+  of tySet:
     case int(getSize(t))
-    of 1: result = toRope("NU8")
-    of 2: result = toRope("NU16")
-    of 4: result = toRope("NU32")
-    of 8: result = toRope("NU64")
-    else: 
+    of 1: result = rope("NU8")
+    of 2: result = rope("NU16")
+    of 4: result = rope("NU32")
+    of 8: result = rope("NU64")
+    else:
       result = getTypeName(t)
       idTablePut(m.typeCache, t, result)
-      if not isImportedType(t): 
-        appf(m.s[cfsTypes], "typedef NU8 $1[$2];$n", 
-             [result, toRope(getSize(t))])
-  of tyGenericInst, tyDistinct, tyOrdinal, tyConst, tyMutable, 
+      if not isImportedType(t):
+        addf(m.s[cfsTypes], "typedef NU8 $1[$2];$n",
+             [result, rope(getSize(t))])
+  of tyGenericInst, tyDistinct, tyOrdinal, tyConst, tyMutable,
       tyIter, tyTypeDesc:
     result = getTypeDescAux(m, lastSon(t), check)
   else:
@@ -604,7 +687,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
   # fixes bug #145:
   excl(check, t.id)
 
-proc getTypeDesc(m: BModule, typ: PType): PRope = 
+proc getTypeDesc(m: BModule, typ: PType): Rope =
   var check = initIntSet()
   result = getTypeDescAux(m, typ, check)
 
@@ -612,274 +695,266 @@ type
   TClosureTypeKind = enum
     clHalf, clHalfWithEnv, clFull
 
-proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): PRope =
+proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): Rope =
   assert t.kind == tyProc
   var check = initIntSet()
   result = getTempName()
-  var rettype, desc: PRope
+  var rettype, desc: Rope
   genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf)
   if not isImportedType(t):
     if t.callConv != ccClosure or kind != clFull:
-      appf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n", 
-           [toRope(CallingConvToStr[t.callConv]), rettype, result, desc])
+      addf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
+           [rope(CallingConvToStr[t.callConv]), rettype, result, desc])
     else:
-      appf(m.s[cfsTypes], "typedef struct {$n" &
-          "N_NIMCALL_PTR($2, ClPrc) $3;$n" & 
+      addf(m.s[cfsTypes], "typedef struct {$n" &
+          "N_NIMCALL_PTR($2, ClPrc) $3;$n" &
           "void* ClEnv;$n} $1;$n",
            [result, rettype, desc])
 
-proc getTypeDesc(m: BModule, magic: string): PRope = 
+proc getTypeDesc(m: BModule, magic: string): Rope =
   var sym = magicsys.getCompilerProc(magic)
-  if sym != nil: 
+  if sym != nil:
     result = getTypeDesc(m, sym.typ)
-  else: 
+  else:
     rawMessage(errSystemNeeds, magic)
     result = nil
 
-proc finishTypeDescriptions(m: BModule) = 
+proc finishTypeDescriptions(m: BModule) =
   var i = 0
-  while i < len(m.typeStack): 
+  while i < len(m.typeStack):
     discard getTypeDesc(m, m.typeStack[i])
     inc(i)
 
 template cgDeclFrmt*(s: PSym): string = s.constraint.strVal
 
-proc genProcHeader(m: BModule, prc: PSym): PRope = 
-  var 
-    rettype, params: PRope
+proc genProcHeader(m: BModule, prc: PSym): Rope =
+  var
+    rettype, params: Rope
   genCLineDir(result, prc.info)
   # using static is needed for inline procs
-  if gCmd != cmdCompileToLLVM and lfExportLib in prc.loc.flags:
+  if lfExportLib in prc.loc.flags:
     if m.isHeaderFile:
-      result.app "N_LIB_IMPORT "
+      result.add "N_LIB_IMPORT "
     else:
-      result.app "N_LIB_EXPORT "
+      result.add "N_LIB_EXPORT "
   elif prc.typ.callConv == ccInline:
-    result.app "static "
+    result.add "static "
   var check = initIntSet()
   fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), OnUnknown)
   genProcParams(m, prc.typ, rettype, params, check)
   # careful here! don't access ``prc.ast`` as that could reload large parts of
   # the object graph!
   if prc.constraint.isNil:
-    appf(result, "$1($2, $3)$4", 
-         [toRope(CallingConvToStr[prc.typ.callConv]), rettype, prc.loc.r, 
+    addf(result, "$1($2, $3)$4",
+         [rope(CallingConvToStr[prc.typ.callConv]), rettype, prc.loc.r,
          params])
   else:
-    result = ropef(prc.cgDeclFrmt, [rettype, prc.loc.r, params])
+    result = prc.cgDeclFrmt % [rettype, prc.loc.r, params]
 
 # ------------------ type info generation -------------------------------------
 
-proc genTypeInfo(m: BModule, t: PType): PRope
-proc getNimNode(m: BModule): PRope = 
-  result = ropef("$1[$2]", [m.typeNodesName, toRope(m.typeNodes)])
+proc genTypeInfo(m: BModule, t: PType): Rope
+proc getNimNode(m: BModule): Rope =
+  result = "$1[$2]" % [m.typeNodesName, rope(m.typeNodes)]
   inc(m.typeNodes)
 
-when false:
-  proc getNimType(m: BModule): PRope = 
-    result = ropef("$1[$2]", [m.nimTypesName, toRope(m.nimTypes)])
-    inc(m.nimTypes)
-
-  proc allocMemTI(m: BModule, typ: PType, name: PRope) = 
-    var tmp = getNimType(m)
-    appf(m.s[cfsTypeInit2], "$2 = &$1;$n", [tmp, name])
-
-proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
+proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: Rope) =
   var nimtypeKind: int
   #allocMemTI(m, typ, name)
   if isObjLackingTypeField(typ):
     nimtypeKind = ord(tyPureObject)
   else:
     nimtypeKind = ord(typ.kind)
-  
-  var size: PRope
-  if tfIncompleteStruct in typ.flags: size = toRope"void*"
+
+  var size: Rope
+  if tfIncompleteStruct in typ.flags: size = rope"void*"
+  elif m.compileToCpp: size = getTypeDesc(m, origType)
   else: size = getTypeDesc(m, typ)
-  appf(m.s[cfsTypeInit3], 
-       "$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n", 
-       [name, size, toRope(nimtypeKind), base])
+  addf(m.s[cfsTypeInit3],
+       "$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n",
+       [name, size, rope(nimtypeKind), base])
   # compute type flags for GC optimization
   var flags = 0
   if not containsGarbageCollectedRef(typ): flags = flags or 1
-  if not canFormAcycle(typ): flags = flags or 2        
+  if not canFormAcycle(typ): flags = flags or 2
   #else MessageOut("can contain a cycle: " & typeToString(typ))
-  if flags != 0: 
-    appf(m.s[cfsTypeInit3], "$1.flags = $2;$n", [name, toRope(flags)])
+  if flags != 0:
+    addf(m.s[cfsTypeInit3], "$1.flags = $2;$n", [name, rope(flags)])
   discard cgsym(m, "TNimType")
-  appf(m.s[cfsVars], "TNimType $1; /* $2 */$n", 
-       [name, toRope(typeToString(typ))])
+  addf(m.s[cfsVars], "TNimType $1; /* $2 */$n",
+       [name, rope(typeToString(typ))])
 
-proc genTypeInfoAux(m: BModule, typ: PType, name: PRope) = 
-  var base: PRope
-  if (sonsLen(typ) > 0) and (typ.sons[0] != nil): 
+proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope) =
+  var base: Rope
+  if (sonsLen(typ) > 0) and (typ.sons[0] != nil):
     base = genTypeInfo(m, typ.sons[0])
-  else: 
-    base = toRope("0")
-  genTypeInfoAuxBase(m, typ, name, base)
+  else:
+    base = rope("0")
+  genTypeInfoAuxBase(m, typ, origType, name, base)
 
-proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope = 
+proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope =
   # bugfix: we need to search the type that contains the discriminator:
   var objtype = objtype
   while lookupInRecord(objtype.n, d.name) == nil:
     objtype = objtype.sons[0]
-  if objtype.sym == nil: 
+  if objtype.sym == nil:
     internalError(d.info, "anonymous obj with discriminator")
-  result = ropef("NimDT_$1_$2", [
-    toRope(objtype.id), toRope(d.name.s.mangle)])
+  result = "NimDT_$1_$2" % [rope(objtype.id), rope(d.name.s.mangle)]
 
-proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): PRope = 
+proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope =
   discard cgsym(m, "TNimNode")
   var tmp = discriminatorTableName(m, objtype, d)
-  result = ropef("TNimNode* $1[$2];$n", [tmp, toRope(lengthOrd(d.typ)+1)])
+  result = "TNimNode* $1[$2];$n" % [tmp, rope(lengthOrd(d.typ)+1)]
 
-proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) = 
+proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: Rope) =
   case n.kind
-  of nkRecList: 
+  of nkRecList:
     var L = sonsLen(n)
-    if L == 1: 
+    if L == 1:
       genObjectFields(m, typ, n.sons[0], expr)
-    elif L > 0: 
+    elif L > 0:
       var tmp = getTempName()
-      appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, toRope(L)])
-      for i in countup(0, L-1): 
+      addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(L)])
+      for i in countup(0, L-1):
         var tmp2 = getNimNode(m)
-        appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, toRope(i), tmp2])
+        addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
         genObjectFields(m, typ, n.sons[i], tmp2)
-      appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n", 
-           [expr, toRope(L), tmp])
+      addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
+           [expr, rope(L), tmp])
     else:
-      appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n", [expr, toRope(L)])
-  of nkRecCase: 
+      addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n", [expr, rope(L)])
+  of nkRecCase:
     assert(n.sons[0].kind == nkSym)
     var field = n.sons[0].sym
     var tmp = discriminatorTableName(m, typ, field)
     var L = lengthOrd(field.typ)
     assert L > 0
-    appf(m.s[cfsTypeInit3], "$1.kind = 3;$n" &
+    addf(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(L)])
-    appf(m.s[cfsData], "TNimNode* $1[$2];$n", [tmp, toRope(L+1)])
-    for i in countup(1, sonsLen(n)-1): 
+        "$1.len = $7;$n", [expr, getTypeDesc(m, typ), field.loc.r,
+                           genTypeInfo(m, field.typ),
+                           makeCString(field.name.s),
+                           tmp, rope(L)])
+    addf(m.s[cfsData], "TNimNode* $1[$2];$n", [tmp, rope(L+1)])
+    for i in countup(1, sonsLen(n)-1):
       var b = n.sons[i]           # branch
       var tmp2 = getNimNode(m)
       genObjectFields(m, typ, lastSon(b), tmp2)
       case b.kind
-      of nkOfBranch: 
-        if sonsLen(b) < 2: 
+      of nkOfBranch:
+        if sonsLen(b) < 2:
           internalError(b.info, "genObjectFields; nkOfBranch broken")
-        for j in countup(0, sonsLen(b) - 2): 
-          if b.sons[j].kind == nkRange: 
+        for j in countup(0, sonsLen(b) - 2):
+          if b.sons[j].kind == nkRange:
             var x = int(getOrdValue(b.sons[j].sons[0]))
             var y = int(getOrdValue(b.sons[j].sons[1]))
-            while x <= y: 
-              appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, toRope(x), tmp2])
+            while x <= y:
+              addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(x), tmp2])
               inc(x)
-          else: 
-            appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", 
-                 [tmp, toRope(getOrdValue(b.sons[j])), tmp2])
-      of nkElse: 
-        appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", 
-             [tmp, toRope(L), tmp2])
+          else:
+            addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
+                 [tmp, rope(getOrdValue(b.sons[j])), tmp2])
+      of nkElse:
+        addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
+             [tmp, rope(L), tmp2])
       else: internalError(n.info, "genObjectFields(nkRecCase)")
-  of nkSym: 
+  of nkSym:
     var field = n.sym
-    appf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
+    addf(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), 
+        "$1.name = $5;$n", [expr, getTypeDesc(m, typ),
         field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)])
   else: internalError(n.info, "genObjectFields")
-  
-proc genObjectInfo(m: BModule, typ: PType, name: PRope) = 
-  if typ.kind == tyObject: genTypeInfoAux(m, typ, name)
-  else: genTypeInfoAuxBase(m, typ, name, toRope("0"))
+
+proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope) =
+  if typ.kind == tyObject: genTypeInfoAux(m, typ, origType, name)
+  else: genTypeInfoAuxBase(m, typ, origType, name, rope("0"))
   var tmp = getNimNode(m)
-  genObjectFields(m, typ, typ.n, tmp)
-  appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
+  if not isImportedCppType(typ):
+    genObjectFields(m, typ, typ.n, tmp)
+  addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
   var t = typ.sons[0]
   while t != nil:
     t = t.skipTypes(abstractInst)
     t.flags.incl tfObjHasKids
     t = t.sons[0]
 
-proc genTupleInfo(m: BModule, typ: PType, name: PRope) =
-  genTypeInfoAuxBase(m, typ, name, toRope("0"))
+proc genTupleInfo(m: BModule, typ: PType, name: Rope) =
+  genTypeInfoAuxBase(m, typ, typ, name, rope("0"))
   var expr = getNimNode(m)
   var length = sonsLen(typ)
-  if length > 0: 
+  if length > 0:
     var tmp = getTempName()
-    appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, toRope(length)])
-    for i in countup(0, length - 1): 
+    addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(length)])
+    for i in countup(0, length - 1):
       var a = typ.sons[i]
       var tmp2 = getNimNode(m)
-      appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, toRope(i), tmp2])
-      appf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
-          "$1.offset = offsetof($2, Field$3);$n" & 
+      addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
+      addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
+          "$1.offset = offsetof($2, Field$3);$n" &
           "$1.typ = $4;$n" &
-          "$1.name = \"Field$3\";$n", 
-           [tmp2, getTypeDesc(m, typ), toRope(i), genTypeInfo(m, a)])
-    appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n", 
-         [expr, toRope(length), tmp])
-  else: 
-    appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n", 
-         [expr, toRope(length)])
-  appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, expr])
-
-proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
+          "$1.name = \"Field$3\";$n",
+           [tmp2, getTypeDesc(m, typ), rope(i), genTypeInfo(m, a)])
+    addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
+         [expr, rope(length), tmp])
+  else:
+    addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n",
+         [expr, rope(length)])
+  addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, expr])
+
+proc genEnumInfo(m: BModule, typ: PType, name: Rope) =
   # Type information for enumerations is quite heavy, so we do some
   # optimizations here: The ``typ`` field is never set, as it is redundant
   # anyway. We generate a cstring array and a loop over it. Exceptional
   # positions will be reset after the loop.
-  genTypeInfoAux(m, typ, name)
+  genTypeInfoAux(m, typ, typ, name)
   var nodePtrs = getTempName()
   var length = sonsLen(typ.n)
-  appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", 
-       [nodePtrs, toRope(length)])
-  var enumNames, specialCases: PRope
+  addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
+       [nodePtrs, rope(length)])
+  var enumNames, specialCases: Rope
   var firstNimNode = m.typeNodes
   var hasHoles = false
-  for i in countup(0, length - 1): 
+  for i in countup(0, length - 1):
     assert(typ.n.sons[i].kind == nkSym)
     var field = typ.n.sons[i].sym
     var elemNode = getNimNode(m)
     if field.ast == nil:
       # no explicit string literal for the enum field, so use field.name:
-      app(enumNames, makeCString(field.name.s))
+      add(enumNames, makeCString(field.name.s))
     else:
-      app(enumNames, makeCString(field.ast.strVal))
-    if i < length - 1: app(enumNames, ", " & tnl)
+      add(enumNames, makeCString(field.ast.strVal))
+    if i < length - 1: add(enumNames, ", " & tnl)
     if field.position != i or tfEnumHasHoles in typ.flags:
-      appf(specialCases, "$1.offset = $2;$n", [elemNode, toRope(field.position)])
+      addf(specialCases, "$1.offset = $2;$n", [elemNode, rope(field.position)])
       hasHoles = true
   var enumArray = getTempName()
   var counter = getTempName()
-  appf(m.s[cfsTypeInit1], "NI $1;$n", [counter])
-  appf(m.s[cfsTypeInit1], "static char* NIM_CONST $1[$2] = {$n$3};$n", 
-       [enumArray, toRope(length), enumNames])
-  appf(m.s[cfsTypeInit3], "for ($1 = 0; $1 < $2; $1++) {$n" &
+  addf(m.s[cfsTypeInit1], "NI $1;$n", [counter])
+  addf(m.s[cfsTypeInit1], "static char* NIM_CONST $1[$2] = {$n$3};$n",
+       [enumArray, rope(length), enumNames])
+  addf(m.s[cfsTypeInit3], "for ($1 = 0; $1 < $2; $1++) {$n" &
       "$3[$1+$4].kind = 1;$n" & "$3[$1+$4].offset = $1;$n" &
-      "$3[$1+$4].name = $5[$1];$n" & "$6[$1] = &$3[$1+$4];$n" & "}$n", [counter, 
-      toRope(length), m.typeNodesName, toRope(firstNimNode), enumArray, nodePtrs])
-  app(m.s[cfsTypeInit3], specialCases)
-  appf(m.s[cfsTypeInit3], 
-       "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n$4.node = &$1;$n", 
-       [getNimNode(m), toRope(length), nodePtrs, name])
+      "$3[$1+$4].name = $5[$1];$n" & "$6[$1] = &$3[$1+$4];$n" & "}$n", [counter,
+      rope(length), m.typeNodesName, rope(firstNimNode), enumArray, nodePtrs])
+  add(m.s[cfsTypeInit3], specialCases)
+  addf(m.s[cfsTypeInit3],
+       "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n$4.node = &$1;$n",
+       [getNimNode(m), rope(length), nodePtrs, name])
   if hasHoles:
     # 1 << 2 is {ntfEnumHole}
-    appf(m.s[cfsTypeInit3], "$1.flags = 1<<2;$n", [name])
+    addf(m.s[cfsTypeInit3], "$1.flags = 1<<2;$n", [name])
 
-proc genSetInfo(m: BModule, typ: PType, name: PRope) = 
+proc genSetInfo(m: BModule, typ: PType, name: Rope) =
   assert(typ.sons[0] != nil)
-  genTypeInfoAux(m, typ, name)
+  genTypeInfoAux(m, typ, typ, name)
   var tmp = getNimNode(m)
-  appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n", 
-       [tmp, toRope(firstOrd(typ)), name])
+  addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n",
+       [tmp, rope(firstOrd(typ)), name])
 
-proc genArrayInfo(m: BModule, typ: PType, name: PRope) = 
-  genTypeInfoAuxBase(m, typ, name, genTypeInfo(m, typ.sons[1]))
+proc genArrayInfo(m: BModule, typ: PType, name: Rope) =
+  genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1]))
 
 proc fakeClosureType(owner: PSym): PType =
   # we generate the same RTTI as for a tuple[pointer, ref tuple[]]
@@ -898,18 +973,18 @@ type
 
 include ccgtrav
 
-proc genDeepCopyProc(m: BModule; s: PSym; result: PRope) =
+proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
   genProc(m, s)
-  appf(m.s[cfsTypeInit3], "$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
+  addf(m.s[cfsTypeInit3], "$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
      [result, s.loc.r])
 
-proc genTypeInfo(m: BModule, t: PType): PRope =
+proc genTypeInfo(m: BModule, t: PType): Rope =
   let origType = t
   var t = getUniqueType(t)
-  result = ropef("NTI$1", [toRope(t.id)])
+  result = "NTI$1" % [rope(t.id)]
   if containsOrIncl(m.typeInfoMarker, t.id):
-    return con("(&".toRope, result, ")".toRope)
-  
+    return "(&".rope & result & ")".rope
+
   # getUniqueType doesn't skip tyDistinct when that has an overriden operation:
   while t.kind == tyDistinct: t = t.lastSon
   let owner = t.skipTypes(typedescPtrs).owner.getModule
@@ -919,29 +994,29 @@ proc genTypeInfo(m: BModule, t: PType): PRope =
     # reference the type info as extern here
     discard cgsym(m, "TNimType")
     discard cgsym(m, "TNimNode")
-    appf(m.s[cfsVars], "extern TNimType $1; /* $2 */$n", 
-         [result, toRope(typeToString(t))])
-    return con("(&".toRope, result, ")".toRope)
+    addf(m.s[cfsVars], "extern TNimType $1; /* $2 */$n",
+         [result, rope(typeToString(t))])
+    return "(&".rope & result & ")".rope
   case t.kind
-  of tyEmpty: result = toRope"0"
+  of tyEmpty: result = rope"0"
   of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
-    genTypeInfoAuxBase(m, t, result, toRope"0")
+    genTypeInfoAuxBase(m, t, t, result, rope"0")
   of tyProc:
     if t.callConv != ccClosure:
-      genTypeInfoAuxBase(m, t, result, toRope"0")
+      genTypeInfoAuxBase(m, t, t, result, rope"0")
     else:
       genTupleInfo(m, fakeClosureType(t.owner), result)
   of tySequence, tyRef:
-    genTypeInfoAux(m, t, result)
+    genTypeInfoAux(m, t, t, result)
     if gSelectedGC >= gcMarkAndSweep:
       let markerProc = genTraverseProc(m, t, tiNew)
-      appf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
-  of tyPtr, tyRange: genTypeInfoAux(m, t, result)
+      addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
+  of tyPtr, tyRange: genTypeInfoAux(m, t, t, result)
   of tyArrayConstr, tyArray: genArrayInfo(m, t, result)
   of tySet: genSetInfo(m, t, result)
   of tyEnum: genEnumInfo(m, t, result)
-  of tyObject: genObjectInfo(m, t, result)
-  of tyTuple: 
+  of tyObject: genObjectInfo(m, t, origType, result)
+  of tyTuple:
     # if t.n != nil: genObjectInfo(m, t, result)
     # else:
     # BUGFIX: use consistently RTTI without proper field names; otherwise
@@ -951,8 +1026,8 @@ proc genTypeInfo(m: BModule, t: PType): PRope =
   if t.deepCopy != nil:
     genDeepCopyProc(m, t.deepCopy, result)
   elif origType.deepCopy != nil:
-    genDeepCopyProc(m, origType.deepCopy, result)  
-  result = con("(&".toRope, result, ")".toRope)
+    genDeepCopyProc(m, origType.deepCopy, result)
+  result = "(&".rope & result & ")".rope
 
-proc genTypeSection(m: BModule, n: PNode) = 
+proc genTypeSection(m: BModule, n: PNode) =
   discard
diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim
index 7396c0bf8..4e94c1867 100644
--- a/compiler/ccgutils.nim
+++ b/compiler/ccgutils.nim
@@ -9,31 +9,31 @@
 
 # This module declares some helpers for the C code generator.
 
-import 
-  ast, astalgo, ropes, lists, hashes, strutils, types, msgs, wordrecg, 
+import
+  ast, astalgo, ropes, lists, hashes, strutils, types, msgs, wordrecg,
   platform, trees
 
 proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
   case n.kind
-  of nkStmtList: 
-    for i in 0 .. < n.len: 
+  of nkStmtList:
+    for i in 0 .. < n.len:
       result = getPragmaStmt(n[i], w)
       if result != nil: break
   of nkPragma:
-    for i in 0 .. < n.len: 
+    for i in 0 .. < n.len:
       if whichPragma(n[i]) == w: return n[i]
   else: discard
 
 proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
   result = getPragmaStmt(n, w) != nil
 
-proc hashString*(s: string): BiggestInt = 
+proc hashString*(s: string): BiggestInt =
   # has to be the same algorithm as system.hashString!
-  if CPU[targetCPU].bit == 64: 
+  if CPU[targetCPU].bit == 64:
     # we have to use the same bitwidth
     # as the target CPU
     var b = 0'i64
-    for i in countup(0, len(s) - 1): 
+    for i in countup(0, len(s) - 1):
       b = b +% ord(s[i])
       b = b +% `shl`(b, 10)
       b = b xor `shr`(b, 6)
@@ -41,9 +41,9 @@ proc hashString*(s: string): BiggestInt =
     b = b xor `shr`(b, 11)
     b = b +% `shl`(b, 15)
     result = b
-  else: 
+  else:
     var a = 0'i32
-    for i in countup(0, len(s) - 1): 
+    for i in countup(0, len(s) - 1):
       a = a +% ord(s[i]).int32
       a = a +% `shl`(a, 10'i32)
       a = a xor `shr`(a, 6'i32)
@@ -52,11 +52,11 @@ proc hashString*(s: string): BiggestInt =
     a = a +% `shl`(a, 15'i32)
     result = a
 
-var 
+var
   gTypeTable: array[TTypeKind, TIdTable]
   gCanonicalTypes: array[TTypeKind, PType]
 
-proc initTypeTables() = 
+proc initTypeTables() =
   for i in countup(low(TTypeKind), high(TTypeKind)): initIdTable(gTypeTable[i])
 
 proc resetCaches* =
@@ -67,28 +67,39 @@ proc resetCaches* =
 
 when false:
   proc echoStats*() =
-    for i in countup(low(TTypeKind), high(TTypeKind)): 
+    for i in countup(low(TTypeKind), high(TTypeKind)):
       echo i, " ", gTypeTable[i].counter
-  
-proc getUniqueType*(key: PType): PType = 
+
+proc slowSearch(key: PType; k: TTypeKind): PType =
+  # tuples are quite horrible as C does not support them directly and
+  # tuple[string, string] is a (strange) subtype of
+  # tuple[nameA, nameB: string]. This bites us here, so we
+  # use 'sameBackendType' instead of 'sameType'.
+  if idTableHasObjectAsKey(gTypeTable[k], key): return key
+  for h in countup(0, high(gTypeTable[k].data)):
+    var t = PType(gTypeTable[k].data[h].key)
+    if t != nil and sameBackendType(t, key):
+      return t
+  idTablePut(gTypeTable[k], key, key)
+  result = key
+
+proc getUniqueType*(key: PType): PType =
   # this is a hotspot in the compiler!
-  if key == nil: return 
+  if key == nil: return
   var k = key.kind
   case k
-  of  tyBool, tyChar, 
-      tyInt..tyUInt64:
+  of tyBool, tyChar, tyInt..tyUInt64:
     # no canonicalization for integral types, so that e.g. ``pid_t`` is
     # produced instead of ``NI``.
     result = key
-  of  tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString, 
+  of  tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString,
       tyCString, tyNone, tyBigNum:
     result = gCanonicalTypes[k]
     if result == nil:
       gCanonicalTypes[k] = key
       result = key
-  of tyTypeDesc, tyTypeClasses, tyGenericParam,
-     tyFromExpr, tyFieldAccessor:
-    internalError("GetUniqueType")
+  of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor:
+    internalError("getUniqueType")
   of tyDistinct:
     if key.deepCopy != nil: result = key
     else: result = getUniqueType(lastSon(key))
@@ -98,42 +109,39 @@ proc getUniqueType*(key: PType): PType =
     #if obj.sym != nil and obj.sym.name.s == "TOption":
     #  echo "for ", typeToString(key), " I returned "
     #  debug result
-  of tyArrayConstr, tyGenericInvokation, tyGenericBody,
+  of tyPtr, tyRef, tyVar:
+    let elemType = lastSon(key)
+    if elemType.kind in {tyBool, tyChar, tyInt..tyUInt64}:
+      # no canonicalization for integral types, so that e.g. ``ptr pid_t`` is
+      # produced instead of ``ptr NI``.
+      result = key
+    else:
+      result = slowSearch(key, k)
+  of tyArrayConstr, tyGenericInvocation, tyGenericBody,
      tyOpenArray, tyArray, tySet, tyRange, tyTuple,
-     tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar:
-    # tuples are quite horrible as C does not support them directly and
-    # tuple[string, string] is a (strange) subtype of
-    # tuple[nameA, nameB: string]. This bites us here, so we 
-    # use 'sameBackendType' instead of 'sameType'.
-
+     tySequence, tyForward, tyVarargs, tyProxy:
     # we have to do a slow linear search because types may need
     # to be compared by their structure:
-    if idTableHasObjectAsKey(gTypeTable[k], key): return key 
-    for h in countup(0, high(gTypeTable[k].data)): 
-      var t = PType(gTypeTable[k].data[h].key)
-      if t != nil and sameBackendType(t, key): 
-        return t
-    idTablePut(gTypeTable[k], key, key)
-    result = key
+    result = slowSearch(key, k)
   of tyObject:
     if tfFromGeneric notin key.flags:
       # fast case; lookup per id suffices:
       result = PType(idTableGet(gTypeTable[k], key))
-      if result == nil: 
+      if result == nil:
         idTablePut(gTypeTable[k], key, key)
         result = key
     else:
       # ugly slow case: need to compare by structure
       if idTableHasObjectAsKey(gTypeTable[k], key): return key
-      for h in countup(0, high(gTypeTable[k].data)): 
+      for h in countup(0, high(gTypeTable[k].data)):
         var t = PType(gTypeTable[k].data[h].key)
-        if t != nil and sameType(t, key): 
+        if t != nil and sameBackendType(t, key):
           return t
       idTablePut(gTypeTable[k], key, key)
-      result = key    
+      result = key
   of tyEnum:
     result = PType(idTableGet(gTypeTable[k], key))
-    if result == nil: 
+    if result == nil:
       idTablePut(gTypeTable[k], key, key)
       result = key
   of tyProc:
@@ -141,24 +149,18 @@ proc getUniqueType*(key: PType): PType =
       result = key
     else:
       # ugh, we need the canon here:
-      if idTableHasObjectAsKey(gTypeTable[k], key): return key 
-      for h in countup(0, high(gTypeTable[k].data)): 
-        var t = PType(gTypeTable[k].data[h].key)
-        if t != nil and sameBackendType(t, key): 
-          return t
-      idTablePut(gTypeTable[k], key, key)
-      result = key
-      
-proc tableGetType*(tab: TIdTable, key: PType): RootRef = 
+      result = slowSearch(key, k)
+
+proc tableGetType*(tab: TIdTable, key: PType): RootRef =
   # returns nil if we need to declare this type
   result = idTableGet(tab, key)
-  if (result == nil) and (tab.counter > 0): 
+  if (result == nil) and (tab.counter > 0):
     # we have to do a slow linear search because types may need
     # to be compared by their structure:
-    for h in countup(0, high(tab.data)): 
+    for h in countup(0, high(tab.data)):
       var t = PType(tab.data[h].key)
-      if t != nil: 
-        if sameType(t, key): 
+      if t != nil:
+        if sameType(t, key):
           return tab.data[h].val
 
 proc makeSingleLineCString*(s: string): string =
@@ -191,20 +193,20 @@ proc mangle*(name: string): string =
     else:
       add(result, "HEX" & toHex(ord(c), 2))
 
-proc makeLLVMString*(s: string): PRope = 
+proc makeLLVMString*(s: string): Rope =
   const MaxLineLength = 64
   result = nil
   var res = "c\""
-  for i in countup(0, len(s) - 1): 
-    if (i + 1) mod MaxLineLength == 0: 
-      app(result, toRope(res))
+  for i in countup(0, len(s) - 1):
+    if (i + 1) mod MaxLineLength == 0:
+      add(result, rope(res))
       setLen(res, 0)
     case s[i]
-    of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\': 
+    of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\':
       add(res, '\\')
       add(res, toHex(ord(s[i]), 2))
     else: add(res, s[i])
   add(res, "\\00\"")
-  app(result, toRope(res))
+  add(result, rope(res))
 
 initTypeTables()
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index c645b81aa..da9c6f653 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -9,14 +9,16 @@
 
 ## This module implements the C code generator.
 
-import 
-  ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
+import
+  ast, astalgo, hashes, trees, platform, magicsys, extccomp,
   options, intsets,
   nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
-  times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, condsyms,
+  ropes, math, passes, rodread, wordrecg, treetab, cgmeth, condsyms,
   rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings,
   semparallel
 
+import strutils except `%` # collides with ropes.`%`
+
 when options.hasTinyCBackend:
   import tccgen
 
@@ -25,16 +27,7 @@ when options.hasTinyCBackend:
 var
   generatedHeader: BModule
 
-proc ropeff(cformat, llvmformat: string, args: varargs[PRope]): PRope = 
-  if gCmd == cmdCompileToLLVM: result = ropef(llvmformat, args)
-  else: result = ropef(cformat, args)
-  
-proc appff(dest: var PRope, cformat, llvmformat: string, 
-           args: varargs[PRope]) = 
-  if gCmd == cmdCompileToLLVM: appf(dest, llvmformat, args)
-  else: appf(dest, cformat, args)
-  
-proc addForwardedProc(m: BModule, prc: PSym) = 
+proc addForwardedProc(m: BModule, prc: PSym) =
   m.forwardedProcs.add(prc)
   inc(gForwardedProcsCounter)
 
@@ -42,7 +35,7 @@ proc getCgenModule(s: PSym): BModule =
   result = if s.position >= 0 and s.position < gModules.len: gModules[s.position]
            else: nil
 
-proc findPendingModule(m: BModule, s: PSym): BModule = 
+proc findPendingModule(m: BModule, s: PSym): BModule =
   var ms = getModule(s)
   result = gModules[ms.position]
 
@@ -50,21 +43,21 @@ proc emitLazily(s: PSym): bool {.inline.} =
   result = optDeadCodeElim in gGlobalOptions or
            sfDeadCodeElim in getModule(s).flags
 
-proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) = 
+proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
   result.k = k
   result.s = s
-  result.t = getUniqueType(typ)
+  result.t = typ
   result.r = nil
   result.flags = {}
 
-proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) = 
+proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: Rope, s: TStorageLoc) =
   # fills the loc if it is not already initialized
-  if a.k == locNone: 
+  if a.k == locNone:
     a.k = k
-    a.t = getUniqueType(typ)
+    a.t = typ
     a.s = s
     if a.r == nil: a.r = r
-  
+
 proc isSimpleConst(typ: PType): bool =
   let t = skipTypes(typ, abstractVar)
   result = t.kind notin
@@ -76,44 +69,44 @@ proc useStringh(m: BModule) =
     m.includesStringh = true
     discard lists.includeStr(m.headerFiles, "<string.h>")
 
-proc useHeader(m: BModule, sym: PSym) = 
-  if lfHeader in sym.loc.flags: 
+proc useHeader(m: BModule, sym: PSym) =
+  if lfHeader in sym.loc.flags:
     assert(sym.annex != nil)
     discard lists.includeStr(m.headerFiles, getStr(sym.annex.path))
 
-proc cgsym(m: BModule, name: string): PRope
+proc cgsym(m: BModule, name: string): Rope
 
-proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope = 
+proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
   var i = 0
   var length = len(frmt)
   result = nil
   var num = 0
-  while i < length: 
-    if frmt[i] == '$': 
+  while i < length:
+    if frmt[i] == '$':
       inc(i)                  # skip '$'
       case frmt[i]
-      of '$': 
-        app(result, "$")
+      of '$':
+        add(result, "$")
         inc(i)
-      of '#': 
+      of '#':
         inc(i)
-        app(result, args[num])
+        add(result, args[num])
         inc(num)
-      of '0'..'9': 
+      of '0'..'9':
         var j = 0
-        while true: 
+        while true:
           j = (j * 10) + ord(frmt[i]) - ord('0')
           inc(i)
-          if i >= length or not (frmt[i] in {'0'..'9'}): break 
+          if i >= length or not (frmt[i] in {'0'..'9'}): break
         num = j
-        if j > high(args) + 1: 
+        if j > high(args) + 1:
           internalError("ropes: invalid format string $" & $j)
-        app(result, args[j-1])
+        add(result, args[j-1])
       of 'n':
-        if optLineDir notin gOptions: app(result, rnl)
+        if optLineDir notin gOptions: add(result, rnl)
         inc(i)
-      of 'N': 
-        app(result, rnl)
+      of 'N':
+        add(result, rnl)
         inc(i)
       else: internalError("ropes: invalid format string $" & frmt[i])
     elif frmt[i] == '#' and frmt[i+1] in IdentStartChars:
@@ -122,174 +115,102 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
       while frmt[j] in IdentChars: inc(j)
       var ident = substr(frmt, i, j-1)
       i = j
-      app(result, cgsym(m, ident))
+      add(result, cgsym(m, ident))
     elif frmt[i] == '#' and frmt[i+1] == '$':
       inc(i, 2)
       var j = 0
-      while frmt[i] in Digits: 
+      while frmt[i] in Digits:
         j = (j * 10) + ord(frmt[i]) - ord('0')
         inc(i)
-      app(result, cgsym(m, args[j-1].ropeToStr))
+      add(result, cgsym(m, $args[j-1]))
     var start = i
-    while i < length: 
+    while i < length:
       if frmt[i] != '$' and frmt[i] != '#': inc(i)
-      else: break 
-    if i - 1 >= start: 
-      app(result, substr(frmt, start, i - 1))
-
-const compileTimeRopeFmt = false
-
-when compileTimeRopeFmt:
-  import macros
-
-  type TFmtFragmentKind = enum
-    ffSym,
-    ffLit,
-    ffParam
-
-  type TFragment = object
-    case kind: TFmtFragmentKind
-    of ffSym, ffLit:
-      value: string
-    of ffParam:
-      intValue: int
-
-  iterator fmtStringFragments(s: string): tuple[kind: TFmtFragmentKind,
-                                                value: string,
-                                                intValue: int] =
-    # This is a bit less featured version of the ropecg's algorithm
-    # (be careful when replacing ropecg calls)
-    var
-      i = 0
-      length = s.len
+      else: break
+    if i - 1 >= start:
+      add(result, substr(frmt, start, i - 1))
 
-    while i < length:
-      var start = i
-      case s[i]
-      of '$':
-        let n = s[i+1]
-        case n
-        of '$':
-          inc i, 2
-        of '0'..'9':
-          # XXX: use the new case object construction syntax when it's ready
-          yield (kind: ffParam, value: "", intValue: n.ord - ord('1'))
-          inc i, 2
-          start = i
-        else:
-          inc i
-      of '#':
-        inc i
-        var j = i
-        while s[i] in IdentChars: inc i
-        yield (kind: ffSym, value: substr(s, j, i-1), intValue: 0)
-        start = i
-      else: discard
-
-      while i < length:
-        if s[i] != '$' and s[i] != '#': inc i
-        else: break
-
-      if i - 1 >= start:
-        yield (kind: ffLit, value: substr(s, start, i-1), intValue: 0)
-
-  macro rfmt(m: BModule, fmt: static[string], args: varargs[PRope]): expr =
-    ## Experimental optimized rope-formatting operator
-    ## The run-time code it produces will be very fast, but will it speed up
-    ## the compilation of nimrod itself or will the macro execution time
-    ## offset the gains?
-    result = newCall(bindSym"ropeConcat")
-    for frag in fmtStringFragments(fmt):
-      case frag.kind
-      of ffSym:
-        result.add(newCall(bindSym"cgsym", m, newStrLitNode(frag.value)))
-      of ffLit:
-        result.add(newCall(bindSym"~", newStrLitNode(frag.value)))
-      of ffParam:
-        result.add(args[frag.intValue])
-else:
-  template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr =
-    ropecg(m, fmt, args)
-
-proc appcg(m: BModule, c: var PRope, frmt: TFormatStr, 
-           args: varargs[PRope]) = 
-  app(c, ropecg(m, frmt, args))
-
-proc appcg(m: BModule, s: TCFileSection, frmt: TFormatStr, 
-           args: varargs[PRope]) = 
-  app(m.s[s], ropecg(m, frmt, args))
-
-proc appcg(p: BProc, s: TCProcSection, frmt: TFormatStr, 
-           args: varargs[PRope]) = 
-  app(p.s(s), ropecg(p.module, frmt, args))
-
-var indent = "\t".toRope
-proc indentLine(p: BProc, r: PRope): PRope =
+template rfmt(m: BModule, fmt: string, args: varargs[Rope]): expr =
+  ropecg(m, fmt, args)
+
+proc appcg(m: BModule, c: var Rope, frmt: FormatStr,
+           args: varargs[Rope]) =
+  add(c, ropecg(m, frmt, args))
+
+proc appcg(m: BModule, s: TCFileSection, frmt: FormatStr,
+           args: varargs[Rope]) =
+  add(m.s[s], ropecg(m, frmt, args))
+
+proc appcg(p: BProc, s: TCProcSection, frmt: FormatStr,
+           args: varargs[Rope]) =
+  add(p.s(s), ropecg(p.module, frmt, args))
+
+var indent = "\t".rope
+proc indentLine(p: BProc, r: Rope): Rope =
   result = r
   for i in countup(0, p.blocks.len-1): prepend(result, indent)
-  
-proc line(p: BProc, s: TCProcSection, r: PRope) =
-  app(p.s(s), indentLine(p, r))
+
+proc line(p: BProc, s: TCProcSection, r: Rope) =
+  add(p.s(s), indentLine(p, r))
 
 proc line(p: BProc, s: TCProcSection, r: string) =
-  app(p.s(s), indentLine(p, r.toRope))
-
-proc lineF(p: BProc, s: TCProcSection, frmt: TFormatStr,
-              args: varargs[PRope]) =
-  app(p.s(s), indentLine(p, ropef(frmt, args)))
-
-proc lineCg(p: BProc, s: TCProcSection, frmt: TFormatStr,
-               args: varargs[PRope]) =
-  app(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
-
-when compileTimeRopeFmt:
-  template linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr,
-                   args: varargs[PRope]) =
-    line(p, s, rfmt(p.module, frmt, args))
-else:
-  proc linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr,
-               args: varargs[PRope]) =
-    app(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
-
-proc appLineCg(p: BProc, r: var PRope, frmt: TFormatStr,
-               args: varargs[PRope]) =
-  app(r, indentLine(p, ropecg(p.module, frmt, args)))
-
-proc lineFF(p: BProc, s: TCProcSection, cformat, llvmformat: string,
-               args: varargs[PRope]) =
-  if gCmd == cmdCompileToLLVM: lineF(p, s, llvmformat, args)
-  else: lineF(p, s, cformat, args)
+  add(p.s(s), indentLine(p, r.rope))
+
+proc lineF(p: BProc, s: TCProcSection, frmt: FormatStr,
+              args: openarray[Rope]) =
+  add(p.s(s), indentLine(p, frmt % args))
+
+proc lineCg(p: BProc, s: TCProcSection, frmt: FormatStr,
+               args: varargs[Rope]) =
+  add(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
+
+proc linefmt(p: BProc, s: TCProcSection, frmt: FormatStr,
+             args: varargs[Rope]) =
+  add(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
+
+proc appLineCg(p: BProc, r: var Rope, frmt: FormatStr,
+               args: varargs[Rope]) =
+  add(r, indentLine(p, ropecg(p.module, frmt, args)))
 
 proc safeLineNm(info: TLineInfo): int =
   result = toLinenumber(info)
   if result < 0: result = 0 # negative numbers are not allowed in #line
 
-proc genCLineDir(r: var PRope, filename: string, line: int) =
+proc genCLineDir(r: var Rope, filename: string, line: int) =
   assert line >= 0
   if optLineDir in gOptions:
-    appff(r, "$N#line $2 $1$N", "; line $2 \"$1\"$n",
-          [toRope(makeSingleLineCString(filename)), toRope(line)])
+    addf(r, "$N#line $2 $1$N",
+        [rope(makeSingleLineCString(filename)), rope(line)])
 
-proc genCLineDir(r: var PRope, info: TLineInfo) = 
+proc genCLineDir(r: var Rope, info: TLineInfo) =
   genCLineDir(r, info.toFullPath, info.safeLineNm)
 
+proc freshLineInfo(p: BProc; info: TLineInfo): bool =
+  if p.lastLineInfo.line != info.line or
+     p.lastLineInfo.fileIndex != info.fileIndex:
+    p.lastLineInfo.line = info.line
+    p.lastLineInfo.fileIndex = info.fileIndex
+    result = true
+
 proc genLineDir(p: BProc, t: PNode) =
   var line = t.info.safeLineNm
   if optEmbedOrigSrc in gGlobalOptions:
-    app(p.s(cpsStmts), con(~"//", t.info.sourceLine, rnl))
+    add(p.s(cpsStmts), ~"//" & t.info.sourceLine & rnl)
   genCLineDir(p.s(cpsStmts), t.info.toFullPath, line)
   if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
       (p.prc == nil or sfPure notin p.prc.flags):
-    linefmt(p, cpsStmts, "#endb($1, $2);$n",
-            line.toRope, makeCString(toFilename(t.info)))
+    if freshLineInfo(p, t.info):
+      linefmt(p, cpsStmts, "#endb($1, $2);$n",
+              line.rope, makeCString(toFilename(t.info)))
   elif ({optLineTrace, optStackTrace} * p.options ==
       {optLineTrace, optStackTrace}) and
       (p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex >= 0:
-    linefmt(p, cpsStmts, "nimln($1, $2);$n",
-            line.toRope, t.info.quotedFilename)
+    if freshLineInfo(p, t.info):
+      linefmt(p, cpsStmts, "nimln($1, $2);$n",
+              line.rope, t.info.quotedFilename)
 
 proc postStmtActions(p: BProc) {.inline.} =
-  app(p.s(cpsStmts), p.module.injectStmt)
+  add(p.s(cpsStmts), p.module.injectStmt)
 
 proc accessThreadLocalVar(p: BProc, s: PSym)
 proc emulatedThreadVars(): bool {.inline.}
@@ -302,21 +223,21 @@ include "ccgtypes.nim"
 
 # ------------------------------ Manager of temporaries ------------------
 
-proc rdLoc(a: TLoc): PRope =
+proc rdLoc(a: TLoc): Rope =
   # 'read' location (deref if indirect)
   result = a.r
-  if lfIndirect in a.flags: result = ropef("(*$1)", [result])
+  if lfIndirect in a.flags: result = "(*$1)" % [result]
 
-proc addrLoc(a: TLoc): PRope =
+proc addrLoc(a: TLoc): Rope =
   result = a.r
   if lfIndirect notin a.flags and mapType(a.t) != ctArray:
-    result = con("(&", result).con(")")
+    result = "(&" & result & ")"
 
-proc rdCharLoc(a: TLoc): PRope =
+proc rdCharLoc(a: TLoc): Rope =
   # read a location that may need a char-cast:
   result = rdLoc(a)
   if skipTypes(a.t, abstractRange).kind == tyChar:
-    result = ropef("((NU8)($1))", [result])
+    result = "((NU8)($1))" % [result]
 
 proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
                    takeAddr: bool) =
@@ -325,11 +246,11 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
     discard
   of frHeader:
     var r = rdLoc(a)
-    if not takeAddr: r = ropef("(*$1)", [r])
+    if not takeAddr: r = "(*$1)" % [r]
     var s = skipTypes(t, abstractInst)
     if not p.module.compileToCpp:
       while (s.kind == tyObject) and (s.sons[0] != nil):
-        app(r, ".Sup")
+        add(r, ".Sup")
         s = skipTypes(s.sons[0], abstractInst)
     linefmt(p, section, "$1.m_type = $2;$n", r, genTypeInfo(p.module, t))
   of frEmbedded:
@@ -351,11 +272,13 @@ proc isComplexValueType(t: PType): bool {.inline.} =
 
 proc resetLoc(p: BProc, loc: var TLoc) =
   let containsGcRef = containsGarbageCollectedRef(loc.t)
-  if not isComplexValueType(skipTypes(loc.t, abstractVarRange)):
+  let typ = skipTypes(loc.t, abstractVarRange)
+  if isImportedCppType(typ): return
+  if not isComplexValueType(typ):
     if containsGcRef:
       var nilLoc: TLoc
       initLoc(nilLoc, locTemp, loc.t, OnStack)
-      nilLoc.r = toRope("NIM_NIL")
+      nilLoc.r = rope("NIM_NIL")
       genRefAssign(p, loc, nilLoc, {afSrcIsNil})
     else:
       linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
@@ -372,41 +295,40 @@ proc resetLoc(p: BProc, loc: var TLoc) =
       useStringh(p.module)
       linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n",
               addrLoc(loc), rdLoc(loc))
-      # XXX: We can be extra clever here and call memset only 
+      # XXX: We can be extra clever here and call memset only
       # on the bytes following the m_type field?
       genObjectInit(p, cpsStmts, loc.t, loc, true)
 
 proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
-  if not isComplexValueType(skipTypes(loc.t, abstractRange)):
+  let typ = skipTypes(loc.t, abstractRange)
+  if not isComplexValueType(typ):
     linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
   else:
     if not isTemp or containsGarbageCollectedRef(loc.t):
       # don't use memset for temporary values for performance if we can
       # avoid it:
-      useStringh(p.module)
-      linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n",
-              addrLoc(loc), rdLoc(loc))
+      if not isImportedCppType(typ):
+        useStringh(p.module)
+        linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n",
+                addrLoc(loc), rdLoc(loc))
     genObjectInit(p, cpsStmts, loc.t, loc, true)
 
 proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
   if sfNoInit notin v.flags:
     # we know it is a local variable and thus on the stack!
     # If ``not immediateAsgn`` it is not initialized in a binding like
-    # ``var v = X`` and thus we need to init it. 
+    # ``var v = X`` and thus we need to init it.
     # If ``v`` contains a GC-ref we may pass it to ``unsureAsgnRef`` somehow
     # which requires initialization. However this can really only happen if
-    # ``var v = X()`` gets transformed into ``X(&v)``. 
+    # ``var v = X()`` gets transformed into ``X(&v)``.
     # Nowadays the logic in ccgcalls deals with this case however.
     if not immediateAsgn:
       constructLoc(p, v.loc)
 
-proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = 
+proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
   inc(p.labels)
-  if gCmd == cmdCompileToLLVM: 
-    result.r = con("%LOC", toRope(p.labels))
-  else: 
-    result.r = con("LOC", toRope(p.labels))
-    linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
+  result.r = "LOC" & rope(p.labels)
+  linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
   result.k = locTemp
   #result.a = - 1
   result.t = getUniqueType(t)
@@ -420,9 +342,9 @@ proc keepAlive(p: BProc, toKeepAlive: TLoc) =
     # of interior pointers instead
     if optRefcGC notin gGlobalOptions: return
     var result: TLoc
-    var fid = toRope(p.gcFrameId)
-    result.r = con("GCFRAME.F", fid)
-    appf(p.gcFrameType, "  $1 F$2;$n",
+    var fid = rope(p.gcFrameId)
+    result.r = "GCFRAME.F" & fid
+    addf(p.gcFrameType, "  $1 F$2;$n",
         [getTypeDesc(p.module, toKeepAlive.t), fid])
     inc(p.gcFrameId)
     result.k = locTemp
@@ -439,137 +361,105 @@ proc keepAlive(p: BProc, toKeepAlive: TLoc) =
            "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
            addrLoc(result), addrLoc(toKeepAlive), rdLoc(result))
 
-proc initGCFrame(p: BProc): PRope =
-  if p.gcFrameId > 0: result = ropef("struct {$1} GCFRAME;$n", p.gcFrameType)
+proc initGCFrame(p: BProc): Rope =
+  if p.gcFrameId > 0: result = "struct {$1} GCFRAME;$n" % [p.gcFrameType]
 
-proc deinitGCFrame(p: BProc): PRope =
+proc deinitGCFrame(p: BProc): Rope =
   if p.gcFrameId > 0:
     result = ropecg(p.module,
                     "if (((NU)&GCFRAME) < 4096) #nimGCFrame(&GCFRAME);$n")
 
-proc cstringLit(p: BProc, r: var PRope, s: string): PRope = 
-  if gCmd == cmdCompileToLLVM: 
-    inc(p.module.labels)
-    inc(p.labels)
-    result = ropef("%LOC$1", [toRope(p.labels)])
-    appf(p.module.s[cfsData], "@C$1 = private constant [$2 x i8] $3$n", 
-         [toRope(p.module.labels), toRope(len(s)), makeLLVMString(s)])
-    appf(r, "$1 = getelementptr [$2 x i8]* @C$3, %NI 0, %NI 0$n", 
-         [result, toRope(len(s)), toRope(p.module.labels)])
-  else: 
-    result = makeCString(s)
-  
-proc cstringLit(m: BModule, r: var PRope, s: string): PRope = 
-  if gCmd == cmdCompileToLLVM: 
-    inc(m.labels, 2)
-    result = ropef("%MOC$1", [toRope(m.labels - 1)])
-    appf(m.s[cfsData], "@MOC$1 = private constant [$2 x i8] $3$n", 
-         [toRope(m.labels), toRope(len(s)), makeLLVMString(s)])
-    appf(r, "$1 = getelementptr [$2 x i8]* @MOC$3, %NI 0, %NI 0$n", 
-         [result, toRope(len(s)), toRope(m.labels)])
-  else: 
-    result = makeCString(s)
-  
-proc allocParam(p: BProc, s: PSym) = 
-  assert(s.kind == skParam)
-  if lfParamCopy notin s.loc.flags: 
-    inc(p.labels)
-    var tmp = con("%LOC", toRope(p.labels))
-    incl(s.loc.flags, lfParamCopy)
-    incl(s.loc.flags, lfIndirect)
-    lineF(p, cpsInit, "$1 = alloca $3$n" & "store $3 $2, $3* $1$n",
-         [tmp, s.loc.r, getTypeDesc(p.module, s.loc.t)])
-    s.loc.r = tmp
-
-proc localDebugInfo(p: BProc, s: PSym) = 
-  if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return 
+proc localDebugInfo(p: BProc, s: PSym) =
+  if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return
   # XXX work around a bug: No type information for open arrays possible:
   if skipTypes(s.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: return
-  var a = con("&", s.loc.r)
+  var a = "&" & s.loc.r
   if s.kind == skParam and ccgIntroducedPtr(s): a = s.loc.r
   lineF(p, cpsInit,
        "F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n",
-       [p.maxFrameLen.toRope, makeCString(normalize(s.name.s)), a,
+       [p.maxFrameLen.rope, makeCString(normalize(s.name.s)), a,
         genTypeInfo(p.module, s.loc.t)])
   inc(p.maxFrameLen)
   inc p.blocks[p.blocks.len-1].frameLen
 
-proc assignLocalVar(p: BProc, s: PSym) = 
-  #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!
-  if s.loc.k == locNone: 
+proc localVarDecl(p: BProc; s: PSym): Rope =
+  if s.loc.k == locNone:
     fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
     if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
-  var decl = getTypeDesc(p.module, s.loc.t)
+  result = getTypeDesc(p.module, s.loc.t)
   if s.constraint.isNil:
-    if sfRegister in s.flags: app(decl, " register")
+    if sfRegister in s.flags: add(result, " register")
     #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
-    #  app(decl, " GC_GUARD")
-    if sfVolatile in s.flags: app(decl, " volatile")
-    appf(decl, " $1;$n", [s.loc.r])
+    #  add(decl, " GC_GUARD")
+    if sfVolatile in s.flags: add(result, " volatile")
+    add(result, " ")
+    add(result, s.loc.r)
   else:
-    decl = ropef(s.cgDeclFrmt & ";$n", decl, s.loc.r)
+    result = s.cgDeclFrmt % [result, s.loc.r]
+
+proc assignLocalVar(p: BProc, s: PSym) =
+  #assert(s.loc.k == locNone) # not yet assigned
+  # this need not be fulfilled for inline procs; they are regenerated
+  # for each module that uses them!
+  let decl = localVarDecl(p, s) & ";" & tnl
   line(p, cpsLocals, decl)
   localDebugInfo(p, s)
 
 include ccgthreadvars
 
 proc varInDynamicLib(m: BModule, sym: PSym)
-proc mangleDynLibProc(sym: PSym): PRope
+proc mangleDynLibProc(sym: PSym): Rope
 
-proc assignGlobalVar(p: BProc, s: PSym) = 
-  if s.loc.k == locNone: 
+proc assignGlobalVar(p: BProc, s: PSym) =
+  if s.loc.k == locNone:
     fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), OnHeap)
-  
+
   if lfDynamicLib in s.loc.flags:
     var q = findPendingModule(p.module, s)
-    if q != nil and not containsOrIncl(q.declaredThings, s.id): 
+    if q != nil and not containsOrIncl(q.declaredThings, s.id):
       varInDynamicLib(q, s)
     else:
       s.loc.r = mangleDynLibProc(s)
     return
   useHeader(p.module, s)
   if lfNoDecl in s.loc.flags: return
-  if sfThread in s.flags: 
+  if sfThread in s.flags:
     declareThreadVar(p.module, s, sfImportc in s.flags)
-  else: 
-    var decl: PRope = nil
+  else:
+    var decl: Rope = nil
     var td = getTypeDesc(p.module, s.loc.t)
     if s.constraint.isNil:
-      if sfImportc in s.flags: app(decl, "extern ")
-      app(decl, td)
-      if sfRegister in s.flags: app(decl, " register")
-      if sfVolatile in s.flags: app(decl, " volatile")
-      appf(decl, " $1;$n", [s.loc.r])
+      if sfImportc in s.flags: add(decl, "extern ")
+      add(decl, td)
+      if sfRegister in s.flags: add(decl, " register")
+      if sfVolatile in s.flags: add(decl, " volatile")
+      addf(decl, " $1;$n", [s.loc.r])
     else:
-      decl = ropef(s.cgDeclFrmt & ";$n", td, s.loc.r)
-    app(p.module.s[cfsVars], decl)
+      decl = (s.cgDeclFrmt & ";$n") % [td, s.loc.r]
+    add(p.module.s[cfsVars], decl)
   if p.withinLoop > 0:
     # fixes tests/run/tzeroarray:
     resetLoc(p, s.loc)
   if p.module.module.options * {optStackTrace, optEndb} ==
-                               {optStackTrace, optEndb}: 
-    appcg(p.module, p.module.s[cfsDebugInit], 
-          "#dbgRegisterGlobal($1, &$2, $3);$n", 
-         [cstringLit(p, p.module.s[cfsDebugInit], 
-          normalize(s.owner.name.s & '.' & s.name.s)), 
+                               {optStackTrace, optEndb}:
+    appcg(p.module, p.module.s[cfsDebugInit],
+          "#dbgRegisterGlobal($1, &$2, $3);$n",
+         [makeCString(normalize(s.owner.name.s & '.' & s.name.s)),
           s.loc.r, genTypeInfo(p.module, s.typ)])
-  
-proc assignParam(p: BProc, s: PSym) = 
+
+proc assignParam(p: BProc, s: PSym) =
   assert(s.loc.r != nil)
-  if sfAddrTaken in s.flags and gCmd == cmdCompileToLLVM: allocParam(p, s)
   localDebugInfo(p, s)
 
-proc fillProcLoc(sym: PSym) = 
-  if sym.loc.k == locNone: 
+proc fillProcLoc(sym: PSym) =
+  if sym.loc.k == locNone:
     fillLoc(sym.loc, locProc, sym.typ, mangleName(sym), OnStack)
-  
-proc getLabel(p: BProc): TLabel = 
+
+proc getLabel(p: BProc): TLabel =
   inc(p.labels)
-  result = con("LA", toRope(p.labels))
+  result = "LA" & rope(p.labels)
 
-proc fixLabel(p: BProc, labl: TLabel) = 
+proc fixLabel(p: BProc, labl: TLabel) =
   lineF(p, cpsStmts, "$1: ;$n", [labl])
 
 proc genVarPrototype(m: BModule, sym: PSym)
@@ -579,75 +469,80 @@ proc expr(p: BProc, n: PNode, d: var TLoc)
 proc genProcPrototype(m: BModule, sym: PSym)
 proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
 proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
-proc intLiteral(i: BiggestInt): PRope
-proc genLiteral(p: BProc, n: PNode): PRope
+proc intLiteral(i: BiggestInt): Rope
+proc genLiteral(p: BProc, n: PNode): Rope
+proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope
 
 proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
   initLoc(result, locNone, e.typ, OnUnknown)
   expr(p, e, result)
 
-proc lenField(p: BProc): PRope =
-  result = toRope(if p.module.compileToCpp: "len" else: "Sup.len")
+proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
+  initLoc(result, locNone, e.typ, OnUnknown)
+  result.flags.incl lfSingleUse
+  expr(p, e, result)
+
+proc lenField(p: BProc): Rope =
+  result = rope(if p.module.compileToCpp: "len" else: "Sup.len")
 
 include ccgcalls, "ccgstmts.nim", "ccgexprs.nim"
 
 # ----------------------------- dynamic library handling -----------------
-# We don't finalize dynamic libs as this does the OS for us.
+# We don't finalize dynamic libs as the OS does this for us.
 
 proc isGetProcAddr(lib: PLib): bool =
   let n = lib.path
-  result = n.kind in nkCallKinds and n.typ != nil and 
+  result = n.kind in nkCallKinds and n.typ != nil and
     n.typ.kind in {tyPointer, tyProc}
 
-proc loadDynamicLib(m: BModule, lib: PLib) = 
+proc loadDynamicLib(m: BModule, lib: PLib) =
   assert(lib != nil)
-  if not lib.generated: 
+  if not lib.generated:
     lib.generated = true
     var tmp = getGlobalTempName()
     assert(lib.name == nil)
     lib.name = tmp # BUGFIX: cgsym has awful side-effects
-    appf(m.s[cfsVars], "static void* $1;$n", [tmp])
+    addf(m.s[cfsVars], "static void* $1;$n", [tmp])
     if lib.path.kind in {nkStrLit..nkTripleStrLit}:
       var s: TStringSeq = @[]
       libCandidates(lib.path.strVal, s)
       if gVerbosity >= 2:
         msgWriteln("Dependency: " & lib.path.strVal)
-      var loadlib: PRope = nil
-      for i in countup(0, high(s)): 
+      var loadlib: Rope = nil
+      for i in countup(0, high(s)):
         inc(m.labels)
-        if i > 0: app(loadlib, "||")
-        appcg(m, loadlib, "($1 = #nimLoadLibrary((#NimStringDesc*) &$2))$n", 
+        if i > 0: add(loadlib, "||")
+        appcg(m, loadlib, "($1 = #nimLoadLibrary((#NimStringDesc*) &$2))$n",
               [tmp, getStrLit(m, s[i])])
-      appcg(m, m.s[cfsDynLibInit], 
-            "if (!($1)) #nimLoadLibraryError((#NimStringDesc*) &$2);$n", 
-            [loadlib, getStrLit(m, lib.path.strVal)]) 
+      appcg(m, m.s[cfsDynLibInit],
+            "if (!($1)) #nimLoadLibraryError((#NimStringDesc*) &$2);$n",
+            [loadlib, getStrLit(m, lib.path.strVal)])
     else:
       var p = newProc(nil, m)
       p.options = p.options - {optStackTrace, optEndb}
       var dest: TLoc
       initLocExpr(p, lib.path, dest)
-      app(m.s[cfsVars], p.s(cpsLocals))
-      app(m.s[cfsDynLibInit], p.s(cpsInit))
-      app(m.s[cfsDynLibInit], p.s(cpsStmts))
-      appcg(m, m.s[cfsDynLibInit], 
-           "if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n", 
+      add(m.s[cfsVars], p.s(cpsLocals))
+      add(m.s[cfsDynLibInit], p.s(cpsInit))
+      add(m.s[cfsDynLibInit], p.s(cpsStmts))
+      appcg(m, m.s[cfsDynLibInit],
+           "if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
            [tmp, rdLoc(dest)])
-      
+
   if lib.name == nil: internalError("loadDynamicLib")
-  
-proc mangleDynLibProc(sym: PSym): PRope =
-  if sfCompilerProc in sym.flags: 
+
+proc mangleDynLibProc(sym: PSym): Rope =
+  if sfCompilerProc in sym.flags:
     # NOTE: sym.loc.r is the external name!
-    result = toRope(sym.name.s)
+    result = rope(sym.name.s)
   else:
-    result = ropef("Dl_$1", [toRope(sym.id)])
-  
-proc symInDynamicLib(m: BModule, sym: PSym) = 
+    result = "Dl_$1" % [rope(sym.id)]
+
+proc symInDynamicLib(m: BModule, sym: PSym) =
   var lib = sym.annex
   let isCall = isGetProcAddr(lib)
   var extname = sym.loc.r
   if not isCall: loadDynamicLib(m, lib)
-  if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
   var tmp = mangleDynLibProc(sym)
   sym.loc.r = tmp             # from now on we only need the internal name
   sym.typ.sym = nil           # generate a new name
@@ -656,34 +551,30 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
     let n = lib.path
     var a: TLoc
     initLocExpr(m.initProc, n[0], a)
-    var params = con(rdLoc(a), "(")
+    var params = rdLoc(a) & "("
     for i in 1 .. n.len-2:
       initLocExpr(m.initProc, n[i], a)
-      params.app(rdLoc(a))
-      params.app(", ")
-    let load = ropef("\t$1 = ($2) ($3$4));$n",
-        [tmp, getTypeDesc(m, sym.typ),
-        params, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))])
+      params.add(rdLoc(a))
+      params.add(", ")
+    let load = "\t$1 = ($2) ($3$4));$n" %
+        [tmp, getTypeDesc(m, sym.typ), params, makeCString($extname)]
     var last = lastSon(n)
     if last.kind == nkHiddenStdConv: last = last.sons[1]
     internalAssert(last.kind == nkStrLit)
     let idx = last.strVal
     if idx.len == 0:
-      app(m.initProc.s(cpsStmts), load)
+      add(m.initProc.s(cpsStmts), load)
     elif idx.len == 1 and idx[0] in {'0'..'9'}:
-      app(m.extensionLoaders[idx[0]], load)
+      add(m.extensionLoaders[idx[0]], load)
     else:
       internalError(sym.info, "wrong index: " & idx)
   else:
-    appcg(m, m.s[cfsDynLibInit], 
-        "\t$1 = ($2) #nimGetProcAddr($3, $4);$n", 
-        [tmp, getTypeDesc(m, sym.typ), 
-        lib.name, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))])
-  appff(m.s[cfsVars], "$2 $1;$n", 
-      "$1 = linkonce global $2 zeroinitializer$n", 
-      [sym.loc.r, getTypeDesc(m, sym.loc.t)])
+    appcg(m, m.s[cfsDynLibInit],
+        "\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
+        [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
+  addf(m.s[cfsVars], "$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
 
-proc varInDynamicLib(m: BModule, sym: PSym) = 
+proc varInDynamicLib(m: BModule, sym: PSym) =
   var lib = sym.annex
   var extname = sym.loc.r
   loadDynamicLib(m, lib)
@@ -691,20 +582,19 @@ proc varInDynamicLib(m: BModule, sym: PSym) =
   var tmp = mangleDynLibProc(sym)
   sym.loc.r = tmp             # from now on we only need the internal name
   inc(m.labels, 2)
-  appcg(m, m.s[cfsDynLibInit], 
-      "$1 = ($2*) #nimGetProcAddr($3, $4);$n", 
-      [tmp, getTypeDesc(m, sym.typ), 
-      lib.name, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))])
-  appf(m.s[cfsVars], "$2* $1;$n",
+  appcg(m, m.s[cfsDynLibInit],
+      "$1 = ($2*) #nimGetProcAddr($3, $4);$n",
+      [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
+  addf(m.s[cfsVars], "$2* $1;$n",
       [sym.loc.r, getTypeDesc(m, sym.loc.t)])
 
 proc symInDynamicLibPartial(m: BModule, sym: PSym) =
   sym.loc.r = mangleDynLibProc(sym)
   sym.typ.sym = nil           # generate a new name
 
-proc cgsym(m: BModule, name: string): PRope = 
+proc cgsym(m: BModule, name: string): Rope =
   var sym = magicsys.getCompilerProc(name)
-  if sym != nil: 
+  if sym != nil:
     case sym.kind
     of skProc, skMethod, skConverter, skIterators: genProc(m, sym)
     of skVar, skResult, skLet: genVarPrototype(m, sym)
@@ -716,31 +606,31 @@ proc cgsym(m: BModule, name: string): PRope =
     # we're picky here for the system module too:
     rawMessage(errSystemNeeds, name)
   result = sym.loc.r
-  
-proc generateHeaders(m: BModule) = 
-  app(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl)
+
+proc generateHeaders(m: BModule) =
+  add(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl)
   var it = PStrEntry(m.headerFiles.head)
-  while it != nil: 
-    if it.data[0] notin {'\"', '<'}: 
-      appf(m.s[cfsHeaders], "$N#include \"$1\"$N", [toRope(it.data)])
-    else: 
-      appf(m.s[cfsHeaders], "$N#include $1$N", [toRope(it.data)])
+  while it != nil:
+    if it.data[0] notin {'\"', '<'}:
+      addf(m.s[cfsHeaders], "$N#include \"$1\"$N", [rope(it.data)])
+    else:
+      addf(m.s[cfsHeaders], "$N#include $1$N", [rope(it.data)])
     it = PStrEntry(it.next)
 
-proc retIsNotVoid(s: PSym): bool = 
+proc retIsNotVoid(s: PSym): bool =
   result = (s.typ.sons[0] != nil) and not isInvalidReturnType(s.typ.sons[0])
 
-proc initFrame(p: BProc, procname, filename: PRope): PRope =
+proc initFrame(p: BProc, procname, filename: Rope): Rope =
   discard cgsym(p.module, "nimFrame")
   if p.maxFrameLen > 0:
     discard cgsym(p.module, "TVarSlot")
     result = rfmt(nil, "\tnimfrs($1, $2, $3, $4)$N",
-                  procname, filename, p.maxFrameLen.toRope,
-                  p.blocks[0].frameLen.toRope)
+                  procname, filename, p.maxFrameLen.rope,
+                  p.blocks[0].frameLen.rope)
   else:
     result = rfmt(nil, "\tnimfr($1, $2)$N", procname, filename)
 
-proc deinitFrame(p: BProc): PRope =
+proc deinitFrame(p: BProc): Rope =
   result = rfmt(p.module, "\t#popFrame();$n")
 
 proc closureSetup(p: BProc, prc: PSym) =
@@ -759,7 +649,7 @@ proc closureSetup(p: BProc, prc: PSym) =
 proc genProcAux(m: BModule, prc: PSym) =
   var p = newProc(prc, m)
   var header = genProcHeader(m, prc)
-  var returnStmt: PRope = nil
+  var returnStmt: Rope = nil
   assert(prc.ast != nil)
   if sfPure notin prc.flags and prc.typ.sons[0] != nil:
     if resultPos >= prc.ast.len:
@@ -775,72 +665,72 @@ proc genProcAux(m: BModule, prc: PSym) =
     else:
       fillResult(res)
       assignParam(p, res)
-      if skipTypes(res.typ, abstractInst).kind == tyArray: 
+      if skipTypes(res.typ, abstractInst).kind == tyArray:
         incl(res.loc.flags, lfIndirect)
         res.loc.s = OnUnknown
-    
-  for i in countup(1, sonsLen(prc.typ.n) - 1): 
+
+  for i in countup(1, sonsLen(prc.typ.n) - 1):
     var param = prc.typ.n.sons[i].sym
     if param.typ.isCompileTimeOnly: continue
     assignParam(p, param)
   closureSetup(p, prc)
   genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
-  var generatedProc: PRope
+  var generatedProc: Rope
   if sfPure in prc.flags:
     if hasNakedDeclspec in extccomp.CC[extccomp.cCompiler].props:
-      header = con("__declspec(naked) ", header)
+      header = "__declspec(naked) " & header
     generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N",
                          header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts))
   else:
     generatedProc = rfmt(nil, "$N$1 {$N", header)
-    app(generatedProc, initGCFrame(p))
-    if optStackTrace in prc.options: 
-      app(generatedProc, p.s(cpsLocals))
-      var procname = cstringLit(p, generatedProc, prc.name.s)
-      app(generatedProc, initFrame(p, procname, prc.info.quotedFilename))
-    else: 
-      app(generatedProc, p.s(cpsLocals))
-    if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM):
+    add(generatedProc, initGCFrame(p))
+    if optStackTrace in prc.options:
+      add(generatedProc, p.s(cpsLocals))
+      var procname = makeCString(prc.name.s)
+      add(generatedProc, initFrame(p, procname, prc.info.quotedFilename))
+    else:
+      add(generatedProc, p.s(cpsLocals))
+    if optProfiler in prc.options:
       # invoke at proc entry for recursion:
       appcg(p, cpsInit, "\t#nimProfile();$n", [])
-    app(generatedProc, p.s(cpsInit))
-    app(generatedProc, p.s(cpsStmts))
-    if p.beforeRetNeeded: app(generatedProc, ~"\tBeforeRet: ;$n")
-    app(generatedProc, deinitGCFrame(p))
-    if optStackTrace in prc.options: app(generatedProc, deinitFrame(p))
-    app(generatedProc, returnStmt)
-    app(generatedProc, ~"}$N")
-  app(m.s[cfsProcs], generatedProc)
+    if p.beforeRetNeeded: add(generatedProc, "{")
+    add(generatedProc, p.s(cpsInit))
+    add(generatedProc, p.s(cpsStmts))
+    if p.beforeRetNeeded: add(generatedProc, ~"\t}BeforeRet: ;$n")
+    add(generatedProc, deinitGCFrame(p))
+    if optStackTrace in prc.options: add(generatedProc, deinitFrame(p))
+    add(generatedProc, returnStmt)
+    add(generatedProc, ~"}$N")
+  add(m.s[cfsProcs], generatedProc)
 
 proc crossesCppBoundary(m: BModule; sym: PSym): bool {.inline.} =
   result = sfCompileToCpp in m.module.flags and
            sfCompileToCpp notin sym.getModule().flags and
            gCmd != cmdCompileToCpp
 
-proc genProcPrototype(m: BModule, sym: PSym) = 
+proc genProcPrototype(m: BModule, sym: PSym) =
   useHeader(m, sym)
-  if lfNoDecl in sym.loc.flags: return 
+  if lfNoDecl in sym.loc.flags: return
   if lfDynamicLib in sym.loc.flags:
     if getModule(sym).id != m.module.id and
-        not containsOrIncl(m.declaredThings, sym.id): 
-      app(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n",
+        not containsOrIncl(m.declaredThings, sym.id):
+      add(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n",
                         getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
-      if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
   elif not containsOrIncl(m.declaredProtos, sym.id):
     var header = genProcHeader(m, sym)
     if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym):
-      header = con("extern \"C\" ", header)
+      header = "extern \"C\" " & header
     if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props:
-      header.app(" __attribute__((naked))")
-    app(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
+      header.add(" __attribute__((naked))")
+    add(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
 
-proc genProcNoForward(m: BModule, prc: PSym) = 
+proc genProcNoForward(m: BModule, prc: PSym) =
   fillProcLoc(prc)
   useHeader(m, prc)
   if lfImportCompilerProc in prc.loc.flags:
     # dependency to a compilerproc:
     discard cgsym(m, prc.name.s)
-    return  
+    return
   genProcPrototype(m, prc)
   if lfNoDecl in prc.loc.flags: discard
   elif prc.typ.callConv == ccInline:
@@ -850,13 +740,13 @@ proc genProcNoForward(m: BModule, prc: PSym) =
     if not containsOrIncl(m.declaredThings, prc.id): genProcAux(m, prc)
   elif lfDynamicLib in prc.loc.flags:
     var q = findPendingModule(m, prc)
-    if q != nil and not containsOrIncl(q.declaredThings, prc.id): 
+    if q != nil and not containsOrIncl(q.declaredThings, prc.id):
       symInDynamicLib(q, prc)
     else:
       symInDynamicLibPartial(m, prc)
   elif sfImportc notin prc.flags:
     var q = findPendingModule(m, prc)
-    if q != nil and not containsOrIncl(q.declaredThings, prc.id): 
+    if q != nil and not containsOrIncl(q.declaredThings, prc.id):
       genProcAux(q, prc)
 
 proc requestConstImpl(p: BProc, sym: PSym) =
@@ -869,20 +759,20 @@ proc requestConstImpl(p: BProc, sym: PSym) =
   var q = findPendingModule(m, sym)
   if q != nil and not containsOrIncl(q.declaredThings, sym.id):
     assert q.initProc.module == q
-    appf(q.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
+    addf(q.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
         [getTypeDesc(q, sym.typ), sym.loc.r, genConstExpr(q.initProc, sym.ast)])
   # declare header:
   if q != m and not containsOrIncl(m.declaredThings, sym.id):
     assert(sym.loc.r != nil)
-    let headerDecl = ropef("extern NIM_CONST $1 $2;$n",
-        [getTypeDesc(m, sym.loc.t), sym.loc.r])
-    app(m.s[cfsData], headerDecl)
+    let headerDecl = "extern NIM_CONST $1 $2;$n" %
+        [getTypeDesc(m, sym.loc.t), sym.loc.r]
+    add(m.s[cfsData], headerDecl)
     if sfExportc in sym.flags and generatedHeader != nil:
-      app(generatedHeader.s[cfsData], headerDecl)
+      add(generatedHeader.s[cfsData], headerDecl)
 
 proc isActivated(prc: PSym): bool = prc.typ != nil
 
-proc genProc(m: BModule, prc: PSym) = 
+proc genProc(m: BModule, prc: PSym) =
   if sfBorrow in prc.flags or not isActivated(prc): return
   fillProcLoc(prc)
   if sfForward in prc.flags: addForwardedProc(m, prc)
@@ -892,69 +782,65 @@ proc genProc(m: BModule, prc: PSym) =
         generatedHeader != nil and lfNoDecl notin prc.loc.flags:
       genProcPrototype(generatedHeader, prc)
       if prc.typ.callConv == ccInline:
-        if not containsOrIncl(generatedHeader.declaredThings, prc.id): 
+        if not containsOrIncl(generatedHeader.declaredThings, prc.id):
           genProcAux(generatedHeader, prc)
 
-proc genVarPrototypeAux(m: BModule, sym: PSym) = 
+proc genVarPrototypeAux(m: BModule, sym: PSym) =
   assert(sfGlobal in sym.flags)
   useHeader(m, sym)
   fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap)
-  if (lfNoDecl in sym.loc.flags) or containsOrIncl(m.declaredThings, sym.id): 
-    return 
-  if sym.owner.id != m.module.id: 
+  if (lfNoDecl in sym.loc.flags) or containsOrIncl(m.declaredThings, sym.id):
+    return
+  if sym.owner.id != m.module.id:
     # else we already have the symbol generated!
     assert(sym.loc.r != nil)
-    if sfThread in sym.flags: 
+    if sfThread in sym.flags:
       declareThreadVar(m, sym, true)
     else:
-      app(m.s[cfsVars], "extern ")
-      app(m.s[cfsVars], getTypeDesc(m, sym.loc.t))
-      if lfDynamicLib in sym.loc.flags: app(m.s[cfsVars], "*")
-      if sfRegister in sym.flags: app(m.s[cfsVars], " register")
-      if sfVolatile in sym.flags: app(m.s[cfsVars], " volatile")
-      appf(m.s[cfsVars], " $1;$n", [sym.loc.r])
+      add(m.s[cfsVars], "extern ")
+      add(m.s[cfsVars], getTypeDesc(m, sym.loc.t))
+      if lfDynamicLib in sym.loc.flags: add(m.s[cfsVars], "*")
+      if sfRegister in sym.flags: add(m.s[cfsVars], " register")
+      if sfVolatile in sym.flags: add(m.s[cfsVars], " volatile")
+      addf(m.s[cfsVars], " $1;$n", [sym.loc.r])
 
 proc genVarPrototype(m: BModule, sym: PSym) =
   genVarPrototypeAux(m, sym)
 
-proc addIntTypes(result: var PRope) {.inline.} =
-  appf(result, "#define NIM_INTBITS $1", [
-    platform.CPU[targetCPU].intSize.toRope])
+proc addIntTypes(result: var Rope) {.inline.} =
+  addf(result, "#define NIM_INTBITS $1", [
+    platform.CPU[targetCPU].intSize.rope])
 
-proc getCopyright(cfile: string): PRope =
+proc getCopyright(cfile: string): Rope =
   if optCompileOnly in gGlobalOptions:
-    result = ropeff("/* Generated by Nim Compiler v$1 */$N" &
-        "/*   (c) 2014 Andreas Rumpf */$N" &
-        "/* The generated code is subject to the original license. */$N",
-        "; Generated by Nim Compiler v$1$N" &
-        ";   (c) 2012 Andreas Rumpf$N", [toRope(VersionAsString)])
+    result = ("/* Generated by Nim Compiler v$1 */$N" &
+        "/*   (c) 2015 Andreas Rumpf */$N" &
+        "/* The generated code is subject to the original license. */$N") %
+        [rope(VersionAsString)]
   else:
-    result = ropeff("/* Generated by Nim Compiler v$1 */$N" &
-        "/*   (c) 2014 Andreas Rumpf */$N" &
+    result = ("/* Generated by Nim Compiler v$1 */$N" &
+        "/*   (c) 2015 Andreas Rumpf */$N" &
         "/* The generated code is subject to the original license. */$N" &
         "/* Compiled for: $2, $3, $4 */$N" &
-        "/* Command for C compiler:$n   $5 */$N",
-        "; Generated by Nim Compiler v$1$N" &
-        ";   (c) 2014 Andreas Rumpf$N" &
-        "; Compiled for: $2, $3, $4$N" &
-        "; Command for LLVM compiler:$N   $5$N", [toRope(VersionAsString),
-        toRope(platform.OS[targetOS].name),
-        toRope(platform.CPU[targetCPU].name),
-        toRope(extccomp.CC[extccomp.cCompiler].name),
-        toRope(getCompileCFileCmd(cfile))])
-
-proc getFileHeader(cfile: string): PRope =
+        "/* Command for C compiler:$n   $5 */$N") %
+        [rope(VersionAsString),
+        rope(platform.OS[targetOS].name),
+        rope(platform.CPU[targetCPU].name),
+        rope(extccomp.CC[extccomp.cCompiler].name),
+        rope(getCompileCFileCmd(cfile))]
+
+proc getFileHeader(cfile: string): Rope =
   result = getCopyright(cfile)
   addIntTypes(result)
 
-proc genFilenames(m: BModule): PRope =
+proc genFilenames(m: BModule): Rope =
   discard cgsym(m, "dbgRegisterFilename")
   result = nil
   for i in 0.. <fileInfos.len:
-    result.appf("dbgRegisterFilename($1);$N", fileInfos[i].projPath.makeCString)
+    result.addf("dbgRegisterFilename($1);$N", [fileInfos[i].projPath.makeCString])
 
 proc genMainProc(m: BModule) =
-  const 
+  const
     # The use of a volatile function pointer to call Pre/NimMainInner
     # prevents inlining of the NimMainInner function and dependent
     # functions, which might otherwise merge their stack frames.
@@ -975,7 +861,7 @@ proc genMainProc(m: BModule) =
 
     MainProcs =
       "\tNimMain();$N"
-    
+
     MainProcsWithResult =
       MainProcs & "\treturn nim_program_result;$N"
 
@@ -996,7 +882,7 @@ proc genMainProc(m: BModule) =
       "char** cmdLine;$N" &
       "char** gEnv;$N" &
       NimMainBody
-  
+
     PosixCMain =
       "int main(int argc, char** args, char** env) {$N" &
         "\tcmdLine = args;$N" &
@@ -1004,20 +890,20 @@ proc genMainProc(m: BModule) =
         "\tgEnv = env;$N" &
         MainProcsWithResult &
       "}$N$N"
-  
+
     StandaloneCMain =
       "int main(void) {$N" &
         MainProcs &
         "\treturn 0;$N" &
       "}$N$N"
-    
+
     WinNimMain = NimMainBody
-    
+
     WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $N" &
       "                        HINSTANCE hPrevInstance, $N" &
       "                        LPSTR lpCmdLine, int nCmdShow) {$N" &
       MainProcsWithResult & "}$N$N"
-  
+
     WinNimDllMain = "N_LIB_EXPORT " & NimMainBody
 
     WinCDllMain =
@@ -1027,19 +913,19 @@ proc genMainProc(m: BModule) =
       "\treturn 1;$N}$N$N"
 
     PosixNimDllMain = WinNimDllMain
-    
+
     PosixCDllMain =
       "void NIM_POSIX_INIT NimMainInit(void) {$N" &
         MainProcs &
       "}$N$N"
 
-  var nimMain, otherMain: TFormatStr
+  var nimMain, otherMain: FormatStr
   if platform.targetOS == osWindows and
-      gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}: 
-    if optGenGuiApp in gGlobalOptions: 
+      gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}:
+    if optGenGuiApp in gGlobalOptions:
       nimMain = WinNimMain
       otherMain = WinCMain
-    else: 
+    else:
       nimMain = WinNimDllMain
       otherMain = WinCDllMain
     discard lists.includeStr(m.headerFiles, "<windows.h>")
@@ -1054,10 +940,10 @@ proc genMainProc(m: BModule) =
     otherMain = PosixCMain
   if gBreakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint")
   if optEndb in gOptions:
-    gBreakpoints.app(m.genFilenames)
-  
+    gBreakpoints.add(m.genFilenames)
+
   let initStackBottomCall =
-    if platform.targetOS == osStandalone: "".toRope
+    if platform.targetOS == osStandalone: "".rope
     else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
   inc(m.labels)
   appcg(m, m.s[cfsProcs], PreMainBody, [
@@ -1065,118 +951,115 @@ proc genMainProc(m: BModule) =
      if emulatedThreadVars() and platform.targetOS != osStandalone:
        ropecg(m, "\t#initThreadVarsEmulation();$N")
      else:
-       "".toRope,
+       "".rope,
      initStackBottomCall])
 
-  appcg(m, m.s[cfsProcs], nimMain, [mainModInit, initStackBottomCall, toRope(m.labels)])
+  appcg(m, m.s[cfsProcs], nimMain, [mainModInit, initStackBottomCall, rope(m.labels)])
   if optNoMain notin gGlobalOptions:
     appcg(m, m.s[cfsProcs], otherMain, [])
 
-proc getSomeInitName(m: PSym, suffix: string): PRope =
+proc getSomeInitName(m: PSym, suffix: string): Rope =
   assert m.kind == skModule
   assert m.owner.kind == skPackage
   if {sfSystemModule, sfMainModule} * m.flags == {}:
-    result = m.owner.name.s.mangle.toRope
-    result.app "_"
-  result.app m.name.s
-  result.app suffix
-  
-proc getInitName(m: PSym): PRope = getSomeInitName(m, "Init")
-proc getDatInitName(m: PSym): PRope = getSomeInitName(m, "DatInit")
-
-proc registerModuleToMain(m: PSym) = 
+    result = m.owner.name.s.mangle.rope
+    result.add "_"
+  result.add m.name.s
+  result.add suffix
+
+proc getInitName(m: PSym): Rope = getSomeInitName(m, "Init")
+proc getDatInitName(m: PSym): Rope = getSomeInitName(m, "DatInit")
+
+proc registerModuleToMain(m: PSym) =
   var
     init = m.getInitName
     datInit = m.getDatInitName
-  appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N",
-                      "declare void $1() noinline$N", [init])
-  appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N",
-                      "declare void $1() noinline$N", [datInit])
+  addf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [init])
+  addf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [datInit])
   if sfSystemModule notin m.flags:
-    appff(mainDatInit, "\t$1();$N", "call void ()* $1$n", [datInit])
-    let initCall = ropeff("\t$1();$N", "call void ()* $1$n", [init])
+    addf(mainDatInit, "\t$1();$N", [datInit])
+    let initCall = "\t$1();$N" % [init]
     if sfMainModule in m.flags:
-      app(mainModInit, initCall)
+      add(mainModInit, initCall)
     else:
-      app(otherModsInit, initCall)
-    
-proc genInitCode(m: BModule) = 
+      add(otherModsInit, initCall)
+
+proc genInitCode(m: BModule) =
   var initname = getInitName(m.module)
-  var prc = ropeff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", 
-                   "define void $1() noinline {$n", [initname])
-  if m.typeNodes > 0: 
-    appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n", 
-          [m.typeNodesName, toRope(m.typeNodes)])
-  if m.nimTypes > 0: 
-    appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n", 
-          [m.nimTypesName, toRope(m.nimTypes)])
-  
-  app(prc, initGCFrame(m.initProc))
- 
-  app(prc, genSectionStart(cpsLocals))
-  app(prc, m.preInitProc.s(cpsLocals))
-  app(prc, m.initProc.s(cpsLocals))
-  app(prc, m.postInitProc.s(cpsLocals))
-  app(prc, genSectionEnd(cpsLocals))
+  var prc = "NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N" % [initname]
+  if m.typeNodes > 0:
+    appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
+          [m.typeNodesName, rope(m.typeNodes)])
+  if m.nimTypes > 0:
+    appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n",
+          [m.nimTypesName, rope(m.nimTypes)])
+
+  add(prc, initGCFrame(m.initProc))
+
+  add(prc, genSectionStart(cpsLocals))
+  add(prc, m.preInitProc.s(cpsLocals))
+  add(prc, m.initProc.s(cpsLocals))
+  add(prc, m.postInitProc.s(cpsLocals))
+  add(prc, genSectionEnd(cpsLocals))
 
   if optStackTrace in m.initProc.options and not m.frameDeclared:
     # BUT: the generated init code might depend on a current frame, so
     # declare it nevertheless:
     m.frameDeclared = true
     if not m.preventStackTrace:
-      var procname = cstringLit(m.initProc, prc, m.module.name.s)
-      app(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
+      var procname = makeCString(m.module.name.s)
+      add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
     else:
-      app(prc, ~"\tTFrame F; F.len = 0;$N")
-    
-  app(prc, genSectionStart(cpsInit))
-  app(prc, m.preInitProc.s(cpsInit))
-  app(prc, m.initProc.s(cpsInit))
-  app(prc, m.postInitProc.s(cpsInit))
-  app(prc, genSectionEnd(cpsInit))
-
-  app(prc, genSectionStart(cpsStmts))
-  app(prc, m.preInitProc.s(cpsStmts))
-  app(prc, m.initProc.s(cpsStmts))
-  app(prc, m.postInitProc.s(cpsStmts))
-  app(prc, genSectionEnd(cpsStmts))
+      add(prc, ~"\tTFrame F; F.len = 0;$N")
+
+  add(prc, genSectionStart(cpsInit))
+  add(prc, m.preInitProc.s(cpsInit))
+  add(prc, m.initProc.s(cpsInit))
+  add(prc, m.postInitProc.s(cpsInit))
+  add(prc, genSectionEnd(cpsInit))
+
+  add(prc, genSectionStart(cpsStmts))
+  add(prc, m.preInitProc.s(cpsStmts))
+  add(prc, m.initProc.s(cpsStmts))
+  add(prc, m.postInitProc.s(cpsStmts))
+  add(prc, genSectionEnd(cpsStmts))
   if optStackTrace in m.initProc.options and not m.preventStackTrace:
-    app(prc, deinitFrame(m.initProc))
-  app(prc, deinitGCFrame(m.initProc))
-  appf(prc, "}$N$N")
+    add(prc, deinitFrame(m.initProc))
+  add(prc, deinitGCFrame(m.initProc))
+  addf(prc, "}$N$N", [])
 
-  prc.appff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
-            "define void $1() noinline {$n", [getDatInitName(m.module)])
+  prc.addf("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
+           [getDatInitName(m.module)])
 
   for i in cfsTypeInit1..cfsDynLibInit:
-    app(prc, genSectionStart(i))
-    app(prc, m.s[i])
-    app(prc, genSectionEnd(i))
-  
-  appf(prc, "}$N$N")
+    add(prc, genSectionStart(i))
+    add(prc, m.s[i])
+    add(prc, genSectionEnd(i))
+
+  addf(prc, "}$N$N", [])
   # we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because
   # that would lead to a *nesting* of merge sections which the merger does
   # not support. So we add it to another special section: ``cfsInitProc``
-  app(m.s[cfsInitProc], prc)
-  
+  add(m.s[cfsInitProc], prc)
+
   for i, el in pairs(m.extensionLoaders):
     if el != nil:
-      let ex = ropef("N_NIMCALL(void, nimLoadProcs$1)(void) {$2}$N$N",
-        (i.ord - '0'.ord).toRope, el)
-      app(m.s[cfsInitProc], ex)
+      let ex = "N_NIMCALL(void, nimLoadProcs$1)(void) {$2}$N$N" %
+        [(i.ord - '0'.ord).rope, el]
+      add(m.s[cfsInitProc], ex)
 
-proc genModule(m: BModule, cfile: string): PRope = 
+proc genModule(m: BModule, cfile: string): Rope =
   result = getFileHeader(cfile)
-  result.app(genMergeInfo(m))
-  
+  result.add(genMergeInfo(m))
+
   generateHeaders(m)
 
   generateThreadLocalStorage(m)
-  for i in countup(cfsHeaders, cfsProcs): 
-    app(result, genSectionStart(i))
-    app(result, m.s[i])
-    app(result, genSectionEnd(i))
-  app(result, m.s[cfsInitProc])
+  for i in countup(cfsHeaders, cfsProcs):
+    add(result, genSectionStart(i))
+    add(result, m.s[i])
+    add(result, genSectionEnd(i))
+  add(result, m.s[cfsInitProc])
 
 proc newPreInitProc(m: BModule): BProc =
   result = newProc(nil, m)
@@ -1188,7 +1071,7 @@ proc newPostInitProc(m: BModule): BProc =
   # little hack so that unique temporaries are generated:
   result.labels = 200_000
 
-proc initProcOptions(m: BModule): TOptions = 
+proc initProcOptions(m: BModule): TOptions =
   if sfSystemModule in m.module.flags: gOptions-{optStackTrace} else: gOptions
 
 proc rawNewModule(module: PSym, filename: string): BModule =
@@ -1243,11 +1126,11 @@ proc resetModule*(m: BModule) =
   m.typeNodes = 0
   m.nimTypes = 0
   nullify m.extensionLoaders
-  
+
   # indicate that this is now cached module
   # the cache will be invalidated by nullifying gModules
   m.fromCache = true
-  
+
   # we keep only the "merge info" information for the module
   # and the properties that can't change:
   # m.filename
@@ -1274,11 +1157,11 @@ proc newModule(module: PSym): BModule =
   growCache gModules, module.position
   gModules[module.position] = result
 
-  if (optDeadCodeElim in gGlobalOptions): 
-    if (sfDeadCodeElim in module.flags): 
+  if (optDeadCodeElim in gGlobalOptions):
+    if (sfDeadCodeElim in module.flags):
       internalError("added pending module twice: " & module.filename)
 
-proc myOpen(module: PSym): PPassContext = 
+proc myOpen(module: PSym): PPassContext =
   result = newModule(module)
   if optGenIndex in gGlobalOptions and generatedHeader == nil:
     let f = if headerFile.len > 0: headerFile else: gProjectFull
@@ -1288,22 +1171,22 @@ proc myOpen(module: PSym): PPassContext =
 
 proc writeHeader(m: BModule) =
   var result = getCopyright(m.filename)
-  var guard = ropef("__$1__", m.filename.splitFile.name.toRope)
-  result.appf("#ifndef $1$n#define $1$n", guard)
+  var guard = "__$1__" % [m.filename.splitFile.name.rope]
+  result.addf("#ifndef $1$n#define $1$n", [guard])
   addIntTypes(result)
   generateHeaders(m)
 
   generateThreadLocalStorage(m)
-  for i in countup(cfsHeaders, cfsProcs): 
-    app(result, genSectionStart(i))
-    app(result, m.s[i])
-    app(result, genSectionEnd(i))
-  app(result, m.s[cfsInitProc])
-  
+  for i in countup(cfsHeaders, cfsProcs):
+    add(result, genSectionStart(i))
+    add(result, m.s[i])
+    add(result, genSectionEnd(i))
+  add(result, m.s[cfsInitProc])
+
   if optGenDynLib in gGlobalOptions:
-    result.app("N_LIB_IMPORT ")
-  result.appf("N_CDECL(void, NimMain)(void);$n")
-  result.appf("#endif /* $1 */$n", guard)
+    result.add("N_LIB_IMPORT ")
+  result.addf("N_CDECL(void, NimMain)(void);$n", [])
+  result.addf("#endif /* $1 */$n", [guard])
   writeRope(result, m.filename)
 
 proc getCFile(m: BModule): string =
@@ -1319,20 +1202,20 @@ proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
   readMergeInfo(getCFile(m), m)
   result = m
 
-proc myProcess(b: PPassContext, n: PNode): PNode = 
+proc myProcess(b: PPassContext, n: PNode): PNode =
   result = n
   if b == nil or passes.skipCodegen(n): return
   var m = BModule(b)
   m.initProc.options = initProcOptions(m)
   genStmts(m.initProc, n)
 
-proc finishModule(m: BModule) = 
+proc finishModule(m: BModule) =
   var i = 0
-  while i <= high(m.forwardedProcs): 
+  while i <= high(m.forwardedProcs):
     # Note: ``genProc`` may add to ``m.forwardedProcs``, so we cannot use
     # a ``for`` loop here
     var prc = m.forwardedProcs[i]
-    if sfForward in prc.flags: 
+    if sfForward in prc.flags:
       internalError(prc.info, "still forwarded: " & prc.name.s)
     genProcNoForward(m, prc)
     inc(i)
@@ -1340,13 +1223,13 @@ proc finishModule(m: BModule) =
   dec(gForwardedProcsCounter, i)
   setLen(m.forwardedProcs, 0)
 
-proc shouldRecompile(code: PRope, cfile: string): bool = 
+proc shouldRecompile(code: Rope, cfile: string): bool =
   result = true
   if optForceFullMake notin gGlobalOptions:
     var objFile = toObjFile(cfile)
-    if writeRopeIfNotEqual(code, cfile): return 
+    if writeRopeIfNotEqual(code, cfile): return
     if existsFile(objFile) and os.fileNewer(objFile, cfile): result = false
-  else: 
+  else:
     writeRope(code, cfile)
 
 # We need 2 different logics here: pending modules (including
@@ -1359,19 +1242,19 @@ proc writeModule(m: BModule, pending: bool) =
   # generate code for the init statements of the module:
   var cfile = getCFile(m)
   var cfilenoext = changeFileExt(cfile, "")
-  
+
   if not m.fromCache or optForceFullMake in gGlobalOptions:
     genInitCode(m)
     finishTypeDescriptions(m)
-    if sfMainModule in m.module.flags: 
+    if sfMainModule in m.module.flags:
       # generate main file:
-      app(m.s[cfsProcHeaders], mainModProcs)
+      add(m.s[cfsProcHeaders], mainModProcs)
       generateThreadVarsSize(m)
-    
+
     var code = genModule(m, cfile)
     when hasTinyCBackend:
       if gCmd == cmdRun:
-        tccgen.compileCCode(ropeToStr(code))
+        tccgen.compileCCode($code)
         return
 
     if shouldRecompile(code, cfile):
@@ -1388,13 +1271,13 @@ proc writeModule(m: BModule, pending: bool) =
     # ``system.c`` but then compilation fails due to an error. This means
     # that ``system.o`` is missing, so we need to call the C compiler for it:
     addFileToCompile(cfile)
-  
+
   addFileToLink(cfilenoext)
 
 proc updateCachedModule(m: BModule) =
   let cfile = getCFile(m)
   let cfilenoext = changeFileExt(cfile, "")
-  
+
   if mergeRequired(m) and sfMainModule notin m.module.flags:
     mergeFiles(cfile, m)
     genInitCode(m)
@@ -1405,17 +1288,17 @@ proc updateCachedModule(m: BModule) =
 
   addFileToLink(cfilenoext)
 
-proc myClose(b: PPassContext, n: PNode): PNode = 
+proc myClose(b: PPassContext, n: PNode): PNode =
   result = n
-  if b == nil or passes.skipCodegen(n): return 
+  if b == nil or passes.skipCodegen(n): return
   var m = BModule(b)
-  if n != nil: 
+  if n != nil:
     m.initProc.options = initProcOptions(m)
     genStmts(m.initProc, n)
-  # cached modules need to registered too: 
+  # cached modules need to registered too:
   registerModuleToMain(m.module)
 
-  if sfMainModule in m.module.flags: 
+  if sfMainModule in m.module.flags:
     m.objHasKidsValid = true
     var disp = generateMethodDispatchers()
     for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym)
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index 508f98074..187186373 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -9,11 +9,13 @@
 
 ## This module contains the data structures for the C code generation phase.
 
-import 
+import
   ast, astalgo, ropes, passes, options, intsets, lists, platform
 
+from msgs import TLineInfo
+
 type
-  TLabel* = PRope             # for the C generator a label is just a rope
+  TLabel* = Rope             # for the C generator a label is just a rope
   TCFileSection* = enum       # the sections a generated C file consists of
     cfsMergeInfo,             # section containing merge information
     cfsHeaders,               # section for C include file headers
@@ -43,34 +45,35 @@ type
     ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
     ctArray, ctPtrToArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc,
     ctCString
-  TCFileSections* = array[TCFileSection, PRope] # represents a generated C file
+  TCFileSections* = array[TCFileSection, Rope] # represents a generated C file
   TCProcSection* = enum       # the sections a generated C proc consists of
     cpsLocals,                # section of local variables for C proc
     cpsInit,                  # section for init of variables for C proc
     cpsStmts                  # section of local statements for C proc
-  TCProcSections* = array[TCProcSection, PRope] # represents a generated C proc
+  TCProcSections* = array[TCProcSection, Rope] # represents a generated C proc
   BModule* = ref TCGen
   BProc* = ref TCProc
-  TBlock*{.final.} = object 
+  TBlock*{.final.} = object
     id*: int                  # the ID of the label; positive means that it
-    label*: PRope             # generated text for the label
+    label*: Rope             # generated text for the label
                               # nil if label is not used
     sections*: TCProcSections # the code beloging
     isLoop*: bool             # whether block is a loop
     nestedTryStmts*: int16    # how many try statements is it nested into
     nestedExceptStmts*: int16 # how many except statements is it nested into
     frameLen*: int16
-  
+
   TCProc{.final.} = object    # represents C proc that is currently generated
     prc*: PSym                # the Nim proc that this C proc belongs to
     beforeRetNeeded*: bool    # true iff 'BeforeRet' label for proc is needed
     threadVarAccessed*: bool  # true if the proc already accessed some threadvar
+    lastLineInfo*: TLineInfo  # to avoid generating excessive 'nimln' statements
     nestedTryStmts*: seq[PNode]   # in how many nested try statements we are
                                   # (the vars must be volatile then)
     inExceptBlock*: int       # are we currently inside an except block?
                               # leaving such scopes by raise or by return must
                               # execute any applicable finally blocks
-    finallySafePoints*: seq[PRope]  # For correctly cleaning up exceptions when
+    finallySafePoints*: seq[Rope]  # For correctly cleaning up exceptions when
                                     # using return in finally statements
     labels*: Natural          # for generating unique labels in the C proc
     blocks*: seq[TBlock]      # nested blocks
@@ -82,9 +85,12 @@ type
     maxFrameLen*: int         # max length of frame descriptor
     module*: BModule          # used to prevent excessive parameter passing
     withinLoop*: int          # > 0 if we are within a loop
+    splitDecls*: int          # > 0 if we are in some context for C++ that
+                              # requires 'T x = T()' to become 'T x; x = T()'
+                              # (yes, C++ is weird like that)
     gcFrameId*: Natural       # for the GC stack marking
-    gcFrameType*: PRope       # the struct {} we put the GC markers into
-  
+    gcFrameType*: Rope       # the struct {} we put the GC markers into
+
   TTypeSeq* = seq[PType]
   TCGen = object of TPassContext # represents a C source file
     module*: PSym
@@ -112,24 +118,24 @@ type
     dataCache*: TNodeTable
     forwardedProcs*: TSymSeq  # keep forwarded procs here
     typeNodes*, nimTypes*: int # used for type info generation
-    typeNodesName*, nimTypesName*: PRope # used for type info generation
+    typeNodesName*, nimTypesName*: Rope # used for type info generation
     labels*: Natural          # for generating unique module-scope names
-    extensionLoaders*: array['0'..'9', PRope] # special procs for the
+    extensionLoaders*: array['0'..'9', Rope] # special procs for the
                                               # OpenGL wrapper
-    injectStmt*: PRope
+    injectStmt*: Rope
 
 var
-  mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: PRope
+  mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope
     # varuious parts of the main module
-  gMapping*: PRope             # the generated mapping file (if requested)
+  gMapping*: Rope             # the generated mapping file (if requested)
   gModules*: seq[BModule] = @[] # list of all compiled modules
   gForwardedProcsCounter*: int = 0
 
-proc s*(p: BProc, s: TCProcSection): var PRope {.inline.} =
+proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
   # section in the current block
   result = p.blocks[p.blocks.len - 1].sections[s]
 
-proc procSec*(p: BProc, s: TCProcSection): var PRope {.inline.} =
+proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} =
   # top level proc sections
   result = p.blocks[0].sections[s]
 
@@ -137,7 +143,7 @@ proc bmod*(module: PSym): BModule =
   # obtains the BModule for a given module PSym
   result = gModules[module.position]
 
-proc newProc*(prc: PSym, module: BModule): BProc = 
+proc newProc*(prc: PSym, module: BModule): BProc =
   new(result)
   result.prc = prc
   result.module = module
diff --git a/compiler/commands.nim b/compiler/commands.nim
index a5b0b40d7..b6ebb6bcb 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -24,8 +24,8 @@ bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep")
 bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational")
 bootSwitch(usedNoGC, defined(nogc), "--gc:none")
 
-import 
-  os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists, 
+import
+  os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists,
   wordrecg, parseutils, nimblecmd, idents, parseopt
 
 # but some have deps to imported modules. Yay.
@@ -39,8 +39,8 @@ bootSwitch(usedFFI, hasFFI, "-d:useFFI")
 
 proc writeCommandLineUsage*()
 
-type 
-  TCmdLinePass* = enum 
+type
+  TCmdLinePass* = enum
     passCmd1,                 # first pass over the command line
     passCmd2,                 # second pass over the command line
     passPP                    # preprocessor called processCommand()
@@ -52,48 +52,48 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo)
 
 const
   HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" &
-      "Copyright (c) 2006-2014 by Andreas Rumpf\n"
+      "Copyright (c) 2006-2015 by Andreas Rumpf\n"
 
-const 
+const
   Usage = slurp"doc/basicopt.txt".replace("//", "")
   AdvancedUsage = slurp"doc/advopt.txt".replace("//", "")
 
-proc getCommandLineDesc(): string = 
-  result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name, 
+proc getCommandLineDesc(): string =
+  result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
                            CPU[platform.hostCPU].name]) & Usage
 
-proc helpOnError(pass: TCmdLinePass) = 
+proc helpOnError(pass: TCmdLinePass) =
   if pass == passCmd1:
     msgWriteln(getCommandLineDesc())
-    quit(0)
+    msgQuit(0)
 
-proc writeAdvancedUsage(pass: TCmdLinePass) = 
+proc writeAdvancedUsage(pass: TCmdLinePass) =
   if pass == passCmd1:
-    msgWriteln(`%`(HelpMessage, [VersionAsString, 
-                                 platform.OS[platform.hostOS].name, 
+    msgWriteln(`%`(HelpMessage, [VersionAsString,
+                                 platform.OS[platform.hostOS].name,
                                  CPU[platform.hostCPU].name]) & AdvancedUsage)
-    quit(0)
+    msgQuit(0)
 
-proc writeVersionInfo(pass: TCmdLinePass) = 
+proc writeVersionInfo(pass: TCmdLinePass) =
   if pass == passCmd1:
-    msgWriteln(`%`(HelpMessage, [VersionAsString, 
-                                 platform.OS[platform.hostOS].name, 
+    msgWriteln(`%`(HelpMessage, [VersionAsString,
+                                 platform.OS[platform.hostOS].name,
                                  CPU[platform.hostCPU].name]))
 
-    discard """const gitHash = gorge("git log -n 1 --format=%H")
-    if gitHash.strip.len == 40:
-      msgWriteln("git hash: " & gitHash)"""
+    const gitHash = gorge("git log -n 1 --format=%H").strip
+    when gitHash.len == 40:
+      msgWriteln("git hash: " & gitHash)
 
     msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine &
       usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas &
       usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedNoGC)
-    quit(0)
+    msgQuit(0)
 
 var
   helpWritten: bool
 
-proc writeCommandLineUsage() = 
-  if not helpWritten: 
+proc writeCommandLineUsage() =
+  if not helpWritten:
     msgWriteln(getCommandLineDesc())
     helpWritten = true
 
@@ -101,71 +101,71 @@ proc addPrefix(switch: string): string =
   if len(switch) == 1: result = "-" & switch
   else: result = "--" & switch
 
-proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) = 
+proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
   if switch == " ": localError(info, errInvalidCmdLineOption, "-")
   else: localError(info, errInvalidCmdLineOption, addPrefix(switch))
 
-proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass, 
-                 info: TLineInfo) = 
+proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
+                 info: TLineInfo) =
   cmd = ""
   var i = 0
   if i < len(switch) and switch[i] == '-': inc(i)
   if i < len(switch) and switch[i] == '-': inc(i)
-  while i < len(switch): 
+  while i < len(switch):
     case switch[i]
     of 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': add(cmd, switch[i])
-    else: break 
+    else: break
     inc(i)
   if i >= len(switch): arg = ""
   elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1)
   else: invalidCmdLineOption(pass, switch, info)
-  
-proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass, 
-                        info: TLineInfo) = 
+
+proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass,
+                        info: TLineInfo) =
   case whichKeyword(arg)
   of wOn: gOptions = gOptions + op
   of wOff: gOptions = gOptions - op
   else: localError(info, errOnOrOffExpectedButXFound, arg)
-  
-proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass, 
-                         info: TLineInfo) = 
+
+proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass,
+                         info: TLineInfo) =
   case whichKeyword(arg)
   of wOn: gGlobalOptions = gGlobalOptions + op
   of wOff: gGlobalOptions = gGlobalOptions - op
   else: localError(info, errOnOrOffExpectedButXFound, arg)
-  
-proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = 
+
+proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   if arg == "": localError(info, errCmdLineArgExpected, addPrefix(switch))
-  
-proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = 
+
+proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch))
-  
-proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass, 
-                         info: TLineInfo) = 
+
+proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
+                         info: TLineInfo; orig: string) =
   var id = ""  # arg = "X]:on|off"
   var i = 0
   var n = hintMin
-  while i < len(arg) and (arg[i] != ']'): 
+  while i < len(arg) and (arg[i] != ']'):
     add(id, arg[i])
     inc(i)
   if i < len(arg) and (arg[i] == ']'): inc(i)
-  else: invalidCmdLineOption(pass, arg, info)
+  else: invalidCmdLineOption(pass, orig, info)
   if i < len(arg) and (arg[i] in {':', '='}): inc(i)
-  else: invalidCmdLineOption(pass, arg, info)
-  if state == wHint: 
+  else: invalidCmdLineOption(pass, orig, info)
+  if state == wHint:
     var x = findStr(msgs.HintsToStr, id)
     if x >= 0: n = TNoteKind(x + ord(hintMin))
-    else: invalidCmdLineOption(pass, arg, info)
-  else: 
+    else: localError(info, "unknown hint: " & id)
+  else:
     var x = findStr(msgs.WarningsToStr, id)
     if x >= 0: n = TNoteKind(x + ord(warnMin))
-    else: invalidCmdLineOption(pass, arg, info)
+    else: localError(info, "unknown warning: " & id)
   case whichKeyword(substr(arg, i))
   of wOn: incl(gNotes, n)
   of wOff: excl(gNotes, n)
   else: localError(info, errOnOrOffExpectedButXFound, arg)
 
-proc processCompile(filename: string) = 
+proc processCompile(filename: string) =
   var found = findFile(filename)
   if found == "": found = filename
   var trunc = changeFileExt(found, "")
@@ -191,7 +191,7 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
     else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
   else: invalidCmdLineOption(passCmd1, switch, info)
 
-proc testCompileOption*(switch: string, info: TLineInfo): bool = 
+proc testCompileOption*(switch: string, info: TLineInfo): bool =
   case switch.normalize
   of "debuginfo": result = contains(gGlobalOptions, optCDebug)
   of "compileonly", "c": result = contains(gGlobalOptions, optCompileOnly)
@@ -228,11 +228,11 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
   of "patterns": result = contains(gOptions, optPatterns)
   of "experimental": result = gExperimentalMode
   else: invalidCmdLineOption(passCmd1, switch, info)
-  
+
 proc processPath(path: string, notRelativeToProj = false): string =
   let p = if notRelativeToProj or os.isAbsolute(path) or
-              '$' in path or path[0] == '.': 
-            path 
+              '$' in path or path[0] == '.':
+            path
           else:
             options.gProjectPath / path
   result = unixToNativePath(p % ["nimrod", getPrefixDir(),
@@ -251,14 +251,14 @@ proc trackDirty(arg: string, info: TLineInfo) =
     localError(info, errInvalidNumber, a[1])
   if parseUtils.parseInt(a[3], column) <= 0:
     localError(info, errInvalidNumber, a[2])
-  
-  gDirtyBufferIdx = a[0].fileInfoIdx
-  gDirtyOriginalIdx = a[1].fileInfoIdx
- 
-  optTrackPos = newLineInfo(gDirtyBufferIdx, line, column)
-  msgs.addCheckpoint(optTrackPos)
-
-proc track(arg: string, info: TLineInfo) = 
+
+  let dirtyOriginalIdx = a[1].fileInfoIdx
+  if dirtyOriginalIdx >= 0:
+    msgs.setDirtyFile(dirtyOriginalIdx, a[0])
+
+  gTrackPos = newLineInfo(dirtyOriginalIdx, line, column)
+
+proc track(arg: string, info: TLineInfo) =
   var a = arg.split(',')
   if a.len != 3: localError(info, errTokenExpected, "FILE,LINE,COLUMN")
   var line, column: int
@@ -266,21 +266,20 @@ proc track(arg: string, info: TLineInfo) =
     localError(info, errInvalidNumber, a[1])
   if parseUtils.parseInt(a[2], column) <= 0:
     localError(info, errInvalidNumber, a[2])
-  optTrackPos = newLineInfo(a[0], line, column)
-  msgs.addCheckpoint(optTrackPos)
+  gTrackPos = newLineInfo(a[0], line, column)
 
 proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   if pass in {passCmd2, passPP}:
     expectArg(switch, arg, pass, info)
     options.inclDynlibOverride(arg)
 
-proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = 
-  var 
+proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
+  var
     theOS: TSystemOS
     cpu: TSystemCPU
     key, val: string
   case switch.normalize
-  of "path", "p": 
+  of "path", "p":
     expectArg(switch, arg, pass, info)
     addPath(processPath(arg), info)
   of "nimblepath", "babelpath":
@@ -304,7 +303,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   of "nimcache":
     expectArg(switch, arg, pass, info)
     options.nimcacheDir = processPath(arg)
-  of "out", "o": 
+  of "out", "o":
     expectArg(switch, arg, pass, info)
     options.outFile = arg
   of "docseesrcurl":
@@ -312,46 +311,46 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
     options.docSeeSrcUrl = arg
   of "mainmodule", "m":
     discard "allow for backwards compatibility, but don't do anything"
-  of "define", "d": 
+  of "define", "d":
     expectArg(switch, arg, pass, info)
     defineSymbol(arg)
-  of "undef", "u": 
+  of "undef", "u":
     expectArg(switch, arg, pass, info)
     undefSymbol(arg)
   of "symbol":
     expectArg(switch, arg, pass, info)
-    declareSymbol(arg)  
-  of "compile": 
+    # deprecated, do nothing
+  of "compile":
     expectArg(switch, arg, pass, info)
     if pass in {passCmd2, passPP}: processCompile(arg)
-  of "link": 
+  of "link":
     expectArg(switch, arg, pass, info)
     if pass in {passCmd2, passPP}: addFileToLink(arg)
-  of "debuginfo": 
+  of "debuginfo":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optCDebug)
   of "embedsrc":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optEmbedOrigSrc)
-  of "compileonly", "c": 
+  of "compileonly", "c":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optCompileOnly)
-  of "nolinking": 
+  of "nolinking":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optNoLinking)
-  of "nomain": 
+  of "nomain":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optNoMain)
-  of "forcebuild", "f": 
+  of "forcebuild", "f":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optForceFullMake)
   of "project":
     expectNoArg(switch, arg, pass, info)
     gWholeProject = true
-  of "gc": 
+  of "gc":
     expectArg(switch, arg, pass, info)
     case arg.normalize
-    of "boehm": 
+    of "boehm":
       gSelectedGC = gcBoehm
       defineSymbol("boehmgc")
     of "refc":
@@ -369,17 +368,27 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
       defineSymbol("nogc")
     else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
   of "warnings", "w": processOnOffSwitch({optWarns}, arg, pass, info)
-  of "warning": processSpecificNote(arg, wWarning, pass, info)
-  of "hint": processSpecificNote(arg, wHint, pass, info)
+  of "warning": processSpecificNote(arg, wWarning, pass, info, switch)
+  of "hint": processSpecificNote(arg, wHint, pass, info, switch)
   of "hints": processOnOffSwitch({optHints}, arg, pass, info)
   of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
   of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info)
   of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info)
-  of "debugger": 
-    processOnOffSwitch({optEndb}, arg, pass, info)
-    if optEndb in gOptions: defineSymbol("endb")
-    else: undefSymbol("endb")
-  of "profiler": 
+  of "debugger":
+    case arg.normalize
+    of "on", "endb":
+      gOptions.incl optEndb
+      defineSymbol("endb")
+    of "off":
+      gOptions.excl optEndb
+      undefSymbol("endb")
+    of "native", "gdb":
+      incl(gGlobalOptions, optCDebug)
+      gOptions = gOptions + {optLineDir} - {optEndb}
+      undefSymbol("endb")
+    else:
+      localError(info, "expected endb|gdb but found " & arg)
+  of "profiler":
     processOnOffSwitch({optProfiler}, arg, pass, info)
     if optProfiler in gOptions: defineSymbol("profiler")
     else: undefSymbol("profiler")
@@ -398,7 +407,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
   of "threads":
     processOnOffSwitchG({optThreads}, arg, pass, info)
-    if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe)
+    #if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe)
   of "tlsemulation": processOnOffSwitchG({optTlsEmulation}, arg, pass, info)
   of "taintmode": processOnOffSwitchG({optTaintMode}, arg, pass, info)
   of "implicitstatic":
@@ -408,17 +417,17 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   of "opt":
     expectArg(switch, arg, pass, info)
     case arg.normalize
-    of "speed": 
+    of "speed":
       incl(gOptions, optOptimizeSpeed)
       excl(gOptions, optOptimizeSize)
-    of "size": 
+    of "size":
       excl(gOptions, optOptimizeSpeed)
       incl(gOptions, optOptimizeSize)
     of "none":
       excl(gOptions, optOptimizeSpeed)
       excl(gOptions, optOptimizeSize)
     else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
-  of "app": 
+  of "app":
     expectArg(switch, arg, pass, info)
     case arg.normalize
     of "gui":
@@ -440,10 +449,10 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
       defineSymbol("library")
       defineSymbol("staticlib")
     else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
-  of "passc", "t": 
+  of "passc", "t":
     expectArg(switch, arg, pass, info)
     if pass in {passCmd2, passPP}: extccomp.addCompileOption(arg)
-  of "passl", "l": 
+  of "passl", "l":
     expectArg(switch, arg, pass, info)
     if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg)
   of "cincludes":
@@ -466,52 +475,50 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   of "include":
     expectArg(switch, arg, pass, info)
     if pass in {passCmd2, passPP}: implicitIncludes.add arg
-  of "listcmd": 
+  of "listcmd":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optListCmd)
-  of "genmapping": 
+  of "genmapping":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optGenMapping)
-  of "os": 
+  of "os":
     expectArg(switch, arg, pass, info)
-    if pass in {passCmd1, passPP}: 
+    if pass in {passCmd1, passPP}:
       theOS = platform.nameToOS(arg)
       if theOS == osNone: localError(info, errUnknownOS, arg)
-      elif theOS != platform.hostOS: 
+      elif theOS != platform.hostOS:
         setTarget(theOS, targetCPU)
-        condsyms.initDefines()
-  of "cpu": 
+  of "cpu":
     expectArg(switch, arg, pass, info)
-    if pass in {passCmd1, passPP}: 
+    if pass in {passCmd1, passPP}:
       cpu = platform.nameToCPU(arg)
       if cpu == cpuNone: localError(info, errUnknownCPU, arg)
-      elif cpu != platform.hostCPU: 
+      elif cpu != platform.hostCPU:
         setTarget(targetOS, cpu)
-        condsyms.initDefines()
-  of "run", "r": 
+  of "run", "r":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optRun)
-  of "verbosity": 
+  of "verbosity":
     expectArg(switch, arg, pass, info)
     gVerbosity = parseInt(arg)
-  of "parallelbuild": 
+  of "parallelbuild":
     expectArg(switch, arg, pass, info)
     gNumberOfProcessors = parseInt(arg)
-  of "version", "v": 
+  of "version", "v":
     expectNoArg(switch, arg, pass, info)
     writeVersionInfo(pass)
-  of "advanced": 
+  of "advanced":
     expectNoArg(switch, arg, pass, info)
     writeAdvancedUsage(pass)
-  of "help", "h": 
+  of "help", "h":
     expectNoArg(switch, arg, pass, info)
     helpOnError(pass)
-  of "symbolfiles": 
+  of "symbolfiles":
     processOnOffSwitchG({optSymbolFiles}, arg, pass, info)
-  of "skipcfg": 
+  of "skipcfg":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optSkipConfigFile)
-  of "skipprojcfg": 
+  of "skipprojcfg":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optSkipProjConfigFile)
   of "skipusercfg":
@@ -520,17 +527,17 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   of "skipparentcfg":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optSkipParentConfigFiles)
-  of "genscript": 
+  of "genscript":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optGenScript)
   of "lib":
     expectArg(switch, arg, pass, info)
     libpath = processPath(arg, notRelativeToProj=true)
-  of "putenv": 
+  of "putenv":
     expectArg(switch, arg, pass, info)
     splitSwitch(arg, key, val, pass, info)
     os.putEnv(key, val)
-  of "cc": 
+  of "cc":
     expectArg(switch, arg, pass, info)
     setCC(arg)
   of "track":
@@ -539,21 +546,21 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   of "trackdirty":
     expectArg(switch, arg, pass, info)
     trackDirty(arg, info)
-  of "suggest": 
+  of "suggest":
     expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optSuggest)
+    gIdeCmd = ideSug
   of "def":
     expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optDef)
+    gIdeCmd = ideDef
   of "eval":
     expectArg(switch, arg, pass, info)
     gEvalExpr = arg
   of "context":
     expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optContext)
+    gIdeCmd = ideCon
   of "usages":
     expectNoArg(switch, arg, pass, info)
-    incl(gGlobalOptions, optUsages)
+    gIdeCmd = ideUse
   of "stdout":
     expectNoArg(switch, arg, pass, info)
     incl(gGlobalOptions, optStdout)
@@ -575,7 +582,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
   else:
     if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
     else: invalidCmdLineOption(pass, switch, info)
-  
+
 proc processCommand(switch: string, pass: TCmdLinePass) =
   var cmd, arg: string
   splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
@@ -591,14 +598,14 @@ proc processSwitch*(pass: TCmdLinePass; p: OptParser) =
   # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
   # we fix this here
   var bracketLe = strutils.find(p.key, '[')
-  if bracketLe >= 0: 
+  if bracketLe >= 0:
     var key = substr(p.key, 0, bracketLe - 1)
     var val = substr(p.key, bracketLe + 1) & ':' & p.val
     processSwitch(key, val, pass, gCmdLineInfo)
-  else: 
+  else:
     processSwitch(p.key, p.val, pass, gCmdLineInfo)
 
-proc processArgument*(pass: TCmdLinePass; p: OptParser; 
+proc processArgument*(pass: TCmdLinePass; p: OptParser;
                       argsCount: var int): bool =
   if argsCount == 0:
     options.command = p.key
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index 9c07972cf..ad7d80c85 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -9,71 +9,69 @@
 
 # This module handles the conditional symbols.
 
-import 
+import
   strtabs, platform, strutils, idents
 
-# We need to use a PStringTable here as defined symbols are always guaranteed
+# We need to use a StringTableRef here as defined symbols are always guaranteed
 # to be style insensitive. Otherwise hell would break lose.
 var gSymbols: StringTableRef
 
-proc defineSymbol*(symbol: string) = 
-  gSymbols[symbol] = "true"
+const
+  catNone = "false"
 
-proc declareSymbol*(symbol: string) = 
-  gSymbols[symbol] = "unknown"
+proc defineSymbol*(symbol: string) =
+  gSymbols[symbol] = "true"
 
-proc undefSymbol*(symbol: string) = 
-  gSymbols[symbol] = "false"
+proc undefSymbol*(symbol: string) =
+  gSymbols[symbol] = catNone
 
-proc isDefined*(symbol: string): bool = 
+proc isDefined*(symbol: string): bool =
   if gSymbols.hasKey(symbol):
-    result = gSymbols[symbol] == "true"
-  
+    result = gSymbols[symbol] != catNone
+  elif cmpIgnoreStyle(symbol, CPU[targetCPU].name) == 0:
+    result = true
+  elif cmpIgnoreStyle(symbol, platform.OS[targetOS].name) == 0:
+    result = true
+  else:
+    case symbol.normalize
+    of "x86": result = targetCPU == cpuI386
+    of "itanium": result = targetCPU == cpuIa64
+    of "x8664": result = targetCPU == cpuAmd64
+    of "posix", "unix":
+      result = targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos,
+                            osQnx, osAtari, osAix,
+                            osHaiku, osVxWorks, osSolaris, osNetbsd,
+                            osFreebsd, osOpenbsd, osMacosx}
+    of "bsd":
+      result = targetOS in {osNetbsd, osFreebsd, osOpenbsd}
+    of "emulatedthreadvars":
+      result = platform.OS[targetOS].props.contains(ospLacksThreadVars)
+    of "msdos": result = targetOS == osDos
+    of "mswindows", "win32": result = targetOS == osWindows
+    of "macintosh": result = targetOS in {osMacos, osMacosx}
+    of "sunos": result = targetOS == osSolaris
+    of "littleendian": result = CPU[targetCPU].endian == platform.littleEndian
+    of "bigendian": result = CPU[targetCPU].endian == platform.bigEndian
+    of "cpu8": result = CPU[targetCPU].bit == 8
+    of "cpu16": result = CPU[targetCPU].bit == 16
+    of "cpu32": result = CPU[targetCPU].bit == 32
+    of "cpu64": result = CPU[targetCPU].bit == 64
+    of "nimrawsetjmp":
+      result = targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd, osMacosx}
+    else: discard
+
 proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s)
-proc isDeclared*(symbol: PIdent): bool = gSymbols.hasKey(symbol.s)
 
 iterator definedSymbolNames*: string =
   for key, val in pairs(gSymbols):
-    if val == "true": yield key
+    if val != catNone: yield key
 
-proc countDefinedSymbols*(): int = 
+proc countDefinedSymbols*(): int =
   result = 0
   for key, val in pairs(gSymbols):
-    if val == "true": inc(result)
-
-# For ease of bootstrapping, we keep them here and not in the global config
-# file for now:
-const
-  additionalSymbols = """
-    x86 itanium x8664
-    msdos mswindows win32 unix posix sunos bsd macintosh RISCOS doslike hpux
-    mac
-
-    hppa hp9000 hp9000s300 hp9000s700 hp9000s800 hp9000s820 ELATE sparcv9
+    if val != catNone: inc(result)
 
-    ecmascript js nimrodvm nimffi nimdoc cpp objc
-    gcc llvmgcc clang lcc bcc dmc wcc vcc tcc pcc ucc icl
-    boehmgc gcmarkandsweep gcgenerational nogc gcUseBitvectors
-    endb profiler
-    executable guiapp consoleapp library dll staticlib
-
-    quick
-    release debug
-    useWinAnsi useFork useNimRtl useMalloc useRealtimeGC ssl memProfiler
-    nodejs kwin nimfix
-
-    usesysassert usegcassert tinyC useFFI
-    useStdoutAsStdmsg createNimRtl
-    booting fulldebug corruption nimsuperops noSignalHandler useGnuReadline
-    noCaas noDocGen noBusyWaiting nativeStackTrace useNodeIds selftest
-    reportMissedDeadlines avoidTimeMachine useClone ignoreAllocationSize
-    debugExecProcesses pcreDll useLipzipSrc
-    preventDeadlocks UNICODE winUnicode trackGcHeaders posixRealtime
-
-    nimStdSetjmp nimRawSetjmp nimSigSetjmp
-  """.split
-
-proc initDefines*() = 
+proc initDefines*() =
   gSymbols = newStringTable(modeStyleInsensitive)
   defineSymbol("nimrod") # 'nimrod' is always defined
   # for bootstrapping purposes and old code:
@@ -89,58 +87,4 @@ proc initDefines*() =
   defineSymbol("nimparsebiggestfloatmagic")
   defineSymbol("nimalias")
   defineSymbol("nimlocks")
-  
-  # add platform specific symbols:
-  for c in low(CPU)..high(CPU):
-    declareSymbol("cpu" & $CPU[c].bit)
-    declareSymbol(normalize(EndianToStr[CPU[c].endian]))
-    declareSymbol(CPU[c].name)
-  for o in low(platform.OS)..high(platform.OS):
-    declareSymbol(platform.OS[o].name)
-
-  for a in additionalSymbols:
-    declareSymbol(a)
-
-  # -----------------------------------------------------------
-  case targetCPU
-  of cpuI386: defineSymbol("x86")
-  of cpuIa64: defineSymbol("itanium")
-  of cpuAmd64: defineSymbol("x8664")
-  else: discard
-  case targetOS
-  of osDos: 
-    defineSymbol("msdos")
-  of osWindows: 
-    defineSymbol("mswindows")
-    defineSymbol("win32")
-  of osLinux, osMorphos, osSkyos, osIrix, osPalmos, osQnx, osAtari, osAix, 
-     osHaiku:
-    # these are all 'unix-like'
-    defineSymbol("unix")
-    defineSymbol("posix")
-  of osSolaris: 
-    defineSymbol("sunos")
-    defineSymbol("unix")
-    defineSymbol("posix")
-  of osNetbsd, osFreebsd, osOpenbsd: 
-    defineSymbol("unix")
-    defineSymbol("bsd")
-    defineSymbol("posix")
-  of osMacos: 
-    defineSymbol("macintosh")
-  of osMacosx: 
-    defineSymbol("macintosh")
-    defineSymbol("unix")
-    defineSymbol("posix")
-  else: discard
-  defineSymbol("cpu" & $CPU[targetCPU].bit)
-  defineSymbol(normalize(EndianToStr[CPU[targetCPU].endian]))
-  defineSymbol(CPU[targetCPU].name)
-  defineSymbol(platform.OS[targetOS].name)
-  declareSymbol("emulatedthreadvars")
-  if platform.OS[targetOS].props.contains(ospLacksThreadVars):
-    defineSymbol("emulatedthreadvars")
-  case targetOS
-  of osSolaris, osNetbsd, osFreebsd, osOpenbsd, osMacosx:
-    defineSymbol("nimRawSetjmp")
-  else: discard
+  defineSymbol("nimnode")
diff --git a/compiler/depends.nim b/compiler/depends.nim
index 115a98f84..1ccb134f2 100644
--- a/compiler/depends.nim
+++ b/compiler/depends.nim
@@ -9,41 +9,41 @@
 
 # This module implements a dependency file generator.
 
-import 
+import
   os, options, ast, astalgo, msgs, ropes, idents, passes, importer
 
 proc generateDot*(project: string)
 
-type 
+type
   TGen = object of TPassContext
     module*: PSym
   PGen = ref TGen
 
-var gDotGraph: PRope # the generated DOT file; we need a global variable
+var gDotGraph: Rope # the generated DOT file; we need a global variable
 
-proc addDependencyAux(importing, imported: string) = 
-  appf(gDotGraph, "$1 -> $2;$n", [toRope(importing), toRope(imported)]) 
+proc addDependencyAux(importing, imported: string) =
+  addf(gDotGraph, "$1 -> $2;$n", [rope(importing), rope(imported)])
   # s1 -> s2_4[label="[0-9]"];
-  
-proc addDotDependency(c: PPassContext, n: PNode): PNode = 
+
+proc addDotDependency(c: PPassContext, n: PNode): PNode =
   result = n
   var g = PGen(c)
   case n.kind
-  of nkImportStmt: 
-    for i in countup(0, sonsLen(n) - 1): 
+  of nkImportStmt:
+    for i in countup(0, sonsLen(n) - 1):
       var imported = getModuleName(n.sons[i])
       addDependencyAux(g.module.name.s, imported)
-  of nkFromStmt, nkImportExceptStmt: 
+  of nkFromStmt, nkImportExceptStmt:
     var imported = getModuleName(n.sons[0])
     addDependencyAux(g.module.name.s, imported)
-  of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr: 
+  of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
     for i in countup(0, sonsLen(n) - 1): discard addDotDependency(c, n.sons[i])
-  else: 
+  else:
     discard
 
-proc generateDot(project: string) = 
-  writeRope(ropef("digraph $1 {$n$2}$n", [
-      toRope(changeFileExt(extractFilename(project), "")), gDotGraph]), 
+proc generateDot(project: string) =
+  writeRope("digraph $1 {$n$2}$n" % [
+      rope(changeFileExt(extractFilename(project), "")), gDotGraph],
             changeFileExt(project, "dot"))
 
 proc myOpen(module: PSym): PPassContext =
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 35acf1379..f8489d825 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -17,12 +17,13 @@ import
   importer, sempass2, json, xmltree, cgi, typesrenderer
 
 type
-  TSections = array[TSymKind, PRope]
+  TSections = array[TSymKind, Rope]
   TDocumentor = object of rstgen.TRstGenerator
-    modDesc: PRope           # module description
+    modDesc: Rope           # module description
     id: int                  # for generating IDs
     toc, section: TSections
     indexValFilename: string
+    analytics: string  # Google Analytics javascript, "" if doesn't exist
     seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML.
 
   PDoc* = ref TDocumentor ## Alias to type less.
@@ -61,12 +62,29 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
   initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex),
                    options.gConfigVars, filename, {roSupportRawDirective},
                    docgenFindFile, compilerMsgHandler)
+
+  if config.hasKey("doc.googleAnalytics"):
+    result.analytics = """
+<script>
+  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+  ga('create', '$1', 'auto');
+  ga('send', 'pageview');
+
+</script>
+    """ % [config["doc.googleAnalytics"]]
+  else:
+    result.analytics = ""
+
   result.seenSymbols = newStringTable(modeCaseInsensitive)
   result.id = 100
 
-proc dispA(dest: var PRope, xml, tex: string, args: openArray[PRope]) =
-  if gCmd != cmdRst2tex: appf(dest, xml, args)
-  else: appf(dest, tex, args)
+proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) =
+  if gCmd != cmdRst2tex: addf(dest, xml, args)
+  else: addf(dest, tex, args)
 
 proc getVarIdx(varnames: openArray[string], id: string): int =
   for i in countup(0, high(varnames)):
@@ -74,8 +92,8 @@ proc getVarIdx(varnames: openArray[string], id: string): int =
       return i
   result = -1
 
-proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
-                         varvalues: openArray[PRope]): PRope =
+proc ropeFormatNamedVars(frmt: FormatStr, varnames: openArray[string],
+                         varvalues: openArray[Rope]): Rope =
   var i = 0
   var L = len(frmt)
   result = nil
@@ -85,11 +103,11 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
       inc(i)                  # skip '$'
       case frmt[i]
       of '#':
-        app(result, varvalues[num])
+        add(result, varvalues[num])
         inc(num)
         inc(i)
       of '$':
-        app(result, "$")
+        add(result, "$")
         inc(i)
       of '0'..'9':
         var j = 0
@@ -99,7 +117,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
           if (i > L + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
         if j > high(varvalues) + 1: internalError("ropeFormatNamedVars")
         num = j
-        app(result, varvalues[j - 1])
+        add(result, varvalues[j - 1])
       of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
         var id = ""
         while true:
@@ -107,8 +125,8 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
           inc(i)
           if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
         var idx = getVarIdx(varnames, id)
-        if idx >= 0: app(result, varvalues[idx])
-        else: rawMessage(errUnkownSubstitionVar, id)
+        if idx >= 0: add(result, varvalues[idx])
+        else: rawMessage(errUnknownSubstitionVar, id)
       of '{':
         var id = ""
         inc(i)
@@ -119,14 +137,14 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
         inc(i)                # skip }
                               # search for the variable:
         var idx = getVarIdx(varnames, id)
-        if idx >= 0: app(result, varvalues[idx])
-        else: rawMessage(errUnkownSubstitionVar, id)
+        if idx >= 0: add(result, varvalues[idx])
+        else: rawMessage(errUnknownSubstitionVar, id)
       else: internalError("ropeFormatNamedVars")
     var start = i
     while i < L:
       if frmt[i] != '$': inc(i)
       else: break
-    if i - 1 >= start: app(result, substr(frmt, start, i - 1))
+    if i - 1 >= start: add(result, substr(frmt, start, i - 1))
 
 proc genComment(d: PDoc, n: PNode): string =
   result = ""
@@ -136,9 +154,9 @@ proc genComment(d: PDoc, n: PNode): string =
                                toLinenumber(n.info), toColumn(n.info),
                                dummyHasToc, d.options + {roSkipPounds}), result)
 
-proc genRecComment(d: PDoc, n: PNode): PRope =
+proc genRecComment(d: PDoc, n: PNode): Rope =
   if n == nil: return nil
-  result = genComment(d, n).toRope
+  result = genComment(d, n).rope
   if result == nil:
     if n.kind notin {nkEmpty..nkNilLit}:
       for i in countup(0, len(n)-1):
@@ -254,7 +272,7 @@ proc complexName(k: TSymKind, n: PNode, baseName: string): string =
   ## type)?(,param type)*``. The callable type part will be added only if the
   ## node is not a proc, as those are the common ones. The suffix will be a dot
   ## and a single letter representing the type of the callable. The parameter
-  ## types will be added with a preceeding dash. Return types won't be added.
+  ## types will be added with a preceding dash. Return types won't be added.
   ##
   ## If you modify the output of this proc, please update the anchor generation
   ## section of ``doc/docgen.txt``.
@@ -313,9 +331,9 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
   if not isVisible(nameNode): return
   let
     name = getName(d, nameNode)
-    nameRope = name.toRope
+    nameRope = name.rope
     plainDocstring = getPlainDocstring(n) # call here before genRecComment!
-  var result: PRope = nil
+  var result: Rope = nil
   var literal, plainName = ""
   var kind = tkEof
   var comm = genRecComment(d, n)  # call this here for the side-effect!
@@ -338,69 +356,69 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
       break
     of tkComment:
       dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
-            [toRope(esc(d.target, literal))])
+            [rope(esc(d.target, literal))])
     of tokKeywordLow..tokKeywordHigh:
       dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
-            [toRope(literal)])
+            [rope(literal)])
     of tkOpr:
       dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
-            [toRope(esc(d.target, literal))])
+            [rope(esc(d.target, literal))])
     of tkStrLit..tkTripleStrLit:
       dispA(result, "<span class=\"StringLit\">$1</span>",
-            "\\spanStringLit{$1}", [toRope(esc(d.target, literal))])
+            "\\spanStringLit{$1}", [rope(esc(d.target, literal))])
     of tkCharLit:
       dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
-            [toRope(esc(d.target, literal))])
+            [rope(esc(d.target, literal))])
     of tkIntLit..tkUInt64Lit:
       dispA(result, "<span class=\"DecNumber\">$1</span>",
-            "\\spanDecNumber{$1}", [toRope(esc(d.target, literal))])
+            "\\spanDecNumber{$1}", [rope(esc(d.target, literal))])
     of tkFloatLit..tkFloat128Lit:
       dispA(result, "<span class=\"FloatNumber\">$1</span>",
-            "\\spanFloatNumber{$1}", [toRope(esc(d.target, literal))])
+            "\\spanFloatNumber{$1}", [rope(esc(d.target, literal))])
     of tkSymbol:
       dispA(result, "<span class=\"Identifier\">$1</span>",
-            "\\spanIdentifier{$1}", [toRope(esc(d.target, literal))])
+            "\\spanIdentifier{$1}", [rope(esc(d.target, literal))])
     of tkSpaces, tkInvalid:
-      app(result, literal)
+      add(result, literal)
     of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
        tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe,
        tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
        tkAccent, tkColonColon,
        tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
       dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
-            [toRope(esc(d.target, literal))])
+            [rope(esc(d.target, literal))])
   inc(d.id)
   let
-    plainNameRope = toRope(xmltree.escape(plainName.strip))
+    plainNameRope = rope(xmltree.escape(plainName.strip))
     cleanPlainSymbol = renderPlainSymbolName(nameNode)
     complexSymbol = complexName(k, n, cleanPlainSymbol)
-    plainSymbolRope = toRope(cleanPlainSymbol)
-    plainSymbolEncRope = toRope(encodeUrl(cleanPlainSymbol))
-    itemIDRope = toRope(d.id)
+    plainSymbolRope = rope(cleanPlainSymbol)
+    plainSymbolEncRope = rope(encodeUrl(cleanPlainSymbol))
+    itemIDRope = rope(d.id)
     symbolOrId = d.newUniquePlainSymbol(complexSymbol)
-    symbolOrIdRope = symbolOrId.toRope
-    symbolOrIdEncRope = encodeUrl(symbolOrId).toRope
+    symbolOrIdRope = symbolOrId.rope
+    symbolOrIdEncRope = encodeUrl(symbolOrId).rope
 
-  var seeSrcRope: PRope = nil
+  var seeSrcRope: Rope = nil
   let docItemSeeSrc = getConfigVar("doc.item.seesrc")
   if docItemSeeSrc.len > 0 and options.docSeeSrcUrl.len > 0:
     # XXX toFilename doesn't really work. We need to ensure that this keeps
     # returning a relative path.
     let urlRope = ropeFormatNamedVars(options.docSeeSrcUrl,
-      ["path", "line"], [n.info.toFilename.toRope, toRope($n.info.line)])
+      ["path", "line"], [n.info.toFilename.rope, rope($n.info.line)])
     dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc,
-        ["path", "line", "url"], [n.info.toFilename.toRope,
-        toRope($n.info.line), urlRope])])
+        ["path", "line", "url"], [n.info.toFilename.rope,
+        rope($n.info.line), urlRope])])
 
-  app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
+  add(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
     ["name", "header", "desc", "itemID", "header_plain", "itemSym",
       "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "seeSrc"],
     [nameRope, result, comm, itemIDRope, plainNameRope, plainSymbolRope,
       symbolOrIdRope, plainSymbolEncRope, symbolOrIdEncRope, seeSrcRope]))
-  app(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
+  add(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
     ["name", "header", "desc", "itemID", "header_plain", "itemSym",
       "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc"],
-    [toRope(getName(d, nameNode, d.splitAfter)), result, comm,
+    [rope(getName(d, nameNode, d.splitAfter)), result, comm,
       itemIDRope, plainNameRope, plainSymbolRope, symbolOrIdRope,
       plainSymbolEncRope, symbolOrIdEncRope]))
 
@@ -418,7 +436,7 @@ proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
   if not isVisible(nameNode): return
   var
     name = getName(d, nameNode)
-    comm = genRecComment(d, n).ropeToStr()
+    comm = $genRecComment(d, n)
     r: TSrcGen
 
   initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
@@ -435,14 +453,14 @@ proc checkForFalse(n: PNode): bool =
 
 proc traceDeps(d: PDoc, n: PNode) =
   const k = skModule
-  if d.section[k] != nil: app(d.section[k], ", ")
+  if d.section[k] != nil: add(d.section[k], ", ")
   dispA(d.section[k],
         "<a class=\"reference external\" href=\"$1.html\">$1</a>",
-        "$1", [toRope(getModuleName(n))])
+        "$1", [rope(getModuleName(n))])
 
 proc generateDoc*(d: PDoc, n: PNode) =
   case n.kind
-  of nkCommentStmt: app(d.modDesc, genComment(d, n))
+  of nkCommentStmt: add(d.modDesc, genComment(d, n))
   of nkProcDef:
     when useEffectSystem: documentRaises(n)
     genItem(d, n, n.sons[namePos], skProc)
@@ -503,13 +521,13 @@ proc generateJson(d: PDoc, n: PNode, jArray: JsonNode = nil): JsonNode =
         result = genJSONItem(d, n.sons[i], n.sons[i].sons[0],
                 succ(skType, ord(n.kind)-ord(nkTypeSection)))
   of nkStmtList:
-    var elem = jArray
-    if elem == nil: elem = newJArray()
+    result = if jArray != nil: jArray else: newJArray()
+
     for i in countup(0, sonsLen(n) - 1):
-      var r = generateJson(d, n.sons[i], elem)
+      var r = generateJson(d, n.sons[i], result)
       if r != nil:
-        elem.add(r)
-        if result == nil: result = elem
+        result.add(r)
+
   of nkWhenStmt:
     # generate documentation for the first branch only:
     if not checkForFalse(n.sons[0].sons[0]) and jArray != nil:
@@ -522,28 +540,28 @@ proc genSection(d: PDoc, kind: TSymKind) =
     "Iterators", "Iterators", "Converters", "Macros", "Templates"
   ]
   if d.section[kind] == nil: return
-  var title = sectionNames[kind].toRope
+  var title = sectionNames[kind].rope
   d.section[kind] = ropeFormatNamedVars(getConfigVar("doc.section"), [
       "sectionid", "sectionTitle", "sectionTitleID", "content"], [
-      ord(kind).toRope, title, toRope(ord(kind) + 50), d.section[kind]])
+      ord(kind).rope, title, rope(ord(kind) + 50), d.section[kind]])
   d.toc[kind] = ropeFormatNamedVars(getConfigVar("doc.section.toc"), [
       "sectionid", "sectionTitle", "sectionTitleID", "content"], [
-      ord(kind).toRope, title, toRope(ord(kind) + 50), d.toc[kind]])
+      ord(kind).rope, title, rope(ord(kind) + 50), d.toc[kind]])
 
-proc genOutFile(d: PDoc): PRope =
+proc genOutFile(d: PDoc): Rope =
   var
-    code, content: PRope
+    code, content: Rope
     title = ""
   var j = 0
   var tmp = ""
   renderTocEntries(d[], j, 1, tmp)
-  var toc = tmp.toRope
+  var toc = tmp.rope
   for i in countup(low(TSymKind), high(TSymKind)):
     genSection(d, i)
-    app(toc, d.toc[i])
+    add(toc, d.toc[i])
   if toc != nil:
     toc = ropeFormatNamedVars(getConfigVar("doc.toc"), ["content"], [toc])
-  for i in countup(low(TSymKind), high(TSymKind)): app(code, d.section[i])
+  for i in countup(low(TSymKind), high(TSymKind)): add(code, d.section[i])
 
   # Extract the title. Non API modules generate an entry in the index table.
   if d.meta[metaTitle].len != 0:
@@ -556,16 +574,16 @@ proc genOutFile(d: PDoc): PRope =
   let bodyname = if d.hasToc: "doc.body_toc" else: "doc.body_no_toc"
   content = ropeFormatNamedVars(getConfigVar(bodyname), ["title",
       "tableofcontents", "moduledesc", "date", "time", "content"],
-      [title.toRope, toc, d.modDesc, toRope(getDateStr()),
-      toRope(getClockStr()), code])
+      [title.rope, toc, d.modDesc, rope(getDateStr()),
+      rope(getClockStr()), code])
   if optCompileOnly notin gGlobalOptions:
     # XXX what is this hack doing here? 'optCompileOnly' means raw output!?
     code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
         "tableofcontents", "moduledesc", "date", "time",
-        "content", "author", "version"],
-        [title.toRope, toc, d.modDesc, toRope(getDateStr()),
-                     toRope(getClockStr()), content, d.meta[metaAuthor].toRope,
-                     d.meta[metaVersion].toRope])
+        "content", "author", "version", "analytics"],
+        [title.rope, toc, d.modDesc, rope(getDateStr()),
+                     rope(getClockStr()), content, d.meta[metaAuthor].rope,
+                     d.meta[metaVersion].rope, d.analytics.rope])
   else:
     code = content
   result = code
@@ -600,7 +618,7 @@ proc commandRstAux(filename, outExt: string) =
   #d.modDesc = newMutableRope(30_000)
   renderRstToOut(d[], rst, modDesc)
   #freezeMutableRope(d.modDesc)
-  d.modDesc = toRope(modDesc)
+  d.modDesc = rope(modDesc)
   writeOutput(d, filename, outExt)
   generateIndex(d)
 
@@ -617,7 +635,7 @@ proc commandJSON*() =
   var d = newDocumentor(gProjectFull, options.gConfigVars)
   d.hasToc = true
   var json = generateJson(d, ast)
-  var content = newRope(pretty(json))
+  var content = rope(pretty(json))
 
   if optStdout in gGlobalOptions:
     writeRope(stdout, content)
@@ -626,11 +644,12 @@ proc commandJSON*() =
     writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
 
 proc commandBuildIndex*() =
-  var content = mergeIndexes(gProjectFull).toRope
+  var content = mergeIndexes(gProjectFull).rope
 
   let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
       "tableofcontents", "moduledesc", "date", "time",
-      "content", "author", "version"],
-      ["Index".toRope, nil, nil, toRope(getDateStr()),
-                   toRope(getClockStr()), content, nil, nil])
+      "content", "author", "version", "analytics"],
+      ["Index".rope, nil, nil, rope(getDateStr()),
+                   rope(getClockStr()), content, nil, nil, nil])
+  # no analytics because context is not available
   writeRope(code, getOutFile("theindex", HtmlExt))
diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim
deleted file mode 100644
index d6b3a1aa5..000000000
--- a/compiler/evalffi.nim
+++ /dev/null
@@ -1,495 +0,0 @@
-#
-#
-#           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This file implements the FFI part of the evaluator for Nim code.
-
-import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs, os
-
-when defined(windows):
-  const libcDll = "msvcrt.dll"
-else:
-  const libcDll = "libc.so(.6|.5|)"
-
-type
-  TDllCache = tables.TTable[string, TLibHandle]
-var
-  gDllCache = initTable[string, TLibHandle]()
-
-when defined(windows):
-  var gExeHandle = loadLib(os.getAppFilename())
-else:
-  var gExeHandle = loadLib()
-
-proc getDll(cache: var TDllCache; dll: string; info: TLineInfo): pointer =
-  result = cache[dll]
-  if result.isNil:
-    var libs: seq[string] = @[]
-    libCandidates(dll, libs)
-    for c in libs:
-      result = loadLib(c)
-      if not result.isNil: break
-    if result.isNil:
-      globalError(info, "cannot load: " & dll)
-    cache[dll] = result
-
-const
-  nkPtrLit = nkIntLit # hopefully we can get rid of this hack soon
-
-var myerrno {.importc: "errno", header: "<errno.h>".}: cint ## error variable
-
-proc importcSymbol*(sym: PSym): PNode =
-  let name = ropeToStr(sym.loc.r)
-  
-  # the AST does not support untyped pointers directly, so we use an nkIntLit
-  # that contains the address instead:
-  result = newNodeIT(nkPtrLit, sym.info, sym.typ)
-  case name
-  of "stdin":  result.intVal = cast[TAddress](system.stdin)
-  of "stdout": result.intVal = cast[TAddress](system.stdout)
-  of "stderr": result.intVal = cast[TAddress](system.stderr)
-  of "vmErrnoWrapper": result.intVal = cast[TAddress](myerrno)
-  else:
-    let lib = sym.annex
-    if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
-      globalError(sym.info, "dynlib needs to be a string lit for the REPL")
-    var theAddr: pointer
-    if lib.isNil and not gExehandle.isNil:
-      # first try this exe itself:
-      theAddr = gExehandle.symAddr(name)
-      # then try libc:
-      if theAddr.isNil:
-        let dllhandle = gDllCache.getDll(libcDll, sym.info)
-        theAddr = dllhandle.symAddr(name)
-    elif not lib.isNil:
-      let dllhandle = gDllCache.getDll(if lib.kind == libHeader: libcDll 
-                                       else: lib.path.strVal, sym.info)
-      theAddr = dllhandle.symAddr(name)
-    if theAddr.isNil: globalError(sym.info, "cannot import: " & sym.name.s)
-    result.intVal = cast[TAddress](theAddr)
-
-proc mapType(t: ast.PType): ptr libffi.TType =
-  if t == nil: return addr libffi.type_void
-  
-  case t.kind
-  of tyBool, tyEnum, tyChar, tyInt..tyInt64, tyUInt..tyUInt64, tySet:
-    case t.getSize
-    of 1: result = addr libffi.type_uint8
-    of 2: result = addr libffi.type_sint16
-    of 4: result = addr libffi.type_sint32
-    of 8: result = addr libffi.type_sint64
-    else: result = nil
-  of tyFloat, tyFloat64: result = addr libffi.type_double
-  of tyFloat32: result = addr libffi.type_float
-  of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,
-     tyStmt, tyTypeDesc, tyProc, tyArray, tyArrayConstr, tyStatic, tyNil:
-    result = addr libffi.type_pointer
-  of tyDistinct:
-    result = mapType(t.sons[0])
-  else:
-    result = nil
-  # too risky:
-  #of tyFloat128: result = addr libffi.type_longdouble
-
-proc mapCallConv(cc: TCallingConvention, info: TLineInfo): TABI =
-  case cc
-  of ccDefault: result = DEFAULT_ABI
-  of ccStdCall: result = when defined(windows): STDCALL else: DEFAULT_ABI
-  of ccCDecl: result = DEFAULT_ABI
-  else:
-    globalError(info, "cannot map calling convention to FFI")
-
-template rd(T, p: expr): expr {.immediate.} = (cast[ptr T](p))[]
-template wr(T, p, v: expr) {.immediate.} = (cast[ptr T](p))[] = v
-template `+!`(x, y: expr): expr {.immediate.} =
-  cast[pointer](cast[TAddress](x) + y)
-
-proc packSize(v: PNode, typ: PType): int =
-  ## computes the size of the blob
-  case typ.kind
-  of tyPtr, tyRef, tyVar:
-    if v.kind in {nkNilLit, nkPtrLit}:
-      result = sizeof(pointer)
-    else:
-      result = sizeof(pointer) + packSize(v.sons[0], typ.lastSon)
-  of tyDistinct, tyGenericInst:
-    result = packSize(v, typ.sons[0])
-  of tyArray, tyArrayConstr:
-    # consider: ptr array[0..1000_000, int] which is common for interfacing;
-    # we use the real length here instead
-    if v.kind in {nkNilLit, nkPtrLit}:
-      result = sizeof(pointer)
-    elif v.len != 0:
-      result = v.len * packSize(v.sons[0], typ.sons[1])
-  else:
-    result = typ.getSize.int
-
-proc pack(v: PNode, typ: PType, res: pointer)
-
-proc getField(n: PNode; position: int): PSym =
-  case n.kind
-  of nkRecList:
-    for i in countup(0, sonsLen(n) - 1):
-      result = getField(n.sons[i], position)
-      if result != nil: return 
-  of nkRecCase:
-    result = getField(n.sons[0], position)
-    if result != nil: return
-    for i in countup(1, sonsLen(n) - 1):
-      case n.sons[i].kind
-      of nkOfBranch, nkElse:
-        result = getField(lastSon(n.sons[i]), position)
-        if result != nil: return
-      else: internalError(n.info, "getField(record case branch)")
-  of nkSym:
-    if n.sym.position == position: result = n.sym
-  else: discard
-
-proc packObject(x: PNode, typ: PType, res: pointer) =
-  internalAssert x.kind in {nkObjConstr, nkPar}
-  # compute the field's offsets:
-  discard typ.getSize
-  for i in countup(ord(x.kind == nkObjConstr), sonsLen(x) - 1):
-    var it = x.sons[i]
-    if it.kind == nkExprColonExpr:
-      internalAssert it.sons[0].kind == nkSym
-      let field = it.sons[0].sym
-      pack(it.sons[1], field.typ, res +! field.offset)
-    elif typ.n != nil:
-      let field = getField(typ.n, i)
-      pack(it, field.typ, res +! field.offset)
-    else:
-      globalError(x.info, "cannot pack unnamed tuple")
-
-const maxPackDepth = 20
-var packRecCheck = 0
-
-proc pack(v: PNode, typ: PType, res: pointer) =
-  template awr(T, v: expr) {.immediate, dirty.} =
-    wr(T, res, v)
-
-  case typ.kind
-  of tyBool: awr(bool, v.intVal != 0)
-  of tyChar: awr(char, v.intVal.chr)
-  of tyInt:  awr(int, v.intVal.int)
-  of tyInt8: awr(int8, v.intVal.int8)
-  of tyInt16: awr(int16, v.intVal.int16)
-  of tyInt32: awr(int32, v.intVal.int32)
-  of tyInt64: awr(int64, v.intVal.int64)
-  of tyUInt: awr(uint, v.intVal.uint)
-  of tyUInt8: awr(uint8, v.intVal.uint8)
-  of tyUInt16: awr(uint16, v.intVal.uint16)
-  of tyUInt32: awr(uint32, v.intVal.uint32)
-  of tyUInt64: awr(uint64, v.intVal.uint64)
-  of tyEnum, tySet:
-    case v.typ.getSize
-    of 1: awr(uint8, v.intVal.uint8)
-    of 2: awr(uint16, v.intVal.uint16)
-    of 4: awr(int32, v.intVal.int32)
-    of 8: awr(int64, v.intVal.int64)
-    else:
-      globalError(v.info, "cannot map value to FFI (tyEnum, tySet)")
-  of tyFloat: awr(float, v.floatVal)
-  of tyFloat32: awr(float32, v.floatVal)
-  of tyFloat64: awr(float64, v.floatVal)
-  
-  of tyPointer, tyProc,  tyCString, tyString:
-    if v.kind == nkNilLit:
-      # nothing to do since the memory is 0 initialized anyway
-      discard
-    elif v.kind == nkPtrLit:
-      awr(pointer, cast[pointer](v.intVal))
-    elif v.kind in {nkStrLit..nkTripleStrLit}:
-      awr(cstring, cstring(v.strVal))
-    else:
-      globalError(v.info, "cannot map pointer/proc value to FFI")
-  of tyPtr, tyRef, tyVar:
-    if v.kind == nkNilLit:
-      # nothing to do since the memory is 0 initialized anyway
-      discard
-    elif v.kind == nkPtrLit:
-      awr(pointer, cast[pointer](v.intVal))
-    else:
-      if packRecCheck > maxPackDepth:
-        packRecCheck = 0
-        globalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
-      inc packRecCheck
-      pack(v.sons[0], typ.lastSon, res +! sizeof(pointer))
-      dec packRecCheck
-      awr(pointer, res +! sizeof(pointer))
-  of tyArray, tyArrayConstr:
-    let baseSize = typ.sons[1].getSize
-    for i in 0 .. <v.len:
-      pack(v.sons[i], typ.sons[1], res +! i * baseSize)
-  of tyObject, tyTuple:
-    packObject(v, typ, res)
-  of tyNil:
-    discard
-  of tyDistinct, tyGenericInst:
-    pack(v, typ.sons[0], res)
-  else:
-    globalError(v.info, "cannot map value to FFI " & typeToString(v.typ))
-
-proc unpack(x: pointer, typ: PType, n: PNode): PNode
-
-proc unpackObjectAdd(x: pointer, n, result: PNode) =
-  case n.kind
-  of nkRecList:
-    for i in countup(0, sonsLen(n) - 1):
-      unpackObjectAdd(x, n.sons[i], result)
-  of nkRecCase:
-    globalError(result.info, "case objects cannot be unpacked")
-  of nkSym:
-    var pair = newNodeI(nkExprColonExpr, result.info, 2)
-    pair.sons[0] = n
-    pair.sons[1] = unpack(x +! n.sym.offset, n.sym.typ, nil)
-    #echo "offset: ", n.sym.name.s, " ", n.sym.offset
-    result.add pair
-  else: discard
-
-proc unpackObject(x: pointer, typ: PType, n: PNode): PNode =
-  # compute the field's offsets:
-  discard typ.getSize
-  
-  # iterate over any actual field of 'n' ... if n is nil we need to create
-  # the nkPar node:
-  if n.isNil:
-    result = newNode(nkPar)
-    result.typ = typ
-    if typ.n.isNil:
-      internalError("cannot unpack unnamed tuple")
-    unpackObjectAdd(x, typ.n, result)
-  else:
-    result = n
-    if result.kind notin {nkObjConstr, nkPar}:
-      globalError(n.info, "cannot map value from FFI")
-    if typ.n.isNil:
-      globalError(n.info, "cannot unpack unnamed tuple")
-    for i in countup(ord(n.kind == nkObjConstr), sonsLen(n) - 1):
-      var it = n.sons[i]
-      if it.kind == nkExprColonExpr:
-        internalAssert it.sons[0].kind == nkSym
-        let field = it.sons[0].sym
-        it.sons[1] = unpack(x +! field.offset, field.typ, it.sons[1])
-      else:
-        let field = getField(typ.n, i)
-        n.sons[i] = unpack(x +! field.offset, field.typ, it)
-
-proc unpackArray(x: pointer, typ: PType, n: PNode): PNode =
-  if n.isNil:
-    result = newNode(nkBracket)
-    result.typ = typ
-    newSeq(result.sons, lengthOrd(typ).int)
-  else:
-    result = n
-    if result.kind != nkBracket:
-      globalError(n.info, "cannot map value from FFI")
-  let baseSize = typ.sons[1].getSize
-  for i in 0 .. < result.len:
-    result.sons[i] = unpack(x +! i * baseSize, typ.sons[1], result.sons[i])
-
-proc canonNodeKind(k: TNodeKind): TNodeKind =
-  case k
-  of nkCharLit..nkUInt64Lit: result = nkIntLit
-  of nkFloatLit..nkFloat128Lit: result = nkFloatLit
-  of nkStrLit..nkTripleStrLit: result = nkStrLit
-  else: result = k
-
-proc unpack(x: pointer, typ: PType, n: PNode): PNode =
-  template aw(k, v, field: expr) {.immediate, dirty.} =
-    if n.isNil:
-      result = newNode(k)
-      result.typ = typ
-    else:
-      # check we have the right field:
-      result = n
-      if result.kind.canonNodeKind != k.canonNodeKind:
-        #echo "expected ", k, " but got ", result.kind
-        #debug result
-        return newNodeI(nkExceptBranch, n.info)
-        #globalError(n.info, "cannot map value from FFI")
-    result.field = v
-
-  template setNil() =
-    if n.isNil:
-      result = newNode(nkNilLit)
-      result.typ = typ
-    else:
-      reset n[]
-      result = n
-      result.kind = nkNilLit
-      result.typ = typ
-
-  template awi(kind, v: expr) {.immediate, dirty.} = aw(kind, v, intVal)
-  template awf(kind, v: expr) {.immediate, dirty.} = aw(kind, v, floatVal)
-  template aws(kind, v: expr) {.immediate, dirty.} = aw(kind, v, strVal)
-  
-  case typ.kind
-  of tyBool: awi(nkIntLit, rd(bool, x).ord)
-  of tyChar: awi(nkCharLit, rd(char, x).ord)
-  of tyInt:  awi(nkIntLit, rd(int, x))
-  of tyInt8: awi(nkInt8Lit, rd(int8, x))
-  of tyInt16: awi(nkInt16Lit, rd(int16, x))
-  of tyInt32: awi(nkInt32Lit, rd(int32, x))
-  of tyInt64: awi(nkInt64Lit, rd(int64, x))
-  of tyUInt: awi(nkUIntLit, rd(uint, x).BiggestInt)
-  of tyUInt8: awi(nkUInt8Lit, rd(uint8, x).BiggestInt)
-  of tyUInt16: awi(nkUInt16Lit, rd(uint16, x).BiggestInt)
-  of tyUInt32: awi(nkUInt32Lit, rd(uint32, x).BiggestInt)
-  of tyUInt64: awi(nkUInt64Lit, rd(uint64, x).BiggestInt)
-  of tyEnum:
-    case typ.getSize
-    of 1: awi(nkIntLit, rd(uint8, x).BiggestInt)
-    of 2: awi(nkIntLit, rd(uint16, x).BiggestInt)
-    of 4: awi(nkIntLit, rd(int32, x).BiggestInt)
-    of 8: awi(nkIntLit, rd(int64, x).BiggestInt)
-    else:
-      globalError(n.info, "cannot map value from FFI (tyEnum, tySet)")
-  of tyFloat: awf(nkFloatLit, rd(float, x))
-  of tyFloat32: awf(nkFloat32Lit, rd(float32, x))
-  of tyFloat64: awf(nkFloat64Lit, rd(float64, x))
-  of tyPointer, tyProc:
-    let p = rd(pointer, x)
-    if p.isNil:
-      setNil()
-    elif n != nil and n.kind == nkStrLit:
-      # we passed a string literal as a pointer; however strings are already
-      # in their unboxed representation so nothing it to be unpacked:
-      result = n
-    else:
-      awi(nkPtrLit, cast[TAddress](p))
-  of tyPtr, tyRef, tyVar:
-    let p = rd(pointer, x)
-    if p.isNil:
-      setNil()
-    elif n == nil or n.kind == nkPtrLit:
-      awi(nkPtrLit, cast[TAddress](p))
-    elif n != nil and n.len == 1:
-      internalAssert n.kind == nkRefTy
-      n.sons[0] = unpack(p, typ.lastSon, n.sons[0])
-      result = n
-    else:
-      globalError(n.info, "cannot map value from FFI " & typeToString(typ))
-  of tyObject, tyTuple:
-    result = unpackObject(x, typ, n)
-  of tyArray, tyArrayConstr:
-    result = unpackArray(x, typ, n)
-  of tyCString, tyString:
-    let p = rd(cstring, x)
-    if p.isNil:
-      setNil()
-    else:
-      aws(nkStrLit, $p)
-  of tyNil:
-    setNil()
-  of tyDistinct, tyGenericInst:
-    result = unpack(x, typ.sons[0], n)
-  else:
-    # XXX what to do with 'array' here?
-    globalError(n.info, "cannot map value from FFI " & typeToString(typ))
-
-proc fficast*(x: PNode, destTyp: PType): PNode =
-  if x.kind == nkPtrLit and x.typ.kind in {tyPtr, tyRef, tyVar, tyPointer, 
-                                           tyProc, tyCString, tyString, 
-                                           tySequence}:
-    result = newNodeIT(x.kind, x.info, destTyp)
-    result.intVal = x.intVal
-  elif x.kind == nkNilLit:
-    result = newNodeIT(x.kind, x.info, destTyp)
-  else:
-    # we play safe here and allocate the max possible size:
-    let size = max(packSize(x, x.typ), packSize(x, destTyp))
-    var a = alloc0(size)
-    pack(x, x.typ, a)
-    # cast through a pointer needs a new inner object:
-    let y = if x.kind == nkRefTy: newNodeI(nkRefTy, x.info, 1)
-            else: x.copyTree
-    y.typ = x.typ
-    result = unpack(a, destTyp, y)
-    dealloc a
-
-proc callForeignFunction*(call: PNode): PNode =
-  internalAssert call.sons[0].kind == nkPtrLit
-  
-  var cif: TCif
-  var sig: TParamList
-  # use the arguments' types for varargs support:
-  for i in 1..call.len-1:
-    sig[i-1] = mapType(call.sons[i].typ)
-    if sig[i-1].isNil:
-      globalError(call.info, "cannot map FFI type")
-  
-  let typ = call.sons[0].typ
-  if prep_cif(cif, mapCallConv(typ.callConv, call.info), cuint(call.len-1),
-              mapType(typ.sons[0]), sig) != OK:
-    globalError(call.info, "error in FFI call")
-  
-  var args: TArgList
-  let fn = cast[pointer](call.sons[0].intVal)
-  for i in 1 .. call.len-1:
-    var t = call.sons[i].typ
-    args[i-1] = alloc0(packSize(call.sons[i], t))
-    pack(call.sons[i], t, args[i-1])
-  let retVal = if isEmptyType(typ.sons[0]): pointer(nil)
-               else: alloc(typ.sons[0].getSize.int)
-
-  libffi.call(cif, fn, retVal, args)
-  
-  if retVal.isNil: 
-    result = emptyNode
-  else:
-    result = unpack(retVal, typ.sons[0], nil)
-    result.info = call.info
-
-  if retVal != nil: dealloc retVal
-  for i in 1 .. call.len-1:
-    call.sons[i] = unpack(args[i-1], typ.sons[i], call[i])
-    dealloc args[i-1]
-
-proc callForeignFunction*(fn: PNode, fntyp: PType,
-                          args: var TNodeSeq, start, len: int,
-                          info: TLineInfo): PNode =
-  internalAssert fn.kind == nkPtrLit
-  
-  var cif: TCif
-  var sig: TParamList
-  for i in 0..len-1:
-    var aTyp = args[i+start].typ
-    if aTyp.isNil:
-      internalAssert i+1 < fntyp.len
-      aTyp = fntyp.sons[i+1]
-      args[i+start].typ = aTyp
-    sig[i] = mapType(aTyp)
-    if sig[i].isNil: globalError(info, "cannot map FFI type")
-  
-  if prep_cif(cif, mapCallConv(fntyp.callConv, info), cuint(len),
-              mapType(fntyp.sons[0]), sig) != OK:
-    globalError(info, "error in FFI call")
-  
-  var cargs: TArgList
-  let fn = cast[pointer](fn.intVal)
-  for i in 0 .. len-1:
-    let t = args[i+start].typ
-    cargs[i] = alloc0(packSize(args[i+start], t))
-    pack(args[i+start], t, cargs[i])
-  let retVal = if isEmptyType(fntyp.sons[0]): pointer(nil)
-               else: alloc(fntyp.sons[0].getSize.int)
-
-  libffi.call(cif, fn, retVal, cargs)
-  
-  if retVal.isNil: 
-    result = emptyNode
-  else:
-    result = unpack(retVal, fntyp.sons[0], nil)
-    result.info = info
-
-  if retVal != nil: dealloc retVal
-  for i in 0 .. len-1:
-    let t = args[i+start].typ
-    args[i+start] = unpack(cargs[i], t, args[i+start])
-    dealloc cargs[i]
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
index 78cc691c0..8959aa4df 100644
--- a/compiler/evaltempl.nim
+++ b/compiler/evaltempl.nim
@@ -10,7 +10,7 @@
 ## Template evaluation engine. Now hygienic.
 
 import
-  strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer, 
+  strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer,
   rodread
 
 type
@@ -29,7 +29,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
   of nkSym:
     var s = templ.sym
     if s.owner.id == c.owner.id:
-      if s.kind == skParam:
+      if s.kind == skParam and sfGenSym notin s.flags:
         let x = actual.sons[s.position]
         if x.kind == nkArgList:
           for y in items(x): result.add(y)
@@ -49,7 +49,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
     result.add copyNode(c, templ, actual)
   else:
     var res = copyNode(c, templ, actual)
-    for i in countup(0, sonsLen(templ) - 1): 
+    for i in countup(0, sonsLen(templ) - 1):
       evalTemplateAux(templ.sons[i], actual, c, res)
     result.add res
 
@@ -86,14 +86,14 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
   ctx.owner = tmpl
   ctx.genSymOwner = genSymOwner
   initIdTable(ctx.mapping)
-  
+
   let body = tmpl.getBody
-  if isAtom(body): 
+  if isAtom(body):
     result = newNodeI(nkPar, body.info)
     evalTemplateAux(body, args, ctx, result)
     if result.len == 1: result = result.sons[0]
     else:
-      globalError(result.info, errIllFormedAstX,
+      localError(result.info, errIllFormedAstX,
                   renderTree(result, {renderNoComments}))
   else:
     result = copyNode(body)
@@ -102,5 +102,5 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
     if ctx.instLines: result.info = n.info
     for i in countup(0, safeLen(body) - 1):
       evalTemplateAux(body.sons[i], args, ctx, result)
-  
+
   dec(evalTemplateCounter)
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index ad9c38904..26f0318ee 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -15,9 +15,9 @@
 import
   lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs, crc
 
-type 
-  TSystemCC* = enum 
-    ccNone, ccGcc, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc, 
+type
+  TSystemCC* = enum
+    ccNone, ccGcc, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc,
     ccTcc, ccPcc, ccUcc, ccIcl
   TInfoCCProp* = enum         # properties of the C compiler:
     hasSwitchRange,           # CC allows ranges in switch statements (GNU C)
@@ -54,7 +54,7 @@ type
     props: TInfoCCProps] # properties of the C compiler
 
 
-# Configuration settings for various compilers. 
+# Configuration settings for various compilers.
 # When adding new compilers, the cmake sources could be a good reference:
 # http://cmake.org/gitweb?p=cmake.git;a=tree;f=Modules/Platform;
 
@@ -136,7 +136,7 @@ compiler icl:
     result = vcc()
   else:
     result = gcc()
-    
+
   result.name = "icl"
   result.compilerExe = "icl"
   result.linkerExe = "icl"
@@ -317,7 +317,7 @@ compiler ucc:
     packedPragma: "", # XXX: not supported yet
     props: {})
 
-const 
+const
   CC*: array[succ(low(TSystemCC))..high(TSystemCC), TInfoCC] = [
     gcc(),
     llvmGcc(),
@@ -332,7 +332,6 @@ const
     ucc(),
     icl()]
 
-const
   hExt* = ".h"
 
 var
@@ -347,7 +346,7 @@ var
 proc libNameTmpl(): string {.inline.} =
   result = if targetOS == osWindows: "$1.lib" else: "lib$1.a"
 
-var 
+var
   toLink, toCompile, externalToCompile: TLinkedList
   linkOptions: string = ""
   compileOptions: string = ""
@@ -356,19 +355,28 @@ var
 proc nameToCC*(name: string): TSystemCC =
   ## Returns the kind of compiler referred to by `name`, or ccNone
   ## if the name doesn't refer to any known compiler.
-  for i in countup(succ(ccNone), high(TSystemCC)): 
-    if cmpIgnoreStyle(name, CC[i].name) == 0: 
+  for i in countup(succ(ccNone), high(TSystemCC)):
+    if cmpIgnoreStyle(name, CC[i].name) == 0:
       return i
   result = ccNone
 
 proc getConfigVar(c: TSystemCC, suffix: string): string =
   # use ``cpu.os.cc`` for cross compilation, unless ``--compileOnly`` is given
   # for niminst support
-  let fullSuffix = (if gCmd == cmdCompileToCpp: ".cpp" & suffix else: suffix)
+  let fullSuffix =
+    if gCmd == cmdCompileToCpp:
+      ".cpp" & suffix
+    elif gCmd == cmdCompileToOC:
+      ".objc" & suffix
+    elif gCmd == cmdCompileToJS:
+      ".js" & suffix
+    else:
+      suffix
+
   if (platform.hostOS != targetOS or platform.hostCPU != targetCPU) and
       optCompileOnly notin gGlobalOptions:
-    let fullCCname = platform.CPU[targetCPU].name & '.' & 
-                     platform.OS[targetOS].name & '.' & 
+    let fullCCname = platform.CPU[targetCPU].name & '.' &
+                     platform.OS[targetOS].name & '.' &
                      CC[c].name & fullSuffix
     result = getConfigVar(fullCCname)
     if result.len == 0:
@@ -377,39 +385,39 @@ proc getConfigVar(c: TSystemCC, suffix: string): string =
   else:
     result = getConfigVar(CC[c].name & fullSuffix)
 
-proc setCC*(ccname: string) = 
+proc setCC*(ccname: string) =
   cCompiler = nameToCC(ccname)
   if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
   compileOptions = getConfigVar(cCompiler, ".options.always")
-  linkOptions = getConfigVar(cCompiler, ".options.linker")
+  linkOptions = ""
   ccompilerpath = getConfigVar(cCompiler, ".path")
   for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
   defineSymbol(CC[cCompiler].name)
 
-proc addOpt(dest: var string, src: string) = 
+proc addOpt(dest: var string, src: string) =
   if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ")
   add(dest, src)
 
-proc addLinkOption*(option: string) = 
-  if find(linkOptions, option, 0) < 0: addOpt(linkOptions, option)
+proc addLinkOption*(option: string) =
+  addOpt(linkOptions, option)
 
-proc addCompileOption*(option: string) = 
-  if strutils.find(compileOptions, option, 0) < 0: 
+proc addCompileOption*(option: string) =
+  if strutils.find(compileOptions, option, 0) < 0:
     addOpt(compileOptions, option)
 
-proc initVars*() = 
+proc initVars*() =
   # we need to define the symbol here, because ``CC`` may have never been set!
   for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
   defineSymbol(CC[cCompiler].name)
   addCompileOption(getConfigVar(cCompiler, ".options.always"))
-  addLinkOption(getConfigVar(cCompiler, ".options.linker"))
+  #addLinkOption(getConfigVar(cCompiler, ".options.linker"))
   if len(ccompilerpath) == 0:
     ccompilerpath = getConfigVar(cCompiler, ".path")
 
-proc completeCFilePath*(cfile: string, createSubDir: bool = true): string = 
+proc completeCFilePath*(cfile: string, createSubDir: bool = true): string =
   result = completeGeneratedFilePath(cfile, createSubDir)
 
-proc toObjFile*(filename: string): string = 
+proc toObjFile*(filename: string): string =
   # Object file for compilation
   result = changeFileExt(filename, CC[cCompiler].objExt)
 
@@ -429,30 +437,34 @@ proc addFileToLink*(filename: string) =
   prependStr(toLink, filename)
   # BUGFIX: was ``appendStr``
 
-proc execExternalProgram*(cmd: string, prettyCmd = "") =
+proc execWithEcho(cmd: string, prettyCmd = ""): int =
   if optListCmd in gGlobalOptions or gVerbosity > 0:
     if prettyCmd != "":
       msgWriteln(prettyCmd)
     else:
       msgWriteln(cmd)
-  if execCmd(cmd) != 0: rawMessage(errExecutionOfProgramFailed, "")
+  result = execCmd(cmd)
 
-proc generateScript(projectFile: string, script: PRope) = 
+proc execExternalProgram*(cmd: string, prettyCmd = "") =
+  if execWithEcho(cmd, prettyCmd) != 0:
+    rawMessage(errExecutionOfProgramFailed, "")
+
+proc generateScript(projectFile: string, script: Rope) =
   let (dir, name, ext) = splitFile(projectFile)
-  writeRope(script, dir / addFileExt("compile_" & name, 
+  writeRope(script, dir / addFileExt("compile_" & name,
                                      platform.OS[targetOS].scriptExt))
 
-proc getOptSpeed(c: TSystemCC): string = 
+proc getOptSpeed(c: TSystemCC): string =
   result = getConfigVar(c, ".options.speed")
   if result == "":
     result = CC[c].optSpeed   # use default settings from this file
 
-proc getDebug(c: TSystemCC): string = 
+proc getDebug(c: TSystemCC): string =
   result = getConfigVar(c, ".options.debug")
   if result == "":
     result = CC[c].debug      # use default settings from this file
 
-proc getOptSize(c: TSystemCC): string = 
+proc getOptSize(c: TSystemCC): string =
   result = getConfigVar(c, ".options.size")
   if result == "":
     result = CC[c].optSize    # use default settings from this file
@@ -464,7 +476,7 @@ proc noAbsolutePaths: bool {.inline.} =
   # `optGenMapping` is included here for niminst.
   result = gGlobalOptions * {optGenScript, optGenMapping} != {}
 
-const 
+const
   specialFileA = 42
   specialFileB = 42
 
@@ -476,7 +488,7 @@ proc add(s: var string, many: openArray[string]) =
 proc cFileSpecificOptions(cfilename: string): string =
   result = compileOptions
   var trunk = splitFile(cfilename).name
-  if optCDebug in gGlobalOptions: 
+  if optCDebug in gGlobalOptions:
     var key = trunk & ".debug"
     if existsConfigVar(key): addOpt(result, getConfigVar(key))
     else: addOpt(result, getDebug(cCompiler))
@@ -516,17 +528,17 @@ proc getLinkerExe(compiler: TSystemCC): string =
            elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler
            else: compiler.getCompilerExe
 
-proc getCompileCFileCmd*(cfilename: string, isExternal = false): string = 
+proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
   var c = cCompiler
   var options = cFileSpecificOptions(cfilename)
   var exe = getConfigVar(c, ".exe")
   if exe.len == 0: exe = c.getCompilerExe
-  
+
   if needsExeExt(): exe = addFileExt(exe, "exe")
   if optGenDynLib in gGlobalOptions and
       ospNeedsPIC in platform.OS[targetOS].props:
     add(options, ' ' & CC[c].pic)
-  
+
   var includeCmd, compilePattern: string
   if not noAbsolutePaths():
     # compute include paths:
@@ -539,7 +551,7 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
   else:
     includeCmd = ""
     compilePattern = c.getCompilerExe
-  
+
   var cfile = if noAbsolutePaths(): extractFilename(cfilename)
               else: cfilename
   var objfile = if not isExternal or noAbsolutePaths():
@@ -547,15 +559,16 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
                 else:
                   completeCFilePath(toObjFile(cfile))
   objfile = quoteShell(objfile)
+  cfile = quoteShell(cfile)
   result = quoteShell(compilePattern % [
     "file", cfile, "objfile", objfile, "options", options,
-    "include", includeCmd, "nimrod", getPrefixDir(),
+    "include", includeCmd, "nim", getPrefixDir(),
     "nim", getPrefixDir(), "lib", libpath])
   add(result, ' ')
   addf(result, CC[c].compileTmpl, [
     "file", cfile, "objfile", objfile,
     "options", options, "include", includeCmd,
-    "nimrod", quoteShell(getPrefixDir()),
+    "nim", quoteShell(getPrefixDir()),
     "nim", quoteShell(getPrefixDir()),
     "lib", quoteShell(libpath)])
 
@@ -567,11 +580,14 @@ proc footprint(filename: string): TCrc32 =
       extccomp.CC[extccomp.cCompiler].name ><
       getCompileCFileCmd(filename, true)
 
-proc externalFileChanged(filename: string): bool = 
+proc externalFileChanged(filename: string): bool =
+  if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
+    return false
+
   var crcFile = toGeneratedFile(filename.withPackageName, "crc")
   var currentCrc = int(footprint(filename))
   var f: File
-  if open(f, crcFile, fmRead): 
+  if open(f, crcFile, fmRead):
     var line = newStringOfCap(40)
     if not f.readLine(line): line = "0"
     close(f)
@@ -579,7 +595,7 @@ proc externalFileChanged(filename: string): bool =
     result = oldCrc != currentCrc
   else:
     result = true
-  if result: 
+  if result:
     if open(f, crcFile, fmWrite):
       f.writeln($currentCrc)
       close(f)
@@ -588,49 +604,51 @@ proc addExternalFileToCompile*(filename: string) =
   if optForceFullMake in gGlobalOptions or externalFileChanged(filename):
     appendStr(externalToCompile, filename)
 
-proc compileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
+proc compileCFile(list: TLinkedList, script: var Rope, cmds: var TStringSeq,
                   prettyCmds: var TStringSeq, isExternal: bool) =
   var it = PStrEntry(list.head)
-  while it != nil: 
+  while it != nil:
     inc(fileCounter)          # call the C compiler for the .c file:
     var compileCmd = getCompileCFileCmd(it.data, isExternal)
-    if optCompileOnly notin gGlobalOptions: 
+    if optCompileOnly notin gGlobalOptions:
       add(cmds, compileCmd)
       let (dir, name, ext) = splitFile(it.data)
       add(prettyCmds, "CC: " & name)
-    if optGenScript in gGlobalOptions: 
-      app(script, compileCmd)
-      app(script, tnl)
+    if optGenScript in gGlobalOptions:
+      add(script, compileCmd)
+      add(script, tnl)
     it = PStrEntry(it.next)
 
 proc callCCompiler*(projectfile: string) =
-  var 
+  var
     linkCmd, buildgui, builddll: string
-  if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}: 
+  if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
     return # speed up that call if only compiling and no script shall be
            # generated
   fileCounter = 0
   var c = cCompiler
-  var script: PRope = nil
+  var script: Rope = nil
   var cmds: TStringSeq = @[]
   var prettyCmds: TStringSeq = @[]
   let prettyCb = proc (idx: int) =
     echo prettyCmds[idx]
   compileCFile(toCompile, script, cmds, prettyCmds, false)
   compileCFile(externalToCompile, script, cmds, prettyCmds, true)
-  if optCompileOnly notin gGlobalOptions: 
+  if optCompileOnly notin gGlobalOptions:
     if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
     var res = 0
-    if gNumberOfProcessors <= 1: 
-      for i in countup(0, high(cmds)): res = max(execCmd(cmds[i]), res)
+    if gNumberOfProcessors <= 1:
+      for i in countup(0, high(cmds)):
+        res = execWithEcho(cmds[i])
+        if res != 0: rawMessage(errExecutionOfProgramFailed, [])
     elif optListCmd in gGlobalOptions or gVerbosity > 1:
-      res = execProcesses(cmds, {poEchoCmd, poUseShell, poParentStreams},
+      res = execProcesses(cmds, {poEchoCmd, poUsePath, poParentStreams},
                           gNumberOfProcessors)
     elif gVerbosity == 1:
-      res = execProcesses(cmds, {poUseShell, poParentStreams},
+      res = execProcesses(cmds, {poUsePath, poParentStreams},
                           gNumberOfProcessors, prettyCb)
     else:
-      res = execProcesses(cmds, {poUseShell, poParentStreams},
+      res = execProcesses(cmds, {poUsePath, poParentStreams},
                           gNumberOfProcessors)
     if res != 0:
       if gNumberOfProcessors <= 1:
@@ -667,21 +685,22 @@ proc callCCompiler*(projectfile: string) =
       else:
         exefile = splitFile(projectfile).name & platform.OS[targetOS].exeExt
         builddll = ""
-      if options.outFile.len > 0: 
+      if options.outFile.len > 0:
         exefile = options.outFile.expandTilde
       if not noAbsolutePaths():
         if not exefile.isAbsolute():
           exefile = joinPath(splitFile(projectfile).dir, exefile)
       exefile = quoteShell(exefile)
-      let linkOptions = getLinkOptions()
+      let linkOptions = getLinkOptions() & " " &
+                        getConfigVar(cCompiler, ".options.linker")
       linkCmd = quoteShell(linkCmd % ["builddll", builddll,
           "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
-          "exefile", exefile, "nimrod", getPrefixDir(), "lib", libpath])
+          "exefile", exefile, "nim", getPrefixDir(), "lib", libpath])
       linkCmd.add ' '
       addf(linkCmd, CC[c].linkTmpl, ["builddll", builddll,
           "buildgui", buildgui, "options", linkOptions,
           "objfiles", objfiles, "exefile", exefile,
-          "nimrod", quoteShell(getPrefixDir()),
+          "nim", quoteShell(getPrefixDir()),
           "lib", quoteShell(libpath)])
     if optCompileOnly notin gGlobalOptions:
       if gVerbosity == 1:
@@ -691,30 +710,30 @@ proc callCCompiler*(projectfile: string) =
   else:
     linkCmd = ""
   if optGenScript in gGlobalOptions:
-    app(script, linkCmd)
-    app(script, tnl)
+    add(script, linkCmd)
+    add(script, tnl)
     generateScript(projectfile, script)
 
-proc genMappingFiles(list: TLinkedList): PRope = 
+proc genMappingFiles(list: TLinkedList): Rope =
   var it = PStrEntry(list.head)
-  while it != nil: 
-    appf(result, "--file:r\"$1\"$N", [toRope(it.data)])
+  while it != nil:
+    addf(result, "--file:r\"$1\"$N", [rope(it.data)])
     it = PStrEntry(it.next)
 
-proc writeMapping*(gSymbolMapping: PRope) = 
-  if optGenMapping notin gGlobalOptions: return 
-  var code = toRope("[C_Files]\n")
-  app(code, genMappingFiles(toCompile))
-  app(code, genMappingFiles(externalToCompile))
-  app(code, "\n[C_Compiler]\nFlags=")
-  app(code, strutils.escape(getCompileOptions()))
-  
-  app(code, "\n[Linker]\nFlags=")
-  app(code, strutils.escape(getLinkOptions()))
-
-  app(code, "\n[Environment]\nlibpath=")
-  app(code, strutils.escape(libpath))
-  
-  appf(code, "\n[Symbols]$n$1", [gSymbolMapping])
+proc writeMapping*(gSymbolMapping: Rope) =
+  if optGenMapping notin gGlobalOptions: return
+  var code = rope("[C_Files]\n")
+  add(code, genMappingFiles(toCompile))
+  add(code, genMappingFiles(externalToCompile))
+  add(code, "\n[C_Compiler]\nFlags=")
+  add(code, strutils.escape(getCompileOptions()))
+
+  add(code, "\n[Linker]\nFlags=")
+  add(code, strutils.escape(getLinkOptions() & " " &
+                            getConfigVar(cCompiler, ".options.linker")))
+
+  add(code, "\n[Environment]\nlibpath=")
+  add(code, strutils.escape(libpath))
+
+  addf(code, "\n[Symbols]$n$1", [gSymbolMapping])
   writeRope(code, joinPath(gProjectPath, "mapping.txt"))
-  
diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim
index 7b975dbaa..5d1f73be4 100644
--- a/compiler/filter_tmpl.nim
+++ b/compiler/filter_tmpl.nim
@@ -37,11 +37,11 @@ const
   PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'}
 
 proc newLine(p: var TTmplParser) = 
-  llStreamWrite(p.outp, repeatChar(p.emitPar, ')'))
+  llStreamWrite(p.outp, repeat(')', p.emitPar))
   p.emitPar = 0
   if p.info.line > int16(1): llStreamWrite(p.outp, "\n")
   if p.pendingExprLine:
-    llStreamWrite(p.outp, repeatChar(2))
+    llStreamWrite(p.outp, spaces(2))
     p.pendingExprLine = false
   
 proc scanPar(p: var TTmplParser, d: int) = 
@@ -88,24 +88,24 @@ proc parseLine(p: var TTmplParser) =
       else: 
         p.info.col = int16(j)
         localError(p.info, errXNotAllowedHere, "end")
-      llStreamWrite(p.outp, repeatChar(p.indent))
+      llStreamWrite(p.outp, spaces(p.indent))
       llStreamWrite(p.outp, "#end")
     of wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator, 
        wConverter, wMacro, wTemplate, wMethod: 
-      llStreamWrite(p.outp, repeatChar(p.indent))
+      llStreamWrite(p.outp, spaces(p.indent))
       llStreamWrite(p.outp, substr(p.x, d))
       inc(p.indent, 2)
     of wElif, wOf, wElse, wExcept, wFinally: 
-      llStreamWrite(p.outp, repeatChar(p.indent - 2))
+      llStreamWrite(p.outp, spaces(p.indent - 2))
       llStreamWrite(p.outp, substr(p.x, d))
     of wLet, wVar, wConst, wType:
-      llStreamWrite(p.outp, repeatChar(p.indent))
+      llStreamWrite(p.outp, spaces(p.indent))
       llStreamWrite(p.outp, substr(p.x, d))
       if not p.x.contains({':', '='}):
         # no inline element --> treat as block:
         inc(p.indent, 2)
     else:
-      llStreamWrite(p.outp, repeatChar(p.indent))
+      llStreamWrite(p.outp, spaces(p.indent))
       llStreamWrite(p.outp, substr(p.x, d))
     p.state = psDirective
   else: 
@@ -120,11 +120,11 @@ proc parseLine(p: var TTmplParser) =
       # next line of string literal:
       llStreamWrite(p.outp, p.conc)
       llStreamWrite(p.outp, "\n")
-      llStreamWrite(p.outp, repeatChar(p.indent + 2))
+      llStreamWrite(p.outp, spaces(p.indent + 2))
       llStreamWrite(p.outp, "\"")
     of psDirective: 
       newLine(p)
-      llStreamWrite(p.outp, repeatChar(p.indent))
+      llStreamWrite(p.outp, spaces(p.indent))
       llStreamWrite(p.outp, p.emit)
       llStreamWrite(p.outp, "(\"")
       inc(p.emitPar)
diff --git a/compiler/forloops.nim b/compiler/forloops.nim
new file mode 100644
index 000000000..efe000968
--- /dev/null
+++ b/compiler/forloops.nim
@@ -0,0 +1,89 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements for loop detection for better C code generation.
+
+import ast, astalgo
+
+const
+  someCmp = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
+    mEqUntracedRef, mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum,
+    mLeCh, mLeB, mLePtr, mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum, 
+    mLtCh, mLtB, mLtPtr}
+
+proc isCounter(s: PSym): bool {.inline.} =
+  s.kind in {skResult, skVar, skLet, skTemp} and 
+  {sfGlobal, sfAddrTaken} * s.flags == {}
+
+proc isCall(n: PNode): bool {.inline.} =
+  n.kind in nkCallKinds and n[0].kind == nkSym
+
+proc fromSystem(op: PSym): bool = sfSystemModule in getModule(op).flags
+
+proc getCounter(lastStmt: PNode): PSym =
+  if lastStmt.isCall:
+    let op = lastStmt.sym
+    if op.magic in {mDec, mInc} or 
+        ((op.name.s == "+=" or op.name.s == "-=") and op.fromSystem):
+      if op[1].kind == nkSym and isCounter(op[1].sym):
+        result = op[1].sym
+
+proc counterInTree(n, loop: PNode; counter: PSym): bool =
+  # prune the search tree: within the loop the counter may be used:
+  if n == loop: return
+  case n.kind
+  of nkSym:
+    if n.sym == counter: return true
+  of nkVarSection, nkLetSection:
+    # definitions are fine!
+    for it in n:
+      if counterInTree(it.lastSon): return true
+  else:
+    for i in 0 .. <safeLen(n):
+      if counterInTree(n[i], loop, counter): return true
+
+proc copyExcept(n: PNode, x, dest: PNode) =
+  if x == n: return
+  if n.kind in {nkStmtList, nkStmtListExpr}:
+    for i in 0 .. <n.len: copyExcept(n[i], x, dest)
+  else:
+    dest.add n
+
+type
+  ForLoop* = object
+    counter*: PSym
+    init*, cond*, increment*, body*: PNode
+
+proc extractForLoop*(loop, fullTree: PNode): ForLoop =
+  ## returns 'counter == nil' if the while loop 'n' is not a for loop:
+  assert loop.kind == nkWhileStmt
+  let cond == loop[0]
+
+  if not cond.isCall: return
+  if cond[0].sym.magic notin someCmp: return
+  
+  var lastStmt = loop[1]
+  while lastStmt.kind in {nkStmtList, nkStmtListExpr}:
+    lastStmt = lastStmt.lastSon
+
+  let counter = getCounter(lastStmt)
+  if counter.isNil or counter.ast.isNil: return
+
+  template `=~`(a, b): expr = a.kind == nkSym and a.sym == b
+  
+  if cond[1] =~ counter or cond[2] =~ counter:
+    # ok, now check 'counter' is not used *after* the loop
+    if counterInTree(fullTree, loop, counter): return
+    # ok, success, fill in the fields:
+    result.counter = counter
+    result.init = counter.ast
+    result.cond = cond
+    result.increment = lastStmt
+    result.body = newNodeI(nkStmtList, loop[1].info)
+    copyExcept(loop[1], lastStmt, result.body)
diff --git a/compiler/guards.nim b/compiler/guards.nim
index cd0aaf296..dc2b24add 100644
--- a/compiler/guards.nim
+++ b/compiler/guards.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -15,14 +15,15 @@ import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents,
 const
   someEq = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
     mEqUntracedRef, mEqStr, mEqSet, mEqCString}
-  
+
   # set excluded here as the semantics are vastly different:
   someLe = {mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum,
             mLeCh, mLeB, mLePtr, mLeStr}
-  someLt = {mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum, 
+  someLt = {mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum,
             mLtCh, mLtB, mLtPtr, mLtStr}
 
-  someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq}
+  someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq,
+             mXLenStr, mXLenSeq}
 
   someIn = {mInRange, mInSet}
 
@@ -34,8 +35,8 @@ const
   someMul = {mMulI, mMulI64, mMulF64}
   someDiv = {mDivI, mDivI64, mDivF64}
   someMod = {mModI, mModI64}
-  someMax = {mMaxI, mMaxI64, mMaxF64}
-  someMin = {mMinI, mMinI64, mMinF64}
+  someMax = {mMaxI, mMaxF64}
+  someMin = {mMinI, mMinF64}
 
 proc isValue(n: PNode): bool = n.kind in {nkCharLit..nkNilLit}
 proc isLocation(n: PNode): bool = not n.isValue
@@ -44,7 +45,7 @@ proc isLet(n: PNode): bool =
   if n.kind == nkSym:
     if n.sym.kind in {skLet, skTemp, skForVar}:
       result = true
-    elif n.sym.kind == skParam and skipTypes(n.sym.typ, 
+    elif n.sym.kind == skParam and skipTypes(n.sym.typ,
                                              abstractInst).kind != tyVar:
       result = true
 
@@ -81,18 +82,12 @@ proc isLetLocation(m: PNode, isApprox: bool): bool =
 
 proc interestingCaseExpr*(m: PNode): bool = isLetLocation(m, true)
 
-proc createMagic*(name: string, m: TMagic): PSym =
-  result = newSym(skProc, getIdent(name), nil, unknownLineInfo())
-  result.magic = m
-
 let
   opLe = createMagic("<=", mLeI)
   opLt = createMagic("<", mLtI)
   opAnd = createMagic("and", mAnd)
   opOr = createMagic("or", mOr)
-  opNot = createMagic("not", mNot)
   opIsNil = createMagic("isnil", mIsNil)
-  opContains = createMagic("contains", mInSet)
   opEq = createMagic("==", mEqI)
   opAdd = createMagic("+", mAddI)
   opSub = createMagic("-", mSubI)
@@ -123,7 +118,7 @@ proc neg(n: PNode): PNode =
     result.sons[0] = n.sons[0]
     result.sons[2] = n.sons[2]
     if t.kind == tyEnum:
-      var s = newNodeIT(nkCurly, n.info, n.sons[1].typ)    
+      var s = newNodeIT(nkCurly, n.info, n.sons[1].typ)
       for e in t.n:
         let eAsNode = newIntNode(nkIntLit, e.sym.position)
         if not inSet(n.sons[1], eAsNode): s.add eAsNode
@@ -195,13 +190,17 @@ proc zero(): PNode = nkIntLit.newIntNode(0)
 proc one(): PNode = nkIntLit.newIntNode(1)
 proc minusOne(): PNode = nkIntLit.newIntNode(-1)
 
-proc lowBound*(x: PNode): PNode = 
+proc lowBound*(x: PNode): PNode =
   result = nkIntLit.newIntNode(firstOrd(x.typ))
   result.info = x.info
 
 proc highBound*(x: PNode): PNode =
-  result = if x.typ.skipTypes(abstractInst).kind == tyArray:
-             nkIntLit.newIntNode(lastOrd(x.typ))
+  let typ = x.typ.skipTypes(abstractInst)
+  result = if typ.kind in {tyArrayConstr, tyArray}:
+             nkIntLit.newIntNode(lastOrd(typ))
+           elif typ.kind == tySequence and x.kind == nkSym and
+               x.sym.kind == skConst:
+             nkIntLit.newIntNode(x.sym.ast.len-1)
            else:
              opAdd.buildCall(opLen.buildCall(x), minusOne())
   result.info = x.info
@@ -211,21 +210,32 @@ proc reassociation(n: PNode): PNode =
   # (foo+5)+5 --> foo+10;  same for '*'
   case result.getMagic
   of someAdd:
-    if result[2].isValue and 
+    if result[2].isValue and
         result[1].getMagic in someAdd and result[1][2].isValue:
       result = opAdd.buildCall(result[1][1], result[1][2] |+| result[2])
   of someMul:
-    if result[2].isValue and 
+    if result[2].isValue and
         result[1].getMagic in someMul and result[1][2].isValue:
       result = opAdd.buildCall(result[1][1], result[1][2] |*| result[2])
   else: discard
 
+proc pred(n: PNode): PNode =
+  if n.kind in {nkCharLit..nkUInt64Lit} and n.intVal != low(BiggestInt):
+    result = copyNode(n)
+    dec result.intVal
+  else:
+    result = n
+
 proc canon*(n: PNode): PNode =
   # XXX for now only the new code in 'semparallel' uses this
   if n.safeLen >= 1:
     result = shallowCopy(n)
     for i in 0 .. < n.len:
       result.sons[i] = canon(n.sons[i])
+  elif n.kind == nkSym and n.sym.kind == skLet and
+      n.sym.ast.getMagic in (someEq + someAdd + someMul + someMin +
+      someMax + someHigh + {mUnaryLt} + someSub + someLen):
+    result = n.sym.ast.copyTree
   else:
     result = n
   case result.getMagic
@@ -237,34 +247,40 @@ proc canon*(n: PNode): PNode =
   of someHigh:
     # high == len+(-1)
     result = opAdd.buildCall(opLen.buildCall(result[1]), minusOne())
-  of mUnaryMinusI, mUnaryMinusI64:
+  of mUnaryLt:
     result = buildCall(opAdd, result[1], newIntNode(nkIntLit, -1))
   of someSub:
     # x - 4  -->  x + (-4)
     result = negate(result[1], result[2], result)
   of someLen:
     result.sons[0] = opLen.newSymNode
+  of someLt:
+    # x < y  same as x <= y-1:
+    let y = n[2].canon
+    let p = pred(y)
+    let minus = if p != y: p else: opAdd.buildCall(y, minusOne()).canon
+    result = opLe.buildCall(n[1].canon, minus)
   else: discard
 
   result = skipConv(result)
   result = reassociation(result)
-  # most important rule: (x-4) < a.len -->  x < a.len+4
+  # most important rule: (x-4) <= a.len -->  x <= a.len+4
   case result.getMagic
-  of someLe, someLt:
+  of someLe:
     let x = result[1]
     let y = result[2]
-    if x.kind in nkCallKinds and x.len == 3 and x[2].isValue and 
+    if x.kind in nkCallKinds and x.len == 3 and x[2].isValue and
         isLetLocation(x[1], true):
       case x.getMagic
       of someSub:
-        result = buildCall(result[0].sym, x[1], 
+        result = buildCall(result[0].sym, x[1],
                            reassociation(opAdd.buildCall(y, x[2])))
       of someAdd:
         # Rule A:
         let plus = negate(y, x[2], nil).reassociation
         if plus != nil: result = buildCall(result[0].sym, x[1], plus)
       else: discard
-    elif y.kind in nkCallKinds and y.len == 3 and y[2].isValue and 
+    elif y.kind in nkCallKinds and y.len == 3 and y[2].isValue and
         isLetLocation(y[1], true):
       # a.len < x-3
       case y.getMagic
@@ -323,7 +339,7 @@ proc usefulFact(n: PNode): PNode =
   of mOr:
     # 'or' sucks! (p.isNil or q.isNil) --> hard to do anything
     # with that knowledge...
-    # DeMorgan helps a little though: 
+    # DeMorgan helps a little though:
     #   not a or not b --> not (a and b)
     #  (x == 3) or (y == 2)  ---> not ( not (x==3) and not (y == 2))
     #  not (x != 3 and y != 2)
@@ -354,17 +370,32 @@ proc addFact*(m: var TModel, n: PNode) =
   let n = usefulFact(n)
   if n != nil: m.add n
 
-proc addFactNeg*(m: var TModel, n: PNode) = 
+proc addFactNeg*(m: var TModel, n: PNode) =
   let n = n.neg
   if n != nil: addFact(m, n)
 
-proc sameTree*(a, b: PNode): bool = 
+proc canonOpr(opr: PSym): PSym =
+  case opr.magic
+  of someEq: result = opEq
+  of someLe: result = opLe
+  of someLt: result = opLt
+  of someLen: result = opLen
+  of someAdd: result = opAdd
+  of someSub: result = opSub
+  of someMul: result = opMul
+  of someDiv: result = opDiv
+  else: result = opr
+
+proc sameTree*(a, b: PNode): bool =
   result = false
   if a == b:
     result = true
-  elif (a != nil) and (b != nil) and (a.kind == b.kind):
+  elif a != nil and b != nil and a.kind == b.kind:
     case a.kind
-    of nkSym: result = a.sym == b.sym
+    of nkSym:
+      result = a.sym == b.sym
+      if not result and a.sym.magic != mNone:
+        result = a.sym.magic == b.sym.magic or canonOpr(a.sym) == canonOpr(b.sym)
     of nkIdent: result = a.ident.id == b.ident.id
     of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
     of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
@@ -388,8 +419,8 @@ proc invalidateFacts*(m: var TModel, n: PNode) =
   # 'while p != nil: f(p); p = p.next'
   # This is actually quite easy to do:
   # Re-assignments (incl. pass to a 'var' param) trigger an invalidation
-  # of every fact that contains 'v'. 
-  # 
+  # of every fact that contains 'v'.
+  #
   #   if x < 4:
   #     if y < 5
   #       x = unknown()
@@ -408,16 +439,9 @@ proc valuesUnequal(a, b: PNode): bool =
   if a.isValue and b.isValue:
     result = not sameValue(a, b)
 
-proc pred(n: PNode): PNode =
-  if n.kind in {nkCharLit..nkUInt64Lit} and n.intVal != low(BiggestInt):
-    result = copyNode(n)
-    dec result.intVal
-  else:
-    result = n
-
 proc impliesEq(fact, eq: PNode): TImplication =
   let (loc, val) = if isLocation(eq.sons[1]): (1, 2) else: (2, 1)
-  
+
   case fact.sons[0].sym.magic
   of someEq:
     if sameTree(fact.sons[1], eq.sons[loc]):
@@ -434,12 +458,12 @@ proc impliesEq(fact, eq: PNode): TImplication =
       else: result = impNo
   of mNot, mOr, mAnd: internalError(eq.info, "impliesEq")
   else: discard
-  
+
 proc leImpliesIn(x, c, aSet: PNode): TImplication =
   if c.kind in {nkCharLit..nkUInt64Lit}:
     # fact:  x <= 4;  question x in {56}?
     # --> true if every value <= 4 is in the set {56}
-    #   
+    #
     var value = newIntNode(c.kind, firstOrd(x.typ))
     # don't iterate too often:
     if c.intVal - value.intVal < 1000:
@@ -455,7 +479,7 @@ proc geImpliesIn(x, c, aSet: PNode): TImplication =
   if c.kind in {nkCharLit..nkUInt64Lit}:
     # fact:  x >= 4;  question x in {56}?
     # --> true iff every value >= 4 is in the set {56}
-    #   
+    #
     var value = newIntNode(c.kind, c.intVal)
     let max = lastOrd(x.typ)
     # don't iterate too often:
@@ -574,19 +598,19 @@ proc impliesLe(fact, x, c: PNode): TImplication =
         # fact:  x < 4;  question x <= 2? --> we don't know
     elif sameTree(fact.sons[2], x):
       # fact: 3 < x; question: x <= 1 ?  --> false iff 1 <= 3
-      if isValue(fact.sons[1]) and isValue(c): 
+      if isValue(fact.sons[1]) and isValue(c):
         if leValue(c, fact.sons[1]): result = impNo
-    
+
   of someLe:
     if sameTree(fact.sons[1], x):
       if isValue(fact.sons[2]) and isValue(c):
         # fact:  x <= 4;  question x <= 56? --> true iff 4 <= 56
         if leValue(fact.sons[2], c): result = impYes
         # fact:  x <= 4;  question x <= 2? --> we don't know
-    
+
     elif sameTree(fact.sons[2], x):
       # fact: 3 <= x; question: x <= 2 ?  --> false iff 2 < 3
-      if isValue(fact.sons[1]) and isValue(c): 
+      if isValue(fact.sons[1]) and isValue(c):
         if leValue(c, fact.sons[1].pred): result = impNo
 
   of mNot, mOr, mAnd: internalError(x.info, "impliesLe")
@@ -620,7 +644,7 @@ proc factImplies(fact, prop: PNode): TImplication =
     # it's provably wrong if every value > 4 is in the set {56}
     # That's because we compute the implication and  'a -> not b' cannot
     # be treated the same as 'not a -> b'
-    
+
     #  (not a) -> b  compute as  not (a -> b) ???
     #  == not a or not b == not (a and b)
     let arg = fact.sons[1]
@@ -635,13 +659,13 @@ proc factImplies(fact, prop: PNode): TImplication =
       if a == b: return ~a
       return impUnknown
     else:
-      internalError(fact.info, "invalid fact")
+      return impUnknown
   of mAnd:
     result = factImplies(fact.sons[1], prop)
     if result != impUnknown: return result
     return factImplies(fact.sons[2], prop)
   else: discard
-  
+
   case prop.sons[0].sym.magic
   of mNot: result = ~fact.factImplies(prop.sons[1])
   of mIsNil: result = impliesIsNil(fact, prop)
@@ -649,7 +673,7 @@ proc factImplies(fact, prop: PNode): TImplication =
   of someLe: result = impliesLe(fact, prop.sons[1], prop.sons[2])
   of someLt: result = impliesLt(fact, prop.sons[1], prop.sons[2])
   of mInSet: result = impliesIn(fact, prop.sons[2], prop.sons[1])
-  else: internalError(prop.info, "invalid proposition")
+  else: result = impUnknown
 
 proc doesImply*(facts: TModel, prop: PNode): TImplication =
   assert prop.kind in nkCallKinds
@@ -677,6 +701,7 @@ proc pleViaModel(model: TModel; aa, bb: PNode): TImplication
 
 proc ple(m: TModel; a, b: PNode): TImplication =
   template `<=?`(a,b): expr = ple(m,a,b) == impYes
+
   #   0 <= 3
   if a.isValue and b.isValue:
     return if leValue(a, b): impYes else: impNo
@@ -750,16 +775,21 @@ proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication =
       # mark as used:
       m[i] = nil
       if ple(m, a, x) == impYes:
-        if ple(m, y, b) == impYes: return impYes
+        if ple(m, y, b) == impYes:
+          return impYes
         #if pleViaModelRec(m, y, b): return impYes
       # fact:  16 <= i
       #         x    y
       # question: i <= 15? no!
       result = impliesLe(fact, a, b)
-      if result != impUnknown: return result
-      if sameTree(y, a):
-        result = ple(m, b, x)
-        if result != impUnknown: return result
+      if result != impUnknown:
+        return result
+      when false:
+        # given: x <= y;  y==a;  x <= a this means: a <= b  if  x <= b
+        if sameTree(y, a):
+          result = ple(m, b, x)
+          if result != impUnknown:
+            return result
 
 proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
   # compute replacements:
diff --git a/compiler/idents.nim b/compiler/idents.nim
index 775bffa00..0cca18929 100644
--- a/compiler/idents.nim
+++ b/compiler/idents.nim
@@ -25,7 +25,7 @@ type
     next*: PIdent             # for hash-table chaining
     h*: THash                 # hash value of s
 
-var firstCharIsCS*: bool
+var firstCharIsCS*: bool = true
 var buckets*: array[0..4096 * 2 - 1, PIdent]
 
 proc cmpIgnoreStyle(a, b: cstring, blen: int): int =
diff --git a/compiler/importer.nim b/compiler/importer.nim
index fbf3be4f2..d619725db 100644
--- a/compiler/importer.nim
+++ b/compiler/importer.nim
@@ -9,7 +9,7 @@
 
 # This module implements the symbol importing mechanism.
 
-import 
+import
   intsets, strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups,
   semdata, passes, renderer
 
@@ -27,7 +27,7 @@ proc getModuleName*(n: PNode): string =
     result = n.ident.s
   of nkSym:
     result = n.sym.name.s
-  of nkInfix:
+  of nkInfix, nkPrefix:
     if n.sons[0].kind == nkIdent and n.sons[0].ident.id == getIdent("as").id:
       # XXX hack ahead:
       n.kind = nkImportAs
@@ -73,12 +73,12 @@ proc rawImportSymbol(c: PContext, s: PSym) =
     if etyp.kind in {tyBool, tyEnum} and sfPure notin s.flags:
       for j in countup(0, sonsLen(etyp.n) - 1):
         var e = etyp.n.sons[j].sym
-        if e.kind != skEnumField: 
-          internalError(s.info, "rawImportSymbol") 
+        if e.kind != skEnumField:
+          internalError(s.info, "rawImportSymbol")
           # BUGFIX: because of aliases for enums the symbol may already
           # have been put into the symbol table
           # BUGFIX: but only iff they are the same symbols!
-        var it: TIdentIter 
+        var it: TIdentIter
         check = initIdentIter(it, c.importTable.symbols, e.name)
         while check != nil:
           if check.id == e.id:
@@ -92,7 +92,7 @@ proc rawImportSymbol(c: PContext, s: PSym) =
     if s.kind == skConverter: addConverter(c, s)
     if hasPattern(s): addPattern(c, s)
 
-proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =        
+proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
   let ident = lookups.considerQuotedIdent(n)
   let s = strTableGet(fromMod.tab, ident)
   if s == nil:
@@ -143,7 +143,7 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) =
   of nkExportExceptStmt:
     localError(n.info, errGenerated, "'export except' not implemented")
   else:
-    for i in 0 ..safeLen(n)-1:
+    for i in 0..safeLen(n)-1:
       importForwarded(c, n.sons[i], exceptSet)
 
 proc importModuleAs(n: PNode, realModule: PSym): PSym =
@@ -155,7 +155,7 @@ proc importModuleAs(n: PNode, realModule: PSym): PSym =
     # some misguided guy will write 'import abc.foo as foo' ...
     result = createModuleAlias(realModule, n.sons[1].ident, realModule.info)
 
-proc myImportModule(c: PContext, n: PNode): PSym = 
+proc myImportModule(c: PContext, n: PNode): PSym =
   var f = checkModuleName(n)
   if f != InvalidFileIDX:
     result = importModuleAs(n, gImportModule(c.module, f))
@@ -164,10 +164,10 @@ proc myImportModule(c: PContext, n: PNode): PSym =
     if sfDeprecated in result.flags:
       message(n.info, warnDeprecated, result.name.s)
 
-proc evalImport(c: PContext, n: PNode): PNode = 
+proc evalImport(c: PContext, n: PNode): PNode =
   result = n
   var emptySet: IntSet
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     var m = myImportModule(c, n.sons[i])
     if m != nil:
       # ``addDecl`` needs to be done before ``importAllSymbols``!
@@ -175,7 +175,7 @@ proc evalImport(c: PContext, n: PNode): PNode =
       importAllSymbolsExcept(c, m, emptySet)
       #importForwarded(c, m.ast, emptySet)
 
-proc evalFrom(c: PContext, n: PNode): PNode = 
+proc evalFrom(c: PContext, n: PNode): PNode =
   result = n
   checkMinSonsLen(n, 2)
   var m = myImportModule(c, n.sons[0])
@@ -186,7 +186,7 @@ proc evalFrom(c: PContext, n: PNode): PNode =
       if n.sons[i].kind != nkNilLit:
         importSymbol(c, n.sons[i], m)
 
-proc evalImportExcept*(c: PContext, n: PNode): PNode = 
+proc evalImportExcept*(c: PContext, n: PNode): PNode =
   result = n
   checkMinSonsLen(n, 2)
   var m = myImportModule(c, n.sons[0])
@@ -194,7 +194,7 @@ proc evalImportExcept*(c: PContext, n: PNode): PNode =
     n.sons[0] = newSymNode(m)
     addDecl(c, m)               # add symbol to symbol table of module
     var exceptSet = initIntSet()
-    for i in countup(1, sonsLen(n) - 1): 
+    for i in countup(1, sonsLen(n) - 1):
       let ident = lookups.considerQuotedIdent(n.sons[i])
       exceptSet.incl(ident.id)
     importAllSymbolsExcept(c, m, exceptSet)
diff --git a/compiler/nim.ini b/compiler/installer.ini
index 576b6d2bb..12a8e702d 100644
--- a/compiler/nim.ini
+++ b/compiler/installer.ini
@@ -51,23 +51,35 @@ Files: "configure;makefile"
 Files: "*.ini"
 Files: "koch.nim"
 
-Files: "icons/nimrod.ico"
-Files: "icons/nimrod.rc"
-Files: "icons/nimrod.res"
-Files: "icons/nimrod_icon.o"
+Files: "icons/nim.ico"
+Files: "icons/nim.rc"
+Files: "icons/nim.res"
+Files: "icons/nim_icon.o"
 Files: "icons/koch.ico"
 Files: "icons/koch.rc"
 Files: "icons/koch.res"
 Files: "icons/koch_icon.o"
 
 Files: "compiler/readme.txt"
-Files: "compiler/nim.ini"
-Files: "compiler/nim.nimrod.cfg"
+Files: "compiler/installer.ini"
+Files: "compiler/nim.nim.cfg"
 Files: "compiler/*.nim"
 Files: "doc/*.txt"
+Files: "doc/manual/*.txt"
+Files: "doc/*.nim"
+Files: "doc/*.cfg"
 Files: "compiler/nimfix/*.nim"
 Files: "compiler/nimfix/*.cfg"
-
+Files: "tools/*.nim"
+Files: "tools/*.cfg"
+Files: "tools/*.tmpl"
+Files: "tools/niminst/*.nim"
+Files: "tools/niminst/*.cfg"
+Files: "tools/niminst/*.tmpl"
+Files: "tools/niminst/*.nsh"
+Files: "web/website.ini"
+Files: "web/*.nim"
+Files: "web/*.txt"
 
 [Lib]
 Files: "lib/nimbase.h"
@@ -77,8 +89,11 @@ Files: "lib/*.cfg"
 Files: "lib/system/*.nim"
 Files: "lib/core/*.nim"
 Files: "lib/pure/*.nim"
+Files: "lib/pure/*.cfg"
 Files: "lib/pure/collections/*.nim"
 Files: "lib/pure/concurrency/*.nim"
+Files: "lib/pure/unidecode/*.nim"
+Files: "lib/pure/concurrency/*.cfg"
 Files: "lib/impure/*.nim"
 Files: "lib/wrappers/*.nim"
 
@@ -125,7 +140,7 @@ Files: "start.bat"
 BinPath: r"bin;dist\mingw\bin;dist"
 
 ;           Section | dir | zipFile | size hint (in KB) | url | exe start menu entry
-Download: r"Documentation|doc|docs.zip|13824|http://nim-lang.org/download/docs-${version}.zip|doc\overview.html"
+Download: r"Documentation|doc|docs.zip|13824|http://nim-lang.org/download/docs-${version}.zip|overview.html"
 Download: r"C Compiler (MingW)|dist|mingw.zip|82944|http://nim-lang.org/download/${mingw}.zip"
 Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.1.3.zip|aporia\bin\aporia.exe"
 ; for now only NSIS supports optional downloads
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 2ae85d5cf..704713243 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -33,7 +33,7 @@ import
   ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
   options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, os,
   times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
-  intsets, cgmeth
+  intsets, cgmeth, lowerings
 
 type
   TTarget = enum
@@ -59,17 +59,17 @@ type
   TCompRes = object
     kind: TResKind
     typ: TJSTypeKind
-    res: PRope               # result part; index if this is an
+    res: Rope               # result part; index if this is an
                              # (address, index)-tuple
-    address: PRope           # address of an (address, index)-tuple
-  
-  TBlock = object 
+    address: Rope           # address of an (address, index)-tuple
+
+  TBlock = object
     id: int                  # the ID of the label; positive means that it
                              # has been used (i.e. the label should be emitted)
     isLoop: bool             # whether it's a 'block' or 'while'
-  
-  TGlobals = object 
-    typeInfo, code: PRope
+
+  TGlobals = object
+    typeInfo, code: Rope
     forwarded: seq[PSym]
     generatedSyms: IntSet
     typeInfoGenerated: IntSet
@@ -79,7 +79,7 @@ type
   TProc = object
     procDef: PNode
     prc: PSym
-    locals, body: PRope
+    locals, body: Rope
     options: TOptions
     module: BModule
     g: PGlobals
@@ -98,21 +98,21 @@ proc newGlobals(): PGlobals =
   result.generatedSyms = initIntSet()
   result.typeInfoGenerated = initIntSet()
 
-proc initCompRes(r: var TCompRes) = 
+proc initCompRes(r: var TCompRes) =
   r.address = nil
   r.res = nil
   r.typ = etyNone
   r.kind = resNone
 
-proc rdLoc(a: TCompRes): PRope {.inline.} =
+proc rdLoc(a: TCompRes): Rope {.inline.} =
   result = a.res
   when false:
     if a.typ != etyBaseIndex:
       result = a.res
     else:
-      result = ropef("$1[$2]", a.address, a.res)
+      result = "$1[$2]" % [a.address, a.res]
 
-proc newProc(globals: PGlobals, module: BModule, procDef: PNode, 
+proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
              options: TOptions): PProc =
   result = PProc(
     blocks: @[],
@@ -121,55 +121,56 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
     procDef: procDef,
     g: globals)
   if procDef != nil: result.prc = procDef.sons[namePos].sym
-  
-const 
-  MappedToObject = {tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, 
-    tySet, tyVar, tyRef, tyPtr, tyBigNum, tyVarargs}
 
-proc mapType(typ: PType): TJSTypeKind = 
+const
+  MappedToObject = {tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray,
+    tySet, tyBigNum, tyVarargs}
+
+proc mapType(typ: PType): TJSTypeKind =
   let t = skipTypes(typ, abstractInst)
   case t.kind
-  of tyVar, tyRef, tyPtr: 
-    if skipTypes(t.lastSon, abstractInst).kind in MappedToObject: 
+  of tyVar, tyRef, tyPtr:
+    if skipTypes(t.lastSon, abstractInst).kind in MappedToObject:
       result = etyObject
-    else: 
+    else:
       result = etyBaseIndex
   of tyPointer:
     # treat a tyPointer like a typed pointer to an array of bytes
     result = etyInt
-  of tyRange, tyDistinct, tyOrdinal, tyConst, tyMutable, tyIter, tyProxy: 
+  of tyRange, tyDistinct, tyOrdinal, tyConst, tyMutable, tyIter, tyProxy:
     result = mapType(t.sons[0])
   of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: result = etyInt
   of tyBool: result = etyBool
   of tyFloat..tyFloat128: result = etyFloat
   of tySet: result = etyObject # map a set to a table
   of tyString, tySequence: result = etyInt # little hack to get right semantics
-  of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, tyBigNum, 
+  of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, tyBigNum,
      tyVarargs:
     result = etyObject
   of tyNil: result = etyNull
-  of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation,
+  of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvocation,
      tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor,
      tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses:
     result = etyNone
   of tyProc: result = etyProc
   of tyCString: result = etyString
-  
-proc mangleName(s: PSym): PRope = 
+
+proc mangleName(s: PSym): Rope =
   result = s.loc.r
-  if result == nil: 
-    result = toRope(mangle(s.name.s))
-    app(result, "_")
-    app(result, toRope(s.id))
+  if result == nil:
+    result = rope(mangle(s.name.s))
+    add(result, "_")
+    add(result, rope(s.id))
     s.loc.r = result
 
-proc makeJSString(s: string): PRope = strutils.escape(s).toRope
+proc makeJSString(s: string): Rope =
+  (if s.isNil: "null".rope else: strutils.escape(s).rope)
 
 include jstypes
-  
+
 proc gen(p: PProc, n: PNode, r: var TCompRes)
 proc genStmt(p: PProc, n: PNode)
-proc genProc(oldProc: PProc, prc: PSym): PRope
+proc genProc(oldProc: PProc, prc: PSym): Rope
 proc genConstant(p: PProc, c: PSym)
 
 proc useMagic(p: PProc, name: string) =
@@ -178,7 +179,7 @@ proc useMagic(p: PProc, name: string) =
   if s != nil:
     internalAssert s.kind in {skProc, skMethod, skConverter}
     if not p.g.generatedSyms.containsOrIncl(s.id):
-      app(p.g.code, genProc(p, s))
+      add(p.g.code, genProc(p, s))
   else:
     # we used to exclude the system module from this check, but for DLL
     # generation support this sloppyness leads to hard to detect bugs, so
@@ -196,10 +197,10 @@ proc isSimpleExpr(n: PNode): bool =
   elif n.isAtom:
     result = true
 
-proc getTemp(p: PProc): PRope =
+proc getTemp(p: PProc): Rope =
   inc(p.unique)
-  result = ropef("Tmp$1", [toRope(p.unique)])
-  appf(p.locals, "var $1;$n" | "local $1;$n", [result])
+  result = "Tmp$1" % [rope(p.unique)]
+  addf(p.locals, "var $1;$n" | "local $1;$n", [result])
 
 proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
   assert r.kind == resNone
@@ -208,7 +209,7 @@ proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
     gen(p, a, x)
     gen(p, b, y)
     r.kind = resExpr
-    r.res = ropef("($1 && $2)" | "($1 and $2)", [x.rdLoc, y.rdLoc])
+    r.res = ("($1 && $2)" | "($1 and $2)") % [x.rdLoc, y.rdLoc]
   else:
     r.res = p.getTemp
     r.kind = resVal
@@ -222,11 +223,11 @@ proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
     #     tmp = b
     # tmp
     gen(p, a, x)
-    p.body.appf("if (!$1) $2 = false; else {" |
-                "if not $1 then $2 = false; else", x.rdLoc, r.rdLoc)
+    p.body.addf("if (!$1) $2 = false; else {" |
+                "if not $1 then $2 = false; else", [x.rdLoc, r.rdLoc])
     gen(p, b, y)
-    p.body.appf("$2 = $1; }" |
-                "$2 = $1 end", y.rdLoc, r.rdLoc)
+    p.body.addf("$2 = $1; }" |
+                "$2 = $1 end", [y.rdLoc, r.rdLoc])
 
 proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
   assert r.kind == resNone
@@ -235,16 +236,16 @@ proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
     gen(p, a, x)
     gen(p, b, y)
     r.kind = resExpr
-    r.res = ropef("($1 || $2)" | "($1 or $2)", [x.rdLoc, y.rdLoc])
+    r.res = ("($1 || $2)" | "($1 or $2)") % [x.rdLoc, y.rdLoc]
   else:
     r.res = p.getTemp
     r.kind = resVal
     gen(p, a, x)
-    p.body.appf("if ($1) $2 = true; else {" |
-                "if $1 then $2 = true; else", x.rdLoc, r.rdLoc)
+    p.body.addf("if ($1) $2 = true; else {" |
+                "if $1 then $2 = true; else", [x.rdLoc, r.rdLoc])
     gen(p, b, y)
-    p.body.appf("$2 = $1; }" |
-                "$2 = $1 end", y.rdLoc, r.rdLoc)
+    p.body.addf("$2 = $1; }" |
+                "$2 = $1 end", [y.rdLoc, r.rdLoc])
 
 type
   TMagicFrmt = array[0..3, string]
@@ -262,6 +263,8 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["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
+    ["addInt", "", "addInt($1, $2)", "($1 + $2)"], # Succ
+    ["subInt", "", "subInt($1, $2)", "($1 - $2)"], # Pred
     ["", "", "($1 + $2)", "($1 + $2)"], # AddF64
     ["", "", "($1 - $2)", "($1 - $2)"], # SubF64
     ["", "", "($1 * $2)", "($1 * $2)"], # MulF64
@@ -278,8 +281,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["", "", "($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
     ["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
@@ -323,7 +324,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["", "", "!($1)", "!($1)"], # Not
     ["", "", "+($1)", "+($1)"], # UnaryPlusI
     ["", "", "~($1)", "~($1)"], # BitnotI
-    ["", "", "+($1)", "+($1)"], # UnaryPlusI64
     ["", "", "~($1)", "~($1)"], # BitnotI64
     ["", "", "+($1)", "+($1)"], # UnaryPlusF64
     ["", "", "-($1)", "-($1)"], # UnaryMinusF64
@@ -341,14 +341,14 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["", "", "$1", "$1"],     # ToBiggestFloat
     ["", "", "Math.floor($1)", "Math.floor($1)"], # ToInt
     ["", "", "Math.floor($1)", "Math.floor($1)"], # ToBiggestInt
-    ["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"], 
+    ["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)"], 
+      "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"]]
 
   luaOps: TMagicOps = [
@@ -362,6 +362,8 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["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
+    ["addInt", "", "addInt($1, $2)", "($1 + $2)"], # Succ
+    ["subInt", "", "subInt($1, $2)", "($1 - $2)"], # Pred
     ["", "", "($1 + $2)", "($1 + $2)"], # AddF64
     ["", "", "($1 - $2)", "($1 - $2)"], # SubF64
     ["", "", "($1 * $2)", "($1 * $2)"], # MulF64
@@ -378,8 +380,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["", "", "($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
     ["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
@@ -423,7 +423,6 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["", "", "not ($1)", "not ($1)"], # Not
     ["", "", "+($1)", "+($1)"], # UnaryPlusI
     ["", "", "~($1)", "~($1)"], # BitnotI
-    ["", "", "+($1)", "+($1)"], # UnaryPlusI64
     ["", "", "~($1)", "~($1)"], # BitnotI64
     ["", "", "+($1)", "+($1)"], # UnaryPlusF64
     ["", "", "-($1)", "-($1)"], # UnaryMinusF64
@@ -441,14 +440,14 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["", "", "$1", "$1"],     # ToBiggestFloat
     ["", "", "Math.floor($1)", "Math.floor($1)"], # ToInt
     ["", "", "Math.floor($1)", "Math.floor($1)"], # ToBiggestInt
-    ["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"], 
+    ["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)"], 
+      "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"]]
 
 proc binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
@@ -456,7 +455,7 @@ proc binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
   useMagic(p, magic)
   gen(p, n.sons[1], x)
   gen(p, n.sons[2], y)
-  r.res = ropef(frmt, [x.rdLoc, y.rdLoc])
+  r.res = frmt % [x.rdLoc, y.rdLoc]
   r.kind = resExpr
 
 proc ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
@@ -465,13 +464,13 @@ proc ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
   gen(p, n.sons[1], x)
   gen(p, n.sons[2], y)
   gen(p, n.sons[3], z)
-  r.res = ropef(frmt, [x.rdLoc, y.rdLoc, z.rdLoc])
+  r.res = frmt % [x.rdLoc, y.rdLoc, z.rdLoc]
   r.kind = resExpr
 
 proc unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
   useMagic(p, magic)
   gen(p, n.sons[1], r)
-  r.res = ropef(frmt, [r.rdLoc])
+  r.res = frmt % [r.rdLoc]
   r.kind = resExpr
 
 proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic, ops: TMagicOps) =
@@ -482,10 +481,10 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic, ops: TMagicOps) =
   if sonsLen(n) > 2:
     gen(p, n.sons[1], x)
     gen(p, n.sons[2], y)
-    r.res = ropef(ops[op][i + 2], [x.rdLoc, y.rdLoc])
+    r.res = ops[op][i + 2] % [x.rdLoc, y.rdLoc]
   else:
     gen(p, n.sons[1], r)
-    r.res = ropef(ops[op][i + 2], [r.rdLoc])
+    r.res = ops[op][i + 2] % [r.rdLoc]
   r.kind = resExpr
 
 proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
@@ -494,17 +493,17 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
 proc genLineDir(p: PProc, n: PNode) =
   let line = toLinenumber(n.info)
   if optLineDir in p.options:
-    appf(p.body, "// line $2 \"$1\"$n" | "-- line $2 \"$1\"$n",
-         [toRope(toFilename(n.info)), toRope(line)])
+    addf(p.body, "// line $2 \"$1\"$n" | "-- line $2 \"$1\"$n",
+         [rope(toFilename(n.info)), rope(line)])
   if {optStackTrace, optEndb} * p.options == {optStackTrace, optEndb} and
       ((p.prc == nil) or sfPure notin p.prc.flags):
     useMagic(p, "endb")
-    appf(p.body, "endb($1);$n", [toRope(line)])
+    addf(p.body, "endb($1);$n", [rope(line)])
   elif ({optLineTrace, optStackTrace} * p.options ==
       {optLineTrace, optStackTrace}) and
-      ((p.prc == nil) or not (sfPure in p.prc.flags)): 
-    appf(p.body, "F.line = $1;$n", [toRope(line)])
-  
+      ((p.prc == nil) or not (sfPure in p.prc.flags)):
+    addf(p.body, "F.line = $1;$n", [rope(line)])
+
 proc genWhileStmt(p: PProc, n: PNode) =
   var
     cond: TCompRes
@@ -515,25 +514,25 @@ proc genWhileStmt(p: PProc, n: PNode) =
   setLen(p.blocks, length + 1)
   p.blocks[length].id = -p.unique
   p.blocks[length].isLoop = true
-  let labl = p.unique.toRope
-  appf(p.body, "L$1: while (true) {$n" | "while true do$n", labl)
+  let labl = p.unique.rope
+  addf(p.body, "L$1: while (true) {$n" | "while true do$n", [labl])
   gen(p, n.sons[0], cond)
-  appf(p.body, "if (!$1) break L$2;$n" | "if not $1 then goto ::L$2:: end;$n",
+  addf(p.body, "if (!$1) break L$2;$n" | "if not $1 then goto ::L$2:: end;$n",
        [cond.res, labl])
   genStmt(p, n.sons[1])
-  appf(p.body, "}$n" | "end ::L$#::$n", [labl])
+  addf(p.body, "}$n" | "end ::L$#::$n", [labl])
   setLen(p.blocks, length)
 
 proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
   if src.kind != resNone:
     if dest.kind != resNone:
-      p.body.appf("$1 = $2;$n", dest.rdLoc, src.rdLoc)
+      p.body.addf("$1 = $2;$n", [dest.rdLoc, src.rdLoc])
     else:
-      p.body.appf("$1;$n", src.rdLoc)
+      p.body.addf("$1;$n", [src.rdLoc])
     src.kind = resNone
     src.res = nil
 
-proc genTry(p: PProc, n: PNode, r: var TCompRes) = 
+proc genTry(p: PProc, n: PNode, r: var TCompRes) =
   # code to generate:
   #
   #  var sp = {prev: excHandler, exc: null};
@@ -558,58 +557,56 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
     r.kind = resVal
     r.res = getTemp(p)
   inc(p.unique)
-  var safePoint = ropef("Tmp$1", [toRope(p.unique)])
-  appf(p.body,
-       "var $1 = {prev: excHandler, exc: null};$nexcHandler = $1;$n" | 
-       "local $1 = pcall(", 
+  var safePoint = "Tmp$1" % [rope(p.unique)]
+  addf(p.body,
+       "var $1 = {prev: excHandler, exc: null};$nexcHandler = $1;$n" |
+       "local $1 = pcall(",
        [safePoint])
-  if optStackTrace in p.options: app(p.body, "framePtr = F;" & tnl)
-  appf(p.body, "try {$n" | "function()$n")
+  if optStackTrace in p.options: add(p.body, "framePtr = F;" & tnl)
+  addf(p.body, "try {$n" | "function()$n", [])
   var length = sonsLen(n)
   var a: TCompRes
   gen(p, n.sons[0], a)
   moveInto(p, a, r)
   var i = 1
   if p.target == targetJS and length > 1 and n.sons[i].kind == nkExceptBranch:
-    appf(p.body, "} catch (EXC) {$n  lastJSError = EXC;$n")
+    addf(p.body, "} catch (EXC) {$n  lastJSError = EXC;$n", [])
   elif p.target == targetLua:
-    appf(p.body, "end)$n")
-  while i < length and n.sons[i].kind == nkExceptBranch: 
+    addf(p.body, "end)$n", [])
+  while i < length and n.sons[i].kind == nkExceptBranch:
     let blen = sonsLen(n.sons[i])
-    if blen == 1: 
+    if blen == 1:
       # general except section:
-      if i > 1: appf(p.body, "else {$n" | "else$n")
+      if i > 1: addf(p.body, "else {$n" | "else$n", [])
       gen(p, n.sons[i].sons[0], a)
       moveInto(p, a, r)
-      if i > 1: appf(p.body, "}$n" | "end$n")
+      if i > 1: addf(p.body, "}$n" | "end$n", [])
     else:
-      var orExpr: PRope = nil
+      var orExpr: Rope = nil
       useMagic(p, "isObj")
-      for j in countup(0, blen - 2): 
-        if n.sons[i].sons[j].kind != nkType: 
+      for j in countup(0, blen - 2):
+        if n.sons[i].sons[j].kind != nkType:
           internalError(n.info, "genTryStmt")
-        if orExpr != nil: app(orExpr, "||" | " or ")
-        appf(orExpr, "isObj($1.exc.m_type, $2)", 
+        if orExpr != nil: add(orExpr, "||" | " or ")
+        addf(orExpr, "isObj($1.exc.m_type, $2)",
              [safePoint, genTypeInfo(p, n.sons[i].sons[j].typ)])
-      if i > 1: app(p.body, "else ")
-      appf(p.body, "if ($1.exc && ($2)) {$n" | "if $1.exc and ($2) then$n",
+      if i > 1: add(p.body, "else ")
+      addf(p.body, "if ($1.exc && ($2)) {$n" | "if $1.exc and ($2) then$n",
         [safePoint, orExpr])
       gen(p, n.sons[i].sons[blen - 1], a)
       moveInto(p, a, r)
-      appf(p.body, "}$n" | "end$n")
+      addf(p.body, "}$n" | "end$n", [])
     inc(i)
   if p.target == targetJS:
-    app(p.body, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl)
+    add(p.body, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl)
   if i < length and n.sons[i].kind == nkFinally:
-    gen(p, n.sons[i].sons[0], a)
-    moveInto(p, a, r)
+    genStmt(p, n.sons[i].sons[0])
   if p.target == targetJS:
-    app(p.body, "}" & tnl)
+    add(p.body, "}" & tnl)
   if p.target == targetLua:
     # we need to repeat the finally block for Lua ...
     if i < length and n.sons[i].kind == nkFinally:
-      gen(p, n.sons[i].sons[0], a)
-      moveInto(p, a, r)
+      genStmt(p, n.sons[i].sons[0])
 
 proc genRaiseStmt(p: PProc, n: PNode) =
   genLineDir(p, n)
@@ -618,59 +615,59 @@ proc genRaiseStmt(p: PProc, n: PNode) =
     gen(p, n.sons[0], a)
     let typ = skipTypes(n.sons[0].typ, abstractPtrs)
     useMagic(p, "raiseException")
-    appf(p.body, "raiseException($1, $2);$n",
+    addf(p.body, "raiseException($1, $2);$n",
          [a.rdLoc, makeJSString(typ.sym.name.s)])
   else:
     useMagic(p, "reraiseException")
-    app(p.body, "reraiseException();" & tnl)
+    add(p.body, "reraiseException();" & tnl)
 
-proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) = 
+proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
   var
     cond, stmt: TCompRes
   genLineDir(p, n)
   gen(p, n.sons[0], cond)
   let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
-  if stringSwitch: 
+  if stringSwitch:
     useMagic(p, "toJSStr")
-    appf(p.body, "switch (toJSStr($1)) {$n", [cond.rdLoc])
+    addf(p.body, "switch (toJSStr($1)) {$n", [cond.rdLoc])
   else:
-    appf(p.body, "switch ($1) {$n", [cond.rdLoc])
+    addf(p.body, "switch ($1) {$n", [cond.rdLoc])
   if not isEmptyType(n.typ):
     r.kind = resVal
     r.res = getTemp(p)
-  for i in countup(1, sonsLen(n) - 1): 
+  for i in countup(1, sonsLen(n) - 1):
     let it = n.sons[i]
     case it.kind
-    of nkOfBranch: 
-      for j in countup(0, sonsLen(it) - 2): 
+    of nkOfBranch:
+      for j in countup(0, sonsLen(it) - 2):
         let e = it.sons[j]
-        if e.kind == nkRange: 
+        if e.kind == nkRange:
           var v = copyNode(e.sons[0])
-          while v.intVal <= e.sons[1].intVal: 
+          while v.intVal <= e.sons[1].intVal:
             gen(p, v, cond)
-            appf(p.body, "case $1: ", [cond.rdLoc])
+            addf(p.body, "case $1: ", [cond.rdLoc])
             inc(v.intVal)
         else:
-          if stringSwitch: 
+          if stringSwitch:
             case e.kind
-            of nkStrLit..nkTripleStrLit: appf(p.body, "case $1: ", 
+            of nkStrLit..nkTripleStrLit: addf(p.body, "case $1: ",
                 [makeJSString(e.strVal)])
             else: internalError(e.info, "jsgen.genCaseStmt: 2")
-          else: 
+          else:
             gen(p, e, cond)
-            appf(p.body, "case $1: ", [cond.rdLoc])
+            addf(p.body, "case $1: ", [cond.rdLoc])
       gen(p, lastSon(it), stmt)
       moveInto(p, stmt, r)
-      appf(p.body, "$nbreak;$n")
+      addf(p.body, "$nbreak;$n", [])
     of nkElse:
-      appf(p.body, "default: $n")
+      addf(p.body, "default: $n", [])
       gen(p, it.sons[0], stmt)
       moveInto(p, stmt, r)
-      appf(p.body, "break;$n")
+      addf(p.body, "break;$n", [])
     else: internalError(it.info, "jsgen.genCaseStmt")
-  appf(p.body, "}$n")
+  addf(p.body, "}$n", [])
 
-proc genCaseLua(p: PProc, n: PNode, r: var TCompRes) = 
+proc genCaseLua(p: PProc, n: PNode, r: var TCompRes) =
   var
     cond, stmt: TCompRes
   genLineDir(p, n)
@@ -679,47 +676,47 @@ proc genCaseLua(p: PProc, n: PNode, r: var TCompRes) =
   if stringSwitch:
     useMagic(p, "eqStr")
   let tmp = getTemp(p)
-  appf(p.body, "$1 = $2;$n", [tmp, cond.rdLoc])
+  addf(p.body, "$1 = $2;$n", [tmp, cond.rdLoc])
   if not isEmptyType(n.typ):
     r.kind = resVal
     r.res = getTemp(p)
-  for i in countup(1, sonsLen(n) - 1): 
+  for i in countup(1, sonsLen(n) - 1):
     let it = n.sons[i]
     case it.kind
     of nkOfBranch:
-      if i != 1: appf(p.body, "$nelsif ")
-      else: appf(p.body, "if ")
-      for j in countup(0, sonsLen(it) - 2): 
-        if j != 0: app(p.body, " or ")
+      if i != 1: addf(p.body, "$nelsif ", [])
+      else: addf(p.body, "if ", [])
+      for j in countup(0, sonsLen(it) - 2):
+        if j != 0: add(p.body, " or ")
         let e = it.sons[j]
         if e.kind == nkRange:
           var ia, ib: TCompRes
           gen(p, e.sons[0], ia)
           gen(p, e.sons[1], ib)
-          appf(p.body, "$1 >= $2 and $1 <= $3", [tmp, ia.rdLoc, ib.rdLoc])
+          addf(p.body, "$1 >= $2 and $1 <= $3", [tmp, ia.rdLoc, ib.rdLoc])
         else:
-          if stringSwitch: 
+          if stringSwitch:
             case e.kind
-            of nkStrLit..nkTripleStrLit: appf(p.body, "eqStr($1, $2)",
+            of nkStrLit..nkTripleStrLit: addf(p.body, "eqStr($1, $2)",
                 [tmp, makeJSString(e.strVal)])
             else: internalError(e.info, "jsgen.genCaseStmt: 2")
           else:
             gen(p, e, cond)
-            appf(p.body, "$1 == $2", [tmp, cond.rdLoc])
-      appf(p.body, " then$n")
+            addf(p.body, "$1 == $2", [tmp, cond.rdLoc])
+      addf(p.body, " then$n", [])
       gen(p, lastSon(it), stmt)
       moveInto(p, stmt, r)
     of nkElse:
-      appf(p.body, "else$n")
+      addf(p.body, "else$n", [])
       gen(p, it.sons[0], stmt)
       moveInto(p, stmt, r)
     else: internalError(it.info, "jsgen.genCaseStmt")
-  appf(p.body, "$nend$n")
-  
+  addf(p.body, "$nend$n", [])
+
 proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
   inc(p.unique)
   let idx = len(p.blocks)
-  if n.sons[0].kind != nkEmpty: 
+  if n.sons[0].kind != nkEmpty:
     # named block?
     if (n.sons[0].kind != nkSym): internalError(n.info, "genBlock")
     var sym = n.sons[0].sym
@@ -728,15 +725,15 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
   setLen(p.blocks, idx + 1)
   p.blocks[idx].id = - p.unique # negative because it isn't used yet
   let labl = p.unique
-  appf(p.body, "L$1: do {$n" | "", labl.toRope)
+  addf(p.body, "L$1: do {$n" | "", [labl.rope])
   gen(p, n.sons[1], r)
-  appf(p.body, "} while(false);$n" | "$n::L$#::$n", labl.toRope)
+  addf(p.body, "} while(false);$n" | "$n::L$#::$n", [labl.rope])
   setLen(p.blocks, idx)
 
-proc genBreakStmt(p: PProc, n: PNode) = 
+proc genBreakStmt(p: PProc, n: PNode) =
   var idx: int
   genLineDir(p, n)
-  if n.sons[0].kind != nkEmpty: 
+  if n.sons[0].kind != nkEmpty:
     # named break?
     assert(n.sons[0].kind == nkSym)
     let sym = n.sons[0].sym
@@ -749,64 +746,64 @@ proc genBreakStmt(p: PProc, n: PNode) =
     if idx < 0 or not p.blocks[idx].isLoop:
       internalError(n.info, "no loop to break")
   p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
-  appf(p.body, "break L$1;$n" | "goto ::L$1::;$n", [toRope(p.blocks[idx].id)])
+  addf(p.body, "break L$1;$n" | "goto ::L$1::;$n", [rope(p.blocks[idx].id)])
 
-proc genAsmStmt(p: PProc, n: PNode) = 
+proc genAsmStmt(p: PProc, n: PNode) =
   genLineDir(p, n)
   assert(n.kind == nkAsmStmt)
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     case n.sons[i].kind
-    of nkStrLit..nkTripleStrLit: app(p.body, n.sons[i].strVal)
-    of nkSym: app(p.body, mangleName(n.sons[i].sym))
+    of nkStrLit..nkTripleStrLit: add(p.body, n.sons[i].strVal)
+    of nkSym: add(p.body, mangleName(n.sons[i].sym))
     else: internalError(n.sons[i].info, "jsgen: genAsmStmt()")
-  
-proc genIf(p: PProc, n: PNode, r: var TCompRes) = 
+
+proc genIf(p: PProc, n: PNode, r: var TCompRes) =
   var cond, stmt: TCompRes
   var toClose = 0
   if not isEmptyType(n.typ):
     r.kind = resVal
     r.res = getTemp(p)
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     let it = n.sons[i]
-    if sonsLen(it) != 1: 
+    if sonsLen(it) != 1:
       if i > 0:
-        appf(p.body, "else {$n" | "else$n", [])
+        addf(p.body, "else {$n" | "else$n", [])
         inc(toClose)
       gen(p, it.sons[0], cond)
-      appf(p.body, "if ($1) {$n" | "if $# then$n", cond.rdLoc)
+      addf(p.body, "if ($1) {$n" | "if $# then$n", [cond.rdLoc])
       gen(p, it.sons[1], stmt)
     else:
       # else part:
-      appf(p.body, "else {$n" | "else$n")
+      addf(p.body, "else {$n" | "else$n", [])
       gen(p, it.sons[0], stmt)
     moveInto(p, stmt, r)
-    appf(p.body, "}$n" | "end$n")
+    addf(p.body, "}$n" | "end$n", [])
   if p.target == targetJS:
-    app(p.body, repeatChar(toClose, '}') & tnl)
+    add(p.body, repeat('}', toClose) & tnl)
   else:
-    for i in 1..toClose: appf(p.body, "end$n")
+    for i in 1..toClose: addf(p.body, "end$n", [])
 
-proc generateHeader(p: PProc, typ: PType): PRope =
+proc generateHeader(p: PProc, typ: PType): Rope =
   result = nil
   for i in countup(1, sonsLen(typ.n) - 1):
-    if result != nil: app(result, ", ")
     assert(typ.n.sons[i].kind == nkSym)
     var param = typ.n.sons[i].sym
     if isCompileTimeOnly(param.typ): continue
+    if result != nil: add(result, ", ")
     var name = mangleName(param)
-    app(result, name)
-    if mapType(param.typ) == etyBaseIndex: 
-      app(result, ", ")
-      app(result, name)
-      app(result, "_Idx")
-
-const 
-  nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit, 
-    nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkObjConstr, nkStringToCString, 
-    nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix, 
+    add(result, name)
+    if mapType(param.typ) == etyBaseIndex:
+      add(result, ", ")
+      add(result, name)
+      add(result, "_Idx")
+
+const
+  nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
+    nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkObjConstr, nkStringToCString,
+    nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix,
     nkCommand, nkHiddenCallConv, nkCallStrLit}
 
-proc needsNoCopy(y: PNode): bool = 
+proc needsNoCopy(y: PNode): bool =
   result = (y.kind in nodeKindsNeedNoCopy) or
       (skipTypes(y.typ, abstractInst).kind in {tyRef, tyPtr, tyVar})
 
@@ -817,42 +814,42 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
   case mapType(x.typ)
   of etyObject:
     if needsNoCopy(y) or noCopyNeeded:
-      appf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
+      addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
     else:
       useMagic(p, "nimCopy")
-      appf(p.body, "$1 = nimCopy($2, $3);$n",
+      addf(p.body, "$1 = nimCopy($2, $3);$n",
            [a.res, b.res, genTypeInfo(p, y.typ)])
-  of etyBaseIndex: 
-    if a.typ != etyBaseIndex or b.typ != etyBaseIndex: 
+  of etyBaseIndex:
+    if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
       internalError(x.info, "genAsgn")
-    appf(p.body, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
+    addf(p.body, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
   else:
-    appf(p.body, "$1 = $2;$n", [a.res, b.res])
+    addf(p.body, "$1 = $2;$n", [a.res, b.res])
 
-proc genAsgn(p: PProc, n: PNode) = 
+proc genAsgn(p: PProc, n: PNode) =
   genLineDir(p, n)
   genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=false)
 
-proc genFastAsgn(p: PProc, n: PNode) = 
+proc genFastAsgn(p: PProc, n: PNode) =
   genLineDir(p, n)
   genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=true)
 
-proc genSwap(p: PProc, n: PNode) = 
+proc genSwap(p: PProc, n: PNode) =
   var a, b: TCompRes
   gen(p, n.sons[1], a)
   gen(p, n.sons[2], b)
   inc(p.unique)
-  var tmp = ropef("Tmp$1", [toRope(p.unique)])
+  var tmp = "Tmp$1" % [rope(p.unique)]
   if mapType(skipTypes(n.sons[1].typ, abstractVar)) == etyBaseIndex:
     inc(p.unique)
-    let tmp2 = ropef("Tmp$1", [toRope(p.unique)])
-    if a.typ != etyBaseIndex or b.typ != etyBaseIndex: 
+    let tmp2 = "Tmp$1" % [rope(p.unique)]
+    if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
       internalError(n.info, "genSwap")
-    appf(p.body, "var $1 = $2; $2 = $3; $3 = $1;$n" |
+    addf(p.body, "var $1 = $2; $2 = $3; $3 = $1;$n" |
                  "local $1 = $2; $2 = $3; $3 = $1;$n", [
                  tmp, a.address, b.address])
     tmp = tmp2
-  appf(p.body, "var $1 = $2; $2 = $3; $3 = $1;" |
+  addf(p.body, "var $1 = $2; $2 = $3; $3 = $1;" |
                "local $1 = $2; $2 = $3; $3 = $1;", [tmp, a.res, b.res])
 
 proc getFieldPosition(f: PNode): int =
@@ -861,7 +858,7 @@ proc getFieldPosition(f: PNode): int =
   of nkSym: result = f.sym.position
   else: internalError(f.info, "genFieldPosition")
 
-proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) = 
+proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
   r.typ = etyBaseIndex
   let b = if n.kind == nkHiddenAddr: n.sons[0] else: n
@@ -872,31 +869,33 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
     if b.sons[1].kind != nkSym: internalError(b.sons[1].info, "genFieldAddr")
     var f = b.sons[1].sym
     if f.loc.r == nil: f.loc.r = mangleName(f)
-    r.res = makeJSString(ropeToStr(f.loc.r))
+    r.res = makeJSString($f.loc.r)
   internalAssert a.typ != etyBaseIndex
   r.address = a.res
   r.kind = resExpr
 
-proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) = 
+proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
   r.typ = etyNone
   gen(p, n.sons[0], r)
   if skipTypes(n.sons[0].typ, abstractVarRange).kind == tyTuple:
-    r.res = ropef("$1.Field$2", [r.res, getFieldPosition(n.sons[1]).toRope])
+    r.res = "$1.Field$2" % [r.res, getFieldPosition(n.sons[1]).rope]
   else:
     if n.sons[1].kind != nkSym: internalError(n.sons[1].info, "genFieldAddr")
     var f = n.sons[1].sym
     if f.loc.r == nil: f.loc.r = mangleName(f)
-    r.res = ropef("$1.$2", [r.res, f.loc.r])
+    r.res = "$1.$2" % [r.res, f.loc.r]
   r.kind = resExpr
 
-proc genCheckedFieldAddr(p: PProc, n: PNode, r: var TCompRes) = 
-  genFieldAddr(p, n.sons[0], r) # XXX
-  
-proc genCheckedFieldAccess(p: PProc, n: PNode, r: var TCompRes) = 
+proc genCheckedFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
+  let m = if n.kind == nkHiddenAddr: n.sons[0] else: n
+  internalAssert m.kind == nkCheckedFieldExpr
+  genFieldAddr(p, m.sons[0], r) # XXX
+
+proc genCheckedFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
   genFieldAccess(p, n.sons[0], r) # XXX
-  
-proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) = 
-  var 
+
+proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
+  var
     a, b: TCompRes
     first: BiggestInt
   r.typ = etyBaseIndex
@@ -910,30 +909,36 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
   else: first = 0
   if optBoundsCheck in p.options and not isConstExpr(m.sons[1]):
     useMagic(p, "chckIndx")
-    r.res = ropef("chckIndx($1, $2, $3.length)-$2", 
-                  [b.res, toRope(first), a.res])
+    r.res = "chckIndx($1, $2, $3.length)-$2" % [b.res, rope(first), a.res]
   elif first != 0:
-    r.res = ropef("($1)-$2", [b.res, toRope(first)])
+    r.res = "($1)-$2" % [b.res, rope(first)]
   else:
     r.res = b.res
   r.kind = resExpr
 
-proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) = 
+proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
   var ty = skipTypes(n.sons[0].typ, abstractVarRange)
   if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
   case ty.kind
   of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString,
      tyVarargs:
     genArrayAddr(p, n, r)
-  of tyTuple: 
+  of tyTuple:
     genFieldAddr(p, n, r)
   else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
   r.typ = etyNone
   if r.res == nil: internalError(n.info, "genArrayAccess")
-  r.res = ropef("$1[$2]", [r.address, r.res])
+  r.res = "$1[$2]" % [r.address, r.res]
   r.address = nil
   r.kind = resExpr
 
+proc isIndirect(v: PSym): bool =
+  result = {sfAddrTaken, sfGlobal} * v.flags != {} and
+    #(mapType(v.typ) != etyObject) and
+    {sfImportc, sfVolatile, sfExportc} * v.flags == {} and
+    v.kind notin {skProc, skConverter, skMethod, skIterator, skClosureIterator,
+                  skConst, skTemp, skLet}
+
 proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
   case n.sons[0].kind
   of nkSym:
@@ -942,37 +947,43 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
     case s.kind
     of skVar, skLet, skResult:
       r.kind = resExpr
-      if mapType(n.sons[0].typ) == etyObject:
+      let jsType = mapType(n.typ)
+      if jsType == etyObject:
         # make addr() a no-op:
         r.typ = etyNone
-        r.res = s.loc.r
+        if isIndirect(s):
+          r.res = s.loc.r & "[0]"
+        else:
+          r.res = s.loc.r
         r.address = nil
-      elif {sfGlobal, sfAddrTaken} * s.flags != {}:
+      elif {sfGlobal, sfAddrTaken} * s.flags != {} or jsType == etyBaseIndex:
         # for ease of code generation, we do not distinguish between
         # sfAddrTaken and sfGlobal.
         r.typ = etyBaseIndex
         r.address = s.loc.r
-        r.res = toRope("0")
+        r.res = rope("0")
       else:
-        internalError(n.info, "genAddr: 4")
+        # 'var openArray' for instance produces an 'addr' but this is harmless:
+        gen(p, n.sons[0], r)
+        #internalError(n.info, "genAddr: 4 " & renderTree(n))
     else: internalError(n.info, "genAddr: 2")
   of nkCheckedFieldExpr:
     genCheckedFieldAddr(p, n, r)
   of nkDotExpr:
-    genFieldAddr(p, n, r)
+    genFieldAddr(p, n.sons[0], r)
   of nkBracketExpr:
     var ty = skipTypes(n.sons[0].typ, abstractVarRange)
     if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
     case ty.kind
     of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString,
-       tyVarargs:
-      genArrayAddr(p, n, r)
-    of tyTuple: 
-      genFieldAddr(p, n, r)
-    else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
-  else: internalError(n.info, "genAddr")
-  
-proc genSym(p: PProc, n: PNode, r: var TCompRes) = 
+       tyVarargs, tyChar:
+      genArrayAddr(p, n.sons[0], r)
+    of tyTuple:
+      genFieldAddr(p, n.sons[0], r)
+    else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $ty.kind & ')')
+  else: internalError(n.sons[0].info, "genAddr")
+
+proc genSym(p: PProc, n: PNode, r: var TCompRes) =
   var s = n.sym
   case s.kind
   of skVar, skLet, skParam, skTemp, skResult:
@@ -982,13 +993,13 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
     if k == etyBaseIndex:
       r.typ = etyBaseIndex
       if {sfAddrTaken, sfGlobal} * s.flags != {}:
-        r.address = ropef("$1[0]", [s.loc.r])
-        r.res = ropef("$1[1]", [s.loc.r])
+        r.address = "$1[0]" % [s.loc.r]
+        r.res = "$1[1]" % [s.loc.r]
       else:
         r.address = s.loc.r
-        r.res = con(s.loc.r, "_Idx")
-    elif k != etyObject and {sfAddrTaken, sfGlobal} * s.flags != {}:
-      r.res = ropef("$1[0]", [s.loc.r])
+        r.res = s.loc.r & "_Idx"
+    elif isIndirect(s):
+      r.res = "$1[0]" % [s.loc.r]
     else:
       r.res = s.loc.r
   of skConst:
@@ -1012,44 +1023,44 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
       var owner = p
       while owner != nil and owner.prc != s.owner:
         owner = owner.up
-      if owner != nil: app(owner.locals, newp)
-      else: app(p.g.code, newp)
+      if owner != nil: add(owner.locals, newp)
+      else: add(p.g.code, newp)
   else:
     if s.loc.r == nil:
       internalError(n.info, "symbol has no generated name: " & s.name.s)
     r.res = s.loc.r
   r.kind = resVal
-  
-proc genDeref(p: PProc, n: PNode, r: var TCompRes) = 
-  if mapType(n.sons[0].typ) == etyObject: 
+
+proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
+  if mapType(n.sons[0].typ) == etyObject:
     gen(p, n.sons[0], r)
   else:
     var a: TCompRes
     gen(p, n.sons[0], a)
     if a.typ != etyBaseIndex: internalError(n.info, "genDeref")
-    r.res = ropef("$1[$2]", [a.address, a.res])
+    r.res = "$1[$2]" % [a.address, a.res]
 
 proc genArg(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
   gen(p, n, a)
   if a.typ == etyBaseIndex:
-    app(r.res, a.address)
-    app(r.res, ", ")
-    app(r.res, a.res)
+    add(r.res, a.address)
+    add(r.res, ", ")
+    add(r.res, a.res)
   else:
-    app(r.res, a.res)
+    add(r.res, a.res)
 
 proc genArgs(p: PProc, n: PNode, r: var TCompRes) =
-  app(r.res, "(")
-  for i in countup(1, sonsLen(n) - 1): 
+  add(r.res, "(")
+  for i in countup(1, sonsLen(n) - 1):
     let it = n.sons[i]
-    if it.typ.isCompileTimeOnly: continue  
-    if i > 1: app(r.res, ", ")
+    if it.typ.isCompileTimeOnly: continue
+    if i > 1: add(r.res, ", ")
     genArg(p, it, r)
-  app(r.res, ")")
+  add(r.res, ")")
   r.kind = resExpr
 
-proc genCall(p: PProc, n: PNode, r: var TCompRes) = 
+proc genCall(p: PProc, n: PNode, r: var TCompRes) =
   gen(p, n.sons[0], r)
   genArgs(p, n, r)
 
@@ -1058,164 +1069,166 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
   if r.typ == etyBaseIndex:
     if r.address == nil:
       globalError(n.info, "cannot invoke with infix syntax")
-    r.res = ropef("$1[$2]", [r.address, r.res])
+    r.res = "$1[$2]" % [r.address, r.res]
     r.address = nil
     r.typ = etyNone
-  app(r.res, ".")
+  add(r.res, ".")
   var op: TCompRes
   gen(p, n.sons[0], op)
-  app(r.res, op.res)
-  
-  app(r.res, "(")
+  add(r.res, op.res)
+
+  add(r.res, "(")
   for i in countup(2, sonsLen(n) - 1):
-    if i > 2: app(r.res, ", ")
+    if i > 2: add(r.res, ", ")
     genArg(p, n.sons[i], r)
-  app(r.res, ")")
+  add(r.res, ")")
   r.kind = resExpr
 
 proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
   useMagic(p, "rawEcho")
-  app(r.res, "rawEcho(")
+  add(r.res, "rawEcho(")
   let n = n[1].skipConv
   internalAssert n.kind == nkBracket
   for i in countup(0, sonsLen(n) - 1):
     let it = n.sons[i]
-    if it.typ.isCompileTimeOnly: continue  
-    if i > 0: app(r.res, ", ")
+    if it.typ.isCompileTimeOnly: continue
+    if i > 0: add(r.res, ", ")
     genArg(p, it, r)
-  app(r.res, ")")
+  add(r.res, ")")
   r.kind = resExpr
 
-proc putToSeq(s: string, indirect: bool): PRope = 
-  result = toRope(s)
-  if indirect: result = ropef("[$1]", [result])
-  
-proc createVar(p: PProc, typ: PType, indirect: bool): PRope
-proc createRecordVarAux(p: PProc, rec: PNode, c: var int): PRope = 
+proc putToSeq(s: string, indirect: bool): Rope =
+  result = rope(s)
+  if indirect: result = "[$1]" % [result]
+
+proc createVar(p: PProc, typ: PType, indirect: bool): Rope
+proc createRecordVarAux(p: PProc, rec: PNode, c: var int): Rope =
   result = nil
   case rec.kind
-  of nkRecList: 
-    for i in countup(0, sonsLen(rec) - 1): 
-      app(result, createRecordVarAux(p, rec.sons[i], c))
-  of nkRecCase: 
-    app(result, createRecordVarAux(p, rec.sons[0], c))
-    for i in countup(1, sonsLen(rec) - 1): 
-      app(result, createRecordVarAux(p, lastSon(rec.sons[i]), c))
-  of nkSym: 
-    if c > 0: app(result, ", ")
-    app(result, mangleName(rec.sym))
-    app(result, ": ")
-    app(result, createVar(p, rec.sym.typ, false))
+  of nkRecList:
+    for i in countup(0, sonsLen(rec) - 1):
+      add(result, createRecordVarAux(p, rec.sons[i], c))
+  of nkRecCase:
+    add(result, createRecordVarAux(p, rec.sons[0], c))
+    for i in countup(1, sonsLen(rec) - 1):
+      add(result, createRecordVarAux(p, lastSon(rec.sons[i]), c))
+  of nkSym:
+    if c > 0: add(result, ", ")
+    add(result, mangleName(rec.sym))
+    add(result, ": ")
+    add(result, createVar(p, rec.sym.typ, false))
     inc(c)
   else: internalError(rec.info, "createRecordVarAux")
-  
-proc createVar(p: PProc, typ: PType, indirect: bool): PRope = 
+
+proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
   var t = skipTypes(typ, abstractInst)
   case t.kind
-  of tyInt..tyInt64, tyEnum, tyChar: 
+  of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar:
     result = putToSeq("0", indirect)
-  of tyFloat..tyFloat128: 
+  of tyFloat..tyFloat128:
     result = putToSeq("0.0", indirect)
-  of tyRange, tyGenericInst: 
+  of tyRange, tyGenericInst:
     result = createVar(p, lastSon(typ), indirect)
-  of tySet: 
-    result = toRope("{}")
-  of tyBool: 
+  of tySet:
+    result = putToSeq("{}", indirect)
+  of tyBool:
     result = putToSeq("false", indirect)
-  of tyArray, tyArrayConstr: 
+  of tyArray, tyArrayConstr:
     var length = int(lengthOrd(t))
     var e = elemType(t)
-    if length > 32: 
+    if length > 32:
       useMagic(p, "arrayConstr")
       # XXX: arrayConstr depends on nimCopy. This line shouldn't be necessary.
       useMagic(p, "nimCopy")
-      result = ropef("arrayConstr($1, $2, $3)", [toRope(length), 
-          createVar(p, e, false), genTypeInfo(p, e)])
-    else: 
-      result = toRope("[")
+      result = "arrayConstr($1, $2, $3)" % [rope(length),
+          createVar(p, e, false), genTypeInfo(p, e)]
+    else:
+      result = rope("[")
       var i = 0
-      while i < length: 
-        if i > 0: app(result, ", ")
-        app(result, createVar(p, e, false))
+      while i < length:
+        if i > 0: add(result, ", ")
+        add(result, createVar(p, e, false))
         inc(i)
-      app(result, "]")
-  of tyTuple: 
-    result = toRope("{")
+      add(result, "]")
+    if indirect: result = "[$1]" % [result]
+  of tyTuple:
+    result = rope("{")
     for i in 0.. <t.sonsLen:
-      if i > 0: app(result, ", ")
-      appf(result, "Field$1: $2" | "Field$# = $#", i.toRope, 
-           createVar(p, t.sons[i], false))
-    app(result, "}")
-  of tyObject: 
-    result = toRope("{")
+      if i > 0: add(result, ", ")
+      addf(result, "Field$1: $2" | "Field$# = $#", [i.rope,
+           createVar(p, t.sons[i], false)])
+    add(result, "}")
+    if indirect: result = "[$1]" % [result]
+  of tyObject:
+    result = rope("{")
     var c = 0
     if tfFinal notin t.flags or t.sons[0] != nil:
       inc(c)
-      appf(result, "m_type: $1" | "m_type = $#", [genTypeInfo(p, t)])
-    while t != nil: 
-      app(result, createRecordVarAux(p, t.n, c))
+      addf(result, "m_type: $1" | "m_type = $#", [genTypeInfo(p, t)])
+    while t != nil:
+      add(result, createRecordVarAux(p, t.n, c))
       t = t.sons[0]
-    app(result, "}")
-  of tyVar, tyPtr, tyRef: 
+    add(result, "}")
+    if indirect: result = "[$1]" % [result]
+  of tyVar, tyPtr, tyRef:
     if mapType(t) == etyBaseIndex:
       result = putToSeq("[null, 0]" | "{nil, 0}", indirect)
     else:
       result = putToSeq("null" | "nil", indirect)
-  of tySequence, tyString, tyCString, tyPointer, tyProc: 
+  of tySequence, tyString, tyCString, tyPointer, tyProc:
     result = putToSeq("null" | "nil", indirect)
   else:
     internalError("createVar: " & $t.kind)
     result = nil
 
-proc isIndirect(v: PSym): bool =
-  result = {sfAddrTaken, sfGlobal} * v.flags != {} and
-    (mapType(v.typ) != etyObject) and
-    v.kind notin {skProc, skConverter, skMethod, skIterator, skClosureIterator}
-
-proc genVarInit(p: PProc, v: PSym, n: PNode) = 
-  var 
+proc genVarInit(p: PProc, v: PSym, n: PNode) =
+  var
     a: TCompRes
-    s: PRope
-  if n.kind == nkEmpty: 
-    appf(p.body, "var $1 = $2;$n" | "local $1 = $2;$n", 
+    s: Rope
+  if n.kind == nkEmpty:
+    addf(p.body, "var $1 = $2;$n" | "local $1 = $2;$n",
          [mangleName(v), createVar(p, v.typ, isIndirect(v))])
-  else: 
+  else:
     discard mangleName(v)
     gen(p, n, a)
     case mapType(v.typ)
-    of etyObject: 
-      if needsNoCopy(n): 
+    of etyObject:
+      if needsNoCopy(n):
         s = a.res
-      else: 
+      else:
         useMagic(p, "nimCopy")
-        s = ropef("nimCopy($1, $2)", [a.res, genTypeInfo(p, n.typ)])
-    of etyBaseIndex: 
+        s = "nimCopy($1, $2)" % [a.res, genTypeInfo(p, n.typ)]
+    of etyBaseIndex:
       if (a.typ != etyBaseIndex): internalError(n.info, "genVarInit")
-      if {sfAddrTaken, sfGlobal} * v.flags != {}: 
-        appf(p.body, "var $1 = [$2, $3];$n" | "local $1 = {$2, $3};$n", 
+      if {sfAddrTaken, sfGlobal} * v.flags != {}:
+        addf(p.body, "var $1 = [$2, $3];$n" | "local $1 = {$2, $3};$n",
             [v.loc.r, a.address, a.res])
       else:
-        appf(p.body, "var $1 = $2; var $1_Idx = $3;$n" | 
+        addf(p.body, "var $1 = $2; var $1_Idx = $3;$n" |
                      "local $1 = $2; local $1_Idx = $3;$n", [
              v.loc.r, a.address, a.res])
       return
     else:
       s = a.res
-    if isIndirect(v): 
-      appf(p.body, "var $1 = [$2];$n" | "local $1 = {$2};$n", [v.loc.r, s])
-    else: 
-      appf(p.body, "var $1 = $2;$n" | "local $1 = $2;$n", [v.loc.r, s])
-  
-proc genVarStmt(p: PProc, n: PNode) = 
-  for i in countup(0, sonsLen(n) - 1): 
+    if isIndirect(v):
+      addf(p.body, "var $1 = /**/[$2];$n" | "local $1 = {$2};$n", [v.loc.r, s])
+    else:
+      addf(p.body, "var $1 = $2;$n" | "local $1 = $2;$n", [v.loc.r, s])
+
+proc genVarStmt(p: PProc, n: PNode) =
+  for i in countup(0, sonsLen(n) - 1):
     var a = n.sons[i]
-    if a.kind == nkCommentStmt: continue 
-    assert(a.kind == nkIdentDefs)
-    assert(a.sons[0].kind == nkSym)
-    var v = a.sons[0].sym
-    if lfNoDecl in v.loc.flags: continue 
-    genLineDir(p, a)
-    genVarInit(p, v, a.sons[2])
+    if a.kind != nkCommentStmt:
+      if a.kind == nkVarTuple:
+        let unpacked = lowerTupleUnpacking(a, p.prc)
+        genStmt(p, unpacked)
+      else:
+        assert(a.kind == nkIdentDefs)
+        assert(a.sons[0].kind == nkSym)
+        var v = a.sons[0].sym
+        if lfNoDecl notin v.loc.flags:
+          genLineDir(p, a)
+          genVarInit(p, v, a.sons[2])
 
 proc genConstant(p: PProc, c: PSym) =
   if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id):
@@ -1223,21 +1236,21 @@ proc genConstant(p: PProc, c: PSym) =
     p.body = nil
     #genLineDir(p, c.ast)
     genVarInit(p, c, c.ast)
-    app(p.g.code, p.body)
+    add(p.g.code, p.body)
     p.body = oldBody
 
 proc genNew(p: PProc, n: PNode) =
   var a: TCompRes
   gen(p, n.sons[1], a)
   var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
-  appf(p.body, "$1 = $2;$n", [a.res, createVar(p, t, true)])
+  addf(p.body, "$1 = $2;$n", [a.res, createVar(p, t, false)])
 
 proc genNewSeq(p: PProc, n: PNode) =
   var x, y: TCompRes
   gen(p, n.sons[1], x)
   gen(p, n.sons[2], y)
   let t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
-  appf(p.body, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}", [
+  addf(p.body, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}", [
     x.rdLoc, y.rdLoc, createVar(p, t, false)])
 
 proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
@@ -1245,29 +1258,29 @@ proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
   of tyEnum, tyInt..tyInt64, tyChar: gen(p, n.sons[1], r)
   of tyBool: unaryExpr(p, n, r, "", "($1 ? 1:0)" | "toBool($#)")
   else: internalError(n.info, "genOrd")
-  
+
 proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
 
   gen(p, n.sons[1], a)
   r.kind = resExpr
   if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyChar:
-    r.res.app(ropef("[$1].concat(", [a.res]))
+    r.res.add("[$1].concat(" % [a.res])
   else:
-    r.res.app(ropef("($1.slice(0,-1)).concat(", [a.res]))
+    r.res.add("($1.slice(0,-1)).concat(" % [a.res])
 
   for i in countup(2, sonsLen(n) - 2):
     gen(p, n.sons[i], a)
     if skipTypes(n.sons[i].typ, abstractVarRange).kind == tyChar:
-      r.res.app(ropef("[$1],", [a.res]))
+      r.res.add("[$1]," % [a.res])
     else:
-      r.res.app(ropef("$1.slice(0,-1),", [a.res]))
+      r.res.add("$1.slice(0,-1)," % [a.res])
 
   gen(p, n.sons[sonsLen(n) - 1], a)
   if skipTypes(n.sons[sonsLen(n) - 1].typ, abstractVarRange).kind == tyChar:
-    r.res.app(ropef("[$1, 0])", [a.res]))
+    r.res.add("[$1, 0])" % [a.res])
   else:
-    r.res.app(ropef("$1)", [a.res]))
+    r.res.add("$1)" % [a.res])
 
 proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
   var t = skipTypes(n.sons[1].typ, abstractVarRange)
@@ -1278,8 +1291,7 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
     gen(p, n.sons[1], r)
     useMagic(p, "cstrToNimstr")
     r.kind = resExpr
-    r.res = ropef("cstrToNimstr($1.node.sons[$2].name)", 
-                 [genTypeInfo(p, t), r.res])
+    r.res = "cstrToNimstr($1.node.sons[$2].name)" % [genTypeInfo(p, t), r.res]
   else:
     # XXX:
     internalError(n.info, "genRepr: Not implemented")
@@ -1289,23 +1301,23 @@ proc genOf(p: PProc, n: PNode, r: var TCompRes) =
   let t = skipTypes(n.sons[2].typ, abstractVarRange+{tyRef, tyPtr, tyTypeDesc})
   gen(p, n.sons[1], x)
   if tfFinal in t.flags:
-    r.res = ropef("($1.m_type == $2)", [x.res, genTypeInfo(p, t)])
+    r.res = "($1.m_type == $2)" % [x.res, genTypeInfo(p, t)]
   else:
     useMagic(p, "isObj")
-    r.res = ropef("isObj($1.m_type, $2)", [x.res, genTypeInfo(p, t)])
+    r.res = "isObj($1.m_type, $2)" % [x.res, genTypeInfo(p, t)]
   r.kind = resExpr
 
 proc genReset(p: PProc, n: PNode) =
   var x: TCompRes
   useMagic(p, "genericReset")
   gen(p, n.sons[1], x)
-  appf(p.body, "$1 = genericReset($1, $2);$n", [x.res, 
+  addf(p.body, "$1 = genericReset($1, $2);$n", [x.res,
                 genTypeInfo(p, n.sons[1].typ)])
 
 proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
-  var 
+  var
     a: TCompRes
-    line, filen: PRope
+    line, filen: Rope
   var op = n.sons[0].sym.magic
   case op
   of mOr: genOr(p, n.sons[1], n.sons[2], r)
@@ -1317,22 +1329,17 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
     # XXX: range checking?
     if not (optOverflowCheck in p.options): unaryExpr(p, n, r, "", "$1 - 1")
     else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)")
-  of mPred:
-    # XXX: range checking?
-    if not (optOverflowCheck in p.options): binaryExpr(p, n, r, "", "$1 - $2")
-    else: binaryExpr(p, n, r, "subInt", "subInt($1, $2)")
-  of mSucc:
-    # XXX: range checking?
-    if not (optOverflowCheck in p.options): binaryExpr(p, n, r, "", "$1 - $2")
-    else: binaryExpr(p, n, r, "addInt", "addInt($1, $2)")
-  of mAppendStrCh: binaryExpr(p, n, r, "addChar", "addChar($1, $2)")
+  of mAppendStrCh: binaryExpr(p, n, r, "addChar",
+        "if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }")
   of mAppendStrStr:
     if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
-        binaryExpr(p, n, r, "", "$1 += $2")
+        binaryExpr(p, n, r, "", "if ($1 != null) { $1 += $2; } else { $1 = $2; }")
     else:
-      binaryExpr(p, n, r, "", "$1 = ($1.slice(0, -1)).concat($2)")
+      binaryExpr(p, n, r, "",
+        "if ($1 != null) { $1 = ($1.slice(0, -1)).concat($2); } else { $1 = $2;}")
     # XXX: make a copy of $2, because of Javascript's sucking semantics
-  of mAppendSeqElem: binaryExpr(p, n, r, "", "$1.push($2)")
+  of mAppendSeqElem: binaryExpr(p, n, r, "",
+        "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }")
   of mConStrStr: genConStrStr(p, n, r)
   of mEqStr: binaryExpr(p, n, r, "eqStrings", "eqStrings($1, $2)")
   of mLeStr: binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) <= 0)")
@@ -1340,17 +1347,20 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
   of mIsNil: unaryExpr(p, n, r, "", "$1 == null")
   of mEnumToStr: genRepr(p, n, r)
   of mNew, mNewFinalize: genNew(p, n)
-  of mSizeOf: r.res = toRope(getSize(n.sons[1].typ))
+  of mSizeOf: r.res = rope(getSize(n.sons[1].typ))
   of mChr, mArrToSeq: gen(p, n.sons[1], r)      # nothing to do
   of mOrd: genOrd(p, n, r)
-  of mLengthStr: unaryExpr(p, n, r, "", "($1.length-1)")
+  of mLengthStr: unaryExpr(p, n, r, "", "($1 != null ? $1.length-1 : 0)")
+  of mXLenStr: unaryExpr(p, n, r, "", "$1.length-1")
   of mLengthSeq, mLengthOpenArray, mLengthArray:
+    unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
+  of mXLenSeq:
     unaryExpr(p, n, r, "", "$1.length")
   of mHigh:
     if skipTypes(n.sons[1].typ, abstractVar).kind == tyString:
-      unaryExpr(p, n, r, "", "($1.length-2)")
+      unaryExpr(p, n, r, "", "($1 != null ? ($1.length-2) : -1)")
     else:
-      unaryExpr(p, n, r, "", "($1.length-1)")
+      unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)")
   of mInc:
     if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 += $2")
     else: binaryExpr(p, n, r, "addInt", "$1 = addInt($1, $2)")
@@ -1369,157 +1379,164 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
   of mIncl: binaryExpr(p, n, r, "", "$1[$2] = true")
   of mExcl: binaryExpr(p, n, r, "", "delete $1[$2]")
   of mInSet: binaryExpr(p, n, r, "", "($1[$2] != undefined)")
-  of mNLen..mNError:
-    localError(n.info, errCannotGenerateCodeForX, n.sons[0].sym.name.s)
   of mNewSeq: genNewSeq(p, n)
   of mOf: genOf(p, n, r)
   of mReset: genReset(p, n)
   of mEcho: genEcho(p, n, r)
-  of mSlurp, mStaticExec:
+  of mNLen..mNError, mSlurp, mStaticExec:
     localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s)
   of mCopyStr: binaryExpr(p, n, r, "", "($1.slice($2))")
   of mCopyStrLast: ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))")
   of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
-  of mNewStringOfCap: unaryExpr(p, n, r, "mnewString", "mnewString(0)")    
+  of mNewStringOfCap: unaryExpr(p, n, r, "mnewString", "mnewString(0)")
   else:
     genCall(p, n, r)
     #else internalError(e.info, 'genMagic: ' + magicToStr[op]);
-  
-proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) = 
+
+proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
   var
     a, b: TCompRes
   useMagic(p, "SetConstr")
-  r.res = toRope("SetConstr(")
+  r.res = rope("SetConstr(")
   r.kind = resExpr
-  for i in countup(0, sonsLen(n) - 1): 
-    if i > 0: app(r.res, ", ")
+  for i in countup(0, sonsLen(n) - 1):
+    if i > 0: add(r.res, ", ")
     var it = n.sons[i]
-    if it.kind == nkRange: 
+    if it.kind == nkRange:
       gen(p, it.sons[0], a)
       gen(p, it.sons[1], b)
-      appf(r.res, "[$1, $2]", [a.res, b.res])
-    else: 
+      addf(r.res, "[$1, $2]", [a.res, b.res])
+    else:
       gen(p, it, a)
-      app(r.res, a.res)
-  app(r.res, ")")
+      add(r.res, a.res)
+  add(r.res, ")")
 
-proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) = 
+proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
-  r.res = toRope("[")
+  r.res = rope("[")
   r.kind = resExpr
-  for i in countup(0, sonsLen(n) - 1): 
-    if i > 0: app(r.res, ", ")
+  for i in countup(0, sonsLen(n) - 1):
+    if i > 0: add(r.res, ", ")
     gen(p, n.sons[i], a)
-    app(r.res, a.res)
-  app(r.res, "]")
+    add(r.res, a.res)
+  add(r.res, "]")
 
 proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
-  r.res = toRope("{")
+  r.res = rope("{")
   r.kind = resExpr
   for i in countup(0, sonsLen(n) - 1):
-    if i > 0: app(r.res, ", ")
+    if i > 0: add(r.res, ", ")
     var it = n.sons[i]
     if it.kind == nkExprColonExpr: it = it.sons[1]
     gen(p, it, a)
-    appf(r.res, "Field$#: $#" | "Field$# = $#", [i.toRope, a.res])
-  r.res.app("}")
+    addf(r.res, "Field$#: $#" | "Field$# = $#", [i.rope, a.res])
+  r.res.add("}")
 
 proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
   # XXX inheritance?
   var a: TCompRes
-  r.res = toRope("{")
+  r.res = rope("{")
   r.kind = resExpr
   for i in countup(1, sonsLen(n) - 1):
-    if i > 1: app(r.res, ", ")
+    if i > 1: add(r.res, ", ")
     var it = n.sons[i]
     internalAssert it.kind == nkExprColonExpr
     gen(p, it.sons[1], a)
     var f = it.sons[0].sym
     if f.loc.r == nil: f.loc.r = mangleName(f)
-    appf(r.res, "$#: $#" | "$# = $#" , [f.loc.r, a.res])
-  r.res.app("}")
+    addf(r.res, "$#: $#" | "$# = $#" , [f.loc.r, a.res])
+  r.res.add("}")
 
-proc genConv(p: PProc, n: PNode, r: var TCompRes) = 
+proc genConv(p: PProc, n: PNode, r: var TCompRes) =
   var dest = skipTypes(n.typ, abstractVarRange)
   var src = skipTypes(n.sons[1].typ, abstractVarRange)
   gen(p, n.sons[1], r)
-  if (dest.kind != src.kind) and (src.kind == tyBool): 
-    r.res = ropef("(($1)? 1:0)" | "toBool($#)", [r.res])
+  if dest.kind == src.kind:
+    # no-op conversion
+    return
+  case dest.kind:
+  of tyBool:
+    r.res = ("(($1)? 1:0)" | "toBool($#)") % [r.res]
     r.kind = resExpr
-  
-proc upConv(p: PProc, n: PNode, r: var TCompRes) = 
+  of tyInt:
+    r.res = "($1|0)" % [r.res]
+  else:
+    # TODO: What types must we handle here?
+    discard
+
+proc upConv(p: PProc, n: PNode, r: var TCompRes) =
   gen(p, n.sons[0], r)        # XXX
-  
-proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) = 
+
+proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) =
   var a, b: TCompRes
   gen(p, n.sons[0], r)
-  if optRangeCheck in p.options: 
+  if optRangeCheck in p.options:
     gen(p, n.sons[1], a)
     gen(p, n.sons[2], b)
     useMagic(p, "chckRange")
-    r.res = ropef("chckRange($1, $2, $3)", [r.res, a.res, b.res])
+    r.res = "chckRange($1, $2, $3)" % [r.res, a.res, b.res]
     r.kind = resExpr
 
-proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) = 
+proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) =
   # we do an optimization here as this is likely to slow down
   # much of the code otherwise:
-  if n.sons[0].kind == nkCStringToString: 
+  if n.sons[0].kind == nkCStringToString:
     gen(p, n.sons[0].sons[0], r)
   else:
     gen(p, n.sons[0], r)
     if r.res == nil: internalError(n.info, "convStrToCStr")
     useMagic(p, "toJSStr")
-    r.res = ropef("toJSStr($1)", [r.res])
+    r.res = "toJSStr($1)" % [r.res]
     r.kind = resExpr
 
-proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) = 
+proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) =
   # we do an optimization here as this is likely to slow down
   # much of the code otherwise:
-  if n.sons[0].kind == nkStringToCString: 
+  if n.sons[0].kind == nkStringToCString:
     gen(p, n.sons[0].sons[0], r)
-  else: 
+  else:
     gen(p, n.sons[0], r)
     if r.res == nil: internalError(n.info, "convCStrToStr")
     useMagic(p, "cstrToNimstr")
-    r.res = ropef("cstrToNimstr($1)", [r.res])
+    r.res = "cstrToNimstr($1)" % [r.res]
     r.kind = resExpr
 
-proc genReturnStmt(p: PProc, n: PNode) = 
+proc genReturnStmt(p: PProc, n: PNode) =
   if p.procDef == nil: internalError(n.info, "genReturnStmt")
   p.beforeRetNeeded = true
-  if (n.sons[0].kind != nkEmpty): 
+  if (n.sons[0].kind != nkEmpty):
     genStmt(p, n.sons[0])
   else:
     genLineDir(p, n)
-  appf(p.body, "break BeforeRet;$n" | "goto ::BeforeRet::;$n")
+  addf(p.body, "break BeforeRet;$n" | "goto ::BeforeRet::;$n", [])
 
-proc genProcBody(p: PProc, prc: PSym): PRope =
+proc genProcBody(p: PProc, prc: PSym): Rope =
   if optStackTrace in prc.options:
-    result = ropef(("var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" |
-                  "local F={procname=$#,prev=framePtr,filename=$#,line=0};$n") &
-                   "framePtr = F;$n", [
-                   makeJSString(prc.owner.name.s & '.' & prc.name.s),
-                   makeJSString(toFilename(prc.info))])
+    result = (("var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" |
+               "local F={procname=$#,prev=framePtr,filename=$#,line=0};$n") &
+              "framePtr = F;$n") % [
+              makeJSString(prc.owner.name.s & '.' & prc.name.s),
+              makeJSString(toFilename(prc.info))]
   else:
     result = nil
   if p.beforeRetNeeded:
-    appf(result, "BeforeRet: do {$n$1} while (false); $n" | 
+    addf(result, "BeforeRet: do {$n$1} while (false); $n" |
                  "$#;::BeforeRet::$n", [p.body])
   else:
-    app(result, p.body)
-  if prc.typ.callConv == ccSysCall and p.target == targetJS: 
-    result = ropef("try {$n$1} catch (e) {$n" &
-        " alert(\"Unhandled exception:\\n\" + e.message + \"\\n\"$n}", [result])
-  if optStackTrace in prc.options: 
-    app(result, "framePtr = framePtr.prev;" & tnl)
-
-proc genProc(oldProc: PProc, prc: PSym): PRope = 
+    add(result, p.body)
+  if prc.typ.callConv == ccSysCall and p.target == targetJS:
+    result = ("try {$n$1} catch (e) {$n" &
+      " alert(\"Unhandled exception:\\n\" + e.message + \"\\n\"$n}") % [result]
+  if optStackTrace in prc.options:
+    add(result, "framePtr = framePtr.prev;" & tnl)
+
+proc genProc(oldProc: PProc, prc: PSym): Rope =
   var
     resultSym: PSym
-    name, returnStmt, resultAsgn, header: PRope
+    name, returnStmt, resultAsgn, header: Rope
     a: TCompRes
-  #if gVerbosity >= 3: 
+  #if gVerbosity >= 3:
   #  echo "BEGIN generating code for: " & prc.name.s
   var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options)
   p.target = oldProc.target
@@ -1528,25 +1545,25 @@ proc genProc(oldProc: PProc, prc: PSym): PRope =
   resultAsgn = nil
   name = mangleName(prc)
   header = generateHeader(p, prc.typ)
-  if prc.typ.sons[0] != nil and sfPure notin prc.flags: 
+  if prc.typ.sons[0] != nil and sfPure notin prc.flags:
     resultSym = prc.ast.sons[resultPos].sym
-    resultAsgn = ropef("var $# = $#;$n" | "local $# = $#;$n", [
-        mangleName(resultSym), 
-        createVar(p, resultSym.typ, isIndirect(resultSym))])
+    resultAsgn = ("var $# = $#;$n" | "local $# = $#;$n") % [
+        mangleName(resultSym),
+        createVar(p, resultSym.typ, isIndirect(resultSym))]
     gen(p, prc.ast.sons[resultPos], a)
-    returnStmt = ropef("return $#;$n", [a.res])
+    returnStmt = "return $#;$n" % [a.res]
   genStmt(p, prc.getBody)
-  result = ropef("function $#($#) {$n$#$#$#$#}$n" |
-                 "function $#($#) $n$#$#$#$#$nend$n",
-                [name, header, p.locals, resultAsgn, 
-                 genProcBody(p, prc), returnStmt])
+  result = ("function $#($#) {$n$#$#$#$#}$n" |
+            "function $#($#) $n$#$#$#$#$nend$n") %
+            [name, header, p.locals, resultAsgn,
+             genProcBody(p, prc), returnStmt]
   #if gVerbosity >= 3:
   #  echo "END   generated code for: " & prc.name.s
 
 proc genStmt(p: PProc, n: PNode) =
   var r: TCompRes
   gen(p, n, r)
-  if r.res != nil: appf(p.body, "$#;$n", r.res)
+  if r.res != nil: addf(p.body, "$#;$n", [r.res])
 
 proc gen(p: PProc, n: PNode, r: var TCompRes) =
   r.typ = etyNone
@@ -1557,42 +1574,42 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
   of nkSym:
     genSym(p, n, r)
   of nkCharLit..nkInt64Lit:
-    r.res = toRope(n.intVal)
+    r.res = rope(n.intVal)
     r.kind = resExpr
   of nkNilLit:
     if isEmptyType(n.typ):
       discard
     elif mapType(n.typ) == etyBaseIndex:
       r.typ = etyBaseIndex
-      r.address = toRope"null" | toRope"nil"
-      r.res = toRope"0"
+      r.address = rope"null" | rope"nil"
+      r.res = rope"0"
       r.kind = resExpr
     else:
-      r.res = toRope"null" | toRope"nil"
+      r.res = rope"null" | rope"nil"
       r.kind = resExpr
   of nkStrLit..nkTripleStrLit:
-    if skipTypes(n.typ, abstractVarRange).kind == tyString: 
+    if skipTypes(n.typ, abstractVarRange).kind == tyString:
       useMagic(p, "cstrToNimstr")
-      r.res = ropef("cstrToNimstr($1)", [makeJSString(n.strVal)])
-    else: 
+      r.res = "cstrToNimstr($1)" % [makeJSString(n.strVal)]
+    else:
       r.res = makeJSString(n.strVal)
     r.kind = resExpr
-  of nkFloatLit..nkFloat64Lit: 
+  of nkFloatLit..nkFloat64Lit:
     let f = n.floatVal
-    if f != f: r.res = toRope"NaN"
-    elif f == 0.0: r.res = toRope"0.0"
-    elif f == 0.5 * f: 
-      if f > 0.0: r.res = toRope"Infinity"
-      else: r.res = toRope"-Infinity"
-    else: r.res = toRope(f.toStrMaxPrecision)
+    if f != f: r.res = rope"NaN"
+    elif f == 0.0: r.res = rope"0.0"
+    elif f == 0.5 * f:
+      if f > 0.0: r.res = rope"Infinity"
+      else: r.res = rope"-Infinity"
+    else: r.res = rope(f.toStrMaxPrecision)
     r.kind = resExpr
   of nkCallKinds:
-    if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone): 
+    if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone):
       genMagic(p, n, r)
     elif n.sons[0].kind == nkSym and sfInfixCall in n.sons[0].sym.flags and
         n.len >= 2:
       genInfixCall(p, n, r)
-    else: 
+    else:
       genCall(p, n, r)
   of nkCurly: genSetConstr(p, n, r)
   of nkBracket: genArrayConstr(p, n, r)
@@ -1613,13 +1630,13 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
   of nkStringToCString: convStrToCStr(p, n, r)
   of nkCStringToString: convCStrToStr(p, n, r)
   of nkEmpty: discard
-  of nkLambdaKinds: 
+  of nkLambdaKinds:
     let s = n.sons[namePos].sym
     discard mangleName(s)
     r.res = s.loc.r
     if lfNoDecl in s.loc.flags or s.magic != mNone: discard
     elif not p.g.generatedSyms.containsOrIncl(s.id):
-      app(p.locals, genProc(p, s))
+      add(p.locals, genProc(p, s))
   of nkType: r.res = genTypeInfo(p, n.typ)
   of nkStmtList, nkStmtListExpr:
     # this shows the distinction is nice for backends and should be kept
@@ -1634,9 +1651,9 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
   of nkWhileStmt: genWhileStmt(p, n)
   of nkVarSection, nkLetSection: genVarStmt(p, n)
   of nkConstSection: discard
-  of nkForStmt, nkParForStmt: 
+  of nkForStmt, nkParForStmt:
     internalError(n.info, "for statement not eliminated")
-  of nkCaseStmt: 
+  of nkCaseStmt:
     if p.target == targetJS: genCaseJS(p, n, r)
     else: genCaseLua(p, n, r)
   of nkReturnStmt: genReturnStmt(p, n)
@@ -1650,8 +1667,8 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
   of nkAsmStmt: genAsmStmt(p, n)
   of nkTryStmt: genTry(p, n, r)
   of nkRaiseStmt: genRaiseStmt(p, n)
-  of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt, 
-     nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, 
+  of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt,
+     nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
      nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: discard
   of nkProcDef, nkMethodDef, nkConverterDef:
     var s = n.sons[namePos].sym
@@ -1662,58 +1679,58 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
     internalError(n.info, "first class iterators not implemented")
   of nkPragmaBlock: gen(p, n.lastSon, r)
   else: internalError(n.info, "gen: unknown node type: " & $n.kind)
-  
+
 var globals: PGlobals
 
-proc newModule(module: PSym): BModule = 
+proc newModule(module: PSym): BModule =
   new(result)
   result.module = module
   if globals == nil: globals = newGlobals()
-  
-proc genHeader(): PRope =
-  result = ropef("/* Generated by the Nim Compiler v$1 */$n" &
-                 "/*   (c) 2014 Andreas Rumpf */$n$n" & 
-                 "var framePtr = null;$n" & 
-                 "var excHandler = null;$n" &
-                 "var lastJSError = null;$n", 
-                 [toRope(VersionAsString)])
-
-proc genModule(p: PProc, n: PNode) = 
+
+proc genHeader(): Rope =
+  result = ("/* Generated by the Nim Compiler v$1 */$n" &
+            "/*   (c) 2015 Andreas Rumpf */$n$n" &
+            "var framePtr = null;$n" &
+            "var excHandler = null;$n" &
+            "var lastJSError = null;$n") %
+           [rope(VersionAsString)]
+
+proc genModule(p: PProc, n: PNode) =
   if optStackTrace in p.options:
-    appf(p.body, "var F = {procname:$1,prev:framePtr,filename:$2,line:0};$n" &
+    addf(p.body, "var F = {procname:$1,prev:framePtr,filename:$2,line:0};$n" &
                  "framePtr = F;$n", [
-        makeJSString("module " & p.module.module.name.s), 
+        makeJSString("module " & p.module.module.name.s),
         makeJSString(toFilename(p.module.module.info))])
   genStmt(p, n)
   if optStackTrace in p.options:
-    appf(p.body, "framePtr = framePtr.prev;$n")
+    addf(p.body, "framePtr = framePtr.prev;$n", [])
 
-proc myProcess(b: PPassContext, n: PNode): PNode = 
+proc myProcess(b: PPassContext, n: PNode): PNode =
   if passes.skipCodegen(n): return n
   result = n
   var m = BModule(b)
   if m.module == nil: internalError(n.info, "myProcess")
   var p = newProc(globals, m, nil, m.module.options)
   genModule(p, n)
-  app(p.g.code, p.locals)
-  app(p.g.code, p.body)
+  add(p.g.code, p.locals)
+  add(p.g.code, p.body)
 
-proc wholeCode*(m: BModule): PRope =
+proc wholeCode*(m: BModule): Rope =
   for prc in globals.forwarded:
     if not globals.generatedSyms.containsOrIncl(prc.id):
       var p = newProc(globals, m, nil, m.module.options)
-      app(p.g.code, genProc(p, prc))
-  
+      add(p.g.code, genProc(p, prc))
+
   var disp = generateMethodDispatchers()
-  for i in 0..sonsLen(disp)-1: 
+  for i in 0..sonsLen(disp)-1:
     let prc = disp.sons[i].sym
     if not globals.generatedSyms.containsOrIncl(prc.id):
       var p = newProc(globals, m, nil, m.module.options)
-      app(p.g.code, genProc(p, prc))
+      add(p.g.code, genProc(p, prc))
+
+  result = globals.typeInfo & globals.code
 
-  result = con(globals.typeInfo, globals.code)
-  
-proc myClose(b: PPassContext, n: PNode): PNode = 
+proc myClose(b: PPassContext, n: PNode): PNode =
   if passes.skipCodegen(n): return n
   result = myProcess(b, n)
   var m = BModule(b)
@@ -1725,13 +1742,13 @@ proc myClose(b: PPassContext, n: PNode): PNode =
         else: getCurrentDir() / options.outFile
       else:
        changeFileExt(completeCFilePath(m.module.filename), "js")
-    discard writeRopeIfNotEqual(con(genHeader(), code), outfile)
+    discard writeRopeIfNotEqual(genHeader() & code, outfile)
 
-proc myOpenCached(s: PSym, rd: PRodReader): PPassContext = 
+proc myOpenCached(s: PSym, rd: PRodReader): PPassContext =
   internalError("symbol files are not possible with the JS code generator")
   result = nil
 
-proc myOpen(s: PSym): PPassContext = 
+proc myOpen(s: PSym): PPassContext =
   result = newModule(s)
 
 const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim
index 8b032c3ce..851938327 100644
--- a/compiler/jstypes.nim
+++ b/compiler/jstypes.nim
@@ -9,138 +9,138 @@
 
 ## Type info generation for the JS backend.
 
-proc genTypeInfo(p: PProc, typ: PType): PRope
-proc genObjectFields(p: PProc, typ: PType, n: PNode): PRope = 
-  var 
-    s, u: PRope
+proc genTypeInfo(p: PProc, typ: PType): Rope
+proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
+  var
+    s, u: Rope
     length: int
     field: PSym
     b: PNode
   result = nil
   case n.kind
-  of nkRecList: 
+  of nkRecList:
     length = sonsLen(n)
-    if length == 1: 
+    if length == 1:
       result = genObjectFields(p, typ, n.sons[0])
-    else: 
+    else:
       s = nil
-      for i in countup(0, length - 1): 
-        if i > 0: app(s, ", " & tnl)
-        app(s, genObjectFields(p, typ, n.sons[i]))
-      result = ropef("{kind: 2, len: $1, offset: 0, " &
-          "typ: null, name: null, sons: [$2]}", [toRope(length), s])
-  of nkSym: 
+      for i in countup(0, length - 1):
+        if i > 0: add(s, ", " & tnl)
+        add(s, genObjectFields(p, typ, n.sons[i]))
+      result = ("{kind: 2, len: $1, offset: 0, " &
+          "typ: null, name: null, sons: [$2]}") % [rope(length), s]
+  of nkSym:
     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, makeJSString(field.name.s)])
-  of nkRecCase: 
+    result = ("{kind: 1, offset: \"$1\", len: 0, " &
+        "typ: $2, name: $3, sons: null}") %
+                   [mangleName(field), s, makeJSString(field.name.s)]
+  of nkRecCase:
     length = sonsLen(n)
     if (n.sons[0].kind != nkSym): internalError(n.info, "genObjectFields")
     field = n.sons[0].sym
     s = genTypeInfo(p, field.typ)
-    for i in countup(1, length - 1): 
+    for i in countup(1, length - 1):
       b = n.sons[i]           # branch
       u = nil
       case b.kind
-      of nkOfBranch: 
-        if sonsLen(b) < 2: 
+      of nkOfBranch:
+        if sonsLen(b) < 2:
           internalError(b.info, "genObjectFields; nkOfBranch broken")
-        for j in countup(0, sonsLen(b) - 2): 
-          if u != nil: app(u, ", ")
-          if b.sons[j].kind == nkRange: 
-            appf(u, "[$1, $2]", [toRope(getOrdValue(b.sons[j].sons[0])), 
-                                 toRope(getOrdValue(b.sons[j].sons[1]))])
-          else: 
-            app(u, toRope(getOrdValue(b.sons[j])))
-      of nkElse: 
-        u = toRope(lengthOrd(field.typ))
+        for j in countup(0, sonsLen(b) - 2):
+          if u != nil: add(u, ", ")
+          if b.sons[j].kind == nkRange:
+            addf(u, "[$1, $2]", [rope(getOrdValue(b.sons[j].sons[0])),
+                                 rope(getOrdValue(b.sons[j].sons[1]))])
+          else:
+            add(u, rope(getOrdValue(b.sons[j])))
+      of nkElse:
+        u = rope(lengthOrd(field.typ))
       else: internalError(n.info, "genObjectFields(nkRecCase)")
-      if result != nil: app(result, ", " & tnl)
-      appf(result, "[SetConstr($1), $2]", 
+      if result != nil: add(result, ", " & tnl)
+      addf(result, "[SetConstr($1), $2]",
            [u, genObjectFields(p, typ, lastSon(b))])
-    result = ropef("{kind: 3, offset: \"$1\", len: $3, " &
-        "typ: $2, name: $4, sons: [$5]}", [mangleName(field), s, 
-        toRope(lengthOrd(field.typ)), makeJSString(field.name.s), result])
+    result = ("{kind: 3, offset: \"$1\", len: $3, " &
+        "typ: $2, name: $4, sons: [$5]}") % [mangleName(field), s,
+        rope(lengthOrd(field.typ)), makeJSString(field.name.s), result]
   else: internalError(n.info, "genObjectFields")
-  
-proc genObjectInfo(p: PProc, typ: PType, name: PRope) = 
-  var s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " &
-                "finalizer: null};$n", [name, toRope(ord(typ.kind))])
+
+proc genObjectInfo(p: PProc, typ: PType, name: Rope) =
+  var s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
+           "finalizer: null};$n") % [name, rope(ord(typ.kind))]
   prepend(p.g.typeInfo, s)
-  appf(p.g.typeInfo, "var NNI$1 = $2;$n", 
-       [toRope(typ.id), genObjectFields(p, typ, typ.n)])
-  appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)])
-  if (typ.kind == tyObject) and (typ.sons[0] != nil): 
-    appf(p.g.typeInfo, "$1.base = $2;$n", 
+  addf(p.g.typeInfo, "var NNI$1 = $2;$n",
+       [rope(typ.id), genObjectFields(p, typ, typ.n)])
+  addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
+  if (typ.kind == tyObject) and (typ.sons[0] != nil):
+    addf(p.g.typeInfo, "$1.base = $2;$n",
          [name, genTypeInfo(p, typ.sons[0])])
 
-proc genTupleFields(p: PProc, typ: PType): PRope =
-  var s: PRope = nil
+proc genTupleFields(p: PProc, typ: PType): Rope =
+  var s: Rope = nil
   for i in 0 .. <typ.len:
-    if i > 0: app(s, ", " & tnl)
-    s.appf("{kind: 1, offset: \"Field$1\", len: 0, " &
+    if i > 0: add(s, ", " & tnl)
+    s.addf("{kind: 1, offset: \"Field$1\", len: 0, " &
            "typ: $2, name: \"Field$1\", sons: null}",
-           [i.toRope, genTypeInfo(p, typ.sons[i])])
-  result = ropef("{kind: 2, len: $1, offset: 0, " &
-                 "typ: null, name: null, sons: [$2]}", [toRope(typ.len), s])
+           [i.rope, genTypeInfo(p, typ.sons[i])])
+  result = ("{kind: 2, len: $1, offset: 0, " &
+            "typ: null, name: null, sons: [$2]}") % [rope(typ.len), s]
 
-proc genTupleInfo(p: PProc, typ: PType, name: PRope) = 
-  var s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " &
-                "finalizer: null};$n", [name, toRope(ord(typ.kind))])
+proc genTupleInfo(p: PProc, typ: PType, name: Rope) =
+  var s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
+           "finalizer: null};$n") % [name, rope(ord(typ.kind))]
   prepend(p.g.typeInfo, s)
-  appf(p.g.typeInfo, "var NNI$1 = $2;$n", 
-       [toRope(typ.id), genTupleFields(p, typ)])
-  appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)])
+  addf(p.g.typeInfo, "var NNI$1 = $2;$n",
+       [rope(typ.id), genTupleFields(p, typ)])
+  addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
 
-proc genEnumInfo(p: PProc, typ: PType, name: PRope) =
+proc genEnumInfo(p: PProc, typ: PType, name: Rope) =
   let length = sonsLen(typ.n)
-  var s: PRope = nil
-  for i in countup(0, length - 1): 
+  var s: Rope = nil
+  for i in countup(0, length - 1):
     if (typ.n.sons[i].kind != nkSym): internalError(typ.n.info, "genEnumInfo")
     let field = typ.n.sons[i].sym
-    if i > 0: app(s, ", " & tnl)
+    if i > 0: add(s, ", " & tnl)
     let extName = if field.ast == nil: field.name.s else: field.ast.strVal
-    appf(s, "{kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}", 
-         [toRope(field.position), name, makeJSString(extName)])
-  var n = ropef("var NNI$1 = {kind: 2, offset: 0, typ: null, " &
-      "name: null, len: $2, sons: [$3]};$n", [toRope(typ.id), toRope(length), s])
-  s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " &
-      "finalizer: null};$n", [name, toRope(ord(typ.kind))])
+    addf(s, "{kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}",
+         [rope(field.position), name, makeJSString(extName)])
+  var n = ("var NNI$1 = {kind: 2, offset: 0, typ: null, " &
+      "name: null, len: $2, sons: [$3]};$n") % [rope(typ.id), rope(length), s]
+  s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
+       "finalizer: null};$n") % [name, rope(ord(typ.kind))]
   prepend(p.g.typeInfo, s)
-  app(p.g.typeInfo, n)
-  appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)])
+  add(p.g.typeInfo, n)
+  addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
   if typ.sons[0] != nil:
-    appf(p.g.typeInfo, "$1.base = $2;$n", 
+    addf(p.g.typeInfo, "$1.base = $2;$n",
          [name, genTypeInfo(p, typ.sons[0])])
 
-proc genTypeInfo(p: PProc, typ: PType): PRope = 
+proc genTypeInfo(p: PProc, typ: PType): Rope =
   var t = typ
   if t.kind == tyGenericInst: t = lastSon(t)
-  result = ropef("NTI$1", [toRope(t.id)])
-  if containsOrIncl(p.g.typeInfoGenerated, t.id): return 
+  result = "NTI$1" % [rope(t.id)]
+  if containsOrIncl(p.g.typeInfoGenerated, t.id): return
   case t.kind
-  of tyDistinct: 
+  of tyDistinct:
     result = genTypeInfo(p, typ.sons[0])
-  of tyPointer, tyProc, tyBool, tyChar, tyCString, tyString, tyInt..tyFloat128: 
-    var s = ropef(
-      "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n", 
-              [result, toRope(ord(t.kind))])
+  of tyPointer, tyProc, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64:
+    var s =
+      "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
+      [result, rope(ord(t.kind))]
     prepend(p.g.typeInfo, s)
-  of tyVar, tyRef, tyPtr, tySequence, tyRange, tySet: 
-    var s = ropef(
-      "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n", 
-              [result, toRope(ord(t.kind))])
+  of tyVar, tyRef, tyPtr, tySequence, tyRange, tySet:
+    var s =
+      "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
+              [result, rope(ord(t.kind))]
     prepend(p.g.typeInfo, s)
-    appf(p.g.typeInfo, "$1.base = $2;$n", 
+    addf(p.g.typeInfo, "$1.base = $2;$n",
          [result, genTypeInfo(p, typ.lastSon)])
-  of tyArrayConstr, tyArray: 
-    var s = ropef(
-      "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n",
-              [result, toRope(ord(t.kind))])
+  of tyArrayConstr, tyArray:
+    var s =
+      "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
+              [result, rope(ord(t.kind))]
     prepend(p.g.typeInfo, s)
-    appf(p.g.typeInfo, "$1.base = $2;$n", 
+    addf(p.g.typeInfo, "$1.base = $2;$n",
          [result, genTypeInfo(p, typ.sons[1])])
   of tyEnum: genEnumInfo(p, t, result)
   of tyObject: genObjectInfo(p, t, result)
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index 194396ddd..c68bc352c 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -9,92 +9,92 @@
 
 # This include file implements lambda lifting for the transformator.
 
-import 
-  intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os, 
+import
+  intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
   idents, renderer, types, magicsys, rodread, lowerings
 
 discard """
   The basic approach is that captured vars need to be put on the heap and
-  that the calling chain needs to be explicitely modelled. Things to consider:
-  
+  that the calling chain needs to be explicitly modelled. Things to consider:
+
   proc a =
     var v = 0
     proc b =
       var w = 2
-      
+
       for x in 0..3:
         proc c = capture v, w, x
         c()
     b()
-    
+
     for x in 0..4:
       proc d = capture x
       d()
-  
+
   Needs to be translated into:
-    
+
   proc a =
     var cl: *
     new cl
     cl.v = 0
-    
+
     proc b(cl) =
       var bcl: *
       new bcl
       bcl.w = 2
       bcl.up = cl
-      
+
       for x in 0..3:
         var bcl2: *
         new bcl2
         bcl2.up = bcl
         bcl2.up2 = cl
         bcl2.x = x
-      
+
         proc c(cl) = capture cl.up2.v, cl.up.w, cl.x
         c(bcl2)
-      
+
       c(bcl)
-    
+
     b(cl)
-    
+
     for x in 0..4:
       var acl2: *
       new acl2
       acl2.x = x
       proc d(cl) = capture cl.x
       d(acl2)
-    
+
   Closures as interfaces:
-  
+
   proc outer: T =
     var captureMe: TObject # value type required for efficiency
     proc getter(): int = result = captureMe.x
     proc setter(x: int) = captureMe.x = x
-    
+
     result = (getter, setter)
-    
+
   Is translated to:
-  
+
   proc outer: T =
     var cl: *
     new cl
-    
+
     proc getter(cl): int = result = cl.captureMe.x
     proc setter(cl: *, x: int) = cl.captureMe.x = x
-    
+
     result = ((cl, getter), (cl, setter))
-    
-    
+
+
   For 'byref' capture, the outer proc needs to access the captured var through
   the indirection too. For 'bycopy' capture, the outer proc accesses the var
   not through the indirection.
-    
-  Possible optimizations: 
-  
+
+  Possible optimizations:
+
   1) If the closure contains a single 'ref' and this
   reference is not re-assigned (check ``sfAddrTaken`` flag) make this the
-  closure. This is an important optimization if closures are used as 
+  closure. This is an important optimization if closures are used as
   interfaces.
   2) If the closure does not escape, put it onto the stack, not on the heap.
   3) Dataflow analysis would help to eliminate the 'up' indirections.
@@ -126,7 +126,7 @@ type
     fn, closureParam, state, resultSym: PSym # most are only valid if
                                              # fn.kind == skClosureIterator
     obj: PType
-    
+
   PEnv = ref TEnv
   TEnv {.final.} = object of RootObj
     attachedNode, replacementNode: PNode
@@ -141,7 +141,7 @@ type
                             # if up.fn != fn then we cross function boundaries.
                             # This is an important case to consider.
     vars: IntSet           # variables belonging to this environment
-    
+
   TOuterContext = object
     fn: PSym # may also be a module!
     head: PEnv
@@ -187,6 +187,7 @@ proc addHiddenParam(routine: PSym, param: PSym) =
   param.position = params.len-1
   addSon(params, newSymNode(param))
   incl(routine.typ.flags, tfCapturesEnv)
+  assert sfFromGeneric in param.flags
   #echo "produced environment: ", param.id, " for ", routine.name.s
 
 proc getHiddenParam(routine: PSym): PSym =
@@ -194,12 +195,14 @@ proc getHiddenParam(routine: PSym): PSym =
   let hidden = lastSon(params)
   internalAssert hidden.kind == nkSym and hidden.sym.kind == skParam
   result = hidden.sym
+  assert sfFromGeneric in result.flags
 
 proc getEnvParam(routine: PSym): PSym =
   let params = routine.ast.sons[paramsPos]
   let hidden = lastSon(params)
   if hidden.kind == nkSym and hidden.sym.name.s == paramName:
     result = hidden.sym
+    assert sfFromGeneric in result.flags
 
 proc initIter(iter: PSym): TIter =
   result.fn = iter
@@ -281,7 +284,7 @@ proc addClosureParam(fn: PSym; e: PEnv) =
     #assert e.obj.kind == tyObject
 
 proc illegalCapture(s: PSym): bool {.inline.} =
-  result = skipTypes(s.typ, abstractInst).kind in 
+  result = skipTypes(s.typ, abstractInst).kind in
                    {tyVar, tyOpenArray, tyVarargs} or
       s.kind == skResult
 
@@ -341,7 +344,7 @@ proc createUpField(obj, fieldType: PType): PSym =
   #rawAddField(obj, result)
   addField(obj, result)
 
-proc captureVar(o: POuterContext; top: PEnv; local: PSym; 
+proc captureVar(o: POuterContext; top: PEnv; local: PSym;
                 info: TLineInfo): bool =
   # first check if we should be concerned at all:
   var it = top
@@ -405,7 +408,7 @@ proc gatherVars(o: POuterContext; e: PEnv; n: PNode): int =
     var s = n.sym
     if interestingVar(s) and e.fn != s.owner:
       if captureVar(o, e, s, n.info): result = 1
-  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkClosure, nkProcDef, 
+  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkClosure, nkProcDef,
      nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, nkTypeSection:
     discard
   else:
@@ -415,7 +418,7 @@ proc gatherVars(o: POuterContext; e: PEnv; n: PNode): int =
 proc generateThunk(prc: PNode, dest: PType): PNode =
   ## Converts 'prc' into '(thunk, nil)' so that it's compatible with
   ## a closure.
-  
+
   # we cannot generate a proper thunk here for GC-safety reasons (see internal
   # documentation):
   if gCmd == cmdCompileToJS: return prc
@@ -512,7 +515,7 @@ proc closureCreationPoint(n: PNode): PNode =
 
 proc addParamsToEnv(fn: PSym; env: PEnv) =
   let params = fn.typ.n
-  for i in 1.. <params.len: 
+  for i in 1.. <params.len:
     if params.sons[i].kind != nkSym:
       internalError(params.info, "liftLambdas: strange params")
     let param = params.sons[i].sym
@@ -538,7 +541,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
       addParamsToEnv(fn, envB)
       searchForInnerProcs(o, body, envB)
       fn.ast.sons[bodyPos] = ex
-      
+
       let capturedCounter = gatherVars(o, envB, body)
       # dummy closure param needed?
       if capturedCounter == 0 and fn.typ.callConv == ccClosure:
@@ -557,7 +560,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
   of nkWhileStmt, nkForStmt, nkParForStmt, nkBlockStmt:
     # some nodes open a new scope, so they are candidates for the insertion
     # of closure creation; however for simplicity we merge closures between
-    # branches, in fact, only loop bodies are of interest here as only they 
+    # branches, in fact, only loop bodies are of interest here as only they
     # yield observable changes in semantics. For Zahary we also
     # include ``nkBlock``. We don't do this for closure iterators because
     # 'yield' can produce wrong code otherwise (XXX show example):
@@ -580,7 +583,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
       elif it.kind == nkIdentDefs:
         var L = sonsLen(it)
         if it.sons[0].kind == nkSym:
-          # this can be false for recursive invokations that already
+          # this can be false for recursive invocations that already
           # transformed it into 'env.varName':
           env.vars.incl(it.sons[0].sym.id)
         searchForInnerProcs(o, it.sons[L-1], env)
@@ -595,7 +598,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
         internalError(it.info, "searchForInnerProcs")
   of nkClosure:
     searchForInnerProcs(o, n.sons[0], env)
-  of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, 
+  of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
      nkTypeSection:
     # don't recurse here:
     discard
@@ -603,7 +606,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
     for i in countup(0, sonsLen(n) - 1):
       searchForInnerProcs(o, n.sons[i], env)
 
-proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode = 
+proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
   # Bugfix: unfortunately we cannot use 'nkFastAsgn' here as that would
   # mean to be able to capture string literals which have no GC header.
   # However this can only happen if the capture happens through a parameter,
@@ -621,7 +624,7 @@ proc rawClosureCreation(o: POuterContext, scope: PEnv; env: PNode): PNode =
     result.add(v)
   # add 'new' statement:
   result.add(newCall(getSysSym"internalNew", env))
-  
+
   # add assignment statements:
   for local in scope.capturedVars:
     let fieldAccess = indirectAccess(env, local, env.info)
@@ -693,10 +696,10 @@ proc transformYield(c: POuterContext, n: PNode, it: TIter): PNode =
     retStmt.add(a)
   else:
     retStmt.add(emptyNode)
-  
+
   var stateLabelStmt = newNodeI(nkState, n.info)
   stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
-  
+
   result = newNodeI(nkStmtList, n.info)
   result.add(stateAsgnStmt)
   result.add(retStmt)
@@ -716,15 +719,17 @@ proc outerProcSons(o: POuterContext, n: PNode, it: TIter) =
     let x = transformOuterProc(o, n.sons[i], it)
     if x != nil: n.sons[i] = x
 
-proc liftIterSym*(n: PNode): PNode =
-  # transforms  (iter)  to  (let env = newClosure[iter](); (iter, env)) 
+proc liftIterSym(n: PNode; owner: PSym): PNode =
+  # transforms  (iter)  to  (let env = newClosure[iter](); (iter, env))
   let iter = n.sym
   assert iter.kind == skClosureIterator
 
   result = newNodeIT(nkStmtListExpr, n.info, n.typ)
-  
-  var env = copySym(getHiddenParam(iter))
-  env.kind = skLet
+
+  let hp = getHiddenParam(iter)
+  let env = newSym(skLet, iter.name, owner, n.info)
+  env.typ = hp.typ
+  env.flags = hp.flags
   var v = newNodeI(nkVarSection, n.info)
   addVar(v, newSymNode(env))
   result.add(v)
@@ -795,7 +800,7 @@ proc transformOuterProcBody(o: POuterContext, n: PNode; it: TIter): PNode =
     # with some rather primitive check for now:
     if n.kind == nkStmtList and n.len > 0:
       if n.sons[0].kind == nkGotoState: return nil
-      if n.len > 1 and n[1].kind == nkStmtList and n[1].len > 0 and 
+      if n.len > 1 and n[1].kind == nkStmtList and n[1].len > 0 and
           n[1][0].kind == nkGotoState:
         return nil
     result = newNodeI(nkStmtList, it.fn.info)
@@ -807,7 +812,7 @@ proc transformOuterProcBody(o: POuterContext, n: PNode; it: TIter): PNode =
     var state0 = newNodeI(nkState, it.fn.info)
     state0.add(newIntNode(nkIntLit, 0))
     result.add(state0)
-    
+
     let newBody = transformOuterProc(o, n, it)
     if newBody != nil:
       result.add(newBody)
@@ -853,7 +858,6 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
         addUniqueField(it.obj, local)
         return indirectAccess(newSymNode(it.closureParam), local, n.info)
 
-    var closure = PEnv(idTableGet(o.lambdasToEnv, local))
     if local.kind == skClosureIterator:
       # consider: [i1, i2, i1]  Since we merged the iterator's closure
       # with the captured owning variables, we need to generate the
@@ -861,13 +865,25 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
       if local == o.fn or local == it.fn:
         message(n.info, errRecursiveDependencyX, local.name.s)
       # XXX why doesn't this work?
+      var closure = PEnv(idTableGet(o.lambdasToEnv, local))
       if closure.isNil:
-        return liftIterSym(n)
+        return liftIterSym(n, o.fn)
       else:
         let createdVar = generateIterClosureCreation(o, closure,
                                                      closure.attachedNode)
+        let lpt = getHiddenParam(local).typ
+        if lpt != createdVar.typ:
+          assert lpt.kind == tyRef and createdVar.typ.kind == tyRef
+          # fix bug 'tshallowcopy_closures' but report if this gets any weirder:
+          if createdVar.typ.sons[0].len == 1 and lpt.sons[0].len >= 1:
+            createdVar.typ = lpt
+            if createdVar.kind == nkSym: createdVar.sym.typ = lpt
+            closure.obj = lpt.sons[0]
+          else:
+            internalError(n.info, "environment computation failed")
         return makeClosure(local, createdVar, n.info)
 
+    var closure = PEnv(idTableGet(o.lambdasToEnv, local))
     if closure != nil:
       # we need to replace the lambda with '(lambda, env)':
       let a = closure.createdVar
@@ -883,7 +899,7 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
         let x = closure.createdVar
         assert x != nil
         return makeClosure(local, x, n.info)
-    
+
     if not contains(o.capturedVars, local.id): return
     # change 'local' to 'closure.local', unless it's a 'byCopy' variable:
     # if sfByCopy notin local.flags:
@@ -930,12 +946,12 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
 proc liftLambdas*(fn: PSym, body: PNode): PNode =
   # XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
   # the transformation even when compiling to JS ...
-  if body.kind == nkEmpty or gCmd == cmdCompileToJS or 
+  if body.kind == nkEmpty or gCmd == cmdCompileToJS or
       fn.skipGenericOwner.kind != skModule:
     # ignore forward declaration:
     result = body
   else:
-    #if fn.name.s == "cbOuter":
+    #if fn.name.s == "sort":
     #  echo rendertree(fn.ast, {renderIds})
     var o = newOuterContext(fn)
     let ex = closureCreationPoint(body)
@@ -969,26 +985,26 @@ proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
 
 proc liftForLoop*(body: PNode): PNode =
   # problem ahead: the iterator could be invoked indirectly, but then
-  # we don't know what environment to create here: 
-  # 
+  # we don't know what environment to create here:
+  #
   # iterator count(): int =
   #   yield 0
-  # 
+  #
   # iterator count2(): int =
   #   var x = 3
   #   yield x
   #   inc x
   #   yield x
-  # 
+  #
   # proc invoke(iter: iterator(): int) =
   #   for x in iter(): echo x
   #
-  # --> When to create the closure? --> for the (count) occurence!
+  # --> When to create the closure? --> for the (count) occurrence!
   discard """
       for i in foo(): ...
 
     Is transformed to:
-      
+
       cl = createClosure()
       while true:
         let i = foo(cl)
@@ -1000,7 +1016,7 @@ proc liftForLoop*(body: PNode): PNode =
   var call = body[L-2]
 
   result = newNodeI(nkStmtList, body.info)
-  
+
   # static binding?
   var env: PSym
   if call[0].kind == nkSym and call[0].sym.kind == skClosureIterator:
@@ -1014,18 +1030,18 @@ proc liftForLoop*(body: PNode): PNode =
     result.add(v)
     # add 'new' statement:
     result.add(newCall(getSysSym"internalNew", env.newSymNode))
-  
+
   var loopBody = newNodeI(nkStmtList, body.info, 3)
   var whileLoop = newNodeI(nkWhileStmt, body.info, 2)
   whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(tyBool))
   whileLoop.sons[1] = loopBody
   result.add whileLoop
-  
+
   # setup loopBody:
   # gather vars in a tuple:
   var v2 = newNodeI(nkLetSection, body.info)
   var vpart = newNodeI(if L == 3: nkIdentDefs else: nkVarTuple, body.info)
-  for i in 0 .. L-3: 
+  for i in 0 .. L-3:
     assert body[i].kind == nkSym
     body[i].sym.kind = skLet
     addSon(vpart, body[i])
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index fb74f27d6..8080e0e8c 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -10,79 +10,79 @@
 # This scanner is handwritten for efficiency. I used an elegant buffering
 # scheme which I have not seen anywhere else:
 # We guarantee that a whole line is in the buffer. Thus only when scanning
-# the \n or \r character we have to check wether we need to read in the next 
+# the \n or \r character we have to check wether we need to read in the next
 # chunk. (\n or \r already need special handling for incrementing the line
 # counter; choosing both \n and \r allows the scanner to properly read Unix,
 # DOS or Macintosh text files, even when it is not the native format.
 
-import 
+import
   hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
   wordrecg
 
-const 
+const
   MaxLineLength* = 80         # lines longer than this lead to a warning
   numChars*: set[char] = {'0'..'9', 'a'..'z', 'A'..'Z'}
   SymChars*: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
   SymStartChars*: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
-  OpChars*: set[char] = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.', 
+  OpChars*: set[char] = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
     '|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'}
 
 # don't forget to update the 'highlite' module if these charsets should change
 
-type 
-  TTokType* = enum 
+type
+  TTokType* = enum
     tkInvalid, tkEof,         # order is important here!
     tkSymbol, # keywords:
-    tkAddr, tkAnd, tkAs, tkAsm, tkAtomic, 
-    tkBind, tkBlock, tkBreak, tkCase, tkCast, 
-    tkConst, tkContinue, tkConverter,
+    tkAddr, tkAnd, tkAs, tkAsm, tkAtomic,
+    tkBind, tkBlock, tkBreak, tkCase, tkCast,
+    tkConcept, tkConst, tkContinue, tkConverter,
     tkDefer, tkDiscard, tkDistinct, tkDiv, tkDo,
     tkElif, tkElse, tkEnd, tkEnum, tkExcept, tkExport,
-    tkFinally, tkFor, tkFrom,
-    tkGeneric, tkIf, tkImport, tkIn, tkInclude, tkInterface, 
+    tkFinally, tkFor, tkFrom, tkFunc,
+    tkGeneric, tkIf, tkImport, tkIn, tkInclude, tkInterface,
     tkIs, tkIsnot, tkIterator,
     tkLet,
-    tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin, 
-    tkObject, tkOf, tkOr, tkOut, 
+    tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin,
+    tkObject, tkOf, tkOr, tkOut,
     tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShl, tkShr, tkStatic,
-    tkTemplate, 
-    tkTry, tkTuple, tkType, tkUsing, 
+    tkTemplate,
+    tkTry, tkTuple, tkType, tkUsing,
     tkVar, tkWhen, tkWhile, tkWith, tkWithout, tkXor,
     tkYield, # end of keywords
     tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit,
     tkUIntLit, tkUInt8Lit, tkUInt16Lit, tkUInt32Lit, tkUInt64Lit,
     tkFloatLit, tkFloat32Lit, tkFloat64Lit, tkFloat128Lit,
     tkStrLit, tkRStrLit, tkTripleStrLit,
-    tkGStrLit, tkGTripleStrLit, tkCharLit, tkParLe, tkParRi, tkBracketLe, 
-    tkBracketRi, tkCurlyLe, tkCurlyRi, 
+    tkGStrLit, tkGTripleStrLit, tkCharLit, tkParLe, tkParRi, tkBracketLe,
+    tkBracketRi, tkCurlyLe, tkCurlyRi,
     tkBracketDotLe, tkBracketDotRi, # [. and  .]
     tkCurlyDotLe, tkCurlyDotRi, # {.  and  .}
     tkParDotLe, tkParDotRi,   # (. and .)
     tkComma, tkSemiColon,
     tkColon, tkColonColon, tkEquals, tkDot, tkDotDot,
     tkOpr, tkComment, tkAccent,
-    tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr,
-    
+    tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr
+
   TTokTypes* = set[TTokType]
 
-const 
+const
   tokKeywordLow* = succ(tkSymbol)
   tokKeywordHigh* = pred(tkIntLit)
-  TokTypeToStr*: array[TTokType, string] = ["tkInvalid", "[EOF]", 
+  TokTypeToStr*: array[TTokType, string] = ["tkInvalid", "[EOF]",
     "tkSymbol",
-    "addr", "and", "as", "asm", "atomic", 
-    "bind", "block", "break", "case", "cast", 
-    "const", "continue", "converter",
+    "addr", "and", "as", "asm", "atomic",
+    "bind", "block", "break", "case", "cast",
+    "concept", "const", "continue", "converter",
     "defer", "discard", "distinct", "div", "do",
     "elif", "else", "end", "enum", "except", "export",
-    "finally", "for", "from", "generic", "if", 
+    "finally", "for", "from", "func", "generic", "if",
     "import", "in", "include", "interface", "is", "isnot", "iterator",
-    "let", 
-    "macro", "method", "mixin", "mod", 
-    "nil", "not", "notin", "object", "of", "or", 
-    "out", "proc", "ptr", "raise", "ref", "return", 
+    "let",
+    "macro", "method", "mixin", "mod",
+    "nil", "not", "notin", "object", "of", "or",
+    "out", "proc", "ptr", "raise", "ref", "return",
     "shl", "shr", "static",
-    "template", 
+    "template",
     "try", "tuple", "type", "using",
     "var", "when", "while", "with", "without", "xor",
     "yield",
@@ -90,7 +90,7 @@ const
     "tkUIntLit", "tkUInt8Lit", "tkUInt16Lit", "tkUInt32Lit", "tkUInt64Lit",
     "tkFloatLit", "tkFloat32Lit", "tkFloat64Lit", "tkFloat128Lit",
     "tkStrLit", "tkRStrLit",
-    "tkTripleStrLit", "tkGStrLit", "tkGTripleStrLit", "tkCharLit", "(", 
+    "tkTripleStrLit", "tkGStrLit", "tkGTripleStrLit", "tkCharLit", "(",
     ")", "[", "]", "{", "}", "[.", ".]", "{.", ".}", "(.", ".)",
     ",", ";",
     ":", "::", "=", ".", "..",
@@ -98,8 +98,8 @@ const
     "tkSpaces", "tkInfixOpr",
     "tkPrefixOpr", "tkPostfixOpr"]
 
-type 
-  TNumericalBase* = enum 
+type
+  TNumericalBase* = enum
     base10,                   # base10 is listed as the first element,
                               # so that it is the correct default value
     base2, base8, base16
@@ -107,7 +107,7 @@ type
   TToken* = object            # a Nim token
     tokType*: TTokType        # the type of the token
     indent*: int              # the indentation; != -1 if the token has been
-                              # preceeded with indentation
+                              # preceded with indentation
     ident*: PIdent            # the parsed identifier
     iNumber*: BiggestInt      # the parsed integer literal
     fNumber*: BiggestFloat    # the parsed floating point literal
@@ -131,64 +131,48 @@ type
 
 var gLinesCompiled*: int  # all lines that have been compiled
 
-proc isKeyword*(kind: TTokType): bool
-proc openLexer*(lex: var TLexer, fileidx: int32, inputstream: PLLStream)
-proc rawGetTok*(L: var TLexer, tok: var TToken)
-  # reads in the next token into tok and skips it
-
 proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
   newLineInfo(L.fileIdx, tok.line, tok.col)
 
-proc closeLexer*(lex: var TLexer)
-proc printTok*(tok: TToken)
-proc tokToStr*(tok: TToken): string
-
-proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
-  openLexer(lex, filename.fileInfoIdx, inputstream)
-
-proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "")
-
-proc isKeyword(kind: TTokType): bool = 
+proc isKeyword*(kind: TTokType): bool =
   result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
 
 proc isNimIdentifier*(s: string): bool =
   if s[0] in SymStartChars:
     var i = 1
     while i < s.len:
-      if s[i] == '_': 
+      if s[i] == '_':
         inc(i)
         if s[i] notin SymChars: return
       if s[i] notin SymChars: return
       inc(i)
     result = true
 
-proc tokToStr*(tok: TToken): string = 
+proc tokToStr*(tok: TToken): string =
   case tok.tokType
   of tkIntLit..tkInt64Lit: result = $tok.iNumber
   of tkFloatLit..tkFloat64Lit: result = $tok.fNumber
   of tkInvalid, tkStrLit..tkCharLit, tkComment: result = tok.literal
-  of tkParLe..tkColon, tkEof, tkAccent: 
+  of tkParLe..tkColon, tkEof, tkAccent:
     result = TokTypeToStr[tok.tokType]
   else:
     if tok.ident != nil:
       result = tok.ident.s
-    else: 
+    else:
       internalError("tokToStr")
       result = ""
-  
+
 proc prettyTok*(tok: TToken): string =
   if isKeyword(tok.tokType): result = "keyword " & tok.ident.s
   else: result = tokToStr(tok)
-  
-proc printTok*(tok: TToken) = 
-  write(stdout, tok.line, ":", tok.col, "\t")
-  write(stdout, TokTypeToStr[tok.tokType])
-  write(stdout, " ")
-  writeln(stdout, tokToStr(tok))
+
+proc printTok*(tok: TToken) =
+  msgWriteln($tok.line & ":" & $tok.col & "\t" &
+      TokTypeToStr[tok.tokType] & " " & tokToStr(tok))
 
 var dummyIdent: PIdent
 
-proc initToken*(L: var TToken) = 
+proc initToken*(L: var TToken) =
   L.tokType = tkInvalid
   L.iNumber = 0
   L.indent = 0
@@ -198,7 +182,7 @@ proc initToken*(L: var TToken) =
   L.base = base10
   L.ident = dummyIdent
 
-proc fillToken(L: var TToken) = 
+proc fillToken(L: var TToken) =
   L.tokType = tkInvalid
   L.iNumber = 0
   L.indent = 0
@@ -207,22 +191,25 @@ proc fillToken(L: var TToken) =
   L.fNumber = 0.0
   L.base = base10
   L.ident = dummyIdent
-  
-proc openLexer(lex: var TLexer, fileIdx: int32, inputstream: PLLStream) = 
+
+proc openLexer*(lex: var TLexer, fileIdx: int32, inputstream: PLLStream) =
   openBaseLexer(lex, inputstream)
   lex.fileIdx = fileidx
   lex.indentAhead = - 1
   lex.currLineIndent = 0
-  inc(lex.lineNumber, inputstream.lineOffset) 
+  inc(lex.lineNumber, inputstream.lineOffset)
 
-proc closeLexer(lex: var TLexer) = 
+proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
+  openLexer(lex, filename.fileInfoIdx, inputstream)
+
+proc closeLexer*(lex: var TLexer) =
   inc(gLinesCompiled, lex.lineNumber)
   closeBaseLexer(lex)
 
-proc getColumn(L: TLexer): int = 
+proc getColumn(L: TLexer): int =
   result = getColNumber(L, L.bufpos)
 
-proc getLineInfo(L: TLexer): TLineInfo = 
+proc getLineInfo(L: TLexer): TLineInfo =
   result = newLineInfo(L.fileIdx, L.lineNumber, getColNumber(L, L.bufpos))
 
 proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) =
@@ -231,31 +218,35 @@ proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) =
   else:
     L.errorHandler(info, msg, arg)
 
-proc lexMessage(L: TLexer, msg: TMsgKind, arg = "") =
+proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
   L.dispMessage(getLineInfo(L), msg, arg)
 
+proc lexMessageTok*(L: TLexer, msg: TMsgKind, tok: TToken, arg = "") =
+  var info = newLineInfo(L.fileIdx, tok.line, tok.col)
+  L.dispMessage(info, msg, arg)
+
 proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
   var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart)
   L.dispMessage(info, msg, arg)
 
-proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]) = 
+proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]) =
   var pos = L.bufpos              # use registers for pos, buf
   var buf = L.buf
-  while true: 
-    if buf[pos] in chars: 
+  while true:
+    if buf[pos] in chars:
       add(tok.literal, buf[pos])
       inc(pos)
-    else: 
-      break 
-    if buf[pos] == '_': 
-      if buf[pos+1] notin chars: 
+    else:
+      break
+    if buf[pos] == '_':
+      if buf[pos+1] notin chars:
         lexMessage(L, errInvalidToken, "_")
         break
       add(tok.literal, '_')
       inc(pos)
   L.bufpos = pos
 
-proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool = 
+proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool =
   result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second)
 
 proc isFloatLiteral(s: string): bool =
@@ -264,8 +255,21 @@ proc isFloatLiteral(s: string): bool =
       return true
   result = false
 
-proc getNumber(L: var TLexer): TToken = 
-  var 
+{.push overflowChecks: off.}
+# We need to parse the largest uint literal without overflow checks
+proc unsafeParseUInt(s: string, b: var BiggestInt, start = 0): int =
+  var i = start
+  if s[i] in {'0'..'9'}:
+    b = 0
+    while s[i] in {'0'..'9'}:
+      b = b * 10 + (ord(s[i]) - ord('0'))
+      inc(i)
+      while s[i] == '_': inc(i) # underscores are allowed and ignored
+    result = i - start
+{.pop.} # overflowChecks
+
+proc getNumber(L: var TLexer): TToken =
+  var
     pos, endpos: int
     xi: BiggestInt
   # get the base:
@@ -279,15 +283,15 @@ proc getNumber(L: var TLexer): TToken =
   else:
     matchUnderscoreChars(L, result, {'0'..'9', 'b', 'B', 'o', 'c', 'C'})
     eallowed = true
-  if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}): 
+  if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
     add(result.literal, '.')
     inc(L.bufpos)
     matchUnderscoreChars(L, result, {'0'..'9'})
     eallowed = true
-  if eallowed and L.buf[L.bufpos] in {'e', 'E'}: 
+  if eallowed and L.buf[L.bufpos] in {'e', 'E'}:
     add(result.literal, 'e')
     inc(L.bufpos)
-    if L.buf[L.bufpos] in {'+', '-'}: 
+    if L.buf[L.bufpos] in {'+', '-'}:
       add(result.literal, L.buf[L.bufpos])
       inc(L.bufpos)
     matchUnderscoreChars(L, result, {'0'..'9'})
@@ -296,7 +300,7 @@ proc getNumber(L: var TLexer): TToken =
     if L.buf[endpos] == '\'': inc(endpos)
     L.bufpos = pos            # restore position
     case L.buf[endpos]
-    of 'f', 'F': 
+    of 'f', 'F':
       inc(endpos)
       if (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'):
         result.tokType = tkFloat32Lit
@@ -309,36 +313,36 @@ proc getNumber(L: var TLexer): TToken =
            (L.buf[endpos + 2] == '8'):
         result.tokType = tkFloat128Lit
         inc(endpos, 3)
-      else: 
+      else:
         lexMessage(L, errInvalidNumber, result.literal & "'f" & L.buf[endpos])
-    of 'i', 'I': 
+    of 'i', 'I':
       inc(endpos)
-      if (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'): 
+      if (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'):
         result.tokType = tkInt64Lit
         inc(endpos, 2)
-      elif (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'): 
+      elif (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'):
         result.tokType = tkInt32Lit
         inc(endpos, 2)
-      elif (L.buf[endpos] == '1') and (L.buf[endpos + 1] == '6'): 
+      elif (L.buf[endpos] == '1') and (L.buf[endpos + 1] == '6'):
         result.tokType = tkInt16Lit
         inc(endpos, 2)
-      elif (L.buf[endpos] == '8'): 
+      elif (L.buf[endpos] == '8'):
         result.tokType = tkInt8Lit
         inc(endpos)
-      else: 
+      else:
         lexMessage(L, errInvalidNumber, result.literal & "'i" & L.buf[endpos])
     of 'u', 'U':
       inc(endpos)
-      if (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'): 
+      if (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'):
         result.tokType = tkUInt64Lit
         inc(endpos, 2)
-      elif (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'): 
+      elif (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'):
         result.tokType = tkUInt32Lit
         inc(endpos, 2)
-      elif (L.buf[endpos] == '1') and (L.buf[endpos + 1] == '6'): 
+      elif (L.buf[endpos] == '1') and (L.buf[endpos + 1] == '6'):
         result.tokType = tkUInt16Lit
         inc(endpos, 2)
-      elif (L.buf[endpos] == '8'): 
+      elif (L.buf[endpos] == '8'):
         result.tokType = tkUInt8Lit
         inc(endpos)
       else:
@@ -346,45 +350,45 @@ proc getNumber(L: var TLexer): TToken =
     else: lexMessage(L, errInvalidNumber, result.literal & "'" & L.buf[endpos])
   else:
     L.bufpos = pos            # restore position
-  try: 
+  try:
     if (L.buf[pos] == '0') and
-        (L.buf[pos + 1] in {'x', 'X', 'b', 'B', 'o', 'O', 'c', 'C'}): 
+        (L.buf[pos + 1] in {'x', 'X', 'b', 'B', 'o', 'O', 'c', 'C'}):
       inc(pos, 2)
       xi = 0                  # it may be a base prefix
       case L.buf[pos - 1]     # now look at the optional type suffix:
-      of 'b', 'B': 
+      of 'b', 'B':
         result.base = base2
-        while true: 
+        while true:
           case L.buf[pos]
-          of '2'..'9', '.': 
+          of '2'..'9', '.':
             lexMessage(L, errInvalidNumber, result.literal)
             inc(pos)
-          of '_': 
-            if L.buf[pos+1] notin {'0'..'1'}: 
+          of '_':
+            if L.buf[pos+1] notin {'0'..'1'}:
               lexMessage(L, errInvalidToken, "_")
               break
             inc(pos)
-          of '0', '1': 
+          of '0', '1':
             xi = `shl`(xi, 1) or (ord(L.buf[pos]) - ord('0'))
             inc(pos)
-          else: break 
-      of 'o', 'c', 'C': 
+          else: break
+      of 'o', 'c', 'C':
         result.base = base8
-        while true: 
+        while true:
           case L.buf[pos]
-          of '8'..'9', '.': 
+          of '8'..'9', '.':
             lexMessage(L, errInvalidNumber, result.literal)
             inc(pos)
-          of '_': 
+          of '_':
             if L.buf[pos+1] notin {'0'..'7'}:
               lexMessage(L, errInvalidToken, "_")
               break
             inc(pos)
-          of '0'..'7': 
+          of '0'..'7':
             xi = `shl`(xi, 3) or (ord(L.buf[pos]) - ord('0'))
             inc(pos)
-          else: break 
-      of 'O': 
+          else: break
+      of 'O':
         lexMessage(L, errInvalidNumber, result.literal)
       of 'x', 'X':
         result.base = base16
@@ -404,7 +408,7 @@ proc getNumber(L: var TLexer): TToken =
           of 'A'..'F':
             xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10)
             inc(pos)
-          else: break 
+          else: break
       else: internalError(getLineInfo(L), "getNumber")
       case result.tokType
       of tkIntLit, tkInt64Lit: result.iNumber = xi
@@ -415,16 +419,22 @@ proc getNumber(L: var TLexer): TToken =
       of tkUInt8Lit: result.iNumber = BiggestInt(int8(toU8(int(xi))))
       of tkUInt16Lit: result.iNumber = BiggestInt(toU16(int(xi)))
       of tkUInt32Lit: result.iNumber = BiggestInt(toU32(xi))
-      of tkFloat32Lit: 
-        result.fNumber = (cast[PFloat32](addr(xi)))[] 
+      of tkFloat32Lit:
+        result.fNumber = (cast[PFloat32](addr(xi)))[]
         # note: this code is endian neutral!
         # XXX: Test this on big endian machine!
-      of tkFloat64Lit: result.fNumber = (cast[PFloat64](addr(xi)))[] 
+      of tkFloat64Lit: result.fNumber = (cast[PFloat64](addr(xi)))[]
       else: internalError(getLineInfo(L), "getNumber")
     elif isFloatLiteral(result.literal) or (result.tokType == tkFloat32Lit) or
-        (result.tokType == tkFloat64Lit): 
+        (result.tokType == tkFloat64Lit):
       result.fNumber = parseFloat(result.literal)
       if result.tokType == tkIntLit: result.tokType = tkFloatLit
+    elif result.tokType == tkUint64Lit:
+      xi = 0
+      let len = unsafeParseUInt(result.literal, xi)
+      if len != result.literal.len or len == 0:
+        raise newException(ValueError, "invalid integer: " & $xi)
+      result.iNumber = xi
     else:
       result.iNumber = parseBiggestInt(result.literal)
       if (result.iNumber < low(int32)) or (result.iNumber > high(int32)):
@@ -444,69 +454,69 @@ proc getNumber(L: var TLexer): TToken =
     lexMessage(L, errNumberOutOfRange, result.literal)
   L.bufpos = endpos
 
-proc handleHexChar(L: var TLexer, xi: var int) = 
+proc handleHexChar(L: var TLexer, xi: var int) =
   case L.buf[L.bufpos]
-  of '0'..'9': 
+  of '0'..'9':
     xi = (xi shl 4) or (ord(L.buf[L.bufpos]) - ord('0'))
     inc(L.bufpos)
-  of 'a'..'f': 
+  of 'a'..'f':
     xi = (xi shl 4) or (ord(L.buf[L.bufpos]) - ord('a') + 10)
     inc(L.bufpos)
-  of 'A'..'F': 
+  of 'A'..'F':
     xi = (xi shl 4) or (ord(L.buf[L.bufpos]) - ord('A') + 10)
     inc(L.bufpos)
   else: discard
 
-proc handleDecChars(L: var TLexer, xi: var int) = 
-  while L.buf[L.bufpos] in {'0'..'9'}: 
+proc handleDecChars(L: var TLexer, xi: var int) =
+  while L.buf[L.bufpos] in {'0'..'9'}:
     xi = (xi * 10) + (ord(L.buf[L.bufpos]) - ord('0'))
     inc(L.bufpos)
 
-proc getEscapedChar(L: var TLexer, tok: var TToken) = 
+proc getEscapedChar(L: var TLexer, tok: var TToken) =
   inc(L.bufpos)               # skip '\'
   case L.buf[L.bufpos]
-  of 'n', 'N': 
+  of 'n', 'N':
     if tok.tokType == tkCharLit: lexMessage(L, errNnotAllowedInCharacter)
     add(tok.literal, tnl)
     inc(L.bufpos)
-  of 'r', 'R', 'c', 'C': 
+  of 'r', 'R', 'c', 'C':
     add(tok.literal, CR)
     inc(L.bufpos)
-  of 'l', 'L': 
+  of 'l', 'L':
     add(tok.literal, LF)
     inc(L.bufpos)
-  of 'f', 'F': 
+  of 'f', 'F':
     add(tok.literal, FF)
     inc(L.bufpos)
-  of 'e', 'E': 
+  of 'e', 'E':
     add(tok.literal, ESC)
     inc(L.bufpos)
-  of 'a', 'A': 
+  of 'a', 'A':
     add(tok.literal, BEL)
     inc(L.bufpos)
-  of 'b', 'B': 
+  of 'b', 'B':
     add(tok.literal, BACKSPACE)
     inc(L.bufpos)
-  of 'v', 'V': 
+  of 'v', 'V':
     add(tok.literal, VT)
     inc(L.bufpos)
-  of 't', 'T': 
+  of 't', 'T':
     add(tok.literal, '\t')
     inc(L.bufpos)
-  of '\'', '\"': 
+  of '\'', '\"':
     add(tok.literal, L.buf[L.bufpos])
     inc(L.bufpos)
-  of '\\': 
+  of '\\':
     add(tok.literal, '\\')
     inc(L.bufpos)
-  of 'x', 'X': 
+  of 'x', 'X':
     inc(L.bufpos)
     var xi = 0
     handleHexChar(L, xi)
     handleHexChar(L, xi)
     add(tok.literal, chr(xi))
-  of '0'..'9': 
-    if matchTwoChars(L, '0', {'0'..'9'}): 
+  of '0'..'9':
+    if matchTwoChars(L, '0', {'0'..'9'}):
       lexMessage(L, warnOctalEscape)
     var xi = 0
     handleDecChars(L, xi)
@@ -523,7 +533,7 @@ proc newString(s: cstring, len: int): string =
 proc handleCRLF(L: var TLexer, pos: int): int =
   template registerLine =
     let col = L.getColNumber(pos)
-    
+
     if col > MaxLineLength:
       lexMessagePos(L, hintLineTooLong, pos)
 
@@ -531,7 +541,7 @@ proc handleCRLF(L: var TLexer, pos: int): int =
       let lineStart = cast[ByteAddress](L.buf) + L.lineStart
       let line = newString(cast[cstring](lineStart), col)
       addSourceLine(L.fileIdx, line)
-  
+
   case L.buf[pos]
   of CR:
     registerLine()
@@ -540,12 +550,12 @@ proc handleCRLF(L: var TLexer, pos: int): int =
     registerLine()
     result = nimlexbase.handleLF(L, pos)
   else: result = pos
-  
-proc getString(L: var TLexer, tok: var TToken, rawMode: bool) = 
+
+proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
   var pos = L.bufpos + 1          # skip "
   var buf = L.buf                 # put `buf` in a register
   var line = L.lineNumber         # save linenumber for better error message
-  if buf[pos] == '\"' and buf[pos+1] == '\"': 
+  if buf[pos] == '\"' and buf[pos+1] == '\"':
     tok.tokType = tkTripleStrLit # long string literal:
     inc(pos, 2)               # skip ""
     # skip leading newline:
@@ -555,112 +565,112 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
       if buf[newpos] in {CR, LF}: pos = newpos
     pos = handleCRLF(L, pos)
     buf = L.buf
-    while true: 
+    while true:
       case buf[pos]
-      of '\"': 
+      of '\"':
         if buf[pos+1] == '\"' and buf[pos+2] == '\"' and
-            buf[pos+3] != '\"': 
+            buf[pos+3] != '\"':
           L.bufpos = pos + 3 # skip the three """
-          break 
+          break
         add(tok.literal, '\"')
         inc(pos)
-      of CR, LF: 
+      of CR, LF:
         pos = handleCRLF(L, pos)
         buf = L.buf
         add(tok.literal, tnl)
-      of nimlexbase.EndOfFile: 
+      of nimlexbase.EndOfFile:
         var line2 = L.lineNumber
         L.lineNumber = line
         lexMessagePos(L, errClosingTripleQuoteExpected, L.lineStart)
         L.lineNumber = line2
-        break 
-      else: 
+        break
+      else:
         add(tok.literal, buf[pos])
         inc(pos)
-  else: 
+  else:
     # ordinary string literal
     if rawMode: tok.tokType = tkRStrLit
     else: tok.tokType = tkStrLit
-    while true: 
+    while true:
       var c = buf[pos]
-      if c == '\"': 
+      if c == '\"':
         if rawMode and buf[pos+1] == '\"':
           inc(pos, 2)
           add(tok.literal, '"')
         else:
           inc(pos) # skip '"'
           break
-      elif c in {CR, LF, nimlexbase.EndOfFile}: 
+      elif c in {CR, LF, nimlexbase.EndOfFile}:
         lexMessage(L, errClosingQuoteExpected)
-        break 
-      elif (c == '\\') and not rawMode: 
+        break
+      elif (c == '\\') and not rawMode:
         L.bufpos = pos
         getEscapedChar(L, tok)
         pos = L.bufpos
-      else: 
+      else:
         add(tok.literal, c)
         inc(pos)
     L.bufpos = pos
 
-proc getCharacter(L: var TLexer, tok: var TToken) = 
+proc getCharacter(L: var TLexer, tok: var TToken) =
   inc(L.bufpos)               # skip '
   var c = L.buf[L.bufpos]
   case c
   of '\0'..pred(' '), '\'': lexMessage(L, errInvalidCharacterConstant)
   of '\\': getEscapedChar(L, tok)
-  else: 
+  else:
     tok.literal = $c
     inc(L.bufpos)
   if L.buf[L.bufpos] != '\'': lexMessage(L, errMissingFinalQuote)
   inc(L.bufpos)               # skip '
-  
-proc getSymbol(L: var TLexer, tok: var TToken) = 
+
+proc getSymbol(L: var TLexer, tok: var TToken) =
   var h: THash = 0
   var pos = L.bufpos
   var buf = L.buf
-  while true: 
+  while true:
     var c = buf[pos]
     case c
-    of 'a'..'z', '0'..'9', '\x80'..'\xFF': 
+    of 'a'..'z', '0'..'9', '\x80'..'\xFF':
       h = h !& ord(c)
-    of 'A'..'Z': 
+    of 'A'..'Z':
       c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
       h = h !& ord(c)
     of '_':
-      if buf[pos+1] notin SymChars: 
+      if buf[pos+1] notin SymChars:
         lexMessage(L, errInvalidToken, "_")
         break
-    else: break 
+    else: break
     inc(pos)
   h = !$h
   tok.ident = getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
   L.bufpos = pos
   if (tok.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or
-      (tok.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)): 
+      (tok.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):
     tok.tokType = tkSymbol
-  else: 
+  else:
     tok.tokType = TTokType(tok.ident.id + ord(tkSymbol))
-  
+
 proc endOperator(L: var TLexer, tok: var TToken, pos: int,
-                 hash: THash) {.inline.} = 
+                 hash: THash) {.inline.} =
   var h = !$hash
   tok.ident = getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
   if (tok.ident.id < oprLow) or (tok.ident.id > oprHigh): tok.tokType = tkOpr
   else: tok.tokType = TTokType(tok.ident.id - oprLow + ord(tkColon))
   L.bufpos = pos
-  
-proc getOperator(L: var TLexer, tok: var TToken) = 
+
+proc getOperator(L: var TLexer, tok: var TToken) =
   var pos = L.bufpos
   var buf = L.buf
   var h: THash = 0
-  while true: 
+  while true:
     var c = buf[pos]
     if c notin OpChars: break
     h = h !& ord(c)
     inc(pos)
   endOperator(L, tok, pos, h)
   # advance pos but don't store it in L.bufpos so the next token (which might
-  # be an operator too) gets the preceeding spaces:
+  # be an operator too) gets the preceding spaces:
   tok.strongSpaceB = 0
   while buf[pos] == ' ':
     inc pos
@@ -674,7 +684,15 @@ proc scanComment(L: var TLexer, tok: var TToken) =
   when not defined(nimfix):
     assert buf[pos+1] == '#'
     if buf[pos+2] == '[':
-      lexMessagePos(L, warnDeprecated, pos, "use '## [' instead; '##['")
+      if buf[pos+3] == ']':
+        #  ##[] is the (rather complex) "cursor token" for idetools
+        tok.tokType = tkComment
+        tok.literal = "[]"
+        inc(L.bufpos, 4)
+        return
+      else:
+        lexMessagePos(L, warnDeprecated, pos, "use '## [' instead; '##['")
+
   tok.tokType = tkComment
   # iNumber contains the number of '\n' in the token
   tok.iNumber = 0
@@ -698,7 +716,7 @@ proc scanComment(L: var TLexer, tok: var TToken) =
     pos = handleCRLF(L, pos)
     buf = L.buf
     var indent = 0
-    while buf[pos] == ' ': 
+    while buf[pos] == ' ':
       inc(pos)
       inc(indent)
 
@@ -713,7 +731,7 @@ proc scanComment(L: var TLexer, tok: var TToken) =
       when defined(nimfix): col = indent
       inc tok.iNumber
     else:
-      if buf[pos] > ' ': 
+      if buf[pos] > ' ':
         L.indentAhead = indent
       break
   L.bufpos = pos
@@ -760,7 +778,7 @@ proc skip(L: var TLexer, tok: var TToken) =
       break                   # EndOfFile also leaves the loop
   L.bufpos = pos
 
-proc rawGetTok(L: var TLexer, tok: var TToken) =
+proc rawGetTok*(L: var TLexer, tok: var TToken) =
   fillToken(tok)
   if L.indentAhead >= 0:
     tok.indent = L.indentAhead
@@ -776,10 +794,10 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
     getSymbol(L, tok)
   else:
     case c
-    of '#': 
+    of '#':
       scanComment(L, tok)
     of '*':
-      # '*:' is unfortunately a special case, because it is two tokens in 
+      # '*:' is unfortunately a special case, because it is two tokens in
       # 'var v*: int'.
       if L.buf[L.bufpos+1] == ':' and L.buf[L.bufpos+2] notin OpChars:
         var h = 0 !& ord('*')
@@ -789,29 +807,29 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
     of ',':
       tok.tokType = tkComma
       inc(L.bufpos)
-    of 'l': 
+    of 'l':
       # if we parsed exactly one character and its a small L (l), this
       # is treated as a warning because it may be confused with the number 1
       if L.buf[L.bufpos+1] notin (SymChars + {'_'}):
         lexMessage(L, warnSmallLshouldNotBeUsed)
       getSymbol(L, tok)
     of 'r', 'R':
-      if L.buf[L.bufpos + 1] == '\"': 
+      if L.buf[L.bufpos + 1] == '\"':
         inc(L.bufpos)
         getString(L, tok, true)
-      else: 
+      else:
         getSymbol(L, tok)
-    of '(': 
+    of '(':
       inc(L.bufpos)
-      if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] != '.': 
+      if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] != '.':
         tok.tokType = tkParDotLe
         inc(L.bufpos)
-      else: 
+      else:
         tok.tokType = tkParLe
-    of ')': 
+    of ')':
       tok.tokType = tkParRi
       inc(L.bufpos)
-    of '[': 
+    of '[':
       inc(L.bufpos)
       if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] != '.':
         tok.tokType = tkBracketDotLe
@@ -822,34 +840,43 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
       tok.tokType = tkBracketRi
       inc(L.bufpos)
     of '.':
-      if L.buf[L.bufpos+1] == ']': 
+      if L.buf[L.bufpos+1] == ']':
         tok.tokType = tkBracketDotRi
         inc(L.bufpos, 2)
-      elif L.buf[L.bufpos+1] == '}': 
+      elif L.buf[L.bufpos+1] == '}':
         tok.tokType = tkCurlyDotRi
         inc(L.bufpos, 2)
-      elif L.buf[L.bufpos+1] == ')': 
+      elif L.buf[L.bufpos+1] == ')':
         tok.tokType = tkParDotRi
         inc(L.bufpos, 2)
-      else: 
+      else:
         getOperator(L, tok)
-    of '{': 
+    of '{':
       inc(L.bufpos)
       if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] != '.':
         tok.tokType = tkCurlyDotLe
         inc(L.bufpos)
-      else: 
+      else:
         tok.tokType = tkCurlyLe
-    of '}': 
+    of '}':
       tok.tokType = tkCurlyRi
       inc(L.bufpos)
-    of ';': 
+    of ';':
       tok.tokType = tkSemiColon
       inc(L.bufpos)
-    of '`': 
+    of '`':
       tok.tokType = tkAccent
       inc(L.bufpos)
-    of '\"': 
+    of '_':
+      inc(L.bufpos)
+      if L.buf[L.bufpos] notin SymChars:
+        tok.tokType = tkSymbol
+        tok.ident = getIdent("_")
+      else:
+        tok.literal = $c
+        tok.tokType = tkInvalid
+        lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
+    of '\"':
       # check for extended raw string literal:
       var rawMode = L.bufpos > 0 and L.buf[L.bufpos-1] in SymChars
       getString(L, tok, rawMode)
@@ -864,7 +891,7 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
     of '0'..'9':
       tok = getNumber(L)
     else:
-      if c in OpChars: 
+      if c in OpChars:
         getOperator(L, tok)
       elif c == nimlexbase.EndOfFile:
         tok.tokType = tkEof
diff --git a/compiler/llstream.nim b/compiler/llstream.nim
index be469548d..18ca4aec7 100644
--- a/compiler/llstream.nim
+++ b/compiler/llstream.nim
@@ -30,47 +30,32 @@ type
   
   PLLStream* = ref TLLStream
 
-proc llStreamOpen*(data: string): PLLStream
-proc llStreamOpen*(f: var File): PLLStream
-proc llStreamOpen*(filename: string, mode: FileMode): PLLStream
-proc llStreamOpen*(): PLLStream
-proc llStreamOpenStdIn*(): PLLStream
-proc llStreamClose*(s: PLLStream)
-proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int
-proc llStreamReadLine*(s: PLLStream, line: var string): bool
-proc llStreamReadAll*(s: PLLStream): string
-proc llStreamWrite*(s: PLLStream, data: string)
-proc llStreamWrite*(s: PLLStream, data: char)
-proc llStreamWrite*(s: PLLStream, buf: pointer, buflen: int)
-proc llStreamWriteln*(s: PLLStream, data: string)
-# implementation
-
-proc llStreamOpen(data: string): PLLStream = 
+proc llStreamOpen*(data: string): PLLStream = 
   new(result)
   result.s = data
   result.kind = llsString
 
-proc llStreamOpen(f: var File): PLLStream = 
+proc llStreamOpen*(f: File): PLLStream = 
   new(result)
   result.f = f
   result.kind = llsFile
 
-proc llStreamOpen(filename: string, mode: FileMode): PLLStream = 
+proc llStreamOpen*(filename: string, mode: FileMode): PLLStream = 
   new(result)
   result.kind = llsFile
   if not open(result.f, filename, mode): result = nil
   
-proc llStreamOpen(): PLLStream = 
+proc llStreamOpen*(): PLLStream = 
   new(result)
   result.kind = llsNone
 
-proc llStreamOpenStdIn(): PLLStream = 
+proc llStreamOpenStdIn*(): PLLStream = 
   new(result)
   result.kind = llsStdIn
   result.s = ""
   result.lineOffset = -1
 
-proc llStreamClose(s: PLLStream) = 
+proc llStreamClose*(s: PLLStream) = 
   case s.kind
   of llsNone, llsString, llsStdIn: 
     discard
@@ -130,7 +115,7 @@ proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
     copyMem(buf, addr(s.s[s.rd]), result)
     inc(s.rd, result)
 
-proc llStreamRead(s: PLLStream, buf: pointer, bufLen: int): int = 
+proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int = 
   case s.kind
   of llsNone: 
     result = 0
@@ -144,7 +129,7 @@ proc llStreamRead(s: PLLStream, buf: pointer, bufLen: int): int =
   of llsStdIn: 
     result = llReadFromStdin(s, buf, bufLen)
   
-proc llStreamReadLine(s: PLLStream, line: var string): bool =
+proc llStreamReadLine*(s: PLLStream, line: var string): bool =
   setLen(line, 0)
   case s.kind
   of llsNone:
@@ -168,7 +153,7 @@ proc llStreamReadLine(s: PLLStream, line: var string): bool =
   of llsStdIn:
     result = readLine(stdin, line)
     
-proc llStreamWrite(s: PLLStream, data: string) = 
+proc llStreamWrite*(s: PLLStream, data: string) = 
   case s.kind
   of llsNone, llsStdIn: 
     discard
@@ -178,11 +163,11 @@ proc llStreamWrite(s: PLLStream, data: string) =
   of llsFile: 
     write(s.f, data)
   
-proc llStreamWriteln(s: PLLStream, data: string) = 
+proc llStreamWriteln*(s: PLLStream, data: string) = 
   llStreamWrite(s, data)
   llStreamWrite(s, "\n")
 
-proc llStreamWrite(s: PLLStream, data: char) = 
+proc llStreamWrite*(s: PLLStream, data: char) = 
   var c: char
   case s.kind
   of llsNone, llsStdIn: 
@@ -194,7 +179,7 @@ proc llStreamWrite(s: PLLStream, data: char) =
     c = data
     discard writeBuffer(s.f, addr(c), sizeof(c))
 
-proc llStreamWrite(s: PLLStream, buf: pointer, buflen: int) = 
+proc llStreamWrite*(s: PLLStream, buf: pointer, buflen: int) = 
   case s.kind
   of llsNone, llsStdIn: 
     discard
@@ -206,7 +191,7 @@ proc llStreamWrite(s: PLLStream, buf: pointer, buflen: int) =
   of llsFile: 
     discard writeBuffer(s.f, buf, buflen)
   
-proc llStreamReadAll(s: PLLStream): string = 
+proc llStreamReadAll*(s: PLLStream): string = 
   const 
     bufSize = 2048
   case s.kind
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index fa1837296..88e32404a 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2012 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -9,8 +9,8 @@
 
 # This module implements lookup helpers.
 
-import 
-  intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread, 
+import
+  intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread,
   renderer, wordrecg, idgen, nimfix.prettybase
 
 proc ensureNoMissingOrUnusedSymbols(scope: PScope)
@@ -22,7 +22,9 @@ proc considerQuotedIdent*(n: PNode): PIdent =
   of nkSym: result = n.sym.name
   of nkAccQuoted:
     case n.len
-    of 0: globalError(n.info, errIdentifierExpected, renderTree(n))
+    of 0:
+      localError(n.info, errIdentifierExpected, renderTree(n))
+      result = getIdent"<Error>"
     of 1: result = considerQuotedIdent(n.sons[0])
     else:
       var id = ""
@@ -31,12 +33,15 @@ proc considerQuotedIdent*(n: PNode): PIdent =
         case x.kind
         of nkIdent: id.add(x.ident.s)
         of nkSym: id.add(x.sym.name.s)
-        else: globalError(n.info, errIdentifierExpected, renderTree(n))
+        else:
+          localError(n.info, errIdentifierExpected, renderTree(n))
+          return getIdent"<Error>"
       result = getIdent(id)
   of nkOpenSymChoice, nkClosedSymChoice: result = n.sons[0].sym.name
   else:
-    globalError(n.info, errIdentifierExpected, renderTree(n))
- 
+    localError(n.info, errIdentifierExpected, renderTree(n))
+    result = getIdent"<Error>"
+
 template addSym*(scope: PScope, s: PSym) =
   strTableAdd(scope.symbols, s)
 
@@ -82,6 +87,16 @@ proc searchInScopes*(c: PContext, s: PIdent): PSym =
     if result != nil: return
   result = nil
 
+proc debugScopes*(c: PContext; limit=0) {.deprecated.} =
+  var i = 0
+  for scope in walkScopes(c.currentScope):
+    echo "scope ", i
+    for h in 0 .. high(scope.symbols.data):
+      if scope.symbols.data[h] != nil:
+        echo scope.symbols.data[h].name.s
+    if i == limit: break
+    inc i
+
 proc searchInScopes*(c: PContext, s: PIdent, filter: TSymKinds): PSym =
   for scope in walkScopes(c.currentScope):
     result = strTableGet(scope.symbols, s)
@@ -93,7 +108,7 @@ proc errorSym*(c: PContext, n: PNode): PSym =
   var m = n
   # ensure that 'considerQuotedIdent' can't fail:
   if m.kind == nkDotExpr: m = m.sons[1]
-  let ident = if m.kind in {nkIdent, nkSym, nkAccQuoted}: 
+  let ident = if m.kind in {nkIdent, nkSym, nkAccQuoted}:
       considerQuotedIdent(m)
     else:
       getIdent("err:" & renderTree(m))
@@ -104,11 +119,11 @@ proc errorSym*(c: PContext, n: PNode): PSym =
   if gCmd != cmdInteractive and c.inCompilesContext == 0:
     c.importTable.addSym(result)
 
-type 
-  TOverloadIterMode* = enum 
+type
+  TOverloadIterMode* = enum
     oimDone, oimNoQualifier, oimSelfModule, oimOtherModule, oimSymChoice,
     oimSymChoiceLocalLookup
-  TOverloadIter*{.final.} = object 
+  TOverloadIter*{.final.} = object
     it*: TIdentIter
     m*: PSym
     mode*: TOverloadIterMode
@@ -116,7 +131,7 @@ type
     scope*: PScope
     inSymChoice: IntSet
 
-proc getSymRepr*(s: PSym): string = 
+proc getSymRepr*(s: PSym): string =
   case s.kind
   of skProc, skMethod, skConverter, skIterators: result = getProcHeader(s)
   else: result = s.name.s
@@ -133,7 +148,7 @@ proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
       if missingImpls == 0:
         localError(s.info, errImplOfXexpected, getSymRepr(s))
       inc missingImpls
-    elif {sfUsed, sfExported} * s.flags == {} and optHints in s.options: 
+    elif {sfUsed, sfExported} * s.flags == {} and optHints in s.options:
       # BUGFIX: check options in s!
       if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}:
         # XXX: implicit type params are currently skTypes
@@ -141,11 +156,11 @@ proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
         if s.typ != nil and tfImplicitTypeParam notin s.typ.flags:
           message(s.info, hintXDeclaredButNotUsed, getSymRepr(s))
     s = nextIter(it, scope.symbols)
-  
+
 proc wrongRedefinition*(info: TLineInfo, s: string) =
   if gCmd != cmdInteractive:
     localError(info, errAttemptToRedefine, s)
-  
+
 proc addDecl*(c: PContext, sym: PSym) =
   if not c.currentScope.addUniqueSym(sym):
     wrongRedefinition(sym.info, sym.name.s)
@@ -157,27 +172,27 @@ proc addDeclAt*(scope: PScope, sym: PSym) =
   if not scope.addUniqueSym(sym):
     wrongRedefinition(sym.info, sym.name.s)
 
-proc addInterfaceDeclAux(c: PContext, sym: PSym) = 
+proc addInterfaceDeclAux(c: PContext, sym: PSym) =
   if sfExported in sym.flags:
     # add to interface:
     if c.module != nil: strTableAdd(c.module.tab, sym)
-    else: internalError(sym.info, "AddInterfaceDeclAux")
+    else: internalError(sym.info, "addInterfaceDeclAux")
 
 proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) =
   addDeclAt(scope, sym)
   addInterfaceDeclAux(c, sym)
 
 proc addOverloadableSymAt*(scope: PScope, fn: PSym) =
-  if fn.kind notin OverloadableSyms: 
+  if fn.kind notin OverloadableSyms:
     internalError(fn.info, "addOverloadableSymAt")
     return
   let check = strTableGet(scope.symbols, fn.name)
-  if check != nil and check.kind notin OverloadableSyms: 
+  if check != nil and check.kind notin OverloadableSyms:
     wrongRedefinition(fn.info, fn.name.s)
   else:
     scope.addSym(fn)
-  
-proc addInterfaceDecl*(c: PContext, sym: PSym) = 
+
+proc addInterfaceDecl*(c: PContext, sym: PSym) =
   # it adds the symbol to the interface if appropriate
   addDecl(c, sym)
   addInterfaceDeclAux(c, sym)
@@ -206,7 +221,7 @@ when defined(nimfix):
 else:
   template fixSpelling(n: PNode; ident: PIdent; op: expr) = discard
 
-proc lookUp*(c: PContext, n: PNode): PSym = 
+proc lookUp*(c: PContext, n: PNode): PSym =
   # Looks up a symbol. Generates an error in case of nil.
   case n.kind
   of nkIdent:
@@ -227,12 +242,12 @@ proc lookUp*(c: PContext, n: PNode): PSym =
   else:
     internalError(n.info, "lookUp")
     return
-  if contains(c.ambiguousSymbols, result.id): 
+  if contains(c.ambiguousSymbols, result.id):
     localError(n.info, errUseQualifier, result.name.s)
   if result.kind == skStub: loadStub(result)
-  
-type 
-  TLookupFlag* = enum 
+
+type
+  TLookupFlag* = enum
     checkAmbiguity, checkUndeclared
 
 proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
@@ -279,7 +294,7 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
   else:
     result = nil
   if result != nil and result.kind == skStub: loadStub(result)
-  
+
 proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
   case n.kind
   of nkIdent, nkAccQuoted:
@@ -296,17 +311,17 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
   of nkSym:
     result = n.sym
     o.mode = oimDone
-  of nkDotExpr: 
+  of nkDotExpr:
     o.mode = oimOtherModule
     o.m = qualifiedLookUp(c, n.sons[0])
     if o.m != nil and o.m.kind == skModule:
       var ident: PIdent = nil
-      if n.sons[1].kind == nkIdent: 
+      if n.sons[1].kind == nkIdent:
         ident = n.sons[1].ident
       elif n.sons[1].kind == nkAccQuoted:
         ident = considerQuotedIdent(n.sons[1])
-      if ident != nil: 
-        if o.m == c.module: 
+      if ident != nil:
+        if o.m == c.module:
           # a module may access its private members:
           result = initIdentIter(o.it, c.topLevelScope.symbols,
                                  ident).skipAlias(n)
@@ -314,7 +329,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
         else:
           result = initIdentIter(o.it, o.m.tab, ident).skipAlias(n)
       else:
-        localError(n.sons[1].info, errIdentifierExpected, 
+        localError(n.sons[1].info, errIdentifierExpected,
                    renderTree(n.sons[1]))
         result = errorSym(c, n.sons[1])
   of nkClosedSymChoice, nkOpenSymChoice:
@@ -332,12 +347,12 @@ proc lastOverloadScope*(o: TOverloadIter): int =
   of oimSelfModule:  result = 1
   of oimOtherModule: result = 0
   else: result = -1
-  
-proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = 
+
+proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
   case o.mode
-  of oimDone: 
+  of oimDone:
     result = nil
-  of oimNoQualifier: 
+  of oimNoQualifier:
     if o.scope != nil:
       result = nextIdentIter(o.it, o.scope.symbols).skipAlias(n)
       while result == nil:
@@ -345,13 +360,13 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
         if o.scope == nil: break
         result = initIdentIter(o.it, o.scope.symbols, o.it.name).skipAlias(n)
         # BUGFIX: o.it.name <-> n.ident
-    else: 
+    else:
       result = nil
-  of oimSelfModule: 
+  of oimSelfModule:
     result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n)
-  of oimOtherModule: 
+  of oimOtherModule:
     result = nextIdentIter(o.it, o.m.tab).skipAlias(n)
-  of oimSymChoice: 
+  of oimSymChoice:
     if o.symChoiceIndex < sonsLen(n):
       result = n.sons[o.symChoiceIndex].sym
       incl(o.inSymChoice, result.id)
@@ -374,7 +389,7 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
       if o.scope == nil: break
       result = firstIdentExcluding(o.it, o.scope.symbols,
                                    n.sons[0].sym.name, o.inSymChoice).skipAlias(n)
-  
+
   if result != nil and result.kind == skStub: loadStub(result)
 
 proc pickSym*(c: PContext, n: PNode; kind: TSymKind;
diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim
index f9f7d6432..b6b01d558 100644
--- a/compiler/lowerings.nim
+++ b/compiler/lowerings.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -13,9 +13,12 @@ const
   genPrefix* = ":tmp"         # prefix for generated names
 
 import ast, astalgo, types, idents, magicsys, msgs, options
-from guards import createMagic
 from trees import getMagic
 
+proc newDeref*(n: PNode): PNode {.inline.} =
+  result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
+  addSon(result, n)
+
 proc newTupleAccess*(tup: PNode, i: int): PNode =
   result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(
                      abstractInst).sons[i])
@@ -24,7 +27,7 @@ proc newTupleAccess*(tup: PNode, i: int): PNode =
   lit.intVal = i
   addSon(result, lit)
 
-proc addVar*(father, v: PNode) = 
+proc addVar*(father, v: PNode) =
   var vpart = newNodeI(nkIdentDefs, v.info, 3)
   vpart.sons[0] = v
   vpart.sons[1] = ast.emptyNode
@@ -51,13 +54,14 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
   incl(temp.flags, sfFromGeneric)
 
   var v = newNodeI(nkVarSection, value.info)
-  v.addVar(newSymNode(temp))
+  let tempAsNode = newSymNode(temp)
+  v.addVar(tempAsNode)
   result.add(v)
-  
-  result.add newAsgnStmt(newSymNode(temp), value)
+
+  result.add newAsgnStmt(tempAsNode, value)
   for i in 0 .. n.len-3:
     if n.sons[i].kind == nkSym: v.addVar(n.sons[i])
-    result.add newAsgnStmt(n.sons[i], newTupleAccess(value, i))
+    result.add newAsgnStmt(n.sons[i], newTupleAccess(tempAsNode, i))
 
 proc createObj*(owner: PSym, info: TLineInfo): PType =
   result = newType(tyObject, owner)
@@ -70,7 +74,7 @@ proc rawAddField*(obj: PType; field: PSym) =
   field.position = sonsLen(obj.n)
   addSon(obj.n, newSymNode(field))
 
-proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode = 
+proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode =
   # returns a[].field as a node
   assert field.kind == skField
   var deref = newNodeI(nkHiddenDeref, info)
@@ -109,7 +113,7 @@ proc newDotExpr(obj, b: PSym): PNode =
   addSon(result, newSymNode(field))
   result.typ = field.typ
 
-proc indirectAccess*(a: PNode, b: string, info: TLineInfo): PNode = 
+proc indirectAccess*(a: PNode, b: string, info: TLineInfo): PNode =
   # returns a[].b as a node
   var deref = newNodeI(nkHiddenDeref, info)
   deref.typ = a.typ.skipTypes(abstractInst).sons[0]
@@ -144,7 +148,7 @@ proc getFieldFromObj*(t: PType; v: PSym): PSym =
     if t == nil: break
     t = t.skipTypes(abstractInst)
 
-proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode = 
+proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode =
   # returns a[].b as a node
   result = indirectAccess(a, b.name.s & $b.id, info)
 
@@ -158,11 +162,11 @@ proc genAddrOf*(n: PNode): PNode =
   result.typ.rawAddSon(n.typ)
 
 proc genDeref*(n: PNode): PNode =
-  result = newNodeIT(nkHiddenDeref, n.info, 
+  result = newNodeIT(nkHiddenDeref, n.info,
                      n.typ.skipTypes(abstractInst).sons[0])
   result.add n
 
-proc callCodegenProc*(name: string, arg1: PNode; 
+proc callCodegenProc*(name: string, arg1: PNode;
                       arg2, arg3: PNode = nil): PNode =
   result = newNodeI(nkCall, arg1.info)
   let sym = magicsys.getCompilerProc(name)
@@ -203,6 +207,17 @@ proc flowVarKind(t: PType): TFlowVarKind =
   elif containsGarbageCollectedRef(t): fvInvalid
   else: fvBlob
 
+proc typeNeedsNoDeepCopy(t: PType): bool =
+  var t = t.skipTypes(abstractInst)
+  # for the tconvexhull example (and others) we're a bit lax here and pretend
+  # seqs and strings are *by value* only and 'shallow' doesn't exist!
+  if t.kind == tyString: return true
+  # note that seq[T] is fine, but 'var seq[T]' is not, so we need to skip 'var'
+  # for the stricter check and likewise we can skip 'seq' for a less
+  # strict check:
+  if t.kind in {tyVar, tySequence}: t = t.sons[0]
+  result = not containsGarbageCollectedRef(t)
+
 proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
                  v: PNode; useShallowCopy=false): PSym =
   result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info)
@@ -215,7 +230,7 @@ proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
   vpart.sons[2] = if varInit.isNil: v else: ast.emptyNode
   varSection.add vpart
   if varInit != nil:
-    if useShallowCopy:
+    if useShallowCopy and typeNeedsNoDeepCopy(typ):
       varInit.add newFastAsgnStmt(newSymNode(result), v)
     else:
       let deepCopyCall = newNodeI(nkCall, varInit.info, 3)
@@ -236,10 +251,10 @@ proc f_wrapper(thread, args) =
 
   fv.owner = thread # optional
   nimArgsPassingDone() # signal parent that the work is done
-  # 
+  #
   args.fv.blob = f(a, b, ...)
   nimFlowVarSignal(args.fv)
-  
+
   # - or -
   f(a, b, ...)
   barrierLeave(args.barrier)  # for parallel statement
@@ -261,7 +276,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
   var threadLocalBarrier: PSym
   if barrier != nil:
     var varSection2 = newNodeI(nkVarSection, barrier.info)
-    threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner, 
+    threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner,
                                      barrier.typ, barrier)
     body.add varSection2
     body.add callCodegenProc("barrierEnter", threadLocalBarrier.newSymNode)
@@ -285,7 +300,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
   elif fv != nil:
     let fk = fv.typ.sons[1].flowVarKind
     if fk == fvInvalid:
-      localError(f.info, "cannot create a flowVar of type: " & 
+      localError(f.info, "cannot create a flowVar of type: " &
         typeToString(fv.typ.sons[1]))
     body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
       if fk == fvGC: "data" else: "blob", fv.info), call)
@@ -330,8 +345,8 @@ proc createCastExpr(argsParam: PSym; objType: PType): PNode =
   result.typ = newType(tyPtr, objType.owner)
   result.typ.rawAddSon(objType)
 
-proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym, 
-                             castExpr, call, 
+proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym,
+                             castExpr, call,
                              varSection, varInit, result: PNode) =
   let formals = n[0].typ.n
   let tmpName = getIdent(genPrefix)
@@ -371,11 +386,11 @@ proc getRoot*(n: PNode): PSym =
     if getMagic(n) == mSlice: result = getRoot(n.sons[1])
   else: discard
 
-proc newIntLit(value: BiggestInt): PNode =
+proc newIntLit*(value: BiggestInt): PNode =
   result = nkIntLit.newIntNode(value)
   result.typ = getSysType(tyInt)
 
-proc genHigh(n: PNode): PNode =
+proc genHigh*(n: PNode): PNode =
   if skipTypes(n.typ, abstractVar).kind in {tyArrayConstr, tyArray}:
     result = newIntLit(lastOrd(skipTypes(n.typ, abstractVar)))
   else:
@@ -385,7 +400,7 @@ proc genHigh(n: PNode): PNode =
     result.sons[1] = n
 
 proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
-                             castExpr, call, 
+                             castExpr, call,
                              varSection, varInit, result: PNode) =
   let formals = n[0].typ.n
   let tmpName = getIdent(genPrefix)
@@ -409,7 +424,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
       var fieldB = newSym(skField, tmpName, objType.owner, n.info)
       fieldB.typ = getSysType(tyInt)
       objType.addField(fieldB)
-      
+
       if getMagic(n) == mSlice:
         let a = genAddrOf(n[1])
         field.typ = a.typ
@@ -464,7 +479,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
                                     useShallowCopy=true)
       call.add(threadLocal.newSymNode)
 
-proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; 
+proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
                        barrier, dest: PNode = nil): PNode =
   # if 'barrier' != nil, then it is in a 'parallel' section and we
   # generate quite different code
@@ -530,10 +545,10 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
   var varSection = newNodeI(nkVarSection, n.info)
   var varInit = newNodeI(nkStmtList, n.info)
   if barrier.isNil:
-    setupArgsForConcurrency(n, objType, scratchObj, castExpr, call, 
+    setupArgsForConcurrency(n, objType, scratchObj, castExpr, call,
                             varSection, varInit, result)
   else:
-    setupArgsForParallelism(n, objType, scratchObj, castExpr, call, 
+    setupArgsForParallelism(n, objType, scratchObj, castExpr, call,
                             varSection, varInit, result)
 
   var barrierAsExpr: PNode = nil
@@ -566,7 +581,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
     fvAsExpr = indirectAccess(castExpr, field, n.info)
     result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest))
 
-  let wrapper = createWrapperProc(fn, threadParam, argsParam, 
+  let wrapper = createWrapperProc(fn, threadParam, argsParam,
                                   varSection, varInit, call,
                                   barrierAsExpr, fvAsExpr, spawnKind)
   result.add callCodegenProc("nimSpawn", wrapper.newSymNode,
diff --git a/compiler/main.nim b/compiler/main.nim
index 82e55058c..0c80c19b7 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -19,12 +19,6 @@ import
 
 from magicsys import systemModule, resetSysTypes
 
-const
-  hasLLVM_Backend = false
-
-when hasLLVM_Backend:
-  import llvmgen
-
 proc rodPass =
   if optSymbolFiles in gGlobalOptions:
     registerPass(rodwritePass)
@@ -60,20 +54,16 @@ proc commandDoc2 =
   finishDoc2Pass(gProjectName)
 
 proc commandCompileToC =
+  extccomp.initVars()
   semanticPasses()
   registerPass(cgenPass)
   rodPass()
   #registerPass(cleanupPass())
-  if optCaasEnabled in gGlobalOptions:
-    # echo "BEFORE CHECK DEP"
-    # discard checkDepMem(gProjectMainIdx)
-    # echo "CHECK DEP COMPLETE"
-    discard
 
   compileProject()
   cgenWriteModules()
   if gCmd != cmdRun:
-    extccomp.callCCompiler(changeFileExt(gProjectFull, ""))
+    extccomp.callCCompiler(if gProjectName == "-": "stdinfile" else: changeFileExt(gProjectFull, ""))
 
   if isServing:
     # caas will keep track only of the compilation commands
@@ -111,14 +101,6 @@ proc commandCompileToC =
     ccgutils.resetCaches()
     GC_fullCollect()
 
-when hasLLVM_Backend:
-  proc commandCompileToLLVM =
-    semanticPasses()
-    registerPass(llvmgen.llvmgenPass())
-    rodPass()
-    #registerPass(cleanupPass())
-    compileProject()
-
 proc commandCompileToJS =
   #incl(gGlobalOptions, optSafeCode)
   setTarget(osJS, cpuJS)
@@ -188,20 +170,18 @@ proc commandSuggest =
     # cache in a state where "no recompilation is necessary", but the
     # cgen pass was never executed at all.
     commandCompileToC()
-    if gDirtyBufferIdx != 0:
-      discard compileModule(gDirtyBufferIdx, {sfDirty})
-      resetModule(gDirtyBufferIdx)
-    if optDef in gGlobalOptions:
-      defFromSourceMap(optTrackPos)
+    let gDirtyBufferIdx = gTrackPos.fileIndex
+    discard compileModule(gDirtyBufferIdx, {sfDirty})
+    resetModule(gDirtyBufferIdx)
   else:
     msgs.gErrorMax = high(int)  # do not stop after first error
     semanticPasses()
     rodPass()
     # XXX: this handles the case when the dirty buffer is the main file,
     # but doesn't handle the case when it's imported module
-    var projFile = if gProjectMainIdx == gDirtyOriginalIdx: gDirtyBufferIdx
-                   else: gProjectMainIdx
-    compileProject(projFile)
+    #var projFile = if gProjectMainIdx == gDirtyOriginalIdx: gDirtyBufferIdx
+    #               else: gProjectMainIdx
+    compileProject() #(projFile)
 
 proc resetMemory =
   resetCompilationLists()
@@ -232,7 +212,6 @@ proc resetMemory =
   # rodread.gMods
 
   # !! ropes.cache
-  # semthreads.computed?
   #
   # suggest.usageSym
   #
@@ -273,7 +252,6 @@ proc mainCommand* =
     commandCompileToC()
   of "cpp", "compiletocpp":
     gCmd = cmdCompileToCpp
-    if cCompiler == ccGcc: setCC("gcc")
     defineSymbol("cpp")
     commandCompileToC()
   of "objc", "compiletooc":
@@ -290,12 +268,6 @@ proc mainCommand* =
   of "js", "compiletojs":
     gCmd = cmdCompileToJS
     commandCompileToJS()
-  of "compiletollvm":
-    gCmd = cmdCompileToLLVM
-    when hasLLVM_Backend:
-      CommandCompileToLLVM()
-    else:
-      rawMessage(errInvalidCommandX, command)
   of "doc":
     wantMainModule()
     gCmd = cmdDoc
@@ -392,7 +364,9 @@ proc mainCommand* =
       gVerbosity > 0):
     rawMessage(hintSuccessX, [$gLinesCompiled,
                formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3),
-               formatSize(getTotalMem())])
+               formatSize(getTotalMem()),
+               if condSyms.isDefined("release"): "Release Build"
+               else: "Debug Build"])
 
   when PrintRopeCacheStats:
     echo "rope cache stats: "
diff --git a/compiler/modules.nim b/compiler/modules.nim
index 05b795473..a2b739efc 100644
--- a/compiler/modules.nim
+++ b/compiler/modules.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -34,9 +34,6 @@ proc getModule(fileIdx: int32): PSym =
   if fileIdx >= 0 and fileIdx < gCompiledModules.len:
     result = gCompiledModules[fileIdx]
 
-template compiledAt(x: PSym): expr =
-  gMemCacheData[x.position].compiledAt
-
 template crc(x: PSym): expr =
   gMemCacheData[x.position].crc
 
@@ -74,10 +71,12 @@ proc addDep(x: PSym, dep: int32) =
 
 proc resetModule*(fileIdx: int32) =
   # echo "HARD RESETTING ", fileIdx.toFilename
-  gMemCacheData[fileIdx].needsRecompile = Yes
-  gCompiledModules[fileIdx] = nil
-  cgendata.gModules[fileIdx] = nil
-  resetSourceMap(fileIdx)
+  if fileIdx <% gMemCacheData.len:
+    gMemCacheData[fileIdx].needsRecompile = Yes
+  if fileIdx <% gCompiledModules.len:
+    gCompiledModules[fileIdx] = nil
+  if fileIdx <% cgendata.gModules.len:
+    cgendata.gModules[fileIdx] = nil
 
 proc resetAllModules* =
   for i in 0..gCompiledModules.high:
@@ -117,7 +116,7 @@ proc newModule(fileIdx: int32): PSym =
   result.kind = skModule
   let filename = fileIdx.toFullPath
   result.name = getIdent(splitFile(filename).name)
-  if not isNimIdentifier(result.name.s):
+  if result.name.s != "-" and not isNimIdentifier(result.name.s):
     rawMessage(errInvalidModuleName, result.name.s)
   
   result.info = newLineInfo(fileIdx, 1, 1)
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 7f4f81dd0..041a181be 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -10,98 +10,95 @@
 import
   options, strutils, os, tables, ropes, platform
 
-when useCaas:
-  import sockets
-
-type 
-  TMsgKind* = enum 
-    errUnknown, errIllFormedAstX, errInternal, errCannotOpenFile, errGenerated, 
-    errXCompilerDoesNotSupportCpp, errStringLiteralExpected, 
-    errIntLiteralExpected, errInvalidCharacterConstant, 
-    errClosingTripleQuoteExpected, errClosingQuoteExpected, 
-    errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong, 
-    errInvalidNumber, errNumberOutOfRange, errNnotAllowedInCharacter, 
-    errClosingBracketExpected, errMissingFinalQuote, errIdentifierExpected, 
+type
+  TMsgKind* = enum
+    errUnknown, errIllFormedAstX, errInternal, errCannotOpenFile, errGenerated,
+    errXCompilerDoesNotSupportCpp, errStringLiteralExpected,
+    errIntLiteralExpected, errInvalidCharacterConstant,
+    errClosingTripleQuoteExpected, errClosingQuoteExpected,
+    errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong,
+    errInvalidNumber, errNumberOutOfRange, errNnotAllowedInCharacter,
+    errClosingBracketExpected, errMissingFinalQuote, errIdentifierExpected,
     errNewlineExpected,
     errInvalidModuleName,
-    errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected, 
-    errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected, 
-    errInvalidPragma, errUnknownPragma, errInvalidDirectiveX, 
-    errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation, 
-    errExceptionExpected, errExceptionAlreadyHandled, 
-    errYieldNotAllowedHere, errYieldNotAllowedInTryStmt, 
-    errInvalidNumberOfYieldExpr, errCannotReturnExpr, errAttemptToRedefine, 
-    errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel, 
-    errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected, 
-    errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler, 
-    errOnOrOffExpectedButXFound, errNoneBoehmRefcExpectedButXFound, 
-    errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound, 
-    errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound, 
-    errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected, 
-    errExprExpected, errUndeclaredIdentifier, errUseQualifier, errTypeExpected, 
-    errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable, 
-    errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue, 
-    errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous, 
-    errConstantDivisionByZero, errOrdinalTypeExpected, 
-    errOrdinalOrFloatTypeExpected, errOverOrUnderflow, 
-    errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255, 
-    errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess, 
-    errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType, 
-    errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit, 
-    errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType, 
-    errCastNotInSafeMode, errExprCannotBeCastedToX, errCommaOrParRiExpected, 
-    errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected, 
-    errMagicOnlyInSystem, errPowerOfTwoExpected, 
-    errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv, 
-    errSymbolMustBeImported, errExprMustBeBool, errConstExprExpected, 
-    errDuplicateCaseLabel, errRangeIsEmpty, errSelectorMustBeOfCertainTypes, 
-    errSelectorMustBeOrdinal, errOrdXMustNotBeNegative, errLenXinvalid, 
-    errWrongNumberOfVariables, errExprCannotBeRaised, errBreakOnlyInLoop, 
-    errTypeXhasUnknownSize, errConstNeedsConstExpr, errConstNeedsValue, 
-    errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig, 
-    errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects, 
-    errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX, 
+    errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected,
+    errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected,
+    errInvalidPragma, errUnknownPragma, errInvalidDirectiveX,
+    errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation,
+    errExceptionExpected, errExceptionAlreadyHandled,
+    errYieldNotAllowedHere, errYieldNotAllowedInTryStmt,
+    errInvalidNumberOfYieldExpr, errCannotReturnExpr, errAttemptToRedefine,
+    errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel,
+    errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected,
+    errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler,
+    errOnOrOffExpectedButXFound, errNoneBoehmRefcExpectedButXFound,
+    errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound,
+    errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound,
+    errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected,
+    errExprExpected, errUndeclaredIdentifier, errUseQualifier, errTypeExpected,
+    errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable,
+    errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue,
+    errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous,
+    errConstantDivisionByZero, errOrdinalTypeExpected,
+    errOrdinalOrFloatTypeExpected, errOverOrUnderflow,
+    errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255,
+    errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess,
+    errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType,
+    errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit,
+    errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType,
+    errCastNotInSafeMode, errExprCannotBeCastedToX, errCommaOrParRiExpected,
+    errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected,
+    errMagicOnlyInSystem, errPowerOfTwoExpected,
+    errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv,
+    errSymbolMustBeImported, errExprMustBeBool, errConstExprExpected,
+    errDuplicateCaseLabel, errRangeIsEmpty, errSelectorMustBeOfCertainTypes,
+    errSelectorMustBeOrdinal, errOrdXMustNotBeNegative, errLenXinvalid,
+    errWrongNumberOfVariables, errExprCannotBeRaised, errBreakOnlyInLoop,
+    errTypeXhasUnknownSize, errConstNeedsConstExpr, errConstNeedsValue,
+    errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig,
+    errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects,
+    errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX,
     errCannotInstantiateX, errExprHasNoAddress, errXStackEscape,
-    errVarForOutParamNeeded, 
-    errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX, 
-    errAmbiguousCallXYZ, errWrongNumberOfArguments, 
-    errXCannotBePassedToProcVar, 
-    errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed, 
-    errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX, 
-    errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice, 
+    errVarForOutParamNeeded,
+    errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX,
+    errAmbiguousCallXYZ, errWrongNumberOfArguments,
+    errXCannotBePassedToProcVar,
+    errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed,
+    errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
+    errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
     errInvalidOrderInArrayConstructor,
-    errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry, 
-    errOptionExpected, errXisNoLabel, errNotAllCasesCovered, 
-    errUnkownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable, 
-    errNoPragmasAllowedForX, errNoGenericParamsAllowedForX, 
-    errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent, 
-    errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX, 
+    errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,
+    errOptionExpected, errXisNoLabel, errNotAllCasesCovered,
+    errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable,
+    errNoPragmasAllowedForX, errNoGenericParamsAllowedForX,
+    errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent,
+    errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX,
     errXNotAllowedHere, errInvalidControlFlowX,
-    errXisNoType, errCircumNeedsPointer, errInvalidExpression, 
-    errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected, 
-    errNamedExprNotAllowed, errXExpectsOneTypeParam, 
-    errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed, 
-    errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType, 
+    errXisNoType, errCircumNeedsPointer, errInvalidExpression,
+    errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected,
+    errNamedExprNotAllowed, errXExpectsOneTypeParam,
+    errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed,
+    errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType,
     errNoReturnTypeDeclared,
-    errInvalidCommandX, errXOnlyAtModuleScope, 
+    errInvalidCommandX, errXOnlyAtModuleScope,
     errXNeedsParamObjectType,
-    errTemplateInstantiationTooNested, errInstantiationFrom, 
+    errTemplateInstantiationTooNested, errInstantiationFrom,
     errInvalidIndexValueForTuple, errCommandExpectsFilename,
     errMainModuleMustBeSpecified,
     errXExpected,
     errTIsNotAConcreteType,
-    errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError, 
-    errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile, 
-    errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely,
+    errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
+    errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
+    errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly,
     errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
     errMacroBodyDependsOnGenericTypes,
     errDestructorNotGenericEnough,
     errInlineIteratorsAsProcParams,
     errXExpectsTwoArguments,
-    errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations, 
-    errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX, 
-    errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument, 
-    errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate, 
+    errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations,
+    errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,
+    errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,
+    errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,
     errXhasSideEffects, errIteratorExpected, errLetNeedsInit,
     errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX,
     errXCannotBeClosure, errXMustBeCompileTime,
@@ -110,17 +107,18 @@ type
     errGenericLambdaNotAllowed,
     errCompilerDoesntSupportTarget,
     errUser,
-    warnCannotOpenFile, 
-    warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit, 
+    warnCannotOpenFile,
+    warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
     warnDeprecated, warnConfigDeprecated,
-    warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel, 
+    warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
     warnUnknownSubstitutionX, warnLanguageXNotSupported,
-    warnFieldXNotSupported, warnCommentXIgnored, 
-    warnNilStatement, warnAnalysisLoophole,
+    warnFieldXNotSupported, warnCommentXIgnored,
+    warnNilStatement, warnTypelessParam,
     warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
-    warnEachIdentIsTuple, warnShadowIdent, 
+    warnEachIdentIsTuple, warnShadowIdent,
     warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
-    warnUninit, warnGcMem, warnLockLevel, warnUser,
+    warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
+    warnUser,
     hintSuccess, hintSuccessX,
     hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
     hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
@@ -128,233 +126,233 @@ type
     hintConditionAlwaysTrue, hintName, hintPattern,
     hintUser
 
-const 
+const
   MsgKindToStr*: array[TMsgKind, string] = [
-    errUnknown: "unknown error", 
+    errUnknown: "unknown error",
     errIllFormedAstX: "illformed AST: $1",
-    errInternal: "internal error: $1", 
-    errCannotOpenFile: "cannot open \'$1\'", 
-    errGenerated: "$1", 
-    errXCompilerDoesNotSupportCpp: "\'$1\' compiler does not support C++", 
-    errStringLiteralExpected: "string literal expected", 
-    errIntLiteralExpected: "integer literal expected", 
-    errInvalidCharacterConstant: "invalid character constant", 
-    errClosingTripleQuoteExpected: "closing \"\"\" expected, but end of file reached", 
-    errClosingQuoteExpected: "closing \" expected", 
-    errTabulatorsAreNotAllowed: "tabulators are not allowed", 
-    errInvalidToken: "invalid token: $1", 
-    errLineTooLong: "line too long", 
-    errInvalidNumber: "$1 is not a valid number", 
-    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 \' for character literal", 
-    errIdentifierExpected: "identifier expected, but found \'$1\'", 
+    errInternal: "internal error: $1",
+    errCannotOpenFile: "cannot open \'$1\'",
+    errGenerated: "$1",
+    errXCompilerDoesNotSupportCpp: "\'$1\' compiler does not support C++",
+    errStringLiteralExpected: "string literal expected",
+    errIntLiteralExpected: "integer literal expected",
+    errInvalidCharacterConstant: "invalid character constant",
+    errClosingTripleQuoteExpected: "closing \"\"\" expected, but end of file reached",
+    errClosingQuoteExpected: "closing \" expected",
+    errTabulatorsAreNotAllowed: "tabulators are not allowed",
+    errInvalidToken: "invalid token: $1",
+    errLineTooLong: "line too long",
+    errInvalidNumber: "$1 is not a valid number",
+    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 \' for character literal",
+    errIdentifierExpected: "identifier expected, but found \'$1\'",
     errNewlineExpected: "newline expected, but found \'$1\'",
     errInvalidModuleName: "invalid module name: '$1'",
-    errOperatorExpected: "operator expected, but found \'$1\'", 
-    errTokenExpected: "\'$1\' expected", 
-    errStringAfterIncludeExpected: "string after \'include\' expected", 
-    errRecursiveDependencyX: "recursive dependency: \'$1\'", 
-    errOnOrOffExpected: "\'on\' or \'off\' expected", 
-    errNoneSpeedOrSizeExpected: "\'none\', \'speed\' or \'size\' expected", 
-    errInvalidPragma: "invalid pragma", 
-    errUnknownPragma: "unknown pragma: \'$1\'", 
-    errInvalidDirectiveX: "invalid directive: \'$1\'", 
-    errAtPopWithoutPush: "\'pop\' without a \'push\' pragma", 
-    errEmptyAsm: "empty asm statement", 
-    errInvalidIndentation: "invalid indentation", 
-    errExceptionExpected: "exception expected", 
-    errExceptionAlreadyHandled: "exception already handled", 
+    errOperatorExpected: "operator expected, but found \'$1\'",
+    errTokenExpected: "\'$1\' expected",
+    errStringAfterIncludeExpected: "string after \'include\' expected",
+    errRecursiveDependencyX: "recursive dependency: \'$1\'",
+    errOnOrOffExpected: "\'on\' or \'off\' expected",
+    errNoneSpeedOrSizeExpected: "\'none\', \'speed\' or \'size\' expected",
+    errInvalidPragma: "invalid pragma",
+    errUnknownPragma: "unknown pragma: \'$1\'",
+    errInvalidDirectiveX: "invalid directive: \'$1\'",
+    errAtPopWithoutPush: "\'pop\' without a \'push\' pragma",
+    errEmptyAsm: "empty asm statement",
+    errInvalidIndentation: "invalid indentation",
+    errExceptionExpected: "exception expected",
+    errExceptionAlreadyHandled: "exception already handled",
     errYieldNotAllowedHere: "'yield' only allowed in an iterator",
     errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator",
-    errInvalidNumberOfYieldExpr: "invalid number of \'yield\' expressions", 
-    errCannotReturnExpr: "current routine cannot return an expression", 
-    errAttemptToRedefine: "redefinition of \'$1\'", 
-    errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\', \'raise\' or \'continue'", 
-    errStmtExpected: "statement expected", 
-    errInvalidLabel: "\'$1\' is no label", 
-    errInvalidCmdLineOption: "invalid command line option: \'$1\'", 
-    errCmdLineArgExpected: "argument for command line option expected: \'$1\'", 
-    errCmdLineNoArgExpected: "invalid argument for command line option: \'$1\'", 
-    errInvalidVarSubstitution: "invalid variable substitution in \'$1\'", 
-    errUnknownVar: "unknown variable: \'$1\'", 
-    errUnknownCcompiler: "unknown C compiler: \'$1\'", 
-    errOnOrOffExpectedButXFound: "\'on\' or \'off\' expected, but \'$1\' found", 
-    errNoneBoehmRefcExpectedButXFound: "'none', 'boehm' or 'refc' expected, but '$1' found", 
-    errNoneSpeedOrSizeExpectedButXFound: "'none', 'speed' or 'size' expected, but '$1' found", 
-    errGuiConsoleOrLibExpectedButXFound: "'gui', 'console' or 'lib' expected, but '$1' found", 
-    errUnknownOS: "unknown OS: '$1'", 
-    errUnknownCPU: "unknown CPU: '$1'", 
-    errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found", 
-    errArgsNeedRunOption: "arguments can only be given if the '--run' option is selected", 
-    errInvalidMultipleAsgn: "multiple assignment is not allowed", 
-    errColonOrEqualsExpected: "\':\' or \'=\' expected, but found \'$1\'", 
-    errExprExpected: "expression expected, but found \'$1\'", 
-    errUndeclaredIdentifier: "undeclared identifier: \'$1\'", 
-    errUseQualifier: "ambiguous identifier: \'$1\' -- use a qualifier", 
-    errTypeExpected: "type expected", 
-    errSystemNeeds: "system module needs \'$1\'", 
-    errExecutionOfProgramFailed: "execution of an external program failed", 
-    errNotOverloadable: "overloaded \'$1\' leads to ambiguous calls", 
-    errInvalidArgForX: "invalid argument for \'$1\'", 
-    errStmtHasNoEffect: "statement has no effect", 
-    errXExpectsTypeOrValue: "\'$1\' expects a type or value", 
-    errXExpectsArrayType: "\'$1\' expects an array type", 
-    errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet", 
-    errExprXAmbiguous: "expression '$1' ambiguous in this context", 
-    errConstantDivisionByZero: "division by zero", 
-    errOrdinalTypeExpected: "ordinal type expected", 
-    errOrdinalOrFloatTypeExpected: "ordinal or float type expected", 
-    errOverOrUnderflow: "over- or underflow", 
-    errCannotEvalXBecauseIncompletelyDefined: "cannot evalutate '$1' because type is not defined completely", 
-    errChrExpectsRange0_255: "\'chr\' expects an int in the range 0..255", 
-    errDynlibRequiresExportc: "\'dynlib\' requires \'exportc\'", 
-    errUndeclaredFieldX: "undeclared field: \'$1\'", 
+    errInvalidNumberOfYieldExpr: "invalid number of \'yield\' expressions",
+    errCannotReturnExpr: "current routine cannot return an expression",
+    errAttemptToRedefine: "redefinition of \'$1\'",
+    errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\', \'raise\' or \'continue'",
+    errStmtExpected: "statement expected",
+    errInvalidLabel: "\'$1\' is no label",
+    errInvalidCmdLineOption: "invalid command line option: \'$1\'",
+    errCmdLineArgExpected: "argument for command line option expected: \'$1\'",
+    errCmdLineNoArgExpected: "invalid argument for command line option: \'$1\'",
+    errInvalidVarSubstitution: "invalid variable substitution in \'$1\'",
+    errUnknownVar: "unknown variable: \'$1\'",
+    errUnknownCcompiler: "unknown C compiler: \'$1\'",
+    errOnOrOffExpectedButXFound: "\'on\' or \'off\' expected, but \'$1\' found",
+    errNoneBoehmRefcExpectedButXFound: "'none', 'boehm' or 'refc' expected, but '$1' found",
+    errNoneSpeedOrSizeExpectedButXFound: "'none', 'speed' or 'size' expected, but '$1' found",
+    errGuiConsoleOrLibExpectedButXFound: "'gui', 'console' or 'lib' expected, but '$1' found",
+    errUnknownOS: "unknown OS: '$1'",
+    errUnknownCPU: "unknown CPU: '$1'",
+    errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found",
+    errArgsNeedRunOption: "arguments can only be given if the '--run' option is selected",
+    errInvalidMultipleAsgn: "multiple assignment is not allowed",
+    errColonOrEqualsExpected: "\':\' or \'=\' expected, but found \'$1\'",
+    errExprExpected: "expression expected, but found \'$1\'",
+    errUndeclaredIdentifier: "undeclared identifier: \'$1\'",
+    errUseQualifier: "ambiguous identifier: \'$1\' -- use a qualifier",
+    errTypeExpected: "type expected",
+    errSystemNeeds: "system module needs \'$1\'",
+    errExecutionOfProgramFailed: "execution of an external program failed",
+    errNotOverloadable: "overloaded \'$1\' leads to ambiguous calls",
+    errInvalidArgForX: "invalid argument for \'$1\'",
+    errStmtHasNoEffect: "statement has no effect",
+    errXExpectsTypeOrValue: "\'$1\' expects a type or value",
+    errXExpectsArrayType: "\'$1\' expects an array type",
+    errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet",
+    errExprXAmbiguous: "expression '$1' ambiguous in this context",
+    errConstantDivisionByZero: "division by zero",
+    errOrdinalTypeExpected: "ordinal type expected",
+    errOrdinalOrFloatTypeExpected: "ordinal or float type expected",
+    errOverOrUnderflow: "over- or underflow",
+    errCannotEvalXBecauseIncompletelyDefined: "cannot evalutate '$1' because type is not defined completely",
+    errChrExpectsRange0_255: "\'chr\' expects an int in the range 0..255",
+    errDynlibRequiresExportc: "\'dynlib\' requires \'exportc\'",
+    errUndeclaredFieldX: "undeclared field: \'$1\'",
     errNilAccess: "attempt to access a nil address",
-    errIndexOutOfBounds: "index out of bounds", 
-    errIndexTypesDoNotMatch: "index types do not match", 
-    errBracketsInvalidForType: "\'[]\' operator invalid for this type", 
-    errValueOutOfSetBounds: "value out of set bounds", 
-    errFieldInitTwice: "field initialized twice: \'$1\'", 
-    errFieldNotInit: "field \'$1\' not initialized", 
-    errExprXCannotBeCalled: "expression \'$1\' cannot be called", 
-    errExprHasNoType: "expression has no type", 
-    errExprXHasNoType: "expression \'$1\' has no type (or is ambiguous)", 
+    errIndexOutOfBounds: "index out of bounds",
+    errIndexTypesDoNotMatch: "index types do not match",
+    errBracketsInvalidForType: "\'[]\' operator invalid for this type",
+    errValueOutOfSetBounds: "value out of set bounds",
+    errFieldInitTwice: "field initialized twice: \'$1\'",
+    errFieldNotInit: "field \'$1\' not initialized",
+    errExprXCannotBeCalled: "expression \'$1\' cannot be called",
+    errExprHasNoType: "expression has no type",
+    errExprXHasNoType: "expression \'$1\' has no type (or is ambiguous)",
     errCastNotInSafeMode: "\'cast\' not allowed in safe mode",
-    errExprCannotBeCastedToX: "expression cannot be casted to $1", 
-    errCommaOrParRiExpected: "',' or ')' expected", 
-    errCurlyLeOrParLeExpected: "\'{\' or \'(\' expected", 
-    errSectionExpected: "section (\'type\', \'proc\', etc.) expected", 
-    errRangeExpected: "range expected", 
-    errMagicOnlyInSystem: "\'magic\' only allowed in system module", 
+    errExprCannotBeCastedToX: "expression cannot be casted to $1",
+    errCommaOrParRiExpected: "',' or ')' expected",
+    errCurlyLeOrParLeExpected: "\'{\' or \'(\' expected",
+    errSectionExpected: "section (\'type\', \'proc\', etc.) expected",
+    errRangeExpected: "range expected",
+    errMagicOnlyInSystem: "\'magic\' only allowed in system module",
     errPowerOfTwoExpected: "power of two expected",
-    errStringMayNotBeEmpty: "string literal may not be empty", 
-    errCallConvExpected: "calling convention expected", 
-    errProcOnlyOneCallConv: "a proc can only have one calling convention", 
-    errSymbolMustBeImported: "symbol must be imported if 'lib' pragma is used", 
-    errExprMustBeBool: "expression must be of type 'bool'", 
-    errConstExprExpected: "constant expression expected", 
-    errDuplicateCaseLabel: "duplicate case label", 
-    errRangeIsEmpty: "range is empty", 
-    errSelectorMustBeOfCertainTypes: "selector must be of an ordinal type, float or string", 
-    errSelectorMustBeOrdinal: "selector must be of an ordinal type", 
-    errOrdXMustNotBeNegative: "ord($1) must not be negative", 
+    errStringMayNotBeEmpty: "string literal may not be empty",
+    errCallConvExpected: "calling convention expected",
+    errProcOnlyOneCallConv: "a proc can only have one calling convention",
+    errSymbolMustBeImported: "symbol must be imported if 'lib' pragma is used",
+    errExprMustBeBool: "expression must be of type 'bool'",
+    errConstExprExpected: "constant expression expected",
+    errDuplicateCaseLabel: "duplicate case label",
+    errRangeIsEmpty: "range is empty",
+    errSelectorMustBeOfCertainTypes: "selector must be of an ordinal type, float or string",
+    errSelectorMustBeOrdinal: "selector must be of an ordinal type",
+    errOrdXMustNotBeNegative: "ord($1) must not be negative",
     errLenXinvalid: "len($1) must be less than 32768",
-    errWrongNumberOfVariables: "wrong number of variables", 
-    errExprCannotBeRaised: "only a 'ref object' can be raised", 
-    errBreakOnlyInLoop: "'break' only allowed in loop construct", 
-    errTypeXhasUnknownSize: "type \'$1\' has unknown size", 
-    errConstNeedsConstExpr: "a constant can only be initialized with a constant expression", 
-    errConstNeedsValue: "a constant needs a value", 
-    errResultCannotBeOpenArray: "the result type cannot be on open array", 
-    errSizeTooBig: "computing the type\'s size produced an overflow", 
-    errSetTooBig: "set is too large", 
-    errBaseTypeMustBeOrdinal: "base type of a set must be an ordinal", 
-    errInheritanceOnlyWithNonFinalObjects: "inheritance only works with non-final objects", 
+    errWrongNumberOfVariables: "wrong number of variables",
+    errExprCannotBeRaised: "only a 'ref object' can be raised",
+    errBreakOnlyInLoop: "'break' only allowed in loop construct",
+    errTypeXhasUnknownSize: "type \'$1\' has unknown size",
+    errConstNeedsConstExpr: "a constant can only be initialized with a constant expression",
+    errConstNeedsValue: "a constant needs a value",
+    errResultCannotBeOpenArray: "the result type cannot be on open array",
+    errSizeTooBig: "computing the type\'s size produced an overflow",
+    errSetTooBig: "set is too large",
+    errBaseTypeMustBeOrdinal: "base type of a set must be an ordinal",
+    errInheritanceOnlyWithNonFinalObjects: "inheritance only works with 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", 
+    errIllegalRecursionInTypeX: "illegal recursion in type \'$1\'",
+    errCannotInstantiateX: "cannot instantiate: \'$1\'",
+    errExprHasNoAddress: "expression has no address",
     errXStackEscape: "address of '$1' may not escape its stack frame",
     errVarForOutParamNeeded: "for a \'var\' type a variable needs to be passed",
-    errPureTypeMismatch: "type mismatch", 
-    errTypeMismatch: "type mismatch: got (", 
+    errPureTypeMismatch: "type mismatch",
+    errTypeMismatch: "type mismatch: got (",
     errButExpected: "but expected one of: ",
-    errButExpectedX: "but expected \'$1\'", 
-    errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3", 
-    errWrongNumberOfArguments: "wrong number of arguments", 
-    errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar", 
-    errXCannotBeInParamDecl: "$1 cannot be declared in parameter declaration", 
-    errPragmaOnlyInHeaderOfProc: "pragmas are only allowed in the header of a proc", 
-    errImplOfXNotAllowed: "implementation of \'$1\' is not allowed", 
-    errImplOfXexpected: "implementation of \'$1\' expected", 
-    errNoSymbolToBorrowFromFound: "no symbol to borrow from found", 
-    errDiscardValueX: "value of type '$1' has to be discarded", 
-    errInvalidDiscard: "statement returns no value that can be discarded", 
+    errButExpectedX: "but expected \'$1\'",
+    errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3",
+    errWrongNumberOfArguments: "wrong number of arguments",
+    errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar",
+    errXCannotBeInParamDecl: "$1 cannot be declared in parameter declaration",
+    errPragmaOnlyInHeaderOfProc: "pragmas are only allowed in the header of a proc",
+    errImplOfXNotAllowed: "implementation of \'$1\' is not allowed",
+    errImplOfXexpected: "implementation of \'$1\' expected",
+    errNoSymbolToBorrowFromFound: "no symbol to borrow from found",
+    errDiscardValueX: "value of type '$1' has to be discarded",
+    errInvalidDiscard: "statement returns no value that can be discarded",
     errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid",
-    errCannotBindXTwice: "cannot bind parameter \'$1\' twice", 
+    errCannotBindXTwice: "cannot bind parameter \'$1\' twice",
     errInvalidOrderInArrayConstructor: "invalid order in array constructor",
-    errInvalidOrderInEnumX: "invalid order in enum \'$1\'", 
-    errEnumXHasHoles: "enum \'$1\' has holes", 
-    errExceptExpected: "\'except\' or \'finally\' expected", 
-    errInvalidTry: "after catch all \'except\' or \'finally\' no section may follow", 
+    errInvalidOrderInEnumX: "invalid order in enum \'$1\'",
+    errEnumXHasHoles: "enum \'$1\' has holes",
+    errExceptExpected: "\'except\' or \'finally\' expected",
+    errInvalidTry: "after catch all \'except\' or \'finally\' no section may follow",
     errOptionExpected: "option expected, but found \'$1\'",
-    errXisNoLabel: "\'$1\' is not a label", 
-    errNotAllCasesCovered: "not all cases are covered", 
-    errUnkownSubstitionVar: "unknown substitution variable: \'$1\'", 
+    errXisNoLabel: "\'$1\' is not a label",
+    errNotAllCasesCovered: "not all cases are covered",
+    errUnknownSubstitionVar: "unknown substitution variable: \'$1\'",
     errComplexStmtRequiresInd: "complex statement requires indentation",
-    errXisNotCallable: "\'$1\' is not callable", 
-    errNoPragmasAllowedForX: "no pragmas allowed for $1", 
-    errNoGenericParamsAllowedForX: "no generic parameters allowed for $1", 
-    errInvalidParamKindX: "invalid param kind: \'$1\'", 
-    errDefaultArgumentInvalid: "default argument invalid", 
-    errNamedParamHasToBeIdent: "named parameter has to be an identifier", 
-    errNoReturnTypeForX: "no return type allowed for $1", 
-    errConvNeedsOneArg: "a type conversion needs exactly one argument", 
-    errInvalidPragmaX: "invalid pragma: $1", 
+    errXisNotCallable: "\'$1\' is not callable",
+    errNoPragmasAllowedForX: "no pragmas allowed for $1",
+    errNoGenericParamsAllowedForX: "no generic parameters allowed for $1",
+    errInvalidParamKindX: "invalid param kind: \'$1\'",
+    errDefaultArgumentInvalid: "default argument invalid",
+    errNamedParamHasToBeIdent: "named parameter has to be an identifier",
+    errNoReturnTypeForX: "no return type allowed for $1",
+    errConvNeedsOneArg: "a type conversion needs exactly one argument",
+    errInvalidPragmaX: "invalid pragma: $1",
     errXNotAllowedHere: "$1 not allowed here",
     errInvalidControlFlowX: "invalid control flow: $1",
     errXisNoType: "invalid type: \'$1\'",
-    errCircumNeedsPointer: "'[]' needs a pointer or reference type", 
+    errCircumNeedsPointer: "'[]' needs a pointer or reference type",
     errInvalidExpression: "invalid expression",
-    errInvalidExpressionX: "invalid expression: \'$1\'", 
+    errInvalidExpressionX: "invalid expression: \'$1\'",
     errEnumHasNoValueX: "enum has no value \'$1\'",
-    errNamedExprExpected: "named expression expected", 
-    errNamedExprNotAllowed: "named expression not allowed here", 
-    errXExpectsOneTypeParam: "\'$1\' expects one type parameter", 
-    errArrayExpectsTwoTypeParams: "array expects two type parameters", 
-    errInvalidVisibilityX: "invalid visibility: \'$1\'", 
-    errInitHereNotAllowed: "initialization not allowed here", 
-    errXCannotBeAssignedTo: "\'$1\' cannot be assigned to", 
-    errIteratorNotAllowed: "iterators can only be defined at the module\'s top level", 
+    errNamedExprExpected: "named expression expected",
+    errNamedExprNotAllowed: "named expression not allowed here",
+    errXExpectsOneTypeParam: "\'$1\' expects one type parameter",
+    errArrayExpectsTwoTypeParams: "array expects two type parameters",
+    errInvalidVisibilityX: "invalid visibility: \'$1\'",
+    errInitHereNotAllowed: "initialization not allowed here",
+    errXCannotBeAssignedTo: "\'$1\' cannot be assigned to",
+    errIteratorNotAllowed: "iterators can only be defined at the module\'s top level",
     errXNeedsReturnType: "$1 needs a return type",
     errNoReturnTypeDeclared: "no return type declared",
-    errInvalidCommandX: "invalid command: \'$1\'", 
-    errXOnlyAtModuleScope: "\'$1\' is only allowed at top level", 
+    errInvalidCommandX: "invalid command: \'$1\'",
+    errXOnlyAtModuleScope: "\'$1\' is only allowed at top level",
     errXNeedsParamObjectType: "'$1' needs a parameter that has an object type",
     errTemplateInstantiationTooNested: "template/macro instantiation too nested",
-    errInstantiationFrom: "instantiation from here", 
-    errInvalidIndexValueForTuple: "invalid index value for tuple subscript", 
+    errInstantiationFrom: "template/generic instantiation from here",
+    errInvalidIndexValueForTuple: "invalid index value for tuple subscript",
     errCommandExpectsFilename: "command expects a filename argument",
     errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
-    errXExpected: "\'$1\' expected", 
+    errXExpected: "\'$1\' expected",
     errTIsNotAConcreteType: "\'$1\' is not a concrete type.",
     errInvalidSectionStart: "invalid section start",
-    errGridTableNotImplemented: "grid table is not implemented", 
+    errGridTableNotImplemented: "grid table is not implemented",
     errGeneralParseError: "general parse error",
-    errNewSectionExpected: "new section expected", 
+    errNewSectionExpected: "new section expected",
     errWhitespaceExpected: "whitespace expected, got \'$1\'",
-    errXisNoValidIndexFile: "\'$1\' is no valid index file", 
-    errCannotRenderX: "cannot render reStructuredText element \'$1\'", 
+    errXisNoValidIndexFile: "\'$1\' is no valid index file",
+    errCannotRenderX: "cannot render reStructuredText element \'$1\'",
     errVarVarTypeNotAllowed: "type \'var var\' is not allowed",
-    errInstantiateXExplicitely: "instantiate '$1' explicitely",
+    errInstantiateXExplicitly: "instantiate '$1' explicitly",
     errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator",
     errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
     errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " &
                                        "because the parameter '$1' has a generic type",
-    errDestructorNotGenericEnough: "Destructor signarue is too specific. " &
+    errDestructorNotGenericEnough: "Destructor signature is too specific. " &
                                    "A destructor must be associated will all instantiations of a generic type",
     errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " &
                                     "templates, macros and other inline iterators",
-    errXExpectsTwoArguments: "\'$1\' expects two arguments", 
+    errXExpectsTwoArguments: "\'$1\' expects two arguments",
     errXExpectsObjectTypes: "\'$1\' expects object types",
-    errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype", 
-    errTooManyIterations: "interpretation requires too many iterations", 
-    errCannotInterpretNodeX: "cannot evaluate \'$1\'", 
-    errFieldXNotFound: "field \'$1\' cannot be found", 
+    errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype",
+    errTooManyIterations: "interpretation requires too many iterations",
+    errCannotInterpretNodeX: "cannot evaluate \'$1\'",
+    errFieldXNotFound: "field \'$1\' cannot be found",
     errInvalidConversionFromTypeX: "invalid conversion from type \'$1\'",
-    errAssertionFailed: "assertion failed", 
-    errCannotGenerateCodeForX: "cannot generate code for \'$1\'", 
-    errXRequiresOneArgument: "$1 requires one parameter", 
-    errUnhandledExceptionX: "unhandled exception: $1", 
-    errCyclicTree: "macro returned a cyclic abstract syntax tree", 
+    errAssertionFailed: "assertion failed",
+    errCannotGenerateCodeForX: "cannot generate code for \'$1\'",
+    errXRequiresOneArgument: "$1 requires one parameter",
+    errUnhandledExceptionX: "unhandled exception: $1",
+    errCyclicTree: "macro returned a cyclic abstract syntax tree",
     errXisNoMacroOrTemplate: "\'$1\' is no macro or template",
-    errXhasSideEffects: "\'$1\' can have side effects", 
+    errXhasSideEffects: "\'$1\' can have side effects",
     errIteratorExpected: "iterator within for loop context expected",
     errLetNeedsInit: "'let' symbol requires an initialization",
     errThreadvarCannotInit: "a thread var cannot be initialized explicitly",
-    errWrongSymbolX: "usage of \'$1\' is a user-defined error", 
+    errWrongSymbolX: "usage of \'$1\' is a user-defined error",
     errIllegalCaptureX: "illegal capture '$1'",
     errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
     errXMustBeCompileTime: "'$1' can only be used in compile-time context",
@@ -362,24 +360,24 @@ const
     errCannotInferReturnType: "cannot infer the return type of the proc",
     errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " &
                                 "it is used as an operand to another routine and the types " &
-                                "of the generic paramers can be infered from the expected signature.",
+                                "of the generic paramers can be inferred from the expected signature.",
     errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
-    errUser: "$1", 
+    errUser: "$1",
     warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
-    warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]", 
-    warnXIsNeverRead: "\'$1\' is never read [XIsNeverRead]", 
-    warnXmightNotBeenInit: "\'$1\' might not have been initialized [XmightNotBeenInit]", 
-    warnDeprecated: "$1 is deprecated [Deprecated]", 
+    warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]",
+    warnXIsNeverRead: "\'$1\' is never read [XIsNeverRead]",
+    warnXmightNotBeenInit: "\'$1\' might not have been initialized [XmightNotBeenInit]",
+    warnDeprecated: "$1 is deprecated [Deprecated]",
     warnConfigDeprecated: "config file '$1' is deprecated [ConfigDeprecated]",
-    warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one) [SmallLshouldNotBeUsed]", 
-    warnUnknownMagic: "unknown magic \'$1\' might crash the compiler [UnknownMagic]", 
-    warnRedefinitionOfLabel: "redefinition of label \'$1\' [RedefinitionOfLabel]", 
-    warnUnknownSubstitutionX: "unknown substitution \'$1\' [UnknownSubstitutionX]", 
-    warnLanguageXNotSupported: "language \'$1\' not supported [LanguageXNotSupported]", 
-    warnFieldXNotSupported: "field \'$1\' not supported [FieldXNotSupported]", 
-    warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]", 
-    warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead [NilStmt]", 
-    warnAnalysisLoophole: "thread analysis incomplete due to unknown call '$1' [AnalysisLoophole]",
+    warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one) [SmallLshouldNotBeUsed]",
+    warnUnknownMagic: "unknown magic \'$1\' might crash the compiler [UnknownMagic]",
+    warnRedefinitionOfLabel: "redefinition of label \'$1\' [RedefinitionOfLabel]",
+    warnUnknownSubstitutionX: "unknown substitution \'$1\' [UnknownSubstitutionX]",
+    warnLanguageXNotSupported: "language \'$1\' not supported [LanguageXNotSupported]",
+    warnFieldXNotSupported: "field \'$1\' not supported [FieldXNotSupported]",
+    warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]",
+    warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead [NilStmt]",
+    warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template' [TypelessParam]",
     warnDifferentHeaps: "possible inconsistency of thread local heaps [DifferentHeaps]",
     warnWriteToForeignHeap: "write to foreign heap [WriteToForeignHeap]",
     warnUnsafeCode: "unsafe code: '$1' [UnsafeCode]",
@@ -389,23 +387,25 @@ const
     warnProveField: "cannot prove that field '$1' is accessible [ProveField]",
     warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]",
     warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]",
-    warnGcUnsafe2: "cannot prove '$1' is GC-safe. Does not compile with --threads:on.",
+    warnGcUnsafe2: "$1",
     warnUninit: "'$1' might not have been initialized [Uninit]",
     warnGcMem: "'$1' uses GC'ed memory [GcMem]",
+    warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future. [Destructor]",
     warnLockLevel: "$1 [LockLevel]",
-    warnUser: "$1 [User]", 
-    hintSuccess: "operation successful [Success]", 
-    hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]", 
-    hintLineTooLong: "line too long [LineTooLong]", 
-    hintXDeclaredButNotUsed: "\'$1\' is declared but not used [XDeclaredButNotUsed]", 
-    hintConvToBaseNotNeeded: "conversion to base object is not needed [ConvToBaseNotNeeded]", 
-    hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless [ConvFromXtoItselfNotNeeded]", 
-    hintExprAlwaysX: "expression evaluates always to \'$1\' [ExprAlwaysX]", 
+    warnResultShadowed: "Special variable 'result' is shadowed. [ResultShadowed]",
+    warnUser: "$1 [User]",
+    hintSuccess: "operation successful [Success]",
+    hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#) [SuccessX]",
+    hintLineTooLong: "line too long [LineTooLong]",
+    hintXDeclaredButNotUsed: "\'$1\' is declared but not used [XDeclaredButNotUsed]",
+    hintConvToBaseNotNeeded: "conversion to base object is not needed [ConvToBaseNotNeeded]",
+    hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless [ConvFromXtoItselfNotNeeded]",
+    hintExprAlwaysX: "expression evaluates always to \'$1\' [ExprAlwaysX]",
     hintQuitCalled: "quit() called [QuitCalled]",
-    hintProcessing: "$1 [Processing]", 
+    hintProcessing: "$1 [Processing]",
     hintCodeBegin: "generated code listing: [CodeBegin]",
-    hintCodeEnd: "end of listing [CodeEnd]", 
-    hintConf: "used config file \'$1\' [Conf]", 
+    hintCodeEnd: "end of listing [CodeEnd]",
+    hintConf: "used config file \'$1\' [Conf]",
     hintPath: "added path: '$1' [Path]",
     hintConditionAlwaysTrue: "condition is always true: '$1' [CondTrue]",
     hintName: "name should be: '$1' [Name]",
@@ -413,25 +413,25 @@ const
     hintUser: "$1 [User]"]
 
 const
-  WarningsToStr*: array[0..28, string] = ["CannotOpenFile", "OctalEscape", 
+  WarningsToStr*: array[0..30, string] = ["CannotOpenFile", "OctalEscape",
     "XIsNeverRead", "XmightNotBeenInit",
     "Deprecated", "ConfigDeprecated",
-    "SmallLshouldNotBeUsed", "UnknownMagic", 
+    "SmallLshouldNotBeUsed", "UnknownMagic",
     "RedefinitionOfLabel", "UnknownSubstitutionX",
     "LanguageXNotSupported", "FieldXNotSupported",
     "CommentXIgnored", "NilStmt",
-    "AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap",
-    "UnsafeCode", "EachIdentIsTuple", "ShadowIdent", 
+    "TypelessParam", "DifferentHeaps", "WriteToForeignHeap",
+    "UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
     "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
-    "GcMem", "LockLevel", "User"]
+    "GcMem", "Destructor", "LockLevel", "ResultShadowed", "User"]
 
-  HintsToStr*: array[0..16, string] = ["Success", "SuccessX", "LineTooLong", 
-    "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded", 
-    "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf", 
+  HintsToStr*: array[0..16, string] = ["Success", "SuccessX", "LineTooLong",
+    "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
+    "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
     "Path", "CondTrue", "Name", "Pattern",
     "User"]
 
-const 
+const
   fatalMin* = errUnknown
   fatalMax* = errInternal
   errMin* = errUnknown
@@ -440,32 +440,35 @@ const
   warnMax* = pred(hintSuccess)
   hintMin* = hintSuccess
   hintMax* = high(TMsgKind)
- 
-type 
+
+type
   TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
   TNoteKinds* = set[TNoteKind]
 
-  TFileInfo*{.final.} = object 
+  TFileInfo* = object
     fullPath: string           # This is a canonical full filesystem path
     projPath*: string          # This is relative to the project's root
     shortName*: string         # short name of the module
-    quotedName*: PRope         # cached quoted short name for codegen
+    quotedName*: Rope         # cached quoted short name for codegen
                                # purposes
-    
-    lines*: seq[PRope]         # the source code of the module
+
+    lines*: seq[Rope]         # the source code of the module
                                #   used for better error messages and
                                #   embedding the original source in the
                                #   generated code
+    dirtyfile: string          # the file that is actually read into memory
+                               # and parsed; usually 'nil' but is used
+                               # for 'nimsuggest'
 
-  TLineInfo*{.final.} = object # This is designed to be as small as possible,
+  TLineInfo* = object          # This is designed to be as small as possible,
                                # because it is used
-                               # in syntax nodes. We safe space here by using 
+                               # in syntax nodes. We save space here by using
                                # two int16 and an int32.
-                               # On 64 bit and on 32 bit systems this is 
+                               # On 64 bit and on 32 bit systems this is
                                # only 8 bytes.
     line*, col*: int16
     fileIndex*: int32
-  
+
   TErrorOutput* = enum
     eStdOut
     eStdErr
@@ -484,30 +487,26 @@ var
   fileInfos*: seq[TFileInfo] = @[]
   systemFileIdx*: int32
 
-proc toCChar*(c: char): string = 
+proc toCChar*(c: char): string =
   case c
   of '\0'..'\x1F', '\x80'..'\xFF': result = '\\' & toOctal(c)
   of '\'', '\"', '\\': result = '\\' & c
   else: result = $(c)
 
-proc makeCString*(s: string): PRope =
-  # BUGFIX: We have to split long strings into many ropes. Otherwise
-  # this could trigger an InternalError(). See the ropes module for
-  # further information.
-  const 
+proc makeCString*(s: string): Rope =
+  const
     MaxLineLength = 64
   result = nil
-  var res = "\""
+  var res = newStringOfCap(int(s.len.toFloat * 1.1) + 1)
+  add(res, "\"")
   for i in countup(0, len(s) - 1):
     if (i + 1) mod MaxLineLength == 0:
       add(res, '\"')
       add(res, tnl)
-      app(result, toRope(res)) # reset:
-      setLen(res, 1)
-      res[0] = '\"'
+      add(res, '\"')
     add(res, toCChar(s[i]))
   add(res, '\"')
-  app(result, toRope(res))
+  add(result, rope(res))
 
 
 proc newFileInfo(fullPath, projPath: string): TFileInfo =
@@ -521,7 +520,7 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo =
   if optEmbedOrigSrc in gGlobalOptions or true:
     result.lines = @[]
 
-proc fileInfoIdx*(filename: string): int32 =
+proc fileInfoIdx*(filename: string; isKnownFile: var bool): int32 =
   var
     canon: string
     pseudoPath = false
@@ -538,11 +537,16 @@ proc fileInfoIdx*(filename: string): int32 =
   if filenameToIndexTbl.hasKey(canon):
     result = filenameToIndexTbl[canon]
   else:
+    isKnownFile = false
     result = fileInfos.len.int32
     fileInfos.add(newFileInfo(canon, if pseudoPath: filename
                                      else: canon.shortenDir))
     filenameToIndexTbl[canon] = result
 
+proc fileInfoIdx*(filename: string): int32 =
+  var dummy: bool
+  result = fileInfoIdx(filename, dummy)
+
 proc newLineInfo*(fileInfoIdx: int32, line, col: int): TLineInfo =
   result.fileIndex = fileInfoIdx
   result.line = int16(line)
@@ -560,10 +564,10 @@ var gCodegenLineInfo* = newLineInfo(int32(1), 1, 1)
 proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
   raise newException(ERecoverableError, msg)
 
-proc sourceLine*(i: TLineInfo): PRope
+proc sourceLine*(i: TLineInfo): Rope
 
 var
-  gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} - 
+  gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} -
                         {warnShadowIdent, warnUninit,
                          warnProveField, warnProveIndex, warnGcUnsafe}
   gErrorCounter*: int = 0     # counts the number of errors
@@ -571,46 +575,28 @@ var
   gWarnCounter*: int = 0
   gErrorMax*: int = 1         # stop after gErrorMax errors
 
-when useCaas:
-  var stdoutSocket*: Socket
-
 proc unknownLineInfo*(): TLineInfo =
   result.line = int16(-1)
   result.col = int16(-1)
   result.fileIndex = -1
 
-var 
+var
   msgContext: seq[TLineInfo] = @[]
   lastError = unknownLineInfo()
-  bufferedMsgs*: seq[string]
 
   errorOutputs* = {eStdOut, eStdErr}
-
-proc clearBufferedMsgs* =
-  bufferedMsgs = nil
+  writelnHook*: proc (output: string) {.closure.}
 
 proc suggestWriteln*(s: string) =
   if eStdOut in errorOutputs:
-    when useCaas:
-      if isNil(stdoutSocket): writeln(stdout, s)
-      else:
-        writeln(stdout, s)
-        stdoutSocket.send(s & "\c\L")
-    else:
-      writeln(stdout, s)
-  
-  if eInMemory in errorOutputs:
-    bufferedMsgs.safeAdd(s)
+    if isNil(writelnHook): writeln(stdout, s)
+    else: writelnHook(s)
+
+proc msgQuit*(x: int8) = quit x
+proc msgQuit*(x: string) = quit x
 
 proc suggestQuit*() =
-  if not isServing:
-    quit(0)
-  elif isWorkingWithDirtyBuffer:
-    # No need to compile the rest if we are working with a
-    # throw-away buffer. Incomplete dot expressions frequently
-    # found in dirty buffers will result in errors few steps
-    # from now anyway.
-    raise newException(ESuggestDone, "suggest done")
+  raise newException(ESuggestDone, "suggest done")
 
 # this format is understood by many text editors: it is the same that
 # Borland and Freepascal use
@@ -626,10 +612,10 @@ const
 proc getInfoContextLen*(): int = return msgContext.len
 proc setInfoContextLen*(L: int) = setLen(msgContext, L)
 
-proc pushInfoContext*(info: TLineInfo) = 
+proc pushInfoContext*(info: TLineInfo) =
   msgContext.add(info)
-  
-proc popInfoContext*() = 
+
+proc popInfoContext*() =
   setLen(msgContext, len(msgContext) - 1)
 
 proc getInfoContext*(index: int): TLineInfo =
@@ -646,6 +632,18 @@ proc toFullPath*(fileIdx: int32): string =
   if fileIdx < 0: result = "???"
   else: result = fileInfos[fileIdx].fullPath
 
+proc setDirtyFile*(fileIdx: int32; filename: string) =
+  assert fileIdx >= 0
+  fileInfos[fileIdx].dirtyFile = filename
+
+proc toFullPathConsiderDirty*(fileIdx: int32): string =
+  if fileIdx < 0:
+    result = "???"
+  elif not fileInfos[fileIdx].dirtyFile.isNil:
+    result = fileInfos[fileIdx].dirtyFile
+  else:
+    result = fileInfos[fileIdx].fullPath
+
 template toFilename*(info: TLineInfo): string =
   info.fileIndex.toFilename
 
@@ -653,17 +651,17 @@ template toFullPath*(info: TLineInfo): string =
   info.fileIndex.toFullPath
 
 proc toMsgFilename*(info: TLineInfo): string =
-  if info.fileIndex < 0: result = "???"
+  if info.fileIndex < 0:
+    result = "???"
+  elif gListFullPaths:
+    result = fileInfos[info.fileIndex].fullPath
   else:
-    if gListFullPaths:
-      result = fileInfos[info.fileIndex].fullPath
-    else:
-      result = fileInfos[info.fileIndex].projPath
+    result = fileInfos[info.fileIndex].projPath
 
-proc toLinenumber*(info: TLineInfo): int {.inline.} = 
+proc toLinenumber*(info: TLineInfo): int {.inline.} =
   result = info.line
 
-proc toColumn*(info: TLineInfo): int {.inline.} = 
+proc toColumn*(info: TLineInfo): int {.inline.} =
   result = info.col
 
 proc toFileLine*(info: TLineInfo): string {.inline.} =
@@ -672,67 +670,51 @@ proc toFileLine*(info: TLineInfo): string {.inline.} =
 proc toFileLineCol*(info: TLineInfo): string {.inline.} =
   result = info.toFilename & "(" & $info.line & "," & $info.col & ")"
 
-template `$`*(info: TLineInfo): expr = toFileLineCol(info)
+proc `$`*(info: TLineInfo): string = toFileLineCol(info)
 
 proc `??`* (info: TLineInfo, filename: string): bool =
   # only for debugging purposes
   result = filename in info.toFilename
 
-var checkPoints*: seq[TLineInfo] = @[]
-var optTrackPos*: TLineInfo
-
-proc addCheckpoint*(info: TLineInfo) = 
-  checkPoints.add(info)
+var gTrackPos*: TLineInfo
 
-proc addCheckpoint*(filename: string, line: int) = 
-  addCheckpoint(newLineInfo(filename, line, - 1))
-
-proc outWriteln*(s: string) = 
+proc outWriteln*(s: string) =
   ## Writes to stdout. Always.
   if eStdOut in errorOutputs: writeln(stdout, s)
- 
-proc msgWriteln*(s: string) = 
+
+proc msgWriteln*(s: string) =
   ## Writes to stdout. If --stdout option is given, writes to stderr instead.
-  if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
 
-  if optStdout in gGlobalOptions:
+  #if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
+
+  if not isNil(writelnHook):
+    writelnHook(s)
+  elif optStdout in gGlobalOptions:
     if eStdErr in errorOutputs: writeln(stderr, s)
   else:
     if eStdOut in errorOutputs: writeln(stdout, s)
-  
-  if eInMemory in errorOutputs: bufferedMsgs.safeAdd(s)
 
-proc coordToStr(coord: int): string = 
+proc coordToStr(coord: int): string =
   if coord == -1: result = "???"
   else: result = $coord
-  
-proc msgKindToString*(kind: TMsgKind): string = 
+
+proc msgKindToString*(kind: TMsgKind): string =
   # later versions may provide translated error messages
   result = MsgKindToStr[kind]
 
-proc getMessageStr(msg: TMsgKind, arg: string): string = 
+proc getMessageStr(msg: TMsgKind, arg: string): string =
   result = msgKindToString(msg) % [arg]
 
 type
-  TCheckPointResult* = enum 
-    cpNone, cpFuzzy, cpExact
-
-proc inCheckpoint*(current: TLineInfo): TCheckPointResult = 
-  for i in countup(0, high(checkPoints)): 
-    if current.fileIndex == checkPoints[i].fileIndex:
-      if current.line == checkPoints[i].line and
-          abs(current.col-checkPoints[i].col) < 4:
-        return cpExact
-      if current.line >= checkPoints[i].line:
-        return cpFuzzy
-
-type
   TErrorHandling = enum doNothing, doAbort, doRaise
 
 proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
   template quit =
     if defined(debug) or gVerbosity >= 3 or msg == errInternal:
-      writeStackTrace()
+      if stackTraceAvailable() and isNil(writelnHook):
+        writeStackTrace()
+      else:
+        msgWriteln("No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp " & options.command & " <file>")
     quit 1
 
   if msg >= fatalMin and msg <= fatalMax:
@@ -750,44 +732,48 @@ proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
 proc `==`*(a, b: TLineInfo): bool =
   result = a.line == b.line and a.fileIndex == b.fileIndex
 
-proc writeContext(lastinfo: TLineInfo) = 
+proc writeContext(lastinfo: TLineInfo) =
   var info = lastinfo
-  for i in countup(0, len(msgContext) - 1): 
-    if msgContext[i] != lastinfo and msgContext[i] != info: 
-      msgWriteln(PosContextFormat % [toMsgFilename(msgContext[i]), 
-                                     coordToStr(msgContext[i].line), 
-                                     coordToStr(msgContext[i].col), 
+  for i in countup(0, len(msgContext) - 1):
+    if msgContext[i] != lastinfo and msgContext[i] != info:
+      msgWriteln(PosContextFormat % [toMsgFilename(msgContext[i]),
+                                     coordToStr(msgContext[i].line),
+                                     coordToStr(msgContext[i].col+1),
                                      getMessageStr(errInstantiationFrom, "")])
     info = msgContext[i]
 
-proc rawMessage*(msg: TMsgKind, args: openArray[string]) = 
+proc ignoreMsgBecauseOfIdeTools(msg: TMsgKind): bool =
+  msg >= errGenerated and gCmd == cmdIdeTools and optIdeDebug notin gGlobalOptions
+
+proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
   var frmt: string
   case msg
-  of errMin..errMax: 
+  of errMin..errMax:
     writeContext(unknownLineInfo())
     frmt = RawErrorFormat
-  of warnMin..warnMax: 
-    if optWarns notin gOptions: return 
-    if msg notin gNotes: return 
+  of warnMin..warnMax:
+    if optWarns notin gOptions: return
+    if msg notin gNotes: return
     writeContext(unknownLineInfo())
     frmt = RawWarningFormat
     inc(gWarnCounter)
-  of hintMin..hintMax: 
-    if optHints notin gOptions: return 
-    if msg notin gNotes: return 
+  of hintMin..hintMax:
+    if optHints notin gOptions: return
+    if msg notin gNotes: return
     frmt = RawHintFormat
     inc(gHintCounter)
   let s = `%`(frmt, `%`(msgKindToString(msg), args))
-  msgWriteln(s)
+  if not ignoreMsgBecauseOfIdeTools(msg):
+    msgWriteln(s)
   handleError(msg, doAbort, s)
 
-proc rawMessage*(msg: TMsgKind, arg: string) = 
+proc rawMessage*(msg: TMsgKind, arg: string) =
   rawMessage(msg, [arg])
 
 proc writeSurroundingSrc(info: TLineInfo) =
   const indent = "  "
-  msgWriteln(indent & info.sourceLine.ropeToStr)
-  msgWriteln(indent & repeatChar(info.col, ' ') & '^')
+  msgWriteln(indent & $info.sourceLine)
+  msgWriteln(indent & spaces(info.col) & '^')
 
 proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
   let frmt = case msg
@@ -795,9 +781,9 @@ proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
              of hintMin..hintMax: PosHintFormat
              else: PosErrorFormat
   result = frmt % [toMsgFilename(info), coordToStr(info.line),
-                   coordToStr(info.col), getMessageStr(msg, arg)]
+                   coordToStr(info.col+1), getMessageStr(msg, arg)]
 
-proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string, 
+proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
                eh: TErrorHandling) =
   var frmt: string
   var ignoreMsg = false
@@ -814,22 +800,25 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
     if not ignoreMsg: writeContext(info)
     frmt = PosWarningFormat
     inc(gWarnCounter)
-  of hintMin..hintMax: 
+  of hintMin..hintMax:
     ignoreMsg = optHints notin gOptions or msg notin gNotes
     frmt = PosHintFormat
     inc(gHintCounter)
+  # NOTE: currently line info line numbers start with 1,
+  # but column numbers start with 0, however most editors expect
+  # first column to be 1, so we need to +1 here
   let s = frmt % [toMsgFilename(info), coordToStr(info.line),
-                  coordToStr(info.col), getMessageStr(msg, arg)]
-  if not ignoreMsg:
+                  coordToStr(info.col+1), getMessageStr(msg, arg)]
+  if not ignoreMsg and not ignoreMsgBecauseOfIdeTools(msg):
     msgWriteln(s)
     if optPrintSurroundingSrc and msg in errMin..errMax:
       info.writeSurroundingSrc
   handleError(msg, eh, s)
-  
-proc fatal*(info: TLineInfo, msg: TMsgKind, arg = "") = 
+
+proc fatal*(info: TLineInfo, msg: TMsgKind, arg = "") =
   liMessage(info, msg, arg, doAbort)
 
-proc globalError*(info: TLineInfo, msg: TMsgKind, arg = "") = 
+proc globalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
   liMessage(info, msg, arg, doRaise)
 
 proc globalError*(info: TLineInfo, arg: string) =
@@ -841,15 +830,18 @@ proc localError*(info: TLineInfo, msg: TMsgKind, arg = "") =
 proc localError*(info: TLineInfo, arg: string) =
   liMessage(info, errGenerated, arg, doNothing)
 
+proc localError*(info: TLineInfo, format: string, params: openarray[string]) =
+  localError(info, format % params)
+
 proc message*(info: TLineInfo, msg: TMsgKind, arg = "") =
   liMessage(info, msg, arg, doNothing)
 
-proc internalError*(info: TLineInfo, errMsg: string) = 
+proc internalError*(info: TLineInfo, errMsg: string) =
   if gCmd == cmdIdeTools: return
   writeContext(info)
   liMessage(info, errInternal, errMsg, doAbort)
 
-proc internalError*(errMsg: string) = 
+proc internalError*(errMsg: string) =
   if gCmd == cmdIdeTools: return
   writeContext(unknownLineInfo())
   rawMessage(errInternal, errMsg)
@@ -862,11 +854,11 @@ template internalAssert*(e: bool): stmt =
   if not e: internalError($instantiationInfo())
 
 proc addSourceLine*(fileIdx: int32, line: string) =
-  fileInfos[fileIdx].lines.add line.toRope
+  fileInfos[fileIdx].lines.add line.rope
 
-proc sourceLine*(i: TLineInfo): PRope =
+proc sourceLine*(i: TLineInfo): Rope =
   if i.fileIndex < 0: return nil
-  
+
   if not optPreserveOrigSource and fileInfos[i.fileIndex].lines.len == 0:
     try:
       for line in lines(i.toFullPath):
@@ -879,16 +871,14 @@ proc sourceLine*(i: TLineInfo): PRope =
 
   result = fileInfos[i.fileIndex].lines[i.line-1]
 
-proc quotedFilename*(i: TLineInfo): PRope =
+proc quotedFilename*(i: TLineInfo): Rope =
   internalAssert i.fileIndex >= 0
   result = fileInfos[i.fileIndex].quotedName
 
-ropes.errorHandler = proc (err: TRopesError, msg: string, useWarning: bool) =
+ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
   case err
   of rInvalidFormatStr:
     internalError("ropes: invalid format string: " & msg)
-  of rTokenTooLong:
-    internalError("ropes: token too long: " & msg)
   of rCannotOpenFile:
     rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)
 
diff --git a/compiler/nim.nim b/compiler/nim.nim
index a87e0a1ac..b8ba2c6da 100644
--- a/compiler/nim.nim
+++ b/compiler/nim.nim
@@ -9,13 +9,14 @@
 
 when defined(gcc) and defined(windows):
   when defined(x86):
-    {.link: "icons/nimrod.res".}
+    {.link: "icons/nim.res".}
   else:
-    {.link: "icons/nimrod_icon.o".}
+    {.link: "icons/nim_icon.o".}
 
 import
   commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
-  extccomp, strutils, os, osproc, platform, main, parseopt, service
+  extccomp, strutils, os, osproc, platform, main, parseopt, service,
+  nodejs
 
 when hasTinyCBackend:
   import tccgen
@@ -60,6 +61,8 @@ proc handleCmdLine() =
         if gCmd == cmdRun:
           tccgen.run(commands.arguments)
       if optRun in gGlobalOptions:
+        if gProjectName == "-":
+          gProjectFull = "stdinfile"
         if gCmd == cmdCompileToJS:
           var ex: string
           if options.outFile.len > 0:
@@ -67,7 +70,7 @@ proc handleCmdLine() =
           else:
             ex = quoteShell(
               completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
-          execExternalProgram("node " & ex & ' ' & commands.arguments)
+          execExternalProgram(findNodeJs() & " " & ex & ' ' & commands.arguments)
         else:
           var binPath: string
           if options.outFile.len > 0:
@@ -89,4 +92,4 @@ condsyms.initDefines()
 
 when not defined(selftest):
   handleCmdLine()
-  quit(int8(msgs.gErrorCounter > 0))
+  msgQuit(int8(msgs.gErrorCounter > 0))
diff --git a/compiler/nim.nimrod.cfg b/compiler/nim.nim.cfg
index ba7697c4c..64631a437 100644
--- a/compiler/nim.nimrod.cfg
+++ b/compiler/nim.nim.cfg
@@ -1,7 +1,5 @@
 # Special configuration file for the Nim project
 
-# gc:markAndSweep
-
 hint[XDeclaredButNotUsed]:off
 path:"llvm"
 path:"$projectPath/.."
@@ -20,3 +18,4 @@ define:useStdoutAsStdmsg
 cs:partial
 #define:useNodeIds
 symbol:nimfix
+#gc:markAndSweep
diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim
index 049b94aa9..23f3331a2 100644
--- a/compiler/nimblecmd.nim
+++ b/compiler/nimblecmd.nim
@@ -33,7 +33,7 @@ proc `<.`(a, b: string): bool =
   while true:
     let ii = parseInt(a, verA, i)
     let jj = parseInt(b, verB, j)
-    # if A has no number left, but B has, B is prefered:  0.8 vs 0.8.3
+    # if A has no number left, but B has, B is preferred:  0.8 vs 0.8.3
     if ii <= 0 or jj <= 0: return jj > 0
     if verA < verB: return true
     elif verA > verB: return false
diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim
index bcf9b5359..711b476e6 100644
--- a/compiler/nimconf.nim
+++ b/compiler/nimconf.nim
@@ -11,10 +11,10 @@
 
 import 
   llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer, 
-  options, idents, wordrecg
+  options, idents, wordrecg, strtabs
 
 # ---------------- configuration file parser -----------------------------
-# we use Nim's scanner here to safe space and work
+# we use Nim's scanner here to save space and work
 
 proc ppGetTok(L: var TLexer, tok: var TToken) = 
   # simple filter
@@ -82,17 +82,17 @@ proc doElif(L: var TLexer, tok: var TToken) =
 proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) = 
   var nestedIfs = 0
   while true: 
-    if (tok.ident != nil) and (tok.ident.s == "@"): 
+    if tok.ident != nil and tok.ident.s == "@":
       ppGetTok(L, tok)
       case whichKeyword(tok.ident)
       of wIf: 
         inc(nestedIfs)
       of wElse: 
-        if (dest == jdElseEndif) and (nestedIfs == 0): 
+        if dest == jdElseEndif and nestedIfs == 0:
           doElse(L, tok)
           break 
       of wElif: 
-        if (dest == jdElseEndif) and (nestedIfs == 0): 
+        if dest == jdElseEndif and nestedIfs == 0:
           doElif(L, tok)
           break 
       of wEnd: 
@@ -119,9 +119,10 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
   of wElif: doElif(L, tok)
   of wElse: doElse(L, tok)
   of wEnd: doEnd(L, tok)
-  of wWrite: 
+  of wWrite:
     ppGetTok(L, tok)
-    msgs.msgWriteln(tokToStr(tok))
+    msgs.msgWriteln(strtabs.`%`(tokToStr(tok), options.gConfigVars,
+                                {useEnvironment, useKey}))
     ppGetTok(L, tok)
   else:
     case tok.ident.s.normalize
@@ -157,7 +158,7 @@ proc checkSymbol(L: TLexer, tok: TToken) =
 proc parseAssignment(L: var TLexer, tok: var TToken) = 
   if tok.ident.id == getIdent("-").id or tok.ident.id == getIdent("--").id:
     confTok(L, tok)           # skip unnecessary prefix
-  var info = getLineInfo(L, tok) # safe for later in case of an error
+  var info = getLineInfo(L, tok) # save for later in case of an error
   checkSymbol(L, tok)
   var s = tokToStr(tok)
   confTok(L, tok)             # skip symbol
@@ -178,9 +179,10 @@ proc parseAssignment(L: var TLexer, tok: var TToken) =
     if tok.tokType == tkBracketRi: confTok(L, tok)
     else: lexMessage(L, errTokenExpected, "']'")
     add(val, ']')
-  if tok.tokType in {tkColon, tkEquals}: 
+  let percent = tok.ident.id == getIdent("%=").id
+  if tok.tokType in {tkColon, tkEquals} or percent: 
     if len(val) > 0: add(val, ':')
-    confTok(L, tok)           # skip ':' or '='
+    confTok(L, tok)           # skip ':' or '=' or '%'
     checkSymbol(L, tok)
     add(val, tokToStr(tok))
     confTok(L, tok)           # skip symbol
@@ -189,7 +191,11 @@ proc parseAssignment(L: var TLexer, tok: var TToken) =
       checkSymbol(L, tok)
       add(val, tokToStr(tok))
       confTok(L, tok)
-  processSwitch(s, val, passPP, info)
+  if percent:
+    processSwitch(s, strtabs.`%`(val, options.gConfigVars,
+                                {useEnvironment, useEmpty}), passPP, info)
+  else:
+    processSwitch(s, val, passPP, info)
 
 proc readConfigFile(filename: string) =
   var
@@ -246,6 +252,11 @@ proc loadConfigs*(cfg: string) =
     
     if gProjectName.len != 0:
       # new project wide config file:
-      let projectConfig = changeFileExt(gProjectFull, "nim.cfg")
-      if fileExists(projectConfig): readConfigFile(projectConfig)
-      else: readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg"))
+      var projectConfig = changeFileExt(gProjectFull, "nimcfg")
+      if not fileExists(projectConfig):
+        projectConfig = changeFileExt(gProjectFull, "nim.cfg")
+      if not fileExists(projectConfig):
+        projectConfig = changeFileExt(gProjectFull, "nimrod.cfg")
+        if fileExists(projectConfig):
+          rawMessage(warnDeprecated, projectConfig)
+      readConfigFile(projectConfig)
diff --git a/compiler/nimeval.nim b/compiler/nimeval.nim
index 5693cbe91..197e8bf86 100644
--- a/compiler/nimeval.nim
+++ b/compiler/nimeval.nim
@@ -24,7 +24,7 @@ proc execute*(program: string) =
   when hasFFI: defineSymbol("nimffi")
   registerPass(verbosePass)
   registerPass(semPass)
-  registerPass(vmPass)
+  registerPass(evalPass)
 
   appendStr(searchPaths, options.libpath)
   compileSystemModule()
diff --git a/compiler/nimfix/nimfix.nim b/compiler/nimfix/nimfix.nim
index 7b42537c4..8caa23ee3 100644
--- a/compiler/nimfix/nimfix.nim
+++ b/compiler/nimfix/nimfix.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -26,12 +26,13 @@ Options:
   --styleCheck:on|off|auto         performs style checking for identifiers
                                    and suggests an alternative spelling; 
                                    'auto' corrects the spelling.
+  --bestEffort                     try to fix the code even when there
+                                   are errors.
 
 In addition, all command line options of Nim are supported.
 """
 
 proc mainCommand =
-  #msgs.gErrorMax = high(int)  # do not stop after first error
   registerPass verbosePass
   registerPass semPass
   gCmd = cmdPretty
@@ -63,13 +64,14 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
         of "on": gCheckExtern = true
         of "off": gCheckExtern = false
         else: localError(gCmdLineInfo, errOnOrOffExpected)
-      of "stylecheck": 
+      of "stylecheck":
         case p.val.normalize
         of "off": gStyleCheck = StyleCheck.None
         of "on": gStyleCheck = StyleCheck.Warn
         of "auto": gStyleCheck = StyleCheck.Auto
         else: localError(gCmdLineInfo, errOnOrOffExpected)
       of "wholeproject": gOnlyMainfile = false
+      of "besteffort": msgs.gErrorMax = high(int) # dont stop after first error
       else:
         processSwitch(pass, p)
     of cmdArgument:
diff --git a/compiler/nimfix/nimfix.nim.cfg b/compiler/nimfix/nimfix.nim.cfg
index 47b4a3713..b23ed13fb 100644
--- a/compiler/nimfix/nimfix.nim.cfg
+++ b/compiler/nimfix/nimfix.nim.cfg
@@ -2,7 +2,7 @@
 # gc:markAndSweep
 
 hint[XDeclaredButNotUsed]:off
-path:"$projectPath/../.."
+path:"$projectPath/.."
 
 path:"$lib/packages/docutils"
 path:"../compiler"
diff --git a/compiler/nimfix/pretty.nim b/compiler/nimfix/pretty.nim
index acac574af..d2d5b5e83 100644
--- a/compiler/nimfix/pretty.nim
+++ b/compiler/nimfix/pretty.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
diff --git a/compiler/nimfix/prettybase.nim b/compiler/nimfix/prettybase.nim
index 225b78479..5130d1863 100644
--- a/compiler/nimfix/prettybase.nim
+++ b/compiler/nimfix/prettybase.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
diff --git a/compiler/nimlexbase.nim b/compiler/nimlexbase.nim
index e18e1c22a..f5db5ca4f 100644
--- a/compiler/nimlexbase.nim
+++ b/compiler/nimlexbase.nim
@@ -166,4 +166,4 @@ proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
     inc(i)
   result.add("\n")
   if marker: 
-    result.add(repeatChar(getColNumber(L, L.bufpos)) & '^' & "\n")
+    result.add(spaces(getColNumber(L, L.bufpos)) & '^' & "\n")
diff --git a/compiler/nimsuggest/nimsuggest.nim b/compiler/nimsuggest/nimsuggest.nim
new file mode 100644
index 000000000..b45ca475c
--- /dev/null
+++ b/compiler/nimsuggest/nimsuggest.nim
@@ -0,0 +1,197 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Nimsuggest is a tool that helps to give editors IDE like capabilities.
+
+import strutils, os, parseopt, parseUtils
+import options, commands, modules, sem, passes, passaux, msgs, nimconf,
+  extccomp, condsyms, lists, net, rdstdin
+
+const Usage = """
+Nimsuggest - Tool to give every editor IDE like capabilities for Nim
+Usage:
+  nimsuggest [options] projectfile.nim
+
+Options:
+  --port:PORT             port, by default 6000
+  --address:HOST          binds to that address, by default ""
+  --stdin                 read commands from stdin and write results to
+                          stdout instead of using sockets
+
+The server then listens to the connection and takes line-based commands.
+
+In addition, all command line options of Nim that do not affect code generation
+are supported.
+"""
+
+var
+  gPort = 6000.Port
+  gAddress = ""
+  gUseStdin: bool
+
+const
+  seps = {':', ';', ' ', '\t'}
+  Help = "usage: sug|con|def|use file.nim[;dirtyfile.nim]:line:col\n"&
+         "type 'quit' to quit\n" &
+         "type 'debug' to toggle debug mode on/off\n" &
+         "type 'terse' to toggle terse mode on/off"
+
+proc parseQuoted(cmd: string; outp: var string; start: int): int =
+  var i = start
+  i += skipWhitespace(cmd, i)
+  if cmd[i] == '"':
+    i += parseUntil(cmd, outp, '"', i+1)+2
+  else:
+    i += parseUntil(cmd, outp, seps, i)
+  result = i
+
+proc action(cmd: string) =
+  template toggle(sw) =
+    if sw in gGlobalOptions:
+      excl(gGlobalOptions, sw)
+    else:
+      incl(gGlobalOptions, sw)
+    return
+
+  template err() =
+    echo Help
+    return
+
+  var opc = ""
+  var i = parseIdent(cmd, opc, 0)
+  case opc.normalize
+  of "sug": gIdeCmd = ideSug
+  of "con": gIdeCmd = ideCon
+  of "def": gIdeCmd = ideDef
+  of "use":
+    modules.resetAllModules()
+    gIdeCmd = ideUse
+  of "quit": quit()
+  of "debug": toggle optIdeDebug
+  of "terse": toggle optIdeTerse
+  else: err()
+  var dirtyfile = ""
+  var orig = ""
+  i = parseQuoted(cmd, orig, i)
+  if cmd[i] == ';':
+    i = parseQuoted(cmd, dirtyfile, i+1)
+  i += skipWhile(cmd, seps, i)
+  var line, col = -1
+  i += parseInt(cmd, line, i)
+  i += skipWhile(cmd, seps, i)
+  i += parseInt(cmd, col, i)
+
+  var isKnownFile = true
+  if orig.len == 0: err()
+  let dirtyIdx = orig.fileInfoIdx(isKnownFile)
+
+  if dirtyfile.len != 0: msgs.setDirtyFile(dirtyIdx, dirtyfile)
+  else: msgs.setDirtyFile(dirtyIdx, nil)
+
+  resetModule dirtyIdx
+  if dirtyIdx != gProjectMainIdx:
+    resetModule gProjectMainIdx
+  gTrackPos = newLineInfo(dirtyIdx, line, col)
+  #echo dirtyfile, gDirtyBufferIdx, " project ", gProjectMainIdx
+  gErrorCounter = 0
+  if not isKnownFile:
+    compileProject(dirtyIdx)
+  else:
+    compileProject()
+
+proc serve() =
+  # do not stop after the first error:
+  msgs.gErrorMax = high(int)
+  if gUseStdin:
+    echo Help
+    var line = ""
+    while readLineFromStdin("> ", line):
+      action line
+      echo ""
+      flushFile(stdout)
+  else:
+    var server = newSocket()
+    server.bindAddr(gPort, gAddress)
+    var inp = "".TaintedString
+    server.listen()
+
+    while true:
+      var stdoutSocket = newSocket()
+      msgs.writelnHook = proc (line: string) =
+        stdoutSocket.send(line & "\c\L")
+
+      accept(server, stdoutSocket)
+
+      stdoutSocket.readLine(inp)
+      action inp.string
+
+      stdoutSocket.send("\c\L")
+      stdoutSocket.close()
+
+proc mainCommand =
+  registerPass verbosePass
+  registerPass semPass
+  gCmd = cmdIdeTools
+  incl gGlobalOptions, optCaasEnabled
+  isServing = true
+  wantMainModule()
+  appendStr(searchPaths, options.libpath)
+  if gProjectFull.len != 0:
+    # current path is always looked first for modules
+    prependStr(searchPaths, gProjectPath)
+
+  serve()
+
+proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
+  var p = parseopt.initOptParser(cmd)
+  while true: 
+    parseopt.next(p)
+    case p.kind
+    of cmdEnd: break 
+    of cmdLongoption, cmdShortOption: 
+      case p.key.normalize
+      of "port": gPort = parseInt(p.val).Port
+      of "address": gAddress = p.val
+      of "stdin": gUseStdin = true
+      else: processSwitch(pass, p)
+    of cmdArgument:
+      options.gProjectName = unixToNativePath(p.key)
+      # if processArgument(pass, p, argsCount): break
+
+proc handleCmdLine() =
+  if paramCount() == 0:
+    stdout.writeln(Usage)
+  else:
+    processCmdLine(passCmd1, "")
+    if gProjectName != "":
+      try:
+        gProjectFull = canonicalizePath(gProjectName)
+      except OSError:
+        gProjectFull = gProjectName
+      var p = splitFile(gProjectFull)
+      gProjectPath = p.dir
+      gProjectName = p.name
+    else:
+      gProjectPath = getCurrentDir()
+    loadConfigs(DefaultConfig) # load all config files
+    # now process command line arguments again, because some options in the
+    # command line can overwite the config file's settings
+    extccomp.initVars()
+    processCmdLine(passCmd2, "")
+    mainCommand()
+
+when false:
+  proc quitCalled() {.noconv.} =
+    writeStackTrace()
+
+  addQuitProc(quitCalled)
+
+condsyms.initDefines()
+defineSymbol "nimsuggest"
+handleCmdline()
diff --git a/compiler/nimsuggest/nimsuggest.nim.cfg b/compiler/nimsuggest/nimsuggest.nim.cfg
new file mode 100644
index 000000000..062092f16
--- /dev/null
+++ b/compiler/nimsuggest/nimsuggest.nim.cfg
@@ -0,0 +1,17 @@
+# Special configuration file for the Nim project
+
+gc:markAndSweep
+
+hint[XDeclaredButNotUsed]:off
+path:"$projectPath/../.."
+
+path:"$lib/packages/docutils"
+path:"$nim/compiler"
+
+define:useStdoutAsStdmsg
+define:nimsuggest
+
+cs:partial
+#define:useNodeIds
+define:booting
+#define:noDocgen
diff --git a/compiler/nodejs.nim b/compiler/nodejs.nim
new file mode 100644
index 000000000..e2b79df19
--- /dev/null
+++ b/compiler/nodejs.nim
@@ -0,0 +1,6 @@
+import os
+
+proc findNodeJs*(): string =
+  result = findExe("nodejs")
+  if result == "":
+    result = findExe("node")
diff --git a/compiler/nversion.nim b/compiler/nversion.nim
index 8dc4b90b2..4dea62876 100644
--- a/compiler/nversion.nim
+++ b/compiler/nversion.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
diff --git a/compiler/options.nim b/compiler/options.nim
index 415ac8430..65250f519 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -9,7 +9,7 @@
 
 import
   os, lists, strutils, strtabs, osproc, sets
-  
+
 const
   hasTinyCBackend* = defined(tinyc)
   useEffectSystem* = true
@@ -21,10 +21,10 @@ const
 type                          # please make sure we have under 32 options
                               # (improves code efficiency a lot!)
   TOption* = enum             # **keep binary compatible**
-    optNone, optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck, 
+    optNone, optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck,
     optOverflowCheck, optNilCheck,
     optNaNCheck, optInfCheck,
-    optAssert, optLineDir, optWarns, optHints, 
+    optAssert, optLineDir, optWarns, optHints,
     optOptimizeSpeed, optOptimizeSize, optStackTrace, # stack tracing support
     optLineTrace,             # line tracing support (includes stack tracing)
     optEndb,                  # embedded debugger
@@ -37,8 +37,8 @@ type                          # please make sure we have under 32 options
 
   TOptions* = set[TOption]
   TGlobalOption* = enum       # **keep binary compatible**
-    gloptNone, optForceFullMake, optDeadCodeElim, 
-    optListCmd, optCompileOnly, optNoLinking, 
+    gloptNone, optForceFullMake, optDeadCodeElim,
+    optListCmd, optCompileOnly, optNoLinking,
     optSafeCode,              # only allow safe code
     optCDebug,                # turn on debugging information
     optGenDynLib,             # generate a dynamic library
@@ -56,23 +56,20 @@ type                          # please make sure we have under 32 options
     optNoMain,                # do not generate a "main" proc
     optThreads,               # support for multi-threading
     optStdout,                # output to stdout
-    optSuggest,               # ideTools: 'suggest'
-    optContext,               # ideTools: 'context'
-    optDef,                   # ideTools: 'def'
-    optUsages,                # ideTools: 'usages'
     optThreadAnalysis,        # thread analysis pass
     optTaintMode,             # taint mode turned on
     optTlsEmulation,          # thread var emulation turned on
     optGenIndex               # generate index file for documentation;
     optEmbedOrigSrc           # embed the original source in the generated code
                               # also: generate header file
-   
+    optIdeDebug               # idetools: debug mode
+    optIdeTerse               # idetools: use terse descriptions
   TGlobalOptions* = set[TGlobalOption]
   TCommands* = enum           # Nim's commands
                               # **keep binary compatible**
-    cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, 
-    cmdCompileToJS, cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc, 
-    cmdGenDepend, cmdDump, 
+    cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
+    cmdCompileToJS, cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
+    cmdGenDepend, cmdDump,
     cmdCheck,                 # semantic checking for whole project
     cmdParse,                 # parse a single file (for debugging)
     cmdScan,                  # scan a single file (for debugging)
@@ -86,13 +83,19 @@ type                          # please make sure we have under 32 options
   TGCMode* = enum             # the selected GC
     gcNone, gcBoehm, gcMarkAndSweep, gcRefc, gcV2, gcGenerational
 
+  TIdeCmd* = enum
+    ideNone, ideSug, ideCon, ideDef, ideUse
+
+var
+  gIdeCmd*: TIdeCmd
+
 const
-  ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck, 
+  ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck,
     optOverflowCheck, optBoundsCheck, optAssert, optNaNCheck, optInfCheck}
 
-var 
-  gOptions*: TOptions = {optObjCheck, optFieldCheck, optRangeCheck, 
-                         optBoundsCheck, optOverflowCheck, optAssert, optWarns, 
+var
+  gOptions*: TOptions = {optObjCheck, optFieldCheck, optRangeCheck,
+                         optBoundsCheck, optOverflowCheck, optAssert, optWarns,
                          optHints, optStackTrace, optLineTrace,
                          optPatterns, optNilCheck}
   gGlobalOptions*: TGlobalOptions = {optThreadAnalysis}
@@ -111,18 +114,12 @@ var
   gLastCmdTime*: float        # when caas is enabled, we measure each command
   gListFullPaths*: bool
   isServing*: bool = false
-  gDirtyBufferIdx* = 0'i32    # indicates the fileIdx of the dirty version of
-                              # the tracked source X, saved by the CAAS client.
-  gDirtyOriginalIdx* = 0'i32  # the original source file of the dirtified buffer.
   gNoNimblePath* = false
   gExperimentalMode*: bool
 
 proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
 proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
 
-template isWorkingWithDirtyBuffer*: expr =
-  gDirtyBufferIdx != 0
-
 template compilationCachePresent*: expr =
   {optCaasEnabled, optSymbolFiles} * gGlobalOptions != {}
 
@@ -132,7 +129,7 @@ template optPreserveOrigSource*: expr =
 template optPrintSurroundingSrc*: expr =
   gVerbosity >= 2
 
-const 
+const
   genSubDir* = "nimcache"
   NimExt* = "nim"
   RodExt* = "rod"
@@ -171,20 +168,20 @@ proc mainCommandArg*: string =
   else:
     result = gProjectName
 
-proc existsConfigVar*(key: string): bool = 
+proc existsConfigVar*(key: string): bool =
   result = hasKey(gConfigVars, key)
 
-proc getConfigVar*(key: string): string = 
+proc getConfigVar*(key: string): string =
   result = gConfigVars[key]
 
-proc setConfigVar*(key, val: string) = 
+proc setConfigVar*(key, val: string) =
   gConfigVars[key] = val
 
-proc getOutFile*(filename, ext: string): string = 
+proc getOutFile*(filename, ext: string): string =
   if options.outFile != "": result = options.outFile
   else: result = changeFileExt(filename, ext)
-  
-proc getPrefixDir*(): string = 
+
+proc getPrefixDir*(): string =
   ## gets the application directory
   result = splitPath(getAppDir()).head
 
@@ -192,22 +189,22 @@ proc canonicalizePath*(path: string): string =
   when not FileSystemCaseSensitive: result = path.expandFilename.toLower
   else: result = path.expandFilename
 
-proc shortenDir*(dir: string): string = 
+proc shortenDir*(dir: string): string =
   ## returns the interesting part of a dir
   var prefix = getPrefixDir() & DirSep
-  if startsWith(dir, prefix): 
+  if startsWith(dir, prefix):
     return substr(dir, len(prefix))
   prefix = gProjectPath & DirSep
   if startsWith(dir, prefix):
     return substr(dir, len(prefix))
   result = dir
 
-proc removeTrailingDirSep*(path: string): string = 
-  if (len(path) > 0) and (path[len(path) - 1] == DirSep): 
+proc removeTrailingDirSep*(path: string): string =
+  if (len(path) > 0) and (path[len(path) - 1] == DirSep):
     result = substr(path, 0, len(path) - 2)
-  else: 
+  else:
     result = path
-  
+
 proc getGeneratedPath: string =
   result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
                                                          genSubDir
@@ -260,7 +257,7 @@ proc withPackageName*(path: string): string =
     let (p, file, ext) = path.splitFile
     result = (p / (x & '_' & file)) & ext
 
-proc toGeneratedFile*(path, ext: string): string = 
+proc toGeneratedFile*(path, ext: string): string =
   ## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
   var (head, tail) = splitPath(path)
   #if len(head) > 0: head = shortenDir(head & dirSep)
@@ -286,25 +283,25 @@ when noTimeMachine:
       var p = startProcess("/usr/bin/tmutil", args = ["addexclusion", dir])
       discard p.waitForExit
       p.close
-    except E_Base, EOS:
+    except Exception:
       discard
 
-proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string = 
+proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
   var (head, tail) = splitPath(f)
   #if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep))
   var subdir = getGeneratedPath() # / head
   if createSubDir:
-    try: 
+    try:
       createDir(subdir)
       when noTimeMachine:
        excludeDirFromTimeMachine(subdir)
-    except OSError: 
+    except OSError:
       writeln(stdout, "cannot create directory: " & subdir)
       quit(1)
   result = joinPath(subdir, tail)
   #echo "completeGeneratedFilePath(", f, ") = ", result
 
-iterator iterSearchPath*(searchPaths: TLinkedList): string = 
+iterator iterSearchPath*(searchPaths: TLinkedList): string =
   var it = PStrEntry(searchPaths.head)
   while it != nil:
     yield it.data
@@ -327,7 +324,7 @@ proc rawFindFile2(f: string): string =
     it = PStrEntry(it.next)
   result = ""
 
-proc findFile*(f: string): string {.procvar.} = 
+proc findFile*(f: string): string {.procvar.} =
   result = f.rawFindFile
   if result.len == 0:
     result = f.toLower.rawFindFile
@@ -354,7 +351,7 @@ proc findModule*(modulename, currentModule: string): string =
   if not existsFile(result):
     result = findFile(m)
 
-proc libCandidates*(s: string, dest: var seq[string]) = 
+proc libCandidates*(s: string, dest: var seq[string]) =
   var le = strutils.find(s, '(')
   var ri = strutils.find(s, ')', le+1)
   if le >= 0 and ri > le:
@@ -362,7 +359,7 @@ proc libCandidates*(s: string, dest: var seq[string]) =
     var suffix = substr(s, ri + 1)
     for middle in split(substr(s, le + 1, ri - 1), '|'):
       libCandidates(prefix & middle & suffix, dest)
-  else: 
+  else:
     add(dest, s)
 
 proc canonDynlibName(s: string): string =
@@ -379,17 +376,17 @@ proc inclDynlibOverride*(lib: string) =
 proc isDynlibOverride*(lib: string): bool =
   result = gDllOverrides.hasKey(lib.canonDynlibName)
 
-proc binaryStrSearch*(x: openArray[string], y: string): int = 
+proc binaryStrSearch*(x: openArray[string], y: string): int =
   var a = 0
   var b = len(x) - 1
-  while a <= b: 
+  while a <= b:
     var mid = (a + b) div 2
     var c = cmpIgnoreCase(x[mid], y)
-    if c < 0: 
+    if c < 0:
       a = mid + 1
-    elif c > 0: 
+    elif c > 0:
       b = mid - 1
-    else: 
+    else:
       return mid
   result = - 1
 
diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim
index 300abea1e..b7fe269df 100644
--- a/compiler/parampatterns.nim
+++ b/compiler/parampatterns.nim
@@ -24,7 +24,7 @@ type
     ppEof = 1, # end of compiled pattern
     ppOr,      # we could short-cut the evaluation for 'and' and 'or',
     ppAnd,     # but currently we don't
-    ppNot, 
+    ppNot,
     ppSym,
     ppAtom,
     ppLit,
@@ -41,7 +41,7 @@ type
 const
   MaxStackSize* = 64 ## max required stack size by the VM
 
-proc patternError(n: PNode) = 
+proc patternError(n: PNode) =
   localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
 
 proc add(code: var TPatternCode, op: TOpcode) {.inline.} =
@@ -56,7 +56,7 @@ proc whichAlias*(p: PSym): TAliasRequest =
 proc compileConstraints(p: PNode, result: var TPatternCode) =
   case p.kind
   of nkCallKinds:
-    if p.sons[0].kind != nkIdent: 
+    if p.sons[0].kind != nkIdent:
       patternError(p.sons[0])
       return
     let op = p.sons[0].ident
@@ -131,11 +131,10 @@ proc semNodeKindConstraints*(p: PNode): PNode =
   result.strVal.add(ppEof)
 
 type
-  TSideEffectAnalysis = enum
+  TSideEffectAnalysis* = enum
     seUnknown, seSideEffect, seNoSideEffect
 
-proc checkForSideEffects(n: PNode): TSideEffectAnalysis =
-  # XXX is 'raise' a side effect?
+proc checkForSideEffects*(n: PNode): TSideEffectAnalysis =
   case n.kind
   of nkCallKinds:
     # only calls can produce side effects:
@@ -162,19 +161,22 @@ proc checkForSideEffects(n: PNode): TSideEffectAnalysis =
     # an atom cannot produce a side effect:
     result = seNoSideEffect
   else:
+    # assume no side effect:
+    result = seNoSideEffect
     for i in 0 .. <n.len:
       let ret = checkForSideEffects(n.sons[i])
       if ret == seSideEffect: return ret
       elif ret == seUnknown and result == seNoSideEffect:
         result = seUnknown
 
-type 
-  TAssignableResult* = enum 
+type
+  TAssignableResult* = enum
     arNone,                   # no l-value and no discriminant
     arLValue,                 # is an l-value
     arLocalLValue,            # is an l-value, but local var; must not escape
                               # its stack frame!
-    arDiscriminant            # is a discriminant
+    arDiscriminant,           # is a discriminant
+    arStrange                 # it is a strange beast like 'typedesc[var T]'
 
 proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
   ## 'owner' can be nil!
@@ -183,26 +185,31 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
   of nkSym:
     # don't list 'skLet' here:
     if n.sym.kind in {skVar, skResult, skTemp}:
-      if owner != nil and owner.id == n.sym.owner.id and 
+      if owner != nil and owner.id == n.sym.owner.id and
           sfGlobal notin n.sym.flags:
         result = arLocalLValue
       else:
         result = arLValue
-  of nkDotExpr: 
-    if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind in 
-        {tyVar, tyPtr, tyRef}: 
+    elif n.sym.kind == skParam and n.sym.typ.kind == tyVar:
+      result = arLValue
+    elif n.sym.kind == skType:
+      let t = n.sym.typ.skipTypes({tyTypeDesc})
+      if t.kind == tyVar: result = arStrange
+  of nkDotExpr:
+    if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind in
+        {tyVar, tyPtr, tyRef}:
       result = arLValue
     else:
       result = isAssignable(owner, n.sons[0])
-    if result != arNone and sfDiscriminant in n.sons[1].sym.flags: 
+    if result != arNone and sfDiscriminant in n.sons[1].sym.flags:
       result = arDiscriminant
-  of nkBracketExpr: 
+  of nkBracketExpr:
     if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind in
-        {tyVar, tyPtr, tyRef}: 
+        {tyVar, tyPtr, tyRef}:
       result = arLValue
     else:
       result = isAssignable(owner, n.sons[0])
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv: 
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
     # Object and tuple conversions are still addressable, so we skip them
     # XXX why is 'tyOpenArray' allowed here?
     if skipTypes(n.typ, abstractPtrs-{tyTypeDesc}).kind in
@@ -211,9 +218,9 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
     elif compareTypes(n.typ, n.sons[1].typ, dcEqIgnoreDistinct):
       # types that are equal modulo distinction preserve l-value:
       result = isAssignable(owner, n.sons[1])
-  of nkHiddenDeref, nkDerefExpr: 
+  of nkHiddenDeref, nkDerefExpr, nkHiddenAddr:
     result = arLValue
-  of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: 
+  of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
     result = isAssignable(owner, n.sons[0])
   of nkCallKinds:
     # builtin slice keeps lvalue-ness:
@@ -221,24 +228,27 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
   else:
     discard
 
+proc isLValue*(n: PNode): bool =
+  isAssignable(nil, n) in {arLValue, arLocalLValue, arStrange}
+
 proc matchNodeKinds*(p, n: PNode): bool =
-  # matches the parameter constraint 'p' against the concrete AST 'n'. 
+  # matches the parameter constraint 'p' against the concrete AST 'n'.
   # Efficiency matters here.
   var stack {.noinit.}: array[0..MaxStackSize, bool]
   # empty patterns are true:
   stack[0] = true
   var sp = 1
-  
+
   template push(x: bool) =
     stack[sp] = x
     inc sp
-  
+
   let code = p.strVal
   var pc = 1
   while true:
     case TOpcode(code[pc])
     of ppEof: break
-    of ppOr: 
+    of ppOr:
       stack[sp-2] = stack[sp-1] or stack[sp-2]
       dec sp
     of ppAnd:
@@ -264,4 +274,4 @@ proc matchNodeKinds*(p, n: PNode): bool =
     of ppNoSideEffect: push checkForSideEffects(n) != seSideEffect
     inc pc
   result = stack[sp-1]
-  
+
diff --git a/compiler/parser.nim b/compiler/parser.nim
index a91760e15..0d2ba7cfc 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -12,7 +12,7 @@
 # it uses several helper routines to keep the parser small. A special
 # efficient algorithm is used for the precedence levels. The parser here can
 # be seen as a refinement of the grammar, as it specifies how the AST is built
-# from the grammar and how comments belong to the AST. 
+# from the grammar and how comments belong to the AST.
 
 
 # In fact the grammar is generated from this file:
@@ -74,7 +74,7 @@ proc getTok(p: var TParser) =
 proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream,
                  strongSpaces=false) =
   ## Open a parser, using the given arguments to set up its internal state.
-  ## 
+  ##
   initToken(p.tok)
   openLexer(p.lex, fileIdx, inputStream)
   getTok(p)                   # read the first token
@@ -91,7 +91,7 @@ proc closeParser(p: var TParser) =
 
 proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
   ## Produce and emit the parser message `arg` to output.
-  lexMessage(p.lex, msg, arg)
+  lexMessageTok(p.lex, msg, p.tok, arg)
 
 proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) =
   ## Produce and emit a parser message to output about the token `tok`
@@ -111,7 +111,12 @@ proc rawSkipComment(p: var TParser, node: PNode) =
   if p.tok.tokType == tkComment:
     if node != nil:
       if node.comment == nil: node.comment = ""
-      add(node.comment, p.tok.literal)
+      if p.tok.literal == "[]":
+        node.flags.incl nfIsCursor
+        #echo "parser: "
+        #debug node
+      else:
+        add(node.comment, p.tok.literal)
     else:
       parMessage(p, errInternal, "skipComment")
     getTok(p)
@@ -138,19 +143,19 @@ proc getTokNoInd(p: var TParser) =
 proc expectIdentOrKeyw(p: TParser) =
   if p.tok.tokType != tkSymbol and not isKeyword(p.tok.tokType):
     lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
-  
+
 proc expectIdent(p: TParser) =
   if p.tok.tokType != tkSymbol:
     lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
-  
+
 proc eat(p: var TParser, tokType: TTokType) =
   ## Move the parser to the next token if the current token is of type
   ## `tokType`, otherwise error.
   if p.tok.tokType == tokType:
     getTok(p)
   else:
-    lexMessage(p.lex, errTokenExpected, TokTypeToStr[tokType])
-  
+    lexMessageTok(p.lex, errTokenExpected, p.tok, TokTypeToStr[tokType])
+
 proc parLineInfo(p: TParser): TLineInfo =
   ## Retrieve the line information associated with the parser's current state.
   result = getLineInfo(p.lex, p.tok)
@@ -161,24 +166,24 @@ proc indAndComment(p: var TParser, n: PNode) =
     else: parMessage(p, errInvalidIndentation)
   else:
     skipComment(p, n)
-  
-proc newNodeP(kind: TNodeKind, p: TParser): PNode = 
+
+proc newNodeP(kind: TNodeKind, p: TParser): PNode =
   result = newNodeI(kind, parLineInfo(p))
 
-proc newIntNodeP(kind: TNodeKind, intVal: BiggestInt, p: TParser): PNode = 
+proc newIntNodeP(kind: TNodeKind, intVal: BiggestInt, p: TParser): PNode =
   result = newNodeP(kind, p)
   result.intVal = intVal
 
-proc newFloatNodeP(kind: TNodeKind, floatVal: BiggestFloat, 
+proc newFloatNodeP(kind: TNodeKind, floatVal: BiggestFloat,
                    p: TParser): PNode =
   result = newNodeP(kind, p)
   result.floatVal = floatVal
 
-proc newStrNodeP(kind: TNodeKind, strVal: string, p: TParser): PNode = 
+proc newStrNodeP(kind: TNodeKind, strVal: string, p: TParser): PNode =
   result = newNodeP(kind, p)
   result.strVal = strVal
 
-proc newIdentNodeP(ident: PIdent, p: TParser): PNode = 
+proc newIdentNodeP(ident: PIdent, p: TParser): PNode =
   result = newNodeP(nkIdent, p)
   result.ident = ident
 
@@ -193,8 +198,8 @@ proc isSigilLike(tok: TToken): bool {.inline.} =
 
 proc isRightAssociative(tok: TToken): bool {.inline.} =
   ## Determines whether the token is right assocative.
-  result = tok.tokType == tkOpr and (tok.ident.s[0] == '^' or
-    (let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>'))
+  result = tok.tokType == tkOpr and tok.ident.s[0] == '^'
+  # or (let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>'))
 
 proc getPrecedence(tok: TToken, strongSpaces: bool): int =
   ## Calculates the precedence of the given token.
@@ -207,27 +212,29 @@ proc getPrecedence(tok: TToken, strongSpaces: bool): int =
     let relevantChar = tok.ident.s[0]
 
     # arrow like?
-    if L > 1 and tok.ident.s[L-1] == '>': return considerStrongSpaces(1)
-    
+    if L > 1 and tok.ident.s[L-1] == '>' and
+      tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1)
+
     template considerAsgn(value: expr) =
-      result = if tok.ident.s[L-1] == '=': 1 else: considerStrongSpaces(value)
-    
+      result = if tok.ident.s[L-1] == '=': 1 else: value
+
     case relevantChar
     of '$', '^': considerAsgn(10)
     of '*', '%', '/', '\\': considerAsgn(9)
-    of '~': result = considerStrongSpaces(8)
+    of '~': result = 8
     of '+', '-', '|': considerAsgn(8)
     of '&': considerAsgn(7)
-    of '=', '<', '>', '!': result = considerStrongSpaces(5)
+    of '=', '<', '>', '!': result = 5
     of '.': considerAsgn(6)
-    of '?': result = considerStrongSpaces(2)
+    of '?': result = 2
     else: considerAsgn(2)
   of tkDiv, tkMod, tkShl, tkShr: result = 9
   of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5
-  of tkDotDot: result = considerStrongSpaces(6)
+  of tkDotDot: result = 6
   of tkAnd: result = 4
   of tkOr, tkXor, tkPtr, tkRef: result = 3
-  else: result = -10
+  else: return -10
+  result = considerStrongSpaces(result)
 
 proc isOperator(tok: TToken): bool =
   ## Determines if the given token is an operator type token.
@@ -236,9 +243,15 @@ proc isOperator(tok: TToken): bool =
 
 proc isUnary(p: TParser): bool =
   ## Check if the current parser token is a unary operator
-  p.strongSpaces and p.tok.tokType in {tkOpr, tkDotDot} and
-    p.tok.strongSpaceB == 0 and
-    p.tok.strongSpaceA > 0
+  if p.tok.tokType in {tkOpr, tkDotDot} and
+     p.tok.strongSpaceB == 0 and
+     p.tok.strongSpaceA > 0:
+    # XXX change this after 0.10.4 is out
+    if p.strongSpaces:
+      result = true
+    else:
+      parMessage(p, warnDeprecated,
+        "will be parsed as unary operator; inconsistent spacing")
 
 proc checkBinary(p: TParser) {.inline.} =
   ## Check if the current parser token is a binary operator.
@@ -257,14 +270,14 @@ proc checkBinary(p: TParser) {.inline.} =
 #| semicolon = ';' COMMENT?
 #| colon = ':' COMMENT?
 #| colcom = ':' COMMENT?
-#| 
+#|
 #| operator =  OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9
 #|          | 'or' | 'xor' | 'and'
 #|          | 'is' | 'isnot' | 'in' | 'notin' | 'of'
-#|          | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'addr' | 'static' | '..'
-#| 
+#|          | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'static' | '..'
+#|
 #| prefixOperator = operator
-#| 
+#|
 #| optInd = COMMENT?
 #| optPar = (IND{>} | IND{=})?
 #|
@@ -286,18 +299,18 @@ proc colcom(p: var TParser, n: PNode) =
 
 proc parseSymbol(p: var TParser, allowNil = false): PNode =
   #| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
-  #|        | IDENT
+  #|        | IDENT | 'addr' | 'type'
   case p.tok.tokType
-  of tkSymbol: 
+  of tkSymbol, tkAddr, tkType:
     result = newIdentNodeP(p.tok.ident, p)
     getTok(p)
-  of tkAccent: 
+  of tkAccent:
     result = newNodeP(nkAccQuoted, p)
     getTok(p)
     while true:
       case p.tok.tokType
       of tkAccent:
-        if result.len == 0: 
+        if result.len == 0:
           parMessage(p, errIdentifierExpected, p.tok)
         break
       of tkOpr, tkDot, tkDotDot, tkEquals, tkParLe..tkParDotRi:
@@ -319,15 +332,18 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode =
       getTok(p)
     else:
       parMessage(p, errIdentifierExpected, p.tok)
-      getTok(p) # BUGFIX: We must consume a token here to prevent endless loops!
+      # BUGFIX: We must consume a token here to prevent endless loops!
+      # But: this really sucks for idetools and keywords, so we don't do it
+      # if it is a keyword:
+      if not isKeyword(p.tok.tokType): getTok(p)
       result = ast.emptyNode
 
-proc indexExpr(p: var TParser): PNode = 
+proc indexExpr(p: var TParser): PNode =
   #| indexExpr = expr
   result = parseExpr(p)
 
-proc indexExprList(p: var TParser, first: PNode, k: TNodeKind, 
-                   endToken: TTokType): PNode = 
+proc indexExprList(p: var TParser, first: PNode, k: TNodeKind,
+                   endToken: TTokType): PNode =
   #| indexExprList = indexExpr ^+ comma
   result = newNodeP(k, p)
   addSon(result, first)
@@ -336,7 +352,7 @@ proc indexExprList(p: var TParser, first: PNode, k: TNodeKind,
   while p.tok.tokType notin {endToken, tkEof}:
     var a = indexExpr(p)
     addSon(result, a)
-    if p.tok.tokType != tkComma: break 
+    if p.tok.tokType != tkComma: break
     getTok(p)
     skipComment(p, a)
   optPar(p)
@@ -363,39 +379,28 @@ proc exprColonEqExpr(p: var TParser): PNode =
   var a = parseExpr(p)
   result = colonOrEquals(p, a)
 
-proc exprList(p: var TParser, endTok: TTokType, result: PNode) = 
+proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
   #| exprList = expr ^+ comma
   getTok(p)
   optInd(p, result)
-  while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof): 
+  while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof):
     var a = parseExpr(p)
     addSon(result, a)
-    if p.tok.tokType != tkComma: break 
+    if p.tok.tokType != tkComma: break
     getTok(p)
     optInd(p, a)
-  eat(p, endTok)
 
 proc dotExpr(p: var TParser, a: PNode): PNode =
-  #| dotExpr = expr '.' optInd ('type' | 'addr' | symbol)
+  #| dotExpr = expr '.' optInd symbol
   var info = p.parLineInfo
   getTok(p)
-  optInd(p, a)
-  case p.tok.tokType
-  of tkType:
-    result = newNodeP(nkTypeOfExpr, p)
-    getTok(p)
-    addSon(result, a)
-  of tkAddr:
-    result = newNodeP(nkAddr, p)
-    getTok(p)
-    addSon(result, a)
-  else:
-    result = newNodeI(nkDotExpr, info)
-    addSon(result, a)
-    addSon(result, parseSymbol(p))
+  result = newNodeI(nkDotExpr, info)
+  optInd(p, result)
+  addSon(result, a)
+  addSon(result, parseSymbol(p))
 
-proc qualifiedIdent(p: var TParser): PNode = 
-  #| qualifiedIdent = symbol ('.' optInd ('type' | 'addr' | symbol))?
+proc qualifiedIdent(p: var TParser): PNode =
+  #| qualifiedIdent = symbol ('.' optInd symbol)?
   result = parseSymbol(p)
   if p.tok.tokType == tkDot: result = dotExpr(p, result)
 
@@ -406,7 +411,7 @@ proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) =
   while p.tok.tokType != endTok and p.tok.tokType != tkEof:
     var a = exprColonEqExpr(p)
     addSon(result, a)
-    if p.tok.tokType != tkComma: break 
+    if p.tok.tokType != tkComma: break
     getTok(p)
     skipComment(p, a)
   optPar(p)
@@ -431,13 +436,13 @@ proc setOrTableConstr(p: var TParser): PNode =
       var a = exprColonEqExpr(p)
       if a.kind == nkExprColonExpr: result.kind = nkTableConstr
       addSon(result, a)
-      if p.tok.tokType != tkComma: break 
+      if p.tok.tokType != tkComma: break
       getTok(p)
       skipComment(p, a)
   optPar(p)
   eat(p, tkCurlyRi) # skip '}'
 
-proc parseCast(p: var TParser): PNode = 
+proc parseCast(p: var TParser): PNode =
   #| castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')'
   result = newNodeP(nkCast, p)
   getTok(p)
@@ -452,21 +457,21 @@ proc parseCast(p: var TParser): PNode =
   optPar(p)
   eat(p, tkParRi)
 
-proc setBaseFlags(n: PNode, base: TNumericalBase) = 
+proc setBaseFlags(n: PNode, base: TNumericalBase) =
   case base
   of base10: discard
   of base2: incl(n.flags, nfBase2)
   of base8: incl(n.flags, nfBase8)
   of base16: incl(n.flags, nfBase16)
-  
-proc parseGStrLit(p: var TParser, a: PNode): PNode = 
+
+proc parseGStrLit(p: var TParser, a: PNode): PNode =
   case p.tok.tokType
-  of tkGStrLit: 
+  of tkGStrLit:
     result = newNodeP(nkCallStrLit, p)
     addSon(result, a)
     addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p))
     getTok(p)
-  of tkGTripleStrLit: 
+  of tkGTripleStrLit:
     result = newNodeP(nkCallStrLit, p)
     addSon(result, a)
     addSon(result, newStrNodeP(nkTripleStrLit, p.tok.literal, p))
@@ -494,18 +499,18 @@ proc parsePar(p: var TParser): PNode =
   #| parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try'
   #|         | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let'
   #|         | 'when' | 'var' | 'mixin'
-  #| par = '(' optInd (&parKeyw complexOrSimpleStmt ^+ ';' 
+  #| par = '(' optInd (&parKeyw complexOrSimpleStmt ^+ ';'
   #|                  | simpleExpr ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )?
   #|                             | (':' expr)? (',' (exprColonEqExpr comma?)*)?  )?
   #|         optPar ')'
   #
-  # unfortunately it's ambiguous: (expr: expr) vs (exprStmt); however a 
+  # unfortunately it's ambiguous: (expr: expr) vs (exprStmt); however a
   # leading ';' could be used to enforce a 'stmt' context ...
   result = newNodeP(nkPar, p)
   getTok(p)
   optInd(p, result)
-  if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase, 
-                       tkTry, tkFinally, tkExcept, tkFor, tkBlock, 
+  if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase,
+                       tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock,
                        tkConst, tkLet, tkWhen, tkVar,
                        tkMixin}:
     # XXX 'bind' used to be an expression, so we exclude it here;
@@ -542,13 +547,13 @@ proc parsePar(p: var TParser): PNode =
         while p.tok.tokType != tkParRi and p.tok.tokType != tkEof:
           var a = exprColonEqExpr(p)
           addSon(result, a)
-          if p.tok.tokType != tkComma: break 
+          if p.tok.tokType != tkComma: break
           getTok(p)
           skipComment(p, a)
   optPar(p)
   eat(p, tkParRi)
 
-proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode = 
+proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
   #| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
   #|           | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
   #|           | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
@@ -562,61 +567,61 @@ proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
   #| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
   #| arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']'
   case p.tok.tokType
-  of tkSymbol:
+  of tkSymbol, tkType, tkAddr:
     result = newIdentNodeP(p.tok.ident, p)
     getTok(p)
     result = parseGStrLit(p, result)
-  of tkAccent: 
+  of tkAccent:
     result = parseSymbol(p)       # literals
   of tkIntLit:
     result = newIntNodeP(nkIntLit, p.tok.iNumber, p)
     setBaseFlags(result, p.tok.base)
     getTok(p)
-  of tkInt8Lit: 
+  of tkInt8Lit:
     result = newIntNodeP(nkInt8Lit, p.tok.iNumber, p)
     setBaseFlags(result, p.tok.base)
     getTok(p)
-  of tkInt16Lit: 
+  of tkInt16Lit:
     result = newIntNodeP(nkInt16Lit, p.tok.iNumber, p)
     setBaseFlags(result, p.tok.base)
     getTok(p)
-  of tkInt32Lit: 
+  of tkInt32Lit:
     result = newIntNodeP(nkInt32Lit, p.tok.iNumber, p)
     setBaseFlags(result, p.tok.base)
     getTok(p)
-  of tkInt64Lit: 
+  of tkInt64Lit:
     result = newIntNodeP(nkInt64Lit, p.tok.iNumber, p)
     setBaseFlags(result, p.tok.base)
     getTok(p)
-  of tkUIntLit: 
+  of tkUIntLit:
     result = newIntNodeP(nkUIntLit, p.tok.iNumber, p)
     setBaseFlags(result, p.tok.base)
     getTok(p)
-  of tkUInt8Lit: 
+  of tkUInt8Lit:
     result = newIntNodeP(nkUInt8Lit, p.tok.iNumber, p)
     setBaseFlags(result, p.tok.base)
     getTok(p)
-  of tkUInt16Lit: 
+  of tkUInt16Lit:
     result = newIntNodeP(nkUInt16Lit, p.tok.iNumber, p)
     setBaseFlags(result, p.tok.base)
     getTok(p)
-  of tkUInt32Lit: 
+  of tkUInt32Lit:
     result = newIntNodeP(nkUInt32Lit, p.tok.iNumber, p)
     setBaseFlags(result, p.tok.base)
     getTok(p)
-  of tkUInt64Lit: 
+  of tkUInt64Lit:
     result = newIntNodeP(nkUInt64Lit, p.tok.iNumber, p)
     setBaseFlags(result, p.tok.base)
     getTok(p)
-  of tkFloatLit: 
+  of tkFloatLit:
     result = newFloatNodeP(nkFloatLit, p.tok.fNumber, p)
     setBaseFlags(result, p.tok.base)
     getTok(p)
-  of tkFloat32Lit: 
+  of tkFloat32Lit:
     result = newFloatNodeP(nkFloat32Lit, p.tok.fNumber, p)
     setBaseFlags(result, p.tok.base)
     getTok(p)
-  of tkFloat64Lit: 
+  of tkFloat64Lit:
     result = newFloatNodeP(nkFloat64Lit, p.tok.fNumber, p)
     setBaseFlags(result, p.tok.base)
     getTok(p)
@@ -624,19 +629,19 @@ proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
     result = newFloatNodeP(nkFloat128Lit, p.tok.fNumber, p)
     setBaseFlags(result, p.tok.base)
     getTok(p)
-  of tkStrLit: 
+  of tkStrLit:
     result = newStrNodeP(nkStrLit, p.tok.literal, p)
     getTok(p)
-  of tkRStrLit: 
+  of tkRStrLit:
     result = newStrNodeP(nkRStrLit, p.tok.literal, p)
     getTok(p)
-  of tkTripleStrLit: 
+  of tkTripleStrLit:
     result = newStrNodeP(nkTripleStrLit, p.tok.literal, p)
     getTok(p)
-  of tkCharLit: 
+  of tkCharLit:
     result = newIntNodeP(nkCharLit, ord(p.tok.literal[0]), p)
     getTok(p)
-  of tkNil: 
+  of tkNil:
     result = newNodeP(nkNilLit, p)
     getTok(p)
   of tkParLe:
@@ -651,7 +656,7 @@ proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
   of tkBracketLe:
     # [] constructor
     result = exprColonEqExprList(p, nkBracket, tkBracketRi)
-  of tkCast: 
+  of tkCast:
     result = parseCast(p)
   else:
     parMessage(p, errExprExpected, p.tok)
@@ -668,11 +673,11 @@ proc namedParams(p: var TParser, callee: PNode,
 proc parseMacroColon(p: var TParser, x: PNode): PNode
 proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
   #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
-  #|               | doBlocks
-  #|               | '.' optInd ('type' | 'addr' | symbol) generalizedLit?
-  #|               | '[' optInd indexExprList optPar ']'
-  #|               | '{' optInd indexExprList optPar '}'
-  #|               | &( '`'|IDENT|literal|'cast') expr # command syntax
+  #|       | doBlocks
+  #|       | '.' optInd symbol generalizedLit?
+  #|       | '[' optInd indexExprList optPar ']'
+  #|       | '{' optInd indexExprList optPar '}'
+  #|       | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax
   result = r
   while p.tok.indent < 0 or
        (p.tok.tokType == tkDot and p.tok.indent >= baseIndent):
@@ -698,21 +703,22 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
     of tkCurlyLe:
       if p.strongSpaces and p.tok.strongSpaceA > 0: break
       result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
-    of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast:
+    of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType:
       if p.inPragma == 0:
         # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet
         # solution, but pragmas.nim can't handle that
         let a = result
         result = newNodeP(nkCommand, p)
         addSon(result, a)
-        addSon result, parseExpr(p)
-        when false:
+        when true:
+          addSon result, parseExpr(p)
+        else:
           while p.tok.tokType != tkEof:
-            let a = parseExpr(p)
-            addSon(result, a)
+            let x = parseExpr(p)
+            addSon(result, x)
             if p.tok.tokType != tkComma: break
             getTok(p)
-            optInd(p, a)
+            optInd(p, x)
           if p.tok.tokType == tkDo:
             parseDoBlocks(p, result)
           else:
@@ -720,7 +726,7 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
       break
     else:
       break
-    
+
 proc primary(p: var TParser, mode: TPrimaryMode): PNode
 proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode
 
@@ -737,7 +743,7 @@ proc parseOperators(p: var TParser, headNode: PNode,
     var a = newNodeP(nkInfix, p)
     var opNode = newIdentNodeP(p.tok.ident, p) # skip operator:
     getTok(p)
-    optInd(p, opNode)
+    optInd(p, a)
     # read sub-expression with higher priority:
     var b = simpleExprAux(p, opPrec + leftAssoc, modeB)
     addSon(a, opNode)
@@ -749,7 +755,7 @@ proc parseOperators(p: var TParser, headNode: PNode,
 proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
   result = primary(p, mode)
   result = parseOperators(p, result, limit, mode)
-  
+
 proc simpleExpr(p: var TParser, mode = pmNormal): PNode =
   result = simpleExprAux(p, -1, mode)
 
@@ -768,7 +774,7 @@ proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
     addSon(branch, parseExpr(p))
     optInd(p, branch)
     addSon(result, branch)
-    if p.tok.tokType != tkElif: break 
+    if p.tok.tokType != tkElif: break
   var branch = newNodeP(nkElseExpr, p)
   eat(p, tkElse)
   colcom(p, branch)
@@ -791,72 +797,73 @@ proc parsePragma(p: var TParser): PNode =
   if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
   else: parMessage(p, errTokenExpected, ".}")
   dec p.inPragma
-  
-proc identVis(p: var TParser): PNode = 
+
+proc identVis(p: var TParser): PNode =
   #| identVis = symbol opr?  # postfix position
   var a = parseSymbol(p)
-  if p.tok.tokType == tkOpr: 
+  if p.tok.tokType == tkOpr:
     result = newNodeP(nkPostfix, p)
     addSon(result, newIdentNodeP(p.tok.ident, p))
     addSon(result, a)
     getTok(p)
-  else: 
+  else:
     result = a
-  
-proc identWithPragma(p: var TParser): PNode = 
+
+proc identWithPragma(p: var TParser): PNode =
   #| identWithPragma = identVis pragma?
   var a = identVis(p)
-  if p.tok.tokType == tkCurlyDotLe: 
+  if p.tok.tokType == tkCurlyDotLe:
     result = newNodeP(nkPragmaExpr, p)
     addSon(result, a)
     addSon(result, parsePragma(p))
-  else: 
+  else:
     result = a
 
 type
-  TDeclaredIdentFlag = enum 
+  TDeclaredIdentFlag = enum
     withPragma,               # identifier may have pragma
     withBothOptional          # both ':' and '=' parts are optional
   TDeclaredIdentFlags = set[TDeclaredIdentFlag]
 
-proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode = 
+proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
   #| declColonEquals = identWithPragma (comma identWithPragma)* comma?
   #|                   (':' optInd typeDesc)? ('=' optInd expr)?
   #| identColonEquals = ident (comma ident)* comma?
   #|      (':' optInd typeDesc)? ('=' optInd expr)?)
   var a: PNode
   result = newNodeP(nkIdentDefs, p)
-  while true: 
+  while true:
     case p.tok.tokType
-    of tkSymbol, tkAccent: 
+    of tkSymbol, tkAccent:
       if withPragma in flags: a = identWithPragma(p)
       else: a = parseSymbol(p)
-      if a.kind == nkEmpty: return 
-    else: break 
+      if a.kind == nkEmpty: return
+    else: break
     addSon(result, a)
-    if p.tok.tokType != tkComma: break 
+    if p.tok.tokType != tkComma: break
     getTok(p)
     optInd(p, a)
-  if p.tok.tokType == tkColon: 
+  if p.tok.tokType == tkColon:
     getTok(p)
     optInd(p, result)
     addSon(result, parseTypeDesc(p))
-  else: 
+  else:
     addSon(result, ast.emptyNode)
-    if p.tok.tokType != tkEquals and withBothOptional notin flags: 
+    if p.tok.tokType != tkEquals and withBothOptional notin flags:
       parMessage(p, errColonOrEqualsExpected, p.tok)
-  if p.tok.tokType == tkEquals: 
+  if p.tok.tokType == tkEquals:
     getTok(p)
     optInd(p, result)
     addSon(result, parseExpr(p))
-  else: 
+  else:
     addSon(result, ast.emptyNode)
-  
+
 proc parseTuple(p: var TParser, indentAllowed = false): PNode =
   #| inlTupleDecl = 'tuple'
   #|     [' optInd  (identColonEquals (comma/semicolon)?)*  optPar ']'
   #| extTupleDecl = 'tuple'
   #|     COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
+  #| tupleClass = 'tuple'
   result = newNodeP(nkTupleTy, p)
   getTok(p)
   if p.tok.tokType == tkBracketLe:
@@ -886,6 +893,8 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
             parMessage(p, errIdentifierExpected, p.tok)
             break
           if not sameInd(p): break
+  else:
+    result = newNodeP(nkTupleClassTy, p)
 
 proc parseParamList(p: var TParser, retColon = true): PNode =
   #| paramList = '(' declColonEquals ^* (comma/semicolon) ')'
@@ -894,20 +903,21 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
   var a: PNode
   result = newNodeP(nkFormalParams, p)
   addSon(result, ast.emptyNode) # return type
-  if p.tok.tokType == tkParLe and p.tok.indent < 0:
+  let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0
+  if hasParLe:
     getTok(p)
     optInd(p, result)
     while true:
       case p.tok.tokType
-      of tkSymbol, tkAccent: 
+      of tkSymbol, tkAccent:
         a = parseIdentColonEquals(p, {withBothOptional, withPragma})
-      of tkParRi: 
-        break 
-      else: 
+      of tkParRi:
+        break
+      else:
         parMessage(p, errTokenExpected, ")")
-        break 
+        break
       addSon(result, a)
-      if p.tok.tokType notin {tkComma, tkSemiColon}: break 
+      if p.tok.tokType notin {tkComma, tkSemiColon}: break
       getTok(p)
       skipComment(p, a)
     optPar(p)
@@ -918,6 +928,9 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
     getTok(p)
     optInd(p, result)
     result.sons[0] = parseTypeDesc(p)
+  elif not retColon and not hasParle:
+    # Mark as "not there" in order to mark for deprecation in the semantic pass:
+    result = ast.emptyNode
 
 proc optPragmas(p: var TParser): PNode =
   if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)):
@@ -931,8 +944,7 @@ proc parseDoBlock(p: var TParser): PNode =
   getTok(p)
   let params = parseParamList(p, retColon=false)
   let pragmas = optPragmas(p)
-  eat(p, tkColon)
-  skipComment(p, result)
+  colcom(p, result)
   result = newProcNode(nkDo, info, parseStmt(p),
                        params = params,
                        pragmas = pragmas)
@@ -942,9 +954,9 @@ proc parseDoBlocks(p: var TParser, call: PNode) =
   if p.tok.tokType == tkDo:
     addSon(call, parseDoBlock(p))
     while sameInd(p) and p.tok.tokType == tkDo:
-      addSon(call, parseDoBlock(p))      
+      addSon(call, parseDoBlock(p))
 
-proc parseProcExpr(p: var TParser, isExpr: bool): PNode = 
+proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
   #| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
   # either a proc type or a anonymous proc
   let info = parLineInfo(p)
@@ -952,7 +964,7 @@ proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
   let hasSignature = p.tok.tokType in {tkParLe, tkColon} and p.tok.indent < 0
   let params = parseParamList(p)
   let pragmas = optPragmas(p)
-  if p.tok.tokType == tkEquals and isExpr: 
+  if p.tok.tokType == tkEquals and isExpr:
     getTok(p)
     skipComment(p, result)
     result = newProcNode(nkLambda, info, parseStmt(p),
@@ -964,11 +976,11 @@ proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
       addSon(result, params)
       addSon(result, pragmas)
 
-proc isExprStart(p: TParser): bool = 
+proc isExprStart(p: TParser): bool =
   case p.tok.tokType
-  of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, 
+  of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf,
      tkProc, tkIterator, tkBind, tkAddr,
-     tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr, 
+     tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
      tkTuple, tkObject, tkType, tkWhen, tkCase:
     result = true
   else: result = false
@@ -998,7 +1010,7 @@ proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
     result.addSon list
     parseSymbolList(p, list, allowNil = true)
 
-proc parseExpr(p: var TParser): PNode = 
+proc parseExpr(p: var TParser): PNode =
   #| expr = (ifExpr
   #|       | whenExpr
   #|       | caseExpr
@@ -1015,12 +1027,11 @@ proc parseEnum(p: var TParser): PNode
 proc parseObject(p: var TParser): PNode
 proc parseTypeClass(p: var TParser): PNode
 
-proc primary(p: var TParser, mode: TPrimaryMode): PNode = 
-  #| typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'type' | 'tuple'
+proc primary(p: var TParser, mode: TPrimaryMode): PNode =
+  #| typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'tuple'
   #|          | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum'
   #| primary = typeKeyw typeDescK
   #|         /  prefixOperator* identOrLiteral primarySuffix*
-  #|         / 'addr' primary
   #|         / 'static' primary
   #|         / 'bind' primary
   if isOperator(p.tok):
@@ -1030,7 +1041,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
     addSon(result, a)
     getTok(p)
     optInd(p, a)
-    if isSigil: 
+    if isSigil:
       #XXX prefix operators
       let baseInd = p.lex.currLineIndent
       addSon(result, primary(p, pmSkipSuffix))
@@ -1038,13 +1049,8 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
     else:
       addSon(result, primary(p, pmNormal))
     return
-  
+
   case p.tok.tokType:
-  of tkVar: result = parseTypeDescKAux(p, nkVarTy, mode)
-  of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode)
-  of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode)
-  of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode)
-  of tkType: result = parseTypeDescKAux(p, nkTypeOfExpr, mode)
   of tkTuple: result = parseTuple(p, mode == pmTypeDef)
   of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
   of tkIterator:
@@ -1073,15 +1079,15 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
     else:
       result = newNodeP(nkObjectTy, p)
       getTok(p)
-  of tkGeneric:
+  of tkGeneric, tkConcept:
     if mode == pmTypeDef:
+      let wasGeneric = p.tok.tokType == tkGeneric
       result = parseTypeClass(p)
+      # hack so that it's remembered and can be marked as deprecated in
+      # sem'check:
+      if wasGeneric: result.flags.incl nfBase2
     else:
       parMessage(p, errInvalidToken, p.tok)
-  of tkAddr:
-    result = newNodeP(nkAddr, p)
-    getTokNoInd(p)
-    addSon(result, primary(p, pmNormal))
   of tkStatic:
     let info = parLineInfo(p)
     getTokNoInd(p)
@@ -1095,6 +1101,10 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
     getTok(p)
     optInd(p, result)
     addSon(result, primary(p, pmNormal))
+  of tkVar: result = parseTypeDescKAux(p, nkVarTy, mode)
+  of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode)
+  of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode)
+  of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode)
   else:
     let baseInd = p.lex.currLineIndent
     result = identOrLiteral(p, mode)
@@ -1105,9 +1115,9 @@ proc parseTypeDesc(p: var TParser): PNode =
   #| typeDesc = simpleExpr
   result = simpleExpr(p, pmTypeDesc)
 
-proc parseTypeDefAux(p: var TParser): PNode = 
+proc parseTypeDefAux(p: var TParser): PNode =
   #| typeDefAux = simpleExpr
-  #|            | 'generic' typeClass
+  #|            | 'concept' typeClass
   result = simpleExpr(p, pmTypeDef)
 
 proc makeCall(n: PNode): PNode =
@@ -1119,7 +1129,7 @@ proc makeCall(n: PNode): PNode =
     result.add n
 
 proc parseMacroColon(p: var TParser, x: PNode): PNode =
-  #| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt 
+  #| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
   #|                        | IND{=} 'elif' expr ':' stmt
   #|                        | IND{=} 'except' exprList ':' stmt
   #|                        | IND{=} 'else' ':' stmt )*
@@ -1128,45 +1138,48 @@ proc parseMacroColon(p: var TParser, x: PNode): PNode =
     result = makeCall(result)
     getTok(p)
     skipComment(p, result)
+    let stmtList = newNodeP(nkStmtList, p)
     if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
       let body = parseStmt(p)
-      addSon(result, newProcNode(nkDo, body.info, body))
+      stmtList.add body
+      #addSon(result, makeStmtList(body))
     while sameInd(p):
       var b: PNode
       case p.tok.tokType
       of tkOf:
         b = newNodeP(nkOfBranch, p)
         exprList(p, tkColon, b)
-      of tkElif: 
+      of tkElif:
         b = newNodeP(nkElifBranch, p)
         getTok(p)
         optInd(p, b)
         addSon(b, parseExpr(p))
-        eat(p, tkColon)
-      of tkExcept: 
+      of tkExcept:
         b = newNodeP(nkExceptBranch, p)
         exprList(p, tkColon, b)
-        skipComment(p, b)
-      of tkElse: 
+      of tkElse:
         b = newNodeP(nkElse, p)
         getTok(p)
-        eat(p, tkColon)
-      else: break 
+      else: break
+      eat(p, tkColon)
       addSon(b, parseStmt(p))
-      addSon(result, b)
+      addSon(stmtList, b)
       if b.kind == nkElse: break
+    if stmtList.len == 1 and stmtList[0].kind == nkStmtList:
+      # to keep backwards compatibility (see tests/vm/tstringnil)
+      result.add stmtList[0]
+    else:
+      result.add stmtList
 
-proc parseExprStmt(p: var TParser): PNode = 
+proc parseExprStmt(p: var TParser): PNode =
   #| exprStmt = simpleExpr
   #|          (( '=' optInd expr )
   #|          / ( expr ^+ comma
   #|              doBlocks
   #|               / macroColon
   #|            ))?
-  inc p.inPragma
   var a = simpleExpr(p)
-  dec p.inPragma
-  if p.tok.tokType == tkEquals: 
+  if p.tok.tokType == tkEquals:
     getTok(p)
     optInd(p, result)
     var b = parseExpr(p)
@@ -1174,12 +1187,24 @@ proc parseExprStmt(p: var TParser): PNode =
     addSon(result, a)
     addSon(result, b)
   else:
-    if p.tok.indent < 0 and isExprStart(p):
-      result = newNode(nkCommand, a.info, @[a])
+    # simpleExpr parsed 'p a' from 'p a, b'?
+    if p.tok.indent < 0 and p.tok.tokType == tkComma and a.kind == nkCommand:
+      result = a
+      while true:
+        getTok(p)
+        optInd(p, result)
+        var e = parseExpr(p)
+        addSon(result, e)
+        if p.tok.tokType != tkComma: break
+    elif p.tok.indent < 0 and isExprStart(p):
+      if a.kind == nkCommand:
+        result = a
+      else:
+        result = newNode(nkCommand, a.info, @[a])
       while true:
         var e = parseExpr(p)
         addSon(result, e)
-        if p.tok.tokType != tkComma: break 
+        if p.tok.tokType != tkComma: break
         getTok(p)
         optInd(p, result)
     else:
@@ -1235,7 +1260,7 @@ proc parseIncludeStmt(p: var TParser): PNode =
     var a = parseExpr(p)
     if a.kind == nkEmpty: break
     addSon(result, a)
-    if p.tok.tokType != tkComma: break 
+    if p.tok.tokType != tkComma: break
     getTok(p)
     optInd(p, a)
   #expectNl(p)
@@ -1254,12 +1279,12 @@ proc parseFromStmt(p: var TParser): PNode =
     a = parseExpr(p)
     if a.kind == nkEmpty: break
     addSon(result, a)
-    if p.tok.tokType != tkComma: break 
+    if p.tok.tokType != tkComma: break
     getTok(p)
     optInd(p, a)
   #expectNl(p)
 
-proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode = 
+proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
   #| returnStmt = 'return' optInd expr?
   #| raiseStmt = 'raise' optInd expr?
   #| yieldStmt = 'yield' optInd expr?
@@ -1289,8 +1314,7 @@ proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
     var branch = newNodeP(nkElifBranch, p)
     optInd(p, branch)
     addSon(branch, parseExpr(p))
-    eat(p, tkColon)
-    skipComment(p, branch)
+    colcom(p, branch)
     addSon(branch, parseStmt(p))
     skipComment(p, branch)
     addSon(result, branch)
@@ -1298,8 +1322,7 @@ proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
   if p.tok.tokType == tkElse and sameOrNoInd(p):
     var branch = newNodeP(nkElse, p)
     eat(p, tkElse)
-    eat(p, tkColon)
-    skipComment(p, branch)
+    colcom(p, branch)
     addSon(branch, parseStmt(p))
     addSon(result, branch)
 
@@ -1329,12 +1352,12 @@ proc parseCase(p: var TParser): PNode =
   addSon(result, parseExpr(p))
   if p.tok.tokType == tkColon: getTok(p)
   skipComment(p, result)
-  
+
   let oldInd = p.currInd
   if realInd(p):
     p.currInd = p.tok.indent
     wasIndented = true
-  
+
   while sameInd(p):
     case p.tok.tokType
     of tkOf:
@@ -1347,20 +1370,18 @@ proc parseCase(p: var TParser): PNode =
       getTok(p)
       optInd(p, b)
       addSon(b, parseExpr(p))
-      eat(p, tkColon)
     of tkElse:
       b = newNodeP(nkElse, p)
       getTok(p)
-      eat(p, tkColon)
     else: break
-    skipComment(p, b)
+    colcom(p, b)
     addSon(b, parseStmt(p))
     addSon(result, b)
     if b.kind == nkElse: break
-  
+
   if wasIndented:
     p.currInd = oldInd
-    
+
 proc parseTry(p: var TParser; isExpr: bool): PNode =
   #| tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally')
   #|            (IND{=}? 'except' exprList colcom stmt)*
@@ -1370,8 +1391,7 @@ proc parseTry(p: var TParser; isExpr: bool): PNode =
   #|            (optInd 'finally' colcom stmt)?
   result = newNodeP(nkTryStmt, p)
   getTok(p)
-  eat(p, tkColon)
-  skipComment(p, result)
+  colcom(p, result)
   addSon(result, parseStmt(p))
   var b: PNode = nil
   while sameOrNoInd(p) or isExpr:
@@ -1381,19 +1401,18 @@ proc parseTry(p: var TParser; isExpr: bool): PNode =
       exprList(p, tkColon, b)
     of tkFinally:
       b = newNodeP(nkFinally, p)
-      getTokNoInd(p)
-      eat(p, tkColon)
+      getTok(p)
     else: break
-    skipComment(p, b)
+    colcom(p, b)
     addSon(b, parseStmt(p))
     addSon(result, b)
-    if b.kind == nkFinally: break 
+    if b.kind == nkFinally: break
   if b == nil: parMessage(p, errTokenExpected, "except")
 
 proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode =
   #| exceptBlock = 'except' colcom stmt
   result = newNodeP(kind, p)
-  getTokNoInd(p)
+  getTok(p)
   colcom(p, result)
   addSon(result, parseStmt(p))
 
@@ -1413,7 +1432,7 @@ proc parseFor(p: var TParser): PNode =
   colcom(p, result)
   addSon(result, parseStmt(p))
 
-proc parseBlock(p: var TParser): PNode = 
+proc parseBlock(p: var TParser): PNode =
   #| blockStmt = 'block' symbol? colcom stmt
   result = newNodeP(nkBlockStmt, p)
   getTokNoInd(p)
@@ -1426,10 +1445,10 @@ proc parseStaticOrDefer(p: var TParser; k: TNodeKind): PNode =
   #| staticStmt = 'static' colcom stmt
   #| deferStmt = 'defer' colcom stmt
   result = newNodeP(k, p)
-  getTokNoInd(p)
+  getTok(p)
   colcom(p, result)
   addSon(result, parseStmt(p))
-  
+
 proc parseAsm(p: var TParser): PNode =
   #| asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLE_STR_LIT)
   result = newNodeP(nkAsmStmt, p)
@@ -1439,51 +1458,51 @@ proc parseAsm(p: var TParser): PNode =
   case p.tok.tokType
   of tkStrLit: addSon(result, newStrNodeP(nkStrLit, p.tok.literal, p))
   of tkRStrLit: addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p))
-  of tkTripleStrLit: addSon(result, 
+  of tkTripleStrLit: addSon(result,
                             newStrNodeP(nkTripleStrLit, p.tok.literal, p))
-  else: 
+  else:
     parMessage(p, errStringLiteralExpected)
     addSon(result, ast.emptyNode)
-    return 
+    return
   getTok(p)
 
 proc parseGenericParam(p: var TParser): PNode =
   #| genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)?
   var a: PNode
   result = newNodeP(nkIdentDefs, p)
-  while true: 
+  while true:
     case p.tok.tokType
-    of tkSymbol, tkAccent: 
+    of tkSymbol, tkAccent:
       a = parseSymbol(p)
-      if a.kind == nkEmpty: return 
-    else: break 
+      if a.kind == nkEmpty: return
+    else: break
     addSon(result, a)
-    if p.tok.tokType != tkComma: break 
+    if p.tok.tokType != tkComma: break
     getTok(p)
     optInd(p, a)
-  if p.tok.tokType == tkColon: 
+  if p.tok.tokType == tkColon:
     getTok(p)
     optInd(p, result)
     addSon(result, parseExpr(p))
-  else: 
+  else:
     addSon(result, ast.emptyNode)
-  if p.tok.tokType == tkEquals: 
+  if p.tok.tokType == tkEquals:
     getTok(p)
     optInd(p, result)
     addSon(result, parseExpr(p))
-  else: 
+  else:
     addSon(result, ast.emptyNode)
 
-proc parseGenericParamList(p: var TParser): PNode = 
+proc parseGenericParamList(p: var TParser): PNode =
   #| genericParamList = '[' optInd
   #|   genericParam ^* (comma/semicolon) optPar ']'
   result = newNodeP(nkGenericParams, p)
   getTok(p)
   optInd(p, result)
-  while p.tok.tokType in {tkSymbol, tkAccent}: 
+  while p.tok.tokType in {tkSymbol, tkAccent}:
     var a = parseGenericParam(p)
     addSon(result, a)
-    if p.tok.tokType notin {tkComma, tkSemiColon}: break 
+    if p.tok.tokType notin {tkComma, tkSemiColon}: break
     getTok(p)
     skipComment(p, a)
   optPar(p)
@@ -1498,7 +1517,7 @@ proc parsePattern(p: var TParser): PNode =
 proc validInd(p: var TParser): bool =
   result = p.tok.indent < 0 or p.tok.indent > p.currInd
 
-proc parseRoutine(p: var TParser, kind: TNodeKind): PNode = 
+proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
   #| indAndComment = (IND{>} COMMENT)? | COMMENT?
   #| routine = optInd identVis pattern? genericParamList?
   #|   paramListColon pragma? ('=' COMMENT? stmt)? indAndComment
@@ -1517,14 +1536,14 @@ proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
   else: addSon(result, ast.emptyNode)
   # empty exception tracking:
   addSon(result, ast.emptyNode)
-  if p.tok.tokType == tkEquals and p.validInd: 
+  if p.tok.tokType == tkEquals and p.validInd:
     getTok(p)
     skipComment(p, result)
     addSon(result, parseStmt(p))
   else:
     addSon(result, ast.emptyNode)
   indAndComment(p, result)
-  
+
 proc newCommentStmt(p: var TParser): PNode =
   #| commentStmt = COMMENT
   result = newNodeP(nkCommentStmt, p)
@@ -1545,39 +1564,39 @@ proc parseSection(p: var TParser, kind: TNodeKind,
       skipComment(p, result)
       while sameInd(p):
         case p.tok.tokType
-        of tkSymbol, tkAccent, tkParLe: 
+        of tkSymbol, tkAccent, tkParLe:
           var a = defparser(p)
           skipComment(p, a)
           addSon(result, a)
-        of tkComment: 
+        of tkComment:
           var a = newCommentStmt(p)
           addSon(result, a)
-        else: 
+        else:
           parMessage(p, errIdentifierExpected, p.tok)
           break
     if result.len == 0: parMessage(p, errIdentifierExpected, p.tok)
   elif p.tok.tokType in {tkSymbol, tkAccent, tkParLe} and p.tok.indent < 0:
     # tkParLe is allowed for ``var (x, y) = ...`` tuple parsing
     addSon(result, defparser(p))
-  else: 
+  else:
     parMessage(p, errIdentifierExpected, p.tok)
-  
+
 proc parseConstant(p: var TParser): PNode =
   #| constant = identWithPragma (colon typedesc)? '=' optInd expr indAndComment
   result = newNodeP(nkConstDef, p)
   addSon(result, identWithPragma(p))
-  if p.tok.tokType == tkColon: 
+  if p.tok.tokType == tkColon:
     getTok(p)
     optInd(p, result)
     addSon(result, parseTypeDesc(p))
-  else: 
+  else:
     addSon(result, ast.emptyNode)
   eat(p, tkEquals)
   optInd(p, result)
   addSon(result, parseExpr(p))
   indAndComment(p, result)
-  
-proc parseEnum(p: var TParser): PNode = 
+
+proc parseEnum(p: var TParser): PNode =
   #| enum = 'enum' optInd (symbol optInd ('=' optInd expr COMMENT?)? comma?)+
   result = newNodeP(nkEnumTy, p)
   getTok(p)
@@ -1585,10 +1604,11 @@ proc parseEnum(p: var TParser): PNode =
   optInd(p, result)
   while true:
     var a = parseSymbol(p)
+    if a.kind == nkEmpty: return
     if p.tok.indent >= 0 and p.tok.indent <= p.currInd:
       add(result, a)
       break
-    if p.tok.tokType == tkEquals and p.tok.indent < 0: 
+    if p.tok.tokType == tkEquals and p.tok.indent < 0:
       getTok(p)
       optInd(p, a)
       var b = a
@@ -1606,15 +1626,15 @@ proc parseEnum(p: var TParser): PNode =
         p.tok.tokType == tkEof:
       break
   if result.len <= 1:
-    lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
+    lexMessageTok(p.lex, errIdentifierExpected, p.tok, prettyTok(p.tok))
 
 proc parseObjectPart(p: var TParser): PNode
-proc parseObjectWhen(p: var TParser): PNode = 
+proc parseObjectWhen(p: var TParser): PNode =
   #| objectWhen = 'when' expr colcom objectPart COMMENT?
   #|             ('elif' expr colcom objectPart COMMENT?)*
   #|             ('else' colcom objectPart COMMENT?)?
   result = newNodeP(nkRecWhen, p)
-  while sameInd(p): 
+  while sameInd(p):
     getTok(p)                 # skip `when`, `elif`
     var branch = newNodeP(nkElifBranch, p)
     optInd(p, branch)
@@ -1632,7 +1652,7 @@ proc parseObjectWhen(p: var TParser): PNode =
     skipComment(p, branch)
     addSon(result, branch)
 
-proc parseObjectCase(p: var TParser): PNode = 
+proc parseObjectCase(p: var TParser): PNode =
   #| objectBranch = 'of' exprList colcom objectPart
   #| objectBranches = objectBranch (IND{=} objectBranch)*
   #|                       (IND{=} 'elif' expr colcom objectPart)*
@@ -1658,15 +1678,14 @@ proc parseObjectCase(p: var TParser): PNode =
   while sameInd(p):
     var b: PNode
     case p.tok.tokType
-    of tkOf: 
+    of tkOf:
       b = newNodeP(nkOfBranch, p)
       exprList(p, tkColon, b)
-    of tkElse: 
+    of tkElse:
       b = newNodeP(nkElse, p)
       getTok(p)
-      eat(p, tkColon)
-    else: break 
-    skipComment(p, b)
+    else: break
+    colcom(p, b)
     var fields = parseObjectPart(p)
     if fields.kind == nkEmpty:
       parMessage(p, errIdentifierExpected, p.tok)
@@ -1676,17 +1695,17 @@ proc parseObjectCase(p: var TParser): PNode =
     if b.kind == nkElse: break
   if wasIndented:
     p.currInd = oldInd
-  
-proc parseObjectPart(p: var TParser): PNode = 
+
+proc parseObjectPart(p: var TParser): PNode =
   #| objectPart = IND{>} objectPart^+IND{=} DED
-  #|            / objectWhen / objectCase / 'nil' / declColonEquals
+  #|            / objectWhen / objectCase / 'nil' / 'discard' / declColonEquals
   if realInd(p):
     result = newNodeP(nkRecList, p)
     withInd(p):
       rawSkipComment(p, result)
       while sameInd(p):
         case p.tok.tokType
-        of tkCase, tkWhen, tkSymbol, tkAccent, tkNil: 
+        of tkCase, tkWhen, tkSymbol, tkAccent, tkNil, tkDiscard:
           addSon(result, parseObjectPart(p))
         else:
           parMessage(p, errIdentifierExpected, p.tok)
@@ -1700,13 +1719,13 @@ proc parseObjectPart(p: var TParser): PNode =
     of tkSymbol, tkAccent:
       result = parseIdentColonEquals(p, {withPragma})
       skipComment(p, result)
-    of tkNil:
+    of tkNil, tkDiscard:
       result = newNodeP(nkNilLit, p)
       getTok(p)
     else:
       result = ast.emptyNode
-  
-proc parseObject(p: var TParser): PNode = 
+
+proc parseObject(p: var TParser): PNode =
   #| object = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart
   result = newNodeP(nkObjectTy, p)
   getTok(p)
@@ -1719,7 +1738,7 @@ proc parseObject(p: var TParser): PNode =
     getTok(p)
     addSon(a, parseTypeDesc(p))
     addSon(result, a)
-  else: 
+  else:
     addSon(result, ast.emptyNode)
   if p.tok.tokType == tkComment:
     skipComment(p, result)
@@ -1731,8 +1750,8 @@ proc parseObject(p: var TParser): PNode =
 
 proc parseTypeClassParam(p: var TParser): PNode =
   if p.tok.tokType == tkVar:
+    result = newNodeP(nkVarTy, p)
     getTok(p)
-    result = newNode(nkVarTy)
     result.addSon(p.parseSymbol)
   else:
     result = p.parseSymbol
@@ -1743,7 +1762,7 @@ proc parseTypeClass(p: var TParser): PNode =
   #|               &IND{>} stmt
   result = newNodeP(nkTypeClassTy, p)
   getTok(p)
-  var args = newNode(nkArgList)
+  var args = newNodeP(nkArgList, p)
   addSon(result, args)
   addSon(args, p.parseTypeClassParam)
   while p.tok.tokType == tkComma:
@@ -1771,7 +1790,7 @@ proc parseTypeClass(p: var TParser): PNode =
   else:
     addSon(result, parseStmt(p))
 
-proc parseTypeDef(p: var TParser): PNode = 
+proc parseTypeDef(p: var TParser): PNode =
   #| typeDef = identWithPragma genericParamList? '=' optInd typeDefAux
   #|             indAndComment?
   result = newNodeP(nkTypeDef, p)
@@ -1787,16 +1806,16 @@ proc parseTypeDef(p: var TParser): PNode =
   else:
     addSon(result, ast.emptyNode)
   indAndComment(p, result)    # special extension!
-  
+
 proc parseVarTuple(p: var TParser): PNode =
   #| varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr
   result = newNodeP(nkVarTuple, p)
   getTok(p)                   # skip '('
   optInd(p, result)
-  while p.tok.tokType in {tkSymbol, tkAccent}: 
+  while p.tok.tokType in {tkSymbol, tkAccent}:
     var a = identWithPragma(p)
     addSon(result, a)
-    if p.tok.tokType != tkComma: break 
+    if p.tok.tokType != tkComma: break
     getTok(p)
     skipComment(p, a)
   addSon(result, ast.emptyNode)         # no type desc
@@ -1811,7 +1830,7 @@ proc parseVariable(p: var TParser): PNode =
   if p.tok.tokType == tkParLe: result = parseVarTuple(p)
   else: result = parseIdentColonEquals(p, {withPragma})
   indAndComment(p, result)
-  
+
 proc parseBind(p: var TParser, k: TNodeKind): PNode =
   #| bindStmt = 'bind' optInd qualifiedIdent ^+ comma
   #| mixinStmt = 'mixin' optInd qualifiedIdent ^+ comma
@@ -1825,7 +1844,7 @@ proc parseBind(p: var TParser, k: TNodeKind): PNode =
     getTok(p)
     optInd(p, a)
   #expectNl(p)
-  
+
 proc parseStmtPragma(p: var TParser): PNode =
   #| pragmaStmt = pragma (':' COMMENT? stmt)?
   result = parsePragma(p)
@@ -1837,7 +1856,7 @@ proc parseStmtPragma(p: var TParser): PNode =
     result.add a
     result.add parseStmt(p)
 
-proc simpleStmt(p: var TParser): PNode = 
+proc simpleStmt(p: var TParser): PNode =
   #| simpleStmt = ((returnStmt | raiseStmt | yieldStmt | discardStmt | breakStmt
   #|            | continueStmt | pragmaStmt | importStmt | exportStmt | fromStmt
   #|            | includeStmt | commentStmt) / exprStmt) COMMENT?
@@ -1859,10 +1878,10 @@ proc simpleStmt(p: var TParser): PNode =
     if isExprStart(p): result = parseExprStmt(p)
     else: result = ast.emptyNode
   if result.kind notin {nkEmpty, nkCommentStmt}: skipComment(p, result)
-  
+
 proc complexOrSimpleStmt(p: var TParser): PNode =
   #| complexOrSimpleStmt = (ifStmt | whenStmt | whileStmt
-  #|                     | tryStmt | finallyStmt | exceptStmt | forStmt
+  #|                     | tryStmt | forStmt
   #|                     | blockStmt | staticStmt | deferStmt | asmStmt
   #|                     | 'proc' routine
   #|                     | 'method' routine
@@ -1911,7 +1930,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
   of tkMixin: result = parseBind(p, nkMixinStmt)
   of tkUsing: result = parseBind(p, nkUsingStmt)
   else: result = simpleStmt(p)
-  
+
 proc parseStmt(p: var TParser): PNode =
   #| stmt = (IND{>} complexOrSimpleStmt^+(IND{=} / ';') DED)
   #|      / simpleStmt ^+ ';'
@@ -1960,14 +1979,14 @@ proc parseStmt(p: var TParser): PNode =
           result.add(a)
           if p.tok.tokType != tkSemiColon: break
           getTok(p)
-  
+
 proc parseAll(p: var TParser): PNode =
   ## Parses the rest of the input stream held by the parser into a PNode.
   result = newNodeP(nkStmtList, p)
-  while p.tok.tokType != tkEof: 
+  while p.tok.tokType != tkEof:
     var a = complexOrSimpleStmt(p)
-    if a.kind != nkEmpty: 
-      addSon(result, a)    
+    if a.kind != nkEmpty:
+      addSon(result, a)
     else:
       parMessage(p, errExprExpected, p.tok)
       # bugfix: consume a token here to prevent an endless loop:
@@ -1980,15 +1999,17 @@ proc parseTopLevelStmt(p: var TParser): PNode =
   ## top-level statement or emptyNode if end of stream.
   result = ast.emptyNode
   while true:
-    if p.tok.indent != 0: 
+    if p.tok.indent != 0:
       if p.firstTok and p.tok.indent < 0: discard
-      else: parMessage(p, errInvalidIndentation)
+      elif p.tok.tokType != tkSemiColon:
+        parMessage(p, errInvalidIndentation)
     p.firstTok = false
     case p.tok.tokType
     of tkSemiColon:
       getTok(p)
       if p.tok.indent <= 0: discard
       else: parMessage(p, errInvalidIndentation)
+      p.firstTok = true
     of tkEof: break
     else:
       result = complexOrSimpleStmt(p)
@@ -2007,8 +2028,8 @@ proc parseString*(s: string; filename: string = ""; line: int = 0;
   var parser: TParser
   # XXX for now the builtin 'parseStmt/Expr' functions do not know about strong
   # spaces...
-  openParser(parser, filename, stream, false)
   parser.lex.errorHandler = errorHandler
+  openParser(parser, filename, stream, false)
 
   result = parser.parseAll
   closeParser(parser)
diff --git a/compiler/passes.nim b/compiler/passes.nim
index a63e29b35..129d8ad47 100644
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -10,15 +10,15 @@
 # This module implements the passes functionality. A pass must implement the
 # `TPass` interface.
 
-import 
-  strutils, lists, options, ast, astalgo, llstream, msgs, platform, os, 
-  condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, 
+import
+  strutils, lists, options, ast, astalgo, llstream, msgs, platform, os,
+  condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
   nimsets, syntaxes, times, rodread, idgen
 
-type  
+type
   TPassContext* = object of RootObj # the pass's context
     fromCache*: bool  # true if created by "openCached"
-   
+
   PPassContext* = ref TPassContext
 
   TPassOpen* = proc (module: PSym): PPassContext {.nimcall.}
@@ -33,8 +33,8 @@ type
   TPassData* = tuple[input: PNode, closeOutput: PNode]
   TPasses* = openArray[TPass]
 
-# a pass is a tuple of procedure vars ``TPass.close`` may produce additional 
-# nodes. These are passed to the other close procedures. 
+# a pass is a tuple of procedure vars ``TPass.close`` may produce additional
+# nodes. These are passed to the other close procedures.
 # This mechanism used to be used for the instantiation of generics.
 
 proc makePass*(open: TPassOpen = nil,
@@ -53,46 +53,46 @@ proc makePass*(open: TPassOpen = nil,
 proc processModule*(module: PSym, stream: PLLStream, rd: PRodReader)
 
 # the semantic checker needs these:
-var 
+var
   gImportModule*: proc (m: PSym, fileIdx: int32): PSym {.nimcall.}
   gIncludeFile*: proc (m: PSym, fileIdx: int32): PNode {.nimcall.}
 
 # implementation
 
-proc skipCodegen*(n: PNode): bool {.inline.} = 
-  # can be used by codegen passes to determine whether they should do 
+proc skipCodegen*(n: PNode): bool {.inline.} =
+  # can be used by codegen passes to determine whether they should do
   # something with `n`. Currently, this ignores `n` and uses the global
   # error count instead.
   result = msgs.gErrorCounter > 0
 
-proc astNeeded*(s: PSym): bool = 
+proc astNeeded*(s: PSym): bool =
   # The ``rodwrite`` module uses this to determine if the body of a proc
   # needs to be stored. The passes manager frees s.sons[codePos] when
   # appropriate to free the procedure body's memory. This is important
   # to keep memory usage down.
   if (s.kind in {skMethod, skProc}) and
       ({sfCompilerProc, sfCompileTime} * s.flags == {}) and
-      (s.typ.callConv != ccInline) and 
-      (s.ast.sons[genericParamsPos].kind == nkEmpty): 
+      (s.typ.callConv != ccInline) and
+      (s.ast.sons[genericParamsPos].kind == nkEmpty):
     result = false
     # XXX this doesn't really make sense with excessive CTFE
   else:
     result = true
-  
-const 
+
+const
   maxPasses = 10
 
-type 
+type
   TPassContextArray = array[0..maxPasses - 1, PPassContext]
 
-var 
+var
   gPasses: array[0..maxPasses - 1, TPass]
   gPassesLen*: int
 
 proc clearPasses* =
   gPassesLen = 0
 
-proc registerPass*(p: TPass) = 
+proc registerPass*(p: TPass) =
   gPasses[gPassesLen] = p
   inc(gPassesLen)
 
@@ -109,48 +109,48 @@ proc carryPasses*(nodes: PNode, module: PSym, passes: TPasses) =
     passdata = carryPass(pass, module, passdata)
 
 proc openPasses(a: var TPassContextArray, module: PSym) =
-  for i in countup(0, gPassesLen - 1): 
-    if not isNil(gPasses[i].open): 
+  for i in countup(0, gPassesLen - 1):
+    if not isNil(gPasses[i].open):
       a[i] = gPasses[i].open(module)
     else: a[i] = nil
-  
+
 proc openPassesCached(a: var TPassContextArray, module: PSym, rd: PRodReader) =
-  for i in countup(0, gPassesLen - 1): 
-    if not isNil(gPasses[i].openCached): 
+  for i in countup(0, gPassesLen - 1):
+    if not isNil(gPasses[i].openCached):
       a[i] = gPasses[i].openCached(module, rd)
-      if a[i] != nil: 
+      if a[i] != nil:
         a[i].fromCache = true
     else:
       a[i] = nil
-  
-proc closePasses(a: var TPassContextArray) = 
+
+proc closePasses(a: var TPassContextArray) =
   var m: PNode = nil
-  for i in countup(0, gPassesLen - 1): 
+  for i in countup(0, gPassesLen - 1):
     if not isNil(gPasses[i].close): m = gPasses[i].close(a[i], m)
     a[i] = nil                # free the memory here
-  
-proc processTopLevelStmt(n: PNode, a: var TPassContextArray): bool = 
+
+proc processTopLevelStmt(n: PNode, a: var TPassContextArray): bool =
   # this implements the code transformation pipeline
   var m = n
-  for i in countup(0, gPassesLen - 1): 
-    if not isNil(gPasses[i].process): 
+  for i in countup(0, gPassesLen - 1):
+    if not isNil(gPasses[i].process):
       m = gPasses[i].process(a[i], m)
       if isNil(m): return false
   result = true
-  
-proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) = 
+
+proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) =
   # this implements the code transformation pipeline
   var m = n
-  for i in countup(0, gPassesLen - 1): 
+  for i in countup(0, gPassesLen - 1):
     if not isNil(gPasses[i].openCached): m = gPasses[i].process(a[i], m)
-  
-proc closePassesCached(a: var TPassContextArray) = 
+
+proc closePassesCached(a: var TPassContextArray) =
   var m: PNode = nil
-  for i in countup(0, gPassesLen - 1): 
-    if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close): 
+  for i in countup(0, gPassesLen - 1):
+    if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close):
       m = gPasses[i].close(a[i], m)
     a[i] = nil                # free the memory here
-  
+
 proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
                       a: var TPassContextArray) =
   for module in items(implicits):
@@ -159,41 +159,45 @@ proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
     str.info = gCmdLineInfo
     importStmt.addSon str
     if not processTopLevelStmt(importStmt, a): break
-  
+
 proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
-  var 
+  var
     p: TParsers
     a: TPassContextArray
     s: PLLStream
     fileIdx = module.fileIdx
-  if rd == nil: 
+  if rd == nil:
     openPasses(a, module)
-    if stream == nil: 
-      let filename = fileIdx.toFullPath
-      s = llStreamOpen(filename, fmRead)
-      if s == nil: 
+    if stream == nil:
+      let filename = fileIdx.toFullPathConsiderDirty
+      if module.name.s == "-":
+        module.name.s = "stdinfile"
+        s = llStreamOpen(stdin)
+      else:
+        s = llStreamOpen(filename, fmRead)
+      if s == nil:
         rawMessage(errCannotOpenFile, filename)
         return
-    else: 
+    else:
       s = stream
-    while true: 
+    while true:
       openParsers(p, fileIdx, s)
 
       if sfSystemModule notin module.flags:
-        # XXX what about caching? no processing then? what if I change the 
+        # XXX what about caching? no processing then? what if I change the
         # modules to include between compilation runs? we'd need to track that
         # in ROD files. I think we should enable this feature only
         # for the interactive mode.
         processImplicits implicitImports, nkImportStmt, a
         processImplicits implicitIncludes, nkIncludeStmt, a
 
-      while true: 
+      while true:
         var n = parseTopLevelStmt(p)
-        if n.kind == nkEmpty: break 
+        if n.kind == nkEmpty: break
         if not processTopLevelStmt(n, a): break
 
       closeParsers(p)
-      if s.kind != llsStdIn: break 
+      if s.kind != llsStdIn: break
     closePasses(a)
     # id synchronization point for more consistent code generation:
     idSynchronizationPoint(1000)
diff --git a/compiler/patterns.nim b/compiler/patterns.nim
index 9ac0988c5..368b0b37b 100644
--- a/compiler/patterns.nim
+++ b/compiler/patterns.nim
@@ -275,7 +275,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
           if arg != rs and aliases.isPartOf(rs, arg) == arYes:
             ok = true
             break
-        # constraint not fullfilled:
+        # constraint not fulfilled:
         if not ok: return nil
       of aqNoAlias:
         # it MUST not alias with any other param:
@@ -284,7 +284,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
           if arg != rs and aliases.isPartOf(rs, arg) != arNo:
             ok = false
             break
-        # constraint not fullfilled:
+        # constraint not fulfilled:
         if not ok: return nil
 
   markUsed(n.info, s)
diff --git a/compiler/platform.nim b/compiler/platform.nim
index 2e78d4fc5..4dd5d8836 100644
--- a/compiler/platform.nim
+++ b/compiler/platform.nim
@@ -1,6 +1,6 @@
 #
 #
-#           The Nimrod Compiler
+#           The Nim Compiler
 #        (c) Copyright 2012 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
@@ -13,188 +13,192 @@
 # Nimrod has been tested on this platform or that the RTL has been ported.
 # Feel free to test for your excentric platform!
 
-import 
+import
   strutils
 
-type 
+type
   TSystemOS* = enum # Also add OS in initialization section and alias
                     # conditionals to condsyms (end of module).
-    osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris, 
-    osIrix, osNetbsd, osFreebsd, osOpenbsd, osAix, osPalmos, osQnx, osAmiga, 
-    osAtari, osNetware, osMacos, osMacosx, osHaiku, osJS, osNimrodVM, 
-    osStandalone
+    osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
+    osIrix, osNetbsd, osFreebsd, osOpenbsd, osAix, osPalmos, osQnx, osAmiga,
+    osAtari, osNetware, osMacos, osMacosx, osHaiku, osVxworks,
+    osJS, osNimrodVM, osStandalone
 
-type 
-  TInfoOSProp* = enum 
+type
+  TInfoOSProp* = enum
     ospNeedsPIC,              # OS needs PIC for libraries
     ospCaseInsensitive,       # OS filesystem is case insensitive
     ospPosix,                 # OS is posix-like
     ospLacksThreadVars        # OS lacks proper __threadvar support
   TInfoOSProps* = set[TInfoOSProp]
-  TInfoOS* = tuple[name: string, parDir: string, dllFrmt: string, 
-                   altDirSep: string, objExt: string, newLine: string, 
-                   pathSep: string, dirSep: string, scriptExt: string, 
-                   curDir: string, exeExt: string, extSep: string, 
+  TInfoOS* = tuple[name: string, parDir: string, dllFrmt: string,
+                   altDirSep: string, objExt: string, newLine: string,
+                   pathSep: string, dirSep: string, scriptExt: string,
+                   curDir: string, exeExt: string, extSep: string,
                    props: TInfoOSProps]
 
-const 
+const
   OS*: array[succ(low(TSystemOS))..high(TSystemOS), TInfoOS] = [
-     (name: "DOS", 
-      parDir: "..", dllFrmt: "$1.dll", altDirSep: "/", objExt: ".obj", 
-      newLine: "\x0D\x0A", pathSep: ";", dirSep: "\\", scriptExt: ".bat", 
-      curDir: ".", exeExt: ".exe", extSep: ".", props: {ospCaseInsensitive}), 
-     (name: "Windows", parDir: "..", dllFrmt: "$1.dll", altDirSep: "/", 
-      objExt: ".obj", newLine: "\x0D\x0A", pathSep: ";", dirSep: "\\", 
-      scriptExt: ".bat", curDir: ".", exeExt: ".exe", extSep: ".", 
-      props: {ospCaseInsensitive}), 
-     (name: "OS2", parDir: "..", 
-      dllFrmt: "$1.dll", altDirSep: "/", 
-      objExt: ".obj", newLine: "\x0D\x0A", 
-      pathSep: ";", dirSep: "\\", 
-      scriptExt: ".bat", curDir: ".", 
-      exeExt: ".exe", extSep: ".", 
-      props: {ospCaseInsensitive}), 
-     (name: "Linux", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", 
-      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", 
-      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", 
-      props: {ospNeedsPIC, ospPosix}), 
-     (name: "MorphOS", parDir: "..", 
-      dllFrmt: "lib$1.so", altDirSep: "/", 
-      objExt: ".o", newLine: "\x0A", 
-      pathSep: ":", dirSep: "/", 
-      scriptExt: ".sh", curDir: ".", 
-      exeExt: "", extSep: ".", 
-      props: {ospNeedsPIC, ospPosix}), 
-     (name: "SkyOS", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", 
-      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", 
-      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", 
-      props: {ospNeedsPIC, ospPosix}), 
-     (name: "Solaris", parDir: "..", 
-      dllFrmt: "lib$1.so", altDirSep: "/", 
-      objExt: ".o", newLine: "\x0A", 
-      pathSep: ":", dirSep: "/", 
-      scriptExt: ".sh", curDir: ".", 
-      exeExt: "", extSep: ".", 
-      props: {ospNeedsPIC, ospPosix}), 
-     (name: "Irix", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", 
-      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", 
-      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", 
-      props: {ospNeedsPIC, ospPosix}), 
-     (name: "NetBSD", parDir: "..", 
-      dllFrmt: "lib$1.so", altDirSep: "/", 
-      objExt: ".o", newLine: "\x0A", 
-      pathSep: ":", dirSep: "/", 
-      scriptExt: ".sh", curDir: ".", 
-      exeExt: "", extSep: ".", 
-      props: {ospNeedsPIC, ospPosix}), 
-     (name: "FreeBSD", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", 
-      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", 
-      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", 
-      props: {ospNeedsPIC, ospPosix}), 
-     (name: "OpenBSD", parDir: "..", 
-      dllFrmt: "lib$1.so", altDirSep: "/", 
-      objExt: ".o", newLine: "\x0A", 
-      pathSep: ":", dirSep: "/", 
-      scriptExt: ".sh", curDir: ".", 
-      exeExt: "", extSep: ".", 
-      props: {ospNeedsPIC, ospPosix}), 
-     (name: "AIX", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", 
-      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", 
-      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", 
-      props: {ospNeedsPIC, ospPosix}), 
-     (name: "PalmOS", parDir: "..", 
-      dllFrmt: "lib$1.so", altDirSep: "/", 
-      objExt: ".o", newLine: "\x0A", 
-      pathSep: ":", dirSep: "/", 
-      scriptExt: ".sh", curDir: ".", 
-      exeExt: "", extSep: ".", 
-      props: {ospNeedsPIC}), 
-     (name: "QNX", 
-      parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", objExt: ".o", 
-      newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh", curDir: ".", 
-      exeExt: "", extSep: ".", props: {ospNeedsPIC, ospPosix}), 
-     (name: "Amiga", 
-      parDir: "..", dllFrmt: "$1.library", altDirSep: "/", objExt: ".o", 
-      newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh", curDir: ".", 
-      exeExt: "", extSep: ".", props: {ospNeedsPIC}), 
-     (name: "Atari", 
-      parDir: "..", dllFrmt: "$1.dll", altDirSep: "/", objExt: ".o", 
-      newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: "", curDir: ".", 
-      exeExt: ".tpp", extSep: ".", props: {ospNeedsPIC}), 
-     (name: "Netware", 
-      parDir: "..", dllFrmt: "$1.nlm", altDirSep: "/", objExt: "", 
-      newLine: "\x0D\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh", 
-      curDir: ".", exeExt: ".nlm", extSep: ".", props: {ospCaseInsensitive}), 
-     (name: "MacOS", parDir: "::", dllFrmt: "$1Lib", altDirSep: ":", 
-      objExt: ".o", newLine: "\x0D", pathSep: ",", dirSep: ":", scriptExt: "", 
-      curDir: ":", exeExt: "", extSep: ".", props: {ospCaseInsensitive}), 
-     (name: "MacOSX", parDir: "..", dllFrmt: "lib$1.dylib", altDirSep: ":", 
-      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", 
-      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", 
-      props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}), 
-     (name: "Haiku", parDir: "..", dllFrmt: "lib$1.so", altDirSep: ":", 
-      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", 
-      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", 
-      props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}), 
-     (name: "JS", parDir: "..", 
-      dllFrmt: "lib$1.so", altDirSep: "/", 
-      objExt: ".o", newLine: "\x0A", 
-      pathSep: ":", dirSep: "/", 
-      scriptExt: ".sh", curDir: ".", 
-      exeExt: "", extSep: ".", props: {}), 
-     (name: "NimrodVM", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", 
-      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", 
+     (name: "DOS",
+      parDir: "..", dllFrmt: "$1.dll", altDirSep: "/", objExt: ".obj",
+      newLine: "\x0D\x0A", pathSep: ";", dirSep: "\\", scriptExt: ".bat",
+      curDir: ".", exeExt: ".exe", extSep: ".", props: {ospCaseInsensitive}),
+     (name: "Windows", parDir: "..", dllFrmt: "$1.dll", altDirSep: "/",
+      objExt: ".obj", newLine: "\x0D\x0A", pathSep: ";", dirSep: "\\",
+      scriptExt: ".bat", curDir: ".", exeExt: ".exe", extSep: ".",
+      props: {ospCaseInsensitive}),
+     (name: "OS2", parDir: "..",
+      dllFrmt: "$1.dll", altDirSep: "/",
+      objExt: ".obj", newLine: "\x0D\x0A",
+      pathSep: ";", dirSep: "\\",
+      scriptExt: ".bat", curDir: ".",
+      exeExt: ".exe", extSep: ".",
+      props: {ospCaseInsensitive}),
+     (name: "Linux", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
+     (name: "MorphOS", parDir: "..",
+      dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A",
+      pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".",
+      exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
+     (name: "SkyOS", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
+     (name: "Solaris", parDir: "..",
+      dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A",
+      pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".",
+      exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
+     (name: "Irix", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
+     (name: "NetBSD", parDir: "..",
+      dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A",
+      pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".",
+      exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
+     (name: "FreeBSD", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
+     (name: "OpenBSD", parDir: "..",
+      dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A",
+      pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".",
+      exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
+     (name: "AIX", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
+     (name: "PalmOS", parDir: "..",
+      dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A",
+      pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".",
+      exeExt: "", extSep: ".",
+      props: {ospNeedsPIC}),
+     (name: "QNX",
+      parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", objExt: ".o",
+      newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh", curDir: ".",
+      exeExt: "", extSep: ".", props: {ospNeedsPIC, ospPosix}),
+     (name: "Amiga",
+      parDir: "..", dllFrmt: "$1.library", altDirSep: "/", objExt: ".o",
+      newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh", curDir: ".",
+      exeExt: "", extSep: ".", props: {ospNeedsPIC}),
+     (name: "Atari",
+      parDir: "..", dllFrmt: "$1.dll", altDirSep: "/", objExt: ".o",
+      newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: "", curDir: ".",
+      exeExt: ".tpp", extSep: ".", props: {ospNeedsPIC}),
+     (name: "Netware",
+      parDir: "..", dllFrmt: "$1.nlm", altDirSep: "/", objExt: "",
+      newLine: "\x0D\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh",
+      curDir: ".", exeExt: ".nlm", extSep: ".", props: {ospCaseInsensitive}),
+     (name: "MacOS", parDir: "::", dllFrmt: "$1Lib", altDirSep: ":",
+      objExt: ".o", newLine: "\x0D", pathSep: ",", dirSep: ":", scriptExt: "",
+      curDir: ":", exeExt: "", extSep: ".", props: {ospCaseInsensitive}),
+     (name: "MacOSX", parDir: "..", dllFrmt: "lib$1.dylib", altDirSep: ":",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}),
+     (name: "Haiku", parDir: "..", dllFrmt: "lib$1.so", altDirSep: ":",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}),
+     (name: "VxWorks", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A", pathSep: ";", dirSep: "\\",
+      scriptExt: ".sh", curDir: ".", exeExt: ".vxe", extSep: ".",
+      props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}),
+     (name: "JS", parDir: "..",
+      dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A",
+      pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".",
+      exeExt: "", extSep: ".", props: {}),
+     (name: "NimrodVM", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
       scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {}),
      (name: "Standalone", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
       objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
-      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", 
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
       props: {})]
 
-type 
-  TSystemCPU* = enum # Also add CPU for in initialization section and 
+type
+  TSystemCPU* = enum # Also add CPU for in initialization section and
                      # alias conditionals to condsyms (end of module).
     cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
-    cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuArm, 
+    cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuArm,
     cpuJS, cpuNimrodVM, cpuAVR
 
-type 
-  TEndian* = enum 
+type
+  TEndian* = enum
     littleEndian, bigEndian
-  TInfoCPU* = tuple[name: string, intSize: int, endian: TEndian, 
+  TInfoCPU* = tuple[name: string, intSize: int, endian: TEndian,
                     floatSize, bit: int]
 
 const
   EndianToStr*: array[TEndian, string] = ["littleEndian", "bigEndian"]
   CPU*: array[succ(low(TSystemCPU))..high(TSystemCPU), TInfoCPU] = [
-    (name: "i386", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32), 
-    (name: "m68k", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32), 
-    (name: "alpha", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64), 
+    (name: "i386", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
+    (name: "m68k", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
+    (name: "alpha", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
     (name: "powerpc", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
-    (name: "powerpc64", intSize: 64, endian: bigEndian, floatSize: 64,bit: 64), 
-    (name: "sparc", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32), 
-    (name: "vm", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32), 
-    (name: "ia64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64), 
-    (name: "amd64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64), 
-    (name: "mips", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32), 
-    (name: "arm", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32), 
-    (name: "js", intSize: 32, endian: bigEndian,floatSize: 64,bit: 32), 
+    (name: "powerpc64", intSize: 64, endian: bigEndian, floatSize: 64,bit: 64),
+    (name: "sparc", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
+    (name: "vm", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
+    (name: "ia64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
+    (name: "amd64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
+    (name: "mips", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
+    (name: "arm", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
+    (name: "js", intSize: 32, endian: bigEndian,floatSize: 64,bit: 32),
     (name: "nimrodvm", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
     (name: "avr", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16)]
 
-var 
+var
   targetCPU*, hostCPU*: TSystemCPU
   targetOS*, hostOS*: TSystemOS
 
 proc nameToOS*(name: string): TSystemOS
 proc nameToCPU*(name: string): TSystemCPU
 
-var 
+var
   intSize*: int
   floatSize*: int
   ptrSize*: int
   tnl*: string                # target newline
 
-proc setTarget*(o: TSystemOS, c: TSystemCPU) = 
+proc setTarget*(o: TSystemOS, c: TSystemCPU) =
   assert(c != cpuNone)
   assert(o != osNone)
   #echo "new Target: OS: ", o, " CPU: ", c
@@ -205,15 +209,15 @@ proc setTarget*(o: TSystemOS, c: TSystemCPU) =
   ptrSize = CPU[c].bit div 8
   tnl = OS[o].newLine
 
-proc nameToOS(name: string): TSystemOS = 
-  for i in countup(succ(osNone), high(TSystemOS)): 
-    if cmpIgnoreStyle(name, OS[i].name) == 0: 
+proc nameToOS(name: string): TSystemOS =
+  for i in countup(succ(osNone), high(TSystemOS)):
+    if cmpIgnoreStyle(name, OS[i].name) == 0:
       return i
   result = osNone
 
-proc nameToCPU(name: string): TSystemCPU = 
-  for i in countup(succ(cpuNone), high(TSystemCPU)): 
-    if cmpIgnoreStyle(name, CPU[i].name) == 0: 
+proc nameToCPU(name: string): TSystemCPU =
+  for i in countup(succ(cpuNone), high(TSystemCPU)):
+    if cmpIgnoreStyle(name, CPU[i].name) == 0:
       return i
   result = cpuNone
 
diff --git a/compiler/plugins.nim b/compiler/plugins.nim
new file mode 100644
index 000000000..1c9b7b77b
--- /dev/null
+++ b/compiler/plugins.nim
@@ -0,0 +1,43 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Plugin support for the Nim compiler. Right now there are no plugins and they
+## need to be build with the compiler, no DLL support.
+
+import ast, semdata, idents
+
+type
+  Transformation* = proc (c: PContext; n: PNode): PNode {.nimcall.}
+  Plugin = ref object
+    fn, module, package: PIdent
+    t: Transformation
+    next: Plugin
+
+proc pluginMatches(p: Plugin; s: PSym): bool =
+  if s.name.id != p.fn.id: return false
+  let module = s.owner
+  if module == nil or module.kind != skModule or
+      module.name.id != p.module.id: return false
+  let package = module.owner
+  if package == nil or package.kind != skPackage or
+      package.name.id != p.package.id: return false
+  return true
+
+var head: Plugin
+
+proc getPlugin*(fn: PSym): Transformation =
+  var it = head
+  while it != nil:
+    if pluginMatches(it, fn): return it.t
+    it = it.next
+
+proc registerPlugin*(package, module, fn: string; t: Transformation) =
+  let oldHead = head
+  head = Plugin(fn: getIdent(fn), module: getIdent(module),
+                 package: getIdent(package), t: t, next: oldHead)
diff --git a/compiler/plugins/active.nim b/compiler/plugins/active.nim
new file mode 100644
index 000000000..e9c11c2ea
--- /dev/null
+++ b/compiler/plugins/active.nim
@@ -0,0 +1,13 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Include file that imports all plugins that are active.
+
+import
+  locals.locals
diff --git a/compiler/plugins/locals/locals.nim b/compiler/plugins/locals/locals.nim
new file mode 100644
index 000000000..d89149f33
--- /dev/null
+++ b/compiler/plugins/locals/locals.nim
@@ -0,0 +1,42 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## The builtin 'system.locals' implemented as a plugin.
+
+import plugins, ast, astalgo, magicsys, lookups, semdata, lowerings
+
+proc semLocals(c: PContext, n: PNode): PNode =
+  var counter = 0
+  var tupleType = newTypeS(tyTuple, c)
+  result = newNodeIT(nkPar, n.info, tupleType)
+  tupleType.n = newNodeI(nkRecList, n.info)
+  # for now we skip openarrays ...
+  for scope in walkScopes(c.currentScope):
+    if scope == c.topLevelScope: break
+    for it in items(scope.symbols):
+      # XXX parameters' owners are wrong for generics; this caused some pain
+      # for closures too; we should finally fix it.
+      #if it.owner != c.p.owner: return result
+      if it.kind in skLocalVars and
+          it.typ.skipTypes({tyGenericInst, tyVar}).kind notin
+            {tyVarargs, tyOpenArray, tyTypeDesc, tyStatic, tyExpr, tyStmt, tyEmpty}:
+
+        var field = newSym(skField, it.name, getCurrOwner(), n.info)
+        field.typ = it.typ.skipTypes({tyGenericInst, tyVar})
+        field.position = counter
+        inc(counter)
+
+        addSon(tupleType.n, newSymNode(field))
+        addSonSkipIntLit(tupleType, field.typ)
+
+        var a = newSymNode(it, result.info)
+        if it.typ.skipTypes({tyGenericInst}).kind == tyVar: a = newDeref(a)
+        result.add(a)
+
+registerPlugin("stdlib", "system", "locals", semLocals)
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 879950e79..c048d78e9 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -9,23 +9,23 @@
 
 # This module implements semantic checking for pragmas
 
-import 
-  os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer, 
+import
+  os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer,
   wordrecg, ropes, options, strutils, lists, extccomp, math, magicsys, trees,
   rodread, types, lookups
 
-const 
+const
   FirstCallConv* = wNimcall
   LastCallConv* = wNoconv
 
 const
-  procPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, 
-    wMagic, wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader, 
-    wCompilerproc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge, 
+  procPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
+    wMagic, wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
+    wCompilerproc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
     wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
     wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
     wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe,
-    wOverride}
+    wOverride, wConstructor}
   converterPragmas* = procPragmas
   methodPragmas* = procPragmas
   templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty,
@@ -33,7 +33,7 @@ const
   macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
     wNodecl, wMagic, wNosideeffect, wCompilerproc, wDeprecated, wExtern,
     wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator}
-  iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect, 
+  iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect,
     wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
     wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
     wTags, wLocks, wGcSafe}
@@ -46,21 +46,21 @@ const
     wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
     wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
     wInjectStmt, wDeprecated, wExperimental}
-  lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, 
-    wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader, 
+  lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
+    wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
     wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
     wRaises, wLocks, wTags, wGcSafe}
-  typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl, 
+  typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
     wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
     wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
     wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
     wBorrow, wGcSafe}
-  fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern, 
+  fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
     wImportCpp, wImportObjC, wError, wGuard}
-  varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, 
+  varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
     wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
     wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
-    wGensym, wInject, wCodegenDecl, wGuard}
+    wGensym, wInject, wCodegenDecl, wGuard, wGoto}
   constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
     wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject}
   letPragmas* = varPragmas
@@ -74,27 +74,27 @@ proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
 proc invalidPragma(n: PNode) =
   localError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments}))
 
-proc pragmaAsm*(c: PContext, n: PNode): char = 
+proc pragmaAsm*(c: PContext, n: PNode): char =
   result = '\0'
-  if n != nil: 
-    for i in countup(0, sonsLen(n) - 1): 
+  if n != nil:
+    for i in countup(0, sonsLen(n) - 1):
       let it = n.sons[i]
       if it.kind == nkExprColonExpr and it.sons[0].kind == nkIdent:
         case whichKeyword(it.sons[0].ident)
-        of wSubsChar: 
+        of wSubsChar:
           if it.sons[1].kind == nkCharLit: result = chr(int(it.sons[1].intVal))
           else: invalidPragma(it)
         else: invalidPragma(it)
-      else: 
+      else:
         invalidPragma(it)
 
 proc setExternName(s: PSym, extname: string) =
-  s.loc.r = toRope(extname % s.name.s)
+  s.loc.r = rope(extname % s.name.s)
   if gCmd == cmdPretty and '$' notin extname:
     # note that '{.importc.}' is transformed into '{.importc: "$1".}'
     s.loc.flags.incl(lfFullExternalName)
 
-proc makeExternImport(s: PSym, extname: string) = 
+proc makeExternImport(s: PSym, extname: string) =
   setExternName(s, extname)
   incl(s.flags, sfImportc)
   excl(s.flags, sfForward)
@@ -105,7 +105,7 @@ proc validateExternCName(s: PSym, info: TLineInfo) =
   ## Valid identifiers are those alphanumeric including the underscore not
   ## starting with a number. If the check fails, a generic error will be
   ## displayed to the user.
-  let target = ropeToStr(s.loc.r)
+  let target = $s.loc.r
   if target.len < 1 or target[0] notin IdentStartChars or
       not target.allCharsInSet(IdentChars):
     localError(info, errGenerated, "invalid exported symbol")
@@ -145,7 +145,7 @@ proc newEmptyStrNode(n: PNode): PNode {.noinline.} =
   result.strVal = ""
 
 proc getStrLitNode(c: PContext, n: PNode): PNode =
-  if n.kind != nkExprColonExpr: 
+  if n.kind != nkExprColonExpr:
     localError(n.info, errStringLiteralExpected)
     # error correction:
     result = newEmptyStrNode(n)
@@ -153,62 +153,62 @@ proc getStrLitNode(c: PContext, n: PNode): PNode =
     n.sons[1] = c.semConstExpr(c, n.sons[1])
     case n.sons[1].kind
     of nkStrLit, nkRStrLit, nkTripleStrLit: result = n.sons[1]
-    else: 
+    else:
       localError(n.info, errStringLiteralExpected)
       # error correction:
       result = newEmptyStrNode(n)
 
-proc expectStrLit(c: PContext, n: PNode): string = 
+proc expectStrLit(c: PContext, n: PNode): string =
   result = getStrLitNode(c, n).strVal
 
-proc expectIntLit(c: PContext, n: PNode): int = 
-  if n.kind != nkExprColonExpr: 
+proc expectIntLit(c: PContext, n: PNode): int =
+  if n.kind != nkExprColonExpr:
     localError(n.info, errIntLiteralExpected)
-  else: 
+  else:
     n.sons[1] = c.semConstExpr(c, n.sons[1])
     case n.sons[1].kind
     of nkIntLit..nkInt64Lit: result = int(n.sons[1].intVal)
     else: localError(n.info, errIntLiteralExpected)
 
-proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string = 
+proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string =
   if n.kind == nkExprColonExpr: result = expectStrLit(c, n)
   else: result = defaultStr
 
 proc processCodegenDecl(c: PContext, n: PNode, sym: PSym) =
   sym.constraint = getStrLitNode(c, n)
 
-proc processMagic(c: PContext, n: PNode, s: PSym) = 
+proc processMagic(c: PContext, n: PNode, s: PSym) =
   #if sfSystemModule notin c.module.flags:
   #  liMessage(n.info, errMagicOnlyInSystem)
-  if n.kind != nkExprColonExpr: 
+  if n.kind != nkExprColonExpr:
     localError(n.info, errStringLiteralExpected)
     return
   var v: string
   if n.sons[1].kind == nkIdent: v = n.sons[1].ident.s
   else: v = expectStrLit(c, n)
-  for m in countup(low(TMagic), high(TMagic)): 
-    if substr($m, 1) == v: 
+  for m in countup(low(TMagic), high(TMagic)):
+    if substr($m, 1) == v:
       s.magic = m
       break
   if s.magic == mNone: message(n.info, warnUnknownMagic, v)
 
-proc wordToCallConv(sw: TSpecialWord): TCallingConvention = 
+proc wordToCallConv(sw: TSpecialWord): TCallingConvention =
   # this assumes that the order of special words and calling conventions is
   # the same
   result = TCallingConvention(ord(ccDefault) + ord(sw) - ord(wNimcall))
 
-proc isTurnedOn(c: PContext, n: PNode): bool = 
+proc isTurnedOn(c: PContext, n: PNode): bool =
   if n.kind == nkExprColonExpr:
     let x = c.semConstBoolExpr(c, n.sons[1])
     n.sons[1] = x
     if x.kind == nkIntLit: return x.intVal != 0
   localError(n.info, errOnOrOffExpected)
 
-proc onOff(c: PContext, n: PNode, op: TOptions) = 
+proc onOff(c: PContext, n: PNode, op: TOptions) =
   if isTurnedOn(c, n): gOptions = gOptions + op
   else: gOptions = gOptions - op
-  
-proc pragmaDeadCodeElim(c: PContext, n: PNode) = 
+
+proc pragmaDeadCodeElim(c: PContext, n: PNode) =
   if isTurnedOn(c, n): incl(c.module.flags, sfDeadCodeElim)
   else: excl(c.module.flags, sfDeadCodeElim)
 
@@ -216,20 +216,20 @@ proc pragmaNoForward(c: PContext, n: PNode) =
   if isTurnedOn(c, n): incl(c.module.flags, sfNoForward)
   else: excl(c.module.flags, sfNoForward)
 
-proc processCallConv(c: PContext, n: PNode) = 
-  if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent): 
+proc processCallConv(c: PContext, n: PNode) =
+  if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
     var sw = whichKeyword(n.sons[1].ident)
     case sw
-    of FirstCallConv..LastCallConv: 
+    of FirstCallConv..LastCallConv:
       POptionEntry(c.optionStack.tail).defaultCC = wordToCallConv(sw)
     else: localError(n.info, errCallConvExpected)
-  else: 
+  else:
     localError(n.info, errCallConvExpected)
-  
-proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib = 
+
+proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib =
   var it = PLib(c.libs.head)
-  while it != nil: 
-    if it.kind == kind: 
+  while it != nil:
+    if it.kind == kind:
       if trees.exprStructuralEquivalent(it.path, path): return it
     it = PLib(it.next)
   result = newLib(kind)
@@ -252,10 +252,10 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode =
     if result.typ == nil or result.typ.kind notin {tyPointer, tyString, tyProc}:
       localError(n.info, errStringLiteralExpected)
       result = newEmptyStrNode(n)
-    
-proc processDynLib(c: PContext, n: PNode, sym: PSym) = 
+
+proc processDynLib(c: PContext, n: PNode, sym: PSym) =
   if (sym == nil) or (sym.kind == skModule):
-    POptionEntry(c.optionStack.tail).dynlib = getLib(c, libDynamic, 
+    POptionEntry(c.optionStack.tail).dynlib = getLib(c, libDynamic,
         expectDynlibNode(c, n))
   else:
     if n.kind == nkExprColonExpr:
@@ -268,7 +268,7 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) =
     # since we'll be loading the dynlib symbols dynamically, we must use
     # a calling convention that doesn't introduce custom name mangling
     # cdecl is the default - the user can override this explicitly
-    if sym.kind in routineKinds and sym.typ != nil and 
+    if sym.kind in routineKinds and sym.typ != nil and
         sym.typ.callConv == ccDefault:
       sym.typ.callConv = ccCDecl
 
@@ -295,10 +295,10 @@ proc processNote(c: PContext, n: PNode) =
     n.sons[1] = x
     if x.kind == nkIntLit and x.intVal != 0: incl(gNotes, nk)
     else: excl(gNotes, nk)
-  else: 
+  else:
     invalidPragma(n)
-  
-proc processOption(c: PContext, n: PNode): bool = 
+
+proc processOption(c: PContext, n: PNode): bool =
   if n.kind != nkExprColonExpr: result = true
   elif n.sons[0].kind == nkBracketExpr: processNote(c, n)
   elif n.sons[0].kind != nkIdent: result = true
@@ -318,34 +318,34 @@ proc processOption(c: PContext, n: PNode): bool =
     of wAssertions: onOff(c, n, {optAssert})
     of wWarnings: onOff(c, n, {optWarns})
     of wHints: onOff(c, n, {optHints})
-    of wCallconv: processCallConv(c, n)   
+    of wCallconv: processCallConv(c, n)
     of wLinedir: onOff(c, n, {optLineDir})
     of wStacktrace: onOff(c, n, {optStackTrace})
     of wLinetrace: onOff(c, n, {optLineTrace})
     of wDebugger: onOff(c, n, {optEndb})
     of wProfiler: onOff(c, n, {optProfiler})
     of wByRef: onOff(c, n, {optByRef})
-    of wDynlib: processDynLib(c, n, nil) 
-    of wOptimization: 
-      if n.sons[1].kind != nkIdent: 
+    of wDynlib: processDynLib(c, n, nil)
+    of wOptimization:
+      if n.sons[1].kind != nkIdent:
         invalidPragma(n)
-      else: 
+      else:
         case n.sons[1].ident.s.normalize
-        of "speed": 
+        of "speed":
           incl(gOptions, optOptimizeSpeed)
           excl(gOptions, optOptimizeSize)
         of "size":
           excl(gOptions, optOptimizeSpeed)
           incl(gOptions, optOptimizeSize)
-        of "none": 
+        of "none":
           excl(gOptions, optOptimizeSpeed)
           excl(gOptions, optOptimizeSize)
         else: localError(n.info, errNoneSpeedOrSizeExpected)
     of wImplicitStatic: onOff(c, n, {optImplicitStatic})
     of wPatterns: onOff(c, n, {optPatterns})
     else: result = true
-  
-proc processPush(c: PContext, n: PNode, start: int) = 
+
+proc processPush(c: PContext, n: PNode, start: int) =
   if n.sons[start-1].kind == nkExprColonExpr:
     localError(n.info, errGenerated, "':' after 'push' not supported")
   var x = newOptionEntry()
@@ -355,41 +355,41 @@ proc processPush(c: PContext, n: PNode, start: int) =
   x.dynlib = y.dynlib
   x.notes = gNotes
   append(c.optionStack, x)
-  for i in countup(start, sonsLen(n) - 1): 
+  for i in countup(start, sonsLen(n) - 1):
     if processOption(c, n.sons[i]):
-      # simply store it somehwere:
+      # simply store it somewhere:
       if x.otherPragmas.isNil:
         x.otherPragmas = newNodeI(nkPragma, n.info)
       x.otherPragmas.add n.sons[i]
-    #LocalError(n.info, errOptionExpected)
-  
-proc processPop(c: PContext, n: PNode) = 
-  if c.optionStack.counter <= 1: 
+    #localError(n.info, errOptionExpected)
+
+proc processPop(c: PContext, n: PNode) =
+  if c.optionStack.counter <= 1:
     localError(n.info, errAtPopWithoutPush)
-  else: 
-    gOptions = POptionEntry(c.optionStack.tail).options 
+  else:
+    gOptions = POptionEntry(c.optionStack.tail).options
     gNotes = POptionEntry(c.optionStack.tail).notes
     remove(c.optionStack, c.optionStack.tail)
 
-proc processDefine(c: PContext, n: PNode) = 
-  if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent): 
+proc processDefine(c: PContext, n: PNode) =
+  if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
     defineSymbol(n.sons[1].ident.s)
     message(n.info, warnDeprecated, "define")
-  else: 
+  else:
     invalidPragma(n)
-  
-proc processUndef(c: PContext, n: PNode) = 
-  if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent): 
+
+proc processUndef(c: PContext, n: PNode) =
+  if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
     undefSymbol(n.sons[1].ident.s)
     message(n.info, warnDeprecated, "undef")
-  else: 
+  else:
     invalidPragma(n)
-  
-type 
-  TLinkFeature = enum 
+
+type
+  TLinkFeature = enum
     linkNormal, linkSys
 
-proc processCompile(c: PContext, n: PNode) = 
+proc processCompile(c: PContext, n: PNode) =
   var s = expectStrLit(c, n)
   var found = findFile(s)
   if found == "": found = s
@@ -397,7 +397,7 @@ proc processCompile(c: PContext, n: PNode) =
   extccomp.addExternalFileToCompile(found)
   extccomp.addFileToLink(completeCFilePath(trunc, false))
 
-proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) = 
+proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
   var f = expectStrLit(c, n)
   if splitFile(f).ext == "": f = addFileExt(f, CC[cCompiler].objExt)
   var found = findFile(f)
@@ -407,15 +407,9 @@ proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
   of linkSys:
     extccomp.addFileToLink(libpath / completeCFilePath(found, false))
   else: internalError(n.info, "processCommonLink")
-  
-proc pragmaBreakpoint(c: PContext, n: PNode) = 
-  discard getOptionalStr(c, n, "")
 
-proc pragmaCheckpoint(c: PContext, n: PNode) = 
-  # checkpoints can be used to debug the compiler; they are not documented
-  var info = n.info
-  inc(info.line)              # next line is affected!
-  msgs.addCheckpoint(info)
+proc pragmaBreakpoint(c: PContext, n: PNode) =
+  discard getOptionalStr(c, n, "")
 
 proc pragmaWatchpoint(c: PContext, n: PNode) =
   if n.kind == nkExprColonExpr:
@@ -433,57 +427,59 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
       return
     # now parse the string literal and substitute symbols:
     var a = 0
-    while true: 
+    while true:
       var b = strutils.find(str, marker, a)
       var sub = if b < 0: substr(str, a) else: substr(str, a, b - 1)
       if sub != "": addSon(result, newStrNode(nkStrLit, sub))
-      if b < 0: break 
+      if b < 0: break
       var c = strutils.find(str, marker, b + 1)
       if c < 0: sub = substr(str, b + 1)
       else: sub = substr(str, b + 1, c - 1)
-      if sub != "": 
+      if sub != "":
         var e = searchInScopes(con, getIdent(sub))
-        if e != nil: 
+        if e != nil:
           if e.kind == skStub: loadStub(e)
           addSon(result, newSymNode(e))
-        else: 
+        else:
           addSon(result, newStrNode(nkStrLit, sub))
       else:
         # an empty '``' produces a single '`'
         addSon(result, newStrNode(nkStrLit, $marker))
-      if c < 0: break 
+      if c < 0: break
       a = c + 1
-  else: illFormedAst(n)
-  
-proc pragmaEmit(c: PContext, n: PNode) = 
+  else:
+    illFormedAstLocal(n)
+    result = newNode(nkAsmStmt, n.info)
+
+proc pragmaEmit(c: PContext, n: PNode) =
   discard getStrLitNode(c, n)
   n.sons[1] = semAsmOrEmit(c, n, '`')
 
-proc noVal(n: PNode) = 
+proc noVal(n: PNode) =
   if n.kind == nkExprColonExpr: invalidPragma(n)
 
-proc pragmaUnroll(c: PContext, n: PNode) = 
-  if c.p.nestedLoopCounter <= 0: 
+proc pragmaUnroll(c: PContext, n: PNode) =
+  if c.p.nestedLoopCounter <= 0:
     invalidPragma(n)
   elif n.kind == nkExprColonExpr:
     var unrollFactor = expectIntLit(c, n)
-    if unrollFactor <% 32: 
+    if unrollFactor <% 32:
       n.sons[1] = newIntNode(nkIntLit, unrollFactor)
-    else: 
+    else:
       invalidPragma(n)
 
 proc pragmaLine(c: PContext, n: PNode) =
   if n.kind == nkExprColonExpr:
     n.sons[1] = c.semConstExpr(c, n.sons[1])
     let a = n.sons[1]
-    if a.kind == nkPar: 
+    if a.kind == nkPar:
       var x = a.sons[0]
       var y = a.sons[1]
       if x.kind == nkExprColonExpr: x = x.sons[1]
       if y.kind == nkExprColonExpr: y = y.sons[1]
-      if x.kind != nkStrLit: 
+      if x.kind != nkStrLit:
         localError(n.info, errStringLiteralExpected)
-      elif y.kind != nkIntLit: 
+      elif y.kind != nkIntLit:
         localError(n.info, errIntLiteralExpected)
       else:
         n.info.fileIndex = msgs.fileInfoIdx(x.strVal)
@@ -494,12 +490,12 @@ proc pragmaLine(c: PContext, n: PNode) =
     # sensible default:
     n.info = getInfoContext(-1)
 
-proc processPragma(c: PContext, n: PNode, i: int) = 
+proc processPragma(c: PContext, n: PNode, i: int) =
   var it = n.sons[i]
   if it.kind != nkExprColonExpr: invalidPragma(n)
   elif it.sons[0].kind != nkIdent: invalidPragma(n)
   elif it.sons[1].kind != nkIdent: invalidPragma(n)
-  
+
   var userPragma = newSym(skTemplate, it.sons[1].ident, nil, it.info)
   var body = newNodeI(nkPragma, n.info)
   for j in i+1 .. sonsLen(n)-1: addSon(body, n.sons[j])
@@ -512,7 +508,7 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) =
     if t.kind != tyObject:
       localError(x.info, errGenerated, "invalid type for raises/tags list")
     x.typ = t
-    
+
   if n.kind == nkExprColonExpr:
     let it = n.sons[1]
     if it.kind notin {nkCurly, nkBracket}:
@@ -573,7 +569,7 @@ proc deprecatedStmt(c: PContext; pragma: PNode) =
       localError(n.info, "key:value pair expected")
 
 proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
-  if it.kind != nkExprColonExpr: 
+  if it.kind != nkExprColonExpr:
     invalidPragma(it); return
   let n = it[1]
   if n.kind == nkSym:
@@ -596,9 +592,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
   var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
   if key.kind == nkIdent:
     var userPragma = strTableGet(c.userPragmas, key.ident)
-    if userPragma != nil: 
+    if userPragma != nil:
       inc c.instCounter
-      if c.instCounter > 100: 
+      if c.instCounter > 100:
         globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
       pragma(c, sym, userPragma.ast, validPragmas)
       # ensure the pragma is also remember for generic instantiations in other
@@ -607,9 +603,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
       dec c.instCounter
     else:
       var k = whichKeyword(key.ident)
-      if k in validPragmas: 
+      if k in validPragmas:
         case k
-        of wExportc: 
+        of wExportc:
           makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
           incl(sym.flags, sfUsed) # avoid wrong hints
         of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"))
@@ -631,16 +627,16 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
           var align = expectIntLit(c, it)
           if (not isPowerOfTwo(align) and align != 0) or align >% high(int16):
             localError(it.info, errPowerOfTwoExpected)
-          else: 
+          else:
             sym.typ.align = align.int16
         of wSize:
           if sym.typ == nil: invalidPragma(it)
           var size = expectIntLit(c, it)
-          if not isPowerOfTwo(size) or size <= 0 or size > 8: 
+          if not isPowerOfTwo(size) or size <= 0 or size > 8:
             localError(it.info, errPowerOfTwoExpected)
           else:
             sym.typ.size = size
-        of wNodecl: 
+        of wNodecl:
           noVal(it)
           incl(sym.loc.flags, lfNoDecl)
         of wPure, wAsmNoStackFrame:
@@ -648,19 +644,19 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
           if sym != nil:
             if k == wPure and sym.kind in routineKinds: invalidPragma(it)
             else: incl(sym.flags, sfPure)
-        of wVolatile: 
+        of wVolatile:
           noVal(it)
           incl(sym.flags, sfVolatile)
-        of wRegister: 
+        of wRegister:
           noVal(it)
           incl(sym.flags, sfRegister)
-        of wThreadVar: 
+        of wThreadVar:
           noVal(it)
           incl(sym.flags, sfThread)
         of wDeadCodeElim: pragmaDeadCodeElim(c, it)
         of wNoForward: pragmaNoForward(c, it)
         of wMagic: processMagic(c, it, sym)
-        of wCompileTime: 
+        of wCompileTime:
           noVal(it)
           incl(sym.flags, sfCompileTime)
           incl(sym.loc.flags, lfNoDecl)
@@ -668,17 +664,20 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
           noVal(it)
           incl(sym.flags, sfGlobal)
           incl(sym.flags, sfPure)
-        of wMerge: 
+        of wMerge:
+          # only supported for backwards compat, doesn't do anything anymore
           noVal(it)
-          incl(sym.flags, sfMerge)
-        of wHeader: 
+        of wConstructor:
+          noVal(it)
+          incl(sym.flags, sfConstructor)
+        of wHeader:
           var lib = getLib(c, libHeader, getStrLitNode(c, it))
           addToLib(lib, sym)
           incl(sym.flags, sfImportc)
           incl(sym.loc.flags, lfHeader)
-          incl(sym.loc.flags, lfNoDecl) 
+          incl(sym.loc.flags, lfNoDecl)
           # implies nodecl, because otherwise header would not make sense
-          if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
+          if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
         of wDestructor:
           sym.flags.incl sfOverriden
           if sym.name.s.normalize != "destroy":
@@ -689,13 +688,13 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
           noVal(it)
           incl(sym.flags, sfNoSideEffect)
           if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
-        of wSideeffect: 
+        of wSideeffect:
           noVal(it)
           incl(sym.flags, sfSideEffect)
-        of wNoreturn: 
+        of wNoreturn:
           noVal(it)
           incl(sym.flags, sfNoReturn)
-        of wDynlib: 
+        of wDynlib:
           processDynLib(c, it, sym)
         of wCompilerproc:
           noVal(it)           # compilerproc may not get a string!
@@ -707,7 +706,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
           if it.kind == nkExprColonExpr: deprecatedStmt(c, it)
           elif sym != nil: incl(sym.flags, sfDeprecated)
           else: incl(c.module.flags, sfDeprecated)
-        of wVarargs: 
+        of wVarargs:
           noVal(it)
           if sym.typ == nil: invalidPragma(it)
           else: incl(sym.typ.flags, tfVarargs)
@@ -717,7 +716,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
           else:
             noVal(it)
             incl(sym.flags, sfBorrow)
-        of wFinal: 
+        of wFinal:
           noVal(it)
           if sym.typ == nil: invalidPragma(it)
           else: incl(sym.typ.flags, tfFinal)
@@ -739,21 +738,20 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
           incl(sym.flags, sfProcvar)
           if sym.typ != nil: incl(sym.typ.flags, tfThread)
         of wGcSafe:
-          if optThreadAnalysis in gGlobalOptions:
-            noVal(it)
-            if sym.kind != skType: incl(sym.flags, sfThread)
-            if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
-            else: invalidPragma(it)
+          noVal(it)
+          if sym.kind != skType: incl(sym.flags, sfThread)
+          if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
+          else: invalidPragma(it)
         of wPacked:
           noVal(it)
           if sym.typ == nil: invalidPragma(it)
           else: incl(sym.typ.flags, tfPacked)
         of wHint: message(it.info, hintUser, expectStrLit(c, it))
         of wWarning: message(it.info, warnUser, expectStrLit(c, it))
-        of wError: 
+        of wError:
           if sym != nil and sym.isRoutine:
             # This is subtle but correct: the error *statement* is only
-            # allowed for top level statements. Seems to be easier than 
+            # allowed for top level statements. Seems to be easier than
             # distinguishing properly between
             # ``proc p() {.error}`` and ``proc p() = {.error: "msg".}``
             noVal(it)
@@ -770,11 +768,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
         of wPassc: extccomp.addCompileOption(expectStrLit(c, it))
         of wBreakpoint: pragmaBreakpoint(c, it)
         of wWatchPoint: pragmaWatchpoint(c, it)
-        of wPush: 
+        of wPush:
           processPush(c, n, i + 1)
-          result = true 
+          result = true
         of wPop: processPop(c, it)
-        of wPragma: 
+        of wPragma:
           processPragma(c, n, i)
           result = true
         of wDiscardable:
@@ -784,16 +782,16 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
           noVal(it)
           if sym != nil: incl(sym.flags, sfNoInit)
         of wCodegenDecl: processCodegenDecl(c, it, sym)
-        of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, 
-           wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, 
+        of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
+           wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
            wLinedir, wStacktrace, wLinetrace, wOptimization,
-           wCallconv, 
+           wCallconv,
            wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks,
            wPatterns:
           if processOption(c, it):
             # calling conventions (boring...):
             localError(it.info, errOptionExpected)
-        of FirstCallConv..LastCallConv: 
+        of FirstCallConv..LastCallConv:
           assert(sym != nil)
           if sym.typ == nil: invalidPragma(it)
           else: sym.typ.callConv = wordToCallConv(k)
@@ -845,17 +843,22 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
             invalidPragma(it)
           else:
             sym.guard = pragmaGuard(c, it, sym.kind)
+        of wGoto:
+          if sym == nil or sym.kind notin {skVar, skLet}:
+            invalidPragma(it)
+          else:
+            sym.flags.incl sfGoto
         of wInjectStmt:
           if it.kind != nkExprColonExpr:
             localError(it.info, errExprExpected)
-          else: 
+          else:
             it.sons[1] = c.semExpr(c, it.sons[1])
         of wExperimental:
           noVal(it)
           if isTopLevel(c):
             c.module.flags.incl sfExperimental
           else:
-            localError(it.info, "'experimental' pragma only valid as toplevel statement") 
+            localError(it.info, "'experimental' pragma only valid as toplevel statement")
         else: invalidPragma(it)
       else: invalidPragma(it)
   else: processNote(c, it)
@@ -867,9 +870,11 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
     while it != nil:
       let o = it.otherPragmas
       if not o.isNil:
+        pushInfoContext(n.info)
         for i in countup(0, sonsLen(o) - 1):
           if singlePragma(c, sym, o, i, validPragmas):
             internalError(n.info, "implicitPragmas")
+        popInfoContext()
       it = it.next.POptionEntry
 
     if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
@@ -879,7 +884,7 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
         sfImportc in sym.flags and lib != nil:
       incl(sym.loc.flags, lfDynamicLib)
       addToLib(lib, sym)
-      if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
+      if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
 
 proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
   if n == nil or n.sons == nil:
@@ -889,7 +894,7 @@ proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
     var key = if p.kind == nkExprColonExpr: p[0] else: p
     if key.kind == nkIdent and whichKeyword(key.ident) == pragma:
       return true
-  
+
   return false
 
 proc pragmaRec(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index b0d328f9e..ffdb60696 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -9,20 +9,20 @@
 
 # This module implements the renderer of the standard Nim representation.
 
-import 
+import
   lexer, options, idents, strutils, ast, msgs, lists
 
-type 
-  TRenderFlag* = enum 
-    renderNone, renderNoBody, renderNoComments, renderDocComments, 
+type
+  TRenderFlag* = enum
+    renderNone, renderNoBody, renderNoComments, renderDocComments,
     renderNoPragmas, renderIds, renderNoProcDefs
   TRenderFlags* = set[TRenderFlag]
-  TRenderTok*{.final.} = object 
+  TRenderTok*{.final.} = object
     kind*: TTokType
     length*: int16
 
   TRenderTokSeq* = seq[TRenderTok]
-  TSrcGen*{.final.} = object 
+  TSrcGen*{.final.} = object
     indent*: int
     lineLen*: int
     pos*: int              # current position for iteration over the buffer
@@ -34,23 +34,27 @@ type
     comStack*: seq[PNode]  # comment stack
     flags*: TRenderFlags
     checkAnon: bool        # we're in a context that can contain sfAnon
+    inPragma: int
 
 
 proc renderModule*(n: PNode, filename: string, renderFlags: TRenderFlags = {})
 proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string
 proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {})
 proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string)
+
+proc `$`*(n: PNode): string = n.renderTree
 # implementation
 # We render the source code in a two phases: The first
 # determines how long the subtree will likely be, the second
 # phase appends to a buffer that will be the output.
 
-proc isKeyword*(s: string): bool =
-  var i = getIdent(s)
+proc isKeyword*(i: PIdent): bool =
   if (i.id >= ord(tokKeywordLow) - ord(tkSymbol)) and
-      (i.id <= ord(tokKeywordHigh) - ord(tkSymbol)): 
+      (i.id <= ord(tokKeywordHigh) - ord(tkSymbol)):
     result = true
 
+proc isKeyword*(s: string): bool = isKeyword(getIdent(s))
+
 proc renderDefinitionName*(s: PSym, noQuotes = false): string =
   ## Returns the definition name of the symbol.
   ##
@@ -58,18 +62,18 @@ proc renderDefinitionName*(s: PSym, noQuotes = false): string =
   ## happen if the name happens to be a keyword or the first character is not
   ## part of the SymStartChars set.
   let x = s.name.s
-  if noQuotes or (x[0] in SymStartChars and not renderer.isKeyword(x)):
+  if noQuotes or (x[0] in SymStartChars and not renderer.isKeyword(s.name)):
     result = x
   else:
     result = '`' & x & '`'
 
-const 
+const
   IndentWidth = 2
   longIndentWid = 4
   MaxLineLen = 80
   LineCommentColumn = 30
 
-proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) = 
+proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
   g.comStack = @[]
   g.tokens = @[]
   g.indent = 0
@@ -81,67 +85,67 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
   g.pendingNL = -1
   g.checkAnon = false
 
-proc addTok(g: var TSrcGen, kind: TTokType, s: string) = 
+proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
   var length = len(g.tokens)
   setLen(g.tokens, length + 1)
   g.tokens[length].kind = kind
   g.tokens[length].length = int16(len(s))
   add(g.buf, s)
 
-proc addPendingNL(g: var TSrcGen) = 
-  if g.pendingNL >= 0: 
-    addTok(g, tkSpaces, "\n" & repeatChar(g.pendingNL))
+proc addPendingNL(g: var TSrcGen) =
+  if g.pendingNL >= 0:
+    addTok(g, tkSpaces, "\n" & spaces(g.pendingNL))
     g.lineLen = g.pendingNL
     g.pendingNL = - 1
 
-proc putNL(g: var TSrcGen, indent: int) = 
+proc putNL(g: var TSrcGen, indent: int) =
   if g.pendingNL >= 0: addPendingNL(g)
   else: addTok(g, tkSpaces, "\n")
   g.pendingNL = indent
   g.lineLen = indent
 
-proc putNL(g: var TSrcGen) = 
+proc putNL(g: var TSrcGen) =
   putNL(g, g.indent)
 
-proc optNL(g: var TSrcGen, indent: int) = 
+proc optNL(g: var TSrcGen, indent: int) =
   g.pendingNL = indent
   g.lineLen = indent          # BUGFIX
-  
-proc optNL(g: var TSrcGen) = 
+
+proc optNL(g: var TSrcGen) =
   optNL(g, g.indent)
 
-proc indentNL(g: var TSrcGen) = 
+proc indentNL(g: var TSrcGen) =
   inc(g.indent, IndentWidth)
   g.pendingNL = g.indent
   g.lineLen = g.indent
 
-proc dedent(g: var TSrcGen) = 
+proc dedent(g: var TSrcGen) =
   dec(g.indent, IndentWidth)
   assert(g.indent >= 0)
-  if g.pendingNL > IndentWidth: 
+  if g.pendingNL > IndentWidth:
     dec(g.pendingNL, IndentWidth)
     dec(g.lineLen, IndentWidth)
 
-proc put(g: var TSrcGen, kind: TTokType, s: string) = 
+proc put(g: var TSrcGen, kind: TTokType, s: string) =
   addPendingNL(g)
-  if len(s) > 0: 
+  if len(s) > 0:
     addTok(g, kind, s)
     inc(g.lineLen, len(s))
 
-proc putLong(g: var TSrcGen, kind: TTokType, s: string, lineLen: int) = 
+proc putLong(g: var TSrcGen, kind: TTokType, s: string, lineLen: int) =
   # use this for tokens over multiple lines.
   addPendingNL(g)
   addTok(g, kind, s)
   g.lineLen = lineLen
 
-proc toNimChar(c: char): string = 
+proc toNimChar(c: char): string =
   case c
   of '\0': result = "\\0"
   of '\x01'..'\x1F', '\x80'..'\xFF': result = "\\x" & strutils.toHex(ord(c), 2)
   of '\'', '\"', '\\': result = '\\' & c
   else: result = c & ""
-  
-proc makeNimString(s: string): string = 
+
+proc makeNimString(s: string): string =
   result = "\""
   for i in countup(0, len(s)-1): add(result, toNimChar(s[i]))
   add(result, '\"')
@@ -172,7 +176,7 @@ proc putComment(g: var TSrcGen, s: string) =
       add(com, s[i])
       inc(i)
       comIndent = 0
-      while s[i] == ' ': 
+      while s[i] == ' ':
         add(com, s[i])
         inc(i)
         inc(comIndent)
@@ -185,109 +189,109 @@ proc putComment(g: var TSrcGen, s: string) =
       # compute length of the following word:
       var j = i
       while s[j] > ' ': inc(j)
-      if not isCode and (g.lineLen + (j - i) > MaxLineLen): 
+      if not isCode and (g.lineLen + (j - i) > MaxLineLen):
         put(g, tkComment, com)
         optNL(g, ind)
-        com = '#' & repeatChar(comIndent)
-      while s[i] > ' ': 
+        com = '#' & spaces(comIndent)
+      while s[i] > ' ':
         add(com, s[i])
         inc(i)
   put(g, tkComment, com)
   optNL(g)
 
-proc maxLineLength(s: string): int = 
+proc maxLineLength(s: string): int =
   if s.isNil: return 0
   var i = 0
   var lineLen = 0
   while true:
     case s[i]
-    of '\0': 
-      break 
-    of '\x0D': 
+    of '\0':
+      break
+    of '\x0D':
       inc(i)
       if s[i] == '\x0A': inc(i)
       result = max(result, lineLen)
       lineLen = 0
-    of '\x0A': 
+    of '\x0A':
       inc(i)
       result = max(result, lineLen)
       lineLen = 0
-    else: 
+    else:
       inc(lineLen)
       inc(i)
 
-proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) = 
+proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) =
   var i = 0
   var hi = len(s) - 1
   var str = ""
-  while i <= hi: 
+  while i <= hi:
     case s[i]
-    of '\x0D': 
+    of '\x0D':
       put(g, kind, str)
       str = ""
       inc(i)
       if (i <= hi) and (s[i] == '\x0A'): inc(i)
       optNL(g, 0)
-    of '\x0A': 
+    of '\x0A':
       put(g, kind, str)
       str = ""
       inc(i)
       optNL(g, 0)
-    else: 
+    else:
       add(str, s[i])
       inc(i)
   put(g, kind, str)
 
-proc containsNL(s: string): bool = 
-  for i in countup(0, len(s) - 1): 
+proc containsNL(s: string): bool =
+  for i in countup(0, len(s) - 1):
     case s[i]
-    of '\x0D', '\x0A': 
+    of '\x0D', '\x0A':
       return true
-    else: 
+    else:
       discard
   result = false
 
-proc pushCom(g: var TSrcGen, n: PNode) = 
+proc pushCom(g: var TSrcGen, n: PNode) =
   var length = len(g.comStack)
   setLen(g.comStack, length + 1)
   g.comStack[length] = n
 
-proc popAllComs(g: var TSrcGen) = 
+proc popAllComs(g: var TSrcGen) =
   setLen(g.comStack, 0)
 
-proc popCom(g: var TSrcGen) = 
+proc popCom(g: var TSrcGen) =
   setLen(g.comStack, len(g.comStack) - 1)
 
-const 
+const
   Space = " "
 
-proc shouldRenderComment(g: var TSrcGen, n: PNode): bool = 
+proc shouldRenderComment(g: var TSrcGen, n: PNode): bool =
   result = false
-  if n.comment != nil: 
+  if n.comment != nil:
     result = (renderNoComments notin g.flags) or
         (renderDocComments in g.flags) and startsWith(n.comment, "##")
-  
-proc gcom(g: var TSrcGen, n: PNode) = 
+
+proc gcom(g: var TSrcGen, n: PNode) =
   assert(n != nil)
-  if shouldRenderComment(g, n): 
+  if shouldRenderComment(g, n):
     if (g.pendingNL < 0) and (len(g.buf) > 0) and (g.buf[len(g.buf)-1] != ' '):
-      put(g, tkSpaces, Space) 
+      put(g, tkSpaces, Space)
       # Before long comments we cannot make sure that a newline is generated,
       # because this might be wrong. But it is no problem in practice.
     if (g.pendingNL < 0) and (len(g.buf) > 0) and
-        (g.lineLen < LineCommentColumn): 
+        (g.lineLen < LineCommentColumn):
       var ml = maxLineLength(n.comment)
-      if ml + LineCommentColumn <= MaxLineLen: 
-        put(g, tkSpaces, repeatChar(LineCommentColumn - g.lineLen))
+      if ml + LineCommentColumn <= MaxLineLen:
+        put(g, tkSpaces, spaces(LineCommentColumn - g.lineLen))
     putComment(g, n.comment)  #assert(g.comStack[high(g.comStack)] = n);
-  
-proc gcoms(g: var TSrcGen) = 
+
+proc gcoms(g: var TSrcGen) =
   for i in countup(0, high(g.comStack)): gcom(g, g.comStack[i])
   popAllComs(g)
 
 proc lsub(n: PNode): int
 proc litAux(n: PNode, x: BiggestInt, size: int): string =
-  proc skip(t: PType): PType = 
+  proc skip(t: PType): PType =
     result = t
     while result.kind in {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
                           tyConst, tyMutable}:
@@ -297,20 +301,20 @@ proc litAux(n: PNode, x: BiggestInt, size: int): string =
     # we need a slow linear search because of enums with holes:
     for e in items(enumfields):
       if e.sym.position == x: return e.sym.name.s
-    
+
   if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
   elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3)
   elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
   else: result = $x
 
-proc ulitAux(n: PNode, x: BiggestInt, size: int): string = 
+proc ulitAux(n: PNode, x: BiggestInt, size: int): string =
   if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
   elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3)
   elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
   else: result = $x
   # XXX proper unsigned output!
-  
-proc atom(n: PNode): string = 
+
+proc atom(n: PNode): string =
   var f: float32
   case n.kind
   of nkEmpty: result = ""
@@ -333,55 +337,55 @@ proc atom(n: PNode): string =
   of nkFloatLit:
     if n.flags * {nfBase2, nfBase8, nfBase16} == {}: result = $(n.floatVal)
     else: result = litAux(n, (cast[PInt64](addr(n.floatVal)))[] , 8)
-  of nkFloat32Lit: 
-    if n.flags * {nfBase2, nfBase8, nfBase16} == {}: 
+  of nkFloat32Lit:
+    if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
       result = $n.floatVal & "\'f32"
-    else: 
+    else:
       f = n.floatVal.float32
       result = litAux(n, (cast[PInt32](addr(f)))[], 4) & "\'f32"
-  of nkFloat64Lit: 
-    if n.flags * {nfBase2, nfBase8, nfBase16} == {}: 
+  of nkFloat64Lit:
+    if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
       result = $n.floatVal & "\'f64"
-    else: 
+    else:
       result = litAux(n, (cast[PInt64](addr(n.floatVal)))[], 8) & "\'f64"
   of nkNilLit: result = "nil"
-  of nkType: 
+  of nkType:
     if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s
     else: result = "[type node]"
-  else: 
+  else:
     internalError("rnimsyn.atom " & $n.kind)
     result = ""
-  
-proc lcomma(n: PNode, start: int = 0, theEnd: int = - 1): int = 
+
+proc lcomma(n: PNode, start: int = 0, theEnd: int = - 1): int =
   assert(theEnd < 0)
   result = 0
-  for i in countup(start, sonsLen(n) + theEnd): 
+  for i in countup(start, sonsLen(n) + theEnd):
     inc(result, lsub(n.sons[i]))
     inc(result, 2)            # for ``, ``
-  if result > 0: 
+  if result > 0:
     dec(result, 2)            # last does not get a comma!
-  
-proc lsons(n: PNode, start: int = 0, theEnd: int = - 1): int = 
+
+proc lsons(n: PNode, start: int = 0, theEnd: int = - 1): int =
   assert(theEnd < 0)
   result = 0
   for i in countup(start, sonsLen(n) + theEnd): inc(result, lsub(n.sons[i]))
-  
-proc lsub(n: PNode): int = 
+
+proc lsub(n: PNode): int =
   # computes the length of a tree
   if isNil(n): return 0
   if n.comment != nil: return MaxLineLen + 1
   case n.kind
   of nkEmpty: result = 0
-  of nkTripleStrLit: 
+  of nkTripleStrLit:
     if containsNL(n.strVal): result = MaxLineLen + 1
     else: result = len(atom(n))
-  of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit: 
+  of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit:
     result = len(atom(n))
   of nkCall, nkBracketExpr, nkCurlyExpr, nkConv, nkPattern, nkObjConstr:
     result = lsub(n.sons[0]) + lcomma(n, 1) + 2
   of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: result = lsub(n[1])
   of nkCast: result = lsub(n.sons[0]) + lsub(n.sons[1]) + len("cast[]()")
-  of nkAddr: result = lsub(n.sons[0]) + len("addr()")
+  of nkAddr: result = (if n.len>0: lsub(n.sons[0]) + len("addr()") else: 4)
   of nkStaticExpr: result = lsub(n.sons[0]) + len("static_")
   of nkHiddenAddr, nkHiddenDeref: result = lsub(n.sons[0])
   of nkCommand: result = lsub(n.sons[0]) + lcomma(n, 1) + 1
@@ -390,9 +394,10 @@ proc lsub(n: PNode): int =
   of nkArgList: result = lcomma(n)
   of nkTableConstr:
     result = if n.len > 0: lcomma(n) + 2 else: len("{:}")
-  of nkClosedSymChoice, nkOpenSymChoice: 
+  of nkClosedSymChoice, nkOpenSymChoice:
     result = lsons(n) + len("()") + sonsLen(n) - 1
   of nkTupleTy: result = lcomma(n) + len("tuple[]")
+  of nkTupleClassTy: result = len("tuple")
   of nkDotExpr: result = lsons(n) + 1
   of nkBind: result = lsons(n) + len("bind_")
   of nkBindStmt: result = lcomma(n) + len("bind_")
@@ -400,7 +405,7 @@ proc lsub(n: PNode): int =
   of nkCheckedFieldExpr: result = lsub(n.sons[0])
   of nkLambda: result = lsons(n) + len("proc__=_")
   of nkDo: result = lsons(n) + len("do__:_")
-  of nkConstDef, nkIdentDefs: 
+  of nkConstDef, nkIdentDefs:
     result = lcomma(n, 0, - 3)
     var L = sonsLen(n)
     if n.sons[L - 2].kind != nkEmpty: result = result + lsub(n.sons[L - 2]) + 2
@@ -409,7 +414,7 @@ proc lsub(n: PNode): int =
   of nkChckRangeF: result = len("chckRangeF") + 2 + lcomma(n)
   of nkChckRange64: result = len("chckRange64") + 2 + lcomma(n)
   of nkChckRange: result = len("chckRange") + 2 + lcomma(n)
-  of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString: 
+  of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString:
     result = 2
     if sonsLen(n) >= 1: result = result + lsub(n.sons[0])
     result = result + lcomma(n, 1)
@@ -423,12 +428,12 @@ proc lsub(n: PNode): int =
   of nkRange: result = lsons(n) + 2
   of nkDerefExpr: result = lsub(n.sons[0]) + 2
   of nkAccQuoted: result = lsons(n) + 2
-  of nkIfExpr: 
+  of nkIfExpr:
     result = lsub(n.sons[0].sons[0]) + lsub(n.sons[0].sons[1]) + lsons(n, 1) +
         len("if_:_")
   of nkElifExpr: result = lsons(n) + len("_elif_:_")
   of nkElseExpr: result = lsub(n.sons[0]) + len("_else:_") # type descriptions
-  of nkTypeOfExpr: result = lsub(n.sons[0]) + len("type_")
+  of nkTypeOfExpr: result = (if n.len > 0: lsub(n.sons[0]) else: 0)+len("type_")
   of nkRefTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("ref")
   of nkPtrTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("ptr")
   of nkVarTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("var")
@@ -444,13 +449,13 @@ proc lsub(n: PNode): int =
   of nkProcTy: result = lsons(n) + len("proc_")
   of nkIteratorTy: result = lsons(n) + len("iterator_")
   of nkSharedTy: result = lsons(n) + len("shared_")
-  of nkEnumTy: 
+  of nkEnumTy:
     if sonsLen(n) > 0:
       result = lsub(n.sons[0]) + lcomma(n, 1) + len("enum_")
     else:
       result = len("enum")
   of nkEnumFieldDef: result = lsons(n) + 3
-  of nkVarSection, nkLetSection: 
+  of nkVarSection, nkLetSection:
     if sonsLen(n) > 1: result = MaxLineLen + 1
     else: result = lsons(n) + len("var_")
   of nkReturnStmt: result = lsub(n.sons[0]) + len("return_")
@@ -467,50 +472,51 @@ proc lsub(n: PNode): int =
   of nkElse: result = lsub(n.sons[0]) + len("else:_")
   of nkFinally: result = lsub(n.sons[0]) + len("finally:_")
   of nkGenericParams: result = lcomma(n) + 2
-  of nkFormalParams: 
+  of nkFormalParams:
     result = lcomma(n, 1) + 2
     if n.sons[0].kind != nkEmpty: result = result + lsub(n.sons[0]) + 2
-  of nkExceptBranch: 
+  of nkExceptBranch:
     result = lcomma(n, 0, -2) + lsub(lastSon(n)) + len("except_:_")
   else: result = MaxLineLen + 1
-  
-proc fits(g: TSrcGen, x: int): bool = 
+
+proc fits(g: TSrcGen, x: int): bool =
   result = x + g.lineLen <= MaxLineLen
 
-type 
-  TSubFlag = enum 
+type
+  TSubFlag = enum
     rfLongMode, rfNoIndent, rfInConstExpr
   TSubFlags = set[TSubFlag]
   TContext = tuple[spacing: int, flags: TSubFlags]
 
-const 
+const
   emptyContext: TContext = (spacing: 0, flags: {})
 
-proc initContext(c: var TContext) = 
+proc initContext(c: var TContext) =
   c.spacing = 0
   c.flags = {}
 
 proc gsub(g: var TSrcGen, n: PNode, c: TContext)
-proc gsub(g: var TSrcGen, n: PNode) = 
+proc gsub(g: var TSrcGen, n: PNode) =
   var c: TContext
   initContext(c)
   gsub(g, n, c)
 
-proc hasCom(n: PNode): bool = 
+proc hasCom(n: PNode): bool =
   result = false
+  if n.isNil: return false
   if n.comment != nil: return true
   case n.kind
   of nkEmpty..nkNilLit: discard
-  else: 
-    for i in countup(0, sonsLen(n) - 1): 
+  else:
+    for i in countup(0, sonsLen(n) - 1):
       if hasCom(n.sons[i]): return true
-  
-proc putWithSpace(g: var TSrcGen, kind: TTokType, s: string) = 
+
+proc putWithSpace(g: var TSrcGen, kind: TTokType, s: string) =
   put(g, kind, s)
   put(g, tkSpaces, Space)
 
-proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0, 
-               theEnd: int = - 1, separator = tkComma) = 
+proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0,
+               theEnd: int = - 1, separator = tkComma) =
   for i in countup(start, sonsLen(n) + theEnd):
     var c = i < sonsLen(n) + theEnd
     var sublen = lsub(n.sons[i]) + ord(c)
@@ -520,54 +526,54 @@ proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0,
     if c:
       if g.tokens.len > oldLen:
         putWithSpace(g, separator, TokTypeToStr[separator])
-      if hasCom(n.sons[i]): 
+      if hasCom(n.sons[i]):
         gcoms(g)
         optNL(g, ind)
 
-proc gcomma(g: var TSrcGen, n: PNode, c: TContext, start: int = 0, 
-            theEnd: int = - 1) = 
+proc gcomma(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
+            theEnd: int = - 1) =
   var ind: int
-  if rfInConstExpr in c.flags: 
+  if rfInConstExpr in c.flags:
     ind = g.indent + IndentWidth
-  else: 
+  else:
     ind = g.lineLen
     if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
   gcommaAux(g, n, ind, start, theEnd)
 
-proc gcomma(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) = 
+proc gcomma(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
   var ind = g.lineLen
   if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
   gcommaAux(g, n, ind, start, theEnd)
 
-proc gsemicolon(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) = 
+proc gsemicolon(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
   var ind = g.lineLen
   if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
   gcommaAux(g, n, ind, start, theEnd, tkSemiColon)
 
-proc gsons(g: var TSrcGen, n: PNode, c: TContext, start: int = 0, 
-           theEnd: int = - 1) = 
+proc gsons(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
+           theEnd: int = - 1) =
   for i in countup(start, sonsLen(n) + theEnd): gsub(g, n.sons[i], c)
 
-proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TTokType, 
-              k: string) = 
+proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TTokType,
+              k: string) =
   if sonsLen(n) == 0: return # empty var sections are possible
   putWithSpace(g, kind, k)
   gcoms(g)
   indentNL(g)
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     optNL(g)
     gsub(g, n.sons[i], c)
     gcoms(g)
   dedent(g)
 
-proc longMode(n: PNode, start: int = 0, theEnd: int = - 1): bool = 
+proc longMode(n: PNode, start: int = 0, theEnd: int = - 1): bool =
   result = n.comment != nil
-  if not result: 
+  if not result:
     # check further
-    for i in countup(start, sonsLen(n) + theEnd): 
-      if (lsub(n.sons[i]) > MaxLineLen): 
+    for i in countup(start, sonsLen(n) + theEnd):
+      if (lsub(n.sons[i]) > MaxLineLen):
         result = true
-        break 
+        break
 
 proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) =
   if n.kind == nkEmpty: return
@@ -587,43 +593,43 @@ proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) =
     gcoms(g)
     optNL(g)
     if rfLongMode in c.flags: dedent(g)
-  
-proc gif(g: var TSrcGen, n: PNode) = 
+
+proc gif(g: var TSrcGen, n: PNode) =
   var c: TContext
   gsub(g, n.sons[0].sons[0])
   initContext(c)
   putWithSpace(g, tkColon, ":")
-  if longMode(n) or (lsub(n.sons[0].sons[1]) + g.lineLen > MaxLineLen): 
+  if longMode(n) or (lsub(n.sons[0].sons[1]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)                    # a good place for comments
   gstmts(g, n.sons[0].sons[1], c)
   var length = sonsLen(n)
-  for i in countup(1, length - 1): 
+  for i in countup(1, length - 1):
     optNL(g)
     gsub(g, n.sons[i], c)
 
-proc gwhile(g: var TSrcGen, n: PNode) = 
+proc gwhile(g: var TSrcGen, n: PNode) =
   var c: TContext
   putWithSpace(g, tkWhile, "while")
   gsub(g, n.sons[0])
   putWithSpace(g, tkColon, ":")
   initContext(c)
-  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen): 
+  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)                    # a good place for comments
   gstmts(g, n.sons[1], c)
 
-proc gpattern(g: var TSrcGen, n: PNode) = 
+proc gpattern(g: var TSrcGen, n: PNode) =
   var c: TContext
   put(g, tkCurlyLe, "{")
   initContext(c)
   if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)                    # a good place for comments
-  gstmts(g, n.sons[0], c)
+  gstmts(g, n, c)
   put(g, tkCurlyRi, "}")
 
-proc gpragmaBlock(g: var TSrcGen, n: PNode) = 
+proc gpragmaBlock(g: var TSrcGen, n: PNode) =
   var c: TContext
   gsub(g, n.sons[0])
   putWithSpace(g, tkColon, ":")
@@ -633,25 +639,25 @@ proc gpragmaBlock(g: var TSrcGen, n: PNode) =
   gcoms(g)                    # a good place for comments
   gstmts(g, n.sons[1], c)
 
-proc gtry(g: var TSrcGen, n: PNode) = 
+proc gtry(g: var TSrcGen, n: PNode) =
   var c: TContext
   put(g, tkTry, "try")
   putWithSpace(g, tkColon, ":")
   initContext(c)
-  if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen): 
+  if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)                    # a good place for comments
   gstmts(g, n.sons[0], c)
   gsons(g, n, c, 1)
 
-proc gfor(g: var TSrcGen, n: PNode) = 
+proc gfor(g: var TSrcGen, n: PNode) =
   var c: TContext
   var length = sonsLen(n)
   putWithSpace(g, tkFor, "for")
   initContext(c)
   if longMode(n) or
       (lsub(n.sons[length - 1]) + lsub(n.sons[length - 2]) + 6 + g.lineLen >
-      MaxLineLen): 
+      MaxLineLen):
     incl(c.flags, rfLongMode)
   gcomma(g, n, c, 0, - 3)
   put(g, tkSpaces, Space)
@@ -661,17 +667,17 @@ proc gfor(g: var TSrcGen, n: PNode) =
   gcoms(g)
   gstmts(g, n.sons[length - 1], c)
 
-proc gmacro(g: var TSrcGen, n: PNode) = 
+proc gmacro(g: var TSrcGen, n: PNode) =
   var c: TContext
   initContext(c)
   gsub(g, n.sons[0])
   putWithSpace(g, tkColon, ":")
-  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen): 
+  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)
   gsons(g, n, c, 1)
 
-proc gcase(g: var TSrcGen, n: PNode) = 
+proc gcase(g: var TSrcGen, n: PNode) =
   var c: TContext
   initContext(c)
   var length = sonsLen(n)
@@ -682,18 +688,18 @@ proc gcase(g: var TSrcGen, n: PNode) =
   gcoms(g)
   optNL(g)
   gsons(g, n, c, 1, last)
-  if last == - 2: 
+  if last == - 2:
     initContext(c)
     if longMode(n.sons[length - 1]): incl(c.flags, rfLongMode)
     gsub(g, n.sons[length - 1], c)
 
-proc gproc(g: var TSrcGen, n: PNode) = 
+proc gproc(g: var TSrcGen, n: PNode) =
   var c: TContext
   if n.sons[namePos].kind == nkSym:
     put(g, tkSymbol, renderDefinitionName(n.sons[namePos].sym))
   else:
     gsub(g, n.sons[namePos])
-  
+
   if n.sons[patternPos].kind != nkEmpty:
     gpattern(g, n.sons[patternPos])
   let oldCheckAnon = g.checkAnon
@@ -720,7 +726,7 @@ proc gproc(g: var TSrcGen, n: PNode) =
 proc gTypeClassTy(g: var TSrcGen, n: PNode) =
   var c: TContext
   initContext(c)
-  putWithSpace(g, tkGeneric, "generic")
+  putWithSpace(g, tkConcept, "concept")
   gsons(g, n[0], c) # arglist
   gsub(g, n[1]) # pragmas
   gsub(g, n[2]) # of
@@ -730,7 +736,7 @@ proc gTypeClassTy(g: var TSrcGen, n: PNode) =
   gstmts(g, n[3], c)
   dedent(g)
 
-proc gblock(g: var TSrcGen, n: PNode) = 
+proc gblock(g: var TSrcGen, n: PNode) =
   var c: TContext
   initContext(c)
   if n.sons[0].kind != nkEmpty:
@@ -739,7 +745,7 @@ proc gblock(g: var TSrcGen, n: PNode) =
   else:
     put(g, tkBlock, "block")
   putWithSpace(g, tkColon, ":")
-  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen): 
+  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)
   # XXX I don't get why this is needed here! gstmts should already handle this!
@@ -747,17 +753,17 @@ proc gblock(g: var TSrcGen, n: PNode) =
   gstmts(g, n.sons[1], c)
   dedent(g)
 
-proc gstaticStmt(g: var TSrcGen, n: PNode) = 
+proc gstaticStmt(g: var TSrcGen, n: PNode) =
   var c: TContext
   putWithSpace(g, tkStatic, "static")
   putWithSpace(g, tkColon, ":")
   initContext(c)
-  if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen): 
+  if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
     incl(c.flags, rfLongMode)
   gcoms(g)                    # a good place for comments
   gstmts(g, n.sons[0], c)
 
-proc gasm(g: var TSrcGen, n: PNode) = 
+proc gasm(g: var TSrcGen, n: PNode) =
   putWithSpace(g, tkAsm, "asm")
   gsub(g, n.sons[0])
   gcoms(g)
@@ -767,16 +773,16 @@ proc gident(g: var TSrcGen, n: PNode) =
   if g.checkAnon and n.kind == nkSym and sfAnon in n.sym.flags: return
   var t: TTokType
   var s = atom(n)
-  if (s[0] in lexer.SymChars): 
-    if (n.kind == nkIdent): 
+  if (s[0] in lexer.SymChars):
+    if (n.kind == nkIdent):
       if (n.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or
-          (n.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)): 
+          (n.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):
         t = tkSymbol
-      else: 
+      else:
         t = TTokType(n.ident.id + ord(tkSymbol))
-    else: 
+    else:
       t = tkSymbol
-  else: 
+  else:
     t = tkOpr
   put(g, t, s)
   if n.kind == nkSym and renderIds in g.flags: put(g, tkIntLit, $n.sym.id)
@@ -786,12 +792,12 @@ proc doParamsAux(g: var TSrcGen, params: PNode) =
     put(g, tkParLe, "(")
     gsemicolon(g, params, 1)
     put(g, tkParRi, ")")
-  
-  if params.sons[0].kind != nkEmpty: 
+
+  if params.sons[0].kind != nkEmpty:
     putWithSpace(g, tkOpr, "->")
     gsub(g, params.sons[0])
 
-proc gsub(g: var TSrcGen, n: PNode, c: TContext) = 
+proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
   if isNil(n): return
   var
     a: TContext
@@ -824,14 +830,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkParLe, "(")
     gcomma(g, n, 1)
     put(g, tkParRi, ")")
-  of nkCallStrLit: 
+  of nkCallStrLit:
     gsub(g, n.sons[0])
-    if n.sons[1].kind == nkRStrLit: 
+    if n.sons[1].kind == nkRStrLit:
       put(g, tkRStrLit, '\"' & replace(n[1].strVal, "\"", "\"\"") & '\"')
-    else: 
+    else:
       gsub(g, n.sons[1])
   of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: gsub(g, n.sons[1])
-  of nkCast: 
+  of nkCast:
     put(g, tkCast, "cast")
     put(g, tkBracketLe, "[")
     gsub(g, n.sons[0])
@@ -839,16 +845,17 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkParLe, "(")
     gsub(g, n.sons[1])
     put(g, tkParRi, ")")
-  of nkAddr: 
+  of nkAddr:
     put(g, tkAddr, "addr")
-    put(g, tkParLe, "(")
-    gsub(g, n.sons[0])
-    put(g, tkParRi, ")")
+    if n.len > 0:
+      put(g, tkParLe, "(")
+      gsub(g, n.sons[0])
+      put(g, tkParRi, ")")
   of nkStaticExpr:
     put(g, tkStatic, "static")
     put(g, tkSpaces, Space)
     gsub(g, n.sons[0])
-  of nkBracketExpr: 
+  of nkBracketExpr:
     gsub(g, n.sons[0])
     put(g, tkBracketLe, "[")
     gcomma(g, n, 1)
@@ -858,41 +865,41 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkCurlyLe, "{")
     gcomma(g, n, 1)
     put(g, tkCurlyRi, "}")
-  of nkPragmaExpr: 
+  of nkPragmaExpr:
     gsub(g, n.sons[0])
     gcomma(g, n, 1)
-  of nkCommand: 
+  of nkCommand:
     gsub(g, n.sons[0])
     put(g, tkSpaces, Space)
     gcomma(g, n, 1)
-  of nkExprEqExpr, nkAsgn, nkFastAsgn: 
+  of nkExprEqExpr, nkAsgn, nkFastAsgn:
     gsub(g, n.sons[0])
     put(g, tkSpaces, Space)
     putWithSpace(g, tkEquals, "=")
     gsub(g, n.sons[1])
-  of nkChckRangeF: 
+  of nkChckRangeF:
     put(g, tkSymbol, "chckRangeF")
     put(g, tkParLe, "(")
     gcomma(g, n)
     put(g, tkParRi, ")")
-  of nkChckRange64: 
+  of nkChckRange64:
     put(g, tkSymbol, "chckRange64")
     put(g, tkParLe, "(")
     gcomma(g, n)
     put(g, tkParRi, ")")
-  of nkChckRange: 
+  of nkChckRange:
     put(g, tkSymbol, "chckRange")
     put(g, tkParLe, "(")
     gcomma(g, n)
     put(g, tkParRi, ")")
-  of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString: 
+  of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString:
     if sonsLen(n) >= 1: gsub(g, n.sons[0])
     put(g, tkParLe, "(")
     gcomma(g, n, 1)
     put(g, tkParRi, ")")
   of nkClosedSymChoice, nkOpenSymChoice:
     put(g, tkParLe, "(")
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       if i > 0: put(g, tkOpr, "|")
       if n.sons[i].kind == nkSym:
         let s = n[i].sym
@@ -903,11 +910,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       else:
         gsub(g, n.sons[i], c)
     put(g, tkParRi, if n.kind == nkOpenSymChoice: "|...)" else: ")")
-  of nkPar, nkClosure: 
+  of nkPar, nkClosure:
     put(g, tkParLe, "(")
     gcomma(g, n, c)
     put(g, tkParRi, ")")
-  of nkCurly: 
+  of nkCurly:
     put(g, tkCurlyLe, "{")
     gcomma(g, n, c)
     put(g, tkCurlyRi, "}")
@@ -922,14 +929,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkBracketLe, "[")
     gcomma(g, n, c)
     put(g, tkBracketRi, "]")
-  of nkDotExpr: 
+  of nkDotExpr:
     gsub(g, n.sons[0])
     put(g, tkDot, ".")
     gsub(g, n.sons[1])
-  of nkBind: 
+  of nkBind:
     putWithSpace(g, tkBind, "bind")
     gsub(g, n.sons[0])
-  of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref: 
+  of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref:
     gsub(g, n.sons[0])
   of nkLambda:
     putWithSpace(g, tkProc, "proc")
@@ -947,34 +954,34 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
   of nkConstDef, nkIdentDefs:
     gcomma(g, n, 0, -3)
     var L = sonsLen(n)
-    if n.sons[L - 2].kind != nkEmpty: 
+    if L >= 2 and n.sons[L - 2].kind != nkEmpty:
       putWithSpace(g, tkColon, ":")
       gsub(g, n.sons[L - 2])
-    if n.sons[L - 1].kind != nkEmpty: 
+    if L >= 1 and n.sons[L - 1].kind != nkEmpty:
       put(g, tkSpaces, Space)
       putWithSpace(g, tkEquals, "=")
       gsub(g, n.sons[L - 1], c)
-  of nkVarTuple: 
+  of nkVarTuple:
     put(g, tkParLe, "(")
     gcomma(g, n, 0, -3)
     put(g, tkParRi, ")")
     put(g, tkSpaces, Space)
     putWithSpace(g, tkEquals, "=")
     gsub(g, lastSon(n), c)
-  of nkExprColonExpr: 
+  of nkExprColonExpr:
     gsub(g, n.sons[0])
     putWithSpace(g, tkColon, ":")
     gsub(g, n.sons[1])
-  of nkInfix: 
+  of nkInfix:
     gsub(g, n.sons[1])
     put(g, tkSpaces, Space)
     gsub(g, n.sons[0])        # binary operator
-    if not fits(g, lsub(n.sons[2]) + lsub(n.sons[0]) + 1): 
+    if not fits(g, lsub(n.sons[2]) + lsub(n.sons[0]) + 1):
       optNL(g, g.indent + longIndentWid)
-    else: 
+    else:
       put(g, tkSpaces, Space)
     gsub(g, n.sons[2])
-  of nkPrefix: 
+  of nkPrefix:
     gsub(g, n.sons[0])
     if n.len > 1:
       put(g, tkSpaces, Space)
@@ -984,10 +991,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
         put(g, tkParRi, ")")
       else:
         gsub(g, n.sons[1])
-  of nkPostfix: 
+  of nkPostfix:
     gsub(g, n.sons[1])
     gsub(g, n.sons[0])
-  of nkRange: 
+  of nkRange:
     gsub(g, n.sons[0])
     put(g, tkDotDot, "..")
     gsub(g, n.sons[1])
@@ -1001,43 +1008,43 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       put(g, tkSpaces, Space)
       gsub(g, n.sons[i])
     put(g, tkAccent, "`")
-  of nkIfExpr: 
+  of nkIfExpr:
     putWithSpace(g, tkIf, "if")
     gsub(g, n.sons[0].sons[0])
     putWithSpace(g, tkColon, ":")
     gsub(g, n.sons[0].sons[1])
     gsons(g, n, emptyContext, 1)
-  of nkElifExpr: 
+  of nkElifExpr:
     putWithSpace(g, tkElif, " elif")
     gsub(g, n.sons[0])
     putWithSpace(g, tkColon, ":")
     gsub(g, n.sons[1])
-  of nkElseExpr: 
+  of nkElseExpr:
     put(g, tkElse, " else")
     putWithSpace(g, tkColon, ":")
     gsub(g, n.sons[0])
   of nkTypeOfExpr:
     putWithSpace(g, tkType, "type")
     if n.len > 0: gsub(g, n.sons[0])
-  of nkRefTy: 
+  of nkRefTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkRef, "ref")
       gsub(g, n.sons[0])
     else:
       put(g, tkRef, "ref")
-  of nkPtrTy: 
+  of nkPtrTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkPtr, "ptr")
       gsub(g, n.sons[0])
     else:
       put(g, tkPtr, "ptr")
-  of nkVarTy: 
+  of nkVarTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkVar, "var")
       gsub(g, n.sons[0])
     else:
       put(g, tkVar, "var")
-  of nkDistinctTy: 
+  of nkDistinctTy:
     if n.len > 0:
       putWithSpace(g, tkDistinct, "distinct")
       gsub(g, n.sons[0])
@@ -1049,14 +1056,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
         gcomma(g, n[1])
     else:
       put(g, tkDistinct, "distinct")
-  of nkTypeDef: 
+  of nkTypeDef:
     gsub(g, n.sons[0])
     gsub(g, n.sons[1])
     put(g, tkSpaces, Space)
-    if n.sons[2].kind != nkEmpty: 
+    if n.sons[2].kind != nkEmpty:
       putWithSpace(g, tkEquals, "=")
       gsub(g, n.sons[2])
-  of nkObjectTy: 
+  of nkObjectTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkObject, "object")
       gsub(g, n.sons[0])
@@ -1065,18 +1072,18 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       gsub(g, n.sons[2])
     else:
       put(g, tkObject, "object")
-  of nkRecList: 
+  of nkRecList:
     indentNL(g)
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       optNL(g)
       gsub(g, n.sons[i], c)
       gcoms(g)
     dedent(g)
     putNL(g)
-  of nkOfInherit: 
+  of nkOfInherit:
     putWithSpace(g, tkOf, "of")
     gsub(g, n.sons[0])
-  of nkProcTy: 
+  of nkProcTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkProc, "proc")
       gsub(g, n.sons[0])
@@ -1095,7 +1102,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkBracketLe, "[")
     if n.len > 0:
       gsub(g, n.sons[0])
-    put(g, tkBracketRi, "]")    
+    put(g, tkBracketRi, "]")
   of nkEnumTy:
     if sonsLen(n) > 0:
       putWithSpace(g, tkEnum, "enum")
@@ -1107,16 +1114,16 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       dedent(g)
     else:
       put(g, tkEnum, "enum")
-  of nkEnumFieldDef: 
+  of nkEnumFieldDef:
     gsub(g, n.sons[0])
     put(g, tkSpaces, Space)
     putWithSpace(g, tkEquals, "=")
     gsub(g, n.sons[1])
   of nkStmtList, nkStmtListExpr, nkStmtListType: gstmts(g, n, emptyContext)
-  of nkIfStmt: 
+  of nkIfStmt:
     putWithSpace(g, tkIf, "if")
     gif(g, n)
-  of nkWhen, nkRecWhen: 
+  of nkWhen, nkRecWhen:
     putWithSpace(g, tkWhen, "when")
     gif(g, n)
   of nkWhileStmt: gwhile(g, n)
@@ -1127,27 +1134,27 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
   of nkBlockStmt, nkBlockExpr: gblock(g, n)
   of nkStaticStmt: gstaticStmt(g, n)
   of nkAsmStmt: gasm(g, n)
-  of nkProcDef: 
+  of nkProcDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkProc, "proc")
     gproc(g, n)
   of nkConverterDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkConverter, "converter")
     gproc(g, n)
-  of nkMethodDef: 
+  of nkMethodDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkMethod, "method")
     gproc(g, n)
-  of nkIteratorDef: 
+  of nkIteratorDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkIterator, "iterator")
     gproc(g, n)
-  of nkMacroDef: 
+  of nkMacroDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkMacro, "macro")
     gproc(g, n)
-  of nkTemplateDef: 
+  of nkTemplateDef:
     if renderNoProcDefs notin g.flags: putWithSpace(g, tkTemplate, "template")
     gproc(g, n)
-  of nkTypeSection: 
+  of nkTypeSection:
     gsection(g, n, emptyContext, tkType, "type")
-  of nkConstSection: 
+  of nkConstSection:
     initContext(a)
     incl(a.flags, rfInConstExpr)
     gsection(g, n, a, tkConst, "const")
@@ -1156,40 +1163,45 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     if L == 0: return
     if n.kind == nkVarSection: putWithSpace(g, tkVar, "var")
     else: putWithSpace(g, tkLet, "let")
-    if L > 1: 
+    if L > 1:
       gcoms(g)
       indentNL(g)
-      for i in countup(0, L - 1): 
+      for i in countup(0, L - 1):
         optNL(g)
         gsub(g, n.sons[i])
         gcoms(g)
       dedent(g)
-    else: 
+    else:
       gsub(g, n.sons[0])
-  of nkReturnStmt: 
+  of nkReturnStmt:
     putWithSpace(g, tkReturn, "return")
     gsub(g, n.sons[0])
-  of nkRaiseStmt: 
+  of nkRaiseStmt:
     putWithSpace(g, tkRaise, "raise")
     gsub(g, n.sons[0])
-  of nkYieldStmt: 
+  of nkYieldStmt:
     putWithSpace(g, tkYield, "yield")
     gsub(g, n.sons[0])
-  of nkDiscardStmt: 
+  of nkDiscardStmt:
     putWithSpace(g, tkDiscard, "discard")
     gsub(g, n.sons[0])
-  of nkBreakStmt: 
+  of nkBreakStmt:
     putWithSpace(g, tkBreak, "break")
     gsub(g, n.sons[0])
-  of nkContinueStmt: 
+  of nkContinueStmt:
     putWithSpace(g, tkContinue, "continue")
     gsub(g, n.sons[0])
-  of nkPragma: 
+  of nkPragma:
     if renderNoPragmas notin g.flags:
-      put(g, tkSpaces, Space)
-      put(g, tkCurlyDotLe, "{.")
-      gcomma(g, n, emptyContext)
-      put(g, tkCurlyDotRi, ".}")
+      if g.inPragma <= 0:
+        inc g.inPragma
+        put(g, tkSpaces, Space)
+        put(g, tkCurlyDotLe, "{.")
+        gcomma(g, n, emptyContext)
+        put(g, tkCurlyDotRi, ".}")
+        dec g.inPragma
+      else:
+        gcomma(g, n, emptyContext)
   of nkImportStmt, nkExportStmt:
     if n.kind == nkImportStmt:
       putWithSpace(g, tkImport, "import")
@@ -1211,24 +1223,24 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     gcommaAux(g, n, g.indent, 1)
     gcoms(g)
     putNL(g)
-  of nkFromStmt: 
+  of nkFromStmt:
     putWithSpace(g, tkFrom, "from")
     gsub(g, n.sons[0])
     put(g, tkSpaces, Space)
     putWithSpace(g, tkImport, "import")
     gcomma(g, n, emptyContext, 1)
     putNL(g)
-  of nkIncludeStmt: 
+  of nkIncludeStmt:
     putWithSpace(g, tkInclude, "include")
     gcoms(g)
     indentNL(g)
     gcommaAux(g, n, g.indent)
     dedent(g)
     putNL(g)
-  of nkCommentStmt: 
+  of nkCommentStmt:
     gcoms(g)
     optNL(g)
-  of nkOfBranch: 
+  of nkOfBranch:
     optNL(g)
     putWithSpace(g, tkOf, "of")
     gcomma(g, n, c, 0, - 2)
@@ -1240,55 +1252,59 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     put(g, tkSpaces, Space)
     putWithSpace(g, tkAs, "as")
     gsub(g, n.sons[1])
-  of nkBindStmt: 
+  of nkBindStmt:
     putWithSpace(g, tkBind, "bind")
     gcomma(g, n, c)
   of nkMixinStmt:
     putWithSpace(g, tkMixin, "mixin")
     gcomma(g, n, c)
-  of nkElifBranch: 
+  of nkElifBranch:
     optNL(g)
     putWithSpace(g, tkElif, "elif")
     gsub(g, n.sons[0])
     putWithSpace(g, tkColon, ":")
     gcoms(g)
     gstmts(g, n.sons[1], c)
-  of nkElse: 
+  of nkElse:
     optNL(g)
     put(g, tkElse, "else")
     putWithSpace(g, tkColon, ":")
     gcoms(g)
     gstmts(g, n.sons[0], c)
-  of nkFinally: 
+  of nkFinally, nkDefer:
     optNL(g)
-    put(g, tkFinally, "finally")
+    if n.kind == nkFinally:
+      put(g, tkFinally, "finally")
+    else:
+      put(g, tkDefer, "defer")
     putWithSpace(g, tkColon, ":")
     gcoms(g)
     gstmts(g, n.sons[0], c)
-  of nkExceptBranch: 
+  of nkExceptBranch:
     optNL(g)
     putWithSpace(g, tkExcept, "except")
     gcomma(g, n, 0, - 2)
     putWithSpace(g, tkColon, ":")
     gcoms(g)
     gstmts(g, lastSon(n), c)
-  of nkGenericParams: 
+  of nkGenericParams:
     put(g, tkBracketLe, "[")
     gcomma(g, n)
     put(g, tkBracketRi, "]")
-  of nkFormalParams: 
+  of nkFormalParams:
     put(g, tkParLe, "(")
     gsemicolon(g, n, 1)
     put(g, tkParRi, ")")
-    if n.sons[0].kind != nkEmpty: 
+    if n.sons[0].kind != nkEmpty:
       putWithSpace(g, tkColon, ":")
       gsub(g, n.sons[0])
-  of nkTupleTy: 
+  of nkTupleTy:
+    put(g, tkTuple, "tuple")
+    put(g, tkBracketLe, "[")
+    gcomma(g, n)
+    put(g, tkBracketRi, "]")
+  of nkTupleClassTy:
     put(g, tkTuple, "tuple")
-    if sonsLen(n) > 0:
-      put(g, tkBracketLe, "[")
-      gcomma(g, n)
-      put(g, tkBracketRi, "]")
   of nkMetaNode_Obsolete:
     put(g, tkParLe, "(META|")
     gsub(g, n.sons[0])
@@ -1300,17 +1316,17 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     gsons(g, n, c)
   of nkTypeClassTy:
     gTypeClassTy(g, n)
-  else: 
-    #nkNone, nkExplicitTypeListCall: 
+  else:
+    #nkNone, nkExplicitTypeListCall:
     internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
 
-proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string = 
+proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string =
   var g: TSrcGen
   initSrcGen(g, renderFlags)
   gsub(g, n)
   result = g.buf
 
-proc renderModule(n: PNode, filename: string, 
+proc renderModule(n: PNode, filename: string,
                   renderFlags: TRenderFlags = {}) =
   var
     f: File
@@ -1330,18 +1346,18 @@ proc renderModule(n: PNode, filename: string,
     write(f, g.buf)
     close(f)
   else:
-    rawMessage(errCannotOpenFile, filename)    
+    rawMessage(errCannotOpenFile, filename)
 
-proc initTokRender(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) = 
+proc initTokRender(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) =
   initSrcGen(r, renderFlags)
   gsub(r, n)
 
-proc getNextTok(r: var TSrcGen, kind: var TTokType, literal: var string) = 
-  if r.idx < len(r.tokens): 
+proc getNextTok(r: var TSrcGen, kind: var TTokType, literal: var string) =
+  if r.idx < len(r.tokens):
     kind = r.tokens[r.idx].kind
     var length = r.tokens[r.idx].length.int
     literal = substr(r.buf, r.pos, r.pos + length - 1)
     inc(r.pos, length)
     inc(r.idx)
-  else: 
+  else:
     kind = tkEof
diff --git a/compiler/rodread.nim b/compiler/rodread.nim
index 3b3538e5d..e92f7ecfa 100644
--- a/compiler/rodread.nim
+++ b/compiler/rodread.nim
@@ -277,7 +277,7 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
       loc.t = nil
     if r.s[r.pos] == '!': 
       inc(r.pos)
-      loc.r = toRope(decodeStr(r.s, r.pos))
+      loc.r = rope(decodeStr(r.s, r.pos))
     else: 
       loc.r = nil
     if r.s[r.pos] == '>': inc(r.pos)
@@ -344,7 +344,7 @@ proc decodeLib(r: PRodReader, info: TLineInfo): PLib =
     result.kind = TLibKind(decodeVInt(r.s, r.pos))
     if r.s[r.pos] != '|': internalError("decodeLib: 1")
     inc(r.pos)
-    result.name = toRope(decodeStr(r.s, r.pos))
+    result.name = rope(decodeStr(r.s, r.pos))
     if r.s[r.pos] != '|': internalError("decodeLib: 2")
     inc(r.pos)
     result.path = decodeNode(r, info)
@@ -666,7 +666,7 @@ proc newRodReader(modfilename: string, crc: TCrc32,
   r.readerIndex = readerIndex
   r.filename = modfilename
   initIdTable(r.syms)
-  # we terminate the file explicitely with ``\0``, so the cast to `cstring`
+  # we terminate the file explicitly with ``\0``, so the cast to `cstring`
   # is safe:
   r.s = cast[cstring](r.memfile.mem)
   if startsWith(r.s, "NIM:"): 
diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim
index 9fed7ac52..e178b7ce6 100644
--- a/compiler/rodwrite.nim
+++ b/compiler/rodwrite.nim
@@ -186,7 +186,7 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
     pushType(w, loc.t)
   if loc.r != nil: 
     add(result, '!')
-    encodeStr(ropeToStr(loc.r), result)
+    encodeStr($loc.r, result)
   if oldLen + 1 == result.len:
     # no data was necessary, so remove the '<' again:
     setLen(result, oldLen)
@@ -200,7 +200,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
     return
   # we need no surrounding [] here because the type is in a line of its own
   if t.kind == tyForward: internalError("encodeType: tyForward")
-  # for the new rodfile viewer we use a preceeding [ so that the data section
+  # for the new rodfile viewer we use a preceding [ so that the data section
   # can easily be disambiguated:
   add(result, '[')
   encodeVInt(ord(t.kind), result)
@@ -241,7 +241,7 @@ proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
   add(result, '|')
   encodeVInt(ord(lib.kind), result)
   add(result, '|')
-  encodeStr(ropeToStr(lib.name), result)
+  encodeStr($lib.name, result)
   add(result, '|')
   encodeNode(w, info, lib.path, result)
 
diff --git a/compiler/ropes.nim b/compiler/ropes.nim
index b14081694..edac8e9d0 100644
--- a/compiler/ropes.nim
+++ b/compiler/ropes.nim
@@ -52,84 +52,66 @@
 #  Note that the left and right pointers are not needed for leaves.
 #  Leaves have relatively high memory overhead (~30 bytes on a 32
 #  bit machines) and we produce many of them. This is why we cache and
-#  share leaves accross different rope trees.
+#  share leaves across different rope trees.
 #  To cache them they are inserted in a `cache` array.
 
-import 
-  strutils, platform, hashes, crc, options
+import
+  platform, hashes
 
 type
-  TFormatStr* = string # later we may change it to CString for better
-                       # performance of the code generator (assignments 
+  FormatStr* = string  # later we may change it to CString for better
+                       # performance of the code generator (assignments
                        # copy the format strings
                        # though it is not necessary)
-  PRope* = ref TRope
-  TRope*{.acyclic.} = object of RootObj # the empty rope is represented 
-                                        # by nil to safe space
-    left*, right*: PRope
+  Rope* = ref RopeObj
+  RopeObj*{.acyclic.} = object of RootObj # the empty rope is represented
+                                          # by nil to safe space
+    left*, right*: Rope
     length*: int
     data*: string             # != nil if a leaf
-  
-  TRopeSeq* = seq[PRope]
 
-  TRopesError* = enum
+  RopeSeq* = seq[Rope]
+
+  RopesError* = enum
     rCannotOpenFile
     rInvalidFormatStr
-    rTokenTooLong
-
-proc con*(a, b: PRope): PRope
-proc con*(a: PRope, b: string): PRope
-proc con*(a: string, b: PRope): PRope
-proc con*(a: varargs[PRope]): PRope
-proc app*(a: var PRope, b: PRope)
-proc app*(a: var PRope, b: string)
-proc prepend*(a: var PRope, b: PRope)
-proc toRope*(s: string): PRope
-proc toRope*(i: BiggestInt): PRope
-proc ropeLen*(a: PRope): int
-proc writeRopeIfNotEqual*(r: PRope, filename: string): bool
-proc ropeToStr*(p: PRope): string
-proc ropef*(frmt: TFormatStr, args: varargs[PRope]): PRope
-proc appf*(c: var PRope, frmt: TFormatStr, args: varargs[PRope])
-proc ropeEqualsFile*(r: PRope, f: string): bool
-  # returns true if the rope r is the same as the contents of file f
-proc ropeInvariant*(r: PRope): bool
-  # exported for debugging
+
 # implementation
 
-var errorHandler*: proc(err: TRopesError, msg: string, useWarning = false)
+var errorHandler*: proc(err: RopesError, msg: string, useWarning = false)
   # avoid dependency on msgs.nim
-  
-proc ropeLen(a: PRope): int = 
+
+proc len*(a: Rope): int =
+  ## the rope's length
   if a == nil: result = 0
   else: result = a.length
-  
-proc newRope*(data: string = nil): PRope = 
+
+proc newRope(data: string = nil): Rope =
   new(result)
-  if data != nil: 
+  if data != nil:
     result.length = len(data)
     result.data = data
 
-proc newMutableRope*(capacity = 30): PRope =
+proc newMutableRope*(capacity = 30): Rope =
   ## creates a new rope that supports direct modifications of the rope's
   ## 'data' and 'length' fields.
   new(result)
   result.data = newStringOfCap(capacity)
 
-proc freezeMutableRope*(r: PRope) {.inline.} =
+proc freezeMutableRope*(r: Rope) {.inline.} =
   r.length = r.data.len
 
-var 
-  cache: array[0..2048*2 -1, PRope]
+var
+  cache: array[0..2048*2 - 1, Rope]
 
 proc resetRopeCache* =
   for i in low(cache)..high(cache):
     cache[i] = nil
 
-proc ropeInvariant(r: PRope): bool = 
-  if r == nil: 
+proc ropeInvariant(r: Rope): bool =
+  if r == nil:
     result = true
-  else: 
+  else:
     result = true #
                   #    if r.data <> snil then
                   #      result := true
@@ -137,13 +119,13 @@ proc ropeInvariant(r: PRope): bool =
                   #      result := (r.left <> nil) and (r.right <> nil);
                   #      if result then result := ropeInvariant(r.left);
                   #      if result then result := ropeInvariant(r.right);
-                  #    end 
+                  #    end
 
 var gCacheTries* = 0
 var gCacheMisses* = 0
 var gCacheIntTries* = 0
 
-proc insertInCache(s: string): PRope = 
+proc insertInCache(s: string): Rope =
   inc gCacheTries
   var h = hash(s) and high(cache)
   result = cache[h]
@@ -151,83 +133,78 @@ proc insertInCache(s: string): PRope =
     inc gCacheMisses
     result = newRope(s)
     cache[h] = result
-  
-proc toRope(s: string): PRope =
+
+proc rope*(s: string): Rope =
+  ## Converts a string to a rope.
   if s.len == 0:
     result = nil
   else:
     result = insertInCache(s)
   assert(ropeInvariant(result))
 
-proc ropeSeqInsert(rs: var TRopeSeq, r: PRope, at: Natural) = 
-  var length = len(rs)
-  if at > length: 
-    setLen(rs, at + 1)
-  else: 
-    setLen(rs, length + 1)    # move old rope elements:
-  for i in countdown(length, at + 1): 
-    rs[i] = rs[i - 1] # this is correct, I used pen and paper to validate it
-  rs[at] = r
-
-proc newRecRopeToStr(result: var string, resultLen: var int, r: PRope) = 
-  var stack = @[r]
-  while len(stack) > 0: 
-    var it = pop(stack)
-    while it.data == nil: 
-      add(stack, it.right)
-      it = it.left
-    assert(it.data != nil)
-    copyMem(addr(result[resultLen]), addr(it.data[0]), it.length)
-    inc(resultLen, it.length)
-    assert(resultLen <= len(result))
-
-proc ropeToStr(p: PRope): string = 
-  if p == nil: 
-    result = ""
-  else: 
-    result = newString(p.length)
-    var resultLen = 0
-    newRecRopeToStr(result, resultLen, p)
-
-proc con(a, b: PRope): PRope = 
-  if a == nil: result = b
-  elif b == nil: result = a
+proc rope*(i: BiggestInt): Rope =
+  ## Converts an int to a rope.
+  inc gCacheIntTries
+  result = rope($i)
+
+proc rope*(f: BiggestFloat): Rope =
+  ## Converts a float to a rope.
+  result = rope($f)
+
+proc `&`*(a, b: Rope): Rope =
+  if a == nil:
+    result = b
+  elif b == nil:
+    result = a
   else:
     result = newRope()
     result.length = a.length + b.length
     result.left = a
     result.right = b
 
-proc con(a: PRope, b: string): PRope = result = con(a, toRope(b))
-proc con(a: string, b: PRope): PRope = result = con(toRope(a), b)
-
-proc con(a: varargs[PRope]): PRope = 
-  for i in countup(0, high(a)): result = con(result, a[i])
-
-proc ropeConcat*(a: varargs[PRope]): PRope =
-  # not overloaded version of concat to speed-up `rfmt` a little bit
-  for i in countup(0, high(a)): result = con(result, a[i])
-
-proc toRope(i: BiggestInt): PRope =
-  inc gCacheIntTries
-  result = toRope($i)
-
-proc app(a: var PRope, b: PRope) = a = con(a, b)
-proc app(a: var PRope, b: string) = a = con(a, b)
-proc prepend(a: var PRope, b: PRope) = a = con(b, a)
-
-proc writeRope*(f: File, c: PRope) = 
-  var stack = @[c]
-  while len(stack) > 0: 
-    var it = pop(stack)
-    while it.data == nil: 
-      add(stack, it.right)
-      it = it.left
-      assert(it != nil)
-    assert(it.data != nil)
-    write(f, it.data)
-
-proc writeRope*(head: PRope, filename: string, useWarning = false) =
+proc `&`*(a: Rope, b: string): Rope =
+  ## the concatenation operator for ropes.
+  result = a & rope(b)
+
+proc `&`*(a: string, b: Rope): Rope =
+  ## the concatenation operator for ropes.
+  result = rope(a) & b
+
+proc `&`*(a: openArray[Rope]): Rope =
+  ## the concatenation operator for an openarray of ropes.
+  for i in countup(0, high(a)): result = result & a[i]
+
+proc add*(a: var Rope, b: Rope) =
+  ## adds `b` to the rope `a`.
+  a = a & b
+
+proc add*(a: var Rope, b: string) =
+  ## adds `b` to the rope `a`.
+  a = a & b
+
+iterator leaves*(r: Rope): string =
+  ## iterates over any leaf string in the rope `r`.
+  if r != nil:
+    var stack = @[r]
+    while stack.len > 0:
+      var it = stack.pop
+      while isNil(it.data):
+        stack.add(it.right)
+        it = it.left
+        assert(it != nil)
+      assert(it.data != nil)
+      yield it.data
+
+iterator items*(r: Rope): char =
+  ## iterates over any character in the rope `r`.
+  for s in leaves(r):
+    for c in items(s): yield c
+
+proc writeRope*(f: File, r: Rope) =
+  ## writes a rope to a file.
+  for s in leaves(r): write(f, s)
+
+proc writeRope*(head: Rope, filename: string, useWarning = false) =
   var f: File
   if open(f, filename, fmWrite):
     if head != nil: writeRope(f, head)
@@ -235,42 +212,69 @@ proc writeRope*(head: PRope, filename: string, useWarning = false) =
   else:
     errorHandler(rCannotOpenFile, filename, useWarning)
 
+proc `$`*(r: Rope): string =
+  ## converts a rope back to a string.
+  result = newString(r.len)
+  setLen(result, 0)
+  for s in leaves(r): add(result, s)
+
+proc ropeConcat*(a: varargs[Rope]): Rope =
+  # not overloaded version of concat to speed-up `rfmt` a little bit
+  for i in countup(0, high(a)): result = result & a[i]
+
+proc prepend*(a: var Rope, b: Rope) = a = b & a
+proc prepend*(a: var Rope, b: string) = a = b & a
+
 var
   rnl* = tnl.newRope
   softRnl* = tnl.newRope
 
-proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope = 
+proc `%`*(frmt: FormatStr, args: openArray[Rope]): Rope =
   var i = 0
   var length = len(frmt)
   result = nil
   var num = 0
-  while i <= length - 1: 
-    if frmt[i] == '$': 
+  while i < length:
+    if frmt[i] == '$':
       inc(i)                  # skip '$'
       case frmt[i]
-      of '$': 
-        app(result, "$")
+      of '$':
+        add(result, "$")
         inc(i)
-      of '#': 
+      of '#':
         inc(i)
-        app(result, args[num])
+        add(result, args[num])
         inc(num)
-      of '0'..'9': 
+      of '0'..'9':
         var j = 0
-        while true: 
-          j = (j * 10) + ord(frmt[i]) - ord('0')
+        while true:
+          j = j * 10 + ord(frmt[i]) - ord('0')
           inc(i)
-          if (i > length + 0 - 1) or not (frmt[i] in {'0'..'9'}): break 
+          if frmt[i] notin {'0'..'9'}: break
         num = j
         if j > high(args) + 1:
           errorHandler(rInvalidFormatStr, $(j))
         else:
-          app(result, args[j - 1])
+          add(result, args[j-1])
+      of '{':
+        inc(i)
+        var j = 0
+        while frmt[i] in {'0'..'9'}:
+          j = j * 10 + ord(frmt[i]) - ord('0')
+          inc(i)
+        num = j
+        if frmt[i] == '}': inc(i)
+        else: errorHandler(rInvalidFormatStr, $(frmt[i]))
+
+        if j > high(args) + 1:
+          errorHandler(rInvalidFormatStr, $(j))
+        else:
+          add(result, args[j-1])
       of 'n':
-        app(result, softRnl)
-        inc i
+        add(result, softRnl)
+        inc(i)
       of 'N':
-        app(result, rnl)
+        add(result, rnl)
         inc(i)
       else:
         errorHandler(rInvalidFormatStr, $(frmt[i]))
@@ -278,85 +282,69 @@ proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
     while i < length:
       if frmt[i] != '$': inc(i)
       else: break
-    if i - 1 >= start: 
-      app(result, substr(frmt, start, i - 1))
+    if i - 1 >= start:
+      add(result, substr(frmt, start, i - 1))
   assert(ropeInvariant(result))
 
+proc addf*(c: var Rope, frmt: FormatStr, args: openArray[Rope]) =
+  ## shortcut for ``add(c, frmt % args)``.
+  add(c, frmt % args)
+
 when true:
-  template `~`*(r: string): PRope = r.ropef
+  template `~`*(r: string): Rope = r % []
 else:
   {.push stack_trace: off, line_trace: off.}
-  proc `~`*(r: static[string]): PRope =
+  proc `~`*(r: static[string]): Rope =
     # this is the new optimized "to rope" operator
     # the mnemonic is that `~` looks a bit like a rope :)
-    var r {.global.} = r.ropef
+    var r {.global.} = r % []
     return r
   {.pop.}
 
-proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) = 
-  app(c, ropef(frmt, args))
-
-const 
+const
   bufSize = 1024              # 1 KB is reasonable
 
-proc auxRopeEqualsFile(r: PRope, bin: var File, buf: pointer): bool = 
-  if r.data != nil:
-    if r.length > bufSize:
-      errorHandler(rTokenTooLong, r.data)
-      return
-    var readBytes = readBuffer(bin, buf, r.length)
-    result = readBytes == r.length and
-        equalMem(buf, addr(r.data[0]), r.length) # BUGFIX
-  else: 
-    result = auxRopeEqualsFile(r.left, bin, buf)
-    if result: result = auxRopeEqualsFile(r.right, bin, buf)
-  
-proc ropeEqualsFile(r: PRope, f: string): bool = 
-  var bin: File
-  result = open(bin, f)
-  if not result: 
-    return                    # not equal if file does not exist
-  var buf = alloc(bufSize)
-  result = auxRopeEqualsFile(r, bin, buf)
-  if result: 
-    result = readBuffer(bin, buf, bufSize) == 0 # really at the end of file?
-  dealloc(buf)
-  close(bin)
-
-proc crcFromRopeAux(r: PRope, startVal: TCrc32): TCrc32 = 
-  if r.data != nil: 
-    result = startVal
-    for i in countup(0, len(r.data) - 1): 
-      result = updateCrc32(r.data[i], result)
-  else: 
-    result = crcFromRopeAux(r.left, startVal)
-    result = crcFromRopeAux(r.right, result)
-
-proc newCrcFromRopeAux(r: PRope, startVal: TCrc32): TCrc32 = 
-  # XXX profiling shows this is actually expensive
-  var stack: TRopeSeq = @[r]
-  result = startVal
-  while len(stack) > 0: 
-    var it = pop(stack)
-    while it.data == nil: 
-      add(stack, it.right)
-      it = it.left
-    assert(it.data != nil)
-    var i = 0
-    var L = len(it.data)
-    while i < L: 
-      result = updateCrc32(it.data[i], result)
-      inc(i)
-
-proc crcFromRope(r: PRope): TCrc32 = 
-  result = newCrcFromRopeAux(r, InitCrc32)
-
-proc writeRopeIfNotEqual(r: PRope, filename: string): bool = 
+proc equalsFile*(r: Rope, f: File): bool =
+  ## returns true if the contents of the file `f` equal `r`.
+  var 
+    buf: array[bufSize, char]
+    bpos = buf.len
+    blen = buf.len
+
+  for s in leaves(r):
+    var spos = 0
+    let slen = s.len
+    while spos < slen:
+      if bpos == blen:
+        # Read more data
+        bpos = 0
+        blen = readBuffer(f, addr(buf[0]), buf.len)
+        if blen == 0:  # no more data in file
+          result = false
+          return
+      let n = min(blen - bpos, slen - spos)
+      # TODO There's gotta be a better way of comparing here...
+      if not equalMem(addr(buf[bpos]), cast[pointer](cast[int](cstring(s))+spos), n):
+        result = false
+        return
+      spos += n
+      bpos += n
+
+  result = readBuffer(f, addr(buf[0]), 1) == 0  # check that we've read all
+
+proc equalsFile*(r: Rope, filename: string): bool =
+  ## returns true if the contents of the file `f` equal `r`. If `f` does not
+  ## exist, false is returned.
+  var f: File
+  result = open(f, filename)
+  if result:
+    result = equalsFile(r, f)
+    close(f)
+
+proc writeRopeIfNotEqual*(r: Rope, filename: string): bool =
   # returns true if overwritten
-  var c: TCrc32
-  c = crcFromFile(filename)
-  if c != crcFromRope(r): 
+  if not equalsFile(r, filename):
     writeRope(r, filename)
     result = true
-  else: 
+  else:
     result = false
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 5160af20a..2e13c88c3 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -16,7 +16,7 @@ import
   procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
   intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
   evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity,
-  semparallel, lowerings
+  semparallel, lowerings, plugins, plugins.active
 
 when defined(nimfix):
   import nimfix.prettybase
@@ -41,15 +41,32 @@ proc addParams(c: PContext, n: PNode, kind: TSymKind)
 proc maybeAddResult(c: PContext, s: PSym, n: PNode)
 proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
 proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
-proc fixImmediateParams(n: PNode): PNode
 proc activate(c: PContext, n: PNode)
 proc semQuoteAst(c: PContext, n: PNode): PNode
 proc finishMethod(c: PContext, s: PSym)
 
 proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode
 
-proc typeMismatch(n: PNode, formal, actual: PType) = 
-  if formal.kind != tyError and actual.kind != tyError: 
+template semIdeForTemplateOrGenericCheck(n, requiresCheck) =
+  # we check quickly if the node is where the cursor is
+  when defined(nimsuggest):
+    if n.info.fileIndex == gTrackPos.fileIndex and n.info.line == gTrackPos.line:
+      requiresCheck = true
+
+template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
+                                    requiresCheck: bool) =
+  # use only for idetools support; this is pretty slow so generics and
+  # templates perform some quick check whether the cursor is actually in
+  # the generic or template.
+  when defined(nimsuggest):
+    assert gCmd == cmdIdeTools
+    if requiresCheck:
+      if optIdeDebug in gGlobalOptions:
+        echo "passing to safeSemExpr: ", renderTree(n)
+      discard safeSemExpr(c, n)
+
+proc typeMismatch(n: PNode, formal, actual: PType) =
+  if formal.kind != tyError and actual.kind != tyError:
     localError(n.info, errGenerated, msgKindToString(errTypeMismatch) &
         typeToString(actual) & ") " &
         `%`(msgKindToString(errButExpectedX), [typeToString(formal)]))
@@ -68,6 +85,10 @@ proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
       # error correction:
       result = copyTree(arg)
       result.typ = formal
+    else:
+      let x = result.skipConv
+      if x.kind == nkPar and formal.kind != tyExpr:
+        changeType(x, formal, check=true)
 
 proc inferWithMetatype(c: PContext, formal: PType,
                        arg: PNode, coerceDistincts = false): PNode
@@ -92,11 +113,20 @@ proc commonType*(x, y: PType): PType =
     else:
       result = newType(tyTypeDesc, a.owner)
       rawAddSon(result, newType(tyNone, a.owner))
-  elif b.kind in {tyArray, tyArrayConstr, tySet, tySequence} and 
+  elif b.kind in {tyArray, tyArrayConstr, tySet, tySequence} and
       a.kind == b.kind:
     # check for seq[empty] vs. seq[int]
     let idx = ord(b.kind in {tyArray, tyArrayConstr})
     if a.sons[idx].kind == tyEmpty: return y
+  elif a.kind == tyTuple and b.kind == tyTuple and a.len == b.len:
+    var nt: PType
+    for i in 0.. <a.len:
+      let aEmpty = isEmptyContainer(a.sons[i])
+      let bEmpty = isEmptyContainer(b.sons[i])
+      if aEmpty != bEmpty:
+        if nt.isNil: nt = copyType(a, a.owner, false)
+        nt.sons[i] = if aEmpty: b.sons[i] else: a.sons[i]
+    if not nt.isNil: result = nt
     #elif b.sons[idx].kind == tyEmpty: return x
   elif a.kind == tyRange and b.kind == tyRange:
     # consider:  (range[0..3], range[0..4]) here. We should make that
@@ -133,7 +163,7 @@ proc commonType*(x, y: PType): PType =
         result = newType(k, r.owner)
         result.addSonSkipIntLit(r)
 
-proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = 
+proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
   result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info)
 
 proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
@@ -152,13 +182,19 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
 proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
                  allowed: TSymFlags): PSym
   # identifier with visability
-proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode, 
+proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
                         allowed: TSymFlags): PSym
 proc semStmtScope(c: PContext, n: PNode): PNode
 
+proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind) =
+  let t = typeAllowed(typ, kind)
+  if t != nil:
+    if t == typ: localError(info, "invalid type: '" & typeToString(typ) & "'")
+    else: localError(info, "invalid type: '" & typeToString(t) &
+                           "' in this context: '" & typeToString(typ) & "'")
+
 proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
-  if not typeAllowed(typ, skConst):
-    localError(typ.n.info, errXisNoType, typeToString(typ))
+  typeAllowedCheck(typ.n.info, typ, skConst)
 
 proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
 proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
@@ -190,7 +226,7 @@ when false:
         result = newSymNode(getSysSym"void")
       else:
         result.typ = makeTypeDesc(c, result.typ)
-    
+
     result.handleIsOperator = proc (n: PNode): PNode =
       result = isOpImpl(c, n)
 
@@ -212,7 +248,7 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
     if result == nil:
       result = arg
       # for 'tcnstseq' we support [] to become 'seq'
-      if eOrig.typ.skipTypes(abstractInst).kind == tySequence and 
+      if eOrig.typ.skipTypes(abstractInst).kind == tySequence and
          arg.typ.skipTypes(abstractInst).kind == tyArrayConstr:
         arg.typ = eOrig.typ
 
@@ -251,6 +287,7 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
     return n
   result = getConstExpr(c.module, e)
   if result == nil:
+    #if e.kind == nkEmpty: globalError(n.info, errConstExprExpected)
     result = evalConstExpr(c.module, e)
     if result == nil or result.kind == nkEmpty:
       if e.info != n.info:
@@ -284,7 +321,7 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
   else:
     case s.typ.sons[0].kind
     of tyExpr:
-      # BUGFIX: we cannot expect a type here, because module aliases would not 
+      # BUGFIX: we cannot expect a type here, because module aliases would not
       # work then (see the ``tmodulealias`` test)
       # semExprWithType(c, result)
       result = semExpr(c, result, flags)
@@ -319,28 +356,22 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
     result = semAfterMacroCall(c, result, sym, flags)
   popInfoContext()
 
-proc forceBool(c: PContext, n: PNode): PNode = 
+proc forceBool(c: PContext, n: PNode): PNode =
   result = fitNode(c, getSysType(tyBool), n)
   if result == nil: result = n
 
-proc semConstBoolExpr(c: PContext, n: PNode): PNode = 
+proc semConstBoolExpr(c: PContext, n: PNode): PNode =
   let nn = semExprWithType(c, n)
   result = fitNode(c, getSysType(tyBool), nn)
   if result == nil:
     localError(n.info, errConstExprExpected)
     return nn
   result = getConstExpr(c.module, result)
-  if result == nil: 
+  if result == nil:
     localError(n.info, errConstExprExpected)
     result = nn
 
-type
-  TSemGenericFlag = enum
-    withinBind, withinTypeDesc, withinMixin
-  TSemGenericFlags = set[TSemGenericFlag]
-
-proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags,
-                    ctx: var IntSet): PNode
+proc semGenericStmt(c: PContext, n: PNode): PNode
 
 include semtypes, semtempl, semgnrc, semstmts, semexprs
 
@@ -367,15 +398,15 @@ proc myOpen(module: PSym): PPassContext =
   c.semInferredLambda = semInferredLambda
   c.semGenerateInstance = generateInstance
   c.semTypeNode = semTypeNode
-  c.instDeepCopy = sigmatch.instDeepCopy
+  c.instTypeBoundOp = sigmatch.instTypeBoundOp
 
   pushProcCon(c, module)
   pushOwner(c.module)
   c.importTable = openScope(c)
   c.importTable.addSym(module) # a module knows itself
-  if sfSystemModule in module.flags: 
+  if sfSystemModule in module.flags:
     magicsys.systemModule = module # set global variable!
-  else: 
+  else:
     c.importTable.addSym magicsys.systemModule # import the "System" identifier
     importAllSymbols(c, magicsys.systemModule)
   c.topLevelScope = openScope(c)
@@ -385,13 +416,13 @@ proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
   result = myOpen(module)
   for m in items(rd.methods): methodDef(m, true)
 
-proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode = 
+proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
   result = semStmt(c, n)
   # BUGFIX: process newly generated generics here, not at the end!
   if c.lastGenericIdx < c.generics.len:
     var a = newNodeI(nkStmtList, n.info)
     addCodeForGenerics(c, a)
-    if sonsLen(a) > 0: 
+    if sonsLen(a) > 0:
       # a generic has been added to `a`:
       if result.kind != nkEmpty: addSon(a, result)
       result = a
@@ -399,17 +430,17 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
   if gCmd == cmdInteractive and not isEmptyType(result.typ):
     result = buildEchoStmt(c, result)
   result = transformStmt(c.module, result)
-    
-proc recoverContext(c: PContext) = 
+
+proc recoverContext(c: PContext) =
   # clean up in case of a semantic error: We clean up the stacks, etc. This is
-  # faster than wrapping every stack operation in a 'try finally' block and 
+  # faster than wrapping every stack operation in a 'try finally' block and
   # requires far less code.
   c.currentScope = c.topLevelScope
   while getCurrOwner().kind != skModule: popOwner()
   while c.p != nil and c.p.owner.kind != skModule: c.p = c.p.next
 
-proc myProcess(context: PPassContext, n: PNode): PNode = 
-  var c = PContext(context)    
+proc myProcess(context: PPassContext, n: PNode): PNode =
+  var c = PContext(context)
   # no need for an expensive 'try' if we stop after the first error anyway:
   if msgs.gErrorMax <= 1:
     result = semStmtAndGenerateGenerics(c, n)
@@ -425,8 +456,8 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
       if getCurrentException() of ESuggestDone: result = nil
       else: result = ast.emptyNode
       #if gCmd == cmdIdeTools: findSuggest(c, n)
-    
-proc myClose(context: PPassContext, n: PNode): PNode = 
+
+proc myClose(context: PPassContext, n: PNode): PNode =
   var c = PContext(context)
   closeScope(c)         # close module's scope
   rawCloseScope(c)      # imported symbols; don't check for unused ones!
diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim
index 483d36bf3..a1e209263 100644
--- a/compiler/semasgn.nim
+++ b/compiler/semasgn.nim
@@ -1,13 +1,14 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
-## This module implements lifting for assignments and ``deepCopy``.
+## This module implements lifting for assignments. Later versions of this code
+## will be able to also lift ``=deepCopy`` and ``=destroy``.
 
 # included from sem.nim
 
@@ -15,98 +16,75 @@ type
   TLiftCtx = object
     c: PContext
     info: TLineInfo # for construction
-    result: PNode
     kind: TTypeAttachedOp
+    fn: PSym
+    asgnForType: PType
+    recurse: bool
 
-type
-  TFieldInstCtx = object  # either 'tup[i]' or 'field' is valid
-    tupleType: PType      # if != nil we're traversing a tuple
-    tupleIndex: int
-    field: PSym
-    replaceByFieldName: bool
+proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode)
+proc liftBody(c: PContext; typ: PType; info: TLineInfo): PSym
+
+proc at(a, i: PNode, elemType: PType): PNode =
+  result = newNodeI(nkBracketExpr, a.info, 2)
+  result.sons[0] = a
+  result.sons[1] = i
+  result.typ = elemType
+
+proc liftBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
+  for i in 0 .. <t.len:
+    let lit = lowerings.newIntLit(i)
+    liftBodyAux(c, t.sons[i], body, x.at(lit, t.sons[i]), y.at(lit, t.sons[i]))
+
+proc dotField(x: PNode, f: PSym): PNode =
+  result = newNodeI(nkDotExpr, x.info, 2)
+  result.sons[0] = x
+  result.sons[1] = newSymNode(f, x.info)
+  result.typ = f.typ
 
-proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
+proc liftBodyObj(c: var TLiftCtx; n, body, x, y: PNode) =
   case n.kind
-  of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n
-  of nkIdent:
-    result = n
-    var L = sonsLen(forLoop)
-    if c.replaceByFieldName:
-      if n.ident.id == forLoop[0].ident.id:
-        let fieldName = if c.tupleType.isNil: c.field.name.s
-                        elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
-                        else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
-        result = newStrNode(nkStrLit, fieldName)
-        return
-    # other fields:
-    for i in ord(c.replaceByFieldName)..L-3:
-      if n.ident.id == forLoop[i].ident.id:
-        var call = forLoop.sons[L-2]
-        var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
-        if c.field.isNil:
-          result = newNodeI(nkBracketExpr, n.info)
-          result.add(tupl)
-          result.add(newIntNode(nkIntLit, c.tupleIndex))
-        else:
-          result = newNodeI(nkDotExpr, n.info)
-          result.add(tupl)
-          result.add(newSymNode(c.field, n.info))
-        break
-  else:
-    if n.kind == nkContinueStmt:
-      localError(n.info, errGenerated,
-                 "'continue' not supported in a 'fields' loop")
-    result = copyNode(n)
-    newSons(result, sonsLen(n))
-    for i in countup(0, sonsLen(n)-1):
-      result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop)
-
-proc liftBodyObj(c: TLiftCtx; typ, x, y: PNode) =
-  case typ.kind
   of nkSym:
-    var fc: TFieldInstCtx  # either 'tup[i]' or 'field' is valid
-    fc.field = typ.sym
-    fc.replaceByFieldName = c.m == mFieldPairs
-    openScope(c.c)
-    inc c.c.inUnrolledContext
-    let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
-    father.add(semStmt(c.c, body))
-    dec c.c.inUnrolledContext
-    closeScope(c.c)
+    let f = n.sym
+    liftBodyAux(c, f.typ, body, x.dotField(f), y.dotField(f))
   of nkNilLit: discard
   of nkRecCase:
-    let L = forLoop.len
-    let call = forLoop.sons[L-2]
-    if call.len > 2:
-      localError(forLoop.info, errGenerated, 
-                 "parallel 'fields' iterator does not work for 'case' objects")
-      return
-    # iterate over the selector:
-    asgnForObjectFields(c, typ[0], forLoop, father)
+    # copy the selector:
+    liftBodyObj(c, n[0], body, x, y)
     # we need to generate a case statement:
     var caseStmt = newNodeI(nkCaseStmt, c.info)
+    # XXX generate 'if' that checks same branches
     # generate selector:
-    var access = newNodeI(nkDotExpr, forLoop.info, 2)
-    access.sons[0] = call.sons[1]
-    access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info)
-    caseStmt.add(semExprWithType(c.c, access))
+    var access = dotField(x, n[0].sym)
+    caseStmt.add(access)
     # copy the branches over, but replace the fields with the for loop body:
-    for i in 1 .. <typ.len:
-      var branch = copyTree(typ[i])
+    for i in 1 .. <n.len:
+      var branch = copyTree(n[i])
       let L = branch.len
-      branch.sons[L-1] = newNodeI(nkStmtList, forLoop.info)
-      semForObjectFields(c, typ[i].lastSon, forLoop, branch[L-1])
+      branch.sons[L-1] = newNodeI(nkStmtList, c.info)
+
+      liftBodyObj(c, n[i].lastSon, branch.sons[L-1], x, y)
       caseStmt.add(branch)
-    father.add(caseStmt)
+    body.add(caseStmt)
+    localError(c.info, "cannot lift assignment operator to 'case' object")
   of nkRecList:
-    for t in items(typ): liftBodyObj(c, t, x, y)
+    for t in items(n): liftBodyObj(c, t, body, x, y)
+  else:
+    illFormedAstLocal(n)
+
+proc genAddr(c: PContext; x: PNode): PNode =
+  if x.kind == nkHiddenDeref:
+    checkSonsLen(x, 1)
+    result = x.sons[0]
   else:
-    illFormedAst(typ)
+    result = newNodeIT(nkHiddenAddr, x.info, makeVarType(c, x.typ))
+    addSon(result, x)
 
-proc newAsgnCall(op: PSym; x, y: PNode): PNode =
+proc newAsgnCall(c: PContext; op: PSym; x, y: PNode): PNode =
+  if sfError in op.flags:
+    localError(x.info, errWrongSymbolX, op.name.s)
   result = newNodeI(nkCall, x.info)
-  result.add(newSymNode(op))
-  result.add x
+  result.add newSymNode(op)
+  result.add genAddr(c, x)
   result.add y
 
 proc newAsgnStmt(le, ri: PNode): PNode =
@@ -117,81 +95,190 @@ proc newAsgnStmt(le, ri: PNode): PNode =
 proc newDestructorCall(op: PSym; x: PNode): PNode =
   result = newNodeIT(nkCall, x.info, op.typ.sons[0])
   result.add(newSymNode(op))
-  result.add x  
+  result.add x
 
 proc newDeepCopyCall(op: PSym; x, y: PNode): PNode =
   result = newAsgnStmt(x, newDestructorCall(op, y))
 
-proc considerOverloadedOp(c: TLiftCtx; t: PType; x, y: PNode): bool =
-  let op = t.attachedOps[c.kind]
-  if op != nil:
-    markUsed(c.info, op)
-    styleCheckUse(c.info, op)
-    case c.kind
-    of attachedDestructor:
-      c.result.add newDestructorCall(op, x)
-    of attachedAsgn:
-      c.result.add newAsgnCall(op, x, y)
-    of attachedDeepCopy:
-      c.result.add newDeepCopyCall(op, x, y)
-    result = true
-
-proc defaultOp(c: TLiftCtx; t: PType; x, y: PNode) =
+proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
+  case c.kind
+  of attachedDestructor:
+    let op = t.destructor
+    if op != nil:
+      markUsed(c.info, op)
+      styleCheckUse(c.info, op)
+      body.add newDestructorCall(op, x)
+      result = true
+  of attachedAsgn:
+    if tfHasAsgn in t.flags:
+      var op: PSym
+      if sameType(t, c.asgnForType):
+        # generate recursive call:
+        if c.recurse:
+          op = c.fn
+        else:
+          c.recurse = true
+          return false
+      else:
+        op = t.assignment
+        if op == nil:
+          op = liftBody(c.c, t, c.info)
+      markUsed(c.info, op)
+      styleCheckUse(c.info, op)
+      body.add newAsgnCall(c.c, op, x, y)
+      result = true
+  of attachedDeepCopy:
+    let op = t.deepCopy
+    if op != nil:
+      markUsed(c.info, op)
+      styleCheckUse(c.info, op)
+      body.add newDeepCopyCall(op, x, y)
+      result = true
+
+proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
   if c.kind != attachedDestructor:
-    c.result.add newAsgnStmt(x, y)
-
-proc liftBodyAux(c: TLiftCtx; t: PType; x, y: PNode) =
-  const hasAttachedOp: array[TTypeAttachedOp, TTypeIter] = [
-    (proc (t: PType, closure: PObject): bool =
-       t.attachedOp[attachedDestructor] != nil),
-    (proc (t: PType, closure: PObject): bool =
-       t.attachedOp[attachedAsgn] != nil),
-    (proc (t: PType, closure: PObject): bool =
-       t.attachedOp[attachedDeepCopy] != nil)]
+    body.add newAsgnStmt(x, y)
+
+proc addVar(father, v, value: PNode) =
+  var vpart = newNodeI(nkIdentDefs, v.info, 3)
+  vpart.sons[0] = v
+  vpart.sons[1] = ast.emptyNode
+  vpart.sons[2] = value
+  addSon(father, vpart)
+
+proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
+  var temp = newSym(skTemp, getIdent(lowerings.genPrefix), c.fn, c.info)
+  temp.typ = getSysType(tyInt)
+  incl(temp.flags, sfFromGeneric)
+
+  var v = newNodeI(nkVarSection, c.info)
+  result = newSymNode(temp)
+  v.addVar(result, lowerings.newIntLit(first))
+  body.add v
+
+proc genBuiltin(magic: TMagic; name: string; i: PNode): PNode =
+  result = newNodeI(nkCall, i.info)
+  result.add createMagic(name, magic).newSymNode
+  result.add i
+
+proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
+  result = newNodeI(nkWhileStmt, c.info, 2)
+  let cmp = genBuiltin(mLeI, "<=", i)
+  cmp.add genHigh(dest)
+  cmp.typ = getSysType(tyBool)
+  result.sons[0] = cmp
+  result.sons[1] = newNodeI(nkStmtList, c.info)
+
+proc addIncStmt(body, i: PNode) =
+  let incCall = genBuiltin(mInc, "inc", i)
+  incCall.add lowerings.newIntLit(1)
+  body.add incCall
+
+proc newSeqCall(c: PContext; x, y: PNode): PNode =
+  # don't call genAddr(c, x) here:
+  result = genBuiltin(mNewSeq, "newSeq", x)
+  let lenCall = genBuiltin(mLengthSeq, "len", y)
+  lenCall.typ = getSysType(tyInt)
+  result.add lenCall
+
+proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
   case t.kind
   of tyNone, tyEmpty: discard
-  of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString:
-    defaultOp(c, t, x, y)
-  of tyPtr, tyString:
-    if not considerOverloadedOp(c, t, x, y):
-      defaultOp(c, t, x, y)
+  of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString,
+      tyPtr, tyString, tyRef:
+    defaultOp(c, t, body, x, y)
   of tyArrayConstr, tyArray, tySequence:
-    if iterOverType(lastSon(t), hasAttachedOp[c.kind], nil):
-      # generate loop and call the attached Op:
-      
+    if tfHasAsgn in t.flags:
+      if t.kind == tySequence:
+        # XXX add 'nil' handling here
+        body.add newSeqCall(c.c, x, y)
+      let i = declareCounter(c, body, firstOrd(t))
+      let whileLoop = genWhileLoop(c, i, x)
+      let elemType = t.lastSon
+      liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType),
+                                                  y.at(i, elemType))
+      addIncStmt(whileLoop.sons[1], i)
+      body.add whileLoop
     else:
-      defaultOp(c, t, x, y)
-  of tyObject:
-    liftBodyObj(c, t.n, x, y)
+      defaultOp(c, t, body, x, y)
+  of tyObject, tyDistinct:
+    if not considerOverloadedOp(c, t, body, x, y):
+      if t.sons[0] != nil: liftBodyAux(c, t.sons[0], body, x, y)
+      if t.kind == tyObject: liftBodyObj(c, t.n, body, x, y)
   of tyTuple:
-    liftBodyTup(c, t, x, y)
-  of tyRef:
-    # we MUST not check for acyclic here as a DAG might still share nodes:
-    
+    liftBodyTup(c, t, body, x, y)
   of tyProc:
     if t.callConv != ccClosure or c.kind != attachedDeepCopy:
-      defaultOp(c, t, x, y)
+      defaultOp(c, t, body, x, y)
     else:
       # a big problem is that we don't know the enviroment's type here, so we
       # have to go through some indirection; we delegate this to the codegen:
-      call = newNodeI(nkCall, n.info, 2)
+      let call = newNodeI(nkCall, c.info, 2)
       call.typ = t
       call.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy))
       call.sons[1] = y
-      c.result.add newAsgnStmt(x, call)
+      body.add newAsgnStmt(x, call)
   of tyVarargs, tyOpenArray:
     localError(c.info, errGenerated, "cannot copy openArray")
   of tyFromExpr, tyIter, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
      tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything,
      tyMutable, tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt,
-     tyTypeDesc, tyGenericInvokation, tyBigNum, tyConst, tyForward:
+     tyTypeDesc, tyGenericInvocation, tyBigNum, tyConst, tyForward:
     internalError(c.info, "assignment requested for type: " & typeToString(t))
-  of tyDistinct, tyOrdinal, tyRange,
+  of tyOrdinal, tyRange,
      tyGenericInst, tyFieldAccessor, tyStatic, tyVar:
-    liftBodyAux(c, lastSon(t))
+    liftBodyAux(c, lastSon(t), body, x, y)
+
+proc newProcType(info: TLineInfo; owner: PSym): PType =
+  result = newType(tyProc, owner)
+  result.n = newNodeI(nkFormalParams, info)
+  rawAddSon(result, nil) # return type
+  # result.n[0] used to be `nkType`, but now it's `nkEffectList` because
+  # the effects are now stored in there too ... this is a bit hacky, but as
+  # usual we desperately try to save memory:
+  addSon(result.n, newNodeI(nkEffectList, info))
+
+proc addParam(procType: PType; param: PSym) =
+  param.position = procType.len-1
+  addSon(procType.n, newSymNode(param))
+  rawAddSon(procType, param.typ)
 
-proc liftBody(c: PContext; typ: PType; info: TLineInfo): PNode =
+proc liftBody(c: PContext; typ: PType; info: TLineInfo): PSym =
   var a: TLiftCtx
   a.info = info
-  a.result = newNodeI(nkStmtList, info)
-  liftBodyAux(a, typ)
+  let body = newNodeI(nkStmtList, info)
+  result = newSym(skProc, getIdent":lifted=", typ.owner, info)
+  a.fn = result
+  a.asgnForType = typ
+
+  let dest = newSym(skParam, getIdent"dest", result, info)
+  let src = newSym(skParam, getIdent"src", result, info)
+  dest.typ = makeVarType(c, typ)
+  src.typ = typ
+
+  result.typ = newProcType(info, typ.owner)
+  result.typ.addParam dest
+  result.typ.addParam src
+
+  liftBodyAux(a, typ, body, newSymNode(dest).newDeref, newSymNode(src))
+
+  var n = newNodeI(nkProcDef, info, bodyPos+1)
+  for i in 0 .. < n.len: n.sons[i] = emptyNode
+  n.sons[namePos] = newSymNode(result)
+  n.sons[paramsPos] = result.typ.n
+  n.sons[bodyPos] = body
+  result.ast = n
+
+  # register late as recursion is handled differently
+  typ.assignment = result
+  #echo "Produced this ", n
+
+proc getAsgnOrLiftBody(c: PContext; typ: PType; info: TLineInfo): PSym =
+  let t = typ.skipTypes({tyGenericInst, tyVar})
+  result = t.assignment
+  if result.isNil:
+    result = liftBody(c, t, info)
+
+proc overloadedAsgn(c: PContext; dest, src: PNode): PNode =
+  let a = getAsgnOrLiftBody(c, dest.typ, dest.info)
+  result = newAsgnCall(c, a, dest, src)
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 3971b8ff5..c48e761e3 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -7,16 +7,16 @@
 #    distribution, for details about the copyright.
 #
 
-## This module implements semantic checking for calls. 
+## This module implements semantic checking for calls.
 # included from sem.nim
 
 proc sameMethodDispatcher(a, b: PSym): bool =
   result = false
-  if a.kind == skMethod and b.kind == skMethod: 
+  if a.kind == skMethod and b.kind == skMethod:
     var aa = lastSon(a.ast)
     var bb = lastSon(b.ast)
     if aa.kind == nkSym and bb.kind == nkSym:
-      if aa.sym == bb.sym: 
+      if aa.sym == bb.sym:
         result = true
     else:
       discard
@@ -31,7 +31,7 @@ proc sameMethodDispatcher(a, b: PSym): bool =
       # to avoid subtle problems, the call remains ambiguous and needs to
       # be disambiguated by the programmer; this way the right generic is
       # instantiated.
-  
+
 proc determineType(c: PContext, s: PSym)
 
 proc pickBestCandidate(c: PContext, headSymbol: PNode,
@@ -41,62 +41,80 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
                        best, alt: var TCandidate,
                        errors: var CandidateErrors) =
   var o: TOverloadIter
-  var sym = initOverloadIter(o, c, headSymbol)
-  var symScope = o.lastOverloadScope
+  # thanks to the lazy semchecking for operands, we need to iterate over the
+  # symbol table *before* any call to 'initCandidate' which might invoke
+  # semExpr which might modify the symbol table in cases like
+  # 'init(a, 1, (var b = new(Type2); b))'.
+  var symx = initOverloadIter(o, c, headSymbol)
+  let symScope = o.lastOverloadScope
+
+  var syms: seq[tuple[a: PSym, b: int]] = @[]
+  while symx != nil:
+    if symx.kind in filter: syms.add((symx, o.lastOverloadScope))
+    symx = nextOverloadIter(o, c, headSymbol)
+  if syms.len == 0: return
 
   var z: TCandidate
-  
-  if sym == nil: return
-  initCandidate(c, best, sym, initialBinding, symScope)
-  initCandidate(c, alt, sym, initialBinding, symScope)
+  initCandidate(c, best, syms[0][0], initialBinding, symScope)
+  initCandidate(c, alt, syms[0][0], initialBinding, symScope)
   best.state = csNoMatch
-  
-  while sym != nil:
-    if sym.kind in filter:
-      determineType(c, sym)
-      initCandidate(c, z, sym, initialBinding, o.lastOverloadScope)
-      z.calleeSym = sym
-      matches(c, n, orig, z)
-      if errors != nil:
-        errors.safeAdd(sym)
-        if z.errors != nil:
-          for err in z.errors:
-            errors.add(err)
-      if z.state == csMatch:
-        # little hack so that iterators are preferred over everything else:
-        if sym.kind in skIterators: inc(z.exactMatches, 200)
-        case best.state
-        of csEmpty, csNoMatch: best = z
-        of csMatch:
-          var cmp = cmpCandidates(best, z)
-          if cmp < 0: best = z   # x is better than the best so far
-          elif cmp == 0: alt = z # x is as good as the best so far
-          else: discard
-    sym = nextOverloadIter(o, c, headSymbol)
+
+  for i in 0 .. <syms.len:
+    let sym = syms[i][0]
+    determineType(c, sym)
+    initCandidate(c, z, sym, initialBinding, syms[i][1])
+    z.calleeSym = sym
+
+    #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
+    #  gDebug = true
+    matches(c, n, orig, z)
+    if errors != nil:
+      errors.safeAdd(sym)
+      if z.errors != nil:
+        for err in z.errors:
+          errors.add(err)
+    if z.state == csMatch:
+      # little hack so that iterators are preferred over everything else:
+      if sym.kind in skIterators: inc(z.exactMatches, 200)
+      case best.state
+      of csEmpty, csNoMatch: best = z
+      of csMatch:
+        var cmp = cmpCandidates(best, z)
+        if cmp < 0: best = z   # x is better than the best so far
+        elif cmp == 0: alt = z # x is as good as the best so far
+        else: discard
+      #if sym.name.s == "cmp" and (n.info ?? "rstgen.nim") and n.info.line == 516:
+      #  echo "Matches ", n.info, " ", typeToString(sym.typ)
+      #  debug sym
+      #  writeMatches(z)
+      #  for i in 1 .. <len(z.call):
+      #    z.call[i].typ.debug
+      #  quit 1
 
 proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
   # Gives a detailed error message; this is separated from semOverloadedCall,
   # as semOverlodedCall is already pretty slow (and we need this information
   # only in case of an error).
-  if c.inCompilesContext > 0: 
+  if c.inCompilesContext > 0:
     # fail fast:
     globalError(n.info, errTypeMismatch, "")
-  if errors.len == 0:
+  if errors.isNil or errors.len == 0:
     localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
+    return
 
-  # to avoid confusing errors like: 
+  # to avoid confusing errors like:
   #   got (SslPtr, SocketHandle)
-  #   but expected one of: 
+  #   but expected one of:
   #   openssl.SSL_set_fd(ssl: SslPtr, fd: SocketHandle): cint
   # we do a pre-analysis. If all types produce the same string, we will add
   # module information.
   let proto = describeArgs(c, n, 1, preferName)
-  
+
   var prefer = preferName
   for err in errors:
     var errProto = ""
     let n = err.typ.n
-    for i in countup(1, n.len - 1): 
+    for i in countup(1, n.len - 1):
       var p = n.sons[i]
       if p.kind == nkSym:
         add(errProto, typeToString(p.sym.typ, preferName))
@@ -123,7 +141,8 @@ proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) =
       for s in scope.usingSyms: usedSyms.safeAdd(s)
 
 proc resolveOverloads(c: PContext, n, orig: PNode,
-                      filter: TSymKinds): TCandidate =
+                      filter: TSymKinds;
+                      errors: var CandidateErrors): TCandidate =
   var initialBinding: PNode
   var alt: TCandidate
   var f = n.sons[0]
@@ -134,7 +153,6 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
   else:
     initialBinding = nil
 
-  var errors: CandidateErrors
   var usedSyms: seq[PNode]
 
   template pickBest(headSymbol: expr) =
@@ -148,9 +166,9 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
 
     n.sons.insert(hiddenArg, 1)
     orig.sons.insert(hiddenArg, 1)
-    
+
     pickBest(f)
- 
+
     if result.state != csMatch:
       n.sons.delete(1)
       orig.sons.delete(1)
@@ -168,7 +186,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
       # we are going to try multiple variants
       n.sons[0..1] = [nil, n[1], calleeName]
       orig.sons[0..1] = [nil, orig[1], calleeName]
-      
+
       template tryOp(x) =
         let op = newIdentNode(getIdent(x), n.info)
         n.sons[0] = op
@@ -177,18 +195,19 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
 
       if nfExplicitCall in n.flags:
         tryOp ".()"
-   
+
       if result.state in {csEmpty, csNoMatch}:
         tryOp "."
 
     elif nfDotSetter in n.flags:
       internalAssert f.kind == nkIdent and n.sonsLen == 3
-      let calleeName = newStrNode(nkStrLit, f.ident.s[0.. -2]).withInfo(n.info)
+      let calleeName = newStrNode(nkStrLit,
+        f.ident.s[0..f.ident.s.len-2]).withInfo(n.info)
       let callOp = newIdentNode(getIdent".=", n.info)
       n.sons[0..1] = [callOp, n[1], calleeName]
       orig.sons[0..1] = [callOp, orig[1], calleeName]
       pickBest(callOp)
-   
+
     if overloadsState == csEmpty and result.state == csEmpty:
       localError(n.info, errUndeclaredIdentifier, considerQuotedIdent(f).s)
       return
@@ -204,7 +223,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
 
         errors = @[]
         pickBest(f)
-        notFoundError(c, n, errors)
+        #notFoundError(c, n, errors)
 
       return
 
@@ -213,7 +232,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
     internalAssert result.state == csMatch
     #writeMatches(result)
     #writeMatches(alt)
-    if c.inCompilesContext > 0: 
+    if c.inCompilesContext > 0:
       # quick error message for performance of 'compiles' built-in:
       globalError(n.info, errGenerated, "ambiguous call")
     elif gErrorCounter == 0:
@@ -243,7 +262,7 @@ proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
     for i in 1 .. <n.len:
       instGenericConvertersArg(c, n.sons[i], x)
 
-proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode = 
+proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
   var m: TCandidate
   initCandidate(c, m, f)
   result = paramTypesMatch(m, f, a, arg, nil)
@@ -260,7 +279,7 @@ proc inferWithMetatype(c: PContext, formal: PType,
     instGenericConvertersArg(c, result, m)
   if result != nil:
     # This almost exactly replicates the steps taken by the compiler during
-    # param matching. It performs an embarassing ammount of back-and-forth
+    # param matching. It performs an embarrassing amount of back-and-forth
     # type jugling, but it's the price to pay for consistency and correctness
     result.typ = generateTypeInstance(c, m.bindings, arg.info,
                                       formal.skipTypes({tyCompositeTypeClass}))
@@ -277,27 +296,47 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
   styleCheckUse(n.sons[0].info, finalCallee)
   if finalCallee.ast == nil:
     internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
+  if x.hasFauxMatch:
+    result = x.call
+    result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
+    if containsGenericType(result.typ) or x.fauxMatch == tyUnknown:
+      result.typ = newTypeS(x.fauxMatch, c)
+    return
   if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty:
-    # a generic proc!
-    if not x.proxyMatch:
-      finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
-    else:
-      result = x.call
-      result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
-      result.typ = finalCallee.typ.sons[0]
-      if containsGenericType(result.typ): result.typ = errorType(c)
-      return
+    finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
   result = x.call
   instGenericConvertersSons(c, result, x)
   result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
   result.typ = finalCallee.typ.sons[0]
 
+proc canDeref(n: PNode): bool {.inline.} =
+  result = n.len >= 2 and (let t = n[1].typ;
+    t != nil and t.skipTypes({tyGenericInst}).kind in {tyPtr, tyRef})
+
+proc tryDeref(n: PNode): PNode =
+  result = newNodeI(nkHiddenDeref, n.info)
+  result.typ = n.typ.skipTypes(abstractInst).sons[0]
+  result.addSon(n)
+
 proc semOverloadedCall(c: PContext, n, nOrig: PNode,
                        filter: TSymKinds): PNode =
-  var r = resolveOverloads(c, n, nOrig, filter)
+  var errors: CandidateErrors
+
+  var r = resolveOverloads(c, n, nOrig, filter, errors)
   if r.state == csMatch: result = semResolvedCall(c, n, r)
+  elif experimentalMode(c) and canDeref(n):
+    # try to deref the first argument and then try overloading resolution again:
+    n.sons[1] = n.sons[1].tryDeref
+    var r = resolveOverloads(c, n, nOrig, filter, errors)
+    if r.state == csMatch: result = semResolvedCall(c, n, r)
+    else:
+      # get rid of the deref again for a better error message:
+      n.sons[1] = n.sons[1].sons[0]
+      notFoundError(c, n, errors)
+  else:
+    notFoundError(c, n, errors)
   # else: result = errorNode(c, n)
-    
+
 proc explicitGenericInstError(n: PNode): PNode =
   localError(n.info, errCannotInstantiateX, renderTree(n))
   result = n
@@ -310,7 +349,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
   styleCheckUse(n.info, s)
   result = newSymNode(newInst, n.info)
 
-proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = 
+proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
   assert n.kind == nkBracketExpr
   for i in 1..sonsLen(n)-1:
     n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
@@ -330,11 +369,11 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
     # XXX I think this could be improved by reusing sigmatch.paramTypesMatch.
     # It's good enough for now.
     result = newNodeI(a.kind, n.info)
-    for i in countup(0, len(a)-1): 
+    for i in countup(0, len(a)-1):
       var candidate = a.sons[i].sym
       if candidate.kind in {skProc, skMethod, skConverter,
                             skIterator, skClosureIterator}:
-        # it suffices that the candidate has the proper number of generic 
+        # it suffices that the candidate has the proper number of generic
         # type parameters:
         if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
           result.add(explicitGenericSym(c, n, candidate))
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index f876770c0..345a8c0d1 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -9,13 +9,13 @@
 
 ## This module contains the data structures for the semantic checking phase.
 
-import 
+import
   strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab,
-  wordrecg, 
-  ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, 
+  wordrecg,
+  ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
   magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef
 
-type 
+type
   TOptionEntry* = object of lists.TListEntry # entries to put on a
                                              # stack for pragma parsing
     options*: TOptions
@@ -26,7 +26,7 @@ type
 
   POptionEntry* = ref TOptionEntry
   PProcCon* = ref TProcCon
-  TProcCon*{.final.} = object # procedure context; also used for top-level
+  TProcCon* = object          # procedure context; also used for top-level
                               # statements
     owner*: PSym              # the symbol this context belongs to
     resultSym*: PSym          # the result symbol (if we are in a proc)
@@ -35,16 +35,24 @@ type
     inTryStmt*: int           # whether we are in a try statement; works also
                               # in standalone ``except`` and ``finally``
     next*: PProcCon           # used for stacking procedure contexts
-  
+    wasForwarded*: bool       # whether the current proc has a separate header
+    bracketExpr*: PNode       # current bracket expression (for ^ support)
+
   TInstantiationPair* = object
     genericSym*: PSym
     inst*: PInstantiation
 
-  TExprFlag* = enum 
-    efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType,
+  TExprFlag* = enum
+    efLValue, efWantIterator, efInTypeof,
+    efWantStmt, efAllowStmt, efDetermineType,
     efAllowDestructor, efWantValue, efOperand, efNoSemCheck
   TExprFlags* = set[TExprFlag]
 
+  TTypeAttachedOp* = enum
+    attachedAsgn,
+    attachedDeepCopy,
+    attachedDestructor
+
   PContext* = ref TContext
   TContext* = object of TPassContext # a context represents a module
     module*: PSym              # the module sym belonging to the context
@@ -56,7 +64,7 @@ type
                                # this is used so that generic instantiations
                                # can access private object fields
     instCounter*: int          # to prevent endless instantiations
-   
+
     ambiguousSymbols*: IntSet  # ids of all ambiguous symbols (cannot
                                # store this info in the syms themselves!)
     inTypeClass*: int          # > 0 if we are in a user-defined type class
@@ -91,10 +99,10 @@ type
     lastGenericIdx*: int      # used for the generics stack
     hloLoopDetector*: int     # used to prevent endless loops in the HLO
     inParallelStmt*: int
-    instDeepCopy*: proc (c: PContext; dc: PSym; t: PType;
-                         info: TLineInfo): PSym {.nimcall.}
+    instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo;
+                            op: TTypeAttachedOp): PSym {.nimcall.}
+
 
-   
 proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
   result.genericSym = s
   result.inst = inst
@@ -110,7 +118,6 @@ proc newOptionEntry*(): POptionEntry
 proc newLib*(kind: TLibKind): PLib
 proc addToLib*(lib: PLib, sym: PSym)
 proc makePtrType*(c: PContext, baseType: PType): PType
-proc makeVarType*(c: PContext, baseType: PType): PType
 proc newTypeS*(kind: TTypeKind, c: PContext): PType
 proc fillTypeS*(dest: PType, kind: TTypeKind, c: PContext)
 
@@ -126,7 +133,7 @@ proc popOwner*()
 
 var gOwners*: seq[PSym] = @[]
 
-proc getCurrOwner(): PSym = 
+proc getCurrOwner(): PSym =
   # owner stack (used for initializing the
   # owner field of syms)
   # the documentation comment always gets
@@ -134,19 +141,19 @@ proc getCurrOwner(): PSym =
   # BUGFIX: global array is needed!
   result = gOwners[high(gOwners)]
 
-proc pushOwner(owner: PSym) = 
+proc pushOwner(owner: PSym) =
   add(gOwners, owner)
 
-proc popOwner() = 
+proc popOwner() =
   var length = len(gOwners)
   if length > 0: setLen(gOwners, length - 1)
   else: internalError("popOwner")
 
-proc lastOptionEntry(c: PContext): POptionEntry = 
+proc lastOptionEntry(c: PContext): POptionEntry =
   result = POptionEntry(c.optionStack.tail)
 
-proc pushProcCon*(c: PContext, owner: PSym) {.inline.} = 
-  if owner == nil: 
+proc pushProcCon*(c: PContext, owner: PSym) {.inline.} =
+  if owner == nil:
     internalError("owner is nil")
     return
   var x: PProcCon
@@ -157,7 +164,7 @@ proc pushProcCon*(c: PContext, owner: PSym) {.inline.} =
 
 proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
 
-proc newOptionEntry(): POptionEntry = 
+proc newOptionEntry(): POptionEntry =
   new(result)
   result.options = gOptions
   result.defaultCC = ccDefault
@@ -181,8 +188,8 @@ proc newContext(module: PSym): PContext =
 
 proc inclSym(sq: var TSymSeq, s: PSym) =
   var L = len(sq)
-  for i in countup(0, L - 1): 
-    if sq[i].id == s.id: return 
+  for i in countup(0, L - 1):
+    if sq[i].id == s.id: return
   setLen(sq, L + 1)
   sq[L] = s
 
@@ -192,22 +199,25 @@ proc addConverter*(c: PContext, conv: PSym) =
 proc addPattern*(c: PContext, p: PSym) =
   inclSym(c.patterns, p)
 
-proc newLib(kind: TLibKind): PLib = 
+proc newLib(kind: TLibKind): PLib =
   new(result)
   result.kind = kind          #initObjectSet(result.syms)
-  
+
 proc addToLib(lib: PLib, sym: PSym) =
   #if sym.annex != nil and not isGenericRoutine(sym):
   #  LocalError(sym.info, errInvalidPragma)
   sym.annex = lib
 
-proc makePtrType(c: PContext, baseType: PType): PType = 
+proc makePtrType(c: PContext, baseType: PType): PType =
   result = newTypeS(tyPtr, c)
   addSonSkipIntLit(result, baseType.assertNotNil)
 
-proc makeVarType(c: PContext, baseType: PType): PType = 
-  result = newTypeS(tyVar, c)
-  addSonSkipIntLit(result, baseType.assertNotNil)
+proc makeVarType*(c: PContext, baseType: PType): PType =
+  if baseType.kind == tyVar:
+    result = baseType
+  else:
+    result = newTypeS(tyVar, c)
+    addSonSkipIntLit(result, baseType.assertNotNil)
 
 proc makeTypeDesc*(c: PContext, typ: PType): PType =
   result = newTypeS(tyTypeDesc, c)
@@ -220,6 +230,7 @@ proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
 
 proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
   result = newTypeS(tyFromExpr, c)
+  assert n != nil
   result.n = n
 
 proc newTypeWithSons*(c: PContext, kind: TTypeKind,
@@ -238,6 +249,7 @@ proc makeAndType*(c: PContext, t1, t2: PType): PType =
   propagateToOwner(result, t1)
   propagateToOwner(result, t2)
   result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
+  result.flags.incl tfHasMeta
 
 proc makeOrType*(c: PContext, t1, t2: PType): PType =
   result = newTypeS(tyOr, c)
@@ -245,12 +257,14 @@ proc makeOrType*(c: PContext, t1, t2: PType): PType =
   propagateToOwner(result, t1)
   propagateToOwner(result, t2)
   result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
+  result.flags.incl tfHasMeta
 
 proc makeNotType*(c: PContext, t1: PType): PType =
   result = newTypeS(tyNot, c)
   result.sons = @[t1]
   propagateToOwner(result, t1)
   result.flags.incl(t1.flags * {tfHasStatic})
+  result.flags.incl tfHasMeta
 
 proc nMinusOne*(n: PNode): PNode =
   result = newNode(nkCall, n.info, @[
@@ -268,7 +282,7 @@ proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
 
 template rangeHasStaticIf*(t: PType): bool =
   # this accepts the ranges's node
-  t.n[1].kind == nkStaticExpr
+  t.n != nil and t.n.len > 1 and t.n[1].kind == nkStaticExpr
 
 template getStaticTypeFromRange*(t: PType): PType =
   t.n[1][0][1].typ
@@ -284,7 +298,7 @@ proc errorNode*(c: PContext, n: PNode): PNode =
   result = newNodeI(nkEmpty, n.info)
   result.typ = errorType(c)
 
-proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) = 
+proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) =
   dest.kind = kind
   dest.owner = getCurrOwner()
   dest.size = - 1
@@ -306,13 +320,16 @@ proc markIndirect*(c: PContext, s: PSym) {.inline.} =
 proc illFormedAst*(n: PNode) =
   globalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
 
-proc checkSonsLen*(n: PNode, length: int) = 
+proc illFormedAstLocal*(n: PNode) =
+  localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
+
+proc checkSonsLen*(n: PNode, length: int) =
   if sonsLen(n) != length: illFormedAst(n)
-  
-proc checkMinSonsLen*(n: PNode, length: int) = 
+
+proc checkMinSonsLen*(n: PNode, length: int) =
   if sonsLen(n) < length: illFormedAst(n)
 
-proc isTopLevel*(c: PContext): bool {.inline.} = 
+proc isTopLevel*(c: PContext): bool {.inline.} =
   result = c.currentScope.depthLevel <= 2
 
 proc experimentalMode*(c: PContext): bool {.inline.} =
diff --git a/compiler/semdestruct.nim b/compiler/semdestruct.nim
index 4ce610bf9..aaab49a10 100644
--- a/compiler/semdestruct.nim
+++ b/compiler/semdestruct.nim
@@ -12,7 +12,7 @@
 # included from sem.nim
 
 # special marker values that indicates that we are
-# 1) AnalyzingDestructor: currently analyzing the type for destructor 
+# 1) AnalyzingDestructor: currently analyzing the type for destructor
 # generation (needed for recursive types)
 # 2) DestructorIsTrivial: completed the analysis before and determined
 # that the type has a trivial destructor
@@ -30,7 +30,7 @@ proc instantiateDestructor(c: PContext, typ: PType): PType
 
 proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
   var t = s.typ.sons[1].skipTypes({tyVar})
-  if t.kind == tyGenericInvokation:
+  if t.kind == tyGenericInvocation:
     for i in 1 .. <t.sonsLen:
       if t.sons[i].kind != tyGenericParam:
         localError(n.info, errDestructorNotGenericEnough)
@@ -41,7 +41,7 @@ proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
     if t.kind != tyGenericBody:
       localError(n.info, errDestructorNotGenericEnough)
       return
-  
+
   t.destructor = s
   # automatically insert calls to base classes' destructors
   if n.sons[bodyPos].kind != nkEmpty:
@@ -71,17 +71,18 @@ proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
   result.addSon(newNode(nkDotExpr, n.info, @[holder, n.sons[0]]))
   for i in countup(1, n.len - 1):
     # of A, B:
-    var caseBranch = newNode(n[i].kind, n[i].info, n[i].sons[0 .. -2])
-    
-    let stmt = destroyFieldOrFields(c, n[i].lastSon, holder)
+    let ni = n[i]
+    var caseBranch = newNode(ni.kind, ni.info, ni.sons[0..ni.len-2])
+
+    let stmt = destroyFieldOrFields(c, ni.lastSon, holder)
     if stmt == nil:
-      caseBranch.addSon(newNode(nkStmtList, n[i].info, @[]))
+      caseBranch.addSon(newNode(nkStmtList, ni.info, @[]))
     else:
       caseBranch.addSon(stmt)
       nonTrivialFields += stmt.len
-    
+
     result.addSon(caseBranch)
-  
+
   # maybe no fields were destroyed?
   if nonTrivialFields == 0:
     result = nil
@@ -107,7 +108,7 @@ proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode =
 proc generateDestructor(c: PContext, t: PType): PNode =
   ## generate a destructor for a user-defined object or tuple type
   ## returns nil if the destructor turns out to be trivial
-  
+
   # XXX: This may be true for some C-imported types such as
   # Tposix_spawnattr
   if t.n == nil or t.n.sons == nil: return
@@ -120,13 +121,13 @@ proc generateDestructor(c: PContext, t: PType): PNode =
 
 proc instantiateDestructor(c: PContext, typ: PType): PType =
   # returns nil if a variable of type `typ` doesn't require a
-  # destructor. Otherwise, returns the type, which holds the 
+  # destructor. Otherwise, returns the type, which holds the
   # destructor that must be used for the varialbe.
   # The destructor is either user-defined or automatically
   # generated by the compiler in a member-wise fashion.
   var t = skipTypes(typ, {tyConst, tyMutable}).skipGenericAlias
   let typeHoldingUserDefinition = if t.kind == tyGenericInst: t.base else: t
-  
+
   if typeHoldingUserDefinition.destructor != nil:
     # XXX: This is not entirely correct for recursive types, but we need
     # it temporarily to hide the "destroy is already defined" problem
@@ -135,7 +136,7 @@ proc instantiateDestructor(c: PContext, typ: PType): PType =
       return typeHoldingUserDefinition
     else:
       return nil
-  
+
   t = t.skipTypes({tyGenericInst})
   case t.kind
   of tySequence, tyArray, tyArrayConstr, tyOpenArray, tyVarargs:
@@ -200,16 +201,16 @@ proc insertDestructors(c: PContext,
       varId = varSection[j][0]
       varTyp = varId.sym.typ
       info = varId.info
-    
+
     if varTyp == nil or sfGlobal in varId.sym.flags: continue
     let destructableT = instantiateDestructor(c, varTyp)
-    
+
     if destructableT != nil:
       var tryStmt = newNodeI(nkTryStmt, info)
 
       if j < totalVars - 1:
         var remainingVars = newNodeI(varSection.kind, info)
-        remainingVars.sons = varSection.sons[(j+1)..(-1)]
+        remainingVars.sons = varSection.sons[(j+1)..varSection.len-1]
         let (outer, inner) = insertDestructors(c, remainingVars)
         if outer != nil:
           tryStmt.addSon(outer)
@@ -221,7 +222,7 @@ proc insertDestructors(c: PContext,
       else:
         result.inner = newNodeI(nkStmtList, info)
         tryStmt.addSon(result.inner)
-    
+
       tryStmt.addSon(
         newNode(nkFinally, info, @[
           semStmt(c, newNode(nkCall, info, @[
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index ac82e9fed..eb8d0c561 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -24,29 +24,29 @@ proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
 proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   # same as 'semExprWithType' but doesn't check for proc vars
   result = semExpr(c, n, flags + {efOperand})
-  if result.kind == nkEmpty: 
+  if result.kind == nkEmpty:
     # do not produce another redundant error message:
     #raiseRecoverableError("")
     result = errorNode(c, n)
   if result.typ != nil:
     # XXX tyGenericInst here?
     if result.typ.kind == tyVar: result = newDeref(result)
-  elif efWantStmt in flags:
+  elif {efWantStmt, efAllowStmt} * flags != {}:
     result.typ = newTypeS(tyEmpty, c)
   else:
-    localError(n.info, errExprXHasNoType, 
+    localError(n.info, errExprXHasNoType,
                renderTree(result, {renderNoComments}))
     result.typ = errorType(c)
 
 proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   result = semExpr(c, n, flags+{efWantValue})
-  if result.isNil or result.kind == nkEmpty: 
+  if result.isNil or result.kind == nkEmpty:
     # do not produce another redundant error message:
     #raiseRecoverableError("")
     result = errorNode(c, n)
   if result.typ == nil or result.typ == enforceVoidContext:
     # we cannot check for 'void' in macros ...
-    localError(n.info, errExprXHasNoType, 
+    localError(n.info, errExprXHasNoType,
                renderTree(result, {renderNoComments}))
     result.typ = errorType(c)
   else:
@@ -61,7 +61,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     # do not produce another redundant error message:
     result = errorNode(c, n)
   if result.typ == nil:
-    localError(n.info, errExprXHasNoType, 
+    localError(n.info, errExprXHasNoType,
                renderTree(result, {renderNoComments}))
     result.typ = errorType(c)
   else:
@@ -70,19 +70,19 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
 
 proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
   result = symChoice(c, n, s, scClosed)
-  
+
 proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
   result = copyTree(s.ast)
   result.typ = s.typ
   result.info = n.info
-  
-proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = 
+
+proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   case s.kind
   of skConst:
     markUsed(n.info, s)
     styleCheckUse(n.info, s)
     case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
-    of  tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, 
+    of  tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
         tyTuple, tySet, tyUInt..tyUInt64:
       if s.magic == mNone: result = inlineConst(n, s)
       else: result = newSymNode(s, n.info)
@@ -103,15 +103,31 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
       result = newSymNode(s, n.info)
   of skMacro: result = semMacroExpr(c, n, n, s, flags)
   of skTemplate: result = semTemplateExpr(c, n, s, flags)
-  of skVar, skLet, skResult, skParam, skForVar:
+  of skParam:
+    markUsed(n.info, s)
+    styleCheckUse(n.info, s)
+    if s.typ.kind == tyStatic and s.typ.n != nil:
+      # XXX see the hack in sigmatch.nim ...
+      return s.typ.n
+    elif sfGenSym in s.flags:
+      if c.p.wasForwarded:
+        # gensym'ed parameters that nevertheless have been forward declared
+        # need a special fixup:
+        let realParam = c.p.owner.typ.n[s.position+1]
+        internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam
+        return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info)
+      elif c.p.owner.kind == skMacro:
+        # gensym'ed macro parameters need a similar hack (see bug #1944):
+        var u = searchInScopes(c, s.name)
+        internalAssert u != nil and u.kind == skParam and u.owner == s.owner
+        return newSymNode(u, n.info)
+    result = newSymNode(s, n.info)
+  of skVar, skLet, skResult, skForVar:
     markUsed(n.info, s)
     styleCheckUse(n.info, s)
     # if a proc accesses a global variable, it is not side effect free:
     if sfGlobal in s.flags:
       incl(c.p.owner.flags, sfSideEffect)
-    elif s.kind == skParam and s.typ.kind == tyStatic and s.typ.n != nil:
-      # XXX see the hack in sigmatch.nim ...
-      return s.typ.n
     result = newSymNode(s, n.info)
     # We cannot check for access to outer vars for example because it's still
     # not sure the symbol really ends up being used:
@@ -151,7 +167,7 @@ proc checkConversionBetweenObjects(castDest, src: PType): TConvStatus =
     else:
       convOK
 
-const 
+const
   IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyUInt64}
 
 proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
@@ -185,10 +201,10 @@ proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
 
 proc isCastable(dst, src: PType): bool =
   ## Checks whether the source type can be casted to the destination type.
-  ## Casting is very unrestrictive; casts are allowed as long as 
+  ## Casting is very unrestrictive; casts are allowed as long as
   ## castDest.size >= src.size, and typeAllowed(dst, skParam)
   #const
-  #  castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString, 
+  #  castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString,
   #                       tySequence, tyPointer, tyNil, tyOpenArray,
   #                       tyProc, tySet, tyEnum, tyBool, tyChar}
   if skipTypes(dst, abstractInst-{tyOpenArray}).kind == tyOpenArray:
@@ -197,19 +213,19 @@ proc isCastable(dst, src: PType): bool =
 
   dstSize = computeSize(dst)
   srcSize = computeSize(src)
-  if dstSize < 0: 
+  if dstSize < 0:
     result = false
   elif srcSize < 0:
     result = false
-  elif not typeAllowed(dst, skParam):
+  elif typeAllowed(dst, skParam) != nil:
     result = false
-  else: 
+  else:
     result = (dstSize >= srcSize) or
         (skipTypes(dst, abstractInst).kind in IntegralTypes) or
         (skipTypes(src, abstractInst-{tyTypeDesc}).kind in IntegralTypes)
   if result and src.kind == tyNil:
     result = dst.size <= platform.ptrSize
-  
+
 proc isSymChoice(n: PNode): bool {.inline.} =
   result = n.kind in nkSymChoices
 
@@ -219,7 +235,7 @@ proc maybeLiftType(t: var PType, c: PContext, info: TLineInfo) =
   # gnrc. params, then it won't be necessary to open a new scope here
   openScope(c)
   var lifted = liftParamType(c, skType, newNodeI(nkArgList, info),
-                         t, ":anon", info)
+                             t, ":anon", info)
   closeScope(c)
   if lifted != nil: t = lifted
 
@@ -229,11 +245,11 @@ proc semConv(c: PContext, n: PNode): PNode =
     return n
 
   result = newNodeI(nkConv, n.info)
-  var targetType = semTypeNode(c, n.sons[0], nil)
+  var targetType = semTypeNode(c, n.sons[0], nil).skipTypes({tyTypeDesc})
   maybeLiftType(targetType, c, n[0].info)
   result.addSon copyTree(n.sons[0])
   var op = semExprWithType(c, n.sons[1])
-  
+
   if targetType.isMetaType:
     let final = inferWithMetatype(c, targetType, op, true)
     result.addSon final
@@ -242,7 +258,7 @@ proc semConv(c: PContext, n: PNode): PNode =
 
   result.typ = targetType
   addSon(result, op)
-  
+
   if not isSymChoice(op):
     let status = checkConvertible(c, result.typ, op.typ)
     case status
@@ -270,7 +286,7 @@ proc semConv(c: PContext, n: PNode): PNode =
         return it
     localError(n.info, errUseQualifier, op.sons[0].sym.name.s)
 
-proc semCast(c: PContext, n: PNode): PNode = 
+proc semCast(c: PContext, n: PNode): PNode =
   ## Semantically analyze a casting ("cast[type](param)")
   if optSafeCode in gGlobalOptions: localError(n.info, errCastNotInSafeMode)
   #incl(c.p.owner.flags, sfSideEffect)
@@ -279,25 +295,25 @@ proc semCast(c: PContext, n: PNode): PNode =
   result.typ = semTypeNode(c, n.sons[0], nil)
   addSon(result, copyTree(n.sons[0]))
   addSon(result, semExprWithType(c, n.sons[1]))
-  if not isCastable(result.typ, result.sons[1].typ): 
-    localError(result.info, errExprCannotBeCastedToX, 
+  if not isCastable(result.typ, result.sons[1].typ):
+    localError(result.info, errExprCannotBeCastedToX,
                typeToString(result.typ))
 
-proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = 
-  const 
+proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
+  const
     opToStr: array[mLow..mHigh, string] = ["low", "high"]
-  if sonsLen(n) != 2: 
+  if sonsLen(n) != 2:
     localError(n.info, errXExpectsTypeOrValue, opToStr[m])
-  else: 
+  else:
     n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
     var typ = skipTypes(n.sons[1].typ, abstractVarRange +
                                        {tyTypeDesc, tyFieldAccessor})
     case typ.kind
-    of tySequence, tyString, tyOpenArray, tyVarargs: 
+    of tySequence, tyString, tyCString, tyOpenArray, tyVarargs:
       n.typ = getSysType(tyInt)
-    of tyArrayConstr, tyArray: 
+    of tyArrayConstr, tyArray:
       n.typ = typ.sons[0] # indextype
-    of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32: 
+    of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32:
       # do not skip the range!
       n.typ = n.sons[1].typ.skipTypes(abstractVar + {tyFieldAccessor})
     of tyGenericParam:
@@ -318,8 +334,8 @@ proc semSizeof(c: PContext, n: PNode): PNode =
   n.typ = getSysType(tyInt)
   result = n
 
-proc semOf(c: PContext, n: PNode): PNode = 
-  if sonsLen(n) == 3: 
+proc semOf(c: PContext, n: PNode): PNode =
+  if sonsLen(n) == 3:
     n.sons[1] = semExprWithType(c, n.sons[1])
     n.sons[2] = semExprWithType(c, n.sons[2], {efDetermineType})
     #restoreOldStyleType(n.sons[1])
@@ -357,7 +373,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
   internalAssert n.sonsLen == 3 and
     n[1].typ != nil and n[1].typ.kind == tyTypeDesc and
     n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
-  
+
   let t1 = n[1].typ.skipTypes({tyTypeDesc, tyFieldAccessor})
 
   if n[2].kind in {nkStrLit..nkTripleStrLit}:
@@ -365,7 +381,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
     of "closure":
       let t = skipTypes(t1, abstractRange)
       result = newIntNode(nkIntLit, ord(t.kind == tyProc and
-                                        t.callConv == ccClosure and 
+                                        t.callConv == ccClosure and
                                         tfIterator notin t.flags))
     else: discard
   else:
@@ -373,7 +389,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
     maybeLiftType(t2, c, n.info)
     var m: TCandidate
     initCandidate(c, m, t2)
-    let match = typeRel(m, t2, t1) != isNone
+    let match = typeRel(m, t2, t1) >= isSubtype # isNone
     result = newIntNode(nkIntLit, ord(match))
 
   result.typ = n.typ
@@ -384,7 +400,7 @@ proc semIs(c: PContext, n: PNode): PNode =
 
   result = n
   n.typ = getSysType(tyBool)
- 
+
   n.sons[1] = semExprWithType(c, n[1], {efDetermineType, efWantIterator})
   if n[2].kind notin {nkStrLit..nkTripleStrLit}:
     let t2 = semTypeNode(c, n[2], nil)
@@ -404,7 +420,7 @@ proc semOpAux(c: PContext, n: PNode) =
   const flags = {efDetermineType}
   for i in countup(1, n.sonsLen-1):
     var a = n.sons[i]
-    if a.kind == nkExprEqExpr and sonsLen(a) == 2: 
+    if a.kind == nkExprEqExpr and sonsLen(a) == 2:
       var info = a.sons[0].info
       a.sons[0] = newIdentNode(considerQuotedIdent(a.sons[0]), info)
       a.sons[1] = semExprWithType(c, a.sons[1], flags)
@@ -412,7 +428,7 @@ proc semOpAux(c: PContext, n: PNode) =
     else:
       n.sons[i] = semExprWithType(c, a, flags)
 
-proc overloadedCallOpr(c: PContext, n: PNode): PNode = 
+proc overloadedCallOpr(c: PContext, n: PNode): PNode =
   # quick check if there is *any* () operator overloaded:
   var par = getIdent("()")
   if searchInScopes(c, par) == nil:
@@ -423,34 +439,39 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
     for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i])
     result = semExpr(c, result)
 
-proc changeType(n: PNode, newType: PType, check: bool) = 
+proc changeType(n: PNode, newType: PType, check: bool) =
   case n.kind
-  of nkCurly, nkBracket: 
-    for i in countup(0, sonsLen(n) - 1): 
+  of nkCurly, nkBracket:
+    for i in countup(0, sonsLen(n) - 1):
       changeType(n.sons[i], elemType(newType), check)
-  of nkPar: 
-    if newType.kind != tyTuple: 
+  of nkPar:
+    let tup = newType.skipTypes({tyGenericInst})
+    if tup.kind != tyTuple:
       internalError(n.info, "changeType: no tuple type for constructor")
-    elif newType.n == nil: discard
-    elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr: 
-      for i in countup(0, sonsLen(n) - 1): 
+    elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr:
+      # named tuple?
+      for i in countup(0, sonsLen(n) - 1):
         var m = n.sons[i].sons[0]
-        if m.kind != nkSym: 
+        if m.kind != nkSym:
           internalError(m.info, "changeType(): invalid tuple constr")
           return
-        var f = getSymFromList(newType.n, m.sym.name)
-        if f == nil: 
-          internalError(m.info, "changeType(): invalid identifier")
-          return
-        changeType(n.sons[i].sons[1], f.typ, check)
+        if tup.n != nil:
+          var f = getSymFromList(tup.n, m.sym.name)
+          if f == nil:
+            internalError(m.info, "changeType(): invalid identifier")
+            return
+          changeType(n.sons[i].sons[1], f.typ, check)
+        else:
+          changeType(n.sons[i].sons[1], tup.sons[i], check)
     else:
       for i in countup(0, sonsLen(n) - 1):
-        var m = n.sons[i]
-        var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
-        addSon(a, newSymNode(newType.n.sons[i].sym))
-        addSon(a, m)
-        changeType(m, newType.sons[i], check)
-        n.sons[i] = a
+        changeType(n.sons[i], tup.sons[i], check)
+        when false:
+          var m = n.sons[i]
+          var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
+          addSon(a, newSymNode(newType.n.sons[i].sym))
+          addSon(a, m)
+          changeType(m, tup.sons[i], check)
   of nkCharLit..nkUInt64Lit:
     if check:
       let value = n.intVal
@@ -460,10 +481,10 @@ proc changeType(n: PNode, newType: PType, check: bool) =
   else: discard
   n.typ = newType
 
-proc arrayConstrType(c: PContext, n: PNode): PType = 
+proc arrayConstrType(c: PContext, n: PNode): PType =
   var typ = newTypeS(tyArrayConstr, c)
   rawAddSon(typ, nil)     # index type
-  if sonsLen(n) == 0: 
+  if sonsLen(n) == 0:
     rawAddSon(typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
   else:
     var x = n.sons[0]
@@ -473,35 +494,35 @@ proc arrayConstrType(c: PContext, n: PNode): PType =
   typ.sons[0] = makeRangeType(c, 0, sonsLen(n) - 1, n.info)
   result = typ
 
-proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = 
+proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   result = newNodeI(nkBracket, n.info)
   result.typ = newTypeS(tyArrayConstr, c)
   rawAddSon(result.typ, nil)     # index type
-  if sonsLen(n) == 0: 
+  if sonsLen(n) == 0:
     rawAddSon(result.typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
   else:
     var x = n.sons[0]
     var lastIndex: BiggestInt = 0
     var indexType = getSysType(tyInt)
-    if x.kind == nkExprColonExpr and sonsLen(x) == 2: 
+    if x.kind == nkExprColonExpr and sonsLen(x) == 2:
       var idx = semConstExpr(c, x.sons[0])
       lastIndex = getOrdValue(idx)
       indexType = idx.typ
       x = x.sons[1]
-    
+
     let yy = semExprWithType(c, x)
     var typ = yy.typ
     addSon(result, yy)
     #var typ = skipTypes(result.sons[0].typ, {tyGenericInst, tyVar, tyOrdinal})
-    for i in countup(1, sonsLen(n) - 1): 
+    for i in countup(1, sonsLen(n) - 1):
       x = n.sons[i]
-      if x.kind == nkExprColonExpr and sonsLen(x) == 2: 
+      if x.kind == nkExprColonExpr and sonsLen(x) == 2:
         var idx = semConstExpr(c, x.sons[0])
         idx = fitNode(c, indexType, idx)
         if lastIndex+1 != getOrdValue(idx):
           localError(x.info, errInvalidOrderInArrayConstructor)
         x = x.sons[1]
-      
+
       let xx = semExprWithType(c, x, flags*{efAllowDestructor})
       result.add xx
       typ = commonType(typ, xx.typ)
@@ -513,21 +534,21 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
       result.sons[i] = fitNode(c, typ, result.sons[i])
   result.typ.sons[0] = makeRangeType(c, 0, sonsLen(result) - 1, n.info)
 
-proc fixAbstractType(c: PContext, n: PNode) = 
+proc fixAbstractType(c: PContext, n: PNode) =
   # XXX finally rewrite that crap!
-  for i in countup(1, sonsLen(n) - 1): 
+  for i in countup(1, sonsLen(n) - 1):
     var it = n.sons[i]
     case it.kind
     of nkHiddenStdConv, nkHiddenSubConv:
       if it.sons[1].kind == nkBracket:
         it.sons[1].typ = arrayConstrType(c, it.sons[1])
         #it.sons[1] = semArrayConstr(c, it.sons[1])
-      if skipTypes(it.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: 
+      if skipTypes(it.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
         #if n.sons[0].kind == nkSym and IdentEq(n.sons[0].sym.name, "[]="):
         #  debug(n)
-        
+
         var s = skipTypes(it.sons[1].typ, abstractVar)
-        if s.kind == tyArrayConstr and s.sons[1].kind == tyEmpty: 
+        if s.kind == tyArrayConstr and s.sons[1].kind == tyEmpty:
           s = copyType(s, getCurrOwner(), false)
           skipTypes(s, abstractVar).sons[1] = elemType(
               skipTypes(it.typ, abstractVar))
@@ -537,86 +558,88 @@ proc fixAbstractType(c: PContext, n: PNode) =
           skipTypes(s, abstractVar).sons[0] = elemType(
               skipTypes(it.typ, abstractVar))
           it.sons[1].typ = s
-          
+
       elif skipTypes(it.sons[1].typ, abstractVar).kind in
-          {tyNil, tyArrayConstr, tyTuple, tySet}: 
+          {tyNil, tyArrayConstr, tyTuple, tySet}:
         var s = skipTypes(it.typ, abstractVar)
-        changeType(it.sons[1], s, check=true)
+        if s.kind != tyExpr:
+          changeType(it.sons[1], s, check=true)
         n.sons[i] = it.sons[1]
-    of nkBracket: 
+    of nkBracket:
       # an implicitly constructed array (passed to an open array):
       n.sons[i] = semArrayConstr(c, it, {})
-    else: 
+    else:
       discard
-      #if (it.typ == nil): 
-      #  InternalError(it.info, "fixAbstractType: " & renderTree(it))  
-  
-proc skipObjConv(n: PNode): PNode = 
+      #if (it.typ == nil):
+      #  InternalError(it.info, "fixAbstractType: " & renderTree(it))
+
+proc skipObjConv(n: PNode): PNode =
   case n.kind
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv: 
-    if skipTypes(n.sons[1].typ, abstractPtrs).kind in {tyTuple, tyObject}: 
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+    if skipTypes(n.sons[1].typ, abstractPtrs).kind in {tyTuple, tyObject}:
       result = n.sons[1]
-    else: 
+    else:
       result = n
   of nkObjUpConv, nkObjDownConv: result = n.sons[0]
   else: result = n
 
-proc isAssignable(c: PContext, n: PNode): TAssignableResult = 
+proc isAssignable(c: PContext, n: PNode): TAssignableResult =
   result = parampatterns.isAssignable(c.p.owner, n)
 
-proc newHiddenAddrTaken(c: PContext, n: PNode): PNode = 
-  if n.kind == nkHiddenDeref: 
+proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
+  if n.kind == nkHiddenDeref and not (gCmd == cmdCompileToCpp or
+                                      sfCompileToCpp in c.module.flags):
     checkSonsLen(n, 1)
     result = n.sons[0]
-  else: 
+  else:
     result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ))
     addSon(result, n)
     if isAssignable(c, n) notin {arLValue, arLocalLValue}:
       localError(n.info, errVarForOutParamNeeded)
 
-proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = 
+proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
   result = n
   case n.kind
   of nkSym:
     # n.sym.typ can be nil in 'check' mode ...
     if n.sym.typ != nil and
-        skipTypes(n.sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar: 
+        skipTypes(n.sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar:
       incl(n.sym.flags, sfAddrTaken)
       result = newHiddenAddrTaken(c, n)
-  of nkDotExpr: 
+  of nkDotExpr:
     checkSonsLen(n, 2)
-    if n.sons[1].kind != nkSym: 
+    if n.sons[1].kind != nkSym:
       internalError(n.info, "analyseIfAddressTaken")
       return
-    if skipTypes(n.sons[1].sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar: 
+    if skipTypes(n.sons[1].sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar:
       incl(n.sons[1].sym.flags, sfAddrTaken)
       result = newHiddenAddrTaken(c, n)
-  of nkBracketExpr: 
+  of nkBracketExpr:
     checkMinSonsLen(n, 1)
-    if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind != tyVar: 
+    if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind != tyVar:
       if n.sons[0].kind == nkSym: incl(n.sons[0].sym.flags, sfAddrTaken)
       result = newHiddenAddrTaken(c, n)
-  else: 
+  else:
     result = newHiddenAddrTaken(c, n)
-  
-proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = 
+
+proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
   checkMinSonsLen(n, 1)
-  const 
-    FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl, 
-      mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap, 
+  const
+    FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl,
+      mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap,
       mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy}
-  
+
   # get the real type of the callee
   # it may be a proc var with a generic alias type, so we skip over them
   var t = n.sons[0].typ.skipTypes({tyGenericInst})
 
-  if n.sons[0].kind == nkSym and n.sons[0].sym.magic in FakeVarParams: 
+  if n.sons[0].kind == nkSym and n.sons[0].sym.magic in FakeVarParams:
     # BUGFIX: check for L-Value still needs to be done for the arguments!
     # note sometimes this is eval'ed twice so we check for nkHiddenAddr here:
-    for i in countup(1, sonsLen(n) - 1): 
+    for i in countup(1, sonsLen(n) - 1):
       if i < sonsLen(t) and t.sons[i] != nil and
-          skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar: 
-        if isAssignable(c, n.sons[i]) notin {arLValue, arLocalLValue}: 
+          skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar:
+        if isAssignable(c, n.sons[i]) notin {arLValue, arLocalLValue}:
           if n.sons[i].kind != nkHiddenAddr:
             localError(n.sons[i].info, errVarForOutParamNeeded)
     return
@@ -630,14 +653,14 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
         skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar:
       if n.sons[i].kind != nkHiddenAddr:
         n.sons[i] = analyseIfAddressTaken(c, n.sons[i])
-  
+
 include semmagic
 
 proc evalAtCompileTime(c: PContext, n: PNode): PNode =
   result = n
   if n.kind notin nkCallKinds or n.sons[0].kind != nkSym: return
   var callee = n.sons[0].sym
-  
+
   # constant folding that is necessary for correctness of semantic pass:
   if callee.magic != mNone and callee.magic in ctfeWhitelist and n.typ != nil:
     var call = newNodeIT(nkCall, n.info, n.typ)
@@ -655,7 +678,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
       if result.isNil: result = n
       else: return result
     result.typ = semfold.getIntervalType(callee.magic, call)
-  
+
   block maybeLabelAsStatic:
     # XXX: temporary work-around needed for tlateboundstatic.
     # This is certainly not correct, but it will get the job
@@ -663,7 +686,9 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
     # implicit statics.
     if n.len > 1:
       for i in 1 .. <n.len:
-        if n[i].typ.kind != tyStatic or tfUnresolved notin n[i].typ.flags:
+        # see bug #2113, it's possible that n[i].typ for errornous code:
+        if n[i].typ.isNil or n[i].typ.kind != tyStatic or
+            tfUnresolved notin n[i].typ.flags:
           break maybeLabelAsStatic
       n.typ = newTypeWithSons(c, tyStatic, @[n.typ])
       n.typ.flags.incl tfUnresolved
@@ -671,15 +696,15 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
   # optimization pass: not necessary for correctness of the semantic pass
   if {sfNoSideEffect, sfCompileTime} * callee.flags != {} and
      {sfForward, sfImportc} * callee.flags == {} and n.typ != nil:
-    if sfCompileTime notin callee.flags and 
+    if sfCompileTime notin callee.flags and
         optImplicitStatic notin gOptions: return
 
     if callee.magic notin ctfeWhitelist: return
     if callee.kind notin {skProc, skConverter} or callee.isGenericRoutine:
       return
-    
-    if n.typ != nil and not typeAllowed(n.typ, skConst): return
-    
+
+    if n.typ != nil and typeAllowed(n.typ, skConst) != nil: return
+
     var call = newNodeIT(nkCall, n.info, n.typ)
     call.add(n.sons[0])
     for i in 1 .. < n.len:
@@ -689,7 +714,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
     #echo "NOW evaluating at compile time: ", call.renderTree
     if sfCompileTime in callee.flags:
       result = evalStaticExpr(c.module, call, c.p.owner)
-      if result.isNil: 
+      if result.isNil:
         localError(n.info, errCannotInterpretNodeX, renderTree(call))
       else: result = fixupTypeAfterEval(c, result, n)
     else:
@@ -712,30 +737,45 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
                                      flags: TExprFlags): PNode =
   if flags*{efInTypeof, efWantIterator} != {}:
     # consider: 'for x in pReturningArray()' --> we don't want the restriction
-    # to 'skIterators' anymore; skIterators are preferred in sigmatch already 
+    # to 'skIterators' anymore; skIterators are preferred in sigmatch already
     # for typeof support.
     # for ``type(countup(1,3))``, see ``tests/ttoseq``.
     result = semOverloadedCall(c, n, nOrig,
       {skProc, skMethod, skConverter, skMacro, skTemplate}+skIterators)
   else:
-    result = semOverloadedCall(c, n, nOrig, 
+    result = semOverloadedCall(c, n, nOrig,
       {skProc, skMethod, skConverter, skMacro, skTemplate})
- 
+
   if result != nil:
-    if result.sons[0].kind != nkSym: 
+    if result.sons[0].kind != nkSym:
       internalError("semOverloadedCallAnalyseEffects")
       return
     let callee = result.sons[0].sym
     case callee.kind
     of skMacro, skTemplate: discard
     else:
-      if (callee.kind in skIterators) and (callee.id == c.p.owner.id): 
+      if callee.kind in skIterators and callee.id == c.p.owner.id:
         localError(n.info, errRecursiveDependencyX, callee.name.s)
-      if sfNoSideEffect notin callee.flags: 
+        # error correction, prevents endless for loop elimination in transf.
+        # See bug #2051:
+        result.sons[0] = newSymNode(errorSym(c, n))
+      if sfNoSideEffect notin callee.flags:
         if {sfImportc, sfSideEffect} * callee.flags != {}:
           incl(c.p.owner.flags, sfSideEffect)
 
 proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode
+
+proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
+                         t: PType): TCandidate =
+  initCandidate(c, result, t)
+  matches(c, n, nOrig, result)
+  if result.state != csMatch:
+    # try to deref the first argument:
+    if experimentalMode(c) and canDeref(n):
+      n.sons[1] = n.sons[1].tryDeref
+      initCandidate(c, result, t)
+      matches(c, n, nOrig, result)
+
 proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
   result = nil
   checkMinSonsLen(n, 1)
@@ -759,9 +799,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
     t = skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc})
   if t != nil and t.kind == tyProc:
     # This is a proc variable, apply normal overload resolution
-    var m: TCandidate
-    initCandidate(c, m, t)
-    matches(c, n, nOrig, m)
+    let m = resolveIndirectCall(c, n, nOrig, t)
     if m.state != csMatch:
       if c.inCompilesContext > 0:
         # speed up error generation:
@@ -770,11 +808,11 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
       else:
         var hasErrorType = false
         var msg = msgKindToString(errTypeMismatch)
-        for i in countup(1, sonsLen(n) - 1): 
+        for i in countup(1, sonsLen(n) - 1):
           if i > 1: add(msg, ", ")
           let nt = n.sons[i].typ
           add(msg, typeToString(nt))
-          if nt.kind == tyError: 
+          if nt.kind == tyError:
             hasErrorType = true
             break
         if not hasErrorType:
@@ -786,18 +824,17 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
     else:
       result = m.call
       instGenericConvertersSons(c, result, m)
-    # we assume that a procedure that calls something indirectly 
+    # we assume that a procedure that calls something indirectly
     # has side-effects:
     if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect)
   elif t != nil and t.kind == tyTypeDesc:
     if n.len == 1: return semObjConstr(c, n, flags)
-    let destType = t.skipTypes({tyTypeDesc, tyGenericInst})
     return semConv(c, n)
   else:
     result = overloadedCallOpr(c, n)
     # Now that nkSym does not imply an iteration over the proc/iterator space,
     # the old ``prc`` (which is likely an nkIdent) has to be restored:
-    if result == nil: 
+    if result == nil:
       # XXX: hmm, what kind of symbols will end up here?
       # do we really need to try the overload resolution?
       n.sons[0] = prc
@@ -832,7 +869,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
   if c.inTypeClass == 0:
     result = evalAtCompileTime(c, result)
 
-proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = 
+proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # this seems to be a hotspot in the compiler!
   let nOrig = n.copyTree
   #semLazyOpAux(c, n)
@@ -840,7 +877,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
   if result != nil: result = afterCallActions(c, result, nOrig, flags)
   else: result = errorNode(c, n)
 
-proc buildEchoStmt(c: PContext, n: PNode): PNode = 
+proc buildEchoStmt(c: PContext, n: PNode): PNode =
   # we MUST not check 'n' for semantics again here! But for now we give up:
   result = newNodeI(nkCall, n.info)
   var e = strTableGet(magicsys.systemModule.tab, getIdent"echo")
@@ -855,80 +892,88 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode =
 proc semExprNoType(c: PContext, n: PNode): PNode =
   result = semExpr(c, n, {efWantStmt})
   discardCheck(c, result)
-  
-proc isTypeExpr(n: PNode): bool = 
+
+proc isTypeExpr(n: PNode): bool =
   case n.kind
   of nkType, nkTypeOfExpr: result = true
   of nkSym: result = n.sym.kind == skType
   else: result = false
-  
-proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent, 
-                                 check: var PNode): PSym = 
+
+proc createSetType(c: PContext; baseType: PType): PType =
+  assert baseType != nil
+  result = newTypeS(tySet, c)
+  rawAddSon(result, baseType)
+
+proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
+                                 check: var PNode): PSym =
   # transform in a node that contains the runtime check for the
   # field, if it is in a case-part...
   result = nil
   case r.kind
-  of nkRecList: 
-    for i in countup(0, sonsLen(r) - 1): 
+  of nkRecList:
+    for i in countup(0, sonsLen(r) - 1):
       result = lookupInRecordAndBuildCheck(c, n, r.sons[i], field, check)
-      if result != nil: return 
-  of nkRecCase: 
+      if result != nil: return
+  of nkRecCase:
     checkMinSonsLen(r, 2)
     if (r.sons[0].kind != nkSym): illFormedAst(r)
     result = lookupInRecordAndBuildCheck(c, n, r.sons[0], field, check)
-    if result != nil: return 
-    var s = newNodeI(nkCurly, r.info)
-    for i in countup(1, sonsLen(r) - 1): 
+    if result != nil: return
+    let setType = createSetType(c, r.sons[0].typ)
+    var s = newNodeIT(nkCurly, r.info, setType)
+    for i in countup(1, sonsLen(r) - 1):
       var it = r.sons[i]
       case it.kind
-      of nkOfBranch: 
+      of nkOfBranch:
         result = lookupInRecordAndBuildCheck(c, n, lastSon(it), field, check)
-        if result == nil: 
+        if result == nil:
           for j in 0..sonsLen(it)-2: addSon(s, copyTree(it.sons[j]))
-        else: 
-          if check == nil: 
+        else:
+          if check == nil:
             check = newNodeI(nkCheckedFieldExpr, n.info)
             addSon(check, ast.emptyNode) # make space for access node
-          s = newNodeI(nkCurly, n.info)
+          s = newNodeIT(nkCurly, n.info, setType)
           for j in countup(0, sonsLen(it) - 2): addSon(s, copyTree(it.sons[j]))
-          var inExpr = newNodeI(nkCall, n.info)
-          addSon(inExpr, newIdentNode(getIdent("in"), n.info))
+          var inExpr = newNodeIT(nkCall, n.info, getSysType(tyBool))
+          addSon(inExpr, newSymNode(ast.opContains, n.info))
+          addSon(inExpr, s)
           addSon(inExpr, copyTree(r.sons[0]))
-          addSon(inExpr, s)   #writeln(output, renderTree(inExpr));
-          addSon(check, semExpr(c, inExpr))
-          return 
-      of nkElse: 
+          addSon(check, inExpr)
+          #addSon(check, semExpr(c, inExpr))
+          return
+      of nkElse:
         result = lookupInRecordAndBuildCheck(c, n, lastSon(it), field, check)
-        if result != nil: 
-          if check == nil: 
+        if result != nil:
+          if check == nil:
             check = newNodeI(nkCheckedFieldExpr, n.info)
             addSon(check, ast.emptyNode) # make space for access node
-          var inExpr = newNodeI(nkCall, n.info)
-          addSon(inExpr, newIdentNode(getIdent("in"), n.info))
-          addSon(inExpr, copyTree(r.sons[0]))
+          var inExpr = newNodeIT(nkCall, n.info, getSysType(tyBool))
+          addSon(inExpr, newSymNode(ast.opContains, n.info))
           addSon(inExpr, s)
-          var notExpr = newNodeI(nkCall, n.info)
-          addSon(notExpr, newIdentNode(getIdent("not"), n.info))
+          addSon(inExpr, copyTree(r.sons[0]))
+          var notExpr = newNodeIT(nkCall, n.info, getSysType(tyBool))
+          addSon(notExpr, newSymNode(ast.opNot, n.info))
           addSon(notExpr, inExpr)
-          addSon(check, semExpr(c, notExpr))
-          return 
+          addSon(check, notExpr)
+          return
       else: illFormedAst(it)
-  of nkSym: 
+  of nkSym:
     if r.sym.name.id == field.id: result = r.sym
   else: illFormedAst(n)
 
-proc makeDeref(n: PNode): PNode = 
+proc makeDeref(n: PNode): PNode =
   var t = skipTypes(n.typ, {tyGenericInst})
   result = n
-  if t.kind == tyVar: 
+  if t.kind == tyVar:
     result = newNodeIT(nkHiddenDeref, n.info, t.sons[0])
     addSon(result, n)
     t = skipTypes(t.sons[0], {tyGenericInst})
   while t.kind in {tyPtr, tyRef}:
     var a = result
-    result = newNodeIT(nkHiddenDeref, n.info, t.sons[0])
+    let baseTyp = t.lastSon
+    result = newNodeIT(nkHiddenDeref, n.info, baseTyp)
     addSon(result, a)
-    t = skipTypes(t.lastSon, {tyGenericInst})
+    t = skipTypes(baseTyp, {tyGenericInst})
 
 const
   tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass}
@@ -937,18 +982,19 @@ const
 proc readTypeParameter(c: PContext, typ: PType,
                        paramName: PIdent, info: TLineInfo): PNode =
   let ty = if typ.kind == tyGenericInst: typ.skipGenericAlias
-           else: (internalAssert(typ.kind == tyCompositeTypeClass); typ.sons[1])
-  
+           else: (internalAssert(typ.kind == tyCompositeTypeClass);
+                  typ.sons[1].skipGenericAlias)
   let tbody = ty.sons[0]
   for s in countup(0, tbody.len-2):
     let tParam = tbody.sons[s]
-    if tParam.sym.name == paramName:
+    if tParam.sym.name.id == paramName.id:
       let rawTyp = ty.sons[s + 1]
       if rawTyp.kind == tyStatic:
         return rawTyp.n
       else:
         let foundTyp = makeTypeDesc(c, rawTyp)
         return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
+  #echo "came here: returned nil"
 
 proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
   ## returns nil if it's not a built-in field access
@@ -983,7 +1029,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
       # look up if the identifier belongs to the enum:
       while ty != nil:
         f = getSymFromList(ty.n, i)
-        if f != nil: break 
+        if f != nil: break
         ty = ty.sons[0]         # enum inheritance
       if f != nil:
         result = newSymNode(f)
@@ -995,7 +1041,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
     of tyTypeParamsHolders:
       return readTypeParameter(c, ty, i, n.info)
     of tyObject, tyTuple:
-      if ty.n.kind == nkRecList:
+      if ty.n != nil and ty.n.kind == nkRecList:
         for field in ty.n:
           if field.sym.name == i:
             n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.sym.typ])
@@ -1033,7 +1079,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
           check.sons[0] = n
           check.typ = n.typ
           result = check
-  elif ty.kind == tyTuple and ty.n != nil: 
+  elif ty.kind == tyTuple and ty.n != nil:
     f = getSymFromList(ty.n, i)
     if f != nil:
       markUsed(n.sons[1].info, f)
@@ -1060,10 +1106,10 @@ proc dotTransformation(c: PContext, n: PNode): PNode =
     result.flags.incl nfDotField
     addSon(result, newIdentNode(i, n[1].info))
     addSon(result, copyTree(n[0]))
-  
-proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = 
+
+proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # this is difficult, because the '.' is used in many different contexts
-  # in Nimrod. We first allow types in the semantic checking.
+  # in Nim. We first allow types in the semantic checking.
   result = builtinFieldAccess(c, n, flags)
   if result == nil:
     result = dotTransformation(c, n)
@@ -1072,7 +1118,7 @@ proc buildOverloadedSubscripts(n: PNode, ident: PIdent): PNode =
   result = newNodeI(nkCall, n.info)
   result.add(newIdentNode(ident, n.info))
   for i in 0 .. n.len-1: result.add(n[i])
-  
+
 proc semDeref(c: PContext, n: PNode): PNode =
   checkSonsLen(n, 1)
   n.sons[0] = semExprWithType(c, n.sons[0])
@@ -1081,27 +1127,28 @@ proc semDeref(c: PContext, n: PNode): PNode =
   case t.kind
   of tyRef, tyPtr: n.typ = t.lastSon
   else: result = nil
-  #GlobalError(n.sons[0].info, errCircumNeedsPointer) 
+  #GlobalError(n.sons[0].info, errCircumNeedsPointer)
 
 proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
   ## returns nil if not a built-in subscript operator; also called for the
   ## checking of assignments
-  if sonsLen(n) == 1: 
-    var x = semDeref(c, n)
+  if sonsLen(n) == 1:
+    let x = semDeref(c, n)
     if x == nil: return nil
     result = newNodeIT(nkDerefExpr, x.info, x.typ)
     result.add(x[0])
     return
   checkMinSonsLen(n, 2)
   n.sons[0] = semExprWithType(c, n.sons[0])
-  var arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
+  let arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
   case arr.kind
-  of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString, 
+  of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString,
      tyCString:
     if n.len != 2: return nil
     n.sons[0] = makeDeref(n.sons[0])
-    for i in countup(1, sonsLen(n) - 1): 
-      n.sons[i] = semExprWithType(c, n.sons[i], 
+    c.p.bracketExpr = n.sons[0]
+    for i in countup(1, sonsLen(n) - 1):
+      n.sons[i] = semExprWithType(c, n.sons[i],
                                   flags*{efInTypeof, efDetermineType})
     var indexType = if arr.kind == tyArray: arr.sons[0] else: getSysType(tyInt)
     var arg = indexTypesMatch(c, indexType, n.sons[1].typ, n.sons[1])
@@ -1111,32 +1158,36 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
       result.typ = elemType(arr)
     #GlobalError(n.info, errIndexTypesDoNotMatch)
   of tyTypeDesc:
-    # The result so far is a tyTypeDesc bound 
+    # The result so far is a tyTypeDesc bound
     # a tyGenericBody. The line below will substitute
     # it with the instantiated type.
     result = n
     result.typ = makeTypeDesc(c, semTypeNode(c, n, nil))
     #result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
-  of tyTuple: 
+  of tyTuple:
     checkSonsLen(n, 2)
     n.sons[0] = makeDeref(n.sons[0])
+    c.p.bracketExpr = n.sons[0]
     # [] operator for tuples requires constant expression:
     n.sons[1] = semConstExpr(c, n.sons[1])
     if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal}).kind in
-        {tyInt..tyInt64}: 
+        {tyInt..tyInt64}:
       var idx = getOrdValue(n.sons[1])
       if idx >= 0 and idx < sonsLen(arr): n.typ = arr.sons[int(idx)]
       else: localError(n.info, errInvalidIndexValueForTuple)
-    else: 
+    else:
       localError(n.info, errIndexTypesDoNotMatch)
     result = n
-  else: discard
-  
-proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = 
+  else:
+    c.p.bracketExpr = n.sons[0]
+
+proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  let oldBracketExpr = c.p.bracketExpr
   result = semSubscript(c, n, flags)
   if result == nil:
     # overloaded [] operator:
     result = semExpr(c, buildOverloadedSubscripts(n, getIdent"[]"))
+  c.p.bracketExpr = oldBracketExpr
 
 proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
   var id = considerQuotedIdent(a[1])
@@ -1149,7 +1200,7 @@ proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
   result.flags.incl nfDotSetter
   let orig = newNode(nkCall, n.info, sons = @[setterId, aOrig[0], nOrig[1]])
   result = semOverloadedCallAnalyseEffects(c, result, orig, {})
-  
+
   if result != nil:
     result = afterCallActions(c, result, nOrig, {})
     #fixAbstractType(c, result)
@@ -1170,13 +1221,14 @@ proc takeImplicitAddr(c: PContext, n: PNode): PNode =
       localError(n.info, errExprHasNoAddress)
   result = newNodeIT(nkHiddenAddr, n.info, makePtrType(c, n.typ))
   result.add(n)
-  
+
 proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
   if le.kind == nkHiddenDeref:
     var x = le.sons[0]
     if x.typ.kind == tyVar and x.kind == nkSym and x.sym.kind == skResult:
       n.sons[0] = x # 'result[]' --> 'result'
       n.sons[1] = takeImplicitAddr(c, ri)
+      x.typ.flags.incl tfVarIsPtr
 
 template resultTypeIsInferrable(typ: PType): expr =
   typ.isMetaType and typ.kind != tyTypeDesc
@@ -1202,11 +1254,15 @@ proc semAsgn(c: PContext, n: PNode): PNode =
   of nkBracketExpr:
     # a[i] = x
     # --> `[]=`(a, i, x)
+    let oldBracketExpr = c.p.bracketExpr
     a = semSubscript(c, a, {efLValue})
     if a == nil:
       result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=")
       add(result, n[1])
-      return semExprNoType(c, result)
+      result = semExprNoType(c, result)
+      c.p.bracketExpr = oldBracketExpr
+      return result
+    c.p.bracketExpr = oldBracketExpr
   of nkCurlyExpr:
     # a{i} = x -->  `{}=`(a, i, x)
     result = buildOverloadedSubscripts(n.sons[0], getIdent"{}=")
@@ -1218,7 +1274,7 @@ proc semAsgn(c: PContext, n: PNode): PNode =
   # a = b # both are vars, means: a[] = b[]
   # a = b # b no 'var T' means: a = addr(b)
   var le = a.typ
-  if skipTypes(le, {tyGenericInst}).kind != tyVar and 
+  if skipTypes(le, {tyGenericInst}).kind != tyVar and
       isAssignable(c, a) == arNone:
     # Direct assignment to a discriminant is allowed!
     localError(a.info, errXCannotBeAssignedTo,
@@ -1228,7 +1284,7 @@ proc semAsgn(c: PContext, n: PNode): PNode =
       lhs = n.sons[0]
       lhsIsResult = lhs.kind == nkSym and lhs.sym.kind == skResult
     var
-      rhs = semExprWithType(c, n.sons[1], 
+      rhs = semExprWithType(c, n.sons[1],
         if lhsIsResult: {efAllowDestructor} else: {})
     if lhsIsResult:
       n.typ = enforceVoidContext
@@ -1242,6 +1298,9 @@ proc semAsgn(c: PContext, n: PNode): PNode =
           typeMismatch(n, lhs.typ, rhs.typ)
 
     n.sons[1] = fitNode(c, le, rhs)
+    if tfHasAsgn in lhs.typ.flags and not lhsIsResult:
+      return overloadedAsgn(c, lhs, n.sons[1])
+
     fixAbstractType(c, n)
     asgnToResultVar(c, n, n.sons[0], n.sons[1])
   result = n
@@ -1249,17 +1308,17 @@ proc semAsgn(c: PContext, n: PNode): PNode =
 proc semReturn(c: PContext, n: PNode): PNode =
   result = n
   checkSonsLen(n, 1)
-  if c.p.owner.kind in {skConverter, skMethod, skProc, skMacro} or
-     c.p.owner.kind == skClosureIterator:
+  if c.p.owner.kind in {skConverter, skMethod, skProc, skMacro,
+                        skClosureIterator}:
     if n.sons[0].kind != nkEmpty:
       # transform ``return expr`` to ``result = expr; return``
-      if c.p.resultSym != nil: 
+      if c.p.resultSym != nil:
         var a = newNodeI(nkAsgn, n.sons[0].info)
         addSon(a, newSymNode(c.p.resultSym))
         addSon(a, n.sons[0])
         n.sons[0] = semAsgn(c, a)
         # optimize away ``result = result``:
-        if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym: 
+        if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym:
           n.sons[0] = ast.emptyNode
       else:
         localError(n.info, errNoReturnTypeDeclared)
@@ -1268,7 +1327,7 @@ proc semReturn(c: PContext, n: PNode): PNode =
 
 proc semProcBody(c: PContext, n: PNode): PNode =
   openScope(c)
-  
+
   result = semExpr(c, n)
   if c.p.resultSym != nil and not isEmptyType(result.typ):
     # transform ``expr`` to ``result = expr``, but not if the expr is already
@@ -1292,10 +1351,15 @@ proc semProcBody(c: PContext, n: PNode): PNode =
       result = semAsgn(c, a)
   else:
     discardCheck(c, result)
-  
+
   if c.p.owner.kind notin {skMacro, skTemplate} and
      c.p.resultSym != nil and c.p.resultSym.typ.isMetaType:
-    localError(c.p.resultSym.info, errCannotInferReturnType)
+    if isEmptyType(result.typ):
+      # we inferred a 'void' return type:
+      c.p.resultSym.typ = nil
+      c.p.owner.typ.sons[0] = nil
+    else:
+      localError(c.p.resultSym.info, errCannotInferReturnType)
 
   closeScope(c)
 
@@ -1310,14 +1374,14 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) =
       if e.kind == tyVar:
         if n.sons[0].kind == nkPar:
           n.sons[0].sons[i] = takeImplicitAddr(c, n.sons[0].sons[i])
-        elif n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv} and 
+        elif n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv} and
              n.sons[0].sons[1].kind == nkPar:
           var a = n.sons[0].sons[1]
           a.sons[i] = takeImplicitAddr(c, a.sons[i])
         else:
           localError(n.sons[0].info, errXExpected, "tuple constructor")
   else: discard
-  
+
 proc semYield(c: PContext, n: PNode): PNode =
   result = n
   checkSonsLen(n, 1)
@@ -1328,20 +1392,21 @@ proc semYield(c: PContext, n: PNode): PNode =
   elif n.sons[0].kind != nkEmpty:
     n.sons[0] = semExprWithType(c, n.sons[0]) # check for type compatibility:
     var iterType = c.p.owner.typ
-    var restype = iterType.sons[0]
+    let restype = iterType.sons[0]
     if restype != nil:
-      let adjustedRes = if c.p.owner.kind == skIterator: restype.base
+      let adjustedRes = if restype.kind == tyIter: restype.base
                         else: restype
-      n.sons[0] = fitNode(c, adjustedRes, n.sons[0])
+      if adjustedRes.kind != tyExpr:
+        n.sons[0] = fitNode(c, adjustedRes, n.sons[0])
       if n.sons[0].typ == nil: internalError(n.info, "semYield")
-      
+
       if resultTypeIsInferrable(adjustedRes):
         let inferred = n.sons[0].typ
-        if c.p.owner.kind == skIterator:
-          iterType.sons[0].sons[0] = inferred
+        if restype.kind == tyIter:
+          restype.sons[0] = inferred
         else:
           iterType.sons[0] = inferred
-      
+
       semYieldVarResult(c, n, adjustedRes)
     else:
       localError(n.info, errCannotReturnExpr)
@@ -1349,25 +1414,25 @@ proc semYield(c: PContext, n: PNode): PNode =
     localError(n.info, errGenerated, "yield statement must yield a value")
 
 proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym =
-  if onlyCurrentScope: 
+  if onlyCurrentScope:
     result = localSearchInScope(c, i)
-  else: 
+  else:
     result = searchInScopes(c, i) # no need for stub loading
 
-proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym = 
+proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
   case n.kind
-  of nkIdent: 
+  of nkIdent:
     result = lookUpForDefined(c, n.ident, onlyCurrentScope)
   of nkDotExpr:
     result = nil
-    if onlyCurrentScope: return 
+    if onlyCurrentScope: return
     checkSonsLen(n, 2)
     var m = lookUpForDefined(c, n.sons[0], onlyCurrentScope)
     if m != nil and m.kind == skModule:
       let ident = considerQuotedIdent(n[1])
       if m == c.module:
         result = strTableGet(c.topLevelScope.symbols, ident)
-      else: 
+      else:
         result = strTableGet(m.tab, ident)
   of nkAccQuoted:
     result = lookUpForDefined(c, considerQuotedIdent(n), onlyCurrentScope)
@@ -1379,7 +1444,7 @@ proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
     localError(n.info, errIdentifierExpected, renderTree(n))
     result = nil
 
-proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode = 
+proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
   checkSonsLen(n, 2)
   # we replace this node by a 'true' or 'false' node:
   result = newIntNode(nkIntLit, 0)
@@ -1388,11 +1453,7 @@ proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
       localError(n.info, "obsolete usage of 'defined', use 'declared' instead")
     elif condsyms.isDefined(n.sons[1].ident):
       result.intVal = 1
-    elif not condsyms.isDeclared(n.sons[1].ident):
-      message(n.info, warnUser,
-        "undeclared conditional symbol; use --symbol to declare it: " &
-        n[1].ident.s)
-  elif lookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil: 
+  elif lookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil:
     result.intVal = 1
   result.info = n.info
   result.typ = getSysType(tyBool)
@@ -1463,7 +1524,9 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
 
   # Preserve the magic symbol in order to be handled in evals.nim
   internalAssert n.sons[0].sym.magic == mExpandToAst
-  n.typ = getSysSym("PNimrodNode").typ # expandedSym.getReturnType
+  #n.typ = getSysSym("PNimrodNode").typ # expandedSym.getReturnType
+  n.typ = if getCompilerProc("NimNode") != nil: sysTypeFromName"NimNode"
+          else: sysTypeFromName"PNimrodNode"
   result = n
 
 proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
@@ -1493,7 +1556,7 @@ proc processQuotations(n: var PNode, op: string,
         n.sons[0] = newIdentNode(getIdent(examinedOp.substr(op.len)), n.info)
   elif n.kind == nkAccQuoted and op == "``":
     returnQuote n[0]
- 
+
   for i in 0 .. <n.safeLen:
     processQuotations(n.sons[i], op, quotes, ids)
 
@@ -1505,7 +1568,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
     doBlk = n{-1}
     op = if n.len == 3: expectString(c, n[1]) else: "``"
     quotes = newSeq[PNode](1)
-      # the quotes will be added to a nkCall statement 
+      # the quotes will be added to a nkCall statement
       # leave some room for the callee symbol
     ids = newSeq[PNode]()
       # this will store the generated param names
@@ -1514,15 +1577,15 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
     localError(n.info, errXExpected, "block")
 
   processQuotations(doBlk.sons[bodyPos], op, quotes, ids)
-  
+
   doBlk.sons[namePos] = newAnonSym(skTemplate, n.info).newSymNode
   if ids.len > 0:
-    doBlk[paramsPos].sons.setLen(2)
-    doBlk[paramsPos].sons[0] = getSysSym("stmt").newSymNode # return type
+    doBlk.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
+    doBlk[paramsPos].add getSysSym("stmt").newSymNode # return type
     ids.add getSysSym("expr").newSymNode # params type
     ids.add emptyNode # no default value
-    doBlk[paramsPos].sons[1] = newNode(nkIdentDefs, n.info, ids)
-  
+    doBlk[paramsPos].add newNode(nkIdentDefs, n.info, ids)
+
   var tmpl = semTemplateDef(c, doBlk)
   quotes[0] = tmpl[namePos]
   result = newNode(nkCall, n.info, @[
@@ -1537,7 +1600,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   inc c.inCompilesContext
   # do not halt after first error:
   msgs.gErrorMax = high(int)
-  
+
   # open a scope for temporary symbol inclusions:
   let oldScope = c.currentScope
   openScope(c)
@@ -1546,7 +1609,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   let oldErrorOutputs = errorOutputs
   errorOutputs = {}
   let oldContextLen = msgs.getInfoContextLen()
-  
+
   let oldInGenericContext = c.inGenericContext
   let oldInUnrolledContext = c.inUnrolledContext
   let oldInGenericInst = c.inGenericInst
@@ -1574,7 +1637,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
 proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # we replace this node by a 'true' or 'false' node:
   if sonsLen(n) != 2: return semDirectOp(c, n, flags)
-  
+
   result = newIntNode(nkIntLit, ord(tryExpr(c, n[1], flags) != nil))
   result.info = n.info
   result.typ = getSysType(tyBool)
@@ -1591,7 +1654,7 @@ proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
     result = semDirectOp(c, n, flags)
 
 proc createFlowVar(c: PContext; t: PType; info: TLineInfo): PType =
-  result = newType(tyGenericInvokation, c.module)
+  result = newType(tyGenericInvocation, c.module)
   addSonSkipIntLit(result, magicsys.getCompilerProc("FlowVar").typ)
   addSonSkipIntLit(result, t)
   result = instGenericContainer(c, info, result, allowMetaTypes = false)
@@ -1601,7 +1664,7 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType;
   let sym = magicsys.getCompilerProc("nimCreateFlowVar")
   if sym == nil:
     localError(info, errSystemNeeds, "nimCreateFlowVar")
-  var bindings: TIdTable 
+  var bindings: TIdTable
   initIdTable(bindings)
   bindings.idTablePut(sym.ast[genericParamsPos].sons[0].typ, t)
   result = c.semGenerateInstance(c, sym, bindings, info)
@@ -1611,16 +1674,22 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType;
     result.flags = result.flags - {sfCompilerProc, sfExportC, sfImportC}
     result.loc.r = nil
 
-proc setMs(n: PNode, s: PSym): PNode = 
+proc setMs(n: PNode, s: PSym): PNode =
   result = n
   n.sons[0] = newSymNode(s)
   n.sons[0].info = n.info
 
-proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = 
+proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   # this is a hotspot in the compiler!
   # DON'T forget to update ast.SpecialSemMagics if you add a magic here!
   result = n
   case s.magic # magics that need special treatment
+  of mAddr:
+    checkSonsLen(n, 2)
+    result = semAddr(c, n.sons[1])
+  of mTypeOf:
+    checkSonsLen(n, 2)
+    result = semTypeOf(c, n.sons[1])
   of mDefined: result = semDefined(c, setMs(n, s), false)
   of mDefinedInScope: result = semDefined(c, setMs(n, s), true)
   of mCompiles: result = semCompiles(c, setMs(n, s), flags)
@@ -1662,68 +1731,68 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
   # If semCheck is set to false, ``when`` will return the verbatim AST of
   # the correct branch. Otherwise the AST will be passed through semStmt.
   result = nil
-  
+
   template setResult(e: expr) =
     if semCheck: result = semStmt(c, e) # do not open a new scope!
     else: result = e
 
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     var it = n.sons[i]
     case it.kind
-    of nkElifBranch, nkElifExpr: 
+    of nkElifBranch, nkElifExpr:
       checkSonsLen(it, 2)
       var e = semConstExpr(c, it.sons[0])
-      if e.kind != nkIntLit: 
+      if e.kind != nkIntLit:
         # can happen for cascading errors, assume false
         # InternalError(n.info, "semWhen")
         discard
       elif e.intVal != 0 and result == nil:
-        setResult(it.sons[1]) 
+        setResult(it.sons[1])
     of nkElse, nkElseExpr:
       checkSonsLen(it, 1)
-      if result == nil: 
+      if result == nil:
         setResult(it.sons[0])
     else: illFormedAst(n)
   if result == nil:
-    result = newNodeI(nkEmpty, n.info) 
+    result = newNodeI(nkEmpty, n.info)
   # The ``when`` statement implements the mechanism for platform dependent
   # code. Thus we try to ensure here consistent ID allocation after the
   # ``when`` statement.
   idSynchronizationPoint(200)
 
-proc semSetConstr(c: PContext, n: PNode): PNode = 
+proc semSetConstr(c: PContext, n: PNode): PNode =
   result = newNodeI(nkCurly, n.info)
   result.typ = newTypeS(tySet, c)
-  if sonsLen(n) == 0: 
+  if sonsLen(n) == 0:
     rawAddSon(result.typ, newTypeS(tyEmpty, c))
-  else: 
+  else:
     # only semantic checking for all elements, later type checking:
     var typ: PType = nil
-    for i in countup(0, sonsLen(n) - 1): 
-      if isRange(n.sons[i]): 
+    for i in countup(0, sonsLen(n) - 1):
+      if isRange(n.sons[i]):
         checkSonsLen(n.sons[i], 3)
         n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1])
         n.sons[i].sons[2] = semExprWithType(c, n.sons[i].sons[2])
-        if typ == nil: 
-          typ = skipTypes(n.sons[i].sons[1].typ, 
+        if typ == nil:
+          typ = skipTypes(n.sons[i].sons[1].typ,
                           {tyGenericInst, tyVar, tyOrdinal})
         n.sons[i].typ = n.sons[i].sons[2].typ # range node needs type too
       elif n.sons[i].kind == nkRange:
         # already semchecked
         if typ == nil:
-          typ = skipTypes(n.sons[i].sons[0].typ, 
+          typ = skipTypes(n.sons[i].sons[0].typ,
                           {tyGenericInst, tyVar, tyOrdinal})
       else:
         n.sons[i] = semExprWithType(c, n.sons[i])
-        if typ == nil: 
+        if typ == nil:
           typ = skipTypes(n.sons[i].typ, {tyGenericInst, tyVar, tyOrdinal})
     if not isOrdinalType(typ):
       localError(n.info, errOrdinalTypeExpected)
       typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
-    elif lengthOrd(typ) > MaxSetElements: 
+    elif lengthOrd(typ) > MaxSetElements:
       typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
     addSonSkipIntLit(result.typ, typ)
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       var m: PNode
       if isRange(n.sons[i]):
         m = newNodeI(nkRange, n.sons[i].info)
@@ -1735,7 +1804,7 @@ proc semSetConstr(c: PContext, n: PNode): PNode =
       addSon(result, m)
 
 proc semTableConstr(c: PContext, n: PNode): PNode =
-  # we simply transform ``{key: value, key2, key3: value}`` to 
+  # we simply transform ``{key: value, key2, key3: value}`` to
   # ``[(key, value), (key2, value2), (key3, value2)]``
   result = newNodeI(nkBracket, n.info)
   var lastKey = 0
@@ -1764,7 +1833,7 @@ type
 
 proc checkPar(n: PNode): TParKind =
   var length = sonsLen(n)
-  if length == 0: 
+  if length == 0:
     result = paTuplePositions # ()
   elif length == 1:
     if n.sons[0].kind == nkExprColonExpr: result = paTupleFields
@@ -1794,7 +1863,7 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
     var id: PIdent
     if n.sons[i].sons[0].kind == nkIdent: id = n.sons[i].sons[0].ident
     else: id = n.sons[i].sons[0].sym.name
-    if containsOrIncl(ids, id.id): 
+    if containsOrIncl(ids, id.id):
       localError(n.sons[i].info, errFieldInitTwice, id.s)
     n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1],
                                         flags*{efAllowDestructor})
@@ -1807,14 +1876,22 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
     addSon(result, n.sons[i])
   result.typ = typ
 
-proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = 
+proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   result = n                  # we don't modify n, but compute the type:
   var typ = newTypeS(tyTuple, c)  # leave typ.n nil!
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     n.sons[i] = semExprWithType(c, n.sons[i], flags*{efAllowDestructor})
     addSonSkipIntLit(typ, n.sons[i].typ)
   result.typ = typ
 
+proc isTupleType(n: PNode): bool =
+  if n.len == 0:
+    return false # don't interpret () as type
+  for i in countup(0, n.len - 1):
+    if n[i].typ == nil or n[i].typ.kind != tyTypeDesc:
+      return false
+  return true
+
 proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) =
   case n.kind
   of nkRecList:
@@ -1830,7 +1907,8 @@ proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) =
         of nkOfBranch, nkElse: checkInitialized(lastSon(n.sons[i]), ids, info)
         else: internalError(info, "checkInitialized")
   of nkSym:
-    if tfNeedsInit in n.sym.typ.flags and n.sym.name.id notin ids:
+    if {tfNotNil, tfNeedsInit} * n.sym.typ.flags != {} and
+        n.sym.name.id notin ids:
       message(info, errGenerated, "field not initialized: " & n.sym.name.s)
   else: internalError(info, "checkInitialized")
 
@@ -1848,12 +1926,11 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   var ids = initIntSet()
   for i in 1.. <n.len:
     let it = n.sons[i]
-    if it.kind != nkExprColonExpr or it.sons[0].kind notin {nkSym, nkIdent}:
+    if it.kind != nkExprColonExpr:
       localError(n.info, errNamedExprExpected)
       break
-    var id: PIdent
-    if it.sons[0].kind == nkIdent: id = it.sons[0].ident
-    else: id = it.sons[0].sym.name
+    let id = considerQuotedIdent(it.sons[0])
+
     if containsOrIncl(ids, id.id):
       localError(it.info, errFieldInitTwice, id.s)
     var e = semExprWithType(c, it.sons[1], flags*{efAllowDestructor})
@@ -1871,7 +1948,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
       it.sons[0] = newSymNode(f)
       e = fitNode(c, f.typ, e)
       # small hack here in a nkObjConstr the ``nkExprColonExpr`` node can have
-      # 3 childen the last being the field check
+      # 3 children the last being the field check
       if check != nil:
         check.sons[0] = it.sons[0]
         it.add(check)
@@ -1904,19 +1981,6 @@ proc semBlock(c: PContext, n: PNode): PNode =
   closeScope(c)
   dec(c.p.nestedBlockCounter)
 
-proc doBlockIsStmtList(n: PNode): bool =
-  result = n.kind == nkDo and
-           n[paramsPos].sonsLen == 1 and
-           n[paramsPos][0].kind == nkEmpty
-
-proc fixImmediateParams(n: PNode): PNode =
-  # XXX: Temporary work-around until we carry out
-  # the planned overload resolution reforms
-  for i in 1 .. <safeLen(n):
-    if doBlockIsStmtList(n[i]):
-      n.sons[i] = n[i][bodyPos]
-  result = n
-
 proc semExport(c: PContext, n: PNode): PNode =
   var x = newNodeI(n.kind, n.info)
   #let L = if n.kind == nkExportExceptStmt: L = 1 else: n.len
@@ -1953,14 +2017,14 @@ proc setGenericParams(c: PContext, n: PNode) =
   for i in 1 .. <n.len:
     n[i].typ = semTypeNode(c, n[i], nil)
 
-proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = 
+proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   result = n
   if gCmd == cmdIdeTools: suggestExpr(c, n)
-  if nfSem in n.flags: return 
+  if nfSem in n.flags: return
   case n.kind
   of nkIdent, nkAccQuoted:
     var s = lookUp(c, n)
-    semCaptureSym(s, c.p.owner)
+    if c.inTypeClass == 0: semCaptureSym(s, c.p.owner)
     result = semSym(c, n, s, flags)
     if s.kind in {skProc, skMethod, skConverter}+skIterators:
       #performProcvarCheck(c, n, s)
@@ -1968,48 +2032,48 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
       if result.kind == nkSym:
         markIndirect(c, result.sym)
         # if isGenericRoutine(result.sym):
-        #   localError(n.info, errInstantiateXExplicitely, s.name.s)
+        #   localError(n.info, errInstantiateXExplicitly, s.name.s)
   of nkSym:
     # because of the changed symbol binding, this does not mean that we
     # don't have to check the symbol for semantics here again!
     result = semSym(c, n, n.sym, flags)
-  of nkEmpty, nkNone, nkCommentStmt: 
+  of nkEmpty, nkNone, nkCommentStmt:
     discard
-  of nkNilLit: 
+  of nkNilLit:
     result.typ = getSysType(tyNil)
   of nkIntLit:
     if result.typ == nil: setIntLitType(result)
   of nkInt8Lit:
     if result.typ == nil: result.typ = getSysType(tyInt8)
-  of nkInt16Lit: 
+  of nkInt16Lit:
     if result.typ == nil: result.typ = getSysType(tyInt16)
-  of nkInt32Lit: 
+  of nkInt32Lit:
     if result.typ == nil: result.typ = getSysType(tyInt32)
-  of nkInt64Lit: 
+  of nkInt64Lit:
     if result.typ == nil: result.typ = getSysType(tyInt64)
   of nkUIntLit:
     if result.typ == nil: result.typ = getSysType(tyUInt)
-  of nkUInt8Lit: 
+  of nkUInt8Lit:
     if result.typ == nil: result.typ = getSysType(tyUInt8)
-  of nkUInt16Lit: 
+  of nkUInt16Lit:
     if result.typ == nil: result.typ = getSysType(tyUInt16)
-  of nkUInt32Lit: 
+  of nkUInt32Lit:
     if result.typ == nil: result.typ = getSysType(tyUInt32)
-  of nkUInt64Lit: 
+  of nkUInt64Lit:
     if result.typ == nil: result.typ = getSysType(tyUInt64)
-  of nkFloatLit: 
+  of nkFloatLit:
     if result.typ == nil: result.typ = getFloatLitType(result)
-  of nkFloat32Lit: 
+  of nkFloat32Lit:
     if result.typ == nil: result.typ = getSysType(tyFloat32)
-  of nkFloat64Lit: 
+  of nkFloat64Lit:
     if result.typ == nil: result.typ = getSysType(tyFloat64)
-  of nkFloat128Lit: 
+  of nkFloat128Lit:
     if result.typ == nil: result.typ = getSysType(tyFloat128)
-  of nkStrLit..nkTripleStrLit: 
+  of nkStrLit..nkTripleStrLit:
     if result.typ == nil: result.typ = getSysType(tyString)
-  of nkCharLit: 
+  of nkCharLit:
     if result.typ == nil: result.typ = getSysType(tyChar)
-  of nkDotExpr: 
+  of nkDotExpr:
     result = semFieldAccess(c, n, flags)
     if result.kind == nkDotCall:
       result.kind = nkCall
@@ -2017,11 +2081,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkBind:
     message(n.info, warnDeprecated, "bind")
     result = semExpr(c, n.sons[0], flags)
-  of nkTypeOfExpr, nkTupleTy, nkRefTy..nkEnumTy, nkStaticTy:
+  of nkTypeOfExpr, nkTupleTy, nkTupleClassTy, nkRefTy..nkEnumTy, nkStaticTy:
     var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc, tyIter})
     result.typ = makeTypeDesc(c, typ)
     #result = symNodeFromType(c, typ, n.info)
-  of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: 
+  of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
     # check if it is an expression macro:
     checkMinSonsLen(n, 1)
     let mode = if nfDotField in n.flags: {} else: {checkUndeclared}
@@ -2034,21 +2098,19 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
         if sfImmediate notin s.flags:
           result = semDirectOp(c, n, flags)
         else:
-          var p = fixImmediateParams(n)
-          result = semMacroExpr(c, p, p, s, flags)
+          result = semMacroExpr(c, n, n, s, flags)
       of skTemplate:
         if sfImmediate notin s.flags:
           result = semDirectOp(c, n, flags)
         else:
-          var p = fixImmediateParams(n)
-          result = semTemplateExpr(c, p, s, flags)
+          result = semTemplateExpr(c, n, s, flags)
       of skType:
         # XXX think about this more (``set`` procs)
         if n.len == 2:
           result = semConv(c, n)
         elif n.len == 1:
           result = semObjConstr(c, n, flags)
-        elif contains(c.ambiguousSymbols, s.id): 
+        elif contains(c.ambiguousSymbols, s.id):
           localError(n.info, errUseQualifier, s.name.s)
         elif s.magic == mNone: result = semDirectOp(c, n, flags)
         else: result = semMagic(c, n, s, flags)
@@ -2087,39 +2149,44 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
       result = semArrayAccess(c, n, flags)
   of nkCurlyExpr:
     result = semExpr(c, buildOverloadedSubscripts(n, getIdent"{}"), flags)
-  of nkPragmaExpr: 
+  of nkPragmaExpr:
     # which pragmas are allowed for expressions? `likely`, `unlikely`
     internalError(n.info, "semExpr() to implement") # XXX: to implement
-  of nkPar: 
+  of nkPar:
     case checkPar(n)
     of paNone: result = errorNode(c, n)
-    of paTuplePositions: result = semTuplePositionsConstr(c, n, flags)
+    of paTuplePositions:
+      var tupexp = semTuplePositionsConstr(c, n, flags)
+      if isTupleType(tupexp):
+        # reinterpret as type
+        var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc, tyIter})
+        result.typ = makeTypeDesc(c, typ)
+      else:
+        result = tupexp
     of paTupleFields: result = semTupleFieldsConstr(c, n, flags)
     of paSingle: result = semExpr(c, n.sons[0], flags)
   of nkCurly: result = semSetConstr(c, n)
   of nkBracket: result = semArrayConstr(c, n, flags)
   of nkObjConstr: result = semObjConstr(c, n, flags)
-  of nkLambdaKinds: result = semLambda(c, n, flags)
+  of nkLambda: result = semLambda(c, n, flags)
+  of nkDo: result = semDo(c, n, flags)
   of nkDerefExpr: result = semDeref(c, n)
   of nkAddr:
     result = n
     checkSonsLen(n, 1)
-    n.sons[0] = semExprWithType(c, n.sons[0])
-    if isAssignable(c, n.sons[0]) notin {arLValue, arLocalLValue}: 
-      localError(n.info, errExprHasNoAddress)
-    n.typ = makePtrType(c, n.sons[0].typ)
+    result = semAddr(c, n.sons[0])
   of nkHiddenAddr, nkHiddenDeref:
     checkSonsLen(n, 1)
     n.sons[0] = semExpr(c, n.sons[0], flags)
   of nkCast: result = semCast(c, n)
   of nkIfExpr, nkIfStmt: result = semIf(c, n)
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv: 
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv:
     checkSonsLen(n, 2)
-  of nkStringToCString, nkCStringToString, nkObjDownConv, nkObjUpConv: 
+  of nkStringToCString, nkCStringToString, nkObjDownConv, nkObjUpConv:
     checkSonsLen(n, 1)
-  of nkChckRangeF, nkChckRange64, nkChckRange: 
+  of nkChckRangeF, nkChckRange64, nkChckRange:
     checkSonsLen(n, 3)
-  of nkCheckedFieldExpr: 
+  of nkCheckedFieldExpr:
     checkMinSonsLen(n, 2)
   of nkTableConstr:
     result = semTableConstr(c, n)
@@ -2154,16 +2221,16 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
   of nkConverterDef: result = semConverterDef(c, n)
   of nkMacroDef: result = semMacroDef(c, n)
   of nkTemplateDef: result = semTemplateDef(c, n)
-  of nkImportStmt: 
+  of nkImportStmt:
     if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "import")
     result = evalImport(c, n)
   of nkImportExceptStmt:
     if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "import")
     result = evalImportExcept(c, n)
-  of nkFromStmt: 
+  of nkFromStmt:
     if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "from")
     result = evalFrom(c, n)
-  of nkIncludeStmt: 
+  of nkIncludeStmt:
     if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "include")
     result = evalInclude(c, n)
   of nkExportStmt, nkExportExceptStmt:
@@ -2173,6 +2240,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     result = semPragmaBlock(c, n)
   of nkStaticStmt:
     result = semStaticStmt(c, n)
+  of nkDefer:
+    localError(n.info, errGenerated, "'defer' not allowed in this context")
   else:
     localError(n.info, errInvalidExpressionX,
                renderTree(n, {renderNoComments}))
diff --git a/compiler/semfields.nim b/compiler/semfields.nim
new file mode 100644
index 000000000..e086e73f8
--- /dev/null
+++ b/compiler/semfields.nim
@@ -0,0 +1,164 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module does the semantic transformation of the fields* iterators.
+#  included from semstmts.nim
+
+type
+  TFieldInstCtx = object  # either 'tup[i]' or 'field' is valid
+    tupleType: PType      # if != nil we're traversing a tuple
+    tupleIndex: int
+    field: PSym
+    replaceByFieldName: bool
+
+proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
+  case n.kind
+  of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = n
+  of nkIdent, nkSym:
+    result = n
+    let ident = considerQuotedIdent(n)
+    var L = sonsLen(forLoop)
+    if c.replaceByFieldName:
+      if ident.id == considerQuotedIdent(forLoop[0]).id:
+        let fieldName = if c.tupleType.isNil: c.field.name.s
+                        elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
+                        else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
+        result = newStrNode(nkStrLit, fieldName)
+        return
+    # other fields:
+    for i in ord(c.replaceByFieldName)..L-3:
+      if ident.id == considerQuotedIdent(forLoop[i]).id:
+        var call = forLoop.sons[L-2]
+        var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
+        if c.field.isNil:
+          result = newNodeI(nkBracketExpr, n.info)
+          result.add(tupl)
+          result.add(newIntNode(nkIntLit, c.tupleIndex))
+        else:
+          result = newNodeI(nkDotExpr, n.info)
+          result.add(tupl)
+          result.add(newSymNode(c.field, n.info))
+        break
+  else:
+    if n.kind == nkContinueStmt:
+      localError(n.info, errGenerated,
+                 "'continue' not supported in a 'fields' loop")
+    result = copyNode(n)
+    newSons(result, sonsLen(n))
+    for i in countup(0, sonsLen(n)-1):
+      result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop)
+
+type
+  TFieldsCtx = object
+    c: PContext
+    m: TMagic
+
+proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
+  case typ.kind
+  of nkSym:
+    var fc: TFieldInstCtx  # either 'tup[i]' or 'field' is valid
+    fc.field = typ.sym
+    fc.replaceByFieldName = c.m == mFieldPairs
+    openScope(c.c)
+    inc c.c.inUnrolledContext
+    let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
+    father.add(semStmt(c.c, body))
+    dec c.c.inUnrolledContext
+    closeScope(c.c)
+  of nkNilLit: discard
+  of nkRecCase:
+    let L = forLoop.len
+    let call = forLoop.sons[L-2]
+    if call.len > 2:
+      localError(forLoop.info, errGenerated, 
+                 "parallel 'fields' iterator does not work for 'case' objects")
+      return
+    # iterate over the selector:
+    semForObjectFields(c, typ[0], forLoop, father)
+    # we need to generate a case statement:
+    var caseStmt = newNodeI(nkCaseStmt, forLoop.info)
+    # generate selector:
+    var access = newNodeI(nkDotExpr, forLoop.info, 2)
+    access.sons[0] = call.sons[1]
+    access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info)
+    caseStmt.add(semExprWithType(c.c, access))
+    # copy the branches over, but replace the fields with the for loop body:
+    for i in 1 .. <typ.len:
+      var branch = copyTree(typ[i])
+      let L = branch.len
+      branch.sons[L-1] = newNodeI(nkStmtList, forLoop.info)
+      semForObjectFields(c, typ[i].lastSon, forLoop, branch[L-1])
+      caseStmt.add(branch)
+    father.add(caseStmt)
+  of nkRecList:
+    for t in items(typ): semForObjectFields(c, t, forLoop, father)
+  else:
+    illFormedAstLocal(typ)
+
+proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
+  # so that 'break' etc. work as expected, we produce
+  # a 'while true: stmt; break' loop ...
+  result = newNodeI(nkWhileStmt, n.info, 2)
+  var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true")
+  if trueSymbol == nil: 
+    localError(n.info, errSystemNeeds, "true")
+    trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(), n.info)
+    trueSymbol.typ = getSysType(tyBool)
+
+  result.sons[0] = newSymNode(trueSymbol, n.info)
+  var stmts = newNodeI(nkStmtList, n.info)
+  result.sons[1] = stmts
+  
+  var length = sonsLen(n)
+  var call = n.sons[length-2]
+  if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs):
+    localError(n.info, errWrongNumberOfVariables)
+    return result
+  
+  var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar-{tyTypeDesc})
+  if tupleTypeA.kind notin {tyTuple, tyObject}:
+    localError(n.info, errGenerated, "no object or tuple type")
+    return result
+  for i in 1..call.len-1:
+    var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar-{tyTypeDesc})
+    if not sameType(tupleTypeA, tupleTypeB):
+      typeMismatch(call.sons[i], tupleTypeA, tupleTypeB)
+  
+  inc(c.p.nestedLoopCounter)
+  if tupleTypeA.kind == tyTuple:
+    var loopBody = n.sons[length-1]
+    for i in 0..sonsLen(tupleTypeA)-1:
+      openScope(c)
+      var fc: TFieldInstCtx
+      fc.tupleType = tupleTypeA
+      fc.tupleIndex = i
+      fc.replaceByFieldName = m == mFieldPairs
+      var body = instFieldLoopBody(fc, loopBody, n)
+      inc c.inUnrolledContext
+      stmts.add(semStmt(c, body))
+      dec c.inUnrolledContext
+      closeScope(c)
+  else:
+    var fc: TFieldsCtx
+    fc.m = m
+    fc.c = c
+    var t = tupleTypeA
+    while t.kind == tyObject:
+      semForObjectFields(fc, t.n, n, stmts)
+      if t.sons[0] == nil: break
+      t = skipTypes(t.sons[0], abstractPtrs)
+  dec(c.p.nestedLoopCounter)
+  # for TR macros this 'while true: ...; break' loop is pretty bad, so
+  # we avoid it now if we can:
+  if containsNode(stmts, {nkBreakStmt}):
+    var b = newNodeI(nkBreakStmt, n.info)
+    b.add(ast.emptyNode)
+    stmts.add(b)
+  else:
+    result = stmts
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index c7ae42548..796dde9a6 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -10,8 +10,8 @@
 # this module folds constants; used by semantic checking phase
 # and evaluation phase
 
-import 
-  strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times, 
+import
+  strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times,
   nversion, platform, math, msgs, os, condsyms, idents, renderer, types,
   commands, magicsys, saturate
 
@@ -41,7 +41,7 @@ proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode =
     result.typ = n.typ
   result.info = n.info
 
-proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode = 
+proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode =
   result = newFloatNode(nkFloatLit, floatVal)
   if skipTypes(n.typ, abstractVarRange).kind == tyFloat:
     result.typ = getFloatLitType(result)
@@ -49,27 +49,27 @@ proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode =
     result.typ = n.typ
   result.info = n.info
 
-proc newStrNodeT(strVal: string, n: PNode): PNode = 
+proc newStrNodeT(strVal: string, n: PNode): PNode =
   result = newStrNode(nkStrLit, strVal)
   result.typ = n.typ
   result.info = n.info
 
-proc ordinalValToString*(a: PNode): string = 
+proc ordinalValToString*(a: PNode): string =
   # because $ has the param ordinal[T], `a` is not necessarily an enum, but an
   # ordinal
   var x = getInt(a)
-  
+
   var t = skipTypes(a.typ, abstractRange)
   case t.kind
-  of tyChar: 
+  of tyChar:
     result = $chr(int(x) and 0xff)
   of tyEnum:
     var n = t.n
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       if n.sons[i].kind != nkSym: internalError(a.info, "ordinalValToString")
       var field = n.sons[i].sym
-      if field.position == x: 
-        if field.ast == nil: 
+      if field.position == x:
+        if field.ast == nil:
           return field.name.s
         else:
           return field.ast.strVal
@@ -112,12 +112,15 @@ proc pickMaxInt(n: PNode): BiggestInt =
   else:
     internalError(n.info, "pickMaxInt")
 
-proc makeRange(typ: PType, first, last: BiggestInt): PType = 
+proc makeRange(typ: PType, first, last: BiggestInt): PType =
   let minA = min(first, last)
   let maxA = max(first, last)
   let lowerNode = newIntNode(nkIntLit, minA)
   if typ.kind == tyInt and minA == maxA:
     result = getIntLitType(lowerNode)
+  elif typ.kind in {tyUint, tyUInt64}:
+    # these are not ordinal types, so you get no subrange type for these:
+    result = typ
   else:
     var n = newNode(nkRange)
     addSon(n, lowerNode)
@@ -135,10 +138,11 @@ proc makeRangeF(typ: PType, first, last: BiggestFloat): PType =
   addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
 
 proc getIntervalType*(m: TMagic, n: PNode): PType =
-  # Nimrod requires interval arithmetic for ``range`` types. Lots of tedious
+  # Nim requires interval arithmetic for ``range`` types. Lots of tedious
   # work but the feature is very nice for reducing explicit conversions.
+  const ordIntLit = {nkIntLit..nkUInt64Lit}
   result = n.typ
-  
+
   template commutativeOp(opr: expr) {.immediate.} =
     let a = n.sons[1]
     let b = n.sons[2]
@@ -146,7 +150,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
       result = makeRange(pickIntRange(a.typ, b.typ),
                          opr(pickMinInt(a), pickMinInt(b)),
                          opr(pickMaxInt(a), pickMaxInt(b)))
-  
+
   template binaryOp(opr: expr) {.immediate.} =
     let a = n.sons[1]
     let b = n.sons[2]
@@ -154,7 +158,7 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
       result = makeRange(a.typ,
                          opr(pickMinInt(a), pickMinInt(b)),
                          opr(pickMaxInt(a), pickMaxInt(b)))
-  
+
   case m
   of mUnaryMinusI, mUnaryMinusI64:
     let a = n.sons[1].typ
@@ -170,13 +174,19 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
     let a = n.sons[1].typ
     if isFloatRange(a):
       # abs(-5.. 1) == (1..5)
-      result = makeRangeF(a, abs(getFloat(a.n.sons[1])),
-                             abs(getFloat(a.n.sons[0])))
+      if a.n[0].floatVal <= 0.0:
+        result = makeRangeF(a, 0.0, abs(getFloat(a.n.sons[0])))
+      else:
+        result = makeRangeF(a, abs(getFloat(a.n.sons[1])),
+                               abs(getFloat(a.n.sons[0])))
   of mAbsI, mAbsI64:
     let a = n.sons[1].typ
     if isIntRange(a):
-      result = makeRange(a, `|abs|`(getInt(a.n.sons[1])),
-                            `|abs|`(getInt(a.n.sons[0])))
+      if a.n[0].intVal <= 0:
+        result = makeRange(a, 0, `|abs|`(getInt(a.n.sons[0])))
+      else:
+        result = makeRange(a, `|abs|`(getInt(a.n.sons[1])),
+                              `|abs|`(getInt(a.n.sons[0])))
   of mSucc:
     let a = n.sons[1].typ
     let b = n.sons[2].typ
@@ -197,18 +207,20 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
   of mSubI, mSubI64, mSubU:
     binaryOp(`|-|`)
   of mBitandI, mBitandI64:
+    # since uint64 is still not even valid for 'range' (since it's no ordinal
+    # yet), we exclude it from the list (see bug #1638) for now:
     var a = n.sons[1]
     var b = n.sons[2]
     # symmetrical:
-    if b.kind notin {nkIntLit..nkUInt64Lit}: swap(a, b)
-    if b.kind in {nkIntLit..nkUInt64Lit}:
+    if b.kind notin ordIntLit: swap(a, b)
+    if b.kind in ordIntLit:
       let x = b.intVal|+|1
       if (x and -x) == x and x >= 0:
         result = makeRange(a.typ, 0, b.intVal)
   of mModU:
     let a = n.sons[1]
     let b = n.sons[2]
-    if b.kind in {nkIntLit..nkUInt64Lit}:
+    if a.kind in ordIntLit:
       if b.intVal >= 0:
         result = makeRange(a.typ, 0, b.intVal-1)
       else:
@@ -224,12 +236,12 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
         result = makeRange(a.typ, b.intVal+1, -(b.intVal+1))
   of mDivI, mDivI64, mDivU:
     binaryOp(`|div|`)
-  of mMinI, mMinI64:
+  of mMinI:
     commutativeOp(min)
-  of mMaxI, mMaxI64:
+  of mMaxI:
     commutativeOp(max)
   else: discard
-  
+
 discard """
   mShlI, mShlI64,
   mShrI, mShrI64, mAddF64, mSubF64, mMulF64, mDivF64, mMaxF64, mMinF64
@@ -240,7 +252,7 @@ proc evalIs(n, a: PNode): PNode =
   internalAssert a.kind == nkSym and a.sym.kind == skType
   internalAssert n.sonsLen == 3 and
     n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
-  
+
   let t1 = a.sym.typ
 
   if n[2].kind in {nkStrLit..nkTripleStrLit}:
@@ -248,12 +260,12 @@ proc evalIs(n, a: PNode): PNode =
     of "closure":
       let t = skipTypes(t1, abstractRange)
       result = newIntNode(nkIntLit, ord(t.kind == tyProc and
-                                        t.callConv == ccClosure and 
+                                        t.callConv == ccClosure and
                                         tfIterator notin t.flags))
     of "iterator":
       let t = skipTypes(t1, abstractRange)
       result = newIntNode(nkIntLit, ord(t.kind == tyProc and
-                                        t.callConv == ccClosure and 
+                                        t.callConv == ccClosure and
                                         tfIterator in t.flags))
     else: discard
   else:
@@ -263,7 +275,7 @@ proc evalIs(n, a: PNode): PNode =
     result = newIntNode(nkIntLit, ord(match))
   result.typ = n.typ
 
-proc evalOp(m: TMagic, n, a, b, c: PNode): PNode = 
+proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
   # b and c may be nil
   result = nil
   case m
@@ -274,18 +286,19 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
   of mNot: result = newIntNodeT(1 - getInt(a), n)
   of mCard: result = newIntNodeT(nimsets.cardSet(a), n)
   of mBitnotI, mBitnotI64: result = newIntNodeT(not getInt(a), n)
-  of mLengthStr: result = newIntNodeT(len(getStr(a)), n)
+  of mLengthStr, mXLenStr: result = newIntNodeT(len(getStr(a)), n)
   of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n)
-  of mLengthSeq, mLengthOpenArray: result = newIntNodeT(sonsLen(a), n) # BUGFIX
-  of mUnaryPlusI, mUnaryPlusI64, mUnaryPlusF64: result = a # throw `+` away
-  of mToFloat, mToBiggestFloat: 
+  of mLengthSeq, mLengthOpenArray, mXLenSeq:
+    result = newIntNodeT(sonsLen(a), n) # BUGFIX
+  of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
+  of mToFloat, mToBiggestFloat:
     result = newFloatNodeT(toFloat(int(getInt(a))), n)
   of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n)
   of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n)
-  of mAbsI, mAbsI64: 
+  of mAbsI, mAbsI64:
     if getInt(a) >= 0: result = a
     else: result = newIntNodeT(- getInt(a), n)
-  of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64: 
+  of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64:
     # byte(-128) = 1...1..1000_0000'64 --> 0...0..1000_0000'64
     result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n)
   of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n)
@@ -297,21 +310,21 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
   of mAddI, mAddI64: result = newIntNodeT(getInt(a) + getInt(b), n)
   of mSubI, mSubI64: result = newIntNodeT(getInt(a) - getInt(b), n)
   of mMulI, mMulI64: result = newIntNodeT(getInt(a) * getInt(b), n)
-  of mMinI, mMinI64: 
+  of mMinI:
     if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n)
     else: result = newIntNodeT(getInt(a), n)
-  of mMaxI, mMaxI64: 
+  of mMaxI:
     if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n)
     else: result = newIntNodeT(getInt(b), n)
-  of mShlI, mShlI64: 
+  of mShlI, mShlI64:
     case skipTypes(n.typ, abstractRange).kind
     of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n)
     of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n)
     of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n)
-    of tyInt64, tyInt, tyUInt..tyUInt64: 
+    of tyInt64, tyInt, tyUInt..tyUInt64:
       result = newIntNodeT(`shl`(getInt(a), getInt(b)), n)
     else: internalError(n.info, "constant folding for shl")
-  of mShrI, mShrI64: 
+  of mShrI, mShrI64:
     case skipTypes(n.typ, abstractRange).kind
     of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n)
     of tyInt16: result = newIntNodeT(int16(getInt(a)) shr int16(getInt(b)), n)
@@ -330,34 +343,34 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
   of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
   of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n)
   of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n)
-  of mDivF64: 
-    if getFloat(b) == 0.0: 
+  of mDivF64:
+    if getFloat(b) == 0.0:
       if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n)
       else: result = newFloatNodeT(Inf, n)
-    else: 
+    else:
       result = newFloatNodeT(getFloat(a) / getFloat(b), n)
-  of mMaxF64: 
+  of mMaxF64:
     if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n)
     else: result = newFloatNodeT(getFloat(b), n)
-  of mMinF64: 
+  of mMinF64:
     if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n)
     else: result = newFloatNodeT(getFloat(a), n)
   of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n)
-  of mLtI, mLtI64, mLtB, mLtEnum, mLtCh: 
+  of mLtI, mLtI64, mLtB, mLtEnum, mLtCh:
     result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n)
-  of mLeI, mLeI64, mLeB, mLeEnum, mLeCh: 
+  of mLeI, mLeI64, mLeB, mLeEnum, mLeCh:
     result = newIntNodeT(ord(getOrdValue(a) <= getOrdValue(b)), n)
-  of mEqI, mEqI64, mEqB, mEqEnum, mEqCh: 
-    result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n) 
+  of mEqI, mEqI64, mEqB, mEqEnum, mEqCh:
+    result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n)
   of mLtF64: result = newIntNodeT(ord(getFloat(a) < getFloat(b)), n)
   of mLeF64: result = newIntNodeT(ord(getFloat(a) <= getFloat(b)), n)
-  of mEqF64: result = newIntNodeT(ord(getFloat(a) == getFloat(b)), n) 
+  of mEqF64: result = newIntNodeT(ord(getFloat(a) == getFloat(b)), n)
   of mLtStr: result = newIntNodeT(ord(getStr(a) < getStr(b)), n)
   of mLeStr: result = newIntNodeT(ord(getStr(a) <= getStr(b)), n)
   of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n)
-  of mLtU, mLtU64: 
+  of mLtU, mLtU64:
     result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n)
-  of mLeU, mLeU64: 
+  of mLeU, mLeU64:
     result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n)
   of mBitandI, mBitandI64, mAnd: result = newIntNodeT(a.getInt and b.getInt, n)
   of mBitorI, mBitorI64, mOr: result = newIntNodeT(getInt(a) or getInt(b), n)
@@ -375,18 +388,18 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
       result = newIntNodeT(`/%`(getInt(a), y), n)
   of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n)
   of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n)
-  of mLtSet: 
+  of mLtSet:
     result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n)
-  of mMulSet: 
+  of mMulSet:
     result = nimsets.intersectSets(a, b)
     result.info = n.info
-  of mPlusSet: 
+  of mPlusSet:
     result = nimsets.unionSets(a, b)
     result.info = n.info
-  of mMinusSet: 
+  of mMinusSet:
     result = nimsets.diffSets(a, b)
     result.info = n.info
-  of mSymDiffSet: 
+  of mSymDiffSet:
     result = nimsets.symdiffSets(a, b)
     result.info = n.info
   of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n)
@@ -395,104 +408,104 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
     # BUGFIX: we cannot eval mRepr here for reasons that I forgot.
     discard
   of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n)
-  of mBoolToStr: 
+  of mBoolToStr:
     if getOrdValue(a) == 0: result = newStrNodeT("false", n)
     else: result = newStrNodeT("true", n)
   of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n)
-  of mCopyStrLast: 
-    result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)), 
+  of mCopyStrLast:
+    result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)),
                                            int(getOrdValue(c))), n)
   of mFloatToStr: result = newStrNodeT($getFloat(a), n)
   of mCStrToStr, mCharToStr: result = newStrNodeT(getStrOrChar(a), n)
   of mStrToStr: result = a
   of mEnumToStr: result = newStrNodeT(ordinalValToString(a), n)
-  of mArrToSeq: 
+  of mArrToSeq:
     result = copyTree(a)
     result.typ = n.typ
   of mCompileOption:
-    result = newIntNodeT(ord(commands.testCompileOption(a.getStr, n.info)), n)  
+    result = newIntNodeT(ord(commands.testCompileOption(a.getStr, n.info)), n)
   of mCompileOptionArg:
     result = newIntNodeT(ord(
       testCompileOptionArg(getStr(a), getStr(b), n.info)), n)
-  of mNewString, mNewStringOfCap, 
-     mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh, 
-     mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq, 
-     mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait,
+  of mNewString, mNewStringOfCap,
+     mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh,
+     mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
+     mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait, mDotDot,
      mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn, mParallel:
     discard
   else: internalError(a.info, "evalOp(" & $m & ')')
-  
-proc getConstIfExpr(c: PSym, n: PNode): PNode = 
+
+proc getConstIfExpr(c: PSym, n: PNode): PNode =
   result = nil
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     var it = n.sons[i]
     if it.len == 2:
       var e = getConstExpr(c, it.sons[0])
       if e == nil: return nil
-      if getOrdValue(e) != 0: 
-        if result == nil: 
+      if getOrdValue(e) != 0:
+        if result == nil:
           result = getConstExpr(c, it.sons[1])
-          if result == nil: return 
+          if result == nil: return
     elif it.len == 1:
       if result == nil: result = getConstExpr(c, it.sons[0])
     else: internalError(it.info, "getConstIfExpr()")
 
-proc partialAndExpr(c: PSym, n: PNode): PNode = 
+proc partialAndExpr(c: PSym, n: PNode): PNode =
   # partial evaluation
   result = n
   var a = getConstExpr(c, n.sons[1])
   var b = getConstExpr(c, n.sons[2])
-  if a != nil: 
+  if a != nil:
     if getInt(a) == 0: result = a
     elif b != nil: result = b
     else: result = n.sons[2]
-  elif b != nil: 
+  elif b != nil:
     if getInt(b) == 0: result = b
     else: result = n.sons[1]
-  
-proc partialOrExpr(c: PSym, n: PNode): PNode = 
+
+proc partialOrExpr(c: PSym, n: PNode): PNode =
   # partial evaluation
   result = n
   var a = getConstExpr(c, n.sons[1])
   var b = getConstExpr(c, n.sons[2])
-  if a != nil: 
+  if a != nil:
     if getInt(a) != 0: result = a
     elif b != nil: result = b
     else: result = n.sons[2]
-  elif b != nil: 
+  elif b != nil:
     if getInt(b) != 0: result = b
     else: result = n.sons[1]
-  
-proc leValueConv(a, b: PNode): bool = 
+
+proc leValueConv(a, b: PNode): bool =
   result = false
   case a.kind
-  of nkCharLit..nkUInt64Lit: 
+  of nkCharLit..nkUInt64Lit:
     case b.kind
     of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal
     of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal)
     else: internalError(a.info, "leValueConv")
-  of nkFloatLit..nkFloat128Lit: 
+  of nkFloatLit..nkFloat128Lit:
     case b.kind
     of nkFloatLit..nkFloat128Lit: result = a.floatVal <= b.floatVal
     of nkCharLit..nkUInt64Lit: result = a.floatVal <= toFloat(int(b.intVal))
     else: internalError(a.info, "leValueConv")
   else: internalError(a.info, "leValueConv")
-  
+
 proc magicCall(m: PSym, n: PNode): PNode =
   if sonsLen(n) <= 1: return
 
   var s = n.sons[0].sym
   var a = getConstExpr(m, n.sons[1])
   var b, c: PNode
-  if a == nil: return 
-  if sonsLen(n) > 2: 
+  if a == nil: return
+  if sonsLen(n) > 2:
     b = getConstExpr(m, n.sons[2])
-    if b == nil: return 
-    if sonsLen(n) > 3: 
+    if b == nil: return
+    if sonsLen(n) > 3:
       c = getConstExpr(m, n.sons[3])
-      if c == nil: return 
+      if c == nil: return
   result = evalOp(s.magic, n, a, b, c)
-  
+
 proc getAppType(n: PNode): PNode =
   if gGlobalOptions.contains(optGenDynLib):
     result = newStrNodeT("lib", n)
@@ -508,48 +521,48 @@ proc rangeCheck(n: PNode, value: BiggestInt) =
     localError(n.info, errGenerated, "cannot convert " & $value &
                                      " to " & typeToString(n.typ))
 
-proc foldConv*(n, a: PNode; check = false): PNode = 
+proc foldConv*(n, a: PNode; check = false): PNode =
   # XXX range checks?
   case skipTypes(n.typ, abstractRange).kind
-  of tyInt..tyInt64: 
+  of tyInt..tyInt64, tyUInt..tyUInt64:
     case skipTypes(a.typ, abstractRange).kind
     of tyFloat..tyFloat64:
       result = newIntNodeT(int(getFloat(a)), n)
     of tyChar: result = newIntNodeT(getOrdValue(a), n)
-    else: 
+    else:
       result = a
       result.typ = n.typ
     if check: rangeCheck(n, result.intVal)
   of tyFloat..tyFloat64:
     case skipTypes(a.typ, abstractRange).kind
-    of tyInt..tyInt64, tyEnum, tyBool, tyChar: 
+    of tyInt..tyInt64, tyEnum, tyBool, tyChar:
       result = newFloatNodeT(toFloat(int(getOrdValue(a))), n)
     else:
       result = a
       result.typ = n.typ
-  of tyOpenArray, tyVarargs, tyProc: 
+  of tyOpenArray, tyVarargs, tyProc:
     discard
-  else: 
+  else:
     result = a
     result.typ = n.typ
-  
+
 proc getArrayConstr(m: PSym, n: PNode): PNode =
   if n.kind == nkBracket:
     result = n
   else:
     result = getConstExpr(m, n)
     if result == nil: result = n
-  
-proc foldArrayAccess(m: PSym, n: PNode): PNode = 
+
+proc foldArrayAccess(m: PSym, n: PNode): PNode =
   var x = getConstExpr(m, n.sons[0])
   if x == nil or x.typ.skipTypes({tyGenericInst}).kind == tyTypeDesc: return
-  
+
   var y = getConstExpr(m, n.sons[1])
   if y == nil: return
-  
+
   var idx = getOrdValue(y)
   case x.kind
-  of nkPar: 
+  of nkPar:
     if idx >= 0 and idx < sonsLen(x):
       result = x.sons[int(idx)]
       if result.kind == nkExprColonExpr: result = result.sons[1]
@@ -561,14 +574,14 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode =
     else: localError(n.info, errIndexOutOfBounds)
   of nkStrLit..nkTripleStrLit:
     result = newNodeIT(nkCharLit, x.info, n.typ)
-    if idx >= 0 and idx < len(x.strVal): 
+    if idx >= 0 and idx < len(x.strVal):
       result.intVal = ord(x.strVal[int(idx)])
-    elif idx == len(x.strVal): 
+    elif idx == len(x.strVal):
       discard
-    else: 
+    else:
       localError(n.info, errIndexOutOfBounds)
   else: discard
-  
+
 proc foldFieldAccess(m: PSym, n: PNode): PNode =
   # a real field access; proc calls have already been transformed
   var x = getConstExpr(m, n.sons[0])
@@ -582,15 +595,15 @@ proc foldFieldAccess(m: PSym, n: PNode): PNode =
       result = x.sons[field.position]
       if result.kind == nkExprColonExpr: result = result.sons[1]
       return
-    if it.sons[0].sym.name.id == field.name.id: 
+    if it.sons[0].sym.name.id == field.name.id:
       result = x.sons[i].sons[1]
       return
   localError(n.info, errFieldXNotFound, field.name.s)
-  
-proc foldConStrStr(m: PSym, n: PNode): PNode = 
+
+proc foldConStrStr(m: PSym, n: PNode): PNode =
   result = newNodeIT(nkStrLit, n.info, n.typ)
   result.strVal = ""
-  for i in countup(1, sonsLen(n) - 1): 
+  for i in countup(1, sonsLen(n) - 1):
     let a = getConstExpr(m, n.sons[i])
     if a == nil: return nil
     result.strVal.add(getStrOrChar(a))
@@ -600,10 +613,10 @@ proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode =
   result.typ = newType(tyTypeDesc, s.owner)
   result.typ.addSonSkipIntLit(s.typ)
 
-proc getConstExpr(m: PSym, n: PNode): PNode = 
+proc getConstExpr(m: PSym, n: PNode): PNode =
   result = nil
   case n.kind
-  of nkSym: 
+  of nkSym:
     var s = n.sym
     case s.kind
     of skEnumField:
@@ -634,14 +647,14 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
       else:
         result = newSymNodeTypeDesc(s, n.info)
     else: discard
-  of nkCharLit..nkNilLit: 
+  of nkCharLit..nkNilLit:
     result = copyNode(n)
-  of nkIfExpr: 
+  of nkIfExpr:
     result = getConstIfExpr(m, n)
-  of nkCall, nkCommand, nkCallStrLit, nkPrefix, nkInfix: 
-    if n.sons[0].kind != nkSym: return 
+  of nkCall, nkCommand, nkCallStrLit, nkPrefix, nkInfix:
+    if n.sons[0].kind != nkSym: return
     var s = n.sons[0].sym
-    if s.kind != skProc: return 
+    if s.kind != skProc: return
     try:
       case s.magic
       of mNone:
@@ -649,8 +662,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
         return
       of mSizeOf:
         var a = n.sons[1]
-        if computeSize(a.typ) < 0: 
-          localError(a.info, errCannotEvalXBecauseIncompletelyDefined, 
+        if computeSize(a.typ) < 0:
+          localError(a.info, errCannotEvalXBecauseIncompletelyDefined,
                      "sizeof")
           result = nil
         elif skipTypes(a.typ, typedescInst).kind in
@@ -660,21 +673,21 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
         else:
           result = nil
           # XXX: size computation for complex types is still wrong
-      of mLow: 
+      of mLow:
         result = newIntNodeT(firstOrd(n.sons[1].typ), n)
-      of mHigh: 
-        if  skipTypes(n.sons[1].typ, abstractVar).kind notin
-            {tyOpenArray, tyVarargs, tySequence, tyString}:
+      of mHigh:
+        if skipTypes(n.sons[1].typ, abstractVar).kind notin
+            {tySequence, tyString, tyCString, tyOpenArray, tyVarargs}:
           result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n)
         else:
           var a = getArrayConstr(m, n.sons[1])
           if a.kind == nkBracket:
-            # we can optimize it away: 
+            # we can optimize it away:
             result = newIntNodeT(sonsLen(a)-1, n)
       of mLengthOpenArray:
         var a = getArrayConstr(m, n.sons[1])
         if a.kind == nkBracket:
-          # we can optimize it away! This fixes the bug ``len(134)``. 
+          # we can optimize it away! This fixes the bug ``len(134)``.
           result = newIntNodeT(sonsLen(a), n)
         else:
           result = magicCall(m, n)
@@ -692,33 +705,33 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
           result = evalIs(n, a)
       else:
         result = magicCall(m, n)
-    except OverflowError: 
+    except OverflowError:
       localError(n.info, errOverOrUnderflow)
-    except DivByZeroError: 
+    except DivByZeroError:
       localError(n.info, errConstantDivisionByZero)
-  of nkAddr: 
+  of nkAddr:
     var a = getConstExpr(m, n.sons[0])
-    if a != nil: 
+    if a != nil:
       result = n
       n.sons[0] = a
-  of nkBracket: 
+  of nkBracket:
     result = copyTree(n)
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       var a = getConstExpr(m, n.sons[i])
       if a == nil: return nil
       result.sons[i] = a
     incl(result.flags, nfAllConst)
-  of nkRange: 
+  of nkRange:
     var a = getConstExpr(m, n.sons[0])
-    if a == nil: return 
+    if a == nil: return
     var b = getConstExpr(m, n.sons[1])
-    if b == nil: return 
+    if b == nil: return
     result = copyNode(n)
     addSon(result, a)
     addSon(result, b)
-  of nkCurly: 
+  of nkCurly:
     result = copyTree(n)
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       var a = getConstExpr(m, n.sons[i])
       if a == nil: return nil
       result.sons[i] = a
@@ -733,33 +746,33 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
   of nkPar:
     # tuple constructor
     result = copyTree(n)
-    if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr): 
-      for i in countup(0, sonsLen(n) - 1): 
+    if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr):
+      for i in countup(0, sonsLen(n) - 1):
         var a = getConstExpr(m, n.sons[i].sons[1])
         if a == nil: return nil
         result.sons[i].sons[1] = a
-    else: 
-      for i in countup(0, sonsLen(n) - 1): 
+    else:
+      for i in countup(0, sonsLen(n) - 1):
         var a = getConstExpr(m, n.sons[i])
         if a == nil: return nil
         result.sons[i] = a
     incl(result.flags, nfAllConst)
-  of nkChckRangeF, nkChckRange64, nkChckRange: 
+  of nkChckRangeF, nkChckRange64, nkChckRange:
     var a = getConstExpr(m, n.sons[0])
-    if a == nil: return 
-    if leValueConv(n.sons[1], a) and leValueConv(a, n.sons[2]): 
+    if a == nil: return
+    if leValueConv(n.sons[1], a) and leValueConv(a, n.sons[2]):
       result = a              # a <= x and x <= b
       result.typ = n.typ
-    else: 
+    else:
       localError(n.info, errGenerated, `%`(
-          msgKindToString(errIllegalConvFromXtoY), 
+          msgKindToString(errIllegalConvFromXtoY),
           [typeToString(n.sons[0].typ), typeToString(n.typ)]))
-  of nkStringToCString, nkCStringToString: 
+  of nkStringToCString, nkCStringToString:
     var a = getConstExpr(m, n.sons[0])
-    if a == nil: return 
+    if a == nil: return
     result = a
     result.typ = n.typ
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv: 
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
     var a = getConstExpr(m, n.sons[1])
     if a == nil: return
     result = foldConv(n, a, check=n.kind == nkHiddenStdConv)
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index 723789a31..db910600b 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -25,10 +25,23 @@ proc getIdentNode(n: PNode): PNode =
   else:
     illFormedAst(n)
     result = n
-  
+
+type
+  GenericCtx = object
+    toMixin: IntSet
+    cursorInBody: bool # only for nimsuggest
+
+type
+  TSemGenericFlag = enum
+    withinBind, withinTypeDesc, withinMixin
+  TSemGenericFlags = set[TSemGenericFlag]
+
+proc semGenericStmt(c: PContext, n: PNode,
+                    flags: TSemGenericFlags, ctx: var GenericCtx): PNode
+
 proc semGenericStmtScope(c: PContext, n: PNode, 
                          flags: TSemGenericFlags,
-                         ctx: var IntSet): PNode = 
+                         ctx: var GenericCtx): PNode = 
   openScope(c)
   result = semGenericStmt(c, n, flags, ctx)
   closeScope(c)
@@ -37,7 +50,8 @@ template macroToExpand(s: expr): expr =
   s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfImmediate in s.flags)
 
 proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
-                          ctx: var IntSet): PNode =
+                          ctx: var GenericCtx): PNode =
+  semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
   incl(s.flags, sfUsed)
   case s.kind
   of skUnknown:
@@ -48,7 +62,6 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
   of skTemplate:
     if macroToExpand(s):
       styleCheckUse(n.info, s)
-      let n = fixImmediateParams(n)
       result = semTemplateExpr(c, n, s, {efNoSemCheck})
       result = semGenericStmt(c, result, {}, ctx)
     else:
@@ -61,13 +74,20 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
     else:
       result = symChoice(c, n, s, scOpen)
   of skGenericParam: 
-    result = newSymNodeTypeDesc(s, n.info)
+    if s.typ != nil and s.typ.kind == tyStatic:
+      if s.typ.n != nil:
+        result = s.typ.n
+      else:
+        result = n
+    else:
+      result = newSymNodeTypeDesc(s, n.info)
     styleCheckUse(n.info, s)
   of skParam:
     result = n
     styleCheckUse(n.info, s)
   of skType: 
-    if (s.typ != nil) and (s.typ.kind != tyGenericParam): 
+    if (s.typ != nil) and
+       (s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}):
       result = newSymNodeTypeDesc(s, n.info)
     else: 
       result = n
@@ -77,17 +97,17 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
     styleCheckUse(n.info, s)
 
 proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, 
-            ctx: var IntSet): PNode =
+            ctx: var GenericCtx): PNode =
   result = n
   let ident = considerQuotedIdent(n)
   var s = searchInScopes(c, ident).skipAlias(n)
   if s == nil:
-    if ident.id notin ctx and withinMixin notin flags:
+    if ident.id notin ctx.toMixin and withinMixin notin flags:
       localError(n.info, errUndeclaredIdentifier, ident.s)
   else:
     if withinBind in flags:
       result = symChoice(c, n, s, scClosed)
-    elif s.name.id in ctx:
+    elif s.name.id in ctx.toMixin:
       result = symChoice(c, n, s, scForceOpen)
     else:
       result = semGenericStmtSymbol(c, n, s, ctx)
@@ -99,8 +119,10 @@ proc newDot(n, b: PNode): PNode =
   result.add(b)
 
 proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, 
-                 ctx: var IntSet; isMacro: var bool): PNode =
+                 ctx: var GenericCtx; isMacro: var bool): PNode =
   assert n.kind == nkDotExpr
+  semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
+
   let luf = if withinMixin notin flags: {checkUndeclared} else: {}
   
   var s = qualifiedLookUp(c, n, luf)
@@ -116,7 +138,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
       isMacro = s.kind in {skTemplate, skMacro}
       if withinBind in flags:
         result = newDot(result, symChoice(c, n, s, scClosed))
-      elif s.name.id in ctx:
+      elif s.name.id in ctx.toMixin:
         result = newDot(result, symChoice(c, n, s, scForceOpen))
       else:
         let sym = semGenericStmtSymbol(c, n, s, ctx)
@@ -131,9 +153,11 @@ proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
   styleCheckDef(n.info, s, kind)
 
 proc semGenericStmt(c: PContext, n: PNode, 
-                    flags: TSemGenericFlags, ctx: var IntSet): PNode =
+                    flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
   result = n
-  if gCmd == cmdIdeTools: suggestStmt(c, n)
+  #if gCmd == cmdIdeTools: suggestStmt(c, n)
+  semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
+
   case n.kind
   of nkIdent, nkAccQuoted:
     result = lookup(c, n, flags, ctx)
@@ -156,14 +180,15 @@ proc semGenericStmt(c: PContext, n: PNode,
   of nkBind:
     result = semGenericStmt(c, n.sons[0], flags+{withinBind}, ctx)
   of nkMixinStmt:
-    result = semMixinStmt(c, n, ctx)
+    result = semMixinStmt(c, n, ctx.toMixin)
   of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit: 
     # check if it is an expression macro:
     checkMinSonsLen(n, 1)
     let fn = n.sons[0]
     var s = qualifiedLookUp(c, fn, {})
     if s == nil and withinMixin notin flags and
-        fn.kind in {nkIdent, nkAccQuoted} and considerQuotedIdent(fn).id notin ctx:
+        fn.kind in {nkIdent, nkAccQuoted} and 
+        considerQuotedIdent(fn).id notin ctx.toMixin:
       localError(n.info, errUndeclaredIdentifier, fn.renderTree)
     
     var first = 0
@@ -171,7 +196,7 @@ proc semGenericStmt(c: PContext, n: PNode,
     if s != nil:
       incl(s.flags, sfUsed)
       mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles}
-      let scOption = if s.name.id in ctx: scForceOpen else: scOpen
+      let scOption = if s.name.id in ctx.toMixin: scForceOpen else: scOpen
       case s.kind
       of skMacro:
         if macroToExpand(s):
@@ -185,7 +210,6 @@ proc semGenericStmt(c: PContext, n: PNode,
       of skTemplate:
         if macroToExpand(s):
           styleCheckUse(fn.info, s)
-          let n = fixImmediateParams(n)
           result = semTemplateExpr(c, n, s, {efNoSemCheck})
           result = semGenericStmt(c, result, {}, ctx)
         else:
@@ -219,7 +243,7 @@ proc semGenericStmt(c: PContext, n: PNode,
     elif fn.kind == nkDotExpr:
       result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
       first = 1
-    # Consider 'when defined(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
+    # Consider 'when declared(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
     # in threads.nim: the subtle preprocessing here binds 'globalsSlot' which 
     # is not exported and yet the generic 'threadProcWrapper' works correctly.
     let flags = if mixinContext: flags+{withinMixin} else: flags
@@ -332,7 +356,7 @@ proc semGenericStmt(c: PContext, n: PNode,
         of nkIdent: a = n.sons[i]
         else: illFormedAst(n)
         addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
-  of nkObjectTy, nkTupleTy:
+  of nkObjectTy, nkTupleTy, nkTupleClassTy:
     discard
   of nkFormalParams:
     checkMinSonsLen(n, 1)
@@ -372,4 +396,9 @@ proc semGenericStmt(c: PContext, n: PNode,
   else:
     for i in countup(0, sonsLen(n) - 1): 
       result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
-  
+
+proc semGenericStmt(c: PContext, n: PNode): PNode =
+  var ctx: GenericCtx
+  ctx.toMixin = initIntset()
+  result = semGenericStmt(c, n, {}, ctx)
+  semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 2decb5d0b..f72e2dc5b 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -11,35 +11,37 @@
 # included from sem.nim
 
 proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
-                                 entry: var TInstantiation) = 
-  if n.kind != nkGenericParams: 
+                                 entry: var TInstantiation) =
+  if n.kind != nkGenericParams:
     internalError(n.info, "instantiateGenericParamList; no generic params")
   newSeq(entry.concreteTypes, n.len)
   for i, a in n.pairs:
-    if a.kind != nkSym: 
+    if a.kind != nkSym:
       internalError(a.info, "instantiateGenericParamList; no symbol")
     var q = a.sym
     if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
       continue
-    var s = newSym(skType, q.name, getCurrOwner(), q.info)
+    let symKind = if q.typ.kind == tyStatic: skConst else: skType
+    var s = newSym(symKind, q.name, getCurrOwner(), q.info)
     s.flags = s.flags + {sfUsed, sfFromGeneric}
     var t = PType(idTableGet(pt, q.typ))
     if t == nil:
       if tfRetType in q.typ.flags:
-        # keep the generic type and allow the return type to be bound 
+        # keep the generic type and allow the return type to be bound
         # later by semAsgn in return type inference scenario
         t = q.typ
       else:
         localError(a.info, errCannotInstantiateX, s.name.s)
         t = errorType(c)
-    elif t.kind == tyGenericParam: 
+    elif t.kind == tyGenericParam:
       localError(a.info, errCannotInstantiateX, q.name.s)
       t = errorType(c)
-    elif t.kind == tyGenericInvokation:
+    elif t.kind == tyGenericInvocation:
       #t = instGenericContainer(c, a, t)
       t = generateTypeInstance(c, pt, a, t)
       #t = ReplaceTypeVarsT(cl, t)
     s.typ = t
+    if t.kind == tyStatic: s.ast = t.n
     addDecl(c, s)
     entry.concreteTypes[i] = t
 
@@ -56,17 +58,17 @@ proc genericCacheGet(genericSym: PSym, entry: TInstantiation): PSym =
       if sameInstantiation(entry, inst[]):
         return inst.sym
 
-proc removeDefaultParamValues(n: PNode) = 
+proc removeDefaultParamValues(n: PNode) =
   # we remove default params, because they cannot be instantiated properly
   # and they are not needed anyway for instantiation (each param is already
   # provided).
   when false:
-    for i in countup(1, sonsLen(n)-1): 
+    for i in countup(1, sonsLen(n)-1):
       var a = n.sons[i]
       if a.kind != nkIdentDefs: IllFormedAst(a)
       var L = a.len
       if a.sons[L-1].kind != nkEmpty and a.sons[L-2].kind != nkEmpty:
-        # ``param: typ = defaultVal``. 
+        # ``param: typ = defaultVal``.
         # We don't need defaultVal for semantic checking and it's wrong for
         # ``cmp: proc (a, b: T): int = cmp``. Hm, for ``cmp = cmp`` that is
         # not possible... XXX We don't solve this issue here.
@@ -75,11 +77,12 @@ proc removeDefaultParamValues(n: PNode) =
 proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
   # we need to create a fresh set of gensym'ed symbols:
   if n.kind == nkSym and sfGenSym in n.sym.flags:
-    var x = PSym(idTableGet(symMap, n.sym))
+    let s = n.sym
+    var x = PSym(idTableGet(symMap, s))
     if x == nil:
-      x = copySym(n.sym, false)
+      x = copySym(s, false)
       x.owner = owner
-      idTablePut(symMap, n.sym, x)
+      idTablePut(symMap, s, x)
     n.sym = x
   else:
     for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, symMap)
@@ -94,16 +97,21 @@ proc addProcDecls(c: PContext, fn: PSym) =
     var param = fn.typ.n.sons[i].sym
     param.owner = fn
     addParamOrResult(c, param, fn.kind)
-  
+
   maybeAddResult(c, fn, fn.ast)
 
-proc instantiateBody(c: PContext, n: PNode, result: PSym) =
+proc instantiateBody(c: PContext, n, params: PNode, result: PSym) =
   if n.sons[bodyPos].kind != nkEmpty:
     inc c.inGenericInst
     # add it here, so that recursive generic procs are possible:
     var b = n.sons[bodyPos]
     var symMap: TIdTable
     initIdTable symMap
+    if params != nil:
+      for i in 1 .. <params.len:
+        let param = params[i].sym
+        if sfGenSym in param.flags:
+          idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym)
     freshGenSyms(b, result, symMap)
     b = semProcBody(c, b)
     b = hloBody(c, b)
@@ -120,13 +128,13 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
       openScope(c)
       var n = oldPrc.ast
       n.sons[bodyPos] = copyTree(s.getBody)
-      instantiateBody(c, n, oldPrc)
+      instantiateBody(c, n, nil, oldPrc)
       closeScope(c)
       popInfoContext()
 
-proc sideEffectsCheck(c: PContext, s: PSym) = 
+proc sideEffectsCheck(c: PContext, s: PSym) =
   if {sfNoSideEffect, sfSideEffect} * s.flags ==
-      {sfNoSideEffect, sfSideEffect}: 
+      {sfNoSideEffect, sfSideEffect}:
     localError(s.info, errXhasSideEffects, s.name.s)
 
 proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
@@ -154,36 +162,49 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
   # Alas, doing this here is probably not enough, because another
   # proc signature could appear in the params:
   # proc foo[T](a: proc (x: T, b: type(x.y))
-  #   
+  #
   # The solution would be to move this logic into semtypinst, but
   # at this point semtypinst have to become part of sem, because it
   # will need to use openScope, addDecl, etc.
   addDecl(c, prc)
-  
+
   pushInfoContext(info)
   var cl = initTypeVars(c, pt, info)
   var result = instCopyType(cl, prc.typ)
   let originalParams = result.n
   result.n = originalParams.shallowCopy
-  
+
   for i in 1 .. <result.len:
+    # twrong_field_caching requires these 'resetIdTable' calls:
+    if i > 1:
+      resetIdTable(cl.symMap)
+      resetIdTable(cl.localCache)
     result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
     propagateToOwner(result, result.sons[i])
-    let param = replaceTypeVarsN(cl, originalParams[i])
-    result.n.sons[i] = param
-    if param.kind == nkSym:
-      # XXX: this won't be true for void params
-      # implement pass-through of void params and
-      # the "sort by distance to point" container
+    internalAssert originalParams[i].kind == nkSym
+    when true:
+      let oldParam = originalParams[i].sym
+      let param = copySym(oldParam)
+      param.owner = prc
+      param.typ = result.sons[i]
+      param.ast = oldParam.ast.copyTree
+      # don't be lazy here and call replaceTypeVarsN(cl, originalParams[i])!
+      result.n.sons[i] = newSymNode(param)
+      addDecl(c, param)
+    else:
+      let param = replaceTypeVarsN(cl, originalParams[i])
+      result.n.sons[i] = param
       param.sym.owner = prc
-      addDecl(c, param.sym)
-    
+      addDecl(c, result.n.sons[i].sym)
+
+  resetIdTable(cl.symMap)
+  resetIdTable(cl.localCache)
   result.sons[0] = replaceTypeVarsT(cl, result.sons[0])
   result.n.sons[0] = originalParams[0].copyTree
-  
+
   eraseVoidParams(result)
   skipIntLiteralParams(result)
- 
+
   prc.typ = result
   maybeAddResult(c, prc, prc.ast)
   popInfoContext()
@@ -232,7 +253,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
       pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
     if isNil(n.sons[bodyPos]):
       n.sons[bodyPos] = copyTree(fn.getBody)
-    instantiateBody(c, n, result)
+    instantiateBody(c, n, fn.typ.n, result)
     sideEffectsCheck(c, result)
     paramsTypeCheck(c, result.typ)
   else:
diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim
index c685d602d..2ef7a54e7 100644
--- a/compiler/semmacrosanity.nim
+++ b/compiler/semmacrosanity.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index d6c420955..0a7846f1d 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -10,10 +10,24 @@
 # This include file implements the semantic checking for magics.
 # included from sem.nim
 
+proc semAddr(c: PContext; n: PNode): PNode =
+  result = newNodeI(nkAddr, n.info)
+  let x = semExprWithType(c, n)
+  if isAssignable(c, x) notin {arLValue, arLocalLValue}:
+    localError(n.info, errExprHasNoAddress)
+  result.add x
+  result.typ = makePtrType(c, x.typ)
+
+proc semTypeOf(c: PContext; n: PNode): PNode =
+  result = newNodeI(nkTypeOfExpr, n.info)
+  let typExpr = semExprWithType(c, n, {efInTypeof})
+  result.add typExpr
+  result.typ = makeTypeDesc(c, typExpr.typ.skipTypes({tyTypeDesc, tyIter}))
+
 proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode =
   var r = isPartOf(n[1], n[2])
   result = newIntNodeT(ord(r), n)
-  
+
 proc expectIntLit(c: PContext, n: PNode): int =
   let x = c.semConstExpr(c, n)
   case x.kind
@@ -31,7 +45,7 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
   line.intVal = toLinenumber(info)
   result.add(filename)
   result.add(line)
- 
+
 proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
   let typ = operand.skipTypes({tyTypeDesc})
   case trait.sym.name.s.normalize
@@ -40,7 +54,7 @@ proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
     result.typ = newType(tyString, context)
     result.info = trait.info
   of "arity":
-    result = newIntNode(nkIntLit, typ.n.len-1)
+    result = newIntNode(nkIntLit, typ.len - ord(typ.kind==tyProc))
     result.typ = newType(tyInt, context)
     result.info = trait.info
   else:
@@ -66,18 +80,18 @@ proc semOrd(c: PContext, n: PNode): PNode =
 proc semBindSym(c: PContext, n: PNode): PNode =
   result = copyNode(n)
   result.add(n.sons[0])
-  
+
   let sl = semConstExpr(c, n.sons[1])
-  if sl.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}: 
+  if sl.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
     localError(n.sons[1].info, errStringLiteralExpected)
     return errorNode(c, n)
-  
+
   let isMixin = semConstExpr(c, n.sons[2])
   if isMixin.kind != nkIntLit or isMixin.intVal < 0 or
       isMixin.intVal > high(TSymChoiceRule).int:
     localError(n.sons[2].info, errConstExprExpected)
     return errorNode(c, n)
-  
+
   let id = newIdentNode(getIdent(sl.strVal), n.info)
   let s = qualifiedLookUp(c, id)
   if s != nil:
@@ -87,38 +101,28 @@ proc semBindSym(c: PContext, n: PNode): PNode =
   else:
     localError(n.sons[1].info, errUndeclaredIdentifier, sl.strVal)
 
-proc semLocals(c: PContext, n: PNode): PNode =
-  var counter = 0
-  var tupleType = newTypeS(tyTuple, c)
-  result = newNodeIT(nkPar, n.info, tupleType)
-  tupleType.n = newNodeI(nkRecList, n.info)
-  # for now we skip openarrays ...
-  for scope in walkScopes(c.currentScope):
-    if scope == c.topLevelScope: break
-    for it in items(scope.symbols):
-      # XXX parameters' owners are wrong for generics; this caused some pain
-      # for closures too; we should finally fix it.
-      #if it.owner != c.p.owner: return result
-      if it.kind in skLocalVars and
-          it.typ.skipTypes({tyGenericInst, tyVar}).kind notin
-            {tyVarargs, tyOpenArray, tyTypeDesc, tyStatic, tyExpr, tyStmt, tyEmpty}:
-
-        var field = newSym(skField, it.name, getCurrOwner(), n.info)
-        field.typ = it.typ.skipTypes({tyGenericInst, tyVar})
-        field.position = counter
-        inc(counter)
-
-        addSon(tupleType.n, newSymNode(field))
-        addSonSkipIntLit(tupleType, field.typ)
-        
-        var a = newSymNode(it, result.info)
-        if it.typ.skipTypes({tyGenericInst}).kind == tyVar: a = newDeref(a)
-        result.add(a)
-
 proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode
-proc magicsAfterOverloadResolution(c: PContext, n: PNode, 
+
+proc isStrangeArray(t: PType): bool =
+  let t = t.skipTypes(abstractInst)
+  result = t.kind == tyArray and t.firstOrd != 0
+
+proc isNegative(n: PNode): bool =
+  let n = n.skipConv
+  if n.kind in {nkCharLit..nkUInt64Lit}:
+    result = n.intVal < 0
+  elif n.kind in nkCallKinds and n.sons[0].kind == nkSym:
+    result = n.sons[0].sym.magic in {mUnaryMinusI, mUnaryMinusI64}
+
+proc magicsAfterOverloadResolution(c: PContext, n: PNode,
                                    flags: TExprFlags): PNode =
   case n[0].sym.magic
+  of mAddr:
+    checkSonsLen(n, 2)
+    result = semAddr(c, n.sons[1])
+  of mTypeOf:
+    checkSonsLen(n, 2)
+    result = semTypeOf(c, n.sons[1])
   of mIsPartOf: result = semIsPartOf(c, n, flags)
   of mTypeTrait: result = semTypeTraits(c, n)
   of mAstToStr:
@@ -129,8 +133,45 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
   of mHigh, mLow: result = semLowHigh(c, n, n[0].sym.magic)
   of mShallowCopy: result = semShallowCopy(c, n, flags)
   of mNBindSym: result = semBindSym(c, n)
-  of mLocals: result = semLocals(c, n)
   of mProcCall:
     result = n
     result.typ = n[1].typ
+  of mDotDot:
+    result = n
+    # disallow negative indexing for now:
+    if not c.p.bracketExpr.isNil:
+      if isNegative(n.sons[1]) or (n.len > 2 and isNegative(n.sons[2])):
+        localError(n.info, "use '^' instead of '-'; negative indexing is obsolete")
+  of mRoof:
+    # error correction:
+    result = n.sons[1]
+    if c.p.bracketExpr.isNil:
+      localError(n.info, "no surrounding array access context for '^'")
+    elif c.p.bracketExpr.checkForSideEffects != seNoSideEffect:
+      localError(n.info, "invalid context for '^' as '$#' has side effects" %
+        renderTree(c.p.bracketExpr))
+    elif c.p.bracketExpr.typ.isStrangeArray:
+      localError(n.info, "invalid context for '^' as len!=high+1 for '$#'" %
+        renderTree(c.p.bracketExpr))
+    else:
+      # ^x  is rewritten to: len(a)-x
+      let lenExpr = newNodeI(nkCall, n.info)
+      lenExpr.add newIdentNode(getIdent"len", n.info)
+      lenExpr.add c.p.bracketExpr
+      let lenExprB = semExprWithType(c, lenExpr)
+      if lenExprB.typ.isNil or not isOrdinalType(lenExprB.typ):
+        localError(n.info, "'$#' has to be of an ordinal type for '^'" %
+          renderTree(lenExpr))
+      else:
+        result = newNodeIT(nkCall, n.info, getSysType(tyInt))
+        result.add newSymNode(createMagic("-", mSubI), n.info)
+        result.add lenExprB
+        result.add n.sons[1]
+  of mPlugin:
+    let plugin = getPlugin(n[0].sym)
+    if plugin.isNil:
+      localError(n.info, "cannot find plugin " & n[0].sym.name.s)
+      result = n
+    else:
+      result = plugin(c, n)
   else: result = n
diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim
index c4546f616..fbcd6b6da 100644
--- a/compiler/semparallel.nim
+++ b/compiler/semparallel.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -37,7 +37,7 @@ is valid, but
   spawn f(a[i])
   spawn f(a[i])
   inc i
-is not! However, 
+is not! However,
   spawn f(a[i])
   if guard: inc i
   spawn f(a[i])
@@ -258,14 +258,18 @@ proc min(a, b: PNode): PNode =
 
 proc fromSystem(op: PSym): bool = sfSystemModule in getModule(op).flags
 
+template pushSpawnId(c: expr, body: stmt) {.immediate, dirty.} =
+  inc c.spawns
+  let oldSpawnId = c.currentSpawnId
+  c.currentSpawnId = c.spawns
+  body
+  c.currentSpawnId = oldSpawnId
+
 proc analyseCall(c: var AnalysisCtx; n: PNode; op: PSym) =
   if op.magic == mSpawn:
-    inc c.spawns
-    let oldSpawnId = c.currentSpawnId
-    c.currentSpawnId = c.spawns
-    gatherArgs(c, n[1])
-    analyseSons(c, n)
-    c.currentSpawnId = oldSpawnId
+    pushSpawnId(c):
+      gatherArgs(c, n[1])
+      analyseSons(c, n)
   elif op.magic == mInc or (op.name.s == "+=" and op.fromSystem):
     if n[1].isLocal:
       let incr = n[2].skipConv
@@ -313,8 +317,9 @@ proc analyseIf(c: var AnalysisCtx; n: PNode) =
 proc analyse(c: var AnalysisCtx; n: PNode) =
   case n.kind
   of nkAsgn, nkFastAsgn:
-    if n[0].isSingleAssignable and n[1].isLocal:
-      let slot = c.getSlot(n[1].sym)
+    let y = n[1].skipConv
+    if n[0].isSingleAssignable and y.isLocal:
+      let slot = c.getSlot(y.sym)
       slot.alias = n[0].sym
     elif n[0].isLocal:
       # since we already ensure sfAddrTaken is not in s.flags, we only need to
@@ -322,8 +327,15 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
       let slot = c.getSlot(n[0].sym)
       slot.blacklisted = true
     invalidateFacts(c.guards, n[0])
-    analyseSons(c, n)
-    addAsgnFact(c.guards, n[0], n[1])
+    let value = n[1]
+    if getMagic(value) == mSpawn:
+      pushSpawnId(c):
+        gatherArgs(c, value[1])
+        analyseSons(c, value[1])
+        analyse(c, n[0])
+    else:
+      analyseSons(c, n)
+    addAsgnFact(c.guards, n[0], y)
   of nkCallKinds:
     # direct call:
     if n[0].kind == nkSym: analyseCall(c, n, n[0].sym)
@@ -338,13 +350,18 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
   of nkVarSection, nkLetSection:
     for it in n:
       let value = it.lastSon
+      let isSpawned = getMagic(value) == mSpawn
+      if isSpawned:
+        pushSpawnId(c):
+          gatherArgs(c, value[1])
+          analyseSons(c, value[1])
       if value.kind != nkEmpty:
         for j in 0 .. it.len-3:
           if it[j].isLocal:
             let slot = c.getSlot(it[j].sym)
             if slot.lower.isNil: slot.lower = value
             else: internalError(it.info, "slot already has a lower bound")
-        analyse(c, value)
+        if not isSpawned: analyse(c, value)
   of nkCaseStmt: analyseCase(c, n)
   of nkIfStmt, nkIfExpr: analyseIf(c, n)
   of nkWhileStmt:
@@ -444,7 +461,7 @@ proc liftParallel*(owner: PSym; n: PNode): PNode =
   # - detect used slices
   # - detect used arguments
   #echo "PAR ", renderTree(n)
-  
+
   var a = initAnalysisCtx()
   let body = n.lastSon
   analyse(a, body)
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index f41e169e3..6bc0fa32c 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -1,19 +1,19 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
 import
-  intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees, 
+  intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
   wordrecg, strutils, options, guards
 
 # Second semantic checking pass over the AST. Necessary because the old
 # way had some inherent problems. Performs:
-# 
+#
 # * effect+exception tracking
 # * "usage before definition" checking
 # * checks for invalid usages of compiletime magics (not implemented)
@@ -23,7 +23,7 @@ import
 # Predefined effects:
 #   io, time (time dependent), gc (performs GC'ed allocation), exceptions,
 #   side effect (accesses global), store (stores into *type*),
-#   store_unkown (performs some store) --> store(any)|store(x) 
+#   store_unknown (performs some store) --> store(any)|store(x)
 #   load (loads from *type*), recursive (recursive call), unsafe,
 #   endless (has endless loops), --> user effects are defined over *patterns*
 #   --> a TR macro can annotate the proc with user defined annotations
@@ -31,31 +31,31 @@ import
 
 # Load&Store analysis is performed on *paths*. A path is an access like
 # obj.x.y[i].z; splitting paths up causes some problems:
-# 
+#
 # var x = obj.x
 # var z = x.y[i].z
 #
 # Alias analysis is affected by this too! A good solution is *type splitting*:
-# T becomes T1 and T2 if it's known that T1 and T2 can't alias. 
-# 
+# T becomes T1 and T2 if it's known that T1 and T2 can't alias.
+#
 # An aliasing problem and a race condition are effectively the same problem.
 # Type based alias analysis is nice but not sufficient; especially splitting
 # an array and filling it in parallel should be supported but is not easily
 # done: It essentially requires a built-in 'indexSplit' operation and dependent
 # typing.
-  
+
 # ------------------------ exception and tag tracking -------------------------
 
 discard """
   exception tracking:
-  
+
   a() # raises 'x', 'e'
   try:
     b() # raises 'e'
   except e:
     # must not undo 'e' here; hrm
     c()
- 
+
  --> we need a stack of scopes for this analysis
 
   # XXX enhance the algorithm to care about 'dirty' expressions:
@@ -138,7 +138,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
   if g.kind == skUnknown:
     var field: PSym = nil
     var ty = n.sons[0].typ.skipTypes(abstractPtrs)
-    if ty.kind == tyTuple:
+    if ty.kind == tyTuple and not ty.n.isNil:
       field = lookupInRecord(ty.n, g.name)
     else:
       while ty != nil and ty.kind == tyObject:
@@ -194,6 +194,39 @@ proc warnAboutGcUnsafe(n: PNode) =
   #assert false
   message(n.info, warnGcUnsafe, renderTree(n))
 
+proc markGcUnsafe(a: PEffects; reason: PSym) =
+  a.gcUnsafe = true
+  if a.owner.kind in routineKinds: a.owner.gcUnsafetyReason = reason
+
+proc markGcUnsafe(a: PEffects; reason: PNode) =
+  a.gcUnsafe = true
+  if a.owner.kind in routineKinds:
+    if reason.kind == nkSym:
+      a.owner.gcUnsafetyReason = reason.sym
+    else:
+      a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"),
+                                        a.owner, reason.info)
+
+proc listGcUnsafety(s: PSym; onlyWarning: bool) =
+  let u = s.gcUnsafetyReason
+  if u != nil:
+    let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated
+    if u.kind in {skLet, skVar}:
+      message(s.info, msgKind,
+        ("'$#' is not GC-safe as it accesses '$#'" &
+        " which is a global using GC'ed memory") % [s.name.s, u.name.s])
+    elif u.kind in routineKinds:
+      # recursive call *always* produces only a warning so the full error
+      # message is printed:
+      listGcUnsafety(u, true)
+      message(s.info, msgKind,
+        "'$#' is not GC-safe as it calls '$#'" %
+        [s.name.s, u.name.s])
+    else:
+      internalAssert u.kind == skUnknown
+      message(u.info, msgKind,
+        "'$#' is not GC-safe as it performs an indirect call here" % s.name.s)
+
 proc useVar(a: PEffects, n: PNode) =
   let s = n.sym
   if isLocalVar(a, s):
@@ -206,10 +239,9 @@ proc useVar(a: PEffects, n: PNode) =
       a.init.add s.id
   if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind in {skVar, skLet}:
     if s.guard != nil: guardGlobal(a, n, s.guard)
-    if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and 
-        tfGcSafe notin s.typ.flags:
-      if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
-      a.gcUnsafe = true
+    if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem):
+      #if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
+      markGcUnsafe(a, s)
 
 type
   TIntersection = seq[tuple[id, count: int]] # a simple count table
@@ -230,7 +262,7 @@ proc getEbase(): PType =
 
 proc excType(n: PNode): PType =
   # reraise is like raising E_Base:
-  let t = if n.kind == nkEmpty: getEbase() else: n.typ
+  let t = if n.kind == nkEmpty or n.typ.isNil: getEbase() else: n.typ
   result = skipTypes(t, skipPtrs)
 
 proc createRaise(n: PNode): PNode =
@@ -318,7 +350,7 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
   dec tracked.inTryStmt
   for i in oldState.. <tracked.init.len:
     addToIntersection(inter, tracked.init[i])
-  
+
   var branches = 1
   var hasFinally = false
   for i in 1 .. < n.len:
@@ -342,7 +374,7 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
       setLen(tracked.init, oldState)
       track(tracked, b.sons[blen-1])
       hasFinally = true
-      
+
   tracked.bottom = oldBottom
   if not hasFinally:
     setLen(tracked.init, oldState)
@@ -353,7 +385,7 @@ proc isIndirectCall(n: PNode, owner: PSym): bool =
   # we don't count f(...) as an indirect call if 'f' is an parameter.
   # Instead we track expressions of type tyProc too. See the manual for
   # details:
-  if n.kind != nkSym: 
+  if n.kind != nkSym:
     result = true
   elif n.sym.kind == skParam:
     result = owner != n.sym.owner or owner == nil
@@ -363,14 +395,14 @@ proc isIndirectCall(n: PNode, owner: PSym): bool =
 proc isForwardedProc(n: PNode): bool =
   result = n.kind == nkSym and sfForward in n.sym.flags
 
-proc trackPragmaStmt(tracked: PEffects, n: PNode) = 
-  for i in countup(0, sonsLen(n) - 1): 
+proc trackPragmaStmt(tracked: PEffects, n: PNode) =
+  for i in countup(0, sonsLen(n) - 1):
     var it = n.sons[i]
     if whichPragma(it) == wEffects:
       # list the computed effects up to here:
       listEffects(tracked)
-      
-proc effectSpec(n: PNode, effectType = wRaises): PNode =
+
+proc effectSpec(n: PNode, effectType: TSpecialWord): PNode =
   for i in countup(0, sonsLen(n) - 1):
     var it = n.sons[i]
     if it.kind == nkExprColonExpr and whichPragma(it) == effectType:
@@ -380,17 +412,16 @@ proc effectSpec(n: PNode, effectType = wRaises): PNode =
         result.add(it.sons[1])
       return
 
-proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int) =
-  var x = x
+proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int): PNode =
   let spec = effectSpec(x, effectType)
   if isNil(spec):
     let s = n.sons[namePos].sym
-    
+
     let actual = s.typ.n.sons[0]
     if actual.len != effectListLen: return
     let real = actual.sons[idx]
-    
-    # warning: hack ahead: 
+
+    # warning: hack ahead:
     var effects = newNodeI(nkBracket, n.info, real.len)
     for i in 0 .. <real.len:
       var t = typeToString(real[i].typ)
@@ -399,18 +430,20 @@ proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int) =
       # set the type so that the following analysis doesn't screw up:
       effects.sons[i].typ = real[i].typ
 
-    var pair = newNode(nkExprColonExpr, n.info, @[
+    result = newNode(nkExprColonExpr, n.info, @[
       newIdentNode(getIdent(specialWords[effectType]), n.info), effects])
-    
-    if x.kind == nkEmpty:
-      x = newNodeI(nkPragma, n.info)
-      n.sons[pragmasPos] = x
-    x.add(pair)
 
 proc documentRaises*(n: PNode) =
   if n.sons[namePos].kind != nkSym: return
-  documentEffect(n, n.sons[pragmasPos], wRaises, exceptionEffects)
-  documentEffect(n, n.sons[pragmasPos], wTags, tagEffects)
+  let pragmas = n.sons[pragmasPos]
+  let p1 = documentEffect(n, pragmas, wRaises, exceptionEffects)
+  let p2 = documentEffect(n, pragmas, wTags, tagEffects)
+
+  if p1 != nil or p2 != nil:
+    if pragmas.kind == nkEmpty:
+      n.sons[pragmasPos] = newNodeI(nkPragma, n.info)
+    if p1 != nil: n.sons[pragmasPos].add p1
+    if p2 != nil: n.sons[pragmasPos].add p2
 
 template notGcSafe(t): expr = {tfGcSafe, tfNoSideEffect} * t.flags == {}
 
@@ -441,28 +474,28 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
   let pragma = s.ast.sons[pragmasPos]
   let spec = effectSpec(pragma, wRaises)
   mergeEffects(tracked, spec, n)
-  
+
   let tagSpec = effectSpec(pragma, wTags)
   mergeTags(tracked, tagSpec, n)
 
   if notGcSafe(s.typ) and sfImportc notin s.flags:
     if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
-    tracked.gcUnsafe = true
+    markGcUnsafe(tracked, s)
   mergeLockLevels(tracked, n, s.getLockLevel)
 
 proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
   let n = n.skipConv
-  if paramType != nil and tfNotNil in paramType.flags and 
+  if paramType != nil and tfNotNil in paramType.flags and
       n.typ != nil and tfNotNil notin n.typ.flags:
     if n.kind == nkAddr:
       # addr(x[]) can't be proven, but addr(x) can:
       if not containsNode(n, {nkDerefExpr, nkHiddenDeref}): return
-    elif n.kind == nkSym and n.sym.kind in routineKinds:
+    elif (n.kind == nkSym and n.sym.kind in routineKinds) or n.kind in procDefs:
       # 'p' is not nil obviously:
       return
     case impliesNotNil(tracked.guards, n)
     of impUnknown:
-      message(n.info, errGenerated, 
+      message(n.info, errGenerated,
               "cannot prove '$1' is not nil" % n.renderTree)
     of impNo:
       message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree)
@@ -501,19 +534,19 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
       # assume GcUnsafe unless in its type; 'forward' does not matter:
       if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
         if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
-        tracked.gcUnsafe = true
+        markGcUnsafe(tracked, a)
     else:
       mergeEffects(tracked, effectList.sons[exceptionEffects], n)
       mergeTags(tracked, effectList.sons[tagEffects], n)
       if notGcSafe(op):
         if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
-        tracked.gcUnsafe = true
+        markGcUnsafe(tracked, a)
   notNilCheck(tracked, n, paramType)
 
 proc breaksBlock(n: PNode): bool =
   case n.kind
   of nkStmtList, nkStmtListExpr:
-    for c in n: 
+    for c in n:
       if breaksBlock(c): return true
   of nkBreakStmt, nkReturnStmt, nkRaiseStmt:
     return true
@@ -541,7 +574,7 @@ proc trackCase(tracked: PEffects, n: PNode) =
     if not breaksBlock(branch.lastSon): inc toCover
     for i in oldState.. <tracked.init.len:
       addToIntersection(inter, tracked.init[i])
-    
+
   let exh = case skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}).kind
             of tyFloat..tyFloat128, tyString:
               lastSon(n).kind == nkElse
@@ -586,7 +619,7 @@ proc trackIf(tracked: PEffects, n: PNode) =
       if count >= toCover: tracked.init.add id
     # else we can't merge as it is not exhaustive
   setLen(tracked.guards, oldFacts)
-  
+
 proc trackBlock(tracked: PEffects, n: PNode) =
   if n.kind in {nkStmtList, nkStmtListExpr}:
     var oldState = -1
@@ -621,7 +654,8 @@ proc track(tracked: PEffects, n: PNode) =
     useVar(tracked, n)
   of nkRaiseStmt:
     n.sons[0].info = n.info
-    throws(tracked.exc, n.sons[0])
+    #throws(tracked.exc, n.sons[0])
+    addEffect(tracked, n.sons[0], useLineInfo=false)
     for i in 0 .. <safeLen(n):
       track(tracked, n.sons[i])
   of nkCallKinds:
@@ -654,7 +688,7 @@ proc track(tracked: PEffects, n: PNode) =
           # and it's not a recursive call:
           if not (a.kind == nkSym and a.sym == tracked.owner):
             warnAboutGcUnsafe(n)
-            tracked.gcUnsafe = true
+            markGcUnsafe(tracked, a)
     for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i))
     if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
       # may not look like an assignment, but it is:
@@ -680,8 +714,8 @@ proc track(tracked: PEffects, n: PNode) =
   of nkVarSection, nkLetSection:
     for child in n:
       let last = lastSon(child)
+      if last.kind != nkEmpty: track(tracked, last)
       if child.kind == nkIdentDefs and last.kind != nkEmpty:
-        track(tracked, last)
         for i in 0 .. child.len-3:
           initVar(tracked, child.sons[i], volatileCheck=false)
           addAsgnFact(tracked.guards, child.sons[i], last)
@@ -730,7 +764,7 @@ proc track(tracked: PEffects, n: PNode) =
     setLen(tracked.locked, oldLocked)
     tracked.currLockLevel = oldLockLevel
   of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
-      nkMacroDef, nkTemplateDef:
+      nkMacroDef, nkTemplateDef, nkLambda, nkDo:
     discard
   else:
     for i in 0 .. <safeLen(n): track(tracked, n.sons[i])
@@ -777,7 +811,7 @@ proc checkMethodEffects*(disp, branch: PSym) =
     checkRaisesSpec(tagsSpec, actual.sons[tagEffects],
       "can have an unlisted effect: ", hints=off, subtypeRelation)
   if sfThread in disp.flags and notGcSafe(branch.typ):
-    localError(branch.info, "base method is GC-safe, but '$1' is not" % 
+    localError(branch.info, "base method is GC-safe, but '$1' is not" %
                                 branch.name.s)
   if branch.typ.lockLevel > disp.typ.lockLevel:
     when true:
@@ -809,21 +843,21 @@ proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
   newSeq(effects.sons, effectListLen)
   effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info)
   effects.sons[tagEffects] = newNodeI(nkArgList, s.info)
-  
+
   t.exc = effects.sons[exceptionEffects]
   t.tags = effects.sons[tagEffects]
   t.owner = s
   t.init = @[]
   t.guards = @[]
   t.locked = @[]
-  
+
 proc trackProc*(s: PSym, body: PNode) =
   var effects = s.typ.n.sons[0]
   internalAssert effects.kind == nkEffectList
   # effects already computed?
   if sfForward in s.flags: return
   if effects.len == effectListLen: return
-  
+
   var t: TEffects
   initEffects(effects, s, t)
   track(t, body)
@@ -847,19 +881,22 @@ proc trackProc*(s: PSym, body: PNode) =
     # after the check, use the formal spec:
     effects.sons[tagEffects] = tagsSpec
 
-  if optThreadAnalysis in gGlobalOptions:
-    if sfThread in s.flags and t.gcUnsafe:
-      if optThreads in gGlobalOptions:
-        localError(s.info, "'$1' is not GC-safe" % s.name.s)
-      else:
-        localError(s.info, warnGcUnsafe2, s.name.s)
-    if not t.gcUnsafe: s.typ.flags.incl tfGcSafe
-    if s.typ.lockLevel == UnspecifiedLockLevel:
-      s.typ.lockLevel = t.maxLockLevel
-    elif t.maxLockLevel > s.typ.lockLevel:
-      localError(s.info,
-        "declared lock level is $1, but real lock level is $2" %
-          [$s.typ.lockLevel, $t.maxLockLevel])
+  if sfThread in s.flags and t.gcUnsafe:
+    if optThreads in gGlobalOptions and optThreadAnalysis in gGlobalOptions:
+      #localError(s.info, "'$1' is not GC-safe" % s.name.s)
+      listGcUnsafety(s, onlyWarning=false)
+    else:
+      listGcUnsafety(s, onlyWarning=true)
+      #localError(s.info, warnGcUnsafe2, s.name.s)
+  if not t.gcUnsafe:
+    s.typ.flags.incl tfGcSafe
+  if s.typ.lockLevel == UnspecifiedLockLevel:
+    s.typ.lockLevel = t.maxLockLevel
+  elif t.maxLockLevel > s.typ.lockLevel:
+    #localError(s.info,
+    message(s.info, warnLockLevel,
+      "declared lock level is $1, but real lock level is $2" %
+        [$s.typ.lockLevel, $t.maxLockLevel])
 
 proc trackTopLevelStmt*(module: PSym; n: PNode) =
   if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef,
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 933ac7daf..c355a5bf1 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -12,13 +12,13 @@
 
 var enforceVoidContext = PType(kind: tyStmt)
 
-proc semDiscard(c: PContext, n: PNode): PNode = 
+proc semDiscard(c: PContext, n: PNode): PNode =
   result = n
   checkSonsLen(n, 1)
   if n.sons[0].kind != nkEmpty:
     n.sons[0] = semExprWithType(c, n.sons[0])
     if isEmptyType(n.sons[0].typ): localError(n.info, errInvalidDiscard)
-  
+
 proc semBreakOrContinue(c: PContext, n: PNode): PNode =
   result = n
   checkSonsLen(n, 1)
@@ -29,7 +29,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
       of nkIdent: s = lookUp(c, n.sons[0])
       of nkSym: s = n.sons[0].sym
       else: illFormedAst(n)
-      if s.kind == skLabel and s.owner.id == c.p.owner.id: 
+      if s.kind == skLabel and s.owner.id == c.p.owner.id:
         var x = newSymNode(s)
         x.info = n.info
         incl(s.flags, sfUsed)
@@ -41,16 +41,16 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
     else:
       localError(n.info, errGenerated, "'continue' cannot have a label")
   elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
-    localError(n.info, errInvalidControlFlowX, 
+    localError(n.info, errInvalidControlFlowX,
                renderTree(n, {renderNoComments}))
 
-proc semAsm(con: PContext, n: PNode): PNode = 
+proc semAsm(con: PContext, n: PNode): PNode =
   checkSonsLen(n, 2)
   var marker = pragmaAsm(con, n.sons[0])
   if marker == '\0': marker = '`' # default marker
   result = semAsmOrEmit(con, n, marker)
-  
-proc semWhile(c: PContext, n: PNode): PNode = 
+
+proc semWhile(c: PContext, n: PNode): PNode =
   result = n
   checkSonsLen(n, 2)
   openScope(c)
@@ -62,16 +62,16 @@ proc semWhile(c: PContext, n: PNode): PNode =
   if n.sons[1].typ == enforceVoidContext:
     result.typ = enforceVoidContext
 
-proc toCover(t: PType): BiggestInt = 
+proc toCover(t: PType): BiggestInt =
   var t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
-  if t2.kind == tyEnum and enumHasHoles(t2): 
+  if t2.kind == tyEnum and enumHasHoles(t2):
     result = sonsLen(t2.n)
   else:
     result = lengthOrd(skipTypes(t, abstractVar-{tyTypeDesc}))
 
 proc performProcvarCheck(c: PContext, n: PNode, s: PSym) =
   ## Checks that the given symbol is a proper procedure variable, meaning
-  ## that it 
+  ## that it
   var smoduleId = getModule(s).id
   if sfProcvar notin s.flags and s.typ.callConv == ccDefault and
       smoduleId != c.module.id:
@@ -92,20 +92,16 @@ proc semProc(c: PContext, n: PNode): PNode
 include semdestruct
 
 proc semDestructorCheck(c: PContext, n: PNode, flags: TExprFlags) {.inline.} =
-  if efAllowDestructor notin flags and n.kind in nkCallKinds+{nkObjConstr}:
+  if efAllowDestructor notin flags and
+      n.kind in nkCallKinds+{nkObjConstr,nkBracket}:
     if instantiateDestructor(c, n.typ) != nil:
-      localError(n.info, errGenerated,
-        "usage of a type with a destructor in a non destructible context")
+      localError(n.info, warnDestructor)
   # This still breaks too many things:
   when false:
-    if efDetermineType notin flags and n.typ.kind == tyTypeDesc and 
+    if efDetermineType notin flags and n.typ.kind == tyTypeDesc and
         c.p.owner.kind notin {skTemplate, skMacro}:
       localError(n.info, errGenerated, "value expected, but got a type")
 
-proc newDeref(n: PNode): PNode {.inline.} =  
-  result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
-  addSon(result, n)
-
 proc semExprBranch(c: PContext, n: PNode): PNode =
   result = semExpr(c, n)
   if result.typ != nil:
@@ -127,7 +123,7 @@ const
 proc implicitlyDiscardable(n: PNode): bool =
   var n = n
   while n.kind in skipForDiscardable: n = n.lastSon
-  result = isCallExpr(n) and n.sons[0].kind == nkSym and 
+  result = isCallExpr(n) and n.sons[0].kind == nkSym and
            sfDiscardable in n.sons[0].sym.flags
 
 proc fixNilType(n: PNode) =
@@ -160,11 +156,11 @@ proc discardCheck(c: PContext, result: PNode) =
         while n.kind in skipForDiscardable: n = n.lastSon
         localError(n.info, errDiscardValueX, result.typ.typeToString)
 
-proc semIf(c: PContext, n: PNode): PNode = 
+proc semIf(c: PContext, n: PNode): PNode =
   result = n
   var typ = commonTypeBegin
   var hasElse = false
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     var it = n.sons[i]
     if it.len == 2:
       when newScopeForIf: openScope(c)
@@ -208,10 +204,10 @@ proc semCase(c: PContext, n: PNode): PNode =
   else:
     localError(n.info, errSelectorMustBeOfCertainTypes)
     return
-  for i in countup(1, sonsLen(n) - 1): 
+  for i in countup(1, sonsLen(n) - 1):
     var x = n.sons[i]
     case x.kind
-    of nkOfBranch: 
+    of nkOfBranch:
       checkMinSonsLen(x, 2)
       semCaseBranch(c, n, x, i, covered)
       var last = sonsLen(x)-1
@@ -263,7 +259,8 @@ proc semTry(c: PContext, n: PNode): PNode =
   n.sons[0] = semExprBranchScope(c, n.sons[0])
   typ = commonType(typ, n.sons[0].typ)
   var check = initIntSet()
-  for i in countup(1, sonsLen(n) - 1): 
+  var last = sonsLen(n) - 1
+  for i in countup(1, last):
     var a = n.sons[i]
     checkMinSonsLen(a, 1)
     var length = sonsLen(a)
@@ -282,11 +279,12 @@ proc semTry(c: PContext, n: PNode): PNode =
         a.sons[j].typ = typ
         if containsOrIncl(check, typ.id):
           localError(a.sons[j].info, errExceptionAlreadyHandled)
-    elif a.kind != nkFinally: 
+    elif a.kind != nkFinally:
       illFormedAst(n)
     # last child of an nkExcept/nkFinally branch is a statement:
     a.sons[length-1] = semExprBranchScope(c, a.sons[length-1])
-    typ = commonType(typ, a.sons[length-1].typ)
+    if a.kind != nkFinally: typ = commonType(typ, a.sons[length-1].typ)
+    else: dec last
   dec c.p.inTryStmt
   if isEmptyType(typ) or typ.kind == tyNil:
     discardCheck(c, n.sons[0])
@@ -294,16 +292,17 @@ proc semTry(c: PContext, n: PNode): PNode =
     if typ == enforceVoidContext:
       result.typ = enforceVoidContext
   else:
+    if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon)
     n.sons[0] = fitNode(c, typ, n.sons[0])
-    for i in 1..n.len-1:
+    for i in 1..last:
       var it = n.sons[i]
       let j = it.len-1
       it.sons[j] = fitNode(c, typ, it.sons[j])
     result.typ = typ
-  
-proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode = 
+
+proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
   result = fitNode(c, typ, n)
-  if result.kind in {nkHiddenStdConv, nkHiddenSubConv}: 
+  if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
     changeType(result.sons[1], typ, check=true)
     result = result.sons[1]
   elif not sameType(result.typ, typ):
@@ -322,7 +321,7 @@ proc identWithin(n: PNode, s: PIdent): bool =
   result = n.kind == nkSym and n.sym.name.id == s.id
 
 proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
-  if isTopLevel(c): 
+  if isTopLevel(c):
     result = semIdentWithPragma(c, kind, n, {sfExported})
     incl(result.flags, sfGlobal)
   else:
@@ -337,14 +336,52 @@ proc checkNilable(v: PSym) =
     elif tfNotNil in v.typ.flags and tfNotNil notin v.ast.typ.flags:
       message(v.info, warnProveInit, v.name.s)
 
-proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = 
+include semasgn
+
+proc addToVarSection(c: PContext; result: var PNode; orig, identDefs: PNode) =
+  # consider this:
+  #   var
+  #     x = 0
+  #     withOverloadedAssignment = foo()
+  #     y = use(withOverloadedAssignment)
+  # We need to split this into a statement list with multiple 'var' sections
+  # in order for this transformation to be correct.
+  let L = identDefs.len
+  let value = identDefs[L-1]
+  if value.typ != nil and tfHasAsgn in value.typ.flags:
+    # the spec says we need to rewrite 'var x = T()' to 'var x: T; x = T()':
+    identDefs.sons[L-1] = emptyNode
+    if result.kind != nkStmtList:
+      let oldResult = result
+      oldResult.add identDefs
+      result = newNodeI(nkStmtList, result.info)
+      result.add oldResult
+    else:
+      let o = copyNode(orig)
+      o.add identDefs
+      result.add o
+    for i in 0 .. L-3:
+      result.add overloadedAsgn(c, identDefs[i], value)
+  elif result.kind == nkStmtList:
+    let o = copyNode(orig)
+    o.add identDefs
+    result.add o
+  else:
+    result.add identDefs
+
+proc isDiscardUnderscore(v: PSym): bool =
+  if v.name.s == "_":
+    v.flags.incl(sfGenSym)
+    result = true
+
+proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
   var b: PNode
   result = copyNode(n)
   var hasCompileTime = false
-  for i in countup(0, sonsLen(n)-1): 
+  for i in countup(0, sonsLen(n)-1):
     var a = n.sons[i]
     if gCmd == cmdIdeTools: suggestStmt(c, a)
-    if a.kind == nkCommentStmt: continue 
+    if a.kind == nkCommentStmt: continue
     if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a)
     checkMinSonsLen(a, 3)
     var length = sonsLen(a)
@@ -356,14 +393,19 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
     var def: PNode
     if a.sons[length-1].kind != nkEmpty:
       def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
+      if def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro:
+        # prevent the all too common 'var x = int' bug:
+        localError(def.info, "'typedesc' metatype is not valid here; typed '=' instead of ':'?")
+        def.typ = errorType(c)
       if typ != nil:
         if typ.isMetaType:
           def = inferWithMetatype(c, typ, def)
           typ = def.typ
         else:
           # BUGFIX: ``fitNode`` is needed here!
-          # check type compability between def.typ and typ        
+          # check type compatibility between def.typ and typ
           def = fitNode(c, typ, def)
+          #changeType(def.skipConv, typ, check=true)
       else:
         typ = skipIntLit(def.typ)
         if typ.kind in {tySequence, tyArray, tySet} and
@@ -373,35 +415,38 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
     else:
       def = ast.emptyNode
       if symkind == skLet: localError(a.info, errLetNeedsInit)
-      
+
     # this can only happen for errornous var statements:
     if typ == nil: continue
-    if not typeAllowed(typ, symkind): 
-      localError(a.info, errXisNoType, typeToString(typ))
+    typeAllowedCheck(a.info, typ, symkind)
     var tup = skipTypes(typ, {tyGenericInst})
-    if a.kind == nkVarTuple: 
-      if tup.kind != tyTuple: 
+    if a.kind == nkVarTuple:
+      if tup.kind != tyTuple:
         localError(a.info, errXExpected, "tuple")
-      elif length-2 != sonsLen(tup): 
+      elif length-2 != sonsLen(tup):
         localError(a.info, errWrongNumberOfVariables)
       else:
         b = newNodeI(nkVarTuple, a.info)
         newSons(b, length)
         b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator
         b.sons[length-1] = def
-        addSon(result, b)
-    elif tup.kind == tyTuple and def.kind == nkPar and 
+        addToVarSection(c, result, n, b)
+    elif tup.kind == tyTuple and def.kind == nkPar and
         a.kind == nkIdentDefs and a.len > 3:
       message(a.info, warnEachIdentIsTuple)
+
     for j in countup(0, length-3):
       var v = semIdentDef(c, a.sons[j], symkind)
-      if sfGenSym notin v.flags: addInterfaceDecl(c, v)
+      if sfGenSym notin v.flags and not isDiscardUnderscore(v):
+        addInterfaceDecl(c, v)
       when oKeepVariableNames:
         if c.inUnrolledContext > 0: v.flags.incl(sfShadowed)
         else:
           let shadowed = findShadowedVar(c, v)
           if shadowed != nil:
             shadowed.flags.incl(sfShadowed)
+            if shadowed.kind == skResult and sfGenSym notin v.flags:
+              message(a.info, warnResultShadowed)
             # a shadowed variable is an error unless it appears on the right
             # side of the '=':
             if warnShadowIdent in gNotes and not identWithin(def, v.name):
@@ -419,7 +464,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
         addSon(b, newSymNode(v))
         addSon(b, a.sons[length-2])      # keep type desc for doc generator
         addSon(b, copyTree(def))
-        addSon(result, b)
+        addToVarSection(c, result, n, b)
       else:
         if def.kind == nkPar: v.ast = def[j]
         v.typ = tup.sons[j]
@@ -428,12 +473,12 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
       if sfCompileTime in v.flags: hasCompileTime = true
   if hasCompileTime: vm.setupCompileTimeVar(c.module, result)
 
-proc semConst(c: PContext, n: PNode): PNode = 
+proc semConst(c: PContext, n: PNode): PNode =
   result = copyNode(n)
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     var a = n.sons[i]
     if gCmd == cmdIdeTools: suggestStmt(c, a)
-    if a.kind == nkCommentStmt: continue 
+    if a.kind == nkCommentStmt: continue
     if (a.kind != nkConstDef): illFormedAst(a)
     checkSonsLen(a, 3)
     var v = semIdentDef(c, a.sons[0], skConst)
@@ -452,7 +497,7 @@ proc semConst(c: PContext, n: PNode): PNode =
     if typ == nil:
       localError(a.sons[2].info, errConstExprExpected)
       continue
-    if not typeAllowed(typ, skConst) and def.kind != nkNilLit:
+    if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit:
       localError(a.info, errXisNoType, typeToString(typ))
       continue
     v.typ = typ
@@ -465,153 +510,7 @@ proc semConst(c: PContext, n: PNode): PNode =
     addSon(b, copyTree(def))
     addSon(result, b)
 
-type
-  TFieldInstCtx = object  # either 'tup[i]' or 'field' is valid
-    tupleType: PType      # if != nil we're traversing a tuple
-    tupleIndex: int
-    field: PSym
-    replaceByFieldName: bool
-
-proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
-  case n.kind
-  of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n
-  of nkIdent:
-    result = n
-    var L = sonsLen(forLoop)
-    if c.replaceByFieldName:
-      if n.ident.id == forLoop[0].ident.id:
-        let fieldName = if c.tupleType.isNil: c.field.name.s
-                        elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
-                        else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
-        result = newStrNode(nkStrLit, fieldName)
-        return
-    # other fields:
-    for i in ord(c.replaceByFieldName)..L-3:
-      if n.ident.id == forLoop[i].ident.id:
-        var call = forLoop.sons[L-2]
-        var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
-        if c.field.isNil:
-          result = newNodeI(nkBracketExpr, n.info)
-          result.add(tupl)
-          result.add(newIntNode(nkIntLit, c.tupleIndex))
-        else:
-          result = newNodeI(nkDotExpr, n.info)
-          result.add(tupl)
-          result.add(newSymNode(c.field, n.info))
-        break
-  else:
-    if n.kind == nkContinueStmt:
-      localError(n.info, errGenerated,
-                 "'continue' not supported in a 'fields' loop")
-    result = copyNode(n)
-    newSons(result, sonsLen(n))
-    for i in countup(0, sonsLen(n)-1):
-      result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop)
-
-type
-  TFieldsCtx = object
-    c: PContext
-    m: TMagic
-
-proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
-  case typ.kind
-  of nkSym:
-    var fc: TFieldInstCtx  # either 'tup[i]' or 'field' is valid
-    fc.field = typ.sym
-    fc.replaceByFieldName = c.m == mFieldPairs
-    openScope(c.c)
-    inc c.c.inUnrolledContext
-    let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
-    father.add(semStmt(c.c, body))
-    dec c.c.inUnrolledContext
-    closeScope(c.c)
-  of nkNilLit: discard
-  of nkRecCase:
-    let L = forLoop.len
-    let call = forLoop.sons[L-2]
-    if call.len > 2:
-      localError(forLoop.info, errGenerated, 
-                 "parallel 'fields' iterator does not work for 'case' objects")
-      return
-    # iterate over the selector:
-    semForObjectFields(c, typ[0], forLoop, father)
-    # we need to generate a case statement:
-    var caseStmt = newNodeI(nkCaseStmt, forLoop.info)
-    # generate selector:
-    var access = newNodeI(nkDotExpr, forLoop.info, 2)
-    access.sons[0] = call.sons[1]
-    access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info)
-    caseStmt.add(semExprWithType(c.c, access))
-    # copy the branches over, but replace the fields with the for loop body:
-    for i in 1 .. <typ.len:
-      var branch = copyTree(typ[i])
-      let L = branch.len
-      branch.sons[L-1] = newNodeI(nkStmtList, forLoop.info)
-      semForObjectFields(c, typ[i].lastSon, forLoop, branch[L-1])
-      caseStmt.add(branch)
-    father.add(caseStmt)
-  of nkRecList:
-    for t in items(typ): semForObjectFields(c, t, forLoop, father)
-  else:
-    illFormedAst(typ)
-
-proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
-  # so that 'break' etc. work as expected, we produce
-  # a 'while true: stmt; break' loop ...
-  result = newNodeI(nkWhileStmt, n.info, 2)
-  var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true")
-  if trueSymbol == nil: 
-    localError(n.info, errSystemNeeds, "true")
-    trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(), n.info)
-    trueSymbol.typ = getSysType(tyBool)
-
-  result.sons[0] = newSymNode(trueSymbol, n.info)
-  var stmts = newNodeI(nkStmtList, n.info)
-  result.sons[1] = stmts
-  
-  var length = sonsLen(n)
-  var call = n.sons[length-2]
-  if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs):
-    localError(n.info, errWrongNumberOfVariables)
-    return result
-  
-  var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar-{tyTypeDesc})
-  if tupleTypeA.kind notin {tyTuple, tyObject}:
-    localError(n.info, errGenerated, "no object or tuple type")
-    return result
-  for i in 1..call.len-1:
-    var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar-{tyTypeDesc})
-    if not sameType(tupleTypeA, tupleTypeB):
-      typeMismatch(call.sons[i], tupleTypeA, tupleTypeB)
-  
-  inc(c.p.nestedLoopCounter)
-  if tupleTypeA.kind == tyTuple:
-    var loopBody = n.sons[length-1]
-    for i in 0..sonsLen(tupleTypeA)-1:
-      openScope(c)
-      var fc: TFieldInstCtx
-      fc.tupleType = tupleTypeA
-      fc.tupleIndex = i
-      fc.replaceByFieldName = m == mFieldPairs
-      var body = instFieldLoopBody(fc, loopBody, n)
-      inc c.inUnrolledContext
-      stmts.add(semStmt(c, body))
-      dec c.inUnrolledContext
-      closeScope(c)
-  else:
-    var fc: TFieldsCtx
-    fc.m = m
-    fc.c = c
-    semForObjectFields(fc, tupleTypeA.n, n, stmts)
-  dec(c.p.nestedLoopCounter)
-  # for TR macros this 'while true: ...; break' loop is pretty bad, so
-  # we avoid it now if we can:
-  if hasSonWith(stmts, nkBreakStmt):
-    var b = newNodeI(nkBreakStmt, n.info)
-    b.add(ast.emptyNode)
-    stmts.add(b)
-  else:
-    result = stmts
+include semfields
 
 proc addForVarDecl(c: PContext, v: PSym) =
   if warnShadowIdent in gNotes:
@@ -634,7 +533,7 @@ proc semForVars(c: PContext, n: PNode): PNode =
   var iter = skipTypes(iterBase, {tyGenericInst})
   # length == 3 means that there is one for loop variable
   # and thus no tuple unpacking:
-  if iter.kind != tyTuple or length == 3: 
+  if iter.kind != tyTuple or length == 3:
     if length == 3:
       var v = symForVar(c, n.sons[0])
       if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal)
@@ -654,7 +553,8 @@ proc semForVars(c: PContext, n: PNode): PNode =
       if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal)
       v.typ = iter.sons[i]
       n.sons[i] = newSymNode(v)
-      if sfGenSym notin v.flags: addForVarDecl(c, v)
+      if sfGenSym notin v.flags and not isDiscardUnderscore(v):
+        addForVarDecl(c, v)
   inc(c.p.nestedLoopCounter)
   n.sons[length-1] = semStmt(c, n.sons[length-1])
   dec(c.p.nestedLoopCounter)
@@ -662,13 +562,13 @@ proc semForVars(c: PContext, n: PNode): PNode =
 proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
   result = newNodeI(nkCall, arg.info)
   result.add(newIdentNode(it.getIdent, arg.info))
-  if arg.typ != nil and arg.typ.kind == tyVar: 
+  if arg.typ != nil and arg.typ.kind == tyVar:
     result.add newDeref(arg)
   else:
     result.add arg
   result = semExprNoDeref(c, result, {efWantIterator})
 
-proc semFor(c: PContext, n: PNode): PNode = 
+proc semFor(c: PContext, n: PNode): PNode =
   result = n
   checkMinSonsLen(n, 3)
   var length = sonsLen(n)
@@ -703,13 +603,13 @@ proc semFor(c: PContext, n: PNode): PNode =
     result.typ = enforceVoidContext
   closeScope(c)
 
-proc semRaise(c: PContext, n: PNode): PNode = 
+proc semRaise(c: PContext, n: PNode): PNode =
   result = n
   checkSonsLen(n, 1)
-  if n.sons[0].kind != nkEmpty: 
+  if n.sons[0].kind != nkEmpty:
     n.sons[0] = semExprWithType(c, n.sons[0])
     var typ = n.sons[0].typ
-    if typ.kind != tyRef or typ.sons[0].kind != tyObject: 
+    if typ.kind != tyRef or typ.sons[0].kind != tyObject:
       localError(n.info, errExprCannotBeRaised)
 
 proc addGenericParamListToScope(c: PContext, n: PNode) =
@@ -719,13 +619,13 @@ proc addGenericParamListToScope(c: PContext, n: PNode) =
     if a.kind == nkSym: addDecl(c, a.sym)
     else: illFormedAst(a)
 
-proc typeSectionLeftSidePass(c: PContext, n: PNode) = 
+proc typeSectionLeftSidePass(c: PContext, n: PNode) =
   # process the symbols on the left side for the whole type section, before
   # we even look at the type definitions on the right
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     var a = n.sons[i]
     if gCmd == cmdIdeTools: suggestStmt(c, a)
-    if a.kind == nkCommentStmt: continue 
+    if a.kind == nkCommentStmt: continue
     if a.kind != nkTypeDef: illFormedAst(a)
     checkSonsLen(a, 3)
     var s = semIdentDef(c, a.sons[0], skType)
@@ -738,29 +638,29 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
     a.sons[0] = newSymNode(s)
 
 proc typeSectionRightSidePass(c: PContext, n: PNode) =
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     var a = n.sons[i]
-    if a.kind == nkCommentStmt: continue 
+    if a.kind == nkCommentStmt: continue
     if (a.kind != nkTypeDef): illFormedAst(a)
     checkSonsLen(a, 3)
     if (a.sons[0].kind != nkSym): illFormedAst(a)
     var s = a.sons[0].sym
-    if s.magic == mNone and a.sons[2].kind == nkEmpty: 
+    if s.magic == mNone and a.sons[2].kind == nkEmpty:
       localError(a.info, errImplOfXexpected, s.name.s)
     if s.magic != mNone: processMagicType(c, s)
-    if a.sons[1].kind != nkEmpty: 
+    if a.sons[1].kind != nkEmpty:
       # We have a generic type declaration here. In generic types,
       # symbol lookup needs to be done here.
       openScope(c)
       pushOwner(s)
       if s.magic == mNone: s.typ.kind = tyGenericBody
       # XXX for generic type aliases this is not correct! We need the
-      # underlying Id really: 
+      # underlying Id really:
       #
       # type
       #   TGObj[T] = object
       #   TAlias[T] = TGObj[T]
-      # 
+      #
       s.typ.n = semGenericParamList(c, a.sons[1], s.typ)
       a.sons[1] = s.typ.n
       s.typ.size = -1 # could not be computed properly
@@ -778,24 +678,35 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
         s.typ.sons[sonsLen(s.typ) - 1] = body
       popOwner()
       closeScope(c)
-    elif a.sons[2].kind != nkEmpty: 
+    elif a.sons[2].kind != nkEmpty:
       # process the type's body:
       pushOwner(s)
       var t = semTypeNode(c, a.sons[2], s.typ)
-      if s.typ == nil: 
+      if s.typ == nil:
         s.typ = t
-      elif t != s.typ: 
+      elif t != s.typ:
         # this can happen for e.g. tcan_alias_specialised_generic:
         assignType(s.typ, t)
         #debug s.typ
       s.ast = a
       popOwner()
+    let aa = a.sons[2]
+    if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
+       aa.sons[0].kind == nkObjectTy:
+      # give anonymous object a dummy symbol:
+      var st = s.typ
+      if st.kind == tyGenericBody: st = st.lastSon
+      internalAssert st.kind in {tyPtr, tyRef}
+      internalAssert st.lastSon.sym == nil
+      st.lastSon.sym = newSym(skType, getIdent(s.name.s & ":ObjectType"),
+                              getCurrOwner(), s.info)
 
 proc checkForMetaFields(n: PNode) =
   template checkMeta(t) =
     if t != nil and t.isMetaType and tfGenericTypeParam notin t.flags:
       localError(n.info, errTIsNotAConcreteType, t.typeToString)
-  
+
+  if n.isNil: return
   case n.kind
   of nkRecList, nkRecCase:
     for s in n: checkForMetaFields(s)
@@ -805,8 +716,8 @@ proc checkForMetaFields(n: PNode) =
     let t = n.sym.typ
     case t.kind
     of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyPtr, tyRef,
-       tyProc, tyGenericInvokation, tyGenericInst:
-      let start = ord(t.kind in {tyGenericInvokation, tyGenericInst})
+       tyProc, tyGenericInvocation, tyGenericInst:
+      let start = ord(t.kind in {tyGenericInvocation, tyGenericInst})
       for i in start .. <t.sons.len:
         checkMeta(t.sons[i])
     else:
@@ -814,34 +725,24 @@ proc checkForMetaFields(n: PNode) =
   else:
     internalAssert false
 
-proc typeSectionFinalPass(c: PContext, n: PNode) = 
-  for i in countup(0, sonsLen(n) - 1): 
+proc typeSectionFinalPass(c: PContext, n: PNode) =
+  for i in countup(0, sonsLen(n) - 1):
     var a = n.sons[i]
-    if a.kind == nkCommentStmt: continue 
+    if a.kind == nkCommentStmt: continue
     if a.sons[0].kind != nkSym: illFormedAst(a)
     var s = a.sons[0].sym
     # compute the type's size and check for illegal recursions:
-    if a.sons[1].kind == nkEmpty: 
+    if a.sons[1].kind == nkEmpty:
       if a.sons[2].kind in {nkSym, nkIdent, nkAccQuoted}:
         # type aliases are hard:
         #MessageOut('for type ' + typeToString(s.typ));
         var t = semTypeNode(c, a.sons[2], nil)
-        if t.kind in {tyObject, tyEnum}: 
+        if t.kind in {tyObject, tyEnum}:
           assignType(s.typ, t)
           s.typ.id = t.id     # same id
       checkConstructedType(s.info, s.typ)
-      if s.typ.kind in {tyObject, tyTuple}:
+      if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil:
         checkForMetaFields(s.typ.n)
-    let aa = a.sons[2]
-    if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
-       aa.sons[0].kind == nkObjectTy:
-      # give anonymous object a dummy symbol:
-      var st = s.typ
-      if st.kind == tyGenericBody: st = st.lastSon
-      internalAssert st.kind in {tyPtr, tyRef}
-      internalAssert st.lastSon.sym == nil
-      st.lastSon.sym = newSym(skType, getIdent(s.name.s & ":ObjectType"),
-                              getCurrOwner(), s.info)
 
 proc semTypeSection(c: PContext, n: PNode): PNode =
   ## Processes a type section. This must be done in separate passes, in order
@@ -858,29 +759,29 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym) =
     if s.typ.sons[0] != nil and s.typ.sons[0].kind == tyStmt:
       localError(n.info, errGenerated, "invalid return type: 'stmt'")
 
-proc addParams(c: PContext, n: PNode, kind: TSymKind) = 
-  for i in countup(1, sonsLen(n)-1): 
+proc addParams(c: PContext, n: PNode, kind: TSymKind) =
+  for i in countup(1, sonsLen(n)-1):
     if n.sons[i].kind == nkSym: addParamOrResult(c, n.sons[i].sym, kind)
     else: illFormedAst(n)
 
-proc semBorrow(c: PContext, n: PNode, s: PSym) = 
+proc semBorrow(c: PContext, n: PNode, s: PSym) =
   # search for the correct alias:
   var b = searchForBorrowProc(c, c.currentScope.parent, s)
-  if b != nil: 
+  if b != nil:
     # store the alias:
     n.sons[bodyPos] = newSymNode(b)
   else:
-    localError(n.info, errNoSymbolToBorrowFromFound) 
-  
-proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) = 
-  if t != nil: 
+    localError(n.info, errNoSymbolToBorrowFromFound)
+
+proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
+  if t != nil:
     var s = newSym(skResult, getIdent"result", getCurrOwner(), info)
     s.typ = t
     incl(s.flags, sfUsed)
     addParamOrResult(c, s, owner)
     c.p.resultSym = s
 
-proc addResultNode(c: PContext, n: PNode) = 
+proc addResultNode(c: PContext, n: PNode) =
   if c.p.resultSym != nil: addSon(n, newSymNode(c.p.resultSym))
 
 proc copyExcept(n: PNode, i: int): PNode =
@@ -895,7 +796,8 @@ proc lookupMacro(c: PContext, n: PNode): PSym =
   else:
     result = searchInScopes(c, considerQuotedIdent(n), {skMacro, skTemplate})
 
-proc semProcAnnotation(c: PContext, prc: PNode): PNode =
+proc semProcAnnotation(c: PContext, prc: PNode;
+                       validPragmas: TSpecialWords): PNode =
   var n = prc.sons[pragmasPos]
   if n == nil or n.kind == nkEmpty: return
   for i in countup(0, <n.len):
@@ -918,14 +820,20 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
     if it.kind == nkExprColonExpr:
       # pass pragma argument to the macro too:
       x.add(it.sons[1])
-    x.add(newProcNode(nkDo, prc.info, prc))
+    x.add(prc)
     # recursion assures that this works for multiple macro annotations too:
-    return semStmt(c, x)
+    result = semStmt(c, x)
+    # since a proc annotation can set pragmas, we process these here again.
+    # This is required for SqueakNim-like export pragmas.
+    if result.kind in procDefs and result[namePos].kind == nkSym and
+        result[pragmasPos].kind != nkEmpty:
+      pragma(c, result[namePos].sym, result[pragmasPos], validPragmas)
+    return
 
 proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
   # XXX semProcAux should be good enough for this now, we will eventually
   # remove semLambda
-  result = semProcAnnotation(c, n)
+  result = semProcAnnotation(c, n, lambdaPragmas)
   if result != nil: return result
   result = n
   checkSonsLen(n, bodyPos + 1)
@@ -939,21 +847,23 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
   pushOwner(s)
   openScope(c)
   var gp: PNode
-  if n.sons[genericParamsPos].kind != nkEmpty: 
+  if n.sons[genericParamsPos].kind != nkEmpty:
     n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
     gp = n.sons[genericParamsPos]
   else:
     gp = newNodeI(nkGenericParams, n.info)
 
   if n.sons[paramsPos].kind != nkEmpty:
+    #if n.kind == nkDo and not experimentalMode(c):
+    #  localError(n.sons[paramsPos].info,
+    #      "use the {.experimental.} pragma to enable 'do' with parameters")
     semParamList(c, n.sons[paramsPos], gp, s)
     # paramsTypeCheck(c, s.typ)
     if sonsLen(gp) > 0 and n.sons[genericParamsPos].kind == nkEmpty:
       # we have a list of implicit type parameters:
       n.sons[genericParamsPos] = gp
   else:
-    s.typ = newTypeS(tyProc, c)
-    rawAddSon(s.typ, nil)
+    s.typ = newProcType(c, n.info)
   if n.sons[pragmasPos].kind != nkEmpty:
     pragma(c, s, n.sons[pragmasPos], lambdaPragmas)
   s.options = gOptions
@@ -965,9 +875,9 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
     if gp.len == 0 or (gp.len == 1 and tfRetType in gp[0].typ.flags):
       pushProcCon(c, s)
       addResult(c, s.typ.sons[0], n.info, skProc)
+      addResultNode(c, n)
       let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
       n.sons[bodyPos] = transformBody(c.module, semBody, s)
-      addResultNode(c, n)
       popProcCon(c)
     elif efOperand notin flags:
       localError(n.info, errGenericLambdaNotAllowed)
@@ -978,26 +888,35 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
   popOwner()
   result.typ = s.typ
 
+proc semDo(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  # 'do' without params produces a stmt:
+  if n[genericParamsPos].kind == nkEmpty and n[paramsPos].kind == nkEmpty:
+    result = semStmt(c, n[bodyPos])
+  else:
+    result = semLambda(c, n, flags)
+
 proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
   var n = n
-  
+
   n = replaceTypesInBody(c, pt, n)
   result = n
-  
+
   n.sons[genericParamsPos] = emptyNode
   n.sons[paramsPos] = n.typ.n
-  
+
   openScope(c)
   var s = n.sons[namePos].sym
+  pushOwner(s)
   addParams(c, n.typ.n, skProc)
   pushProcCon(c, s)
   addResult(c, n.typ.sons[0], n.info, skProc)
+  addResultNode(c, n)
   let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
   n.sons[bodyPos] = transformBody(c.module, semBody, n.sons[namePos].sym)
-  addResultNode(c, n)
   popProcCon(c)
+  popOwner()
   closeScope(c)
-  
+
   s.ast = result
 
   # alternative variant (not quite working):
@@ -1026,8 +945,12 @@ proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
 
 proc semOverride(c: PContext, s: PSym, n: PNode) =
   case s.name.s.normalize
-  of "destroy": doDestructorStuff(c, s, n)
-  of "deepcopy":
+  of "destroy", "=destroy":
+    doDestructorStuff(c, s, n)
+    if not experimentalMode(c):
+      localError n.info, "use the {.experimental.} pragma to enable destructors"
+    incl(s.flags, sfUsed)
+  of "deepcopy", "=deepcopy":
     if s.typ.len == 2 and
         s.typ.sons[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and
         sameType(s.typ.sons[1], s.typ.sons[0]):
@@ -1036,11 +959,11 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
       var t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst)
       while true:
         if t.kind == tyGenericBody: t = t.lastSon
-        elif t.kind == tyGenericInvokation: t = t.sons[0]
+        elif t.kind == tyGenericInvocation: t = t.sons[0]
         else: break
       if t.kind in {tyObject, tyDistinct, tyEnum}:
         if t.deepCopy.isNil: t.deepCopy = s
-        else: 
+        else:
           localError(n.info, errGenerated,
                      "cannot bind another 'deepCopy' to: " & typeToString(t))
       else:
@@ -1049,10 +972,35 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
     else:
       localError(n.info, errGenerated,
                  "signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T")
-  of "=": discard
-  else: localError(n.info, errGenerated,
-                   "'destroy' or 'deepCopy' expected for 'override'")
-  incl(s.flags, sfUsed)
+    incl(s.flags, sfUsed)
+  of "=":
+    incl(s.flags, sfUsed)
+    let t = s.typ
+    if t.len == 3 and t.sons[0] == nil and t.sons[1].kind == tyVar:
+      var obj = t.sons[1].sons[0]
+      while true:
+        incl(obj.flags, tfHasAsgn)
+        if obj.kind == tyGenericBody: obj = obj.lastSon
+        elif obj.kind == tyGenericInvocation: obj = obj.sons[0]
+        else: break
+      var objB = t.sons[2]
+      while true:
+        if objB.kind == tyGenericBody: objB = objB.lastSon
+        elif objB.kind == tyGenericInvocation: objB = objB.sons[0]
+        else: break
+      if obj.kind in {tyObject, tyDistinct} and sameType(obj, objB):
+        if obj.assignment.isNil:
+          obj.assignment = s
+        else:
+          localError(n.info, errGenerated,
+                     "cannot bind another '=' to: " & typeToString(obj))
+        return
+    localError(n.info, errGenerated,
+               "signature for '=' must be proc[T: object](x: var T; y: T)")
+  else:
+    if sfOverriden in s.flags:
+      localError(n.info, errGenerated,
+                 "'destroy' or 'deepCopy' expected for 'override'")
 
 type
   TProcCompilationSteps = enum
@@ -1067,7 +1015,7 @@ proc isForwardDecl(s: PSym): bool =
 proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
                 validPragmas: TSpecialWords,
                 phase = stepRegisterSymbol): PNode =
-  result = semProcAnnotation(c, n)
+  result = semProcAnnotation(c, n, validPragmas)
   if result != nil: return result
   result = n
   checkSonsLen(n, bodyPos + 1)
@@ -1084,7 +1032,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
       s = semIdentDef(c, n.sons[0], kind)
     n.sons[namePos] = newSymNode(s)
     s.ast = n
-    s.scope = c.currentScope
+    #s.scope = c.currentScope
 
     if sfNoForward in c.module.flags and
        sfSystemModule notin c.module.flags:
@@ -1096,40 +1044,39 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     s.owner = getCurrOwner()
     typeIsDetermined = s.typ == nil
     s.ast = n
-    s.scope = c.currentScope
+    #s.scope = c.currentScope
 
     # if typeIsDetermined: assert phase == stepCompileBody
     # else: assert phase == stepDetermineType
   # before compiling the proc body, set as current the scope
   # where the proc was declared
   let oldScope = c.currentScope
-  c.currentScope = s.scope
+  #c.currentScope = s.scope
   pushOwner(s)
   openScope(c)
   var gp: PNode
-  if n.sons[genericParamsPos].kind != nkEmpty: 
+  if n.sons[genericParamsPos].kind != nkEmpty:
     n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
     gp = n.sons[genericParamsPos]
-  else: 
+  else:
     gp = newNodeI(nkGenericParams, n.info)
   # process parameters:
   if n.sons[paramsPos].kind != nkEmpty:
     semParamList(c, n.sons[paramsPos], gp, s)
-    if sonsLen(gp) > 0: 
+    if sonsLen(gp) > 0:
       if n.sons[genericParamsPos].kind == nkEmpty:
         # we have a list of implicit type parameters:
         n.sons[genericParamsPos] = gp
         # check for semantics again:
         # semParamList(c, n.sons[ParamsPos], nil, s)
   else:
-    s.typ = newTypeS(tyProc, c)
-    rawAddSon(s.typ, nil)
+    s.typ = newProcType(c, n.info)
   if n.sons[patternPos].kind != nkEmpty:
     n.sons[patternPos] = semPattern(c, n.sons[patternPos])
   if s.kind in skIterators:
     s.typ.flags.incl(tfIterator)
-  
-  var proto = searchForProc(c, s.scope, s)
+
+  var proto = searchForProc(c, oldScope, s)
   if proto == nil:
     if s.kind == skClosureIterator: s.typ.callConv = ccClosure
     else: s.typ.callConv = lastOptionEntry(c).defaultCC
@@ -1137,23 +1084,23 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     if sfGenSym in s.flags: discard
     elif kind in OverloadableSyms:
       if not typeIsDetermined:
-        addInterfaceOverloadableSymAt(c, s.scope, s)
+        addInterfaceOverloadableSymAt(c, oldScope, s)
     else:
       if not typeIsDetermined:
-        addInterfaceDeclAt(c, s.scope, s)
+        addInterfaceDeclAt(c, oldScope, s)
     if n.sons[pragmasPos].kind != nkEmpty:
       pragma(c, s, n.sons[pragmasPos], validPragmas)
     else:
       implicitPragmas(c, s, n, validPragmas)
   else:
-    if n.sons[pragmasPos].kind != nkEmpty: 
+    if n.sons[pragmasPos].kind != nkEmpty:
       localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProc)
-    if sfForward notin proto.flags: 
+    if sfForward notin proto.flags:
       wrongRedefinition(n.info, proto.name.s)
     excl(proto.flags, sfForward)
     closeScope(c)         # close scope with wrong parameter symbols
     openScope(c)          # open scope for old (correct) parameter symbols
-    if proto.ast.sons[genericParamsPos].kind != nkEmpty: 
+    if proto.ast.sons[genericParamsPos].kind != nkEmpty:
       addGenericParamListToScope(c, proto.ast.sons[genericParamsPos])
     addParams(c, proto.typ.n, proto.kind)
     proto.info = s.info       # more accurate line information
@@ -1170,7 +1117,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     popOwner()
     pushOwner(s)
   s.options = gOptions
-  if sfOverriden in s.flags: semOverride(c, s, n)
+  if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
   if n.sons[bodyPos].kind != nkEmpty:
     # for DLL generation it is annoying to check for sfImportc!
     if sfBorrow in s.flags:
@@ -1182,6 +1129,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics:
       if not usePseudoGenerics: paramsTypeCheck(c, s.typ)
       pushProcCon(c, s)
+      c.p.wasForwarded = proto != nil
       maybeAddResult(c, s, n)
       if sfImportc notin s.flags:
         # no semantic checking for importc:
@@ -1193,20 +1141,21 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     else:
       if s.typ.sons[0] != nil and kind notin skIterators:
         addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info))
-      var toBind = initIntSet()
-      n.sons[bodyPos] = semGenericStmtScope(c, n.sons[bodyPos], {}, toBind)
+      openScope(c)
+      n.sons[bodyPos] = semGenericStmt(c, n.sons[bodyPos])
+      closeScope(c)
       fixupInstantiatedSymbols(c, s)
     if sfImportc in s.flags:
       # so we just ignore the body after semantic checking for importc:
       n.sons[bodyPos] = ast.emptyNode
   else:
     if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s)
-    if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone: 
+    if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone:
       incl(s.flags, sfForward)
     elif sfBorrow in s.flags: semBorrow(c, n, s)
   sideEffectsCheck(c, s)
   closeScope(c)           # close scope for parameters
-  c.currentScope = oldScope
+  # c.currentScope = oldScope
   popOwner()
   if n.sons[patternPos].kind != nkEmpty:
     c.patterns.add(s)
@@ -1239,14 +1188,14 @@ proc semIterator(c: PContext, n: PNode): PNode =
   else:
     s.typ.callConv = ccInline
   when false:
-    if s.typ.callConv != ccInline: 
+    if s.typ.callConv != ccInline:
       s.typ.callConv = ccClosure
       # and they always at least use the 'env' for the state field:
       incl(s.typ.flags, tfCapturesEnv)
   if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone:
     localError(n.info, errImplOfXexpected, s.name.s)
-  
-proc semProc(c: PContext, n: PNode): PNode = 
+
+proc semProc(c: PContext, n: PNode): PNode =
   result = semProcAux(c, n, skProc, procPragmas)
 
 proc hasObjParam(s: PSym): bool =
@@ -1259,18 +1208,21 @@ proc finishMethod(c: PContext, s: PSym) =
   if hasObjParam(s):
     methodDef(s, false)
 
-proc semMethod(c: PContext, n: PNode): PNode = 
+proc semMethod(c: PContext, n: PNode): PNode =
   if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method")
   result = semProcAux(c, n, skMethod, methodPragmas)
-  
+
   var s = result.sons[namePos].sym
-  if not isGenericRoutine(s) and result.sons[bodyPos].kind != nkEmpty:
+  if not isGenericRoutine(s):
+    # why check for the body? bug #2400 has none. Checking for sfForward makes
+    # no sense either.
+    # and result.sons[bodyPos].kind != nkEmpty:
     if hasObjParam(s):
       methodDef(s, fromCache=false)
     else:
       localError(n.info, errXNeedsParamObjectType, "method")
 
-proc semConverterDef(c: PContext, n: PNode): PNode = 
+proc semConverterDef(c: PContext, n: PNode): PNode =
   if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter")
   checkSonsLen(n, bodyPos + 1)
   result = semProcAux(c, n, skConverter, converterPragmas)
@@ -1280,7 +1232,7 @@ proc semConverterDef(c: PContext, n: PNode): PNode =
   if sonsLen(t) != 2: localError(n.info, errXRequiresOneArgument, "converter")
   addConverter(c, s)
 
-proc semMacroDef(c: PContext, n: PNode): PNode = 
+proc semMacroDef(c: PContext, n: PNode): PNode =
   checkSonsLen(n, bodyPos + 1)
   result = semProcAux(c, n, skMacro, macroPragmas)
   var s = result.sons[namePos].sym
@@ -1288,23 +1240,23 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
   if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro")
   if n.sons[bodyPos].kind == nkEmpty:
     localError(n.info, errImplOfXexpected, s.name.s)
-  
+
 proc evalInclude(c: PContext, n: PNode): PNode =
   result = newNodeI(nkStmtList, n.info)
   addSon(result, n)
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     var f = checkModuleName(n.sons[i])
     if f != InvalidFileIDX:
-      if containsOrIncl(c.includedFiles, f): 
+      if containsOrIncl(c.includedFiles, f):
         localError(n.info, errRecursiveDependencyX, f.toFilename)
       else:
         addSon(result, semStmt(c, gIncludeFile(c.module, f)))
         excl(c.includedFiles, f)
-  
+
 proc setLine(n: PNode, info: TLineInfo) =
   for i in 0 .. <safeLen(n): setLine(n.sons[i], info)
   n.info = info
-  
+
 proc semPragmaBlock(c: PContext, n: PNode): PNode =
   let pragmaList = n.sons[0]
   pragma(c, nil, pragmaList, exprPragmas)
@@ -1313,12 +1265,14 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
   for i in 0 .. <pragmaList.len:
     case whichPragma(pragmaList.sons[i])
     of wLine: setLine(result, pragmaList.sons[i].info)
-    of wLocks: 
+    of wLocks:
       result = n
       result.typ = n.sons[1].typ
     else: discard
 
 proc semStaticStmt(c: PContext, n: PNode): PNode =
+  #echo "semStaticStmt"
+  #writeStackTrace()
   let a = semStmt(c, n.sons[0])
   n.sons[0] = a
   evalStaticStmt(c.module, a, c.p.owner)
@@ -1336,7 +1290,8 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
 proc usesResult(n: PNode): bool =
   # nkStmtList(expr) properly propagates the void context,
   # so we don't need to process that all over again:
-  if n.kind notin {nkStmtList, nkStmtListExpr} + procDefs:
+  if n.kind notin {nkStmtList, nkStmtListExpr,
+                   nkMacroDef, nkTemplateDef} + procDefs:
     if isAtom(n):
       result = n.kind == nkSym and n.sym.kind == skResult
     elif n.kind == nkReturnStmt:
@@ -1388,18 +1343,23 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
       var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
       var body = newNodeI(nkStmtList, n.sons[i].info)
       if i < n.sonsLen - 1:
-        body.sons = n.sons[(i+1)..(-1)]
+        body.sons = n.sons[(i+1)..n.len-1]
       tryStmt.addSon(body)
       tryStmt.addSon(deferPart)
       n.sons[i] = semTry(c, tryStmt)
       n.sons.setLen(i+1)
+      n.typ = n.sons[i].typ
       return
     else:
       n.sons[i] = semExpr(c, n.sons[i])
-      if c.inTypeClass > 0 and n[i].typ != nil and n[i].typ.kind == tyBool:
-        let verdict = semConstExpr(c, n[i])
-        if verdict.intVal == 0:
-          localError(result.info, "type class predicate failed")
+      if c.inTypeClass > 0 and n[i].typ != nil:
+        case n[i].typ.kind
+        of tyBool:
+          let verdict = semConstExpr(c, n[i])
+          if verdict.intVal == 0:
+            localError(result.info, "type class predicate failed")
+        of tyUnknown: continue
+        else: discard
       if n.sons[i].typ == enforceVoidContext or usesResult(n.sons[i]):
         voidContext = true
         n.typ = enforceVoidContext
@@ -1420,8 +1380,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
           inner.addSon(semStmtList(c, rest, flags))
           n.sons.setLen(i+1)
           return
-      of LastBlockStmts: 
-        for j in countup(i + 1, length - 1): 
+      of LastBlockStmts:
+        for j in countup(i + 1, length - 1):
           case n.sons[j].kind
           of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard
           else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
@@ -1443,7 +1403,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
         #  "Last expression must be explicitly returned if it " &
         #  "is discardable or discarded")
 
-proc semStmt(c: PContext, n: PNode): PNode = 
+proc semStmt(c: PContext, n: PNode): PNode =
   # now: simply an alias:
   result = semExprNoType(c, n)
 
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 38b0536db..161d22fc1 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -10,17 +10,17 @@
 # included from sem.nim
 
 discard """
-  hygienic templates: 
-  
+  hygienic templates:
+
     template `||` (a, b: expr): expr =
       let aa = a
       if aa: aa else: b
-    
+
     var
       a, b: T
-      
+
     a || b || a
-    
+
   Each evaluation context has to be different and we need to perform
   some form of preliminary symbol lookup in template definitions. Hygiene is
   a way to achieve lexical scoping at compile time.
@@ -50,7 +50,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
     o: TOverloadIter
   var i = 0
   a = initOverloadIter(o, c, n)
-  while a != nil: 
+  while a != nil:
     a = nextOverloadIter(o, c, n)
     inc(i)
     if i > 1: break
@@ -96,7 +96,7 @@ proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
   for i in 0 .. < n.len:
     toMixin.incl(considerQuotedIdent(n.sons[i]).id)
   result = newNodeI(nkEmpty, n.info)
-  
+
 proc replaceIdentBySym(n: var PNode, s: PNode) =
   case n.kind
   of nkPostfix: replaceIdentBySym(n.sons[1], s)
@@ -105,10 +105,11 @@ proc replaceIdentBySym(n: var PNode, s: PNode) =
   else: illFormedAst(n)
 
 type
-  TemplCtx {.pure, final.} = object
+  TemplCtx = object
     c: PContext
     toBind, toMixin, toInject: IntSet
     owner: PSym
+    cursorInBody: bool # only for nimsuggest
 
 proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
   case n.kind
@@ -127,14 +128,14 @@ proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
 
 proc isTemplParam(c: TemplCtx, n: PNode): bool {.inline.} =
   result = n.kind == nkSym and n.sym.kind == skParam and
-           n.sym.owner == c.owner
+           n.sym.owner == c.owner and sfGenSym notin n.sym.flags
 
 proc semTemplBody(c: var TemplCtx, n: PNode): PNode
 
 proc openScope(c: var TemplCtx) = openScope(c.c)
 proc closeScope(c: var TemplCtx) = closeScope(c.c)
 
-proc semTemplBodyScope(c: var TemplCtx, n: PNode): PNode = 
+proc semTemplBodyScope(c: var TemplCtx, n: PNode): PNode =
   openScope(c)
   result = semTemplBody(c, n)
   closeScope(c)
@@ -190,24 +191,24 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
     else:
       replaceIdentBySym(n, ident)
 
-proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode = 
+proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
   incl(s.flags, sfUsed)
   # we do not call styleCheckUse here, as the identifier is not really
   # resolved here. We will fixup the used identifiers later.
   case s.kind
-  of skUnknown: 
+  of skUnknown:
     # Introduced in this pass! Leave it as an identifier.
     result = n
   of OverloadableSyms:
     result = symChoice(c, n, s, scOpen)
-  of skGenericParam: 
+  of skGenericParam:
     result = newSymNodeTypeDesc(s, n.info)
-  of skParam: 
+  of skParam:
     result = n
-  of skType: 
-    if (s.typ != nil) and (s.typ.kind != tyGenericParam): 
+  of skType:
+    if (s.typ != nil) and (s.typ.kind != tyGenericParam):
       result = newSymNodeTypeDesc(s, n.info)
-    else: 
+    else:
       result = n
   else:
     result = newSymNode(s, n.info)
@@ -246,8 +247,8 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
     n.sons[i] = semTemplBody(c, n.sons[i])
   closeScope(c)
 
-proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind) =
-  for i in countup(0, sonsLen(n) - 1):
+proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind; start=0) =
+  for i in countup(start, sonsLen(n) - 1):
     var a = n.sons[i]
     if a.kind == nkCommentStmt: continue
     if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a)
@@ -259,8 +260,9 @@ proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind) =
       addLocalDecl(c, a.sons[j], symKind)
 
 proc semPattern(c: PContext, n: PNode): PNode
-proc semTemplBody(c: var TemplCtx, n: PNode): PNode = 
+proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
   result = n
+  semIdeForTemplateOrGenericCheck(n, c.cursorInBody)
   case n.kind
   of nkIdent:
     if n.ident.id in c.toInject: return n
@@ -303,21 +305,21 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
         n.sons[i] = semTemplBodyScope(c, it)
   of nkWhileStmt:
     openScope(c)
-    for i in countup(0, sonsLen(n)-1): 
+    for i in countup(0, sonsLen(n)-1):
       n.sons[i] = semTemplBody(c, n.sons[i])
     closeScope(c)
   of nkCaseStmt:
     openScope(c)
     n.sons[0] = semTemplBody(c, n.sons[0])
-    for i in countup(1, sonsLen(n)-1): 
+    for i in countup(1, sonsLen(n)-1):
       var a = n.sons[i]
       checkMinSonsLen(a, 1)
       var L = sonsLen(a)
-      for j in countup(0, L-2): 
+      for j in countup(0, L-2):
         a.sons[j] = semTemplBody(c, a.sons[j])
       a.sons[L-1] = semTemplBodyScope(c, a.sons[L-1])
     closeScope(c)
-  of nkForStmt, nkParForStmt: 
+  of nkForStmt, nkParForStmt:
     var L = sonsLen(n)
     openScope(c)
     n.sons[L-2] = semTemplBody(c, n.sons[L-2])
@@ -336,45 +338,49 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
       n.sons[0] = newSymNode(s, n.sons[0].info)
     n.sons[1] = semTemplBody(c, n.sons[1])
     closeScope(c)
-  of nkTryStmt: 
+  of nkTryStmt:
     checkMinSonsLen(n, 2)
     n.sons[0] = semTemplBodyScope(c, n.sons[0])
-    for i in countup(1, sonsLen(n)-1): 
+    for i in countup(1, sonsLen(n)-1):
       var a = n.sons[i]
       checkMinSonsLen(a, 1)
       var L = sonsLen(a)
-      for j in countup(0, L-2): 
+      for j in countup(0, L-2):
         a.sons[j] = semTemplBody(c, a.sons[j])
       a.sons[L-1] = semTemplBodyScope(c, a.sons[L-1])
   of nkVarSection: semTemplSomeDecl(c, n, skVar)
   of nkLetSection: semTemplSomeDecl(c, n, skLet)
+  of nkFormalParams:
+    checkMinSonsLen(n, 1)
+    n.sons[0] = semTemplBody(c, n.sons[0])
+    semTemplSomeDecl(c, n, skParam, 1)
   of nkConstSection:
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       var a = n.sons[i]
-      if a.kind == nkCommentStmt: continue 
+      if a.kind == nkCommentStmt: continue
       if (a.kind != nkConstDef): illFormedAst(a)
       checkSonsLen(a, 3)
       addLocalDecl(c, a.sons[0], skConst)
       a.sons[1] = semTemplBody(c, a.sons[1])
       a.sons[2] = semTemplBody(c, a.sons[2])
-  of nkTypeSection: 
-    for i in countup(0, sonsLen(n) - 1): 
+  of nkTypeSection:
+    for i in countup(0, sonsLen(n) - 1):
       var a = n.sons[i]
-      if a.kind == nkCommentStmt: continue 
+      if a.kind == nkCommentStmt: continue
       if (a.kind != nkTypeDef): illFormedAst(a)
       checkSonsLen(a, 3)
       addLocalDecl(c, a.sons[0], skType)
     for i in countup(0, sonsLen(n) - 1):
       var a = n.sons[i]
-      if a.kind == nkCommentStmt: continue 
+      if a.kind == nkCommentStmt: continue
       if (a.kind != nkTypeDef): illFormedAst(a)
       checkSonsLen(a, 3)
-      if a.sons[1].kind != nkEmpty: 
+      if a.sons[1].kind != nkEmpty:
         openScope(c)
         a.sons[1] = semTemplBody(c, a.sons[1])
         a.sons[2] = semTemplBody(c, a.sons[2])
         closeScope(c)
-      else: 
+      else:
         a.sons[2] = semTemplBody(c, a.sons[2])
   of nkProcDef, nkLambdaKinds:
     result = semRoutineInTemplBody(c, n, skProc)
@@ -402,7 +408,13 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
     if n.kind == nkDotExpr or n.kind == nkAccQuoted:
       let s = qualifiedLookUp(c.c, n, {})
       if s != nil:
-        if contains(c.toBind, s.id):
+        # do not symchoice a quoted template parameter (bug #2390):
+        if s.owner == c.owner and s.kind == skParam and
+            n.kind == nkAccQuoted and n.len == 1:
+          incl(s.flags, sfUsed)
+          styleCheckUse(n.info, s)
+          return newSymNode(s, n.info)
+        elif contains(c.toBind, s.id):
           return symChoice(c.c, n, s, scClosed)
         elif contains(c.toMixin, s.name.id):
           return symChoice(c.c, n, s, scForceOpen)
@@ -412,8 +424,9 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
     for i in countup(0, sonsLen(n) - 1):
       result.sons[i] = semTemplBody(c, n.sons[i])
 
-proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode = 
+proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
   result = n
+  semIdeForTemplateOrGenericCheck(n, c.cursorInBody)
   case n.kind
   of nkIdent:
     let s = qualifiedLookUp(c.c, n, {})
@@ -429,7 +442,7 @@ proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
   of nkEmpty, nkSym..nkNilLit:
     discard
   else:
-    # dotExpr is ambiguous: note that we explicitely allow 'x.TemplateParam',
+    # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
     # so we use the generic code for nkDotExpr too
     if n.kind == nkDotExpr or n.kind == nkAccQuoted:
       let s = qualifiedLookUp(c.c, n, {})
@@ -438,38 +451,38 @@ proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
     result = n
     for i in countup(0, sonsLen(n) - 1):
       result.sons[i] = semTemplBodyDirty(c, n.sons[i])
-  
-proc transformToExpr(n: PNode): PNode = 
+
+proc transformToExpr(n: PNode): PNode =
   var realStmt: int
   result = n
   case n.kind
-  of nkStmtList: 
+  of nkStmtList:
     realStmt = - 1
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       case n.sons[i].kind
-      of nkCommentStmt, nkEmpty, nkNilLit: 
+      of nkCommentStmt, nkEmpty, nkNilLit:
         discard
-      else: 
+      else:
         if realStmt == - 1: realStmt = i
         else: realStmt = - 2
     if realStmt >= 0: result = transformToExpr(n.sons[realStmt])
     else: n.kind = nkStmtListExpr
-  of nkBlockStmt: 
+  of nkBlockStmt:
     n.kind = nkBlockExpr
     #nkIfStmt: n.kind = nkIfExpr // this is not correct!
   else:
     discard
 
-proc semTemplateDef(c: PContext, n: PNode): PNode = 
+proc semTemplateDef(c: PContext, n: PNode): PNode =
   var s: PSym
-  if c.p.owner.kind == skModule: 
+  if c.p.owner.kind == skModule:
     s = semIdentVis(c, skTemplate, n.sons[0], {sfExported})
     incl(s.flags, sfGlobal)
   else:
     s = semIdentVis(c, skTemplate, n.sons[0], {})
   styleCheckDef(s)
   # check parameter list:
-  s.scope = c.currentScope
+  #s.scope = c.currentScope
   pushOwner(s)
   openScope(c)
   n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
@@ -477,14 +490,19 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
     pragma(c, s, n.sons[pragmasPos], templatePragmas)
 
   var gp: PNode
-  if n.sons[genericParamsPos].kind != nkEmpty: 
+  if n.sons[genericParamsPos].kind != nkEmpty:
     n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
     gp = n.sons[genericParamsPos]
-  else: 
+  else:
     gp = newNodeI(nkGenericParams, n.info)
   # process parameters:
   if n.sons[paramsPos].kind != nkEmpty:
     semParamList(c, n.sons[paramsPos], gp, s)
+    # a template's parameters are not gensym'ed even if that was originally the
+    # case as we determine whether it's a template parameter in the template
+    # body by the absence of the sfGenSym flag:
+    for i in 1 .. s.typ.n.len-1:
+      s.typ.n.sons[i].sym.flags.excl sfGenSym
     if sonsLen(gp) > 0:
       if n.sons[genericParamsPos].kind == nkEmpty:
         # we have a list of implicit type parameters:
@@ -513,13 +531,14 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
   else:
     n.sons[bodyPos] = semTemplBody(ctx, n.sons[bodyPos])
   if s.typ.sons[0].kind notin {tyStmt, tyTypeDesc}:
-    n.sons[bodyPos] = transformToExpr(n.sons[bodyPos]) 
+    n.sons[bodyPos] = transformToExpr(n.sons[bodyPos])
     # only parameters are resolved, no type checking is performed
+  semIdeForTemplateOrGeneric(c, n.sons[bodyPos], ctx.cursorInBody)
   closeScope(c)
   popOwner()
   s.ast = n
   result = n
-  if n.sons[bodyPos].kind == nkEmpty: 
+  if n.sons[bodyPos].kind == nkEmpty:
     localError(n.info, errImplOfXexpected, s.name.s)
   var proto = searchForProc(c, c.currentScope, s)
   if proto == nil:
@@ -532,7 +551,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
 proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
   template templToExpand(s: expr): expr =
     s.kind == skTemplate and (s.typ.len == 1 or sfImmediate in s.flags)
-  
+
   proc newParam(c: var TemplCtx, n: PNode, s: PSym): PNode =
     # the param added in the current scope is actually wrong here for
     # macros because they have a shadowed param of type 'PNimNode' (see
@@ -543,7 +562,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
     let x = c.owner.typ.n.sons[s.position+1].sym
     assert x.name == s.name
     result = newSymNode(x, n.info)
-  
+
   proc handleSym(c: var TemplCtx, n: PNode, s: PSym): PNode =
     result = n
     if s != nil:
@@ -557,7 +576,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
         discard
         # we keep the ident unbound for matching instantiated symbols and
         # more flexibility
-  
+
   proc expectParam(c: var TemplCtx, n: PNode): PNode =
     let s = qualifiedLookUp(c.c, n, {})
     if s != nil and s.owner == c.owner and s.kind == skParam:
@@ -565,7 +584,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
     else:
       localError(n.info, errInvalidExpression)
       result = n
-  
+
   result = n
   case n.kind
   of nkIdent:
@@ -575,7 +594,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
     result = semBindStmt(c.c, n, c.toBind)
   of nkEmpty, nkSym..nkNilLit: discard
   of nkCurlyExpr:
-    # we support '(pattern){x}' to bind a subpattern to a parameter 'x'; 
+    # we support '(pattern){x}' to bind a subpattern to a parameter 'x';
     # '(pattern){|x}' does the same but the matches will be gathered in 'x'
     if n.len != 2:
       localError(n.info, errInvalidExpression)
@@ -598,7 +617,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
       elif contains(c.toBind, s.id): discard
       elif templToExpand(s):
         return semPatternBody(c, semTemplateExpr(c.c, n, s, {efNoSemCheck}))
-    
+
     if n.kind == nkInfix and n.sons[0].kind == nkIdent:
       # we interpret `*` and `|` only as pattern operators if they occur in
       # infix notation, so that '`*`(a, b)' can be used for verbatim matching:
@@ -615,7 +634,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
         result.sons[1] = semPatternBody(c, n.sons[1])
         result.sons[2] = semPatternBody(c, n.sons[2])
         return
-    
+
     if n.kind == nkPrefix and n.sons[0].kind == nkIdent:
       let opr = n.sons[0]
       if opr.ident.s == "~":
@@ -623,13 +642,13 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
         result.sons[0] = opr
         result.sons[1] = semPatternBody(c, n.sons[1])
         return
-    
+
     for i in countup(0, sonsLen(n) - 1):
       result.sons[i] = semPatternBody(c, n.sons[i])
   else:
-    # dotExpr is ambiguous: note that we explicitely allow 'x.TemplateParam',
+    # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
     # so we use the generic code for nkDotExpr too
-    case n.kind 
+    case n.kind
     of nkDotExpr, nkAccQuoted:
       let s = qualifiedLookUp(c.c, n, {})
       if s != nil:
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index d71ad6fe6..304fe6d14 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -10,14 +10,14 @@
 # this module does the semantic checking of type declarations
 # included from sem.nim
 
-proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType = 
-  if prev == nil: 
+proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
+  if prev == nil:
     result = newTypeS(kind, c)
-  else: 
+  else:
     result = prev
     if result.kind == tyForward: result.kind = kind
 
-proc newConstraint(c: PContext, k: TTypeKind): PType = 
+proc newConstraint(c: PContext, k: TTypeKind): PType =
   result = newTypeS(tyBuiltInTypeClass, c)
   result.addSonSkipIntLit(newTypeS(k, c))
 
@@ -32,22 +32,22 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
   result = newOrPrevType(tyEnum, prev, c)
   result.n = newNodeI(nkEnumTy, n.info)
   checkMinSonsLen(n, 1)
-  if n.sons[0].kind != nkEmpty: 
+  if n.sons[0].kind != nkEmpty:
     base = semTypeNode(c, n.sons[0].sons[0], nil)
-    if base.kind != tyEnum: 
+    if base.kind != tyEnum:
       localError(n.sons[0].info, errInheritanceOnlyWithEnums)
     counter = lastOrd(base) + 1
   rawAddSon(result, base)
   let isPure = result.sym != nil and sfPure in result.sym.flags
   var hasNull = false
-  for i in countup(1, sonsLen(n) - 1): 
+  for i in countup(1, sonsLen(n) - 1):
     case n.sons[i].kind
-    of nkEnumFieldDef: 
+    of nkEnumFieldDef:
       e = newSymS(skEnumField, n.sons[i].sons[0], c)
       var v = semConstExpr(c, n.sons[i].sons[1])
       var strVal: PNode = nil
-      case skipTypes(v.typ, abstractInst-{tyTypeDesc}).kind 
-      of tyTuple: 
+      case skipTypes(v.typ, abstractInst-{tyTypeDesc}).kind
+      of tyTuple:
         if sonsLen(v) == 2:
           strVal = v.sons[1] # second tuple part is the string value
           if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCString}:
@@ -63,14 +63,14 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
         x = getOrdValue(v)
       if i != 1:
         if x != counter: incl(result.flags, tfEnumHasHoles)
-        if x < counter: 
+        if x < counter:
           localError(n.sons[i].info, errInvalidOrderInEnumX, e.name.s)
           x = counter
       e.ast = strVal # might be nil
       counter = x
-    of nkSym: 
+    of nkSym:
       e = n.sons[i].sym
-    of nkIdent, nkAccQuoted: 
+    of nkIdent, nkAccQuoted:
       e = newSymS(skEnumField, n.sons[i], c)
     else:
       illFormedAst(n[i])
@@ -87,28 +87,28 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
     inc(counter)
   if not hasNull: incl(result.flags, tfNeedsInit)
 
-proc semSet(c: PContext, n: PNode, prev: PType): PType = 
+proc semSet(c: PContext, n: PNode, prev: PType): PType =
   result = newOrPrevType(tySet, prev, c)
-  if sonsLen(n) == 2: 
+  if sonsLen(n) == 2:
     var base = semTypeNode(c, n.sons[1], nil)
     addSonSkipIntLit(result, base)
     if base.kind == tyGenericInst: base = lastSon(base)
     if base.kind != tyGenericParam:
-      if not isOrdinalType(base): 
+      if not isOrdinalType(base):
         localError(n.info, errOrdinalTypeExpected)
-      elif lengthOrd(base) > MaxSetElements: 
+      elif lengthOrd(base) > MaxSetElements:
         localError(n.info, errSetTooBig)
   else:
     localError(n.info, errXExpectsOneTypeParam, "set")
     addSonSkipIntLit(result, errorType(c))
-  
-proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string, 
-                  prev: PType): PType = 
+
+proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
+                  prev: PType): PType =
   result = newOrPrevType(kind, prev, c)
-  if sonsLen(n) == 2: 
+  if sonsLen(n) == 2:
     var base = semTypeNode(c, n.sons[1], nil)
     addSonSkipIntLit(result, base)
-  else: 
+  else:
     localError(n.info, errXExpectsOneTypeParam, kindStr)
     addSonSkipIntLit(result, errorType(c))
 
@@ -140,23 +140,23 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
     var base = semTypeNode(c, n.lastSon, nil)
     addSonSkipIntLit(result, base)
 
-proc semVarType(c: PContext, n: PNode, prev: PType): PType = 
-  if sonsLen(n) == 1: 
+proc semVarType(c: PContext, n: PNode, prev: PType): PType =
+  if sonsLen(n) == 1:
     result = newOrPrevType(tyVar, prev, c)
     var base = semTypeNode(c, n.sons[0], nil)
-    if base.kind == tyVar: 
+    if base.kind == tyVar:
       localError(n.info, errVarVarTypeNotAllowed)
       base = base.sons[0]
     addSonSkipIntLit(result, base)
   else:
     result = newConstraint(c, tyVar)
 
-proc semDistinct(c: PContext, n: PNode, prev: PType): PType = 
+proc semDistinct(c: PContext, n: PNode, prev: PType): PType =
   if n.len == 0: return newConstraint(c, tyDistinct)
   result = newOrPrevType(tyDistinct, prev, c)
   addSonSkipIntLit(result, semTypeNode(c, n.sons[0], nil))
   if n.len > 1: result.n = n[1]
-  
+
 proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
   assert isRange(n)
   checkSonsLen(n, 3)
@@ -164,11 +164,11 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
   result.n = newNodeI(nkRange, n.info)
   if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty):
     localError(n.info, errRangeIsEmpty)
-  
+
   var range: array[2, PNode]
   range[0] = semExprWithType(c, n[1], {efDetermineType})
   range[1] = semExprWithType(c, n[2], {efDetermineType})
-  
+
   var rangeT: array[2, PType]
   for i in 0..1:
     rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit
@@ -179,13 +179,13 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
     localError(n.info, errOrdinalTypeExpected)
   elif enumHasHoles(rangeT[0]):
     localError(n.info, errEnumXHasHoles, rangeT[0].sym.name.s)
-  
+
   for i in 0..1:
     if hasGenericArguments(range[i]):
       result.n.addSon makeStaticExpr(c, range[i])
     else:
       result.n.addSon semConstExpr(c, range[i])
- 
+
   if weakLeValue(result.n[0], result.n[1]) == impNo:
     localError(n.info, errRangeIsEmpty)
 
@@ -201,10 +201,10 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
         incl(result.flags, tfNeedsInit)
       elif n.sons[1].kind in {nkCharLit..nkUInt64Lit} and n.sons[1].intVal < 0:
         incl(result.flags, tfNeedsInit)
-      elif n.sons[0].kind in {nkFloatLit..nkFloat64Lit} and 
+      elif n.sons[0].kind in {nkFloatLit..nkFloat64Lit} and
           n.sons[0].floatVal > 0.0:
         incl(result.flags, tfNeedsInit)
-      elif n.sons[1].kind in {nkFloatLit..nkFloat64Lit} and 
+      elif n.sons[1].kind in {nkFloatLit..nkFloat64Lit} and
           n.sons[1].floatVal < 0.0:
         incl(result.flags, tfNeedsInit)
     else:
@@ -214,63 +214,67 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
     localError(n.info, errXExpectsOneTypeParam, "range")
     result = newOrPrevType(tyError, prev, c)
 
-proc semArray(c: PContext, n: PNode, prev: PType): PType = 
-  var indx, base: PType
-  result = newOrPrevType(tyArray, prev, c)
-  if sonsLen(n) == 3: 
-    # 3 = length(array indx base)
-    if isRange(n[1]): indx = semRangeAux(c, n[1], nil)
+proc semArrayIndex(c: PContext, n: PNode): PType =
+  if isRange(n): result = semRangeAux(c, n, nil)
+  else:
+    let e = semExprWithType(c, n, {efDetermineType})
+    if e.typ.kind == tyFromExpr:
+      result = makeRangeWithStaticExpr(c, e.typ.n)
+    elif e.kind in {nkIntLit..nkUInt64Lit}:
+      result = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
+    elif e.kind == nkSym and e.typ.kind == tyStatic:
+      if e.sym.ast != nil:
+        return semArrayIndex(c, e.sym.ast)
+      if not isOrdinalType(e.typ.lastSon):
+        localError(n[1].info, errOrdinalTypeExpected)
+      result = makeRangeWithStaticExpr(c, e)
+      if c.inGenericContext > 0: result.flags.incl tfUnresolved
+    elif e.kind in nkCallKinds and hasGenericArguments(e):
+      if not isOrdinalType(e.typ):
+        localError(n[1].info, errOrdinalTypeExpected)
+      # This is an int returning call, depending on an
+      # yet unknown generic param (see tgenericshardcases).
+      # We are going to construct a range type that will be
+      # properly filled-out in semtypinst (see how tyStaticExpr
+      # is handled there).
+      result = makeRangeWithStaticExpr(c, e)
+    elif e.kind == nkIdent:
+      result = e.typ.skipTypes({tyTypeDesc})
     else:
-      let e = semExprWithType(c, n.sons[1], {efDetermineType})
-      if e.typ.kind == tyFromExpr:
-        indx = makeRangeWithStaticExpr(c, e.typ.n)
-      elif e.kind in {nkIntLit..nkUInt64Lit}:
-        indx = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
-      elif e.kind == nkSym and e.typ.kind == tyStatic:
-        if e.sym.ast != nil: return semArray(c, e.sym.ast, nil)
-        internalAssert c.inGenericContext > 0
-        if not isOrdinalType(e.typ.lastSon):
-          localError(n[1].info, errOrdinalTypeExpected)
-        indx = makeRangeWithStaticExpr(c, e)
-        indx.flags.incl tfUnresolved
-      elif e.kind in nkCallKinds and hasGenericArguments(e):
-        if not isOrdinalType(e.typ):
-          localError(n[1].info, errOrdinalTypeExpected)
-        # This is an int returning call, depending on an
-        # yet unknown generic param (see tgenericshardcases).
-        # We are going to construct a range type that will be
-        # properly filled-out in semtypinst (see how tyStaticExpr
-        # is handled there).
-        indx = makeRangeWithStaticExpr(c, e)
-      elif e.kind == nkIdent:
-        indx = e.typ.skipTypes({tyTypeDesc})
+      let x = semConstExpr(c, e)
+      if x.kind in {nkIntLit..nkUInt64Lit}:
+        result = makeRangeType(c, 0, x.intVal-1, n.info,
+                             x.typ.skipTypes({tyTypeDesc}))
       else:
-        let x = semConstExpr(c, e)
-        if x.kind in {nkIntLit..nkUInt64Lit}:
-          indx = makeRangeType(c, 0, x.intVal-1, n.info, 
-                               x.typ.skipTypes({tyTypeDesc}))
-        else:
-          indx = x.typ.skipTypes({tyTypeDesc})
-          #localError(n[1].info, errConstExprExpected)
+        result = x.typ.skipTypes({tyTypeDesc})
+        #localError(n[1].info, errConstExprExpected)
+
+proc semArray(c: PContext, n: PNode, prev: PType): PType =
+  var base: PType
+  result = newOrPrevType(tyArray, prev, c)
+  if sonsLen(n) == 3:
+    # 3 = length(array indx base)
+    var indx = semArrayIndex(c, n[1])
     addSonSkipIntLit(result, indx)
     if indx.kind == tyGenericInst: indx = lastSon(indx)
     if indx.kind notin {tyGenericParam, tyStatic, tyFromExpr}:
       if not isOrdinalType(indx):
         localError(n.sons[1].info, errOrdinalTypeExpected)
-      elif enumHasHoles(indx): 
-        localError(n.sons[1].info, errEnumXHasHoles, indx.sym.name.s)
+      elif enumHasHoles(indx):
+        localError(n.sons[1].info, errEnumXHasHoles,
+                   typeToString(indx.skipTypes({tyRange})))
     base = semTypeNode(c, n.sons[2], nil)
     addSonSkipIntLit(result, base)
-  else: 
+  else:
     localError(n.info, errArrayExpectsTwoTypeParams)
     result = newOrPrevType(tyError, prev, c)
-  
-proc semOrdinal(c: PContext, n: PNode, prev: PType): PType = 
+
+proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
   result = newOrPrevType(tyOrdinal, prev, c)
-  if sonsLen(n) == 2: 
+  if sonsLen(n) == 2:
     var base = semTypeNode(c, n.sons[1], nil)
-    if base.kind != tyGenericParam: 
-      if not isOrdinalType(base): 
+    if base.kind != tyGenericParam:
+      if not isOrdinalType(base):
         localError(n.sons[1].info, errOrdinalTypeExpected)
     addSonSkipIntLit(result, base)
   else:
@@ -278,7 +282,7 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
     result = newOrPrevType(tyError, prev, c)
 
 proc semTypeIdent(c: PContext, n: PNode): PSym =
-  if n.kind == nkSym: 
+  if n.kind == nkSym:
     result = n.sym
   else:
     when defined(nimfix):
@@ -304,7 +308,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
         result = result.typ.sym.copySym
         result.typ = copyType(result.typ, result.typ.owner, true)
         result.typ.flags.incl tfUnresolved
-      
+
       if result.kind == skGenericParam:
         if result.typ.kind == tyGenericParam and result.typ.len == 0 and
            tfWildcard in result.typ.flags:
@@ -316,7 +320,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
           localError(n.info, errTypeExpected)
           return errorSym(c, n)
 
-      if result.kind != skType: 
+      if result.kind != skType:
         # this implements the wanted ``var v: V, x: V`` feature ...
         var ov: TOverloadIter
         var amb = initOverloadIter(ov, c, n)
@@ -329,55 +333,66 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
       if result.typ.kind != tyGenericParam:
         # XXX get rid of this hack!
         var oldInfo = n.info
+        when defined(useNodeIds):
+          let oldId = n.id
         reset(n[])
+        when defined(useNodeIds):
+          n.id = oldId
         n.kind = nkSym
         n.sym = result
         n.info = oldInfo
+        n.typ = result.typ
     else:
       localError(n.info, errIdentifierExpected)
       result = errorSym(c, n)
-  
-proc semTuple(c: PContext, n: PNode, prev: PType): PType = 
-  if n.sonsLen == 0: return newConstraint(c, tyTuple)
+
+proc semAnonTuple(c: PContext, n: PNode, prev: PType): PType =
+  if sonsLen(n) == 0:
+    localError(n.info, errTypeExpected)
+  result = newOrPrevType(tyTuple, prev, c)
+  for i in countup(0, sonsLen(n) - 1):
+    addSonSkipIntLit(result, semTypeNode(c, n.sons[i], nil))
+
+proc semTuple(c: PContext, n: PNode, prev: PType): PType =
   var typ: PType
   result = newOrPrevType(tyTuple, prev, c)
   result.n = newNodeI(nkRecList, n.info)
   var check = initIntSet()
   var counter = 0
-  for i in countup(0, sonsLen(n) - 1): 
+  for i in countup(0, sonsLen(n) - 1):
     var a = n.sons[i]
     if (a.kind != nkIdentDefs): illFormedAst(a)
     checkMinSonsLen(a, 3)
     var length = sonsLen(a)
-    if a.sons[length - 2].kind != nkEmpty: 
+    if a.sons[length - 2].kind != nkEmpty:
       typ = semTypeNode(c, a.sons[length - 2], nil)
     else:
       localError(a.info, errTypeExpected)
       typ = errorType(c)
-    if a.sons[length - 1].kind != nkEmpty: 
+    if a.sons[length - 1].kind != nkEmpty:
       localError(a.sons[length - 1].info, errInitHereNotAllowed)
-    for j in countup(0, length - 3): 
+    for j in countup(0, length - 3):
       var field = newSymG(skField, a.sons[j], c)
       field.typ = typ
       field.position = counter
       inc(counter)
-      if containsOrIncl(check, field.name.id): 
+      if containsOrIncl(check, field.name.id):
         localError(a.sons[j].info, errAttemptToRedefine, field.name.s)
       else:
         addSon(result.n, newSymNode(field))
         addSonSkipIntLit(result, typ)
       if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, field)
 
-proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, 
-                 allowed: TSymFlags): PSym = 
+proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
+                 allowed: TSymFlags): PSym =
   # identifier with visibility
-  if n.kind == nkPostfix: 
-    if sonsLen(n) == 2 and n.sons[0].kind == nkIdent: 
+  if n.kind == nkPostfix:
+    if sonsLen(n) == 2 and n.sons[0].kind == nkIdent:
       # for gensym'ed identifiers the identifier may already have been
       # transformed to a symbol and we need to use that here:
       result = newSymG(kind, n.sons[1], c)
       var v = n.sons[0].ident
-      if sfExported in allowed and v.id == ord(wStar): 
+      if sfExported in allowed and v.id == ord(wStar):
         incl(result.flags, sfExported)
       else:
         localError(n.sons[0].info, errInvalidVisibilityX, v.s)
@@ -385,14 +400,14 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
       illFormedAst(n)
   else:
     result = newSymG(kind, n, c)
-  
-proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode, 
-                        allowed: TSymFlags): PSym = 
-  if n.kind == nkPragmaExpr: 
+
+proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
+                        allowed: TSymFlags): PSym =
+  if n.kind == nkPragmaExpr:
     checkSonsLen(n, 2)
     result = semIdentVis(c, kind, n.sons[0], allowed)
     case kind
-    of skType: 
+    of skType:
       # process pragmas later, because result.typ has not been set yet
       discard
     of skField: pragma(c, result, n.sons[1], fieldPragmas)
@@ -403,35 +418,35 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
   else:
     result = semIdentVis(c, kind, n, allowed)
   if gCmd == cmdPretty: styleCheckDef(n.info, result)
-  
+
 proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
   let ex = t[branchIndex][currentEx].skipConv
   for i in countup(1, branchIndex):
-    for j in countup(0, sonsLen(t.sons[i]) - 2): 
+    for j in countup(0, sonsLen(t.sons[i]) - 2):
       if i == branchIndex and j == currentEx: break
       if overlap(t.sons[i].sons[j].skipConv, ex):
         localError(ex.info, errDuplicateCaseLabel)
-  
+
 proc semBranchRange(c: PContext, t, a, b: PNode, covered: var BiggestInt): PNode =
   checkMinSonsLen(t, 1)
   let ac = semConstExpr(c, a)
   let bc = semConstExpr(c, b)
   let at = fitNode(c, t.sons[0].typ, ac).skipConvTakeType
   let bt = fitNode(c, t.sons[0].typ, bc).skipConvTakeType
-  
+
   result = newNodeI(nkRange, a.info)
   result.add(at)
   result.add(bt)
   if emptyRange(ac, bc): localError(b.info, errRangeIsEmpty)
   else: covered = covered + getOrdValue(bc) - getOrdValue(ac) + 1
 
-proc semCaseBranchRange(c: PContext, t, b: PNode, 
-                        covered: var BiggestInt): PNode = 
+proc semCaseBranchRange(c: PContext, t, b: PNode,
+                        covered: var BiggestInt): PNode =
   checkSonsLen(b, 3)
   result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
 
-proc semCaseBranchSetElem(c: PContext, t, b: PNode, 
-                          covered: var BiggestInt): PNode = 
+proc semCaseBranchSetElem(c: PContext, t, b: PNode,
+                          covered: var BiggestInt): PNode =
   if isRange(b):
     checkSonsLen(b, 3)
     result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
@@ -442,9 +457,10 @@ proc semCaseBranchSetElem(c: PContext, t, b: PNode,
     result = fitNode(c, t.sons[0].typ, b)
     inc(covered)
 
-proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int, 
-                   covered: var BiggestInt) = 
-  for i in countup(0, sonsLen(branch) - 2): 
+proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
+                   covered: var BiggestInt) =
+
+  for i in countup(0, sonsLen(branch) - 2):
     var b = branch.sons[i]
     if b.kind == nkRange:
       branch.sons[i] = b
@@ -453,8 +469,11 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
     else:
       # constant sets and arrays are allowed:
       var r = semConstExpr(c, b)
-      # for ``{}`` we want to trigger the type mismatch in ``fitNode``:
-      if r.kind notin {nkCurly, nkBracket} or len(r) == 0:
+      if r.kind in {nkCurly, nkBracket} and len(r) == 0  and sonsLen(branch)==2:
+        # discarding ``{}`` and ``[]`` branches silently
+        delSon(branch, 0)
+        return
+      elif r.kind notin {nkCurly, nkBracket} or len(r) == 0:
         checkMinSonsLen(t, 1)
         branch.sons[i] = skipConv(fitNode(c, t.sons[0].typ, r))
         inc(covered)
@@ -468,7 +487,7 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
           var L = branch.len
           swap(branch.sons[L-2], branch.sons[L-1])
     checkForOverlap(c, t, i, branchIndex)
-    
+
 proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
                       father: PNode, rectype: PType)
 proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
@@ -502,11 +521,11 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
     else: illFormedAst(n)
     delSon(b, sonsLen(b) - 1)
     semRecordNodeAux(c, lastSon(n.sons[i]), check, pos, b, rectype)
-  if chckCovered and (covered != lengthOrd(a.sons[0].typ)): 
+  if chckCovered and (covered != lengthOrd(a.sons[0].typ)):
     localError(a.info, errNotAllCasesCovered)
   addSon(father, a)
 
-proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, 
+proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
                       father: PNode, rectype: PType) =
   if n == nil: return
   case n.kind
@@ -544,12 +563,12 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
       semRecordNodeAux(c, branch, check, pos, father, rectype)
   of nkRecCase:
     semRecordCase(c, n, check, pos, father, rectype)
-  of nkNilLit: 
+  of nkNilLit:
     if father.kind != nkRecList: addSon(father, newNodeI(nkRecList, n.info))
   of nkRecList:
     # attempt to keep the nesting at a sane level:
     var a = if father.kind == nkRecList: father else: copyNode(n)
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       semRecordNodeAux(c, n.sons[i], check, pos, a, rectype)
     if a != father: addSon(father, a)
   of nkIdentDefs:
@@ -558,10 +577,10 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
     var a: PNode
     if father.kind != nkRecList and length>=4: a = newNodeI(nkRecList, n.info)
     else: a = ast.emptyNode
-    if n.sons[length-1].kind != nkEmpty: 
+    if n.sons[length-1].kind != nkEmpty:
       localError(n.sons[length-1].info, errInitHereNotAllowed)
     var typ: PType
-    if n.sons[length-2].kind == nkEmpty: 
+    if n.sons[length-2].kind == nkEmpty:
       localError(n.info, errTypeExpected)
       typ = errorType(c)
     else:
@@ -574,8 +593,8 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
       f.typ = typ
       f.position = pos
       if (rec != nil) and ({sfImportc, sfExportc} * rec.flags != {}) and
-          (f.loc.r == nil): 
-        f.loc.r = toRope(f.name.s)
+          (f.loc.r == nil):
+        f.loc.r = rope(f.name.s)
         f.flags = f.flags + ({sfImportc, sfExportc} * rec.flags)
       inc(pos)
       if containsOrIncl(check, f.name.id):
@@ -586,8 +605,8 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
     if a.kind != nkEmpty: addSon(father, a)
   of nkEmpty: discard
   else: illFormedAst(n)
-  
-proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int, 
+
+proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
                            n: PNode) =
   case n.kind
   of nkRecCase:
@@ -605,36 +624,40 @@ proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
     incl(check, n.sym.name.id)
     inc(pos)
   else: internalError(n.info, "addInheritedFieldsAux()")
-  
-proc addInheritedFields(c: PContext, check: var IntSet, pos: var int, 
-                        obj: PType) = 
-  if (sonsLen(obj) > 0) and (obj.sons[0] != nil): 
-    addInheritedFields(c, check, pos, obj.sons[0])
-  addInheritedFieldsAux(c, check, pos, obj.n)
 
-proc skipGenericInvokation(t: PType): PType {.inline.} = 
+proc skipGenericInvocation(t: PType): PType {.inline.} =
   result = t
-  if result.kind == tyGenericInvokation:
+  if result.kind == tyGenericInvocation:
     result = result.sons[0]
   if result.kind == tyGenericBody:
     result = lastSon(result)
 
+proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
+                        obj: PType) =
+  assert obj.kind == tyObject
+  if (sonsLen(obj) > 0) and (obj.sons[0] != nil):
+    addInheritedFields(c, check, pos, obj.sons[0].skipGenericInvocation)
+  addInheritedFieldsAux(c, check, pos, obj.n)
+
 proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
   if n.sonsLen == 0: return newConstraint(c, tyObject)
   var check = initIntSet()
-  var pos = 0 
+  var pos = 0
   var base: PType = nil
   # n.sons[0] contains the pragmas (if any). We process these later...
   checkSonsLen(n, 3)
-  if n.sons[1].kind != nkEmpty: 
-    base = skipTypes(semTypeNode(c, n.sons[1].sons[0], nil), skipPtrs)
-    var concreteBase = skipGenericInvokation(base).skipTypes(skipPtrs)
-    if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags: 
-      addInheritedFields(c, check, pos, concreteBase)
+  if n.sons[1].kind != nkEmpty:
+    base = skipTypesOrNil(semTypeNode(c, n.sons[1].sons[0], nil), skipPtrs)
+    if base.isNil:
+      localError(n.info, errIllegalRecursionInTypeX, "object")
     else:
-      if concreteBase.kind != tyError:
-        localError(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects)
-      base = nil
+      var concreteBase = skipGenericInvocation(base).skipTypes(skipPtrs)
+      if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
+        addInheritedFields(c, check, pos, concreteBase)
+      else:
+        if concreteBase.kind != tyError:
+          localError(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects)
+        base = nil
   if n.kind != nkObjectTy: internalError(n.info, "semObjectNode")
   result = newOrPrevType(tyObject, prev, c)
   rawAddSon(result, base)
@@ -659,25 +682,23 @@ proc findEnforcedStaticType(t: PType): PType =
       if t != nil: return t
 
 proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
-  template addDecl(x) =
-    if sfGenSym notin x.flags: addDecl(c, x)
-
   if kind == skMacro:
     let staticType = findEnforcedStaticType(param.typ)
     if staticType != nil:
       var a = copySym(param)
       a.typ = staticType.base
-      addDecl(a)
+      addDecl(c, a)
     elif param.typ.kind == tyTypeDesc:
-      addDecl(param)
+      addDecl(c, param)
     else:
-      # within a macro, every param has the type PNimrodNode!
-      let nn = getSysSym"PNimrodNode"
+      # within a macro, every param has the type NimNode!
+      let nn = if getCompilerProc("NimNode") != nil: getSysSym"NimNode"
+               else: getSysSym"PNimrodNode"
       var a = copySym(param)
       a.typ = nn.typ
-      addDecl(a)
+      addDecl(c, a)
   else:
-    addDecl(param)
+    if sfGenSym notin param.flags: addDecl(c, param)
 
 let typedescId = getIdent"typedesc"
 
@@ -712,7 +733,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
     genericParams.addSon(newSymNode(s))
     result = typeClass
     addDecl(c, s)
- 
+
   # XXX: There are codegen errors if this is turned into a nested proc
   template liftingWalk(typ: PType, anonFlag = false): expr =
     liftParamType(c, procKind, genericParams, typ, paramName, info, anonFlag)
@@ -731,7 +752,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
   case paramType.kind:
   of tyAnything:
     result = addImplicitGeneric(newTypeS(tyGenericParam, c))
-  
+
   of tyStatic:
     # proc(a: expr{string}, b: expr{nkLambda})
     # overload on compile time values and AST trees
@@ -742,7 +763,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
       localError(info, errMacroBodyDependsOnGenericTypes, paramName)
     result = addImplicitGeneric(c.newTypeWithSons(tyStatic, @[base]))
     result.flags.incl({tfHasStatic, tfUnresolved})
-  
+
   of tyTypeDesc:
     if tfUnresolved notin paramType.flags:
       # naked typedescs are not bindOnce types
@@ -750,12 +771,12 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
          paramTypId.id == typedescId.id: paramTypId = nil
       result = addImplicitGeneric(
         c.newTypeWithSons(tyTypeDesc, @[paramType.base]))
-  
+
   of tyDistinct:
     if paramType.sonsLen == 1:
       # disable the bindOnce behavior for the type class
       result = liftingWalk(paramType.sons[0], true)
-  
+
   of tySequence, tySet, tyArray, tyOpenArray,
      tyVar, tyPtr, tyRef, tyProc:
     # XXX: this is a bit strange, but proc(s: seq)
@@ -769,24 +790,31 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
                                   @[newTypeS(paramType.kind, c)])
       result = addImplicitGeneric(typ)
     else:
-      for i in 0 .. <paramType.sons.len:
+      for i in 0 .. <paramType.len:
+        if paramType.sons[i] == paramType:
+          globalError(info, errIllegalRecursionInTypeX, typeToString(paramType))
         var lifted = liftingWalk(paramType.sons[i])
         if lifted != nil:
           paramType.sons[i] = lifted
           result = paramType
-  
+
   of tyGenericBody:
-    result = newTypeS(tyGenericInvokation, c)
+    result = newTypeS(tyGenericInvocation, c)
     result.rawAddSon(paramType)
+
     for i in 0 .. paramType.sonsLen - 2:
-      result.rawAddSon newTypeS(tyAnything, c)
-      # result.rawAddSon(copyType(paramType.sons[i], getCurrOwner(), true))
+      if paramType.sons[i].kind == tyStatic:
+        var x = copyNode(ast.emptyNode)
+        x.typ = paramType.sons[i]
+        result.rawAddSon makeTypeFromExpr(c, x) # aka 'tyUnknown'
+      else:
+        result.rawAddSon newTypeS(tyAnything, c)
 
     if paramType.lastSon.kind == tyUserTypeClass:
       result.kind = tyUserTypeClassInst
       result.rawAddSon paramType.lastSon
       return addImplicitGeneric(result)
-   
+
     result = instGenericContainer(c, paramType.sym.info, result,
                                   allowMetaTypes = true)
     result = newTypeWithSons(c, tyCompositeTypeClass, @[paramType, result])
@@ -807,7 +835,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
       cp.kind = tyUserTypeClassInst
       return addImplicitGeneric(cp)
 
-    for i in 1 .. (paramType.sons.len - 2):
+    for i in 1 .. paramType.len-2:
       var lifted = liftingWalk(paramType.sons[i])
       if lifted != nil:
         paramType.sons[i] = lifted
@@ -818,9 +846,9 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
     if liftBody != nil:
       result = liftBody
       result.shouldHaveMeta
- 
-  of tyGenericInvokation:
-    for i in 1 .. <paramType.sonsLen:
+
+  of tyGenericInvocation:
+    for i in 1 .. <paramType.len:
       let lifted = liftingWalk(paramType.sons[i])
       if lifted != nil: paramType.sons[i] = lifted
     when false:
@@ -830,18 +858,18 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
 
   of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
     result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
-  
+
   of tyExpr:
     if procKind notin {skMacro, skTemplate}:
       result = addImplicitGeneric(newTypeS(tyAnything, c))
-  
+
   of tyGenericParam:
     markUsed(info, paramType.sym)
     styleCheckUse(info, paramType.sym)
     if tfWildcard in paramType.flags:
       paramType.flags.excl tfWildcard
       paramType.sym.kind = skType
-    
+
   else: discard
 
   # result = liftingWalk(paramType)
@@ -853,23 +881,25 @@ proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
   else:
     result = semTypeNode(c, n, nil)
 
-proc semProcTypeNode(c: PContext, n, genericParams: PNode,
-                     prev: PType, kind: TSymKind): PType =
-  var
-    res: PNode
-    cl: IntSet
-  checkMinSonsLen(n, 1)
+proc newProcType(c: PContext; info: TLineInfo; prev: PType = nil): PType =
   result = newOrPrevType(tyProc, prev, c)
   result.callConv = lastOptionEntry(c).defaultCC
-  result.n = newNodeI(nkFormalParams, n.info)
-  if genericParams != nil and sonsLen(genericParams) == 0:
-    cl = initIntSet()
+  result.n = newNodeI(nkFormalParams, info)
   rawAddSon(result, nil) # return type
-  # result.n[0] used to be `nkType`, but now it's `nkEffectList` because 
+  # result.n[0] used to be `nkType`, but now it's `nkEffectList` because
   # the effects are now stored in there too ... this is a bit hacky, but as
   # usual we desperately try to save memory:
-  res = newNodeI(nkEffectList, n.info)
-  addSon(result.n, res)
+  addSon(result.n, newNodeI(nkEffectList, info))
+
+proc semProcTypeNode(c: PContext, n, genericParams: PNode,
+                     prev: PType, kind: TSymKind; isType=false): PType =
+  # for historical reasons (code grows) this is invoked for parameter
+  # lists too and then 'isType' is false.
+  var cl: IntSet
+  checkMinSonsLen(n, 1)
+  result = newProcType(c, n.info, prev)
+  if genericParams != nil and sonsLen(genericParams) == 0:
+    cl = initIntSet()
   var check = initIntSet()
   var counter = 0
   for i in countup(1, n.len - 1):
@@ -893,8 +923,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       typ = semParamType(c, a.sons[length-2], constraint)
 
     if hasDefault:
-      def = semExprWithType(c, a.sons[length-1]) 
-      # check type compability between def.typ and typ:
+      def = semExprWithType(c, a.sons[length-1])
+      # check type compatibility between def.typ and typ:
       if typ == nil:
         typ = def.typ
       elif def != nil:
@@ -903,12 +933,15 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
         # proc sort[T](cmp: proc(a, b: T): int = cmp)
         if not containsGenericType(typ):
           def = fitNode(c, typ, def)
-    if not (hasType or hasDefault):
+    if not hasType and not hasDefault:
+      if isType: localError(a.info, "':' expected")
       let tdef = if kind in {skTemplate, skMacro}: tyExpr else: tyAnything
+      if tdef == tyAnything:
+        message(a.info, warnTypelessParam, renderTree(n))
       typ = newTypeS(tdef, c)
 
     if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
-    for j in countup(0, length-3): 
+    for j in countup(0, length-3):
       var arg = newSymG(skParam, a.sons[j], c)
       let lifted = liftParamType(c, kind, genericParams, typ,
                                  arg.name.s, arg.info)
@@ -918,7 +951,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       arg.constraint = constraint
       inc(counter)
       if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
-      if containsOrIncl(check, arg.name.id): 
+      if containsOrIncl(check, arg.name.id):
         localError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
       addSon(result.n, newSymNode(arg))
       rawAddSon(result, finalType)
@@ -929,25 +962,28 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
   if n.sons[0].kind != nkEmpty:
     r = semTypeNode(c, n.sons[0], nil)
   elif kind == skIterator:
-    r = newTypeS(tyAnything, c)
-  
+    # XXX This is special magic we should likely get rid of
+    r = newTypeS(tyExpr, c)
+
   if r != nil:
-    # turn explicit 'void' return type into 'nil' because the rest of the 
+    # turn explicit 'void' return type into 'nil' because the rest of the
     # compiler only checks for 'nil':
     if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
-      if r.sym == nil or sfAnon notin r.sym.flags:
-        let lifted = liftParamType(c, kind, genericParams, r, "result",
-                                   n.sons[0].info)
-        if lifted != nil: r = lifted
-        r.flags.incl tfRetType
-      r = skipIntLit(r)
-      if kind == skIterator:
-        # see tchainediterators
-        # in cases like iterator foo(it: iterator): type(it)
-        # we don't need to change the return type to iter[T]
-        if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r])
+      # 'auto' as a return type does not imply a generic:
+      if r.kind != tyExpr:
+        if r.sym == nil or sfAnon notin r.sym.flags:
+          let lifted = liftParamType(c, kind, genericParams, r, "result",
+                                     n.sons[0].info)
+          if lifted != nil: r = lifted
+          r.flags.incl tfRetType
+        r = skipIntLit(r)
+        if kind == skIterator:
+          # see tchainediterators
+          # in cases like iterator foo(it: iterator): type(it)
+          # we don't need to change the return type to iter[T]
+          if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r])
       result.sons[0] = r
-      res.typ = r
+      result.n.typ = r
 
   if genericParams != nil:
     for n in genericParams:
@@ -966,8 +1002,8 @@ proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
     n.sons[length - 1].typ = result
   else:
     result = nil
-  
-proc semBlockType(c: PContext, n: PNode, prev: PType): PType = 
+
+proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
   inc(c.p.nestedBlockCounter)
   checkSonsLen(n, 2)
   openScope(c)
@@ -979,7 +1015,7 @@ proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
   closeScope(c)
   dec(c.p.nestedBlockCounter)
 
-proc semGenericParamInInvokation(c: PContext, n: PNode): PType =
+proc semGenericParamInInvocation(c: PContext, n: PNode): PType =
   result = semTypeNode(c, n, nil)
 
 proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
@@ -987,12 +1023,12 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
     localError(n.info, "cannot instantiate the '$1' $2" %
                        [s.name.s, ($s.kind).substr(2).toLower])
     return newOrPrevType(tyError, prev, c)
-  
+
   var t = s.typ
   if t.kind == tyCompositeTypeClass and t.base.kind == tyGenericBody:
     t = t.base
 
-  result = newOrPrevType(tyGenericInvokation, prev, c)
+  result = newOrPrevType(tyGenericInvocation, prev, c)
   addSonSkipIntLit(result, t)
 
   template addToResult(typ) =
@@ -1003,32 +1039,37 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
 
   if t.kind == tyForward:
     for i in countup(1, sonsLen(n)-1):
-      var elem = semGenericParamInInvokation(c, n.sons[i])
+      var elem = semGenericParamInInvocation(c, n.sons[i])
       addToResult(elem)
     return
   elif t.kind != tyGenericBody:
-    #we likely got code of the form TypeA[TypeB] where TypeA is
-    #not generic.
+    # we likely got code of the form TypeA[TypeB] where TypeA is
+    # not generic.
     localError(n.info, errNoGenericParamsAllowedForX, s.name.s)
     return newOrPrevType(tyError, prev, c)
   else:
     var m = newCandidate(c, t)
     matches(c, n, copyTree(n), m)
-    
-    if m.state != csMatch:
-      var err = "cannot instantiate " & typeToString(t) & "\n" &
+
+    if m.state != csMatch and not m.typedescMatched:
+      let err = "cannot instantiate " & typeToString(t) & "\n" &
                 "got: (" & describeArgs(c, n) & ")\n" &
                 "but expected: (" & describeArgs(c, t.n, 0) & ")"
       localError(n.info, errGenerated, err)
       return newOrPrevType(tyError, prev, c)
 
     var isConcrete = true
- 
+
     for i in 1 .. <m.call.len:
-      let typ = m.call[i].typ.skipTypes({tyTypeDesc})
-      if containsGenericType(typ): isConcrete = false
-      addToResult(typ)
-   
+      var typ = m.call[i].typ
+      if typ.kind == tyTypeDesc and typ.sons[0].kind == tyNone:
+        isConcrete = false
+        addToResult(typ)
+      else:
+        typ = typ.skipTypes({tyTypeDesc})
+        if containsGenericType(typ): isConcrete = false
+        addToResult(typ)
+
     if isConcrete:
       if s.ast == nil and s.typ.kind != tyCompositeTypeClass:
         # XXX: What kind of error is this? is it still relevant?
@@ -1053,13 +1094,15 @@ proc freshType(res, prev: PType): PType {.inline.} =
 
 proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
   # if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
+  if nfBase2 in n.flags:
+    message(n.info, warnDeprecated, "use 'concept' instead; 'generic'")
   result = newOrPrevType(tyUserTypeClass, prev, c)
   result.n = n
 
   let
     pragmas = n[1]
     inherited = n[2]
-    
+
   if inherited.kind != nkEmpty:
     for n in inherited.sons:
       let typ = semTypeNode(c, n, nil)
@@ -1069,7 +1112,7 @@ proc semProcTypeWithScope(c: PContext, n: PNode,
                         prev: PType, kind: TSymKind): PType =
   checkSonsLen(n, 2)
   openScope(c)
-  result = semProcTypeNode(c, n.sons[0], nil, prev, kind)
+  result = semProcTypeNode(c, n.sons[0], nil, prev, kind, isType=true)
   # dummy symbol for `pragma`:
   var s = newSymS(kind, newIdentNode(getIdent("dummy"), n.info), c)
   s.typ = result
@@ -1092,12 +1135,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
     checkSonsLen(n, 1)
     let typExpr = semExprWithType(c, n.sons[0], {efInTypeof})
     result = typExpr.typ.skipTypes({tyIter})
-  of nkPar: 
+  of nkPar:
     if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
     else:
-      # XXX support anon tuple here
-      localError(n.info, errTypeExpected)
-      result = newOrPrevType(tyError, prev, c)
+      result = semAnonTuple(c, n, prev)
   of nkCallKinds:
     if isRange(n):
       result = semRangeAux(c, n, prev)
@@ -1123,7 +1164,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
         case n.len
         of 3:
           result = semTypeNode(c, n.sons[1], prev)
-          if result.kind in NilableTypes and n.sons[2].kind == nkNilLit:
+          if result.skipTypes({tyGenericInst}).kind in NilableTypes+GenericTypes and
+              n.sons[2].kind == nkNilLit:
             result = freshType(result, prev)
             result.flags.incl(tfNotNil)
           else:
@@ -1137,6 +1179,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
         result = semAnyRef(c, n, tyPtr, prev)
       elif op.id == ord(wRef):
         result = semAnyRef(c, n, tyRef, prev)
+      elif op.id == ord(wType):
+        checkSonsLen(n, 2)
+        let typExpr = semExprWithType(c, n.sons[1], {efInTypeof})
+        result = typExpr.typ.skipTypes({tyIter})
       else:
         result = semTypeExpr(c, n)
   of nkWhenStmt:
@@ -1166,15 +1212,15 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
     var typeExpr = semExpr(c, n)
     if typeExpr.typ.kind != tyTypeDesc:
       localError(n.info, errTypeExpected)
-      return errorType(c)
-    result = typeExpr.typ.base
-    if result.isMetaType:
-      var toBind = initIntSet()
-      var preprocessed = semGenericStmt(c, n, {}, toBind)
-      return makeTypeFromExpr(c, preprocessed)
+      result = errorType(c)
+    else:
+      result = typeExpr.typ.base
+      if result.isMetaType:
+        var preprocessed = semGenericStmt(c, n)
+        result = makeTypeFromExpr(c, preprocessed.copyTree)
   of nkIdent, nkAccQuoted:
     var s = semTypeIdent(c, n)
-    if s.typ == nil: 
+    if s.typ == nil:
       if s.kind != skError: localError(n.info, errTypeExpected)
       result = newOrPrevType(tyError, prev, c)
     elif s.kind == skParam and s.typ.kind == tyTypeDesc:
@@ -1182,19 +1228,19 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       result = s.typ.base
     elif prev == nil:
       result = s.typ
-    else: 
+    else:
       assignType(prev, s.typ)
       # bugfix: keep the fresh id for aliases to integral types:
       if s.typ.kind notin {tyBool, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
-                           tyUInt..tyUInt64}: 
+                           tyUInt..tyUInt64}:
         prev.id = s.typ.id
       result = prev
   of nkSym:
     if n.sym.kind == skType and n.sym.typ != nil:
       var t = n.sym.typ
-      if prev == nil: 
+      if prev == nil:
         result = t
-      else: 
+      else:
         assignType(prev, t)
         result = prev
       markUsed(n.info, n.sym)
@@ -1204,6 +1250,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       result = newOrPrevType(tyError, prev, c)
   of nkObjectTy: result = semObjectNode(c, n, prev)
   of nkTupleTy: result = semTuple(c, n, prev)
+  of nkTupleClassTy: result = newConstraint(c, tyTuple)
   of nkTypeClassTy: result = semTypeClass(c, n, prev)
   of nkRefTy: result = semAnyRef(c, n, tyRef, prev)
   of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
@@ -1242,13 +1289,14 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   else:
     localError(n.info, errTypeExpected)
     result = newOrPrevType(tyError, prev, c)
-  
-proc setMagicType(m: PSym, kind: TTypeKind, size: int) = 
+  n.typ = result
+
+proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
   m.typ.kind = kind
   m.typ.align = size.int16
   m.typ.size = size
-  
-proc processMagicType(c: PContext, m: PSym) = 
+
+proc processMagicType(c: PContext, m: PSym) =
   case m.magic
   of mInt: setMagicType(m, tyInt, intSize)
   of mInt8: setMagicType(m, tyInt8, 1)
@@ -1266,21 +1314,21 @@ proc processMagicType(c: PContext, m: PSym) =
   of mFloat128: setMagicType(m, tyFloat128, 16)
   of mBool: setMagicType(m, tyBool, 1)
   of mChar: setMagicType(m, tyChar, 1)
-  of mString: 
+  of mString:
     setMagicType(m, tyString, ptrSize)
     rawAddSon(m.typ, getSysType(tyChar))
-  of mCstring: 
+  of mCstring:
     setMagicType(m, tyCString, ptrSize)
     rawAddSon(m.typ, getSysType(tyChar))
   of mPointer: setMagicType(m, tyPointer, ptrSize)
-  of mEmptySet: 
+  of mEmptySet:
     setMagicType(m, tySet, 1)
     rawAddSon(m.typ, newTypeS(tyEmpty, c))
   of mIntSetBaseType: setMagicType(m, tyRange, intSize)
   of mNil: setMagicType(m, tyNil, ptrSize)
   of mExpr: setMagicType(m, tyExpr, 0)
   of mStmt: setMagicType(m, tyStmt, 0)
-  of mTypeDesc: 
+  of mTypeDesc:
     setMagicType(m, tyTypeDesc, 0)
     rawAddSon(m.typ, newTypeS(tyNone, c))
   of mVoidType: setMagicType(m, tyEmpty, 0)
@@ -1294,8 +1342,8 @@ proc processMagicType(c: PContext, m: PSym) =
     setMagicType(m, tyRange, 0)
     rawAddSon(m.typ, newTypeS(tyNone, c))
   of mSet:
-    setMagicType(m, tySet, 0) 
-  of mSeq: 
+    setMagicType(m, tySet, 0)
+  of mSeq:
     setMagicType(m, tySequence, 0)
   of mOrdinal:
     setMagicType(m, tyOrdinal, 0)
@@ -1311,13 +1359,13 @@ proc processMagicType(c: PContext, m: PSym) =
     incl m.typ.flags, tfShared
     rawAddSon(m.typ, sysTypeFromName"shared")
   else: localError(m.info, errTypeExpected)
-  
+
 proc semGenericConstraints(c: PContext, x: PType): PType =
   result = newTypeWithSons(c, tyGenericParam, @[x])
 
-proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = 
+proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
   result = copyNode(n)
-  if n.kind != nkGenericParams: 
+  if n.kind != nkGenericParams:
     illFormedAst(n)
     return
   for i in countup(0, sonsLen(n)-1):
@@ -1327,7 +1375,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
     var def = a{-1}
     let constraint = a{-2}
     var typ: PType
-    
+
     if constraint.kind != nkEmpty:
       typ = semTypeNode(c, constraint, nil)
       if typ.kind != tyStatic or typ.len == 0:
@@ -1336,7 +1384,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
             typ = newTypeWithSons(c, tyTypeDesc, @[newTypeS(tyNone, c)])
         else:
           typ = semGenericConstraints(c, typ)
-    
+
     if def.kind != nkEmpty:
       def = semConstExpr(c, def)
       if typ == nil:
@@ -1348,7 +1396,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
         def.typ = def.typ.skipTypes({tyTypeDesc})
         if not containsGenericType(def.typ):
           def = fitNode(c, typ, def)
-    
+
     if typ == nil:
       typ = newTypeS(tyGenericParam, c)
       if father == nil: typ.flags.incl tfWildcard
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index c53464f80..c5caf8b92 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -16,9 +16,9 @@ const
 
 proc sharedPtrCheck(info: TLineInfo, t: PType) =
   if t.kind == tyPtr and t.len > 1:
-    if t.sons[0].sym.magic in {mShared, mGuarded}:
+    if t.sons[0].sym.magic == mShared:
       incl(t.flags, tfShared)
-      if t.sons[0].sym.magic == mGuarded: incl(t.flags, tfGuarded)
+      #if t.sons[0].sym.magic == mGuarded: incl(t.flags, tfGuarded)
       if tfHasGCedMem in t.flags or t.isGCedMem:
         localError(info, errGenerated,
                    "shared memory may not refer to GC'ed thread local memory")
@@ -34,9 +34,9 @@ proc checkPartialConstructedType(info: TLineInfo, t: PType) =
 proc checkConstructedType*(info: TLineInfo, typ: PType) =
   var t = typ.skipTypes({tyDistinct})
   if t.kind in tyTypeClasses: discard
-  elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject: 
+  elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
     localError(info, errInvalidPragmaX, "acyclic")
-  elif t.kind == tyVar and t.sons[0].kind == tyVar: 
+  elif t.kind == tyVar and t.sons[0].kind == tyVar:
     localError(info, errVarVarTypeNotAllowed)
   elif computeSize(t) == szIllegalRecursion:
     localError(info, errIllegalRecursionInTypeX, typeToString(t))
@@ -44,7 +44,7 @@ proc checkConstructedType*(info: TLineInfo, typ: PType) =
     sharedPtrCheck(info, t)
   when false:
     if t.kind == tyObject and t.sons[0] != nil:
-      if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags: 
+      if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
         localError(info, errInheritanceOnlyWithNonFinalObjects)
 
 proc searchInstTypes*(key: PType): PType =
@@ -61,7 +61,7 @@ proc searchInstTypes*(key: PType): PType =
     if inst.sons.len < key.sons.len:
       # XXX: This happens for prematurely cached
       # types such as TChannel[empty]. Why?
-      # See the notes for PActor in handleGenericInvokation
+      # See the notes for PActor in handleGenericInvocation
       return
     block matchType:
       for j in 1 .. high(key.sons):
@@ -69,7 +69,7 @@ proc searchInstTypes*(key: PType): PType =
         if not compareTypes(inst.sons[j], key.sons[j],
                             flags = {ExactGenericParams}):
           break matchType
-       
+
       return inst
 
 proc cacheTypeInst*(inst: PType) =
@@ -79,7 +79,7 @@ proc cacheTypeInst*(inst: PType) =
   genericTyp.sym.typeInstCache.safeAdd(inst)
 
 type
-  TReplTypeVars* {.final.} = object 
+  TReplTypeVars* {.final.} = object
     c*: PContext
     typeMap*: TIdTable        # map PType to PType
     symMap*: TIdTable         # map PSym to PSym
@@ -89,6 +89,7 @@ type
     info*: TLineInfo
     allowMetaTypes*: bool     # allow types such as seq[Number]
                               # i.e. the result contains unresolved generics
+    skipTypedesc*: bool       # wether we should skip typeDescs
 
 proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType
 proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
@@ -101,7 +102,6 @@ template checkMetaInvariants(cl: TReplTypeVars, t: PType) =
       echo "UNEXPECTED META ", t.id, " ", instantiationInfo(-1)
       debug t
       writeStackTrace()
-      quit 1
 
 proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
   result = replaceTypeVarsTAux(cl, t)
@@ -152,7 +152,7 @@ proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode =
     if needsFixing:
       n.sons[0] = newSymNode(n.sons[0].sym.owner)
       return cl.c.semOverloadedCall(cl.c, n, n, {skProc})
-  
+
   for i in 0 .. <n.safeLen:
     n.sons[i] = reResolveCallsWithTypedescParams(cl, n[i])
 
@@ -204,18 +204,18 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
       newSons(result, length)
       for i in countup(0, length - 1):
         result.sons[i] = replaceTypeVarsN(cl, n.sons[i])
-  
-proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym = 
+
+proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
   if s == nil: return nil
   result = PSym(idTableGet(cl.symMap, s))
-  if result == nil: 
+  if result == nil:
     result = copySym(s, false)
     incl(result.flags, sfFromGeneric)
     idTablePut(cl.symMap, s, result)
     result.owner = s.owner
     result.typ = replaceTypeVarsT(cl, s.typ)
     result.ast = replaceTypeVarsN(cl, s.ast)
-    
+
 proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
   result = PType(idTableGet(cl.typeMap, t))
   if result == nil:
@@ -224,7 +224,7 @@ proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
     result = errorType(cl.c)
     # In order to prevent endless recursions, we must remember
     # this bad lookup and replace it with errorType everywhere.
-    # These code paths are only active in nimrod check
+    # These code paths are only active in "nim check"
     idTablePut(cl.typeMap, t, result)
   elif result.kind == tyGenericParam and not cl.allowMetaTypes:
     internalError(cl.info, "substitution with generic parameter")
@@ -233,11 +233,13 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
   # XXX: relying on allowMetaTypes is a kludge
   result = copyType(t, t.owner, cl.allowMetaTypes)
   result.flags.incl tfFromGeneric
-  result.flags.excl tfInstClearedFlags
+  if not (t.kind in tyMetaTypes or
+         (t.kind == tyStatic and t.n == nil)):
+    result.flags.excl tfInstClearedFlags
 
-proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = 
-  # tyGenericInvokation[A, tyGenericInvokation[A, B]]
-  # is difficult to handle: 
+proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
+  # tyGenericInvocation[A, tyGenericInvocation[A, B]]
+  # is difficult to handle:
   var body = t.sons[0]
   if body.kind != tyGenericBody: internalError(cl.info, "no generic body")
   var header: PType = t
@@ -246,7 +248,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
     result = PType(idTableGet(cl.localCache, t))
   else:
     result = searchInstTypes(t)
-  if result != nil: return
+  if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
   for i in countup(1, sonsLen(t) - 1):
     var x = t.sons[i]
     if x.kind == tyGenericParam:
@@ -257,14 +259,14 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
         propagateToOwner(header, x)
     else:
       propagateToOwner(header, x)
-  
+
   if header != t:
     # search again after first pass:
     result = searchInstTypes(header)
-    if result != nil: return
+    if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
   else:
     header = instCopyType(cl, t)
-  
+
   result = newType(tyGenericInst, t.sons[0].owner)
   result.flags = header.flags
   # be careful not to propagate unnecessary flags here (don't use rawAddSon)
@@ -277,25 +279,29 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
   else:
     idTablePut(cl.localCache, t, result)
 
+  let oldSkipTypedesc = cl.skipTypedesc
+  cl.skipTypedesc = true
   for i in countup(1, sonsLen(t) - 1):
     var x = replaceTypeVarsT(cl, t.sons[i])
-    assert x.kind != tyGenericInvokation
+    assert x.kind != tyGenericInvocation
     header.sons[i] = x
     propagateToOwner(header, x)
     idTablePut(cl.typeMap, body.sons[i-1], x)
-  
+
   for i in countup(1, sonsLen(t) - 1):
     # if one of the params is not concrete, we cannot do anything
     # but we already raised an error!
     rawAddSon(result, header.sons[i])
 
   var newbody = replaceTypeVarsT(cl, lastSon(body))
+  cl.skipTypedesc = oldSkipTypedesc
   newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
   result.flags = result.flags + newbody.flags - tfInstClearedFlags
-  newbody.callConv = body.callConv
+  # This is actually wrong: tgeneric_closure fails with this line:
+  #newbody.callConv = body.callConv
   # This type may be a generic alias and we want to resolve it here.
   # One step is enough, because the recursive nature of
-  # handleGenericInvokation will handle the alias-to-alias-to-alias case
+  # handleGenericInvocation will handle the alias-to-alias-to-alias case
   if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
   rawAddSon(result, newbody)
   checkPartialConstructedType(cl.info, newbody)
@@ -303,14 +309,20 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
   if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
     # 'deepCopy' needs to be instantiated for
     # generics *when the type is constructed*:
-    newbody.deepCopy = cl.c.instDeepCopy(cl.c, dc, result, cl.info)
+    newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
+                                            attachedDeepCopy)
+  let asgn = newbody.assignment
+  if asgn != nil and sfFromGeneric notin asgn.flags:
+    # '=' needs to be instantiated for generics when the type is constructed:
+    newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
+                                              attachedAsgn)
 
 proc eraseVoidParams*(t: PType) =
   # transform '(): void' into '()' because old parts of the compiler really
-  # doesn't deal with '(): void':
+  # don't deal with '(): void':
   if t.sons[0] != nil and t.sons[0].kind == tyEmpty:
     t.sons[0] = nil
-  
+
   for i in 1 .. <t.sonsLen:
     # don't touch any memory unless necessary
     if t.sons[i].kind == tyEmpty:
@@ -332,7 +344,7 @@ proc skipIntLiteralParams*(t: PType) =
     if skipped != p:
       t.sons[i] = skipped
       if i > 0: t.n.sons[i].sym.typ = skipped
-  
+
   # when the typeof operator is used on a static input
   # param, the results gets infected with static as well:
   if t.sons[0] != nil and t.sons[0].kind == tyStatic:
@@ -341,6 +353,8 @@ proc skipIntLiteralParams*(t: PType) =
 proc propagateFieldFlags(t: PType, n: PNode) =
   # This is meant for objects and tuples
   # The type must be fully instantiated!
+  if n.isNil:
+    return
   internalAssert n.kind != nkRecWhen
   case n.kind
   of nkSym:
@@ -357,10 +371,10 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
   if t.kind in {tyStatic, tyGenericParam, tyIter} + tyTypeClasses:
     let lookup = PType(idTableGet(cl.typeMap, t))
     if lookup != nil: return lookup
-  
+
   case t.kind
-  of tyGenericInvokation:
-    result = handleGenericInvokation(cl, t)
+  of tyGenericInvocation:
+    result = handleGenericInvocation(cl, t)
 
   of tyGenericBody:
     localError(cl.info, errCannotInstantiateX, typeToString(t))
@@ -369,8 +383,10 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
 
   of tyFromExpr:
     if cl.allowMetaTypes: return
+    assert t.n.typ != t
     var n = prepareNode(cl, t.n)
-    n = cl.c.semConstExpr(cl.c, n)
+    if n.kind != nkEmpty:
+      n = cl.c.semConstExpr(cl.c, n)
     if n.typ.kind == tyTypeDesc:
       # XXX: sometimes, chained typedescs enter here.
       # It may be worth investigating why this is happening,
@@ -389,51 +405,58 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
       else:
         result = n.typ
 
-  of tyInt:
+  of tyInt, tyFloat:
     result = skipIntLit(t)
-    # XXX now there are also float literals
-  
+
   of tyTypeDesc:
     let lookup = PType(idTableGet(cl.typeMap, t)) # lookupTypeVar(cl, t)
     if lookup != nil:
       result = lookup
-      if tfUnresolved in t.flags: result = result.base
+      if tfUnresolved in t.flags or cl.skipTypedesc: result = result.base
     elif t.sons[0].kind != tyNone:
       result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0]))
- 
+
   of tyUserTypeClass:
     result = t
 
   of tyGenericInst:
+    result = PType(idTableGet(cl.localCache, t))
+    if result != nil: return result
     result = instCopyType(cl, t)
+    idTablePut(cl.localCache, t, result)
     for i in 1 .. <result.sonsLen:
       result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
     propagateToOwner(result, result.lastSon)
-  
+
   else:
     if containsGenericType(t):
+      #if not cl.allowMetaTypes:
+      result = PType(idTableGet(cl.localCache, t))
+      if result != nil: return result
       result = instCopyType(cl, t)
       result.size = -1 # needs to be recomputed
-      
+      #if not cl.allowMetaTypes:
+      idTablePut(cl.localCache, t, result)
+
       for i in countup(0, sonsLen(result) - 1):
         if result.sons[i] != nil:
           result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
           propagateToOwner(result, result.sons[i])
 
       result.n = replaceTypeVarsN(cl, result.n)
-     
+
       case result.kind
       of tyArray:
         let idx = result.sons[0]
         internalAssert idx.kind != tyStatic
-       
+
       of tyObject, tyTuple:
         propagateFieldFlags(result, result.n)
-      
+
       of tyProc:
         eraseVoidParams(result)
         skipIntLiteralParams(result)
-      
+
       else: discard
 
 proc initTypeVars*(p: PContext, pt: TIdTable, info: TLineInfo): TReplTypeVars =
@@ -448,7 +471,7 @@ proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode): PNode =
   pushInfoContext(n.info)
   result = replaceTypeVarsN(cl, n)
   popInfoContext()
-  
+
 proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
                            t: PType): PType =
   var cl = initTypeVars(p, pt, info)
diff --git a/compiler/service.nim b/compiler/service.nim
index 4a1b296cd..7cb9d7d29 100644
--- a/compiler/service.nim
+++ b/compiler/service.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2012 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -14,7 +14,7 @@ import
   extccomp, strutils, os, platform, parseopt
 
 when useCaas:
-  import sockets
+  import net
 
 # We cache modules and the dependency graph. However, we don't check for
 # file changes but expect the client to tell us about them, otherwise the
@@ -33,7 +33,12 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
     parseopt.next(p)
     case p.kind
     of cmdEnd: break
-    of cmdLongoption, cmdShortOption: processSwitch(pass, p)
+    of cmdLongoption, cmdShortOption:
+      if p.key == " ":
+        p.key = "-"
+        if processArgument(pass, p, argsCount): break
+      else:
+        processSwitch(pass, p)
     of cmdArgument:
       if processArgument(pass, p, argsCount): break
   if pass == passCmd2:
@@ -45,8 +50,6 @@ proc serve*(action: proc (){.nimcall.}) =
     curCaasCmd = cmd
     processCmdLine(passCmd2, cmd)
     action()
-    gDirtyBufferIdx = 0
-    gDirtyOriginalIdx = 0
     gErrorCounter = 0
 
   let typ = getConfigVar("server.type")
@@ -61,14 +64,16 @@ proc serve*(action: proc (){.nimcall.}) =
 
   of "tcp", "":
     when useCaas:
-      var server = socket()
-      if server == invalidSocket: raiseOSError(osLastError())
+      var server = newSocket()
       let p = getConfigVar("server.port")
       let port = if p.len > 0: parseInt(p).Port else: 6000.Port
       server.bindAddr(port, getConfigVar("server.address"))
       var inp = "".TaintedString
       server.listen()
-      new(stdoutSocket)
+      var stdoutSocket = newSocket()
+      msgs.writelnHook = proc (line: string) =
+        stdoutSocket.send(line & "\c\L")
+
       while true:
         accept(server, stdoutSocket)
         stdoutSocket.readLine(inp)
@@ -76,7 +81,7 @@ proc serve*(action: proc (){.nimcall.}) =
         stdoutSocket.send("\c\L")
         stdoutSocket.close()
     else:
-      quit "server.type not supported; compiler built without caas support"
+      msgQuit "server.type not supported; compiler built without caas support"
   else:
     echo "Invalid server.type:", typ
-    quit 1
+    msgQuit 1
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 123d1df2e..5c8a3bc58 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -10,7 +10,7 @@
 ## This module implements the signature matching for resolving
 ## the call to overloaded procs, generic procs and operators.
 
-import 
+import
   intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
   magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees,
   nimfix.pretty
@@ -19,7 +19,7 @@ when not defined(noDocgen):
   import docgen
 
 type
-  TCandidateState* = enum 
+  TCandidateState* = enum
     csEmpty, csMatch, csNoMatch
 
   CandidateErrors* = seq[PSym]
@@ -39,12 +39,14 @@ type
     bindings*: TIdTable      # maps types to types
     baseTypeMatch: bool      # needed for conversions from T to openarray[T]
                              # for example
-    proxyMatch*: bool        # to prevent instantiations
+    fauxMatch*: TTypeKind    # the match was successful only due to the use
+                             # of error or wildcard (unknown) types.
+                             # this is used to prevent instantiations.
     genericConverter*: bool  # true if a generic converter needs to
                              # be instantiated
     coerceDistincts*: bool   # this is an explicit coercion that can strip away
                              # a distrinct type
-    typedescMatched: bool
+    typedescMatched*: bool
     inheritancePenalty: int  # to prefer closest father object type
     errors*: CandidateErrors # additional clarifications to be displayed to the
                              # user if overload resolution fails
@@ -60,12 +62,14 @@ type
     isGeneric,
     isFromIntLit,            # conversion *from* int literal; proven safe
     isEqual
-  
+
 const
   isNilConversion = isConvertible # maybe 'isIntConv' fits better?
-    
+
 proc markUsed*(info: TLineInfo, s: PSym)
 
+template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone
+
 proc initCandidateAux(ctx: PContext,
                       c: var TCandidate, callee: PType) {.inline.} =
   c.c = ctx
@@ -87,7 +91,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) =
   initIdTable(c.bindings)
 
 proc put(t: var TIdTable, key, val: PType) {.inline.} =
-  idTablePut(t, key, val)
+  idTablePut(t, key, val.skipIntLit)
 
 proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
                     binding: PNode, calleeScope = -1) =
@@ -95,9 +99,12 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
   c.calleeSym = callee
   if callee.kind in skProcKinds and calleeScope == -1:
     if callee.originatingModule == ctx.module:
-      let rootSym = if sfFromGeneric notin callee.flags: callee
-                    else: callee.owner
-      c.calleeScope = rootSym.scope.depthLevel
+      c.calleeScope = 2
+      var owner = callee
+      while true:
+        owner = owner.skipGenericOwner
+        if owner.kind == skModule: break
+        inc c.calleeScope
     else:
       c.calleeScope = 1
   else:
@@ -109,9 +116,12 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
     for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1):
       var formalTypeParam = typeParams.sons[i-1].typ
       var bound = binding[i].typ
-      if bound != nil and formalTypeParam.kind != tyTypeDesc:
+      internalAssert bound != nil
+      if formalTypeParam.kind == tyTypeDesc:
+        if bound.kind != tyTypeDesc:
+          bound = makeTypeDesc(ctx, bound)
+      else:
         bound = bound.skipTypes({tyTypeDesc})
-      assert bound != nil
       put(c.bindings, formalTypeParam, bound)
 
 proc newCandidate*(ctx: PContext, callee: PSym,
@@ -121,7 +131,7 @@ proc newCandidate*(ctx: PContext, callee: PSym,
 proc newCandidate*(ctx: PContext, callee: PType): TCandidate =
   initCandidate(ctx, result, callee)
 
-proc copyCandidate(a: var TCandidate, b: TCandidate) = 
+proc copyCandidate(a: var TCandidate, b: TCandidate) =
   a.c = b.c
   a.exactMatches = b.exactMatches
   a.subtypeMatches = b.subtypeMatches
@@ -146,36 +156,44 @@ proc sumGeneric(t: PType): int =
     of tyVar:
       # but do not make 'var T' more specific than 'T'!
       t = t.sons[0]
-    of tyGenericInvokation, tyTuple:
-      result = ord(t.kind == tyGenericInvokation)
+    of tyGenericInvocation, tyTuple:
+      result = ord(t.kind == tyGenericInvocation)
       for i in 0 .. <t.len: result += t.sons[i].sumGeneric
       break
-    of tyProc:
-      # proc matche proc better than 'stmt' to disambiguate 'spawn'
-      return 1
     of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break
+    of tyBool, tyChar, tyEnum, tyObject, tyProc, tyPointer,
+        tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
+        tyUInt..tyUInt64:
+      return 1
     else: return 0
 
+#var ggDebug: bool
+
 proc complexDisambiguation(a, b: PType): int =
-  var x, y: int
-  for i in 1 .. <a.len: x += a.sons[i].sumGeneric
-  for i in 1 .. <b.len: y += b.sons[i].sumGeneric
-  result = x - y
+  # 'a' matches better if *every* argument matches better or equal than 'b'.
+  var winner = 0
+  for i in 1 .. <min(a.len, b.len):
+    let x = a.sons[i].sumGeneric
+    let y = b.sons[i].sumGeneric
+    #if ggDebug:
+    #  echo "came her ", typeToString(a.sons[i]), " ", typeToString(b.sons[i])
+    if x != y:
+      if winner == 0:
+        if x > y: winner = 1
+        else: winner = -1
+      elif x > y:
+        if winner != 1:
+          # contradiction
+          return 0
+      else:
+        if winner != -1:
+          return 0
+  result = winner
   when false:
-    proc betterThan(a, b: PType): bool {.inline.} = a.sumGeneric > b.sumGeneric
-
-    if a.len > 1 and b.len > 1:
-      let aa = a.sons[1].sumGeneric
-      let bb = b.sons[1].sumGeneric
-      var a = a
-      var b = b
-      
-      if aa < bb: swap(a, b)
-      # all must be better
-      for i in 2 .. <min(a.len, b.len):
-        if not a.sons[i].betterThan(b.sons[i]): return 0
-      # a must be longer or of the same length as b:
-      result = a.len - b.len
+    var x, y: int
+    for i in 1 .. <a.len: x += a.sons[i].sumGeneric
+    for i in 1 .. <b.len: y += b.sons[i].sumGeneric
+    result = x - y
 
 proc cmpCandidates*(a, b: TCandidate): int =
   result = a.exactMatches - b.exactMatches
@@ -196,12 +214,13 @@ proc cmpCandidates*(a, b: TCandidate): int =
   # prefer more specialized generic over more general generic:
   result = complexDisambiguation(a.callee, b.callee)
 
-proc writeMatches*(c: TCandidate) = 
+proc writeMatches*(c: TCandidate) =
   writeln(stdout, "exact matches: " & $c.exactMatches)
+  writeln(stdout, "generic matches: " & $c.genericMatches)
   writeln(stdout, "subtype matches: " & $c.subtypeMatches)
-  writeln(stdout, "conv matches: " & $c.convMatches)
   writeln(stdout, "intconv matches: " & $c.intConvMatches)
-  writeln(stdout, "generic matches: " & $c.genericMatches)
+  writeln(stdout, "conv matches: " & $c.convMatches)
+  writeln(stdout, "inheritance: " & $c.inheritancePenalty)
 
 proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
   if arg.kind in nkSymChoices:
@@ -217,7 +236,7 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
   result = ""
   for i in countup(startIdx, n.len - 1):
     var arg = n.sons[i]
-    if n.sons[i].kind == nkExprEqExpr: 
+    if n.sons[i].kind == nkExprEqExpr:
       add(result, renderTree(n.sons[i].sons[0]))
       add(result, ": ")
       if arg.typ.isNil:
@@ -233,9 +252,9 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
     if i != sonsLen(n) - 1: add(result, ", ")
 
 proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
-proc concreteType(c: TCandidate, t: PType): PType = 
+proc concreteType(c: TCandidate, t: PType): PType =
   case t.kind
-  of tyArrayConstr: 
+  of tyArrayConstr:
     # make it an array
     result = newType(tyArray, t.owner)
     addSonSkipIntLit(result, t.sons[0]) # XXX: t.owner is wrong for ID!
@@ -247,27 +266,27 @@ proc concreteType(c: TCandidate, t: PType): PType =
     else: result = t
   of tyGenericParam, tyAnything:
     result = t
-    while true: 
+    while true:
       result = PType(idTableGet(c.bindings, t))
       if result == nil:
         break # it's ok, no match
         # example code that triggers it:
         # proc sort[T](cmp: proc(a, b: T): int = cmp)
       if result.kind != tyGenericParam: break
-  of tyGenericInvokation:
+  of tyGenericInvocation:
     internalError("cannot resolve type: " & typeToString(t))
     result = t
   else:
     result = t                # Note: empty is valid here
-  
-proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation = 
-  if a.kind == f.kind: 
+
+proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
+  if a.kind == f.kind:
     result = isEqual
   else:
     let ab = skipTypes(a, {tyRange})
     let k = ab.kind
     if k == f.kind: result = isSubrange
-    elif k == tyInt and f.kind in {tyRange, tyInt8..tyInt64, 
+    elif k == tyInt and f.kind in {tyRange, tyInt8..tyInt64,
                                    tyUInt..tyUInt64} and
         isIntLit(ab) and ab.n.intVal >= firstOrd(f) and
                          ab.n.intVal <= lastOrd(f):
@@ -276,9 +295,9 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
       result = isFromIntLit
     elif f.kind == tyInt and k in {tyInt8..tyInt32}:
       result = isIntConv
-    elif k >= min and k <= max: 
+    elif k >= min and k <= max:
       result = isConvertible
-    elif a.kind == tyRange and a.sons[0].kind in {tyInt..tyInt64, 
+    elif a.kind == tyRange and a.sons[0].kind in {tyInt..tyInt64,
                                                   tyUInt8..tyUInt32} and
                          a.n[0].intVal >= firstOrd(f) and
                          a.n[1].intVal <= lastOrd(f):
@@ -310,12 +329,12 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
       if f.kind == tyFloat32: result = isConvertible
       else: result = isIntConv
     else: result = isNone
-  
+
 proc isObjectSubtype(a, f: PType): int =
   var t = a
   assert t.kind == tyObject
   var depth = 0
-  while t != nil and not sameObjectTypes(f, t): 
+  while t != nil and not sameObjectTypes(f, t):
     assert t.kind == tyObject
     t = t.sons[0]
     if t == nil: break
@@ -324,17 +343,18 @@ proc isObjectSubtype(a, f: PType): int =
   if t != nil:
     result = depth
 
-proc minRel(a, b: TTypeRelation): TTypeRelation = 
+proc minRel(a, b: TTypeRelation): TTypeRelation =
   if a <= b: result = a
   else: result = b
-  
+
 proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
   result = isNone
-  if sameType(f, a): result = isEqual
+  if sameType(f, a):
+    result = isEqual
   elif sonsLen(a) == sonsLen(f):
     result = isEqual
     let firstField = if f.kind == tyTuple: 0
-                     else: 1 
+                     else: 1
     for i in countup(firstField, sonsLen(f) - 1):
       var m = typeRel(c, f.sons[i], a.sons[i])
       if m < isSubtype: return isNone
@@ -365,32 +385,32 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
       # We are matching a generic proc (as proc param)
       # to another generic type appearing in the proc
       # signature. There is a change that the target
-      # type is already fully-determined, so we are 
+      # type is already fully-determined, so we are
       # going to try resolve it
       f = generateTypeInstance(c.c, c.bindings, c.call.info, f)
       if f == nil or f.isMetaType:
         # no luck resolving the type, so the inference fails
         return isNone
     let reverseRel = typeRel(c, a, f)
-    if reverseRel == isGeneric:
+    if reverseRel >= isGeneric:
       result = isInferred
-      inc c.genericMatches
+      #inc c.genericMatches
   else:
     result = typeRel(c, f, a)
 
   if result <= isSubtype or inconsistentVarTypes(f, a):
     result = isNone
- 
-  if result == isEqual:
-    inc c.exactMatches
-    
+
+  #if result == isEqual:
+  #  inc c.exactMatches
+
 proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   case a.kind
   of tyProc:
     if sonsLen(f) != sonsLen(a): return
     result = isEqual      # start with maximum; also correct for no
                           # params at all
-    
+
     template checkParam(f, a) =
       result = minRel(result, procParamTypeRel(c, f, a))
       if result == isNone: return
@@ -399,7 +419,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
     # return type!
     for i in 1 .. <f.sonsLen:
       checkParam(f.sons[i], a.sons[i])
-    
+
     if f.sons[0] != nil:
       if a.sons[0] != nil:
         checkParam(f.sons[0], a.sons[0])
@@ -410,7 +430,8 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
 
     if tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags:
       return isNone
-    elif tfThread in f.flags and a.flags * {tfThread, tfNoSideEffect} == {}:
+    elif tfThread in f.flags and a.flags * {tfThread, tfNoSideEffect} == {} and
+        optThreadAnalysis in gGlobalOptions:
       # noSideEffect implies ``tfThread``!
       return isNone
     elif f.flags * {tfIterator} != a.flags * {tfIterator}:
@@ -424,6 +445,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
         return isNone
     when useEffectSystem:
       if not compatibleEffects(f, a): return isNone
+
   of tyNil:
     result = f.allowsNil
   of tyIter:
@@ -453,7 +475,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
   openScope(c)
   inc c.inTypeClass
 
-  finally:
+  defer:
     dec c.inTypeClass
     closeScope(c)
 
@@ -462,42 +484,46 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
       var
         typeParamName = ff.base.sons[i-1].sym.name
         typ = ff.sons[i]
-        param = newSym(skType, typeParamName, body.sym, body.sym.info)
-        
-      param.typ = makeTypeDesc(c, typ)
+        param: PSym
+
+      template paramSym(kind): expr =
+        newSym(kind, typeParamName, body.sym, body.sym.info)
+
+      case typ.kind
+      of tyStatic:
+        param = paramSym skConst
+        param.typ = typ.base
+        param.ast = typ.n
+      of tyUnknown:
+        param = paramSym skVar
+        param.typ = typ
+      else:
+        param = paramSym skType
+        param.typ = makeTypeDesc(c, typ)
+
       addDecl(c, param)
+      #echo "A ", param.name.s, " ", typeToString(param.typ), " ", param.kind
 
   for param in body.n[0]:
     var
       dummyName: PNode
       dummyType: PType
-    
+
     if param.kind == nkVarTy:
       dummyName = param[0]
-      dummyType = if a.kind != tyVar: makeVarType(c, a)
-                  else: a
+      dummyType = if a.kind != tyVar: makeVarType(c, a) else: a
     else:
       dummyName = param
       dummyType = a
 
     internalAssert dummyName.kind == nkIdent
-    var dummyParam = newSym(skType, dummyName.ident, body.sym, body.sym.info)
+    var dummyParam = newSym(skVar, dummyName.ident, body.sym, body.sym.info)
     dummyParam.typ = dummyType
     addDecl(c, dummyParam)
+    #echo "B ", dummyName.ident.s, " ", typeToString(dummyType), " ", dummyparam.kind
 
   var checkedBody = c.semTryExpr(c, body.n[3].copyTree)
-  #m.errors = bufferedMsgs
-  clearBufferedMsgs()
   if checkedBody == nil: return isNone
-
-  if checkedBody.kind == nkStmtList:
-    for stmt in checkedBody:
-      case stmt.kind
-      of nkReturnStmt: discard
-      of nkTypeSection: discard
-      of nkConstDef: discard
-      else: discard
-    
   return isGeneric
 
 proc shouldSkipDistinct(rules: PNode, callIdent: PIdent): bool =
@@ -517,11 +543,21 @@ proc maybeSkipDistinct(t: PType, callee: PSym): PType =
   else:
     result = t
 
+proc tryResolvingStaticExpr(c: var TCandidate, n: PNode): PNode =
+  # Consider this example:
+  #   type Value[N: static[int]] = object
+  #   proc foo[N](a: Value[N], r: range[0..(N-1)])
+  # Here, N-1 will be initially nkStaticExpr that can be evaluated only after
+  # N is bound to a concrete value during the matching of the first param.
+  # This proc is used to evaluate such static expressions.
+  let instantiated = replaceTypesInBody(c.c, c.bindings, n)
+  result = c.c.semExpr(c.c, instantiated)
+
 proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   # typeRel can be used to establish various relationships between types:
   #
   # 1) When used with concrete types, it will check for type equivalence
-  # or a subtype relationship. 
+  # or a subtype relationship.
   #
   # 2) When used with a concrete type against a type class (such as generic
   # signature of a proc), it will check whether the concrete type is a member
@@ -536,9 +572,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
 
   result = isNone
   assert(f != nil)
-  
+
   if f.kind == tyExpr:
-    put(c.bindings, f, aOrig)
+    if aOrig != nil: put(c.bindings, f, aOrig)
     return isGeneric
 
   assert(aOrig != nil)
@@ -549,18 +585,17 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   # start the param matching process. This could be done in `prepareOperand`
   # for example, but unfortunately `prepareOperand` is not called in certain
   # situation when nkDotExpr are rotated to nkDotCalls
-  
+
   if a.kind == tyGenericInst and
       skipTypes(f, {tyVar}).kind notin {
-        tyGenericBody, tyGenericInvokation,
+        tyGenericBody, tyGenericInvocation,
         tyGenericInst, tyGenericParam} + tyTypeClasses:
     return typeRel(c, f, lastSon(a))
 
   template bindingRet(res) =
-    when res == isGeneric:
-      if doBind:
-        let bound = aOrig.skipTypes({tyRange}).skipIntLit
-        if doBind: put(c.bindings, f, bound)
+    if doBind:
+      let bound = aOrig.skipTypes({tyRange}).skipIntLit
+      if doBind: put(c.bindings, f, bound)
     return res
 
   template considerPreviousT(body: stmt) {.immediate.} =
@@ -572,20 +607,21 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   of tyOr:
     # seq[int|string] vs seq[number]
     # both int and string must match against number
+    # but ensure that '[T: A|A]' matches as good as '[T: A]' (bug #2219):
+    result = isGeneric
     for branch in a.sons:
-      if typeRel(c, f, branch, false) == isNone:
-        return isNone
-
-    return isGeneric
+      let x = typeRel(c, f, branch, false)
+      if x == isNone: return isNone
+      if x < result: result = x
 
   of tyAnd:
     # seq[Sortable and Iterable] vs seq[Sortable]
     # only one match is enough
     for branch in a.sons:
-      if typeRel(c, f, branch, false) != isNone:
-        return isGeneric
-
-    return isNone
+      let x = typeRel(c, f, branch, false)
+      if x != isNone:
+        return if x >= isGeneric: isGeneric else: x
+    result = isNone
 
   of tyNot:
     case f.kind
@@ -593,9 +629,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       # seq[!int] vs seq[!number]
       # seq[float] matches the first, but not the second
       # we must turn the problem around:
-      # is number a subset of int? 
+      # is number a subset of int?
       return typeRel(c, a.lastSon, f.lastSon)
- 
+
     else:
       # negative type classes are essentially infinite,
       # so only the `any` type class is their superset
@@ -616,10 +652,16 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
     elif skipTypes(a, {tyRange}).kind == f.kind: result = isSubtype
   of tyRange:
     if a.kind == f.kind:
+      if f.base.kind == tyNone: return isGeneric
       result = typeRel(c, base(f), base(a))
       # bugfix: accept integer conversions here
       #if result < isGeneric: result = isNone
       if result notin {isNone, isGeneric}:
+        # resolve any late-bound static expressions
+        # that may appear in the range:
+        for i in 0..1:
+          if f.n[i].kind == nkStaticExpr:
+            f.n.sons[i] = tryResolvingStaticExpr(c, f.n[i])
         result = typeRangeRel(f, a)
     else:
       if skipTypes(f, {tyRange}).kind == a.kind:
@@ -657,22 +699,27 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
         else:
           fRange = prev
       result = typeRel(c, f.sons[1], a.sons[1])
-      if result < isGeneric:
-        result = isNone
-      elif tfUnresolved in fRange.flags and
-           rangeHasStaticIf(fRange):
-        # This is a range from an array instantiated with a generic
-        # static param. We must extract the static param here and bind
-        # it to the size of the currently supplied array.
-        var
-          rangeStaticT = fRange.getStaticTypeFromRange
-          replacementT = newTypeWithSons(c.c, tyStatic, @[tyInt.getSysType])
-          inputUpperBound = a.sons[0].n[1].intVal
-        # we must correct for the off-by-one discrepancy between
-        # ranges and static params:
-        replacementT.n = newIntNode(nkIntLit, inputUpperBound + 1)
-        put(c.bindings, rangeStaticT, replacementT)
-        result = isGeneric
+      if result < isGeneric: return isNone
+      if rangeHasStaticIf(fRange):
+        if tfUnresolved in fRange.flags:
+          # This is a range from an array instantiated with a generic
+          # static param. We must extract the static param here and bind
+          # it to the size of the currently supplied array.
+          var
+            rangeStaticT = fRange.getStaticTypeFromRange
+            replacementT = newTypeWithSons(c.c, tyStatic, @[tyInt.getSysType])
+            inputUpperBound = a.sons[0].n[1].intVal
+          # we must correct for the off-by-one discrepancy between
+          # ranges and static params:
+          replacementT.n = newIntNode(nkIntLit, inputUpperBound + 1)
+          put(c.bindings, rangeStaticT, replacementT)
+          return isGeneric
+
+        let len = tryResolvingStaticExpr(c, fRange.n[1])
+        if len.kind == nkIntLit and len.intVal+1 == lengthOrd(a):
+          return # if we get this far, the result is already good
+        else:
+          return isNone
       elif lengthOrd(fRange) != lengthOrd(a):
         result = isNone
     else: discard
@@ -683,20 +730,20 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
     of tyOpenArray, tyVarargs:
       result = typeRel(c, base(f), base(a))
       if result < isGeneric: result = isNone
-    of tyArrayConstr: 
-      if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty): 
+    of tyArrayConstr:
+      if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
         result = isSubtype    # [] is allowed here
-      elif typeRel(c, base(f), a.sons[1]) >= isGeneric: 
+      elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
         result = isSubtype
-    of tyArray: 
-      if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty): 
+    of tyArray:
+      if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
         result = isSubtype
-      elif typeRel(c, base(f), a.sons[1]) >= isGeneric: 
+      elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
         result = isConvertible
-    of tySequence: 
-      if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): 
+    of tySequence:
+      if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
         result = isConvertible
-      elif typeRel(c, base(f), a.sons[0]) >= isGeneric: 
+      elif typeRel(c, base(f), a.sons[0]) >= isGeneric:
         result = isConvertible
     else: discard
   of tySequence:
@@ -724,7 +771,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   of tyForward: internalError("forward type in typeRel()")
   of tyNil:
     if a.kind == f.kind: result = isEqual
-  of tyTuple: 
+  of tyTuple:
     if a.kind == tyTuple: result = recordRel(c, f, a)
   of tyObject:
     if a.kind == tyObject:
@@ -737,15 +784,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
           inc(c.inheritancePenalty, depth)
           result = isSubtype
   of tyDistinct:
-    if (a.kind == tyDistinct) and sameDistinctTypes(f, a): result = isEqual
+    if a.kind == tyDistinct and sameDistinctTypes(f, a): result = isEqual
     elif c.coerceDistincts: result = typeRel(c, f.base, a)
-  of tySet: 
-    if a.kind == tySet: 
-      if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty): 
+  of tySet:
+    if a.kind == tySet:
+      if f.sons[0].kind != tyGenericParam and a.sons[0].kind == tyEmpty:
         result = isSubtype
-      else: 
+      else:
         result = typeRel(c, f.sons[0], a.sons[0])
-        if result <= isConvertible: 
+        if result <= isConvertible:
           result = isNone     # BUGFIX!
   of tyPtr, tyRef:
     if a.kind == f.kind:
@@ -779,9 +826,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       if a.len == 1: result = isConvertible
     of tyCString: result = isConvertible
     else: discard
-  of tyString: 
+  of tyString:
     case a.kind
-    of tyString: 
+    of tyString:
       if tfNotNil in f.flags and tfNotNil notin a.flags:
         result = isNilConversion
       else:
@@ -804,7 +851,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
     of tyArray:
       if (firstOrd(a.sons[0]) == 0) and
           (skipTypes(a.sons[0], {tyRange}).kind in {tyInt..tyInt64}) and
-          (a.sons[1].kind == tyChar): 
+          (a.sons[1].kind == tyChar):
         result = isConvertible
     else: discard
 
@@ -819,10 +866,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
         let ff = rootf.sons[i]
         let aa = roota.sons[i]
         result = typeRel(c, ff, aa)
-        if result == isNone: return        
+        if result == isNone: return
         if ff.kind == tyRange and result != isEqual: return isNone
-
-      result = isGeneric
+      #result = isGeneric
+      # XXX See bug #2220. A[int] should match A[int] better than some generic X
     else:
       result = typeRel(c, lastSon(f), a)
 
@@ -833,52 +880,70 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       let ff = lastSon(f)
       if ff != nil: result = typeRel(c, ff, a)
 
-  of tyGenericInvokation:
+  of tyGenericInvocation:
     var x = a.skipGenericAlias
-    if x.kind == tyGenericInvokation or f.sons[0].kind != tyGenericBody:
-      #InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation")
+    if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody:
+      #InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
       # simply no match for now:
       discard
-    elif x.kind == tyGenericInst and 
+    elif x.kind == tyGenericInst and
           (f.sons[0] == x.sons[0]) and
           (sonsLen(x) - 1 == sonsLen(f)):
       for i in countup(1, sonsLen(f) - 1):
         if x.sons[i].kind == tyGenericParam:
           internalError("wrong instantiated type!")
-        elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return 
+        elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return
       result = isGeneric
     else:
-      result = typeRel(c, f.sons[0], x)
+      let genericBody = f.sons[0]
+      result = typeRel(c, genericBody, x)
       if result != isNone:
+        # see tests/generics/tgeneric3.nim for an example that triggers this
+        # piece of code:
+        #
+        # proc internalFind[T,D](n: PNode[T,D], key: T): ref TItem[T,D]
+        # proc internalPut[T,D](ANode: ref TNode[T,D], Akey: T, Avalue: D,
+        #                       Oldvalue: var D): ref TNode[T,D]
+        # var root = internalPut[int, int](nil, 312, 312, oldvalue)
+        # var it1 = internalFind(root, 312) # cannot instantiate: 'D'
+        #
         # we steal the generic parameters from the tyGenericBody:
         for i in countup(1, sonsLen(f) - 1):
-          var x = PType(idTableGet(c.bindings, f.sons[0].sons[i - 1]))
-          if x == nil or x.kind in {tyGenericInvokation, tyGenericParam}:
+          var x = PType(idTableGet(c.bindings, genericBody.sons[i-1]))
+          if x == nil:
+            discard "maybe fine (for eg. a==tyNil)"
+          elif x.kind in {tyGenericInvocation, tyGenericParam}:
             internalError("wrong instantiated type!")
-          put(c.bindings, f.sons[i], x)
-  
+          else:
+            put(c.bindings, f.sons[i], x)
+
   of tyAnd:
     considerPreviousT:
       for branch in f.sons:
-        if typeRel(c, branch, aOrig) < isSubtype:
-          return isNone
-
-      bindingRet isGeneric
+        let x = typeRel(c, branch, aOrig)
+        if x < isSubtype: return isNone
+        # 'and' implies minimum matching result:
+        if x < result: result = x
+      bindingRet result
 
   of tyOr:
     considerPreviousT:
+      result = isNone
       for branch in f.sons:
-        if typeRel(c, branch, aOrig) >= isSubtype:
-          bindingRet isGeneric
-       
-      return isNone
+        let x = typeRel(c, branch, aOrig)
+        # 'or' implies maximum matching result:
+        if x > result: result = x
+      if result >= isSubtype:
+        bindingRet result
+      else:
+        result = isNone
 
   of tyNot:
     considerPreviousT:
       for branch in f.sons:
         if typeRel(c, branch, aOrig) != isNone:
           return isNone
-      
+
       bindingRet isGeneric
 
   of tyAnything:
@@ -917,7 +982,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
     if x == nil:
       if c.callee.kind == tyGenericBody and
          f.kind == tyGenericParam and not c.typedescMatched:
-        # XXX: The fact that generic types currently use tyGenericParam for 
+        # XXX: The fact that generic types currently use tyGenericParam for
         # their parameters is really a misnomer. tyGenericParam means "match
         # any value" and what we need is "match any type", which can be encoded
         # by a tyTypeDesc params. Unfortunately, this requires more substantial
@@ -930,7 +995,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
           else:
             internalAssert a.sons != nil and a.sons.len > 0
             c.typedescMatched = true
-            result = typeRel(c, f.base, a.base)
+            var aa = a
+            while aa.kind in {tyTypeDesc, tyGenericParam} and
+                aa.len > 0:
+              aa = lastSon(aa)
+            result = typeRel(c, f.base, aa)
+            if result > isGeneric: result = isGeneric
         else:
           result = isNone
       else:
@@ -954,20 +1024,38 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
             return isNone
         if doBind:
           put(c.bindings, f, concrete)
+      elif result > isGeneric:
+        result = isGeneric
     elif a.kind == tyEmpty:
       result = isGeneric
     elif x.kind == tyGenericParam:
       result = isGeneric
     else:
       result = typeRel(c, x, a) # check if it fits
-  
+      if result > isGeneric: result = isGeneric
+
   of tyStatic:
-    if aOrig.kind == tyStatic:
-      result = typeRel(c, f.lastSon, a)
-      if result != isNone: put(c.bindings, f, aOrig)
+    let prev = PType(idTableGet(c.bindings, f))
+    if prev == nil:
+      if aOrig.kind == tyStatic:
+        result = typeRel(c, f.lastSon, a)
+        if result != isNone and f.n != nil:
+          if not exprStructuralEquivalent(f.n, aOrig.n):
+            result = isNone
+        if result != isNone: put(c.bindings, f, aOrig)
+      else:
+        result = isNone
+    elif prev.kind == tyStatic:
+      if aOrig.kind == tyStatic:
+        result = typeRel(c, prev.lastSon, a)
+        if result != isNone and prev.n != nil:
+          if not exprStructuralEquivalent(prev.n, aOrig.n):
+            result = isNone
+      else: result = isNone
     else:
+      # XXX endless recursion?
+      #result = typeRel(c, prev, aOrig)
       result = isNone
-
   of tyTypeDesc:
     var prev = PType(idTableGet(c.bindings, f))
     if prev == nil:
@@ -975,12 +1063,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
       # when `f` is an unresolved typedesc, `a` could be any
       # type, so we should not perform this check earlier
       if a.kind != tyTypeDesc: return isNone
-    
+
       if f.base.kind == tyNone:
         result = isGeneric
       else:
         result = typeRel(c, f.base, a.base)
-      
+
       if result != isNone:
         put(c.bindings, f, a)
     else:
@@ -990,9 +1078,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
         result = typeRel(c, prev.base, a.base)
       else:
         result = isNone
- 
+
   of tyIter:
-    if a.kind == tyIter or 
+    if a.kind == tyIter or
       (a.kind == tyProc and tfIterator in a.flags):
       result = typeRel(c, f.base, a.base)
     else:
@@ -1000,48 +1088,50 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
 
   of tyStmt:
     result = isGeneric
-  
+
   of tyProxy:
     result = isEqual
 
   of tyFromExpr:
     # fix the expression, so it contains the already instantiated types
-    let instantiated = replaceTypesInBody(c.c, c.bindings, f.n)
-    let reevaluted = c.c.semExpr(c.c, instantiated)
-    case reevaluted.typ.kind
+    if f.n == nil or f.n.kind == nkEmpty: return isGeneric
+    let reevaluated = tryResolvingStaticExpr(c, f.n)
+    case reevaluated.typ.kind
     of tyTypeDesc:
-      result = typeRel(c, a, reevaluted.typ.base)
+      result = typeRel(c, a, reevaluated.typ.base)
     of tyStatic:
-      result = typeRel(c, a, reevaluted.typ.base)
-      if result != isNone and reevaluted.typ.n != nil:
-        if not exprStructuralEquivalent(aOrig.n, reevaluted.typ.n):
+      result = typeRel(c, a, reevaluated.typ.base)
+      if result != isNone and reevaluated.typ.n != nil:
+        if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n):
           result = isNone
     else:
       localError(f.n.info, errTypeExpected)
       result = isNone
-  
+
+  of tyNone:
+    if a.kind == tyNone: result = isEqual
   else:
-    internalAssert false
-  
-proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation = 
+    internalError " unknown type kind " & $f.kind
+
+proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
   var m: TCandidate
   initCandidate(c, m, f)
   result = typeRel(m, f, a)
 
-proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate, 
-                         f: PType): PType = 
+proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate,
+                         f: PType): PType =
   result = PType(idTableGet(m.bindings, f))
-  if result == nil: 
+  if result == nil:
     result = generateTypeInstance(c, m.bindings, arg, f)
   if result == nil:
     internalError(arg.info, "getInstantiatedType")
     result = errorType(c)
-  
-proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate, 
-                  c: PContext): PNode = 
+
+proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
+                  c: PContext): PNode =
   result = newNodeI(kind, arg.info)
   if containsGenericType(f):
-    if not m.proxyMatch:
+    if not m.hasFauxMatch:
       result.typ = getInstantiatedType(c, arg, m, f)
     else:
       result.typ = errorType(c)
@@ -1051,10 +1141,10 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
   addSon(result, ast.emptyNode)
   addSon(result, arg)
 
-proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, 
-                   arg: PNode): PNode = 
+proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
+                   arg: PNode): PNode =
   result = nil
-  for i in countup(0, len(c.converters) - 1): 
+  for i in countup(0, len(c.converters) - 1):
     var src = c.converters[i].typ.sons[1]
     var dest = c.converters[i].typ.sons[0]
     # for generic type converters we need to check 'src <- a' before
@@ -1062,12 +1152,12 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
     # see tests/tgenericconverter:
     let srca = typeRel(m, src, a)
     if srca notin {isEqual, isGeneric}: continue
-    
+
     let destIsGeneric = containsGenericType(dest)
     if destIsGeneric:
       dest = generateTypeInstance(c, m.bindings, arg, dest)
     let fdest = typeRel(m, f, dest)
-    if fdest in {isEqual, isGeneric}: 
+    if fdest in {isEqual, isGeneric}:
       markUsed(arg.info, c.converters[i])
       var s = newSymNode(c.converters[i])
       s.typ = c.converters[i].typ
@@ -1079,10 +1169,15 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
       m.genericConverter = srca == isGeneric or destIsGeneric
       return result
 
-proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType, 
-                    arg: PNode): PNode = 
+proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
+                    arg: PNode): PNode =
   # arg.typ can be nil in 'suggest':
   if isNil(arg.typ): return nil
+
+  # sem'checking for 'echo' needs to be re-entrant:
+  # XXX we will revisit this issue after 0.10.2 is released
+  if f == arg.typ and arg.kind == nkHiddenStdConv: return arg
+
   var call = newNodeI(nkCall, arg.info)
   call.add(f.n.copyTree)
   call.add(arg.copyTree)
@@ -1101,6 +1196,26 @@ proc isInlineIterator*(t: PType): bool =
   result = t.kind == tyIter or
           (t.kind == tyBuiltInTypeClass and t.base.kind == tyIter)
 
+proc isEmptyContainer*(t: PType): bool =
+  case t.kind
+  of tyExpr, tyNil: result = true
+  of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty
+  of tySet, tySequence, tyOpenArray, tyVarargs:
+    result = t.sons[0].kind == tyEmpty
+  of tyGenericInst: result = isEmptyContainer(t.lastSon)
+  else: result = false
+
+proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
+  case r
+  of isConvertible, isIntConv: inc(m.convMatches, convMatch)
+  of isSubtype, isSubrange: inc(m.subtypeMatches)
+  of isGeneric, isInferred: inc(m.genericMatches)
+  of isFromIntLit: inc(m.intConvMatches, 256)
+  of isInferredConvertible:
+    inc(m.convMatches)
+  of isEqual: inc(m.exactMatches)
+  of isNone: discard
+
 proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
                         argSemantized, argOrig: PNode): PNode =
   var
@@ -1108,12 +1223,12 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
     arg = argSemantized
     argType = argType
     c = m.c
- 
+
   if tfHasStatic in fMaybeStatic.flags:
     # XXX: When implicit statics are the default
     # this will be done earlier - we just have to
     # make sure that static types enter here
-     
+
     # XXX: weaken tyGenericParam and call it tyGenericPlaceholder
     # and finally start using tyTypedesc for generic types properly.
     if argType.kind == tyGenericParam and tfWildcard in argType.flags:
@@ -1122,9 +1237,8 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
       return argSemantized
 
     if argType.kind == tyStatic:
-      if m.callee.kind == tyGenericBody:
-        result = newNodeI(nkType, argOrig.info)
-        result.typ = makeTypeFromExpr(c, arg)
+      if m.callee.kind == tyGenericBody and tfGenericTypeParam notin argType.flags:
+        result = newNodeIT(nkType, argOrig.info, makeTypeFromExpr(c, arg))
         return
     else:
       var evaluated = c.semTryConstExpr(c, arg)
@@ -1133,34 +1247,26 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
         arg.typ.sons = @[evaluated.typ]
         arg.typ.n = evaluated
         argType = arg.typ
- 
+
   var
     a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc, tyFieldAccessor})
         else: argType
- 
+
     r = typeRel(m, f, a)
 
   if r != isNone and m.calleeSym != nil and
      m.calleeSym.kind in {skMacro, skTemplate}:
-    # XXX: duplicating this is ugly, maybe we should move this
+    # XXX: duplicating this is ugly, but we cannot (!) move this
     # directly into typeRel using return-like templates
-    case r
-    of isConvertible, isIntConv: inc(m.convMatches)
-    of isSubtype, isSubrange: inc(m.subtypeMatches)
-    of isGeneric, isInferred: inc(m.genericMatches)
-    of isInferredConvertible: inc(m.genericMatches); inc(m.convMatches)
-    of isFromIntLit: inc(m.intConvMatches, 256)
-    of isEqual: inc(m.exactMatches)
-    of isNone: discard
-
-    if f.kind == tyStmt and argOrig.kind == nkDo:
-      return argOrig[bodyPos]
+    incMatches(m, r)
+    if f.kind == tyStmt:
+      return arg
     elif f.kind == tyTypeDesc:
       return arg
     elif f.kind == tyStatic:
       return arg.typ.n
     else:
-      return argOrig
+      return argSemantized # argOrig
 
   if r != isNone and f.isInlineIterator:
     var inlined = newTypeS(tyStatic, c)
@@ -1172,21 +1278,22 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
   case r
   of isConvertible:
     inc(m.convMatches)
-    result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
+    result = implicitConv(nkHiddenStdConv, f, arg, m, c)
   of isIntConv:
     # I'm too lazy to introduce another ``*matches`` field, so we conflate
     # ``isIntConv`` and ``isIntLit`` here:
     inc(m.intConvMatches)
-    result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
-  of isSubtype: 
+    result = implicitConv(nkHiddenStdConv, f, arg, m, c)
+  of isSubtype:
     inc(m.subtypeMatches)
-    result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
+    result = implicitConv(nkHiddenSubConv, f, arg, m, c)
   of isSubrange:
     inc(m.subtypeMatches)
-    #result = copyTree(arg)
-    result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
+    if f.kind == tyVar:
+      result = arg
+    else:
+      result = implicitConv(nkHiddenStdConv, f, arg, m, c)
   of isInferred, isInferredConvertible:
-    inc(m.genericMatches)
     if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
       result = c.semInferredLambda(c, m.bindings, arg)
     else:
@@ -1195,31 +1302,36 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
     if r == isInferredConvertible:
       inc(m.convMatches)
       result = implicitConv(nkHiddenStdConv, f, result, m, c)
+    else:
+      inc(m.genericMatches)
   of isGeneric:
     inc(m.genericMatches)
-    result = copyTree(arg)
-    result.typ = getInstantiatedType(c, arg, m, f)
-    # BUG: f may not be the right key!
-    if skipTypes(result.typ, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
+    if arg.typ == nil:
+      result = arg
+    elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
       result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
-      # BUGFIX: use ``result.typ`` and not `f` here
+    elif arg.typ.isEmptyContainer:
+      result = arg.copyTree
+      result.typ = getInstantiatedType(c, arg, m, f)
+    else:
+      result = arg
   of isFromIntLit:
     # too lazy to introduce another ``*matches`` field, so we conflate
     # ``isIntConv`` and ``isIntLit`` here:
     inc(m.intConvMatches, 256)
-    result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
-  of isEqual: 
+    result = implicitConv(nkHiddenStdConv, f, arg, m, c)
+  of isEqual:
     inc(m.exactMatches)
-    result = copyTree(arg)
+    result = arg
     if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
-      result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
+      result = implicitConv(nkHiddenStdConv, f, arg, m, c)
   of isNone:
     # do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
-    if a.kind == tyProxy:
+    if a.kind in {tyProxy, tyUnknown}:
       inc(m.genericMatches)
-      m.proxyMatch = true
-      return copyTree(arg)
-    result = userConvMatch(c, m, f, a, arg) 
+      m.fauxMatch = a.kind
+      return arg
+    result = userConvMatch(c, m, f, a, arg)
     # check for a base type match, which supports varargs[T] without []
     # constructor in a call:
     if result == nil and f.kind == tyVarargs:
@@ -1240,12 +1352,11 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
                       arg, argOrig: PNode): PNode =
   if arg == nil or arg.kind notin nkSymChoices:
     result = paramTypesMatchAux(m, f, a, arg, argOrig)
-  else: 
+  else:
     # CAUTION: The order depends on the used hashing scheme. Thus it is
     # incorrect to simply use the first fitting match. However, to implement
     # this correctly is inefficient. We have to copy `m` here to be able to
     # roll back the side effects of the unification algorithm.
-
     let c = m.c
     var x, y, z: TCandidate
     initCandidate(c, x, m.callee)
@@ -1255,38 +1366,54 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
     y.calleeSym = m.calleeSym
     z.calleeSym = m.calleeSym
     var best = -1
-    for i in countup(0, sonsLen(arg) - 1): 
+    for i in countup(0, sonsLen(arg) - 1):
       if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}+skIterators:
         copyCandidate(z, m)
-        var r = typeRel(z, f, arg.sons[i].typ)
-        if r != isNone: 
+        z.callee = arg.sons[i].typ
+        z.calleeSym = arg.sons[i].sym
+        #if arg.sons[i].sym.name.s == "cmp":
+        #  ggDebug = true
+        #  echo "CALLLEEEEEEEE A ", typeToString(z.callee)
+        # XXX this is still all wrong: (T, T) should be 2 generic matches
+        # and  (int, int) 2 exact matches, etc. Essentially you cannot call
+        # typeRel here and expect things to work!
+        let r = typeRel(z, f, arg.sons[i].typ)
+        incMatches(z, r, 2)
+        #if arg.sons[i].sym.name.s == "cmp": # and arg.info.line == 606:
+        #  echo "M ", r, " ", arg.info, " ", typeToString(arg.sons[i].sym.typ)
+        #  writeMatches(z)
+        if r != isNone:
+          z.state = csMatch
           case x.state
-          of csEmpty, csNoMatch: 
+          of csEmpty, csNoMatch:
             x = z
             best = i
-            x.state = csMatch
-          of csMatch: 
-            var cmp = cmpCandidates(x, z)
+          of csMatch:
+            let cmp = cmpCandidates(x, z)
             if cmp < 0:
               best = i
               x = z
             elif cmp == 0:
               y = z           # z is as good as x
-    if x.state == csEmpty: 
-      result = nil
-    elif (y.state == csMatch) and (cmpCandidates(x, y) == 0): 
-      if x.state != csMatch: 
-        internalError(arg.info, "x.state is not csMatch") 
-      # ambiguous: more than one symbol fits
+    if x.state == csEmpty:
       result = nil
-    else: 
+    elif y.state == csMatch and cmpCandidates(x, y) == 0:
+      if x.state != csMatch:
+        internalError(arg.info, "x.state is not csMatch")
+      # ambiguous: more than one symbol fits!
+      # See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match
+      # anyway:
+      if f.kind == tyExpr: result = arg
+      else: result = nil
+    else:
       # only one valid interpretation found:
       markUsed(arg.info, arg.sons[best].sym)
       styleCheckUse(arg.info, arg.sons[best].sym)
       result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
                                   argOrig)
 
-proc setSon(father: PNode, at: int, son: PNode) = 
+
+proc setSon(father: PNode, at: int, son: PNode) =
   if sonsLen(father) <= at: setLen(father.sons, at + 1)
   father.sons[at] = son
 
@@ -1297,9 +1424,12 @@ proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
     # a.typ == nil is valid
     result = a
   elif a.typ.isNil:
+    # XXX This is unsound! 'formal' can differ from overloaded routine to
+    # overloaded routine!
     let flags = if formal.kind == tyIter: {efDetermineType, efWantIterator}
-                elif formal.kind == tyStmt: {efDetermineType, efWantStmt}
-                else: {efDetermineType}
+                else: {efDetermineType, efAllowStmt}
+                #elif formal.kind == tyStmt: {efDetermineType, efWantStmt}
+                #else: {efDetermineType}
     result = c.semOperand(c, a, flags)
   else:
     result = a
@@ -1330,7 +1460,7 @@ proc incrIndexType(t: PType) =
   inc t.sons[0].n.sons[1].intVal
 
 proc matchesAux(c: PContext, n, nOrig: PNode,
-                m: var TCandidate, marker: var IntSet) = 
+                m: var TCandidate, marker: var IntSet) =
   template checkConstraint(n: expr) {.immediate, dirty.} =
     if not formal.constraint.isNil:
       if matchNodeKinds(formal.constraint, n):
@@ -1339,6 +1469,12 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
       else:
         m.state = csNoMatch
         return
+    if formal.typ.kind == tyVar:
+      if n.isLValue:
+        inc(m.genericMatches, 100)
+      else:
+        m.state = csNoMatch
+        return
 
   var
     # iterates over formal parameters
@@ -1360,20 +1496,20 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
       # named param
       # check if m.callee has such a param:
       prepareNamedParam(n.sons[a])
-      if n.sons[a].sons[0].kind != nkIdent: 
+      if n.sons[a].sons[0].kind != nkIdent:
         localError(n.sons[a].info, errNamedParamHasToBeIdent)
         m.state = csNoMatch
-        return 
+        return
       formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1)
-      if formal == nil: 
+      if formal == nil:
         # no error message!
         m.state = csNoMatch
-        return 
-      if containsOrIncl(marker, formal.position): 
+        return
+      if containsOrIncl(marker, formal.position):
         # already in namedParams:
         localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
         m.state = csNoMatch
-        return 
+        return
       m.baseTypeMatch = false
       n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1])
       n.sons[a].typ = n.sons[a].sons[1].typ
@@ -1383,14 +1519,15 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
         m.state = csNoMatch
         return
       checkConstraint(n.sons[a].sons[1])
-      if m.baseTypeMatch: 
-        assert(container == nil)
+      if m.baseTypeMatch:
+        #assert(container == nil)
         container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
         addSon(container, arg)
         setSon(m.call, formal.position + 1, container)
         if f != formalLen - 1: container = nil
-      else: 
+      else:
         setSon(m.call, formal.position + 1, arg)
+      inc f
     else:
       # unnamed param
       if f >= formalLen:
@@ -1404,12 +1541,14 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
                                         copyTree(n.sons[a]), m, c))
           else:
             addSon(m.call, copyTree(n.sons[a]))
-        elif formal != nil:
+        elif formal != nil and formal.typ.kind == tyVarargs:
+          # beware of the side-effects in 'prepareOperand'! So only do it for
+          # varags matching. See tests/metatype/tstatic_overloading.
           m.baseTypeMatch = false
           n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
           var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
                                     n.sons[a], nOrig.sons[a])
-          if (arg != nil) and m.baseTypeMatch and (container != nil):
+          if arg != nil and m.baseTypeMatch and container != nil:
             addSon(container, arg)
             incrIndexType(container.typ)
           else:
@@ -1419,15 +1558,15 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           m.state = csNoMatch
           return
       else:
-        if m.callee.n.sons[f].kind != nkSym: 
+        if m.callee.n.sons[f].kind != nkSym:
           internalError(n.sons[a].info, "matches")
           return
         formal = m.callee.n.sons[f].sym
-        if containsOrIncl(marker, formal.position): 
+        if containsOrIncl(marker, formal.position) and container.isNil:
           # already in namedParams:
           localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
           m.state = csNoMatch
-          return 
+          return
         m.baseTypeMatch = false
         n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
         var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
@@ -1436,17 +1575,22 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           m.state = csNoMatch
           return
         if m.baseTypeMatch:
-          assert(container == nil)
-          container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
+          #assert(container == nil)
+          if container.isNil:
+            container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
           addSon(container, arg)
-          setSon(m.call, formal.position + 1, 
+          setSon(m.call, formal.position + 1,
                  implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
-          if f != formalLen - 1: container = nil
+          #if f != formalLen - 1: container = nil
+
+          # pick the formal from the end, so that 'x, y, varargs, z' works:
+          f = max(f, formalLen - n.len + a + 1)
         else:
           setSon(m.call, formal.position + 1, arg)
+          inc(f)
+          container = nil
       checkConstraint(n.sons[a])
     inc(a)
-    inc(f)
 
 proc semFinishOperands*(c: PContext, n: PNode) =
   # this needs to be called to ensure that after overloading resolution every
@@ -1491,12 +1635,15 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool =
   # instantiate generic converters for that
   result = res != nil
 
-proc instDeepCopy*(c: PContext; dc: PSym; t: PType; info: TLineInfo): PSym {.
-                    procvar.} =
+proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
+                      op: TTypeAttachedOp): PSym {.procvar.} =
   var m: TCandidate
   initCandidate(c, m, dc.typ)
   var f = dc.typ.sons[1]
-  if f.kind in {tyRef, tyPtr}: f = f.lastSon
+  if op == attachedDeepCopy:
+    if f.kind in {tyRef, tyPtr}: f = f.lastSon
+  else:
+    if f.kind == tyVar: f = f.lastSon
   if typeRel(m, f, t) == isNone:
     localError(info, errGenerated, "cannot instantiate 'deepCopy'")
   else:
@@ -1510,7 +1657,7 @@ when not declared(tests):
 
 tests:
   var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo())
-  
+
   proc `|` (t1, t2: PType): PType =
     result = newType(tyOr, dummyOwner)
     result.rawAddSon(t1)
@@ -1531,12 +1678,12 @@ tests:
 
   proc array(x: int, t: PType): PType =
     result = newType(tyArray, dummyOwner)
-    
+
     var n = newNodeI(nkRange, UnknownLineInfo())
     addSon(n, newIntNode(nkIntLit, 0))
     addSon(n, newIntNode(nkIntLit, x))
     let range = newType(tyRange, dummyOwner)
-    
+
     result.rawAddSon(range)
     result.rawAddSon(t)
 
@@ -1562,7 +1709,7 @@ tests:
 
     setup:
       var c: TCandidate
-      InitCandidate(nil, c, nil)
+      initCandidate(nil, c, nil)
 
     template yes(x, y) =
       test astToStr(x) & " is " & astToStr(y):
@@ -1571,7 +1718,7 @@ tests:
     template no(x, y) =
       test astToStr(x) & " is not " & astToStr(y):
         check typeRel(c, y, x) == isNone
-    
+
     yes seq(any), array(10, int) | seq(any)
     # Sure, seq[any] is directly included
 
@@ -1579,16 +1726,16 @@ tests:
     yes seq(int), seq(number)
     # Sure, the int sequence is certainly
     # part of the number sequences (and all sequences)
-    
+
     no seq(any), seq(float)
     # Nope, seq[any] includes types that are not seq[float] (e.g. seq[int])
 
     yes seq(int|string), seq(any)
     # Sure
- 
+
     yes seq(int&string), seq(any)
     # Again
-    
+
     yes seq(int&string), seq(int)
     # A bit more complicated
     # seq[int&string] is not a real type, but it's analogous to
@@ -1597,23 +1744,23 @@ tests:
     no seq(int|string), seq(int|float)
     # Nope, seq[string] is not included in not included in
     # the seq[int|float] set
-    
+
     no seq(!(int|string)), seq(string)
     # A sequence that is neither seq[int] or seq[string]
     # is obviously not seq[string]
-     
+
     no seq(!int), seq(number)
     # Now your head should start to hurt a bit
     # A sequence that is not seq[int] is not necessarily a number sequence
     # it could well be seq[string] for example
-    
+
     yes seq(!(int|string)), seq(!string)
     # all sequnece types besides seq[int] and seq[string]
     # are subset of all sequence types that are not seq[string]
 
     no seq(!(int|string)), seq(!(string|TFoo))
     # Nope, seq[TFoo] is included in the first set, but not in the second
-    
+
     no seq(!string), seq(!number)
     # Nope, seq[int] in included in the first set, but not in the second
 
@@ -1621,7 +1768,7 @@ tests:
     yes seq(!int), seq(any)
     no seq(any), seq(!any)
     no seq(!int), seq(!any)
-    
+
     yes int, ordinal
     no  string, ordinal
 
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index c700db323..6b168670c 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2013 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -22,44 +22,57 @@ const
 
 #template sectionSuggest(): expr = "##begin\n" & getStackTrace() & "##end\n"
 
-proc origModuleName(m: PSym): string =
-  result = if m.position == gDirtyBufferIdx:
-             fileInfos[gDirtyOriginalIdx].shortName
-           else:
-             m.name.s
+template origModuleName(m: PSym): string = m.name.s
 
 proc symToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string = 
   result = section
   result.add(sep)
-  result.add($s.kind)
-  result.add(sep)
-  if not isLocal and s.kind != skModule:
-    let ow = s.owner
-    if ow.kind != skModule and ow.owner != nil:
-      let ow2 = ow.owner
-      result.add(ow2.origModuleName)
+  if optIdeTerse in gGlobalOptions:
+    if s.kind in routineKinds:
+      result.add renderTree(s.ast, {renderNoBody, renderNoComments,
+                                    renderDocComments, renderNoPragmas})
+    else:
+      result.add s.name.s
+    result.add(sep)
+    result.add(toFullPath(li))
+    result.add(sep)
+    result.add($toLinenumber(li))
+    result.add(sep)
+    result.add($toColumn(li))
+  else:
+    result.add($s.kind)
+    result.add(sep)
+    if not isLocal and s.kind != skModule:
+      let ow = s.owner
+      if ow.kind != skModule and ow.owner != nil:
+        let ow2 = ow.owner
+        result.add(ow2.origModuleName)
+        result.add('.')
+      result.add(ow.origModuleName)
       result.add('.')
-    result.add(ow.origModuleName)
-    result.add('.')
-  result.add(s.name.s)
-  result.add(sep)
-  if s.typ != nil: 
-    result.add(typeToString(s.typ))
-  result.add(sep)
-  result.add(toFullPath(li))
-  result.add(sep)
-  result.add($toLinenumber(li))
-  result.add(sep)
-  result.add($toColumn(li))
-  result.add(sep)
-  when not defined(noDocgen):
-    result.add(s.extractDocComment.escape)
+    result.add(s.name.s)
+    result.add(sep)
+    if s.typ != nil: 
+      result.add(typeToString(s.typ))
+    result.add(sep)
+    result.add(toFullPath(li))
+    result.add(sep)
+    result.add($toLinenumber(li))
+    result.add(sep)
+    result.add($toColumn(li))
+    result.add(sep)
+    when not defined(noDocgen):
+      result.add(s.extractDocComment.escape)
 
 proc symToStr(s: PSym, isLocal: bool, section: string): string = 
   result = symToStr(s, isLocal, section, s.info)
 
 proc filterSym(s: PSym): bool {.inline.} =
-  result = s.name.s[0] in lexer.SymChars and s.kind != skModule
+  result = s.kind != skModule
+
+proc filterSymNoOpr(s: PSym): bool {.inline.} =
+  result = s.kind != skModule and s.name.s[0] in lexer.SymChars and
+     not isKeyword(s.name)
 
 proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} =
   let fmoduleId = getModule(f).id
@@ -74,9 +87,6 @@ proc suggestField(c: PContext, s: PSym, outputs: var int) =
     suggestWriteln(symToStr(s, isLocal=true, sectionSuggest))
     inc outputs
 
-when not defined(nimhygiene):
-  {.pragma: inject.}
-
 template wholeSymTab(cond, section: expr) {.immediate.} =
   var isLocal = true
   for scope in walkScopes(c.currentScope):
@@ -134,11 +144,20 @@ proc suggestCall(c: PContext, n, nOrig: PNode, outputs: var int) =
 
 proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} = 
   if s.typ != nil and sonsLen(s.typ) > 1 and s.typ.sons[1] != nil:
+    # special rule: if system and some weird generic match via 'tyExpr'
+    # or 'tyGenericParam' we won't list it either to reduce the noise (nobody
+    # wants 'system.`-|` as suggestion
+    let m = s.getModule()
+    if m != nil and sfSystemModule in m.flags:
+      if s.kind == skType: return
+      var exp = s.typ.sons[1].skipTypes({tyGenericInst, tyVar})
+      if exp.kind == tyVarargs: exp = elemType(exp)
+      if exp.kind in {tyExpr, tyStmt, tyGenericParam, tyAnything}: return
     result = sigmatch.argtypeMatches(c, s.typ.sons[1], firstArg)
 
 proc suggestOperations(c: PContext, n: PNode, typ: PType, outputs: var int) =
   assert typ != nil
-  wholeSymTab(filterSym(it) and typeFits(c, it, typ), sectionSuggest)
+  wholeSymTab(filterSymNoOpr(it) and typeFits(c, it, typ), sectionSuggest)
 
 proc suggestEverything(c: PContext, n: PNode, outputs: var int) =
   # do not produce too many symbols:
@@ -194,19 +213,28 @@ proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) =
     else:
       suggestOperations(c, n, typ, outputs)
 
+type
+  TCheckPointResult = enum 
+    cpNone, cpFuzzy, cpExact
+
+proc inCheckpoint(current: TLineInfo): TCheckPointResult = 
+  if current.fileIndex == gTrackPos.fileIndex:
+    if current.line == gTrackPos.line and
+        abs(current.col-gTrackPos.col) < 4:
+      return cpExact
+    if current.line >= gTrackPos.line:
+      return cpFuzzy
+
 proc findClosestDot(n: PNode): PNode =
-  if n.kind == nkDotExpr and msgs.inCheckpoint(n.info) == cpExact:
+  if n.kind == nkDotExpr and inCheckpoint(n.info) == cpExact:
     result = n
   else:
     for i in 0.. <safeLen(n):
       result = findClosestDot(n.sons[i])
       if result != nil: return
 
-const
-  CallNodes = {nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit}
-
 proc findClosestCall(n: PNode): PNode = 
-  if n.kind in CallNodes and msgs.inCheckpoint(n.info) == cpExact: 
+  if n.kind in nkCallKinds and inCheckpoint(n.info) == cpExact: 
     result = n
   else:
     for i in 0.. <safeLen(n):
@@ -214,34 +242,20 @@ proc findClosestCall(n: PNode): PNode =
       if result != nil: return
 
 proc isTracked(current: TLineInfo, tokenLen: int): bool =
-  for i in countup(0, high(checkPoints)):
-    if current.fileIndex == checkPoints[i].fileIndex:
-      if current.line == checkPoints[i].line:
-        let col = checkPoints[i].col
-        if col >= current.col and col <= current.col+tokenLen-1:
-          return true
+  if current.fileIndex == gTrackPos.fileIndex:
+    if current.line == gTrackPos.line:
+      let col = gTrackPos.col
+      if col >= current.col and col <= current.col+tokenLen-1:
+        return true
 
 proc findClosestSym(n: PNode): PNode = 
-  if n.kind == nkSym and msgs.inCheckpoint(n.info) == cpExact: 
+  if n.kind == nkSym and inCheckpoint(n.info) == cpExact: 
     result = n
   elif n.kind notin {nkNone..nkNilLit}:
     for i in 0.. <sonsLen(n):
       result = findClosestSym(n.sons[i])
       if result != nil: return
 
-proc safeSemExpr(c: PContext, n: PNode): PNode = 
-  try:
-    result = c.semExpr(c, n)
-  except ERecoverableError:
-    result = ast.emptyNode
-
-proc fuzzySemCheck(c: PContext, n: PNode): PNode = 
-  result = safeSemExpr(c, n)
-  if result == nil or result.kind == nkEmpty:
-    result = newNodeI(n.kind, n.info)
-    if n.kind notin {nkNone..nkNilLit}:
-      for i in 0 .. < sonsLen(n): result.addSon(fuzzySemCheck(c, n.sons[i]))
-
 var
   usageSym*: PSym
   lastLineInfo: TLineInfo
@@ -261,69 +275,18 @@ proc findDefinition(info: TLineInfo; s: PSym) =
     suggestWriteln(symToStr(s, isLocal=false, sectionDef))
     suggestQuit()
 
-type
-  TSourceMap = object
-    lines: seq[TLineMap]
-  
-  TEntry = object
-    pos: int
-    sym: PSym
-
-  TLineMap = object
-    entries: seq[TEntry]
-
-var
-  gSourceMaps: seq[TSourceMap] = @[]
-
 proc ensureIdx[T](x: var T, y: int) =
   if x.len <= y: x.setLen(y+1)
 
 proc ensureSeq[T](x: var seq[T]) =
   if x == nil: newSeq(x, 0)
 
-proc resetSourceMap*(fileIdx: int32) =
-  ensureIdx(gSourceMaps, fileIdx)
-  gSourceMaps[fileIdx].lines = @[]
-
-proc addToSourceMap(sym: PSym, info: TLineInfo) =
-  ensureIdx(gSourceMaps, info.fileIndex)
-  ensureSeq(gSourceMaps[info.fileIndex].lines)
-  ensureIdx(gSourceMaps[info.fileIndex].lines, info.line)
-  ensureSeq(gSourceMaps[info.fileIndex].lines[info.line].entries)
-  gSourceMaps[info.fileIndex].lines[info.line].entries.add(TEntry(pos: info.col, sym: sym))
-
-proc defFromLine(entries: var seq[TEntry], col: int32) =
-  if entries == nil: return
-  # The sorting is done lazily here on purpose.
-  # No need to pay the price for it unless the user requests
-  # "goto definition" on a particular line
-  sort(entries) do (a,b: TEntry) -> int:
-    return cmp(a.pos, b.pos)
-  
-  for e in entries:
-    # currently, the line-infos for most expressions point to
-    # one position past the end of the expression. This means
-    # that the first expr that ends after the cursor column is
-    # the one we are looking for.
-    if e.pos >= col:
-      suggestWriteln(symToStr(e.sym, isLocal=false, sectionDef))
-      return
-
-proc defFromSourceMap*(i: TLineInfo) =
-  if not ((i.fileIndex < gSourceMaps.len) and
-          (gSourceMaps[i.fileIndex].lines != nil) and
-          (i.line < gSourceMaps[i.fileIndex].lines.len)): return
-  
-  defFromLine(gSourceMaps[i.fileIndex].lines[i.line].entries, i.col)
-
 proc suggestSym*(info: TLineInfo; s: PSym) {.inline.} =
   ## misnamed: should be 'symDeclared'
-  if optUsages in gGlobalOptions:
+  if gIdeCmd == ideUse:
     findUsages(info, s)
-  if optDef in gGlobalOptions:
+  elif gIdeCmd == ideDef:
     findDefinition(info, s)
-  if isServing:
-    addToSourceMap(s, info)
 
 proc markUsed(info: TLineInfo; s: PSym) =
   incl(s.flags, sfUsed)
@@ -336,31 +299,39 @@ proc useSym*(sym: PSym): PNode =
   result = newSymNode(sym)
   markUsed(result.info, sym)
 
+proc safeSemExpr*(c: PContext, n: PNode): PNode =
+  # use only for idetools support!
+  try:
+    result = c.semExpr(c, n)
+  except ERecoverableError:
+    result = ast.emptyNode
+
 proc suggestExpr*(c: PContext, node: PNode) = 
-  var cp = msgs.inCheckpoint(node.info)
-  if cp == cpNone: return
+  if nfIsCursor notin node.flags:
+    if gTrackPos.line < 0: return
+    var cp = inCheckpoint(node.info)
+    if cp == cpNone: return
   var outputs = 0
   # This keeps semExpr() from coming here recursively:
   if c.inCompilesContext > 0: return
   inc(c.inCompilesContext)
-  
-  if optSuggest in gGlobalOptions:
-    var n = findClosestDot(node)
+
+  if gIdeCmd == ideSug:
+    var n = if nfIsCursor in node.flags: node else: findClosestDot(node)
     if n == nil: n = node
-    else: cp = cpExact
-    if n.kind == nkDotExpr and cp == cpExact:
+    if n.kind == nkDotExpr:
       var obj = safeSemExpr(c, n.sons[0])
       suggestFieldAccess(c, obj, outputs)
+      if optIdeDebug in gGlobalOptions:
+        echo "expression ", renderTree(obj), " has type ", typeToString(obj.typ)
+      #writeStackTrace()
     else:
-      #debug n
       suggestEverything(c, n, outputs)
   
-  if optContext in gGlobalOptions:
-    var n = findClosestCall(node)
+  elif gIdeCmd == ideCon:
+    var n = if nfIsCursor in node.flags: node else: findClosestCall(node)
     if n == nil: n = node
-    else: cp = cpExact
-    
-    if n.kind in CallNodes:
+    if n.kind in nkCallKinds:
       var a = copyNode(n)
       var x = safeSemExpr(c, n.sons[0])
       if x.kind == nkEmpty or x.typ == nil: x = n.sons[0]
@@ -371,15 +342,9 @@ proc suggestExpr*(c: PContext, node: PNode) =
         if x.kind == nkEmpty or x.typ == nil: break
         addSon(a, x)
       suggestCall(c, a, n, outputs)
-  
+          
   dec(c.inCompilesContext)
-  if outputs > 0 and optUsages notin gGlobalOptions: suggestQuit()
+  if outputs > 0 and gIdeCmd != ideUse: suggestQuit()
 
 proc suggestStmt*(c: PContext, n: PNode) = 
   suggestExpr(c, n)
-
-proc findSuggest*(c: PContext, n: PNode) = 
-  if n == nil: return
-  suggestExpr(c, n)
-  for i in 0.. <safeLen(n):
-    findSuggest(c, n.sons[i])
diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim
index 61677a641..7f9e25f82 100644
--- a/compiler/syntaxes.nim
+++ b/compiler/syntaxes.nim
@@ -45,7 +45,7 @@ proc parseFile(fileIdx: int32): PNode =
   var 
     p: TParsers
     f: File
-  let filename = fileIdx.toFullPath
+  let filename = fileIdx.toFullPathConsiderDirty
   if not open(f, filename):
     rawMessage(errCannotOpenFile, filename)
     return 
@@ -163,7 +163,7 @@ proc evalPipe(p: var TParsers, n: PNode, filename: string,
 proc openParsers(p: var TParsers, fileIdx: int32, inputstream: PLLStream) = 
   var s: PLLStream
   p.skin = skinStandard
-  let filename = fileIdx.toFullPath
+  let filename = fileIdx.toFullPathConsiderDirty
   var pipe = parsePipe(filename, inputstream)
   if pipe != nil: s = evalPipe(p, pipe, filename, inputstream)
   else: s = inputstream
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 3409acb74..2143b6bec 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -17,27 +17,27 @@
 # * introduces method dispatchers
 # * performs lambda lifting for closure support
 
-import 
-  intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os, 
+import
+  intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
   idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread,
   lambdalifting, sempass2, lowerings
 
 # implementation
 
-type 
+type
   PTransNode* = distinct PNode
-  
+
   PTransCon = ref TTransCon
   TTransCon{.final.} = object # part of TContext; stackable
     mapping: TIdNodeTable     # mapping from symbols to nodes
     owner: PSym               # current owner
     forStmt: PNode            # current for stmt
-    forLoopBody: PTransNode   # transformed for loop body 
-    yieldStmts: int           # we count the number of yield statements, 
+    forLoopBody: PTransNode   # transformed for loop body
+    yieldStmts: int           # we count the number of yield statements,
                               # because we need to introduce new variables
                               # if we encounter the 2nd yield statement
     next: PTransCon           # for stacking
-  
+
   TTransfContext = object of passes.TPassContext
     module: PSym
     transCon: PTransCon      # top of a TransCon stack
@@ -46,52 +46,52 @@ type
     contSyms, breakSyms: seq[PSym]  # to transform 'continue' and 'break'
   PTransf = ref TTransfContext
 
-proc newTransNode(a: PNode): PTransNode {.inline.} = 
+proc newTransNode(a: PNode): PTransNode {.inline.} =
   result = PTransNode(shallowCopy(a))
 
-proc newTransNode(kind: TNodeKind, info: TLineInfo, 
-                  sons: int): PTransNode {.inline.} = 
+proc newTransNode(kind: TNodeKind, info: TLineInfo,
+                  sons: int): PTransNode {.inline.} =
   var x = newNodeI(kind, info)
   newSeq(x.sons, sons)
   result = x.PTransNode
 
-proc newTransNode(kind: TNodeKind, n: PNode, 
-                  sons: int): PTransNode {.inline.} = 
+proc newTransNode(kind: TNodeKind, n: PNode,
+                  sons: int): PTransNode {.inline.} =
   var x = newNodeIT(kind, n.info, n.typ)
   newSeq(x.sons, sons)
   x.typ = n.typ
   result = x.PTransNode
 
-proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} = 
+proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
   var n = PNode(a)
   n.sons[i] = PNode(x)
 
-proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} = 
+proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} =
   var n = PNode(a)
   result = n.sons[i].PTransNode
-  
+
 proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
 proc len(a: PTransNode): int {.inline.} = result = sonsLen(a.PNode)
 
-proc newTransCon(owner: PSym): PTransCon = 
+proc newTransCon(owner: PSym): PTransCon =
   assert owner != nil
   new(result)
   initIdNodeTable(result.mapping)
   result.owner = owner
 
-proc pushTransCon(c: PTransf, t: PTransCon) = 
+proc pushTransCon(c: PTransf, t: PTransCon) =
   t.next = c.transCon
   c.transCon = t
 
-proc popTransCon(c: PTransf) = 
+proc popTransCon(c: PTransf) =
   if (c.transCon == nil): internalError("popTransCon")
   c.transCon = c.transCon.next
 
-proc getCurrOwner(c: PTransf): PSym = 
+proc getCurrOwner(c: PTransf): PSym =
   if c.transCon != nil: result = c.transCon.owner
   else: result = c.module
-  
-proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PSym = 
+
+proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PSym =
   result = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c), info)
   result.typ = skipTypes(typ, {tyGenericInst})
   incl(result.flags, sfFromGeneric)
@@ -100,10 +100,10 @@ proc transform(c: PTransf, n: PNode): PTransNode
 
 proc transformSons(c: PTransf, n: PNode): PTransNode =
   result = newTransNode(n)
-  for i in countup(0, sonsLen(n)-1): 
+  for i in countup(0, sonsLen(n)-1):
     result[i] = transform(c, n.sons[i])
 
-proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode = 
+proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
   result = newTransNode(nkFastAsgn, PNode(ri).info, 2)
   result[0] = PTransNode(le)
   result[1] = ri
@@ -113,30 +113,30 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
   #  return liftIterSym(n)
   var b: PNode
   var tc = c.transCon
-  if sfBorrow in n.sym.flags: 
+  if sfBorrow in n.sym.flags:
     # simply exchange the symbol:
     b = n.sym.getBody
     if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol")
     b = newSymNode(b.sym)
     b.info = n.info
-  else: 
+  else:
     b = n
-  while tc != nil: 
+  while tc != nil:
     result = idNodeTableGet(tc.mapping, b.sym)
     if result != nil: return
     tc = tc.next
   result = b
 
-proc transformSym(c: PTransf, n: PNode): PTransNode = 
+proc transformSym(c: PTransf, n: PNode): PTransNode =
   result = PTransNode(transformSymAux(c, n))
 
 proc transformVarSection(c: PTransf, v: PNode): PTransNode =
   result = newTransNode(v)
   for i in countup(0, sonsLen(v)-1):
     var it = v.sons[i]
-    if it.kind == nkCommentStmt: 
+    if it.kind == nkCommentStmt:
       result[i] = PTransNode(it)
-    elif it.kind == nkIdentDefs: 
+    elif it.kind == nkIdentDefs:
       if it.sons[0].kind != nkSym: internalError(it.info, "transformVarSection")
       internalAssert(it.len == 3)
       var newVar = copySym(it.sons[0].sym)
@@ -152,13 +152,14 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode =
       defs[0] = newSymNode(newVar).PTransNode
       defs[1] = it.sons[1].PTransNode
       defs[2] = transform(c, it.sons[2])
+      newVar.ast = defs[2].PNode
       result[i] = defs
-    else: 
-      if it.kind != nkVarTuple: 
+    else:
+      if it.kind != nkVarTuple:
         internalError(it.info, "transformVarSection: not nkVarTuple")
       var L = sonsLen(it)
       var defs = newTransNode(it.kind, it.info, L)
-      for j in countup(0, L-3): 
+      for j in countup(0, L-3):
         var newVar = copySym(it.sons[j].sym)
         incl(newVar.flags, sfFromGeneric)
         newVar.owner = getCurrOwner(c)
@@ -188,12 +189,12 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode =
       else:
         result[i] = PTransNode(it)
 
-proc hasContinue(n: PNode): bool = 
+proc hasContinue(n: PNode): bool =
   case n.kind
   of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: discard
   of nkContinueStmt: result = true
-  else: 
-    for i in countup(0, sonsLen(n) - 1): 
+  else:
+    for i in countup(0, sonsLen(n) - 1):
       if hasContinue(n.sons[i]): return true
 
 proc newLabel(c: PTransf, n: PNode): PSym =
@@ -224,10 +225,10 @@ proc transformBlock(c: PTransf, n: PNode): PTransNode =
   discard c.breakSyms.pop
   result[0] = newSymNode(labl).PTransNode
 
-proc transformLoopBody(c: PTransf, n: PNode): PTransNode =  
-  # What if it contains "continue" and "break"? "break" needs 
+proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
+  # What if it contains "continue" and "break"? "break" needs
   # an explicit label too, but not the same!
-  
+
   # We fix this here by making every 'break' belong to its enclosing loop
   # and changing all breaks that belong to a 'block' by annotating it with
   # a label (if it hasn't one already).
@@ -239,7 +240,7 @@ proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
     result[0] = newSymNode(labl).PTransNode
     result[1] = transform(c, n)
     discard c.contSyms.pop()
-  else: 
+  else:
     result = transform(c, n)
 
 proc transformWhile(c: PTransf; n: PNode): PTransNode =
@@ -273,27 +274,27 @@ proc transformBreak(c: PTransf, n: PNode): PTransNode =
     result = transformSons(c, n)
     result[0] = newSymNode(labl).PTransNode
 
-proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) = 
+proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
   # XXX: BUG: what if `n` is an expression with side-effects?
-  for i in countup(0, sonsLen(c.transCon.forStmt) - 3): 
-    add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i], 
+  for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
+    add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
         transform(c, newTupleAccess(n, i))))
 
-proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode = 
+proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
   case n.kind
-  of nkSym: 
+  of nkSym:
     result = transformSym(c, n)
-  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: 
+  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
     # nothing to be done for leaves:
     result = PTransNode(n)
   of nkVarSection, nkLetSection:
     result = transformVarSection(c, n)
   else:
     result = newTransNode(n)
-    for i in countup(0, sonsLen(n)-1): 
+    for i in countup(0, sonsLen(n)-1):
       result[i] =  introduceNewLocalVars(c, n.sons[i])
 
-proc transformYield(c: PTransf, n: PNode): PTransNode = 
+proc transformYield(c: PTransf, n: PNode): PTransNode =
   result = newTransNode(nkStmtList, n.info, 0)
   var e = n.sons[0]
   # c.transCon.forStmt.len == 3 means that there is one for loop variable
@@ -301,26 +302,27 @@ proc transformYield(c: PTransf, n: PNode): PTransNode =
   if skipTypes(e.typ, {tyGenericInst}).kind == tyTuple and
       c.transCon.forStmt.len != 3:
     e = skipConv(e)
-    if e.kind == nkPar: 
-      for i in countup(0, sonsLen(e) - 1): 
-        add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i], 
+    if e.kind == nkPar:
+      for i in countup(0, sonsLen(e) - 1):
+        add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i],
                                 transform(c, e.sons[i])))
-    else: 
+    else:
       unpackTuple(c, e, result)
-  else: 
+  else:
     var x = transform(c, e)
     add(result, newAsgnStmt(c, c.transCon.forStmt.sons[0], x))
-  
+
   inc(c.transCon.yieldStmts)
   if c.transCon.yieldStmts <= 1:
     # common case
     add(result, c.transCon.forLoopBody)
-  else: 
+  else:
     # we need to introduce new local variables:
     add(result, introduceNewLocalVars(c, c.transCon.forLoopBody.PNode))
 
 proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
   result = transformSons(c, n)
+  if gCmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return
   var n = result.PNode
   case n.sons[0].kind
   of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
@@ -339,25 +341,25 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
     if n.sons[0].kind == a or n.sons[0].kind == b:
       # addr ( deref ( x )) --> x
       result = PTransNode(n.sons[0].sons[0])
-  
-proc transformConv(c: PTransf, n: PNode): PTransNode = 
+
+proc transformConv(c: PTransf, n: PNode): PTransNode =
   # numeric types need range checks:
   var dest = skipTypes(n.typ, abstractVarRange)
   var source = skipTypes(n.sons[1].typ, abstractVarRange)
   case dest.kind
-  of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32: 
+  of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32:
     # we don't include uint and uint64 here as these are no ordinal types ;-)
     if not isOrdinalType(source):
       # float -> int conversions. ugh.
       result = transformSons(c, n)
     elif firstOrd(n.typ) <= firstOrd(n.sons[1].typ) and
-        lastOrd(n.sons[1].typ) <= lastOrd(n.typ): 
+        lastOrd(n.sons[1].typ) <= lastOrd(n.typ):
       # BUGFIX: simply leave n as it is; we need a nkConv node,
       # but no range check:
       result = transformSons(c, n)
-    else: 
+    else:
       # generate a range check:
-      if dest.kind == tyInt64 or source.kind == tyInt64: 
+      if dest.kind == tyInt64 or source.kind == tyInt64:
         result = newTransNode(nkChckRange64, n, 3)
       else:
         result = newTransNode(nkChckRange, n, 3)
@@ -367,7 +369,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
       result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
   of tyFloat..tyFloat128:
     # XXX int64 -> float conversion?
-    if skipTypes(n.typ, abstractVar).kind == tyRange: 
+    if skipTypes(n.typ, abstractVar).kind == tyRange:
       result = newTransNode(nkChckRangeF, n, 3)
       dest = skipTypes(n.typ, abstractVar)
       result[0] = transform(c, n.sons[1])
@@ -377,81 +379,81 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
       result = transformSons(c, n)
   of tyOpenArray, tyVarargs:
     result = transform(c, n.sons[1])
-  of tyCString: 
-    if source.kind == tyString: 
+  of tyCString:
+    if source.kind == tyString:
       result = newTransNode(nkStringToCString, n, 1)
       result[0] = transform(c, n.sons[1])
     else:
       result = transformSons(c, n)
-  of tyString: 
-    if source.kind == tyCString: 
+  of tyString:
+    if source.kind == tyCString:
       result = newTransNode(nkCStringToString, n, 1)
       result[0] = transform(c, n.sons[1])
     else:
       result = transformSons(c, n)
-  of tyRef, tyPtr: 
+  of tyRef, tyPtr:
     dest = skipTypes(dest, abstractPtrs)
     source = skipTypes(source, abstractPtrs)
-    if source.kind == tyObject: 
+    if source.kind == tyObject:
       var diff = inheritanceDiff(dest, source)
-      if diff < 0: 
+      if diff < 0:
         result = newTransNode(nkObjUpConv, n, 1)
         result[0] = transform(c, n.sons[1])
-      elif diff > 0: 
+      elif diff > 0 and diff != high(int):
         result = newTransNode(nkObjDownConv, n, 1)
         result[0] = transform(c, n.sons[1])
-      else: 
+      else:
         result = transform(c, n.sons[1])
     else:
       result = transformSons(c, n)
-  of tyObject: 
+  of tyObject:
     var diff = inheritanceDiff(dest, source)
-    if diff < 0: 
+    if diff < 0:
       result = newTransNode(nkObjUpConv, n, 1)
       result[0] = transform(c, n.sons[1])
-    elif diff > 0: 
+    elif diff > 0 and diff != high(int):
       result = newTransNode(nkObjDownConv, n, 1)
       result[0] = transform(c, n.sons[1])
-    else: 
+    else:
       result = transform(c, n.sons[1])
   of tyGenericParam, tyOrdinal:
     result = transform(c, n.sons[1])
     # happens sometimes for generated assignments, etc.
-  else: 
+  else:
     result = transformSons(c, n)
-  
-type 
-  TPutArgInto = enum 
+
+type
+  TPutArgInto = enum
     paDirectMapping, paFastAsgn, paVarAsgn
 
-proc putArgInto(arg: PNode, formal: PType): TPutArgInto = 
+proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
   # This analyses how to treat the mapping "formal <-> arg" in an
   # inline context.
   if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
     return paDirectMapping    # XXX really correct?
                               # what if ``arg`` has side-effects?
   case arg.kind
-  of nkEmpty..nkNilLit: 
+  of nkEmpty..nkNilLit:
     result = paDirectMapping
-  of nkPar, nkCurly, nkBracket: 
+  of nkPar, nkCurly, nkBracket:
     result = paFastAsgn
-    for i in countup(0, sonsLen(arg) - 1): 
-      if putArgInto(arg.sons[i], formal) != paDirectMapping: return 
+    for i in countup(0, sonsLen(arg) - 1):
+      if putArgInto(arg.sons[i], formal) != paDirectMapping: return
     result = paDirectMapping
-  else: 
+  else:
     if skipTypes(formal, abstractInst).kind == tyVar: result = paVarAsgn
     else: result = paFastAsgn
-  
+
 proc findWrongOwners(c: PTransf, n: PNode) =
   if n.kind == nkVarSection:
     let x = n.sons[0].sons[0]
     if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
-      internalError(x.info, "bah " & x.sym.name.s & " " & 
+      internalError(x.info, "bah " & x.sym.name.s & " " &
         x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
   else:
     for i in 0 .. <safeLen(n): findWrongOwners(c, n.sons[i])
 
-proc transformFor(c: PTransf, n: PNode): PTransNode = 
+proc transformFor(c: PTransf, n: PNode): PTransNode =
   # generate access statements for the parameters (unless they are constant)
   # put mapping from formal parameters to actual parameters
   if n.kind != nkForStmt: internalError(n.info, "transformFor")
@@ -465,38 +467,39 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
   result[0] = newSymNode(labl).PTransNode
 
   if call.typ.kind != tyIter and
-    (call.kind notin nkCallKinds or call.sons[0].kind != nkSym or 
+    (call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
       call.sons[0].sym.kind != skIterator):
     n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
     result[1] = lambdalifting.liftForLoop(n).PTransNode
     discard c.breakSyms.pop
     return result
-  
+
   #echo "transforming: ", renderTree(n)
   var stmtList = newTransNode(nkStmtList, n.info, 0)
-  
+
   var loopBody = transformLoopBody(c, n.sons[length-1])
 
   result[1] = stmtList
   discard c.breakSyms.pop
 
   var v = newNodeI(nkVarSection, n.info)
-  for i in countup(0, length - 3): 
+  for i in countup(0, length - 3):
     addVar(v, copyTree(n.sons[i])) # declare new vars
   add(stmtList, v.PTransNode)
-  
+
   # Bugfix: inlined locals belong to the invoking routine, not to the invoked
   # iterator!
   let iter = call.sons[0].sym
   var newC = newTransCon(getCurrOwner(c))
   newC.forStmt = n
   newC.forLoopBody = loopBody
-  internalAssert iter.kind == skIterator
+  # this can fail for 'nimsuggest' and 'check':
+  if iter.kind != skIterator: return result
   # generate access statements for the parameters (unless they are constant)
   pushTransCon(c, newC)
-  for i in countup(1, sonsLen(call) - 1): 
+  for i in countup(1, sonsLen(call) - 1):
     var arg = transform(c, call.sons[i]).PNode
-    var formal = skipTypes(iter.typ, abstractInst).n.sons[i].sym 
+    var formal = skipTypes(iter.typ, abstractInst).n.sons[i].sym
     if arg.typ.kind == tyIter: continue
     case putArgInto(arg, formal.typ)
     of paDirectMapping:
@@ -525,20 +528,20 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
   popInfoContext()
   popTransCon(c)
   # echo "transformed: ", stmtList.PNode.renderTree
-  
-proc getMagicOp(call: PNode): TMagic = 
+
+proc getMagicOp(call: PNode): TMagic =
   if call.sons[0].kind == nkSym and
-      call.sons[0].sym.kind in {skProc, skMethod, skConverter}: 
+      call.sons[0].sym.kind in {skProc, skMethod, skConverter}:
     result = call.sons[0].sym.magic
   else:
     result = mNone
 
-proc transformCase(c: PTransf, n: PNode): PTransNode = 
+proc transformCase(c: PTransf, n: PNode): PTransNode =
   # removes `elif` branches of a case stmt
   # adds ``else: nil`` if needed for the code generator
   result = newTransNode(nkCaseStmt, n, 0)
   var ifs = PTransNode(nil)
-  for i in 0 .. sonsLen(n)-1: 
+  for i in 0 .. sonsLen(n)-1:
     var it = n.sons[i]
     var e = transform(c, it)
     case it.kind
@@ -562,8 +565,8 @@ proc transformCase(c: PTransf, n: PNode): PTransNode =
     var elseBranch = newTransNode(nkElse, n.info, 1)
     elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
     add(result, elseBranch)
-  
-proc transformArrayAccess(c: PTransf, n: PNode): PTransNode = 
+
+proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
   # XXX this is really bad; transf should use a proper AST visitor
   if n.sons[0].kind == nkSym and n.sons[0].sym.kind == skType:
     result = n.PTransNode
@@ -571,45 +574,44 @@ proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
     result = newTransNode(n)
     for i in 0 .. < n.len:
       result[i] = transform(c, skipConv(n.sons[i]))
-  
-proc getMergeOp(n: PNode): PSym = 
+
+proc getMergeOp(n: PNode): PSym =
   case n.kind
-  of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix, 
-     nkCallStrLit: 
-    if (n.sons[0].kind == nkSym) and (n.sons[0].sym.kind == skProc) and
-        (sfMerge in n.sons[0].sym.flags): 
+  of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
+     nkCallStrLit:
+    if n.sons[0].kind == nkSym and n.sons[0].sym.magic == mConStrStr:
       result = n.sons[0].sym
   else: discard
 
-proc flattenTreeAux(d, a: PNode, op: PSym) = 
+proc flattenTreeAux(d, a: PNode, op: PSym) =
   let op2 = getMergeOp(a)
   if op2 != nil and
-      (op2.id == op.id or op.magic != mNone and op2.magic == op.magic): 
+      (op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
     for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op)
-  else: 
+  else:
     addSon(d, copyTree(a))
-  
-proc flattenTree(root: PNode): PNode = 
+
+proc flattenTree(root: PNode): PNode =
   let op = getMergeOp(root)
-  if op != nil: 
+  if op != nil:
     result = copyNode(root)
     addSon(result, copyTree(root.sons[0]))
     flattenTreeAux(result, root, op)
-  else: 
+  else:
     result = root
 
-proc transformCall(c: PTransf, n: PNode): PTransNode = 
+proc transformCall(c: PTransf, n: PNode): PTransNode =
   var n = flattenTree(n)
   let op = getMergeOp(n)
   let magic = getMagic(n)
-  if op != nil and op.magic != mNone and n.len >= 3: 
+  if op != nil and op.magic != mNone and n.len >= 3:
     result = newTransNode(nkCall, n, 0)
     add(result, transform(c, n.sons[0]))
     var j = 1
-    while j < sonsLen(n): 
+    while j < sonsLen(n):
       var a = transform(c, n.sons[j]).PNode
       inc(j)
-      if isConstExpr(a): 
+      if isConstExpr(a):
         while (j < sonsLen(n)):
           let b = transform(c, n.sons[j]).PNode
           if not isConstExpr(b): break
@@ -638,7 +640,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
 proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
   # symbols that expand to a complex constant (array, etc.) should not be
   # inlined, unless it's the empty array:
-  result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkBracket} and 
+  result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkBracket} and
       cnst.len != 0
 
 proc commonOptimizations*(c: PSym, n: PNode): PNode =
@@ -671,11 +673,11 @@ proc commonOptimizations*(c: PSym, n: PNode): PNode =
     else:
       result = n
 
-proc transform(c: PTransf, n: PNode): PTransNode = 
+proc transform(c: PTransf, n: PNode): PTransNode =
   case n.kind
-  of nkSym: 
+  of nkSym:
     result = transformSym(c, n)
-  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: 
+  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
     # nothing to be done for leaves:
     result = PTransNode(n)
   of nkBracketExpr: result = transformArrayAccess(c, n)
@@ -700,7 +702,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
         n.sons[bodyPos] = PNode(transform(c, s.getBody))
         if n.kind == nkMethodDef: methodDef(s, false)
     result = PTransNode(n)
-  of nkForStmt: 
+  of nkForStmt:
     result = transformFor(c, n)
   of nkParForStmt:
     result = transformSons(c, n)
@@ -711,14 +713,14 @@ proc transform(c: PTransf, n: PNode): PTransNode =
     add(result, PTransNode(newSymNode(labl)))
   of nkBreakStmt: result = transformBreak(c, n)
   of nkWhileStmt: result = transformWhile(c, n)
-  of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix, 
-     nkCallStrLit: 
+  of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
+     nkCallStrLit:
     result = transformCall(c, n)
-  of nkAddr, nkHiddenAddr: 
+  of nkAddr, nkHiddenAddr:
     result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
-  of nkDerefExpr, nkHiddenDeref: 
+  of nkDerefExpr, nkHiddenDeref:
     result = transformAddrDeref(c, n, nkAddr, nkHiddenAddr)
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv: 
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
     result = transformConv(c, n)
   of nkDiscardStmt:
     result = PTransNode(n)
@@ -728,7 +730,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
         # ensure that e.g. discard "some comment" gets optimized away
         # completely:
         result = PTransNode(newNode(nkCommentStmt))
-  of nkCommentStmt, nkTemplateDef: 
+  of nkCommentStmt, nkTemplateDef:
     return n.PTransNode
   of nkConstSection:
     # do not replace ``const c = 3`` with ``const 3 = 3``
@@ -742,10 +744,10 @@ proc transform(c: PTransf, n: PNode): PTransNode =
       result = transformVarSection(c, n)
     else:
       result = transformSons(c, n)
-  of nkYieldStmt: 
+  of nkYieldStmt:
     if c.inlining > 0:
       result = transformYield(c, n)
-    else: 
+    else:
       result = transformSons(c, n)
   of nkBlockStmt, nkBlockExpr:
     result = transformBlock(c, n)
@@ -762,7 +764,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
   if cnst != nil and not dontInlineConstant(n, cnst):
     result = PTransNode(cnst) # do not miss an optimization
 
-proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode = 
+proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
   # Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
   # this step! We have to rely that the semantic pass transforms too errornous
   # nodes into an empty node.
@@ -772,7 +774,7 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
   popTransCon(c)
   incl(result.flags, nfTransf)
 
-proc openTransf(module: PSym, filename: string): PTransf = 
+proc openTransf(module: PSym, filename: string): PTransf =
   new(result)
   result.contSyms = @[]
   result.breakSyms = @[]
diff --git a/compiler/trees.nim b/compiler/trees.nim
index 86a1139a0..2c631af99 100644
--- a/compiler/trees.nim
+++ b/compiler/trees.nim
@@ -9,40 +9,40 @@
 
 # tree helper routines
 
-import 
+import
   ast, astalgo, lexer, msgs, strutils, wordrecg
 
-proc hasSon(father, son: PNode): bool = 
-  for i in countup(0, sonsLen(father) - 1): 
-    if father.sons[i] == son: 
+proc hasSon(father, son: PNode): bool =
+  for i in countup(0, sonsLen(father) - 1):
+    if father.sons[i] == son:
       return true
   result = false
 
-proc cyclicTreeAux(n, s: PNode): bool = 
-  if n == nil: 
+proc cyclicTreeAux(n, s: PNode): bool =
+  if n == nil:
     return false
-  if hasSon(s, n): 
+  if hasSon(s, n):
     return true
   var m = sonsLen(s)
   addSon(s, n)
-  if not (n.kind in {nkEmpty..nkNilLit}): 
-    for i in countup(0, sonsLen(n) - 1): 
-      if cyclicTreeAux(n.sons[i], s): 
+  if not (n.kind in {nkEmpty..nkNilLit}):
+    for i in countup(0, sonsLen(n) - 1):
+      if cyclicTreeAux(n.sons[i], s):
         return true
   result = false
   delSon(s, m)
 
-proc cyclicTree*(n: PNode): bool = 
+proc cyclicTree*(n: PNode): bool =
   var s = newNodeI(nkEmpty, n.info)
   result = cyclicTreeAux(n, s)
 
-proc exprStructuralEquivalent*(a, b: PNode): bool = 
+proc exprStructuralEquivalent*(a, b: PNode): bool =
   result = false
-  if a == b: 
+  if a == b:
     result = true
-  elif (a != nil) and (b != nil) and (a.kind == b.kind): 
+  elif (a != nil) and (b != nil) and (a.kind == b.kind):
     case a.kind
-    of nkSym: 
+    of nkSym:
       # don't go nuts here: same symbol as string is enough:
       result = a.sym.name.id == b.sym.name.id
     of nkIdent: result = a.ident.id == b.ident.id
@@ -50,12 +50,12 @@ proc exprStructuralEquivalent*(a, b: PNode): bool =
     of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
     of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
     of nkEmpty, nkNilLit, nkType: result = true
-    else: 
-      if sonsLen(a) == sonsLen(b): 
-        for i in countup(0, sonsLen(a) - 1): 
-          if not exprStructuralEquivalent(a.sons[i], b.sons[i]): return 
+    else:
+      if sonsLen(a) == sonsLen(b):
+        for i in countup(0, sonsLen(a) - 1):
+          if not exprStructuralEquivalent(a.sons[i], b.sons[i]): return
         result = true
-  
+
 proc sameTree*(a, b: PNode): bool =
   result = false
   if a == b:
@@ -66,7 +66,7 @@ proc sameTree*(a, b: PNode): bool =
     if a.info.col != b.info.col:
       return                  #if a.info.fileIndex <> b.info.fileIndex then exit;
     case a.kind
-    of nkSym: 
+    of nkSym:
       # don't go nuts here: same symbol as string is enough:
       result = a.sym.name.id == b.sym.name.id
     of nkIdent: result = a.ident.id == b.ident.id
@@ -75,15 +75,15 @@ proc sameTree*(a, b: PNode): bool =
     of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
     of nkEmpty, nkNilLit, nkType: result = true
     else:
-      if sonsLen(a) == sonsLen(b): 
-        for i in countup(0, sonsLen(a) - 1): 
-          if not sameTree(a.sons[i], b.sons[i]): return 
+      if sonsLen(a) == sonsLen(b):
+        for i in countup(0, sonsLen(a) - 1):
+          if not sameTree(a.sons[i], b.sons[i]): return
         result = true
-  
-proc getProcSym*(call: PNode): PSym = 
+
+proc getProcSym*(call: PNode): PSym =
   result = call.sons[0].sym
 
-proc getOpSym*(op: PNode): PSym = 
+proc getOpSym*(op: PNode): PSym =
   if op.kind notin {nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit}:
     result = nil
   else:
@@ -91,25 +91,25 @@ proc getOpSym*(op: PNode): PSym =
     elif op.sons[0].kind == nkSym: result = op.sons[0].sym
     else: result = nil
 
-proc getMagic*(op: PNode): TMagic = 
+proc getMagic*(op: PNode): TMagic =
   case op.kind
   of nkCallKinds:
     case op.sons[0].kind
     of nkSym: result = op.sons[0].sym.magic
     else: result = mNone
   else: result = mNone
-  
-proc treeToSym*(t: PNode): PSym = 
+
+proc treeToSym*(t: PNode): PSym =
   result = t.sym
 
-proc isConstExpr*(n: PNode): bool = 
+proc isConstExpr*(n: PNode): bool =
   result = (n.kind in
-      {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit, 
+      {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
        nkFloatLit..nkFloat64Lit, nkNilLit}) or (nfAllConst in n.flags)
 
 proc isDeepConstExpr*(n: PNode): bool =
   case n.kind
-  of nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit, 
+  of nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
       nkFloatLit..nkFloat64Lit, nkNilLit:
     result = true
   of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
@@ -122,33 +122,33 @@ proc isDeepConstExpr*(n: PNode): bool =
     result = n.typ.isNil or n.typ.skipTypes({tyGenericInst, tyDistinct}).kind != tyObject
   else: discard
 
-proc flattenTreeAux(d, a: PNode, op: TMagic) = 
+proc flattenTreeAux(d, a: PNode, op: TMagic) =
   if (getMagic(a) == op):     # a is a "leaf", so add it:
     for i in countup(1, sonsLen(a) - 1): # BUGFIX
       flattenTreeAux(d, a.sons[i], op)
-  else: 
+  else:
     addSon(d, copyTree(a))
-  
-proc flattenTree*(root: PNode, op: TMagic): PNode = 
+
+proc flattenTree*(root: PNode, op: TMagic): PNode =
   result = copyNode(root)
   if getMagic(root) == op:
     # BUGFIX: forget to copy prc
     addSon(result, copyNode(root.sons[0]))
     flattenTreeAux(result, root, op)
 
-proc swapOperands*(op: PNode) = 
+proc swapOperands*(op: PNode) =
   var tmp = op.sons[1]
   op.sons[1] = op.sons[2]
   op.sons[2] = tmp
 
-proc isRange*(n: PNode): bool {.inline.} = 
-  if n.kind == nkInfix:
+proc isRange*(n: PNode): bool {.inline.} =
+  if n.kind in nkCallKinds:
     if n[0].kind == nkIdent and n[0].ident.id == ord(wDotDot) or
-        n[0].kind in {nkClosedSymChoice, nkOpenSymChoice} and 
+        n[0].kind in {nkClosedSymChoice, nkOpenSymChoice} and
         n[0][1].sym.name.id == ord(wDotDot):
       result = true
 
-proc whichPragma*(n: PNode): TSpecialWord = 
+proc whichPragma*(n: PNode): TSpecialWord =
   let key = if n.kind == nkExprColonExpr: n.sons[0] else: n
   if key.kind == nkIdent: result = whichKeyword(key.ident)
 
diff --git a/compiler/treetab.nim b/compiler/treetab.nim
index 63f3fc6e2..8d66d56c7 100644
--- a/compiler/treetab.nim
+++ b/compiler/treetab.nim
@@ -28,8 +28,9 @@ proc hashTree(n: PNode): THash =
   of nkFloatLit..nkFloat64Lit:
     if (n.floatVal >= - 1000000.0) and (n.floatVal <= 1000000.0): 
       result = result !& toInt(n.floatVal)
-  of nkStrLit..nkTripleStrLit: 
-    result = result !& hash(n.strVal)
+  of nkStrLit..nkTripleStrLit:
+    if not n.strVal.isNil:
+      result = result !& hash(n.strVal)
   else: 
     for i in countup(0, sonsLen(n) - 1): 
       result = result !& hashTree(n.sons[i])
diff --git a/compiler/types.nim b/compiler/types.nim
index 87f2e1a59..7f05e7051 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -9,20 +9,20 @@
 
 # this module contains routines for accessing and iterating over types
 
-import 
+import
   intsets, ast, astalgo, trees, msgs, strutils, platform, renderer
 
 proc firstOrd*(t: PType): BiggestInt
 proc lastOrd*(t: PType): BiggestInt
 proc lengthOrd*(t: PType): BiggestInt
-type 
+type
   TPreferedDesc* = enum
-    preferName, preferDesc, preferExported, preferModuleInfo
+    preferName, preferDesc, preferExported, preferModuleInfo, preferGenericArg
 
 proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string
 proc base*(t: PType): PType
   # ------------------- type iterator: ----------------------------------------
-type 
+type
   TTypeIter* = proc (t: PType, closure: RootRef): bool {.nimcall.} # true if iteration should stop
   TTypeMutator* = proc (t: PType, closure: RootRef): PType {.nimcall.} # copy t and mutate it
   TTypePredicate* = proc (t: PType): bool {.nimcall.}
@@ -32,7 +32,7 @@ proc iterOverType*(t: PType, iter: TTypeIter, closure: RootRef): bool
 proc mutateType*(t: PType, iter: TTypeMutator, closure: RootRef): PType
   # Returns result of `iter`.
 
-type 
+type
   TParamsEquality* = enum     # they are equal, but their
                               # identifiers or their return
                               # type differ (i.e. they cannot be
@@ -59,7 +59,7 @@ const
   abstractInst* = {tyGenericInst, tyDistinct, tyConst, tyMutable, tyOrdinal,
                    tyTypeDesc}
 
-  skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable, 
+  skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable,
                tyTypeDesc}
   typedescPtrs* = abstractPtrs + {tyTypeDesc}
   typedescInst* = abstractInst + {tyTypeDesc}
@@ -75,9 +75,9 @@ proc getSize*(typ: PType): BiggestInt
 proc isPureObject*(typ: PType): bool
 proc invalidGenericInst*(f: PType): bool
   # for debugging
-type 
-  TTypeFieldResult* = enum 
-    frNone,                   # type has no object type field 
+type
+  TTypeFieldResult* = enum
+    frNone,                   # type has no object type field
     frHeader,                 # type has an object type field only in the header
     frEmbedded                # type has an object type field somewhere embedded
 
@@ -85,18 +85,16 @@ proc analyseObjectWithTypeField*(t: PType): TTypeFieldResult
   # this does a complex analysis whether a call to ``objectInit`` needs to be
   # made or intializing of the type field suffices or if there is no type field
   # at all in this type.
-proc typeAllowed*(t: PType, kind: TSymKind): bool
-# implementation
 
-proc invalidGenericInst(f: PType): bool = 
+proc invalidGenericInst(f: PType): bool =
   result = f.kind == tyGenericInst and lastSon(f) == nil
 
-proc isPureObject(typ: PType): bool = 
+proc isPureObject(typ: PType): bool =
   var t = typ
   while t.kind == tyObject and t.sons[0] != nil: t = t.sons[0]
   result = t.sym != nil and sfPure in t.sym.flags
 
-proc getOrdValue(n: PNode): BiggestInt = 
+proc getOrdValue(n: PNode): BiggestInt =
   case n.kind
   of nkCharLit..nkUInt64Lit: result = n.intVal
   of nkNilLit: result = 0
@@ -111,21 +109,21 @@ proc isIntLit*(t: PType): bool {.inline.} =
 proc isFloatLit*(t: PType): bool {.inline.} =
   result = t.kind == tyFloat and t.n != nil and t.n.kind == nkFloatLit
 
-proc isCompatibleToCString(a: PType): bool = 
-  if a.kind == tyArray: 
+proc isCompatibleToCString(a: PType): bool =
+  if a.kind == tyArray:
     if (firstOrd(a.sons[0]) == 0) and
-        (skipTypes(a.sons[0], {tyRange, tyConst, 
-                               tyMutable, tyGenericInst}).kind in 
+        (skipTypes(a.sons[0], {tyRange, tyConst,
+                               tyMutable, tyGenericInst}).kind in
             {tyInt..tyInt64, tyUInt..tyUInt64}) and
-        (a.sons[1].kind == tyChar): 
+        (a.sons[1].kind == tyChar):
       result = true
-  
-proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string = 
+
+proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string =
   result = sym.owner.name.s & '.' & sym.name.s & '('
   var n = sym.typ.n
-  for i in countup(1, sonsLen(n) - 1): 
+  for i in countup(1, sonsLen(n) - 1):
     var p = n.sons[i]
-    if p.kind == nkSym: 
+    if p.kind == nkSym:
       add(result, p.sym.name.s)
       add(result, ": ")
       add(result, typeToString(p.sym.typ, prefer))
@@ -136,18 +134,18 @@ proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string =
   if n.sons[0].typ != nil:
     result.add(": " & typeToString(n.sons[0].typ, prefer))
 
-proc elemType*(t: PType): PType = 
+proc elemType*(t: PType): PType =
   assert(t != nil)
   case t.kind
   of tyGenericInst, tyDistinct: result = elemType(lastSon(t))
   of tyArray, tyArrayConstr: result = t.sons[1]
-  else: result = t.sons[0]
+  else: result = t.lastSon
   assert(result != nil)
 
-proc skipGeneric(t: PType): PType = 
+proc skipGeneric(t: PType): PType =
   result = t
   while result.kind == tyGenericInst: result = lastSon(result)
-      
+
 proc isOrdinalType(t: PType): bool =
   assert(t != nil)
   # caution: uint, uint64 are no ordinal types!
@@ -155,134 +153,134 @@ proc isOrdinalType(t: PType): bool =
       (t.kind in {tyRange, tyOrdinal, tyConst, tyMutable, tyGenericInst}) and
        isOrdinalType(t.sons[0])
 
-proc enumHasHoles(t: PType): bool = 
+proc enumHasHoles(t: PType): bool =
   var b = t
   while b.kind in {tyConst, tyMutable, tyRange, tyGenericInst}: b = b.sons[0]
   result = b.kind == tyEnum and tfEnumHasHoles in b.flags
 
-proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, 
+proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter,
                      closure: RootRef): bool
-proc iterOverNode(marker: var IntSet, n: PNode, iter: TTypeIter, 
-                  closure: RootRef): bool = 
-  if n != nil: 
+proc iterOverNode(marker: var IntSet, n: PNode, iter: TTypeIter,
+                  closure: RootRef): bool =
+  if n != nil:
     case n.kind
-    of nkNone..nkNilLit: 
+    of nkNone..nkNilLit:
       # a leaf
       result = iterOverTypeAux(marker, n.typ, iter, closure)
-    else: 
-      for i in countup(0, sonsLen(n) - 1): 
+    else:
+      for i in countup(0, sonsLen(n) - 1):
         result = iterOverNode(marker, n.sons[i], iter, closure)
-        if result: return 
-  
-proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, 
-                     closure: RootRef): bool = 
+        if result: return
+
+proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter,
+                     closure: RootRef): bool =
   result = false
-  if t == nil: return 
+  if t == nil: return
   result = iter(t, closure)
-  if result: return 
-  if not containsOrIncl(marker, t.id): 
+  if result: return
+  if not containsOrIncl(marker, t.id):
     case t.kind
-    of tyGenericInst, tyGenericBody: 
+    of tyGenericInst, tyGenericBody:
       result = iterOverTypeAux(marker, lastSon(t), iter, closure)
-    else: 
-      for i in countup(0, sonsLen(t) - 1): 
+    else:
+      for i in countup(0, sonsLen(t) - 1):
         result = iterOverTypeAux(marker, t.sons[i], iter, closure)
-        if result: return 
+        if result: return
       if t.n != nil: result = iterOverNode(marker, t.n, iter, closure)
-  
-proc iterOverType(t: PType, iter: TTypeIter, closure: RootRef): bool = 
+
+proc iterOverType(t: PType, iter: TTypeIter, closure: RootRef): bool =
   var marker = initIntSet()
   result = iterOverTypeAux(marker, t, iter, closure)
 
-proc searchTypeForAux(t: PType, predicate: TTypePredicate, 
+proc searchTypeForAux(t: PType, predicate: TTypePredicate,
                       marker: var IntSet): bool
 
-proc searchTypeNodeForAux(n: PNode, p: TTypePredicate, 
-                          marker: var IntSet): bool = 
+proc searchTypeNodeForAux(n: PNode, p: TTypePredicate,
+                          marker: var IntSet): bool =
   result = false
   case n.kind
-  of nkRecList: 
-    for i in countup(0, sonsLen(n) - 1): 
+  of nkRecList:
+    for i in countup(0, sonsLen(n) - 1):
       result = searchTypeNodeForAux(n.sons[i], p, marker)
-      if result: return 
-  of nkRecCase: 
+      if result: return
+  of nkRecCase:
     assert(n.sons[0].kind == nkSym)
     result = searchTypeNodeForAux(n.sons[0], p, marker)
-    if result: return 
-    for i in countup(1, sonsLen(n) - 1): 
+    if result: return
+    for i in countup(1, sonsLen(n) - 1):
       case n.sons[i].kind
-      of nkOfBranch, nkElse: 
+      of nkOfBranch, nkElse:
         result = searchTypeNodeForAux(lastSon(n.sons[i]), p, marker)
-        if result: return 
+        if result: return
       else: internalError("searchTypeNodeForAux(record case branch)")
-  of nkSym: 
+  of nkSym:
     result = searchTypeForAux(n.sym.typ, p, marker)
   else: internalError(n.info, "searchTypeNodeForAux()")
-  
-proc searchTypeForAux(t: PType, predicate: TTypePredicate, 
-                      marker: var IntSet): bool = 
+
+proc searchTypeForAux(t: PType, predicate: TTypePredicate,
+                      marker: var IntSet): bool =
   # iterates over VALUE types!
   result = false
-  if t == nil: return 
-  if containsOrIncl(marker, t.id): return 
+  if t == nil: return
+  if containsOrIncl(marker, t.id): return
   result = predicate(t)
-  if result: return 
+  if result: return
   case t.kind
-  of tyObject: 
+  of tyObject:
     result = searchTypeForAux(t.sons[0], predicate, marker)
     if not result: result = searchTypeNodeForAux(t.n, predicate, marker)
-  of tyGenericInst, tyDistinct: 
+  of tyGenericInst, tyDistinct:
     result = searchTypeForAux(lastSon(t), predicate, marker)
-  of tyArray, tyArrayConstr, tySet, tyTuple: 
-    for i in countup(0, sonsLen(t) - 1): 
+  of tyArray, tyArrayConstr, tySet, tyTuple:
+    for i in countup(0, sonsLen(t) - 1):
       result = searchTypeForAux(t.sons[i], predicate, marker)
-      if result: return 
-  else: 
+      if result: return
+  else:
     discard
 
-proc searchTypeFor(t: PType, predicate: TTypePredicate): bool = 
+proc searchTypeFor(t: PType, predicate: TTypePredicate): bool =
   var marker = initIntSet()
   result = searchTypeForAux(t, predicate, marker)
 
-proc isObjectPredicate(t: PType): bool = 
+proc isObjectPredicate(t: PType): bool =
   result = t.kind == tyObject
 
-proc containsObject(t: PType): bool = 
+proc containsObject(t: PType): bool =
   result = searchTypeFor(t, isObjectPredicate)
 
-proc isObjectWithTypeFieldPredicate(t: PType): bool = 
+proc isObjectWithTypeFieldPredicate(t: PType): bool =
   result = t.kind == tyObject and t.sons[0] == nil and
-      not (t.sym != nil and sfPure in t.sym.flags) and
+      not (t.sym != nil and {sfPure, sfInfixCall} * t.sym.flags != {}) and
       tfFinal notin t.flags
 
-proc analyseObjectWithTypeFieldAux(t: PType, 
-                                   marker: var IntSet): TTypeFieldResult = 
+proc analyseObjectWithTypeFieldAux(t: PType,
+                                   marker: var IntSet): TTypeFieldResult =
   var res: TTypeFieldResult
   result = frNone
-  if t == nil: return 
+  if t == nil: return
   case t.kind
-  of tyObject: 
-    if (t.n != nil): 
-      if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker): 
+  of tyObject:
+    if (t.n != nil):
+      if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker):
         return frEmbedded
-    for i in countup(0, sonsLen(t) - 1): 
+    for i in countup(0, sonsLen(t) - 1):
       res = analyseObjectWithTypeFieldAux(t.sons[i], marker)
-      if res == frEmbedded: 
+      if res == frEmbedded:
         return frEmbedded
       if res == frHeader: result = frHeader
-    if result == frNone: 
+    if result == frNone:
       if isObjectWithTypeFieldPredicate(t): result = frHeader
-  of tyGenericInst, tyDistinct, tyConst, tyMutable: 
+  of tyGenericInst, tyDistinct, tyConst, tyMutable:
     result = analyseObjectWithTypeFieldAux(lastSon(t), marker)
-  of tyArray, tyArrayConstr, tyTuple: 
-    for i in countup(0, sonsLen(t) - 1): 
+  of tyArray, tyArrayConstr, tyTuple:
+    for i in countup(0, sonsLen(t) - 1):
       res = analyseObjectWithTypeFieldAux(t.sons[i], marker)
-      if res != frNone: 
+      if res != frNone:
         return frEmbedded
-  else: 
+  else:
     discard
 
-proc analyseObjectWithTypeField(t: PType): TTypeFieldResult = 
+proc analyseObjectWithTypeField(t: PType): TTypeFieldResult =
   var marker = initIntSet()
   result = analyseObjectWithTypeFieldAux(t, marker)
 
@@ -290,7 +288,7 @@ proc isGCRef(t: PType): bool =
   result = t.kind in GcTypeKinds or
     (t.kind == tyProc and t.callConv == ccClosure)
 
-proc containsGarbageCollectedRef(typ: PType): bool = 
+proc containsGarbageCollectedRef(typ: PType): bool =
   # returns true if typ contains a reference, sequence or string (all the
   # things that are garbage-collected)
   result = searchTypeFor(typ, isGCRef)
@@ -298,47 +296,47 @@ proc containsGarbageCollectedRef(typ: PType): bool =
 proc isTyRef(t: PType): bool =
   result = t.kind == tyRef or (t.kind == tyProc and t.callConv == ccClosure)
 
-proc containsTyRef*(typ: PType): bool = 
+proc containsTyRef*(typ: PType): bool =
   # returns true if typ contains a 'ref'
   result = searchTypeFor(typ, isTyRef)
 
-proc isHiddenPointer(t: PType): bool = 
+proc isHiddenPointer(t: PType): bool =
   result = t.kind in {tyString, tySequence}
 
-proc containsHiddenPointer(typ: PType): bool = 
+proc containsHiddenPointer(typ: PType): bool =
   # returns true if typ contains a string, table or sequence (all the things
   # that need to be copied deeply)
   result = searchTypeFor(typ, isHiddenPointer)
 
 proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool
-proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool = 
+proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool =
   result = false
-  if n != nil: 
+  if n != nil:
     result = canFormAcycleAux(marker, n.typ, startId)
-    if not result: 
+    if not result:
       case n.kind
-      of nkNone..nkNilLit: 
+      of nkNone..nkNilLit:
         discard
-      else: 
-        for i in countup(0, sonsLen(n) - 1): 
+      else:
+        for i in countup(0, sonsLen(n) - 1):
           result = canFormAcycleNode(marker, n.sons[i], startId)
-          if result: return 
-  
-proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool = 
+          if result: return
+
+proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool =
   result = false
-  if typ == nil: return 
-  if tfAcyclic in typ.flags: return 
+  if typ == nil: return
+  if tfAcyclic in typ.flags: return
   var t = skipTypes(typ, abstractInst-{tyTypeDesc})
-  if tfAcyclic in t.flags: return 
+  if tfAcyclic in t.flags: return
   case t.kind
   of tyTuple, tyObject, tyRef, tySequence, tyArray, tyArrayConstr, tyOpenArray,
      tyVarargs:
-    if not containsOrIncl(marker, t.id): 
-      for i in countup(0, sonsLen(t) - 1): 
+    if not containsOrIncl(marker, t.id):
+      for i in countup(0, sonsLen(t) - 1):
         result = canFormAcycleAux(marker, t.sons[i], startId)
-        if result: return 
+        if result: return
       if t.n != nil: result = canFormAcycleNode(marker, t.n, startId)
-    else: 
+    else:
       result = t.id == startId
     # Inheritance can introduce cyclic types, however this is not relevant
     # as the type that is passed to 'new' is statically known!
@@ -353,29 +351,29 @@ proc canFormAcycle(typ: PType): bool =
   var marker = initIntSet()
   result = canFormAcycleAux(marker, typ, typ.id)
 
-proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator, 
+proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator,
                    closure: RootRef): PType
-proc mutateNode(marker: var IntSet, n: PNode, iter: TTypeMutator, 
-                closure: RootRef): PNode = 
+proc mutateNode(marker: var IntSet, n: PNode, iter: TTypeMutator,
+                closure: RootRef): PNode =
   result = nil
-  if n != nil: 
+  if n != nil:
     result = copyNode(n)
     result.typ = mutateTypeAux(marker, n.typ, iter, closure)
     case n.kind
-    of nkNone..nkNilLit: 
+    of nkNone..nkNilLit:
       # a leaf
       discard
-    else: 
-      for i in countup(0, sonsLen(n) - 1): 
+    else:
+      for i in countup(0, sonsLen(n) - 1):
         addSon(result, mutateNode(marker, n.sons[i], iter, closure))
-  
-proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator, 
-                   closure: RootRef): PType = 
+
+proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator,
+                   closure: RootRef): PType =
   result = nil
-  if t == nil: return 
+  if t == nil: return
   result = iter(t, closure)
-  if not containsOrIncl(marker, t.id): 
-    for i in countup(0, sonsLen(t) - 1): 
+  if not containsOrIncl(marker, t.id):
+    for i in countup(0, sonsLen(t) - 1):
       result.sons[i] = mutateTypeAux(marker, result.sons[i], iter, closure)
     if t.n != nil: result.n = mutateNode(marker, t.n, iter, closure)
   assert(result != nil)
@@ -395,10 +393,10 @@ proc rangeToStr(n: PNode): string =
   assert(n.kind == nkRange)
   result = valueToString(n.sons[0]) & ".." & valueToString(n.sons[1])
 
-const 
+const
   typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty",
     "Array Constructor [$1]", "nil", "expr", "stmt", "typeDesc",
-    "GenericInvokation", "GenericBody", "GenericInst", "GenericParam",
+    "GenericInvocation", "GenericBody", "GenericInst", "GenericParam",
     "distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple",
     "set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc",
     "pointer", "OpenArray[$1]", "string", "CString", "Forward",
@@ -411,11 +409,13 @@ const
     "UserTypeClassInst", "CompositeTypeClass",
     "and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor"]
 
+const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg}
+
 proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
   var t = typ
   result = ""
-  if t == nil: return 
-  if prefer in {preferName, preferModuleInfo} and t.sym != nil and
+  if t == nil: return
+  if prefer in preferToResolveSymbols and t.sym != nil and
        sfAnon notin t.sym.flags:
     if t.kind == tyInt and isIntLit(t):
       return t.sym.name.s & " literal(" & $t.n.intVal & ")"
@@ -428,20 +428,26 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
     if not isIntLit(t) or prefer == preferExported:
       result = typeToStr[t.kind]
     else:
-      result = "int literal(" & $t.n.intVal & ")"
-  of tyGenericBody, tyGenericInst, tyGenericInvokation:
+      if prefer == preferGenericArg:
+        result = $t.n.intVal
+      else:
+        result = "int literal(" & $t.n.intVal & ")"
+  of tyGenericBody, tyGenericInst, tyGenericInvocation:
     result = typeToString(t.sons[0]) & '['
-    for i in countup(1, sonsLen(t) -1 -ord(t.kind != tyGenericInvokation)):
+    for i in countup(1, sonsLen(t)-1-ord(t.kind != tyGenericInvocation)):
       if i > 1: add(result, ", ")
-      add(result, typeToString(t.sons[i]))
+      add(result, typeToString(t.sons[i], preferGenericArg))
     add(result, ']')
   of tyTypeDesc:
     if t.base.kind == tyNone: result = "typedesc"
     else: result = "typedesc[" & typeToString(t.base) & "]"
   of tyStatic:
     internalAssert t.len > 0
-    result = "static[" & typeToString(t.sons[0]) & "]"
-    if t.n != nil: result.add "(" & renderTree(t.n) & ")"
+    if prefer == preferGenericArg and t.n != nil:
+      result = t.n.renderTree
+    else:
+      result = "static[" & typeToString(t.sons[0]) & "]"
+      if t.n != nil: result.add "(" & renderTree(t.n) & ")"
   of tyUserTypeClass:
     internalAssert t.sym != nil and t.sym.owner != nil
     return t.sym.owner.name.s
@@ -478,47 +484,51 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
     result = "expr"
   of tyFromExpr, tyFieldAccessor:
     result = renderTree(t.n)
-  of tyArray: 
-    if t.sons[0].kind == tyRange: 
+  of tyArray:
+    if t.sons[0].kind == tyRange:
       result = "array[" & rangeToStr(t.sons[0].n) & ", " &
           typeToString(t.sons[1]) & ']'
-    else: 
+    else:
       result = "array[" & typeToString(t.sons[0]) & ", " &
           typeToString(t.sons[1]) & ']'
-  of tyArrayConstr: 
+  of tyArrayConstr:
     result = "Array constructor[" & rangeToStr(t.sons[0].n) & ", " &
         typeToString(t.sons[1]) & ']'
-  of tySequence: 
+  of tySequence:
     result = "seq[" & typeToString(t.sons[0]) & ']'
-  of tyOrdinal: 
+  of tyOrdinal:
     result = "ordinal[" & typeToString(t.sons[0]) & ']'
-  of tySet: 
+  of tySet:
     result = "set[" & typeToString(t.sons[0]) & ']'
-  of tyOpenArray: 
+  of tyOpenArray:
     result = "openarray[" & typeToString(t.sons[0]) & ']'
   of tyDistinct:
     result = "distinct " & typeToString(t.sons[0],
       if prefer == preferModuleInfo: preferModuleInfo else: preferName)
-  of tyTuple: 
+  of tyTuple:
     # we iterate over t.sons here, because t.n may be nil
-    result = "tuple["
-    if t.n != nil: 
+    if t.n != nil:
+      result = "tuple["
       assert(sonsLen(t.n) == sonsLen(t))
-      for i in countup(0, sonsLen(t.n) - 1): 
+      for i in countup(0, sonsLen(t.n) - 1):
         assert(t.n.sons[i].kind == nkSym)
         add(result, t.n.sons[i].sym.name.s & ": " & typeToString(t.sons[i]))
         if i < sonsLen(t.n) - 1: add(result, ", ")
-    else: 
-      for i in countup(0, sonsLen(t) - 1): 
+      add(result, ']')
+    elif sonsLen(t) == 0:
+      result = "tuple[]"
+    else:
+      result = "("
+      for i in countup(0, sonsLen(t) - 1):
         add(result, typeToString(t.sons[i]))
         if i < sonsLen(t) - 1: add(result, ", ")
-    add(result, ']')
-  of tyPtr, tyRef, tyVar, tyMutable, tyConst: 
+      add(result, ')')
+  of tyPtr, tyRef, tyVar, tyMutable, tyConst:
     result = typeToStr[t.kind]
     if t.len >= 2:
       setLen(result, result.len-1)
       result.add '['
-      for i in countup(0, sonsLen(t) - 1): 
+      for i in countup(0, sonsLen(t) - 1):
         add(result, typeToString(t.sons[i]))
         if i < sonsLen(t) - 1: add(result, ", ")
       result.add ']'
@@ -530,7 +540,10 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
       result.add("(" & typeToString(t.sons[0]) & ")")
   of tyProc:
     result = if tfIterator in t.flags: "iterator (" else: "proc ("
-    for i in countup(1, sonsLen(t) - 1): 
+    for i in countup(1, sonsLen(t) - 1):
+      if t.n != nil and i < t.n.len and t.n[i].kind == nkSym:
+        add(result, t.n[i].sym.name.s)
+        add(result, ": ")
       add(result, typeToString(t.sons[i]))
       if i < sonsLen(t) - 1: add(result, ", ")
     add(result, ')')
@@ -548,29 +561,29 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
     if len(prag) != 0: add(result, "{." & prag & ".}")
   of tyVarargs, tyIter:
     result = typeToStr[t.kind] % typeToString(t.sons[0])
-  else: 
+  else:
     result = typeToStr[t.kind]
   if tfShared in t.flags: result = "shared " & result
   if tfNotNil in t.flags: result.add(" not nil")
 
-proc resultType(t: PType): PType = 
+proc resultType(t: PType): PType =
   assert(t.kind == tyProc)
   result = t.sons[0]          # nil is allowed
-  
-proc base(t: PType): PType = 
+
+proc base(t: PType): PType =
   result = t.sons[0]
 
-proc firstOrd(t: PType): BiggestInt = 
+proc firstOrd(t: PType): BiggestInt =
   case t.kind
   of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy:
     result = 0
   of tySet, tyVar: result = firstOrd(t.sons[0])
   of tyArray, tyArrayConstr: result = firstOrd(t.sons[0])
-  of tyRange: 
+  of tyRange:
     assert(t.n != nil)        # range directly given:
     assert(t.n.kind == nkRange)
     result = getOrdValue(t.n.sons[0])
-  of tyInt: 
+  of tyInt:
     if platform.intSize == 4: result = - (2147483646) - 2
     else: result = 0x8000000000000000'i64
   of tyInt8: result = - 128
@@ -578,11 +591,11 @@ proc firstOrd(t: PType): BiggestInt =
   of tyInt32: result = - 2147483646 - 2
   of tyInt64: result = 0x8000000000000000'i64
   of tyUInt..tyUInt64: result = 0
-  of tyEnum: 
+  of tyEnum:
     # if basetype <> nil then return firstOrd of basetype
-    if (sonsLen(t) > 0) and (t.sons[0] != nil): 
+    if sonsLen(t) > 0 and t.sons[0] != nil:
       result = firstOrd(t.sons[0])
-    else: 
+    else:
       assert(t.n.sons[0].kind == nkSym)
       result = t.n.sons[0].sym.position
   of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc, tyFieldAccessor:
@@ -594,31 +607,31 @@ proc firstOrd(t: PType): BiggestInt =
     internalError("invalid kind for first(" & $t.kind & ')')
     result = 0
 
-proc lastOrd(t: PType): BiggestInt = 
+proc lastOrd(t: PType): BiggestInt =
   case t.kind
   of tyBool: result = 1
   of tyChar: result = 255
   of tySet, tyVar: result = lastOrd(t.sons[0])
   of tyArray, tyArrayConstr: result = lastOrd(t.sons[0])
-  of tyRange: 
+  of tyRange:
     assert(t.n != nil)        # range directly given:
     assert(t.n.kind == nkRange)
     result = getOrdValue(t.n.sons[1])
-  of tyInt: 
+  of tyInt:
     if platform.intSize == 4: result = 0x7FFFFFFF
     else: result = 0x7FFFFFFFFFFFFFFF'i64
   of tyInt8: result = 0x0000007F
   of tyInt16: result = 0x00007FFF
   of tyInt32: result = 0x7FFFFFFF
   of tyInt64: result = 0x7FFFFFFFFFFFFFFF'i64
-  of tyUInt: 
+  of tyUInt:
     if platform.intSize == 4: result = 0xFFFFFFFF
     else: result = 0x7FFFFFFFFFFFFFFF'i64
   of tyUInt8: result = 0xFF
   of tyUInt16: result = 0xFFFF
   of tyUInt32: result = 0xFFFFFFFF
   of tyUInt64: result = 0x7FFFFFFFFFFFFFFF'i64
-  of tyEnum: 
+  of tyEnum:
     assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
     result = t.n.sons[sonsLen(t.n) - 1].sym.position
   of tyGenericInst, tyDistinct, tyConst, tyMutable,
@@ -632,7 +645,7 @@ proc lastOrd(t: PType): BiggestInt =
     internalError("invalid kind for last(" & $t.kind & ')')
     result = 0
 
-proc lengthOrd(t: PType): BiggestInt = 
+proc lengthOrd(t: PType): BiggestInt =
   case t.kind
   of tyInt64, tyInt32, tyInt: result = lastOrd(t)
   of tyDistinct, tyConst, tyMutable: result = lengthOrd(t.sons[0])
@@ -643,12 +656,12 @@ proc lengthOrd(t: PType): BiggestInt =
 type
   TDistinctCompare* = enum ## how distinct types are to be compared
     dcEq,                  ## a and b should be the same type
-    dcEqIgnoreDistinct,    ## compare symetrically: (distinct a) == b, a == b
+    dcEqIgnoreDistinct,    ## compare symmetrically: (distinct a) == b, a == b
                            ## or a == (distinct b)
     dcEqOrDistinctOf       ## a equals b or a is distinct of b
 
   TTypeCmpFlag* = enum
-    IgnoreTupleFields
+    IgnoreTupleFields      ## NOTE: Only set this flag for backends!
     IgnoreCC
     ExactTypeDescValues
     ExactGenericParams
@@ -667,7 +680,7 @@ type
 proc initSameTypeClosure: TSameTypeClosure =
   # we do the initialization lazily for performance (avoids memory allocations)
   discard
-  
+
 proc containsOrIncl(c: var TSameTypeClosure, a, b: PType): bool =
   result = not isNil(c.s) and c.s.contains((a.id, b.id))
   if not result:
@@ -694,17 +707,17 @@ proc sameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool =
     if a == nil or b == nil: result = false
     else: result = sameType(a, b, flags)
 
-proc equalParam(a, b: PSym): TParamsEquality = 
+proc equalParam(a, b: PSym): TParamsEquality =
   if sameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}) and
       exprStructuralEquivalent(a.constraint, b.constraint):
-    if a.ast == b.ast: 
+    if a.ast == b.ast:
       result = paramsEqual
-    elif a.ast != nil and b.ast != nil: 
+    elif a.ast != nil and b.ast != nil:
       if exprStructuralEquivalent(a.ast, b.ast): result = paramsEqual
       else: result = paramsIncompatible
-    elif a.ast != nil: 
+    elif a.ast != nil:
       result = paramsEqual
-    elif b.ast != nil: 
+    elif b.ast != nil:
       result = paramsIncompatible
   else:
     result = paramsNotEqual
@@ -717,73 +730,71 @@ proc sameConstraints(a, b: PNode): bool =
       return false
   return true
 
-proc equalParams(a, b: PNode): TParamsEquality = 
+proc equalParams(a, b: PNode): TParamsEquality =
   result = paramsEqual
   var length = sonsLen(a)
-  if length != sonsLen(b): 
+  if length != sonsLen(b):
     result = paramsNotEqual
-  else: 
-    for i in countup(1, length - 1): 
+  else:
+    for i in countup(1, length - 1):
       var m = a.sons[i].sym
       var n = b.sons[i].sym
       assert((m.kind == skParam) and (n.kind == skParam))
       case equalParam(m, n)
-      of paramsNotEqual: 
+      of paramsNotEqual:
         return paramsNotEqual
-      of paramsEqual: 
+      of paramsEqual:
         discard
-      of paramsIncompatible: 
+      of paramsIncompatible:
         result = paramsIncompatible
-      if (m.name.id != n.name.id): 
+      if (m.name.id != n.name.id):
         # BUGFIX
         return paramsNotEqual # paramsIncompatible;
       # continue traversal! If not equal, we can return immediately; else
       # it stays incompatible
     if not sameTypeOrNil(a.sons[0].typ, b.sons[0].typ, {ExactTypeDescValues}):
-      if (a.sons[0].typ == nil) or (b.sons[0].typ == nil): 
+      if (a.sons[0].typ == nil) or (b.sons[0].typ == nil):
         result = paramsNotEqual # one proc has a result, the other not is OK
-      else: 
+      else:
         result = paramsIncompatible # overloading by different
                                     # result types does not work
-  
-proc sameLiteral(x, y: PNode): bool = 
-  if x.kind == y.kind: 
+
+proc sameLiteral(x, y: PNode): bool =
+  if x.kind == y.kind:
     case x.kind
     of nkCharLit..nkInt64Lit: result = x.intVal == y.intVal
     of nkFloatLit..nkFloat64Lit: result = x.floatVal == y.floatVal
     of nkNilLit: result = true
     else: assert(false)
-  
-proc sameRanges(a, b: PNode): bool = 
+
+proc sameRanges(a, b: PNode): bool =
   result = sameLiteral(a.sons[0], b.sons[0]) and
            sameLiteral(a.sons[1], b.sons[1])
 
-proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool = 
+proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
   # 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.
-  if sonsLen(a) == sonsLen(b): 
+  if sonsLen(a) == sonsLen(b):
     result = true
-    for i in countup(0, sonsLen(a) - 1): 
+    for i in countup(0, sonsLen(a) - 1):
       var x = a.sons[i]
       var y = b.sons[i]
       if IgnoreTupleFields in c.flags:
-        x = skipTypes(x, {tyRange})
-        y = skipTypes(y, {tyRange})
-      
+        x = skipTypes(x, {tyRange, tyGenericInst})
+        y = skipTypes(y, {tyRange, tyGenericInst})
+
       result = sameTypeAux(x, y, c)
-      if not result: return 
+      if not result: return
     if a.n != nil and b.n != nil and IgnoreTupleFields notin c.flags:
-      for i in countup(0, sonsLen(a.n) - 1): 
-        # check field names: 
+      for i in countup(0, sonsLen(a.n) - 1):
+        # check field names:
         if a.n.sons[i].kind == nkSym and b.n.sons[i].kind == nkSym:
           var x = a.n.sons[i].sym
           var y = b.n.sons[i].sym
           result = x.name.id == y.name.id
-          if not result: break 
+          if not result: break
         else: internalError(a.n.info, "sameTuple")
-  else:
-    result = false
 
 template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} =
   if tfFromGeneric notin a.flags + b.flags:
@@ -792,8 +803,8 @@ template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} =
   else:
     # expensive structural equality test; however due to the way generic and
     # objects work, if one of the types does **not** contain tfFromGeneric,
-    # they cannot be equal. The check ``a.sym.Id == b.sym.Id`` checks
-    # for the same origin and is essential because we don't want "pure" 
+    # they cannot be equal. The check ``a.sym.id == b.sym.id`` checks
+    # for the same origin and is essential because we don't want "pure"
     # structural type equivalence:
     #
     # type
@@ -819,8 +830,13 @@ proc sameEnumTypes*(a, b: PType): bool {.inline.} =
 proc sameObjectTree(a, b: PNode, c: var TSameTypeClosure): bool =
   if a == b:
     result = true
-  elif (a != nil) and (b != nil) and (a.kind == b.kind):
-    if sameTypeOrNilAux(a.typ, b.typ, c):
+  elif a != nil and b != nil and a.kind == b.kind:
+    var x = a.typ
+    var y = b.typ
+    if IgnoreTupleFields in c.flags:
+      if x != nil: x = skipTypes(x, {tyRange, tyGenericInst})
+      if y != nil: y = skipTypes(y, {tyRange, tyGenericInst})
+    if sameTypeOrNilAux(x, y, c):
       case a.kind
       of nkSym:
         # same symbol as string is enough:
@@ -831,9 +847,9 @@ proc sameObjectTree(a, b: PNode, c: var TSameTypeClosure): bool =
       of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
       of nkEmpty, nkNilLit, nkType: result = true
       else:
-        if sonsLen(a) == sonsLen(b): 
-          for i in countup(0, sonsLen(a) - 1): 
-            if not sameObjectTree(a.sons[i], b.sons[i], c): return 
+        if sonsLen(a) == sonsLen(b):
+          for i in countup(0, sonsLen(a) - 1):
+            if not sameObjectTree(a.sons[i], b.sons[i], c): return
           result = true
 
 proc sameObjectStructures(a, b: PType, c: var TSameTypeClosure): bool =
@@ -849,7 +865,7 @@ proc sameChildrenAux(a, b: PType, c: var TSameTypeClosure): bool =
   result = true
   for i in countup(0, sonsLen(a) - 1):
     result = sameTypeOrNilAux(a.sons[i], b.sons[i], c)
-    if not result: return 
+    if not result: return
 
 proc isGenericAlias*(t: PType): bool =
   return t.kind == tyGenericInst and t.lastSon.kind == tyGenericInst
@@ -862,7 +878,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
     # believe it or not, the direct check for ``containsOrIncl(c, a, b)``
     # increases bootstrapping time from 2.4s to 3.3s on my laptop! So we cheat
     # again: Since the recursion check is only to not get caught in an endless
-    # recursion, we use a counter and only if it's value is over some 
+    # recursion, we use a counter and only if it's value is over some
     # threshold we perform the expensive exact cycle check:
     if c.recCheck < 3:
       inc c.recCheck
@@ -870,11 +886,11 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
       if containsOrIncl(c, a, b): return true
 
   proc sameFlags(a, b: PType): bool {.inline.} =
-    result = eqTypeFlags*a.flags == eqTypeFlags*b.flags   
+    result = eqTypeFlags*a.flags == eqTypeFlags*b.flags
 
   if x == y: return true
   var a = skipTypes(x, {tyGenericInst})
-  var b = skipTypes(y, {tyGenericInst})  
+  var b = skipTypes(y, {tyGenericInst})
   assert(a != nil)
   assert(b != nil)
   if a.kind != b.kind:
@@ -887,7 +903,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
     of dcEqOrDistinctOf:
       while a.kind == tyDistinct: a = a.sons[0]
       if a.kind != b.kind: return false
-  
+
   if x.kind == tyGenericInst:
     let
       lhs = x.skipGenericAlias
@@ -906,17 +922,20 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
     result = sameFlags(a, b)
   of tyStatic, tyFromExpr:
     result = exprStructuralEquivalent(a.n, b.n) and sameFlags(a, b)
+    if result and a.len == b.len and a.len == 1:
+      cycleCheck()
+      result = sameTypeAux(a.sons[0], b.sons[0], c)
   of tyObject:
     ifFastObjectTypeCheckFailed(a, b):
       cycleCheck()
       result = sameObjectStructures(a, b, c) and sameFlags(a, b)
   of tyDistinct:
     cycleCheck()
-    if c.cmp == dcEq:      
+    if c.cmp == dcEq:
       if sameFlags(a, b):
         ifFastObjectTypeCheckFailed(a, b):
-          result = sameTypeAux(a.sons[0], b.sons[0], c)     
-    else: 
+          result = sameTypeAux(a.sons[0], b.sons[0], c)
+    else:
       result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b)
   of tyEnum, tyForward:
     # XXX generic enums do not make much sense, but require structural checking
@@ -937,7 +956,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
     result = sameChildrenAux(a, b, c) and sameFlags(a, b)
     if result and ExactGenericParams in c.flags:
       result = a.sym.position == b.sym.position
-  of tyGenericInvokation, tyGenericBody, tySequence,
+  of tyGenericInvocation, tyGenericBody, tySequence,
      tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
      tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
      tyOrdinal, tyTypeClasses, tyFieldAccessor:
@@ -953,13 +972,13 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
         sameValue(a.n.sons[0], b.n.sons[0]) and
         sameValue(a.n.sons[1], b.n.sons[1])
   of tyGenericInst: discard
-  of tyNone: result = false  
+  of tyNone: result = false
 
 proc sameBackendType*(x, y: PType): bool =
   var c = initSameTypeClosure()
   c.flags.incl IgnoreTupleFields
   result = sameTypeAux(x, y, c)
-  
+
 proc compareTypes*(x, y: PType,
                    cmp: TDistinctCompare = dcEq,
                    flags: TTypeCmpFlags = {}): bool =
@@ -968,8 +987,8 @@ proc compareTypes*(x, y: PType,
   c.cmp = cmp
   c.flags = flags
   result = sameTypeAux(x, y, c)
-  
-proc inheritanceDiff*(a, b: PType): int = 
+
+proc 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`
@@ -981,14 +1000,14 @@ proc inheritanceDiff*(a, b: PType): int =
   result = 0
   while x != nil:
     x = skipTypes(x, skipPtrs)
-    if sameObjectTypes(x, b): return 
+    if sameObjectTypes(x, b): return
     x = x.sons[0]
     dec(result)
   var y = b
   result = 0
   while y != nil:
     y = skipTypes(y, skipPtrs)
-    if sameObjectTypes(y, a): return 
+    if sameObjectTypes(y, a): return
     y = y.sons[0]
     inc(result)
   result = high(int)
@@ -1021,22 +1040,23 @@ type
   TTypeAllowedFlags = set[TTypeAllowedFlag]
 
 proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
-                    flags: TTypeAllowedFlags = {}): bool
+                    flags: TTypeAllowedFlags = {}): PType
 
 proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind,
-                     flags: TTypeAllowedFlags = {}): bool =
-  result = true
-  if n != nil: 
+                     flags: TTypeAllowedFlags = {}): PType =
+  if n != nil:
     result = typeAllowedAux(marker, n.typ, kind, flags)
     #if not result: debug(n.typ)
-    if result: 
+    if result == nil:
       case n.kind
-      of nkNone..nkNilLit: 
+      of nkNone..nkNilLit:
         discard
-      else: 
-        for i in countup(0, sonsLen(n) - 1): 
-          result = typeAllowedNode(marker, n.sons[i], kind, flags)
-          if not result: break
+      else:
+        for i in countup(0, sonsLen(n) - 1):
+          let it = n.sons[i]
+          if it.kind == nkRecCase and kind == skConst: return n.typ
+          result = typeAllowedNode(marker, it, kind, flags)
+          if result != nil: break
 
 proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
                 last: TTypeKind): bool =
@@ -1048,88 +1068,94 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
   result = a.kind == last
 
 proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
-                    flags: TTypeAllowedFlags = {}): bool =
+                    flags: TTypeAllowedFlags = {}): PType =
   assert(kind in {skVar, skLet, skConst, skParam, skResult})
   # if we have already checked the type, return true, because we stop the
   # evaluation if something is wrong:
-  result = true
+  result = nil
   if typ == nil: return
-  if containsOrIncl(marker, typ.id): return 
+  if containsOrIncl(marker, typ.id): return
   var t = skipTypes(typ, abstractInst-{tyTypeDesc})
   case t.kind
   of tyVar:
-    if kind == skConst: return false
+    if kind == skConst: return t
     var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc})
     case t2.kind
-    of tyVar: 
-      result = taHeap in flags # ``var var`` is illegal on the heap:
-    of tyOpenArray: 
-      result = kind == skParam and typeAllowedAux(marker, t2, kind, flags)
+    of tyVar:
+      if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap
+    of tyOpenArray:
+      if kind != skParam: result = t
+      else: result = typeAllowedAux(marker, t2, kind, flags)
     else:
-      result = kind in {skParam, skResult} and
-               typeAllowedAux(marker, t2, kind, flags)
-  of tyProc: 
-    for i in countup(1, sonsLen(t) - 1): 
+      if kind notin {skParam, skResult}: result = t
+      else: result = typeAllowedAux(marker, t2, kind, flags)
+  of tyProc:
+    for i in countup(1, sonsLen(t) - 1):
       result = typeAllowedAux(marker, t.sons[i], skParam, flags)
-      if not result: break 
-    if result and t.sons[0] != nil:
+      if result != nil: break
+    if result.isNil and t.sons[0] != nil:
       result = typeAllowedAux(marker, t.sons[0], skResult, flags)
-  of tyExpr, tyStmt, tyTypeDesc, tyStatic:
-    result = true
-    # XXX er ... no? these should not be allowed!
+  of tyTypeDesc:
+    # XXX: This is still a horrible idea...
+    result = nil
+  of tyExpr, tyStmt, tyStatic:
+    if kind notin {skParam, skResult}: result = t
   of tyEmpty:
-    result = taField in flags
+    if taField notin flags: result = t
   of tyTypeClasses:
-    result = tfGenericTypeParam in t.flags or
-             taField notin flags
-  of tyGenericBody, tyGenericParam, tyGenericInvokation,
+    if not (tfGenericTypeParam in t.flags or taField notin flags): result = t
+  of tyGenericBody, tyGenericParam, tyGenericInvocation,
      tyNone, tyForward, tyFromExpr, tyFieldAccessor:
-    result = false
+    result = t
   of tyNil:
-    result = kind == skConst
-  of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer: 
-    result = true
-  of tyOrdinal: 
-    result = kind == skParam
-  of tyGenericInst, tyDistinct: 
+    if kind != skConst: result = t
+  of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer:
+    result = nil
+  of tyOrdinal:
+    if kind != skParam: result = t
+  of tyGenericInst, tyDistinct:
     result = typeAllowedAux(marker, lastSon(t), kind, flags)
-  of tyRange: 
-    result = skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind in
-        {tyChar, tyEnum, tyInt..tyFloat128}
-  of tyOpenArray, tyVarargs: 
-    result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar, flags)
-  of tySequence: 
-    result = t.sons[0].kind == tyEmpty or 
-        typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap})
+  of tyRange:
+    if skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind notin
+        {tyChar, tyEnum, tyInt..tyFloat128, tyUInt8..tyUInt32}: result = t
+  of tyOpenArray, tyVarargs:
+    if kind != skParam: result = t
+    else: result = typeAllowedAux(marker, t.sons[0], skVar, flags)
+  of tySequence:
+    if t.sons[0].kind != tyEmpty:
+      result = typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap})
   of tyArray:
-    result = t.sons[1].kind == tyEmpty or
-        typeAllowedAux(marker, t.sons[1], skVar, flags)
+    if t.sons[1].kind != tyEmpty:
+      result = typeAllowedAux(marker, t.sons[1], skVar, flags)
   of tyRef:
-    if kind == skConst: return false
-    result = typeAllowedAux(marker, t.lastSon, skVar, flags+{taHeap})
+    if kind == skConst: result = t
+    else: result = typeAllowedAux(marker, t.lastSon, skVar, flags+{taHeap})
   of tyPtr:
     result = typeAllowedAux(marker, t.lastSon, skVar, flags+{taHeap})
   of tyArrayConstr, tySet, tyConst, tyMutable, tyIter:
     for i in countup(0, sonsLen(t) - 1):
       result = typeAllowedAux(marker, t.sons[i], kind, flags)
-      if not result: break
+      if result != nil: break
   of tyObject, tyTuple:
-    if kind == skConst and t.kind == tyObject: return false
+    if kind == skConst and t.kind == tyObject and t.sons[0] != nil: return t
     let flags = flags+{taField}
-    for i in countup(0, sonsLen(t) - 1): 
+    for i in countup(0, sonsLen(t) - 1):
       result = typeAllowedAux(marker, t.sons[i], kind, flags)
-      if not result: break
-    if result and t.n != nil: result = typeAllowedNode(marker, t.n, kind, flags)
+      if result != nil: break
+    if result.isNil and t.n != nil:
+      result = typeAllowedNode(marker, t.n, kind, flags)
   of tyProxy:
     # for now same as error node; we say it's a valid type as it should
     # prevent cascading errors:
-    result = true
+    result = nil
 
-proc typeAllowed(t: PType, kind: TSymKind): bool = 
+proc typeAllowed*(t: PType, kind: TSymKind): PType =
+  # returns 'nil' on success and otherwise the part of the type that is
+  # wrong!
   var marker = initIntSet()
   result = typeAllowedAux(marker, t, kind, {})
 
-proc align(address, alignment: BiggestInt): BiggestInt = 
+proc align(address, alignment: BiggestInt): BiggestInt =
   result = (address + (alignment - 1)) and not (alignment - 1)
 
 const
@@ -1138,17 +1164,17 @@ const
   szUnknownSize* = -1
 
 proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt
-proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt = 
+proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt =
   var maxAlign, maxSize, b, res: BiggestInt
   case n.kind
-  of nkRecCase: 
+  of nkRecCase:
     assert(n.sons[0].kind == nkSym)
     result = computeRecSizeAux(n.sons[0], a, currOffset)
     maxSize = 0
     maxAlign = 1
-    for i in countup(1, sonsLen(n) - 1): 
+    for i in countup(1, sonsLen(n) - 1):
       case n.sons[i].kind
-      of nkOfBranch, nkElse: 
+      of nkOfBranch, nkElse:
         res = computeRecSizeAux(lastSon(n.sons[i]), b, currOffset)
         if res < 0: return res
         maxSize = max(maxSize, res)
@@ -1157,17 +1183,17 @@ proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt =
     currOffset = align(currOffset, maxAlign) + maxSize
     result = align(result, maxAlign) + maxSize
     a = maxAlign
-  of nkRecList: 
+  of nkRecList:
     result = 0
     maxAlign = 1
-    for i in countup(0, sonsLen(n) - 1): 
+    for i in countup(0, sonsLen(n) - 1):
       res = computeRecSizeAux(n.sons[i], b, currOffset)
       if res < 0: return res
       currOffset = align(currOffset, b) + res
       result = align(result, b) + res
       if b > maxAlign: maxAlign = b
     a = maxAlign
-  of nkSym: 
+  of nkSym:
     result = computeSizeAux(n.sym.typ, a)
     n.sym.offset = int(currOffset)
   else:
@@ -1184,31 +1210,31 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
     # size already computed
     result = typ.size
     a = typ.align
-    return 
+    return
   typ.size = szIllegalRecursion # mark as being computed
   case typ.kind
-  of tyInt, tyUInt: 
+  of tyInt, tyUInt:
     result = intSize
     a = result
-  of tyInt8, tyUInt8, tyBool, tyChar: 
+  of tyInt8, tyUInt8, tyBool, tyChar:
     result = 1
     a = result
-  of tyInt16, tyUInt16: 
+  of tyInt16, tyUInt16:
     result = 2
     a = result
-  of tyInt32, tyUInt32, tyFloat32: 
+  of tyInt32, tyUInt32, tyFloat32:
     result = 4
     a = result
-  of tyInt64, tyUInt64, tyFloat64: 
+  of tyInt64, tyUInt64, tyFloat64:
     result = 8
     a = result
   of tyFloat128:
     result = 16
     a = result
-  of tyFloat: 
+  of tyFloat:
     result = floatSize
     a = result
-  of tyProc: 
+  of tyProc:
     if typ.callConv == ccClosure: result = 2 * ptrSize
     else: result = ptrSize
     a = ptrSize
@@ -1223,17 +1249,17 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
     let elemSize = computeSizeAux(typ.sons[1], a)
     if elemSize < 0: return elemSize
     result = lengthOrd(typ.sons[0]) * elemSize
-  of tyEnum: 
-    if firstOrd(typ) < 0: 
+  of tyEnum:
+    if firstOrd(typ) < 0:
       result = 4              # use signed int32
-    else: 
+    else:
       length = lastOrd(typ)   # BUGFIX: use lastOrd!
       if length + 1 < `shl`(1, 8): result = 1
       elif length + 1 < `shl`(1, 16): result = 2
       elif length + 1 < `shl`(BiggestInt(1), 32): result = 4
       else: result = 8
     a = result
-  of tySet: 
+  of tySet:
     length = lengthOrd(typ.sons[0])
     if length <= 8: result = 1
     elif length <= 16: result = 2
@@ -1242,32 +1268,32 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
     elif align(length, 8) mod 8 == 0: result = align(length, 8) div 8
     else: result = align(length, 8) div 8 + 1
     a = result
-  of tyRange: 
+  of tyRange:
     result = computeSizeAux(typ.sons[0], a)
-  of tyTuple: 
+  of tyTuple:
     result = 0
     maxAlign = 1
-    for i in countup(0, sonsLen(typ) - 1): 
+    for i in countup(0, sonsLen(typ) - 1):
       res = computeSizeAux(typ.sons[i], a)
       if res < 0: return res
       maxAlign = max(maxAlign, a)
       result = align(result, a) + res
     result = align(result, maxAlign)
     a = maxAlign
-  of tyObject: 
-    if typ.sons[0] != nil: 
+  of tyObject:
+    if typ.sons[0] != nil:
       result = computeSizeAux(typ.sons[0], a)
-      if result < 0: return 
+      if result < 0: return
       maxAlign = a
-    elif isObjectWithTypeFieldPredicate(typ): 
+    elif isObjectWithTypeFieldPredicate(typ):
       result = intSize
       maxAlign = result
-    else: 
+    else:
       result = 0
       maxAlign = 1
     currOffset = result
     result = computeRecSizeAux(typ.n, a, currOffset)
-    if result < 0: return 
+    if result < 0: return
     if a < maxAlign: a = maxAlign
     result = align(result, a)
   of tyGenericInst, tyDistinct, tyGenericBody, tyMutable, tyConst, tyIter:
@@ -1281,7 +1307,7 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
   typ.size = result
   typ.align = int16(a)
 
-proc computeSize(typ: PType): BiggestInt = 
+proc computeSize(typ: PType): BiggestInt =
   var a: BiggestInt = 1
   result = computeSizeAux(typ, a)
 
@@ -1290,7 +1316,7 @@ proc getReturnType*(s: PSym): PType =
   assert s.kind in skProcKinds
   result = s.typ.sons[0]
 
-proc getSize(typ: PType): BiggestInt = 
+proc getSize(typ: PType): BiggestInt =
   result = computeSize(typ)
   if result < 0: internalError("getSize: " & $typ.kind)
 
@@ -1308,7 +1334,7 @@ proc containsGenericTypeIter(t: PType, closure: RootRef): bool =
 
   return false
 
-proc containsGenericType*(t: PType): bool = 
+proc containsGenericType*(t: PType): bool =
   result = iterOverType(t, containsGenericTypeIter, nil)
 
 proc baseOfDistinct*(t: PType): PType =
@@ -1327,7 +1353,7 @@ proc baseOfDistinct*(t: PType): PType =
 
 proc safeInheritanceDiff*(a, b: PType): int =
   # same as inheritanceDiff but checks for tyError:
-  if a.kind == tyError or b.kind == tyError: 
+  if a.kind == tyError or b.kind == tyError:
     result = -1
   else:
     result = inheritanceDiff(a, b)
@@ -1347,7 +1373,7 @@ proc compatibleEffects*(formal, actual: PType): bool =
   assert formal.kind == tyProc and actual.kind == tyProc
   internalAssert formal.n.sons[0].kind == nkEffectList
   internalAssert actual.n.sons[0].kind == nkEffectList
-  
+
   var spec = formal.n.sons[0]
   if spec.len != 0:
     var real = actual.n.sons[0]
diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim
index f3121a0b4..700356ab7 100644
--- a/compiler/typesrenderer.nim
+++ b/compiler/typesrenderer.nim
@@ -1,3 +1,12 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
 import renderer, strutils, ast, msgs, types, astalgo
 
 const defaultParamSeparator* = ","
@@ -26,7 +35,7 @@ proc renderPlainSymbolName*(n: PNode): string =
     result = renderPlainSymbolName(n[<n.len])
   else:
     internalError(n.info, "renderPlainSymbolName() with " & $n.kind)
-  assert (not result.isNil)
+  assert(not result.isNil)
 
 proc renderType(n: PNode): string =
   ## Returns a string with the node type or the empty string.
@@ -59,7 +68,6 @@ proc renderType(n: PNode): string =
       assert n[i].kind == nkIdent
       result.add(',' & typeStr)
   of nkTupleTy:
-    assert len(n) > 0
     result = "tuple["
     for i in 0 .. <len(n): result.add(renderType(n[i]) & ',')
     result[<len(result)] = ']'
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 3d2ddfc82..6fae5a8b7 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -1,13 +1,13 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
-## This file implements the new evaluation engine for Nimrod code.
+## This file implements the new evaluation engine for Nim code.
 ## An instruction is 1-3 int32s in memory, it is a register based VM.
 
 const debugEchoCode = false
@@ -123,8 +123,12 @@ proc createStrKeepNode(x: var TFullReg) =
   if x.node.isNil:
     x.node = newNode(nkStrLit)
   elif x.node.kind == nkNilLit:
+    when defined(useNodeIds):
+      let id = x.node.id
     system.reset(x.node[])
     x.node.kind = nkStrLit
+    when defined(useNodeIds):
+      x.node.id = id
   elif x.node.kind notin {nkStrLit..nkTripleStrLit} or
       nfAllConst in x.node.flags:
     # XXX this is hacky; tests/txmlgen triggers it:
@@ -154,7 +158,7 @@ proc moveConst(x: var TFullReg, y: TFullReg) =
   of rkNodeAddr: x.nodeAddr = y.nodeAddr
 
 # this seems to be the best way to model the reference semantics
-# of PNimrodNode:
+# of system.NimNode:
 template asgnRef(x, y: expr) = moveConst(x, y)
 
 proc copyValue(src: PNode): PNode =
@@ -235,7 +239,7 @@ proc pushSafePoint(f: PStackFrame; pc: int) =
 
 proc popSafePoint(f: PStackFrame) = discard f.safePoints.pop()
 
-proc cleanUpOnException(c: PCtx; tos: PStackFrame): 
+proc cleanUpOnException(c: PCtx; tos: PStackFrame):
                                               tuple[pc: int, f: PStackFrame] =
   let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs)
   var f = tos
@@ -253,7 +257,7 @@ proc cleanUpOnException(c: PCtx; tos: PStackFrame):
       let exceptType = c.types[c.code[pc2].regBx-wordExcess].skipTypes(
                           abstractPtrs)
       if inheritanceDiff(exceptType, raisedType) <= 0:
-        # mark exception as handled but keep it in B for 
+        # mark exception as handled but keep it in B for
         # the getCurrentException() builtin:
         c.currentExceptionB = c.currentExceptionA
         c.currentExceptionA = nil
@@ -345,14 +349,14 @@ proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
       if dest.kind != rkFloat:
         myreset(dest); dest.kind = rkFloat
       case skipTypes(srctyp, abstractRange).kind
-      of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyBool, tyChar: 
+      of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyBool, tyChar:
         dest.floatVal = toFloat(src.intVal.int)
       else:
         dest.floatVal = src.floatVal
     else:
       asgnComplex(dest, src)
 
-proc compile(c: PCtx, s: PSym): int = 
+proc compile(c: PCtx, s: PSym): int =
   result = vmgen.genProc(c, s)
   when debugEchoCode: c.echoCode result
   #c.echoCode
@@ -392,10 +396,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       pc = tos.comesFrom
       tos = tos.next
       let retVal = regs[0]
-      if tos.isNil: 
+      if tos.isNil:
         #echo "RET ", retVal.rendertree
         return retVal
-      
+
       move(regs, tos.slots)
       assert c.code[pc].opcode in {opcIndCall, opcIndCallAsgn}
       if c.code[pc].opcode == opcIndCallAsgn:
@@ -454,8 +458,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcLdStrIdx:
       decodeBC(rkInt)
       let idx = regs[rc].intVal.int
-      if idx <=% regs[rb].node.strVal.len:
-        regs[ra].intVal = regs[rb].node.strVal[idx].ord
+      let s = regs[rb].node.strVal
+      if s.isNil:
+        stackTrace(c, tos, pc, errNilAccess)
+      elif idx <=% s.len:
+        regs[ra].intVal = s[idx].ord
       else:
         stackTrace(c, tos, pc, errIndexOutOfBounds)
     of opcWrArr:
@@ -646,7 +653,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcSubu:
       decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal -% regs[rc].intVal
-    of opcMulu: 
+    of opcMulu:
       decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal *% regs[rc].intVal
     of opcDivu:
@@ -719,7 +726,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcLeSet:
       decodeBC(rkInt)
       regs[ra].intVal = ord(containsSets(regs[rb].node, regs[rc].node))
-    of opcEqSet: 
+    of opcEqSet:
       decodeBC(rkInt)
       regs[ra].intVal = ord(equalSets(regs[rb].node, regs[rc].node))
     of opcLtSet:
@@ -730,9 +737,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcMulSet:
       decodeBC(rkNode)
       createSet(regs[ra])
-      move(regs[ra].node.sons, 
+      move(regs[ra].node.sons,
             nimsets.intersectSets(regs[rb].node, regs[rc].node).sons)
-    of opcPlusSet: 
+    of opcPlusSet:
       decodeBC(rkNode)
       createSet(regs[ra])
       move(regs[ra].node.sons,
@@ -746,7 +753,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       decodeBC(rkNode)
       createSet(regs[ra])
       move(regs[ra].node.sons,
-           nimsets.symdiffSets(regs[rb].node, regs[rc].node).sons)    
+           nimsets.symdiffSets(regs[rb].node, regs[rc].node).sons)
     of opcConcatStr:
       decodeBC(rkNode)
       createStr regs[ra]
@@ -769,10 +776,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         stackTrace(c, tos, pc, errNilAccess)
     of opcEcho:
       let rb = instr.regB
-      for i in ra..ra+rb-1:
-        #if regs[i].kind != rkNode: debug regs[i]
-        write(stdout, regs[i].node.strVal)
-      writeln(stdout, "")
+      if rb == 1:
+        msgWriteln(regs[ra].node.strVal)
+      else:
+        var outp = ""
+        for i in ra..ra+rb-1:
+          #if regs[i].kind != rkNode: debug regs[i]
+          outp.add(regs[i].node.strVal)
+        msgWriteln(outp)
     of opcContainsSet:
       decodeBC(rkInt)
       regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode))
@@ -782,7 +793,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       assert c.code[pc].opcode == opcSubStr
       let rd = c.code[pc].regA
       createStr regs[ra]
-      regs[ra].node.strVal = substr(regs[rb].node.strVal, 
+      regs[ra].node.strVal = substr(regs[rb].node.strVal,
                                     regs[rc].intVal.int, regs[rd].intVal.int)
     of opcParseFloat:
       decodeBC(rkInt)
@@ -803,7 +814,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
               leValueConv(regs[ra].regToNode, regs[rc].regToNode)):
         stackTrace(c, tos, pc, errGenerated,
           msgKindToString(errIllegalConvFromXtoY) % [
-          "unknown type" , "unknown type"])
+          $regs[ra].regToNode, "[" & $regs[rb].regToNode & ".." & $regs[rc].regToNode & "]"])
     of opcIndCall, opcIndCallAsgn:
       # dest = call regStart, n; where regStart = fn, arg1, ...
       let rb = instr.regB
@@ -885,12 +896,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       # we know the next instruction is a 'fjmp':
       let branch = c.constants[instr.regBx-wordExcess]
       var cond = false
-      for j in countup(0, sonsLen(branch) - 2): 
-        if overlap(regs[ra].regToNode, branch.sons[j]): 
+      for j in countup(0, sonsLen(branch) - 2):
+        if overlap(regs[ra].regToNode, branch.sons[j]):
           cond = true
           break
       assert c.code[pc+1].opcode == opcFJmp
-      inc pc 
+      inc pc
       # we skip this instruction so that the final 'inc(pc)' skips
       # the following jump
       if not cond:
@@ -981,6 +992,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       let rb = instr.regBx - wordExcess
       let cnst = c.constants.sons[rb]
       if fitsRegister(cnst.typ):
+        myreset(regs[ra])
         putIntoReg(regs[ra], cnst)
       else:
         ensureKind(rkNode)
@@ -1008,7 +1020,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcQuit:
       if c.mode in {emRepl, emStaticExpr, emStaticStmt}:
         message(c.debug[pc], hintQuitCalled)
-        quit(int(getOrdValue(regs[ra].regToNode)))
+        msgQuit(int8(getOrdValue(regs[ra].regToNode)))
       else:
         return TFullReg(kind: rkNone)
     of opcSetLenStr:
@@ -1031,7 +1043,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       decodeB(rkNode)
       let newLen = regs[rb].intVal.int
       if regs[ra].node.isNil: stackTrace(c, tos, pc, errNilAccess)
-      else: setLen(regs[ra].node.sons, newLen)
+      else:
+        let oldLen = regs[ra].node.len
+        setLen(regs[ra].node.sons, newLen)
+        if oldLen < newLen:
+          # XXX This is still not entirely correct
+          # set to default value:
+          for i in oldLen .. <newLen:
+            regs[ra].node.sons[i] = newNodeI(nkEmpty, c.debug[pc])
     of opcSwap:
       let rb = instr.regB
       if regs[ra].kind == regs[rb].kind:
@@ -1058,7 +1077,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       regs[ra].intVal = regs[ra].intVal and ((1'i64 shl rb)-1)
     of opcIsNil:
       decodeB(rkInt)
-      regs[ra].intVal = ord(regs[rb].node.kind == nkNilLit)
+      let node = regs[rb].node
+      regs[ra].intVal = ord(node.kind == nkNilLit or
+        (node.kind in {nkStrLit..nkTripleStrLit} and node.strVal.isNil))
     of opcNBindSym:
       decodeBx(rkNode)
       regs[ra].node = copyTree(c.constants.sons[rbx])
@@ -1081,14 +1102,20 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcNAdd:
       decodeBC(rkNode)
       var u = regs[rb].node
-      u.add(regs[rc].node)
+      if u.kind notin {nkEmpty..nkNilLit}:
+        u.add(regs[rc].node)
+      else:
+        stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind)
       regs[ra].node = u
     of opcNAddMultiple:
       decodeBC(rkNode)
       let x = regs[rc].node
       var u = regs[rb].node
-      # XXX can be optimized:
-      for i in 0.. <x.len: u.add(x.sons[i])
+      if u.kind notin {nkEmpty..nkNilLit}:
+        # XXX can be optimized:
+        for i in 0.. <x.len: u.add(x.sons[i])
+      else:
+        stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind)
       regs[ra].node = u
     of opcNKind:
       decodeB(rkInt)
@@ -1121,7 +1148,21 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       else:
         stackTrace(c, tos, pc, errFieldXNotFound, "ident")
     of opcNGetType:
-      internalError(c.debug[pc], "unknown opcode " & $instr.opcode)
+      let rb = instr.regB
+      let rc = instr.regC
+      if rc == 0:
+        ensureKind(rkNode)
+        if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
+          regs[ra].node = opMapTypeToAst(regs[rb].node.typ, c.debug[pc])
+        else:
+          stackTrace(c, tos, pc, errGenerated, "node has no type")
+      else:
+        # typeKind opcode:
+        ensureKind(rkInt)
+        if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
+          regs[ra].intVal = ord(regs[rb].node.typ.kind)
+        #else:
+        #  stackTrace(c, tos, pc, errGenerated, "node has no type")
     of opcNStrVal:
       decodeB(rkNode)
       createStr regs[ra]
@@ -1151,7 +1192,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFullPath,
                             c.debug[pc].line.int,
                             proc (info: TLineInfo; msg: TMsgKind; arg: string) =
-                              if error.isNil: error = formatMsg(info, msg, arg))
+                              if error.isNil and msg <= msgs.errMax:
+                                error = formatMsg(info, msg, arg))
       if not error.isNil:
         c.errorFlag = error
       elif sonsLen(ast) != 1:
@@ -1164,7 +1206,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFullPath,
                             c.debug[pc].line.int,
                             proc (info: TLineInfo; msg: TMsgKind; arg: string) =
-                              if error.isNil: error = formatMsg(info, msg, arg))
+                              if error.isNil and msg <= msgs.errMax:
+                                error = formatMsg(info, msg, arg))
       if not error.isNil:
         c.errorFlag = error
       else:
@@ -1237,7 +1280,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcNSetIntVal:
       decodeB(rkNode)
       var dest = regs[ra].node
-      if dest.kind in {nkCharLit..nkInt64Lit} and 
+      if dest.kind in {nkCharLit..nkInt64Lit} and
          regs[rb].kind in {rkInt}:
         dest.intVal = regs[rb].intVal
       else:
@@ -1245,24 +1288,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcNSetFloatVal:
       decodeB(rkNode)
       var dest = regs[ra].node
-      if dest.kind in {nkFloatLit..nkFloat64Lit} and 
+      if dest.kind in {nkFloatLit..nkFloat64Lit} and
          regs[rb].kind in {rkFloat}:
         dest.floatVal = regs[rb].floatVal
-      else: 
+      else:
         stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
     of opcNSetSymbol:
       decodeB(rkNode)
       var dest = regs[ra].node
       if dest.kind == nkSym and regs[rb].node.kind == nkSym:
         dest.sym = regs[rb].node.sym
-      else: 
+      else:
         stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
     of opcNSetIdent:
       decodeB(rkNode)
       var dest = regs[ra].node
       if dest.kind == nkIdent and regs[rb].node.kind == nkIdent:
         dest.ident = regs[rb].node.ident
-      else: 
+      else:
         stackTrace(c, tos, pc, errFieldXNotFound, "ident")
     of opcNSetType:
       decodeB(rkNode)
@@ -1273,7 +1316,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcNSetStrVal:
       decodeB(rkNode)
       var dest = regs[ra].node
-      if dest.kind in {nkStrLit..nkTripleStrLit} and 
+      if dest.kind in {nkStrLit..nkTripleStrLit} and
          regs[rb].kind in {rkNode}:
         dest.strVal = regs[rb].node.strVal
       else:
@@ -1356,9 +1399,11 @@ var
   globalCtx: PCtx
 
 proc setupGlobalCtx(module: PSym) =
-  if globalCtx.isNil: globalCtx = newCtx(module)
-  else: refresh(globalCtx, module)
-  registerAdditionalOps(globalCtx)
+  if globalCtx.isNil:
+    globalCtx = newCtx(module)
+    registerAdditionalOps(globalCtx)
+  else:
+    refresh(globalCtx, module)
 
 proc myOpen(module: PSym): PPassContext =
   #var c = newEvalContext(module, emRepl)
@@ -1397,8 +1442,9 @@ proc evalConstExprAux(module, prc: PSym, n: PNode, mode: TEvalMode): PNode =
   newSeq(tos.slots, c.prc.maxSlots)
   #for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
   result = rawExecute(c, start, tos).regToNode
+  if result.info.line < 0: result.info = n.info
 
-proc evalConstExpr*(module: PSym, e: PNode): PNode = 
+proc evalConstExpr*(module: PSym, e: PNode): PNode =
   result = evalConstExprAux(module, nil, e, emConst)
 
 proc evalStaticExpr*(module: PSym, e: PNode, prc: PSym): PNode =
@@ -1424,6 +1470,14 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
   inc(evalMacroCounter)
   if evalMacroCounter > 100:
     globalError(n.info, errTemplateInstantiationTooNested)
+
+  # immediate macros can bypass any type and arity checking so we check the
+  # arity here too:
+  if sym.typ.len > n.safeLen and sym.typ.len > 1:
+    globalError(n.info, "in call '$#' got $#, but expected $# argument(s)" % [
+        n.renderTree,
+        $ <n.safeLen, $ <sym.typ.len])
+
   setupGlobalCtx(module)
   var c = globalCtx
 
@@ -1439,6 +1493,7 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
   # This is wrong for tests/reject/tind1.nim where the passed 'else' part
   # doesn't end up in the parameter:
   #InternalAssert tos.slots.len >= L
+
   # return value:
   tos.slots[0].kind = rkNode
   tos.slots[0].node = newNodeIT(nkEmpty, n.info, sym.typ.sons[0])
@@ -1449,6 +1504,7 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
   # temporary storage:
   #for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty)
   result = rawExecute(c, start, tos).regToNode
+  if result.info.line < 0: result.info = n.info
   if cyclicTree(result): globalError(n.info, errCyclicTree)
   dec(evalMacroCounter)
   c.callsite = nil
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index c06606318..b4892d010 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -16,7 +16,7 @@ const
   byteExcess* = 128 # we use excess-K for immediates
   wordExcess* = 32768
 
-  MaxLoopIterations* = 500_000 # max iterations of all loops
+  MaxLoopIterations* = 1500_000 # max iterations of all loops
 
 
 type
@@ -29,7 +29,7 @@ type
     opcRet,         # return
     opcYldYoid,     # yield with no value
     opcYldVal,      # yield with a value
-    
+
     opcAsgnInt,
     opcAsgnStr,
     opcAsgnFloat,
@@ -48,8 +48,8 @@ type
     opcWrDeref,
     opcWrStrIdx,
     opcLdStrIdx, # a = b[c]
-    
-    opcAddInt, 
+
+    opcAddInt,
     opcAddImmInt,
     opcSubInt,
     opcSubImmInt,
@@ -58,36 +58,36 @@ type
 
     opcIncl, opcInclRange, opcExcl, opcCard, opcMulInt, opcDivInt, opcModInt,
     opcAddFloat, opcSubFloat, opcMulFloat, opcDivFloat, opcShrInt, opcShlInt,
-    opcBitandInt, opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu, 
-    opcDivu, opcModu, opcEqInt, opcLeInt, opcLtInt, opcEqFloat, 
-    opcLeFloat, opcLtFloat, opcLeu, opcLtu, opcEqRef, opcEqNimrodNode, opcXor, 
-    opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt, 
+    opcBitandInt, opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu,
+    opcDivu, opcModu, opcEqInt, opcLeInt, opcLtInt, opcEqFloat,
+    opcLeFloat, opcLtFloat, opcLeu, opcLtu, opcEqRef, opcEqNimrodNode, opcXor,
+    opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt,
     opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
     opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr,
     opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
     opcSwap, opcIsNil, opcOf, opcIs,
     opcSubStr, opcParseFloat, opcConv, opcCast, opcQuit, opcReset,
     opcNarrowS, opcNarrowU,
-    
+
     opcAddStrCh,
     opcAddStrStr,
     opcAddSeqElem,
     opcRangeChck,
-    
+
     opcNAdd,
     opcNAddMultiple,
-    opcNKind, 
-    opcNIntVal, 
-    opcNFloatVal, 
-    opcNSymbol, 
+    opcNKind,
+    opcNIntVal,
+    opcNFloatVal,
+    opcNSymbol,
     opcNIdent,
     opcNGetType,
     opcNStrVal,
-    
+
     opcNSetIntVal,
     opcNSetFloatVal, opcNSetSymbol, opcNSetIdent, opcNSetType, opcNSetStrVal,
     opcNNewNimNode, opcNCopyNimNode, opcNCopyNimTree, opcNDel, opcGenSym,
-    
+
     opcSlurp,
     opcGorge,
     opcParseExprToAst,
@@ -100,7 +100,7 @@ type
     opcEqIdent,
     opcStrToIdent,
     opcIdentToStr,
-    
+
     opcEcho,
     opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
     opcIndCallAsgn, # dest = call regStart, n; where regStart = fn, arg1, ...
@@ -110,7 +110,7 @@ type
     opcNSetChild,
     opcCallSite,
     opcNewStr,
-  
+
     opcTJmp,  # jump Bx if A != 0
     opcFJmp,  # jump Bx if A == 0
     opcJmp,   # jump Bx
@@ -164,7 +164,8 @@ type
     slotTempInt,      # some temporary int
     slotTempFloat,    # some temporary float
     slotTempStr,      # some temporary string
-    slotTempComplex   # some complex temporary (s.node field is used)
+    slotTempComplex,  # some complex temporary (s.node field is used)
+    slotTempPerm      # slot is temporary but permanent (hack)
 
   PProc* = ref object
     blocks*: seq[TBlock]    # blocks; temp data structure
@@ -177,13 +178,13 @@ type
     slots*: pointer
     currentException*: PNode
   VmCallback* = proc (args: VmArgs) {.closure.}
-  
+
   PCtx* = ref TCtx
   TCtx* = object of passes.TPassContext # code gen context
     code*: seq[TInstr]
     debug*: seq[TLineInfo]  # line info for every instruction; kept separate
                             # to not slow down interpretation
-    globals*: PNode         # 
+    globals*: PNode         #
     constants*: PNode       # constant data
     types*: seq[PType]      # some instructions reference types (e.g. 'except')
     currentExceptionA*, currentExceptionB*: PNode
@@ -202,7 +203,7 @@ type
   TPosition* = distinct int
 
   PEvalContext* = PCtx
-  
+
 proc newCtx*(module: PSym): PCtx =
   PCtx(code: @[], debug: @[],
     globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
@@ -212,6 +213,7 @@ proc newCtx*(module: PSym): PCtx =
 proc refresh*(c: PCtx, module: PSym) =
   c.module = module
   c.prc = PProc(blocks: @[])
+  c.loopIterations = MaxLoopIterations
 
 proc registerCallback*(c: PCtx; name: string; callback: VmCallback) =
   c.callbacks.add((name, callback))
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index 6673d0bd2..21ee4967b 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -1,13 +1,13 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2013 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
-import ast, types, msgs, osproc, streams, options
+import ast, types, msgs, osproc, streams, options, idents
 
 proc readOutput(p: Process): string =
   result = ""
@@ -19,13 +19,16 @@ proc readOutput(p: Process): string =
   discard p.waitForExit
 
 proc opGorge*(cmd, input: string): string =
-  var p = startCmd(cmd)
-  if input.len != 0:
-    p.inputStream.write(input)
-    p.inputStream.close()
-  result = p.readOutput
+  try:
+    var p = startProcess(cmd, options={poEvalCommand})
+    if input.len != 0:
+      p.inputStream.write(input)
+      p.inputStream.close()
+    result = p.readOutput
+  except IOError, OSError:
+    result = ""
 
-proc opSlurp*(file: string, info: TLineInfo, module: PSym): string = 
+proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
   try:
     let filename = file.findFile
     result = readFile(filename)
@@ -36,3 +39,124 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
   except IOError:
     localError(info, errCannotOpenFile, file)
     result = ""
+
+proc atomicTypeX(name: string; t: PType; info: TLineInfo): PNode =
+  let sym = newSym(skType, getIdent(name), t.owner, info)
+  sym.typ = t
+  result = newSymNode(sym)
+  result.typ = t
+
+proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode
+
+proc mapTypeToBracket(name: string; t: PType; info: TLineInfo): PNode =
+  result = newNodeIT(nkBracketExpr, info, t)
+  result.add atomicTypeX(name, t, info)
+  for i in 0 .. < t.len:
+    if t.sons[i] == nil:
+      let void = atomicTypeX("void", t, info)
+      void.typ = newType(tyEmpty, t.owner)
+      result.add void
+    else:
+      result.add mapTypeToAst(t.sons[i], info)
+
+proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode =
+  template atomicType(name): expr = atomicTypeX(name, t, info)
+
+  case t.kind
+  of tyNone: result = atomicType("none")
+  of tyBool: result = atomicType("bool")
+  of tyChar: result = atomicType("char")
+  of tyNil: result = atomicType("nil")
+  of tyExpr: result = atomicType("expr")
+  of tyStmt: result = atomicType("stmt")
+  of tyEmpty: result = atomicType"void"
+  of tyArrayConstr, tyArray:
+    result = newNodeIT(nkBracketExpr, info, t)
+    result.add atomicType("array")
+    result.add mapTypeToAst(t.sons[0], info)
+    result.add mapTypeToAst(t.sons[1], info)
+  of tyTypeDesc:
+    if t.base != nil:
+      result = newNodeIT(nkBracketExpr, info, t)
+      result.add atomicType("typeDesc")
+      result.add mapTypeToAst(t.base, info)
+    else:
+      result = atomicType"typeDesc"
+  of tyGenericInvocation:
+    result = newNodeIT(nkBracketExpr, info, t)
+    for i in 0 .. < t.len:
+      result.add mapTypeToAst(t.sons[i], info)
+  of tyGenericInst, tyGenericBody, tyOrdinal, tyUserTypeClassInst:
+    result = mapTypeToAst(t.lastSon, info)
+  of tyDistinct:
+    if allowRecursion:
+      result = mapTypeToBracket("distinct", t, info)
+    else:
+      result = atomicType(t.sym.name.s)
+  of tyGenericParam, tyForward: result = atomicType(t.sym.name.s)
+  of tyObject:
+    if allowRecursion:
+      result = newNodeIT(nkObjectTy, info, t)
+      if t.sons[0] == nil:
+        result.add ast.emptyNode
+      else:
+        result.add mapTypeToAst(t.sons[0], info)
+      result.add copyTree(t.n)
+    else:
+      result = atomicType(t.sym.name.s)
+  of tyEnum:
+    result = newNodeIT(nkEnumTy, info, t)
+    result.add copyTree(t.n)
+  of tyTuple: result = mapTypeToBracket("tuple", t, info)
+  of tySet: result = mapTypeToBracket("set", t, info)
+  of tyPtr: result = mapTypeToBracket("ptr", t, info)
+  of tyRef: result = mapTypeToBracket("ref", t, info)
+  of tyVar: result = mapTypeToBracket("var", t, info)
+  of tySequence: result = mapTypeToBracket("seq", t, info)
+  of tyProc: result = mapTypeToBracket("proc", t, info)
+  of tyOpenArray: result = mapTypeToBracket("openArray", t, info)
+  of tyRange:
+    result = newNodeIT(nkBracketExpr, info, t)
+    result.add atomicType("range")
+    result.add t.n.sons[0].copyTree
+    result.add t.n.sons[1].copyTree
+  of tyPointer: result = atomicType"pointer"
+  of tyString: result = atomicType"string"
+  of tyCString: result = atomicType"cstring"
+  of tyInt: result = atomicType"int"
+  of tyInt8: result = atomicType"int8"
+  of tyInt16: result = atomicType"int16"
+  of tyInt32: result = atomicType"int32"
+  of tyInt64: result = atomicType"int64"
+  of tyFloat: result = atomicType"float"
+  of tyFloat32: result = atomicType"float32"
+  of tyFloat64: result = atomicType"float64"
+  of tyFloat128: result = atomicType"float128"
+  of tyUInt: result = atomicType"uint"
+  of tyUInt8: result = atomicType"uint8"
+  of tyUInt16: result = atomicType"uint16"
+  of tyUInt32: result = atomicType"uint32"
+  of tyUInt64: result = atomicType"uint64"
+  of tyBigNum: result = atomicType"bignum"
+  of tyConst: result = mapTypeToBracket("const", t, info)
+  of tyMutable: result = mapTypeToBracket("mutable", t, info)
+  of tyVarargs: result = mapTypeToBracket("varargs", t, info)
+  of tyIter: result = mapTypeToBracket("iter", t, info)
+  of tyProxy: result = atomicType"error"
+  of tyBuiltInTypeClass: result = mapTypeToBracket("builtinTypeClass", t, info)
+  of tyUserTypeClass:
+    result = mapTypeToBracket("concept", t, info)
+    result.add t.n.copyTree
+  of tyCompositeTypeClass: result = mapTypeToBracket("compositeTypeClass", t, info)
+  of tyAnd: result = mapTypeToBracket("and", t, info)
+  of tyOr: result = mapTypeToBracket("or", t, info)
+  of tyNot: result = mapTypeToBracket("not", t, info)
+  of tyAnything: result = atomicType"anything"
+  of tyStatic, tyFromExpr, tyFieldAccessor:
+    result = newNodeIT(nkBracketExpr, info, t)
+    result.add atomicType("static")
+    if t.n != nil:
+      result.add t.n.copyTree
+
+proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode =
+  result = mapTypeToAst(t, info, true)
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 8b7dc293c..b354061a9 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -15,8 +15,8 @@
 #   this doesn't matter. However it matters for strings and other complex
 #   types that use the 'node' field; the reason is that slots are
 #   re-used in a register based VM. Example:
-# 
-# .. code-block:: nimrod
+#
+# .. code-block:: nim
 #   let s = a & b  # no matter what, create fresh node
 #   s = a & b  # no matter what, keep the node
 #
@@ -28,7 +28,7 @@
 # this copy depends on the involved types.
 
 import
-  unsigned, strutils, ast, astalgo, types, msgs, renderer, vmdef, 
+  unsigned, strutils, ast, astalgo, types, msgs, renderer, vmdef,
   trees, intsets, rodread, magicsys, options, lowerings
 
 from os import splitFile
@@ -58,22 +58,23 @@ proc codeListing(c: PCtx, result: var string, start=0; last = -1) =
     if i in jumpTargets: result.addf("L$1:\n", i)
     let x = c.code[i]
 
+    result.add($i)
     let opc = opcode(x)
     if opc in {opcConv, opcCast}:
       let y = c.code[i+1]
       let z = c.code[i+2]
       result.addf("\t$#\tr$#, r$#, $#, $#", ($opc).substr(3), x.regA, x.regB,
-        c.types[y.regBx-wordExcess].typeToString, 
+        c.types[y.regBx-wordExcess].typeToString,
         c.types[z.regBx-wordExcess].typeToString)
       inc i, 2
     elif opc < firstABxInstr:
-      result.addf("\t$#\tr$#, r$#, r$#", ($opc).substr(3), x.regA, 
+      result.addf("\t$#\tr$#, r$#, r$#", ($opc).substr(3), x.regA,
                   x.regB, x.regC)
     elif opc in relativeJumps:
       result.addf("\t$#\tr$#, L$#", ($opc).substr(3), x.regA,
                   i+x.regBx-wordExcess)
     elif opc in {opcLdConst, opcAsgnConst}:
-      result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA, 
+      result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA,
         c.constants[x.regBx-wordExcess].renderTree)
     else:
       result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA, x.regBx-wordExcess)
@@ -116,7 +117,7 @@ proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) =
   # Applies `opc` to `bx` and stores it into register `a`
   # `bx` must be signed and in the range [-32767, 32768]
   if bx >= -32767 and bx <= 32768:
-    let ins = (opc.uint32 or a.uint32 shl 8'u32 or 
+    let ins = (opc.uint32 or a.uint32 shl 8'u32 or
               (bx+wordExcess).uint32 shl 16'u32).TInstr
     c.code.add(ins)
     c.debug.add(n.info)
@@ -173,7 +174,7 @@ proc getTemp(c: PCtx; typ: PType): TRegister =
     if c.slots[i].kind == k and not c.slots[i].inUse:
       c.slots[i].inUse = true
       return TRegister(i)
-      
+
   # if register pressure is high, we re-use more aggressively:
   if c.maxSlots >= HighRegisterPressure:
     for i in 0 .. c.maxSlots-1:
@@ -188,7 +189,7 @@ proc getTemp(c: PCtx; typ: PType): TRegister =
 
 proc freeTemp(c: PCtx; r: TRegister) =
   let c = c.prc
-  if c.slots[r].kind >= slotSomeTemp: c.slots[r].inUse = false
+  if c.slots[r].kind in {slotSomeTemp..slotTempComplex}: c.slots[r].inUse = false
 
 proc getTempRange(c: PCtx; n: int; kind: TSlotKind): TRegister =
   # if register pressure is high, we re-use more aggressively:
@@ -207,7 +208,7 @@ proc getTempRange(c: PCtx; n: int; kind: TSlotKind): TRegister =
   result = TRegister(c.maxSlots)
   inc c.maxSlots, n
   for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind)
-  
+
 proc freeTempRange(c: PCtx; start: TRegister, n: int) =
   for i in start .. start+n-1: c.freeTemp(TRegister(i))
 
@@ -216,7 +217,7 @@ template withTemp(tmp, typ: expr, body: stmt) {.immediate, dirty.} =
   body
   c.freeTemp(tmp)
 
-proc popBlock(c: PCtx; oldLen: int) =  
+proc popBlock(c: PCtx; oldLen: int) =
   for f in c.prc.blocks[oldLen].fixups:
     c.patch(f)
   c.prc.blocks.setLen(oldLen)
@@ -367,11 +368,11 @@ proc sameConstant*(a, b: PNode): bool =
     case a.kind
     of nkSym: result = a.sym == b.sym
     of nkIdent: result = a.ident.id == b.ident.id
-    of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
+    of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal
     of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
     of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
-    of nkType: result = a.typ == b.typ
-    of nkEmpty, nkNilLit: result = true
+    of nkType, nkNilLit: result = a.typ == b.typ
+    of nkEmpty: result = true
     else:
       if sonsLen(a) == sonsLen(b):
         for i in countup(0, sonsLen(a) - 1):
@@ -385,7 +386,7 @@ proc genLiteral(c: PCtx; n: PNode): int =
   result = rawGenLiteral(c, n)
 
 proc unused(n: PNode; x: TDest) {.inline.} =
-  if x >= 0: 
+  if x >= 0:
     #debug(n)
     internalError(n.info, "not unused")
 
@@ -445,11 +446,11 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
       var blen = len(it)
       # first opcExcept contains the end label of the 'except' block:
       let endExcept = c.xjmp(it, opcExcept, 0)
-      for j in countup(0, blen - 2): 
+      for j in countup(0, blen - 2):
         assert(it.sons[j].kind == nkType)
         let typ = it.sons[j].typ.skipTypes(abstractPtrs-{tyTypeDesc})
         c.gABx(it, opcExcept, 0, c.genType(typ))
-      if blen == 1: 
+      if blen == 1:
         # general except section:
         c.gABx(it, opcExcept, 0, 0)
       c.gen(it.lastSon, dest)
@@ -463,7 +464,7 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
   # from the stack
   c.gABx(fin, opcFinally, 0, 0)
   if fin.kind == nkFinally:
-    c.gen(fin.sons[0], dest)
+    c.gen(fin.sons[0])
     c.clearDest(n, dest)
   c.gABx(fin, opcFinallyEnd, 0, 0)
 
@@ -497,7 +498,7 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) =
 template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar
 proc isGlobal(n: PNode): bool = n.kind == nkSym and isGlobal(n.sym)
 
-proc needsAsgnPatch(n: PNode): bool = 
+proc needsAsgnPatch(n: PNode): bool =
   n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr,
              nkDerefExpr, nkHiddenDeref} or (n.kind == nkSym and n.sym.isGlobal)
 
@@ -551,9 +552,9 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
 proc genNew(c: PCtx; n: PNode) =
   let dest = if needsAsgnPatch(n.sons[1]): c.getTemp(n.sons[1].typ)
              else: c.genx(n.sons[1])
-  # we use the ref's base type here as the VM conflates 'ref object' 
+  # we use the ref's base type here as the VM conflates 'ref object'
   # and 'object' since internally we already have a pointer.
-  c.gABx(n, opcNew, dest, 
+  c.gABx(n, opcNew, dest,
          c.genType(n.sons[1].typ.skipTypes(abstractVar-{tyTypeDesc}).sons[0]))
   c.genAsgnPatch(n.sons[1], dest)
   c.freeTemp(dest)
@@ -603,7 +604,8 @@ proc genNarrowU(c: PCtx; n: PNode; dest: TDest) =
   let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
   # uint is uint64 in the VM, we we only need to mask the result for
   # other unsigned types:
-  if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32}:
+  if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or
+      (t.kind == tyInt and t.size == 4):
     c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
 
 proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
@@ -655,7 +657,7 @@ proc genUnaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
 proc genVarargsABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
   if dest < 0: dest = getTemp(c, n.typ)
   var x = c.getTempRange(n.len-1, slotTempStr)
-  for i in 1..n.len-1: 
+  for i in 1..n.len-1:
     var r: TRegister = x+i-1
     c.gen(n.sons[i], r)
   c.gABC(n, opc, dest, x, n.len-1)
@@ -679,7 +681,7 @@ proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
     genBinaryABC(c, n, dest, opc)
   c.genNarrow(n, dest)
 
-proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =  
+proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
   let tmp = c.genx(arg)
   if dest < 0: dest = c.getTemp(n.typ)
   c.gABC(n, opc, dest, tmp)
@@ -740,9 +742,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     c.gABC(n, opcNewStr, dest, tmp)
     c.freeTemp(tmp)
     # XXX buggy
-  of mLengthOpenArray, mLengthArray, mLengthSeq:
+  of mLengthOpenArray, mLengthArray, mLengthSeq, mXLenSeq:
     genUnaryABI(c, n, dest, opcLenSeq)
-  of mLengthStr:
+  of mLengthStr, mXLenStr:
     genUnaryABI(c, n, dest, opcLenStr)
   of mIncl, mExcl:
     unused(n, dest)
@@ -789,13 +791,13 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     genUnaryABC(c, n, dest, opcUnaryMinusInt)
     genNarrow(c, n, dest)
   of mUnaryMinusF64: genUnaryABC(c, n, dest, opcUnaryMinusFloat)
-  of mUnaryPlusI, mUnaryPlusI64, mUnaryPlusF64: gen(c, n.sons[1], dest)
-  of mBitnotI, mBitnotI64: 
+  of mUnaryPlusI, mUnaryPlusF64: gen(c, n.sons[1], dest)
+  of mBitnotI, mBitnotI64:
     genUnaryABC(c, n, dest, opcBitnotInt)
     genNarrowU(c, n, dest)
   of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64,
-     mToU8, mToU16, mToU32, mToFloat, mToBiggestFloat, mToInt, 
-     mToBiggestInt, mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, 
+     mToU8, mToU16, mToU32, mToFloat, mToBiggestFloat, mToInt,
+     mToBiggestInt, mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr,
      mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
     genConv(c, n, n.sons[1], dest)
   of mEqStr: genBinaryABC(c, n, dest, opcEqStr)
@@ -823,7 +825,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     c.gABC(n, if m == mSetLengthStr: opcSetLenStr else: opcSetLenSeq, d, tmp)
     c.genAsgnPatch(n.sons[1], d)
     c.freeTemp(tmp)
-  of mSwap: 
+  of mSwap:
     unused(n, dest)
     var
       d1 = c.genx(n.sons[1])
@@ -872,7 +874,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     c.freeTemp(tmp1)
     c.freeTemp(tmp3)
     c.genAsgnPatch(d2AsNode, d2)
-    c.freeTemp(d2)    
+    c.freeTemp(d2)
   of mReset:
     unused(n, dest)
     var d = c.genx(n.sons[1])
@@ -892,7 +894,8 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
   of mHigh:
     if dest < 0: dest = c.getTemp(n.typ)
     let tmp = c.genx(n.sons[1])
-    if n.sons[1].typ.skipTypes(abstractVar-{tyTypeDesc}).kind == tyString:
+    case n.sons[1].typ.skipTypes(abstractVar-{tyTypeDesc}).kind:
+    of tyString, tyCString:
       c.gABI(n, opcLenStr, dest, tmp, 1)
     else:
       c.gABI(n, opcLenSeq, dest, tmp, 1)
@@ -910,7 +913,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
   of mAppendStrCh:
     unused(n, dest)
     genBinaryStmtVar(c, n, opcAddStrCh)
-  of mAppendStrStr: 
+  of mAppendStrStr:
     unused(n, dest)
     genBinaryStmtVar(c, n, opcAddStrStr)
   of mAppendSeqElem:
@@ -920,7 +923,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     genUnaryABC(c, n, dest, opcParseExprToAst)
   of mParseStmtToAst:
     genUnaryABC(c, n, dest, opcParseStmtToAst)
-  of mTypeTrait: 
+  of mTypeTrait:
     let tmp = c.genx(n.sons[1])
     if dest < 0: dest = c.getTemp(n.typ)
     c.gABx(n, opcSetType, tmp, c.genType(n.sons[1].typ))
@@ -947,24 +950,29 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
   of mNFloatVal: genUnaryABC(c, n, dest, opcNFloatVal)
   of mNSymbol: genUnaryABC(c, n, dest, opcNSymbol)
   of mNIdent: genUnaryABC(c, n, dest, opcNIdent)
-  of mNGetType: genUnaryABC(c, n, dest, opcNGetType)
+  of mNGetType:
+    let tmp = c.genx(n.sons[1])
+    if dest < 0: dest = c.getTemp(n.typ)
+    c.gABC(n, opcNGetType, dest, tmp, if n[0].sym.name.s == "typeKind": 1 else: 0)
+    c.freeTemp(tmp)
+    #genUnaryABC(c, n, dest, opcNGetType)
   of mNStrVal: genUnaryABC(c, n, dest, opcNStrVal)
   of mNSetIntVal:
     unused(n, dest)
     genBinaryStmt(c, n, opcNSetIntVal)
-  of mNSetFloatVal: 
+  of mNSetFloatVal:
     unused(n, dest)
     genBinaryStmt(c, n, opcNSetFloatVal)
   of mNSetSymbol:
     unused(n, dest)
     genBinaryStmt(c, n, opcNSetSymbol)
-  of mNSetIdent: 
+  of mNSetIdent:
     unused(n, dest)
     genBinaryStmt(c, n, opcNSetIdent)
   of mNSetType:
     unused(n, dest)
     genBinaryStmt(c, n, opcNSetType)
-  of mNSetStrVal: 
+  of mNSetStrVal:
     unused(n, dest)
     genBinaryStmt(c, n, opcNSetStrVal)
   of mNNewNimNode: genBinaryABC(c, n, dest, opcNNewNimNode)
@@ -982,10 +990,10 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
   of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent)
   of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqNimrodNode)
   of mNLineInfo: genUnaryABC(c, n, dest, opcNLineInfo)
-  of mNHint: 
+  of mNHint:
     unused(n, dest)
     genUnaryStmt(c, n, opcNHint)
-  of mNWarning: 
+  of mNWarning:
     unused(n, dest)
     genUnaryStmt(c, n, opcNWarning)
   of mNError:
@@ -1000,7 +1008,8 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     if dest < 0: dest = c.getTemp(n.typ)
     c.gABC(n, opcCallSite, dest)
   of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
-  of mMinI, mMaxI, mMinI64, mMaxI64, mAbsF64, mMinF64, mMaxF64, mAbsI, mAbsI64:
+  of mMinI, mMaxI, mAbsF64, mMinF64, mMaxF64, mAbsI,
+     mAbsI64, mDotDot:
     c.genCall(n, dest)
   of mExpandToAst:
     if n.len != 2:
@@ -1016,7 +1025,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     else:
       globalError(n.info, "expandToAst requires a call expression")
   else:
-    # mGCref, mGCunref, 
+    # mGCref, mGCunref,
     internalError(n.info, "cannot generate code for: " & $m)
 
 const
@@ -1048,7 +1057,7 @@ proc unneededIndirection(n: PNode): bool =
   n.typ.skipTypes(abstractInst-{tyTypeDesc}).kind == tyRef
 
 proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
-                  flags: TGenFlags) = 
+                  flags: TGenFlags) =
   # a nop for certain types
   let isAddr = opc in {opcAddrNode, opcAddrReg}
   let newflags = if isAddr: flags+{gfAddrOf} else: flags
@@ -1074,8 +1083,10 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
         c.gABC(n, opcNodeToReg, dest, dest)
     elif c.prc.slots[tmp].kind >= slotTempUnknown:
       gABC(c, n, opcAddrNode, dest, tmp)
-      # XXX this can still be wrong sometimes; hopefully it's only generated
-      # in call contexts, where it is safe
+      # hack ahead; in order to fix bug #1781 we mark the temporary as
+      # permanent, so that it's not used for anything else:
+      c.prc.slots[tmp].kind = slotTempPerm
+      # XXX this is still a hack
       #message(n.info, warnUser, "suspicious opcode used")
     else:
       gABC(c, n, opcAddrReg, dest, tmp)
@@ -1134,7 +1145,7 @@ proc checkCanEval(c: PCtx; n: PNode) =
   # proc foo() = var x ...
   let s = n.sym
   if {sfCompileTime, sfGlobal} <= s.flags: return
-  if s.kind in {skVar, skTemp, skLet, skParam, skResult} and 
+  if s.kind in {skVar, skTemp, skLet, skParam, skResult} and
       not s.isOwnedBy(c.prc.sym) and s.owner != c.module:
     cannotEval(n)
 
@@ -1241,8 +1252,8 @@ proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
   c.globals.add(getNullValue(s.typ, n.info))
   s.position = c.globals.len
   # This is rather hard to support, due to the laziness of the VM code
-  # generator. See tests/compile/tmacro2 for why this is necesary:
-  #   var decls{.compileTime.}: seq[PNimrodNode] = @[]
+  # generator. See tests/compile/tmacro2 for why this is necessary:
+  #   var decls{.compileTime.}: seq[NimNode] = @[]
   let dest = c.getTemp(s.typ)
   c.gABx(n, opcLdGlobal, dest, s.position)
   let tmp = c.genx(s.ast)
@@ -1328,30 +1339,32 @@ proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
   else:
     genArrAccess2(c, n, dest, opcLdArr, flags)
 
-proc getNullValueAux(obj: PNode, result: PNode) = 
+proc getNullValueAux(obj: PNode, result: PNode) =
   case obj.kind
   of nkRecList:
     for i in countup(0, sonsLen(obj) - 1): getNullValueAux(obj.sons[i], result)
   of nkRecCase:
     getNullValueAux(obj.sons[0], result)
-    for i in countup(1, sonsLen(obj) - 1): 
+    for i in countup(1, sonsLen(obj) - 1):
       getNullValueAux(lastSon(obj.sons[i]), result)
   of nkSym:
     addSon(result, getNullValue(obj.sym.typ, result.info))
   else: internalError(result.info, "getNullValueAux")
-  
-proc getNullValue(typ: PType, info: TLineInfo): PNode = 
+
+proc getNullValue(typ: PType, info: TLineInfo): PNode =
   var t = skipTypes(typ, abstractRange-{tyTypeDesc})
   result = emptyNode
   case t.kind
-  of tyBool, tyEnum, tyChar, tyInt..tyInt64: 
+  of tyBool, tyEnum, tyChar, tyInt..tyInt64:
     result = newNodeIT(nkIntLit, info, t)
   of tyUInt..tyUInt64:
     result = newNodeIT(nkUIntLit, info, t)
-  of tyFloat..tyFloat128: 
+  of tyFloat..tyFloat128:
     result = newNodeIT(nkFloatLit, info, t)
-  of tyVar, tyPointer, tyPtr, tyCString, tySequence, tyString, tyExpr,
-     tyStmt, tyTypeDesc, tyStatic, tyRef:
+  of tyCString, tyString:
+    result = newNodeIT(nkStrLit, info, t)
+  of tyVar, tyPointer, tyPtr, tySequence, tyExpr,
+     tyStmt, tyTypeDesc, tyStatic, tyRef, tyNil:
     result = newNodeIT(nkNilLit, info, t)
   of tyProc:
     if t.callConv != ccClosure:
@@ -1360,7 +1373,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
       result = newNodeIT(nkPar, info, t)
       result.add(newNodeIT(nkNilLit, info, t))
       result.add(newNodeIT(nkNilLit, info, t))
-  of tyObject: 
+  of tyObject:
     result = newNodeIT(nkPar, info, t)
     getNullValueAux(t.n, result)
     # initialize inherited fields:
@@ -1368,9 +1381,9 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
     while base != nil:
       getNullValueAux(skipTypes(base, skipPtrs).n, result)
       base = base.sons[0]
-  of tyArray, tyArrayConstr: 
+  of tyArray, tyArrayConstr:
     result = newNodeIT(nkBracket, info, t)
-    for i in countup(0, int(lengthOrd(t)) - 1): 
+    for i in countup(0, int(lengthOrd(t)) - 1):
       addSon(result, getNullValue(elemType(t), info))
   of tyTuple:
     result = newNodeIT(nkPar, info, t)
@@ -1378,7 +1391,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
       addSon(result, getNullValue(t.sons[i], info))
   of tySet:
     result = newNodeIT(nkCurly, info, t)
-  else: internalError("getNullValue: " & $t.kind)
+  else: internalError(info, "getNullValue: " & $t.kind)
 
 proc ldNullOpcode(t: PType): TOpcode =
   if fitsRegister(t): opcLdNullReg else: opcLdNull
@@ -1447,7 +1460,7 @@ proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
     c.gABx(n, opcNewSeq, dest, c.genType(seqType))
     c.gABx(n, opcNewSeq, tmp, 0)
     c.freeTemp(tmp)
-  
+
   if n.len > 0:
     var tmp = getTemp(c, intType)
     c.gABx(n, opcLdNullReg, tmp, c.genType(intType))
@@ -1524,7 +1537,7 @@ proc procIsCallback(c: PCtx; s: PSym): bool =
   if s.offset < -1: return true
   var i = -2
   for key, value in items(c.callbacks):
-    if s.matches(key): 
+    if s.matches(key):
       doAssert s.offset == -1
       s.offset = i
       return true
@@ -1570,9 +1583,9 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
       genLit(c, n, dest)
   of nkUIntLit..pred(nkNilLit): genLit(c, n, dest)
   of nkNilLit:
-    if not n.typ.isEmptyType: genLit(c, n, dest)
+    if not n.typ.isEmptyType: genLit(c, getNullValue(n.typ, n.info), dest)
     else: unused(n, dest)
-  of nkAsgn, nkFastAsgn: 
+  of nkAsgn, nkFastAsgn:
     unused(n, dest)
     genAsgn(c, n.sons[0], n.sons[1], n.kind == nkAsgn)
   of nkDotExpr: genObjAccess(c, n, dest, flags)
@@ -1597,7 +1610,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     genBreak(c, n)
   of nkTryStmt: genTry(c, n, dest)
   of nkStmtList:
-    unused(n, dest)
+    #unused(n, dest)
+    # XXX Fix this bug properly, lexim triggers it
     for x in n: gen(c, x)
   of nkStmtListExpr:
     let L = n.len-1
@@ -1610,6 +1624,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     gen(c, n.sons[0])
   of nkHiddenStdConv, nkHiddenSubConv, nkConv:
     genConv(c, n, n.sons[1], dest)
+  of nkObjDownConv:
+    genConv(c, n, n.sons[0], dest)
   of nkVarSection, nkLetSection:
     unused(n, dest)
     genVarSection(c, n)
@@ -1619,7 +1635,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     let s = n.sons[namePos].sym
     discard genProc(c, s)
     genLit(c, n.sons[namePos], dest)
-  of nkChckRangeF, nkChckRange64, nkChckRange: 
+  of nkChckRangeF, nkChckRange64, nkChckRange:
     let
       tmp0 = c.genx(n.sons[0])
       tmp1 = c.genx(n.sons[1])
@@ -1645,7 +1661,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     if allowCast in c.features:
       genConv(c, n, n.sons[1], dest, opcCast)
     else:
-      localError(n.info, errGenerated, "VM is not allowed to 'cast'")
+      globalError(n.info, errGenerated, "VM is not allowed to 'cast'")
   else:
     internalError n.info, "cannot generate VM code for " & n.renderTree
 
diff --git a/compiler/vmhooks.nim b/compiler/vmhooks.nim
index cce87d433..6ec5f6044 100644
--- a/compiler/vmhooks.nim
+++ b/compiler/vmhooks.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
diff --git a/compiler/vmops.nim b/compiler/vmops.nim
index ef2bfabb2..1023d4783 100644
--- a/compiler/vmops.nim
+++ b/compiler/vmops.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -10,7 +10,7 @@
 # Unforunately this cannot be a module yet:
 #import vmdeps, vm
 from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
-  arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc, 
+  arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc,
   floor, ceil, fmod
 
 from os import getEnv, existsEnv, dirExists, fileExists
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index f08ab0ad9..63fd995c4 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nim Compiler
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -13,44 +13,44 @@
 # does not support strings. Without this the code would
 # be slow and unreadable.
 
-import 
+import
   hashes, strutils, idents
 
 # Keywords must be kept sorted and within a range
 
 type
-  TSpecialWord* = enum 
-    wInvalid, 
-    
-    wAddr, wAnd, wAs, wAsm, wAtomic, 
-    wBind, wBlock, wBreak, wCase, wCast, wConst, 
-    wContinue, wConverter, wDefer, wDiscard, wDistinct, wDiv, wDo, 
+  TSpecialWord* = enum
+    wInvalid,
+
+    wAddr, wAnd, wAs, wAsm, wAtomic,
+    wBind, wBlock, wBreak, wCase, wCast, wConcept, wConst,
+    wContinue, wConverter, wDefer, wDiscard, wDistinct, wDiv, wDo,
     wElif, wElse, wEnd, wEnum, wExcept, wExport,
-    wFinally, wFor, wFrom, wGeneric, wIf, wImport, wIn, 
+    wFinally, wFor, wFrom, wFunc, wGeneric, wIf, wImport, wIn,
     wInclude, wInterface, wIs, wIsnot, wIterator, wLet,
-    wMacro, wMethod, wMixin, wMod, wNil, 
-    wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn, 
-    wShl, wShr, wStatic, wTemplate, wTry, wTuple, wType, wUsing, wVar, 
+    wMacro, wMethod, wMixin, wMod, wNil,
+    wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn,
+    wShl, wShr, wStatic, wTemplate, wTry, wTuple, wType, wUsing, wVar,
     wWhen, wWhile, wWith, wWithout, wXor, wYield,
-    
+
     wColon, wColonColon, wEquals, wDot, wDotDot,
     wStar, wMinus,
     wMagic, wThread, wFinal, wProfiler, wObjChecks,
 
     wDestroy,
-    
-    wImmediate, wDestructor, wDelegator, wOverride,
+
+    wImmediate, wConstructor, wDestructor, wDelegator, wOverride,
     wImportCpp, wImportObjC,
     wImportCompilerProc,
     wImportc, wExportc, wIncompleteStruct, wRequiresInit,
     wAlign, wNodecl, wPure, wSideeffect, wHeader,
-    wNosideeffect, wGcSafe, wNoreturn, wMerge, wLib, wDynlib, 
-    wCompilerproc, wProcVar, 
-    wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef, 
-    wLinedir, wStacktrace, wLinetrace, wLink, wCompile, 
-    wLinksys, wDeprecated, wVarargs, wCallconv, wBreakpoint, wDebugger, 
-    wNimcall, wStdcall, wCdecl, wSafecall, wSyscall, wInline, wNoInline, 
-    wFastcall, wClosure, wNoconv, wOn, wOff, wChecks, wRangechecks, 
+    wNosideeffect, wGcSafe, wNoreturn, wMerge, wLib, wDynlib,
+    wCompilerproc, wProcVar,
+    wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef,
+    wLinedir, wStacktrace, wLinetrace, wLink, wCompile,
+    wLinksys, wDeprecated, wVarargs, wCallconv, wBreakpoint, wDebugger,
+    wNimcall, wStdcall, wCdecl, wSafecall, wSyscall, wInline, wNoInline,
+    wFastcall, wClosure, wNoconv, wOn, wOff, wChecks, wRangechecks,
     wBoundchecks, wOverflowchecks, wNilchecks,
     wFloatchecks, wNanChecks, wInfChecks,
     wAssertions, wPatterns, wWarnings,
@@ -59,11 +59,11 @@ type
     wPragma,
     wCompileTime, wNoInit,
     wPassc, wPassl, wBorrow, wDiscardable,
-    wFieldChecks, 
-    wWatchPoint, wSubsChar, 
-    wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, 
+    wFieldChecks,
+    wWatchPoint, wSubsChar,
+    wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto,
     wInjectStmt, wExperimental,
-    wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit, 
+    wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
     wAsmNoStackFrame,
     wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wLocks,
 
@@ -82,38 +82,38 @@ type
     wStdIn, wStdOut, wStdErr,
 
     wInOut, wByCopy, wByRef, wOneWay,
-    
+
   TSpecialWords* = set[TSpecialWord]
 
-const 
+const
   oprLow* = ord(wColon)
   oprHigh* = ord(wDotDot)
-  
+
   nimKeywordsLow* = ord(wAsm)
   nimKeywordsHigh* = ord(wYield)
-  
+
   ccgKeywordsLow* = ord(wAuto)
   ccgKeywordsHigh* = ord(wOneWay)
-  
+
   cppNimSharedKeywords* = {
     wAsm, wBreak, wCase, wConst, wContinue, wDo, wElse, wEnum, wExport,
     wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile, wUsing}
 
-  specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["", 
-    
-    "addr", "and", "as", "asm", "atomic", 
-    "bind", "block", "break", "case", "cast", 
-    "const", "continue", "converter",
+  specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["",
+
+    "addr", "and", "as", "asm", "atomic",
+    "bind", "block", "break", "case", "cast",
+    "concept", "const", "continue", "converter",
     "defer", "discard", "distinct", "div", "do",
-    "elif", "else", "end", "enum", "except", "export", 
-    "finally", "for", "from", "generic", "if", 
+    "elif", "else", "end", "enum", "except", "export",
+    "finally", "for", "from", "func", "generic", "if",
     "import", "in", "include", "interface", "is", "isnot", "iterator",
     "let",
     "macro", "method", "mixin", "mod", "nil", "not", "notin",
-    "object", "of", "or", 
+    "object", "of", "or",
     "out", "proc", "ptr", "raise", "ref", "return",
     "shl", "shr", "static",
-    "template", "try", "tuple", "type", "using", "var", 
+    "template", "try", "tuple", "type", "using", "var",
     "when", "while", "with", "without", "xor",
     "yield",
 
@@ -122,22 +122,22 @@ const
     "magic", "thread", "final", "profiler", "objchecks",
 
     "destroy",
-    
-    "immediate", "destructor", "delegator", "override",
+
+    "immediate", "constructor", "destructor", "delegator", "override",
     "importcpp", "importobjc",
     "importcompilerproc", "importc", "exportc", "incompletestruct",
     "requiresinit", "align", "nodecl", "pure", "sideeffect",
-    "header", "nosideeffect", "gcsafe", "noreturn", "merge", "lib", "dynlib", 
-    "compilerproc", "procvar", "fatal", "error", "warning", "hint", "line", 
-    "push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace", 
-    "link", "compile", "linksys", "deprecated", "varargs", 
-    "callconv", "breakpoint", "debugger", "nimcall", "stdcall", 
+    "header", "nosideeffect", "gcsafe", "noreturn", "merge", "lib", "dynlib",
+    "compilerproc", "procvar", "fatal", "error", "warning", "hint", "line",
+    "push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace",
+    "link", "compile", "linksys", "deprecated", "varargs",
+    "callconv", "breakpoint", "debugger", "nimcall", "stdcall",
     "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "closure",
-    "noconv", "on", "off", "checks", "rangechecks", "boundchecks", 
+    "noconv", "on", "off", "checks", "rangechecks", "boundchecks",
     "overflowchecks", "nilchecks",
     "floatchecks", "nanchecks", "infchecks",
 
-    "assertions", "patterns", "warnings", "hints", 
+    "assertions", "patterns", "warnings", "hints",
     "optimization", "raises", "writes", "reads", "size", "effects", "tags",
     "deadcodeelim", "safecode", "noforward",
     "pragma",
@@ -149,7 +149,7 @@ const
     "write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
     "asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked",
     "guard", "locks",
-    
+
     "auto", "bool", "catch", "char", "class",
     "const_cast", "default", "delete", "double",
     "dynamic_cast", "explicit", "extern", "false",
@@ -169,22 +169,22 @@ const
     "inout", "bycopy", "byref", "oneway",
     ]
 
-proc findStr*(a: openArray[string], s: string): int = 
-  for i in countup(low(a), high(a)): 
-    if cmpIgnoreStyle(a[i], s) == 0: 
+proc findStr*(a: openArray[string], s: string): int =
+  for i in countup(low(a), high(a)):
+    if cmpIgnoreStyle(a[i], s) == 0:
       return i
   result = - 1
 
-proc whichKeyword*(id: PIdent): TSpecialWord = 
+proc whichKeyword*(id: PIdent): TSpecialWord =
   if id.id < 0: result = wInvalid
   else: result = TSpecialWord(id.id)
 
-proc whichKeyword*(id: string): TSpecialWord = 
+proc whichKeyword*(id: string): TSpecialWord =
   result = whichKeyword(getIdent(id))
-  
-proc initSpecials() = 
+
+proc initSpecials() =
   # initialize the keywords:
-  for s in countup(succ(low(specialWords)), high(specialWords)): 
+  for s in countup(succ(low(specialWords)), high(specialWords)):
     getIdent(specialWords[s], hashIgnoreStyle(specialWords[s])).id = ord(s)
-  
+
 initSpecials()
diff --git a/config/nim.cfg b/config/nim.cfg
index ef416323a..ccb9977db 100644
--- a/config/nim.cfg
+++ b/config/nim.cfg
@@ -1,14 +1,21 @@
 # Configuration file for the Nim Compiler.
-# (c) 2014 Andreas Rumpf
+# (c) 2015 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!
+# Environment variables can be accessed like so:
+#  gcc.path %= "$CC_PATH"
 
 cc = gcc
 
+# additional options always passed to the compiler:
+--parallel_build: "0" # 0 to auto-detect number of processors
+
+hint[LineTooLong]=off
+#hint[XDeclaredButNotUsed]=off
+
 # example of how to setup a cross-compiler:
 arm.linux.gcc.exe = "arm-linux-gcc"
 arm.linux.gcc.linkerexe = "arm-linux-gcc"
@@ -21,6 +28,7 @@ mips.linux.gcc.linkerexe = "mips-openwrt-linux-gcc"
 @end
 
 path="$lib/core"
+
 path="$lib/pure"
 path="$lib/pure/collections"
 path="$lib/pure/concurrency"
@@ -64,12 +72,6 @@ path="$lib/pure/unidecode"
   opt:speed
 @end
 
-# additional options always passed to the compiler:
---parallel_build: "0" # 0 to auto-detect number of processors
-
-hint[LineTooLong]=off
-#hint[XDeclaredButNotUsed]=off
-
 @if unix:
   @if not bsd:
     # -fopenmp
@@ -100,16 +102,46 @@ hint[LineTooLong]=off
   @end
 @end
 
-@if macosx:
+@if macosx or freebsd:
   cc = clang
   tlsEmulation:on
-  gcc.options.always = "-w -fasm-blocks"
-  gcc.cpp.options.always = "-w -fasm-blocks -fpermissive"
+  gcc.options.always = "-w"
+  gcc.cpp.options.always = "-w -fpermissive"
 @else:
-  gcc.options.always = "-w" 
+  gcc.options.always = "-w"
   gcc.cpp.options.always = "-w -fpermissive"
 @end
 
+# Configuration for Objective-C compiler:
+#
+# Options for GNUStep. GNUStep configuration varies wildly, so you'll probably
+# have to add additional compiler and linker flags on a per-project basis.
+gcc.objc.options.linker = "-lobjc -lgnustep-base"
+llvm_gcc.objc.options.linker = "-lobjc -lgnustep-base"
+clang.objc.options.linker = "-lobjc -lgnustep-base"
+
+# Options for Mac OS X. Mac OS X uses its own Objective-C stack that is
+# totally different from GNUStep.
+@if macosx:
+  gcc.objc.options.linker = "-framework Foundation"
+  llvm_gcc.objc.options.linker = "-framework Foundation"
+  clang.objc.options.linker = "-framework Foundation"
+@end
+
+# Configuration for the VxWorks
+# This has been tested with VxWorks 6.9 only
+@if vxworks:
+  # For now we only support compiling RTPs applications (i.e. no DKMs)
+  gcc.options.always = "-mrtp -fno-strict-aliasing -D_C99 -D_HAS_C9X -std=c99 -fasm -Wall -Wno-write-strings"
+  # The linker config must add the VxWorks common library for the selected
+  # processor which is usually found in:
+  # "$WIND_BASE/target/lib/usr/lib/PROCESSOR_FAMILY/PROCESSOR_TYPE/common",
+  # where PROCESSOR_FAMILY and PROCESSOR_TYPE are those supported by the VxWorks
+  # compiler (e.g. ppc/PPC32 or mips/MIPSI64, etc)
+  # For now we only support the PowerPC CPU
+  gcc.options.linker %= "-L $WIND_BASE/target/lib/usr/lib/ppc/PPC32/common -mrtp -fno-strict-aliasing -D_C99 -D_HAS_C9X -std=c99 -fasm -Wall -Wno-write-strings"
+@end
+
 gcc.options.speed = "-O3 -fno-strict-aliasing"
 gcc.options.size = "-Os"
 gcc.options.debug = "-g3 -O0"
@@ -135,7 +167,7 @@ clang.options.size = "-Os"
 vcc.options.linker = "/DEBUG /Zi /Fd\"$projectName.pdb\" /F33554432" # set the stack size to 8 MB
 vcc.options.debug = "/Zi /Fd\"$projectName.pdb\""
 vcc.options.always = "/nologo"
-vcc.options.speed = "/Ox /arch:SSE2"
+vcc.options.speed = "/O2 /arch:SSE2"
 vcc.options.size = "/O1"
 
 # Configuration for the Digital Mars C/C++ compiler:
diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg
index 975c7c06a..e036c3b9a 100644
--- a/config/nimdoc.cfg
+++ b/config/nimdoc.cfg
@@ -1,15 +1,15 @@
 # This is the config file for the documentation generator.
 # (c) 2012 Andreas Rumpf
 # Feel free to edit the templates as you need. If you modify this file, it
-# might be worth updating the hardcoded values in packages/docutils/rstgen.ni
+# might be worth updating the hardcoded values in packages/docutils/rstgen.nim
 
-split.item.toc = "20"  
+split.item.toc = "20"
 # too long entries in the table of contents wrap around
 # after this number of characters
 
 doc.section = """
 <div class="section" id="$sectionID">
-<h1><a class="toc-backref" href="#$sectionTitleID">$sectionTitle</a></h1>
+<h1><a class="toc-backref" href="#$sectionID">$sectionTitle</a></h1>
 <dl class="item">
 $content
 </dl></div>
@@ -17,14 +17,14 @@ $content
 
 doc.section.toc = """
 <li>
-  <a class="reference" href="#$sectionID" id="$sectionTitleID">$sectionTitle</a>
-  <ul class="simple">
+  <a class="reference reference-toplevel" href="#$sectionID" id="$sectionTitleID">$sectionTitle</a>
+  <ul class="simple simple-toc-section">
     $content
   </ul>
 </li>
 """
 
-# Chunk of HTML emmited for each entry in the HTML table of contents.
+# Chunk of HTML emitted for each entry in the HTML table of contents.
 # Available variables are:
 # * $desc: the actual docstring of the item.
 # * $header: the full version of name, including types, pragmas, tags, etc.
@@ -41,10 +41,11 @@ doc.item = """
 <dt id="$itemSym"><a name="$itemSymOrID"></a><pre>$header</pre></dt>
 <dd>
 $desc
+$seeSrc
 </dd>
 """
 
-# Chunk of HTML emmited for each entry in the HTML table of contents.
+# Chunk of HTML emitted for each entry in the HTML table of contents.
 # See doc.item for available substitution variables.
 doc.item.toc = """
   <li><a class="reference" href="#$itemSymOrID"
@@ -58,22 +59,25 @@ doc.item.toc = """
 # * $line: line of the item in the original source file.
 # * $url: whatever you did pass through the --docSeeSrcUrl switch (which also
 #   gets variables path/line replaced!)
-doc.item.seesrc = """<a
-href="https://github.com/Araq/Nimrod/blob/${url}/${path}#L${line}"
->See source</a>"""
+doc.item.seesrc = """&nbsp;&nbsp;<a
+href="${url}/${path}#L${line}"
+class="link-seesrc" target="_blank">Source</a>"""
 
 doc.toc = """
-<div class="navigation" id="navigation">
-<ul class="simple">
+<ul class="simple simple-toc" id="toc-list">
 $content
 </ul>
-</div>"""
+"""
 
 doc.body_toc = """
-$tableofcontents
-<div class="content" id="content">
-$moduledesc
-$content
+<div class="row">
+  <div class="three columns">
+  $tableofcontents
+  </div>
+  <div class="nine columns" id="content">
+  <p class="module-desc">$moduledesc</p>
+  $content
+  </div>
 </div>
 """
 
@@ -82,6 +86,7 @@ $moduledesc
 $content
 """
 
+# * $analytics: Google analytics location, includes <script> tags
 doc.file = """<?xml version="1.0" encoding="utf-8" ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
@@ -89,136 +94,783 @@ doc.file = """<?xml version="1.0" encoding="utf-8" ?>
 <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" />
+
+<!-- Favicon -->
+<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
+
+<!-- Google fonts -->
+<link href='http://fonts.googleapis.com/css?family=Raleway:400,600,900' rel='stylesheet' type='text/css'>
+<link href='http://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'>
+
+<!-- CSS -->
 <title>$title</title>
-<style type="text/css">
+<style type="text/css" >
+/*
+Stylesheet for use with Docutils/rst2html.
+
+See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
+customize this style sheet.
+
+Modified from Chad Skeeters' rst2html-style
+https://bitbucket.org/cskeeters/rst2html-style/
+
+Modified by Boyd Greenfield
+*/
+/* SCSS variables */
+/* Text weights */
+/* Body colors */
+/* Text colors */
+/* Link colors */
+/* Syntax highlighting colors */
+/* Pct changes */
+/* Mixins */
+/* Body/layout */
+html {
+  font-size: 100%;
+  -webkit-text-size-adjust: 100%;
+  -ms-text-size-adjust: 100%; }
+
+/* Where we want fancier font if available */
+h1, h2, h3, h4, h5, h6, p.module-desc, table.docinfo + blockquote p, table.docinfo blockquote p, h1 + blockquote p {
+  font-family: "Raleway", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif !important; }
+
+h1.title {
+  font-weight: 900; }
 
 body {
-  color: black;
-  background: white;
-}
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+  font-weight: 400;
+  font-size: 14px;
+  line-height: 20px;
+  color: #2d2d2d;
+  background-color: rgba(252, 248, 244, 0.75); }
 
-span.DecNumber {color: blue}
-span.BinNumber {color: blue}
-span.HexNumber {color: blue}
-span.OctNumber {color: blue}
-span.FloatNumber {color: blue}
-span.Identifier  {color: black}
-span.Keyword {font-weight: bold}
-span.StringLit {color: blue}
-span.LongStringLit {color: blue}
-span.CharLit {color: blue}
-span.EscapeSequence {color: black}
-span.Operator {color: black}
-span.Punctuation {color: black}
-span.Comment, span.LongComment {font-style:italic; color: green}
-span.RegularExpression  {color: DarkViolet}
-span.TagStart {color: DarkViolet}
-span.TagEnd {color: DarkViolet}
-span.Key  {color: blue}
-span.Value  {color: black}
-span.RawData {color: blue}
-span.Assembler  {color: blue}
-span.Preprocessor {color: DarkViolet}
-span.Directive  {color: DarkViolet}
-span.Command, span.Rule, span.Hyperlink, span.Label, span.Reference, 
-span.Other  {color: black}
-
-div.navigation {
-  -moz-border-radius: 5px 5px 5px 5px;
-  float: left; 
-  width: 30%;
-  margin: 0; padding: 0;
-  border: 3px outset #7F7F7F;
-  background-color: #7F7F7F;
-}
+/* Skeleton grid */
+.container {
+  position: relative;
+  width: 100%;
+  max-width: 960px;
+  margin: 0 auto;
+  padding: 0 20px;
+  box-sizing: border-box; }
 
-div.navigation ul {
-  list-style-type: none;
-  padding-left: 1em;
-}
-div.navigation ul li a, div.navigation ul li a:visited {
-  font-weight: bold;
-  color: #FFFFFF;
-  text-decoration: none;
-}
-div.navigation ul li a:hover {
+.column,
+.columns {
+  width: 100%;
+  float: left;
+  box-sizing: border-box; }
+
+/* For devices larger than 400px */
+@media (min-width: 400px) {
+  .container {
+    width: 100%;
+    padding: 0; } }
+/* For devices larger than 650px */
+@media (min-width: 650px) {
+  .container {
+    width: 100%; }
+
+  .column,
+  .columns {
+    margin-left: 4%; }
+
+  .column:first-child,
+  .columns:first-child {
+    margin-left: 0; }
+
+  .one.column,
+  .one.columns {
+    width: 4.66666666667%; }
+
+  .two.columns {
+    width: 13.3333333333%; }
+
+  .three.columns {
+    width: 22%; }
+
+  .four.columns {
+    width: 30.6666666667%; }
+
+  .five.columns {
+    width: 39.3333333333%; }
+
+  .six.columns {
+    width: 48%; }
+
+  .seven.columns {
+    width: 56.6666666667%; }
+
+  .eight.columns {
+    width: 65.3333333333%; }
+
+  .nine.columns {
+    width: 74.0%; }
+
+  .ten.columns {
+    width: 82.6666666667%; }
+
+  .eleven.columns {
+    width: 91.3333333333%; }
+
+  .twelve.columns {
+    width: 100%;
+    margin-left: 0; }
+
+  .one-third.column {
+    width: 30.6666666667%; }
+
+  .two-thirds.column {
+    width: 65.3333333333%; } }
+/* Customer Overrides */
+.footer {
+  text-align: center;
+  color: #969696;
+  padding-top: 10%; }
+
+p.module-desc {
+  font-size: 1.1em;
+  color: #666666; }
+
+a.link-seesrc {
+  color: #aec7d2;
+  font-style: italic; }
+
+a.link-seesrc:hover {
+  color: #6c9aae; }
+
+#toc-list {
+  word-wrap: break-word; }
+
+ul.simple-toc {
+  list-style: none; }
+
+ul.simple-toc a.reference-toplevel {
   font-weight: bold;
-  text-decoration: none;
-  color: gold;
-}
+  color: #0077b3; }
 
-div.content {
-  margin-left: 30%;
-  padding: 0 1em;
-  border-left: 4em;
-}
+ul.simple-toc-section {
+  list-style-type: circle;
+  color: #6c9aae; }
 
-dl.item dd, dl.item dd p {
-  margin-top:3px;
-}
-dl.item dd pre {
-  margin-left: 15pt;
-  border: 0px;
-}
-dl.item dt, dl.item dt pre {
-  margin:  20pt 0 0 5pt;
+ul.simple-toc-section a.reference {
+  color: #0077b3; }
+
+cite {
+  font-style: italic !important; }
+
+dt > pre {
+  border-color: rgba(0, 0, 0, 0.15);
+  background-color: transparent;
+  margin: 15px 0px 5px; }
+
+dd > pre {
+  border-color: rgba(0, 0, 0, 0.1);
+  background-color: whitesmoke;
+  margin-top: 8px; }
+
+.item > dd {
+  margin-left: 10px;
+  margin-bottom: 30px; }
+
+/* Nim line-numbered tables */
+.line-nums-table {
+  width: 100%;
+  table-layout: fixed; }
+
+table.line-nums-table {
+  border-radius: 4px;
+  border: 1px solid #cccccc;
+  background-color: whitesmoke;
+  border-collapse: separate;
+  margin-top: 15px;
+  margin-bottom: 25px; }
+
+.line-nums-table tbody {
+  border: none; }
+
+.line-nums-table td pre {
+  border: none;
+  background-color: transparent; }
+
+.line-nums-table td.blob-line-nums {
+  width: 28px; }
+
+.line-nums-table td.blob-line-nums pre {
+  color: #b0b0b0;
+  -webkit-filter: opacity(75%);
+  text-align: right;
+  border-color: transparent;
+  background-color: transparent;
+  padding-left: 0px;
+  margin-left: 0px;
+  padding-right: 0px;
+  margin-right: 0px; }
+
+/* Docgen styles */
+/* Links */
+a {
+  color: #0077b3;
+  text-decoration: none; }
+
+a:hover,
+a:focus {
+  color: #00334d;
+  text-decoration: underline; }
+
+a:visited {
+  color: #00334d; }
+
+a:focus {
+  outline: thin dotted #2d2d2d;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px; }
+
+a:hover,
+a:active {
+  outline: 0; }
+
+sub,
+sup {
+  position: relative;
+  font-size: 75%;
+  line-height: 0;
+  vertical-align: baseline; }
+
+sup {
+  top: -0.5em; }
+
+sub {
+  bottom: -0.25em; }
+
+img {
+  width: auto;
+  height: auto;
+  max-width: 100%;
+  vertical-align: middle;
+  border: 0;
+  -ms-interpolation-mode: bicubic; }
+
+@media print {
+  * {
+    color: black !important;
+    text-shadow: none !important;
+    background: transparent !important;
+    box-shadow: none !important; }
+
+  a,
+  a:visited {
+    text-decoration: underline; }
+
+  a[href]:after {
+    content: " (" attr(href) ")"; }
+
+  abbr[title]:after {
+    content: " (" attr(title) ")"; }
+
+  .ir a:after,
+  a[href^="javascript:"]:after,
+  a[href^="#"]:after {
+    content: ""; }
+
+  pre,
+  blockquote {
+    border: 1px solid #999;
+    page-break-inside: avoid; }
+
+  thead {
+    display: table-header-group; }
+
+  tr,
+  img {
+    page-break-inside: avoid; }
+
+  img {
+    max-width: 100% !important; }
+
+  @page {
+    margin: 0.5cm; }
+
+  h1 {
+    page-break-before: always; }
+
+  h1.title {
+    page-break-before: avoid; }
+
+  p,
+  h2,
+  h3 {
+    orphans: 3;
+    widows: 3; }
+
+  h2,
+  h3 {
+    page-break-after: avoid; } }
+.img-rounded {
+  -webkit-border-radius: 6px;
+  -moz-border-radius: 6px;
+  border-radius: 6px; }
+
+.img-polaroid {
+  padding: 4px;
+  background-color: rgba(252, 248, 244, 0.75);
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, 0.2);
+  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+  -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); }
+
+p {
+  margin: 0 0 12px; }
+
+small {
+  font-size: 85%; }
+
+strong {
+  font-weight: 600; }
+
+em {
+  font-style: italic; }
+
+cite {
+  font-style: normal; }
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+  font-weight: 600;
+  line-height: 20px;
+  color: inherit;
+  text-rendering: optimizelegibility; }
+
+h1 {
+  font-size: 2em;
+  padding-bottom: .15em;
+  border-bottom: 1px solid #aaaaaa;
+  margin-top: 1.0em;
+  line-height: 1.2em; }
+
+h1.title {
+  padding-bottom: 1em;
+  border-bottom: 0px;
+  font-size: 2.75em; }
+
+h2 {
+  font-size: 1.5em;
+  margin-top: 1.5em; }
+
+h3 {
+  font-size: 1.3em;
+  font-style: italic;
+  margin-top: 0.75em; }
+
+h4 {
+  font-size: 1.3em;
+  margin-top: 0.5em; }
+
+h5 {
+  font-size: 1.2em;
+  margin-top: 0.25em; }
+
+h6 {
+  font-size: 1.1em; }
+
+ul,
+ol {
+  padding: 0;
+  margin: 0 0 0px 15px; }
+
+ul ul,
+ul ol,
+ol ol,
+ol ul {
+  margin-bottom: 0; }
+
+li {
+  line-height: 20px; }
+
+dl {
+  margin-bottom: 20px; }
+
+dt,
+dd {
+  line-height: 20px; }
+
+dt {
+  font-weight: bold; }
+
+dd {
+  margin-left: 10px;
+  margin-bottom: 26px; }
+
+hr {
+  margin: 20px 0;
+  border: 0;
+  border-top: 1px solid #eeeeee;
+  border-bottom: 1px solid #ffffff; }
+
+abbr[title],
+abbr[data-original-title] {
+  cursor: help;
+  border-bottom: 1px dotted #999999; }
+
+abbr.initialism {
+  font-size: 90%;
+  text-transform: uppercase; }
+
+blockquote {
+  padding: 0 0 0 15px;
+  margin: 0 0 20px;
+  border-left: 5px solid #EFEBE0; }
+
+table.docinfo + blockquote, table.docinfo blockquote, h1 + blockquote {
+  border-left: 5px solid #c9c9c9;
 }
 
-pre, span.tok {
-  background-color: #F9F9F9;
-  border-color: #C4C4C4;
-  border-style: solid;
-  border-width: 1px 1px 1px 2px;
-  color: black;
-  line-spacing: 110%;
-  padding: 2px;
+table.docinfo + blockquote p, table.docinfo blockquote p, h1 + blockquote p {
+  margin-bottom: 0;
+  font-size: 15px;
+  font-weight: 200;
+  line-height: 1.5;
+  font-style: italic; }
+
+q:before,
+q:after,
+blockquote:before,
+blockquote:after {
+  content: ""; }
+
+address {
+  display: block;
+  margin-bottom: 20px;
+  font-style: normal;
+  line-height: 20px; }
+
+code,
+pre {
+  font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace;
+  padding: 0 3px 2px;
+  font-weight: 500;
+  font-size: 12px;
+  color: #444444;
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+  border-radius: 3px; }
+
+.pre {
+  font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace;
+  font-weight: 600;
+  /*color: #504da6;*/
 }
 
-span.red {
-  color: #A80000;
+code {
+  padding: 2px 4px;
+  color: #444444;
+  white-space: nowrap;
+  background-color: white;
+  border: 1px solid #777777; }
+
+pre {
+  display: inline-block;
+  box-sizing: border-box;
+  min-width: calc(100% - 19.5px);
+  padding: 9.5px;
+  margin: 0 10px 0px 10px;
+  font-size: 14px;
+  line-height: 20px;
+  white-space: pre !important;
+  overflow-y: hidden;
+  overflow-x: visible;
+  background-color: whitesmoke;
+  border: 1px solid #cccccc;
+  -webkit-border-radius: 4px;
+  -moz-border-radius: 4px;
+  border-radius: 4px; }
+
+pre.prettyprint {
+  margin-bottom: 20px; }
+
+pre code {
+  padding: 0;
+  color: inherit;
+  white-space: pre;
+  overflow-x: visible;
+  background-color: transparent;
+  border: 0; }
+
+.pre-scrollable {
+  max-height: 340px;
+  overflow-y: scroll; }
+
+table {
+  max-width: 100%;
+  background-color: transparent;
+  border-collapse: collapse;
+  border-spacing: 0; }
+
+table th, table td {
+  padding: 0px 8px 0px;
 }
 
-hr {background-color:#9D9D9D; border:0 none; color:#9D9D9D; height:1px; width:100%;}
+.table {
+  width: 100%;
+  margin-bottom: 20px; }
 
-/*
-:Author: David Goodger
-:Contact: goodger@python.org
-:Date: Date: 2006-05-21 22:44:42 +0200 (Sun, 21 May 2006)
-:Revision: Revision: 4564
-:Copyright: This stylesheet has been placed in the public domain.
+.table th,
+.table td {
+  padding: 8px;
+  line-height: 20px;
+  text-align: left;
+  vertical-align: top;
+  border-top: 1px solid #444444; }
 
-Default cascading style sheet for the HTML output of Docutils.
+.table th {
+  font-weight: bold; }
 
-See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
-customize this style sheet.
-*/
-/* used to remove borders from tables and images */
-.borderless, table.borderless td, table.borderless th { border: 0 }
+.table thead th {
+  vertical-align: bottom; }
+
+.table caption + thead tr:first-child th,
+.table caption + thead tr:first-child td,
+.table colgroup + thead tr:first-child th,
+.table colgroup + thead tr:first-child td,
+.table thead:first-child tr:first-child th,
+.table thead:first-child tr:first-child td {
+  border-top: 0; }
+
+.table tbody + tbody {
+  border-top: 2px solid #444444; }
+
+.table .table {
+  background-color: rgba(252, 248, 244, 0.75); }
+
+.table-condensed th,
+.table-condensed td {
+  padding: 4px 5px; }
+
+.table-bordered {
+  border: 1px solid #444444;
+  border-collapse: separate;
+  *border-collapse: collapse;
+  border-left: 0;
+  -webkit-border-radius: 4px;
+  -moz-border-radius: 4px;
+  border-radius: 4px; }
+
+.table-bordered th,
+.table-bordered td {
+  border-left: 1px solid #444444; }
+
+.table-bordered caption + thead tr:first-child th,
+.table-bordered caption + tbody tr:first-child th,
+.table-bordered caption + tbody tr:first-child td,
+.table-bordered colgroup + thead tr:first-child th,
+.table-bordered colgroup + tbody tr:first-child th,
+.table-bordered colgroup + tbody tr:first-child td,
+.table-bordered thead:first-child tr:first-child th,
+.table-bordered tbody:first-child tr:first-child th,
+.table-bordered tbody:first-child tr:first-child td {
+  border-top: 0; }
+
+.table-bordered thead:first-child tr:first-child > th:first-child,
+.table-bordered tbody:first-child tr:first-child > td:first-child,
+.table-bordered tbody:first-child tr:first-child > th:first-child {
+  -webkit-border-top-left-radius: 4px;
+  border-top-left-radius: 4px;
+  -moz-border-radius-topleft: 4px; }
+
+.table-bordered thead:first-child tr:first-child > th:last-child,
+.table-bordered tbody:first-child tr:first-child > td:last-child,
+.table-bordered tbody:first-child tr:first-child > th:last-child {
+  -webkit-border-top-right-radius: 4px;
+  border-top-right-radius: 4px;
+  -moz-border-radius-topright: 4px; }
+
+.table-bordered thead:last-child tr:last-child > th:first-child,
+.table-bordered tbody:last-child tr:last-child > td:first-child,
+.table-bordered tbody:last-child tr:last-child > th:first-child,
+.table-bordered tfoot:last-child tr:last-child > td:first-child,
+.table-bordered tfoot:last-child tr:last-child > th:first-child {
+  -webkit-border-bottom-left-radius: 4px;
+  border-bottom-left-radius: 4px;
+  -moz-border-radius-bottomleft: 4px; }
+
+.table-bordered thead:last-child tr:last-child > th:last-child,
+.table-bordered tbody:last-child tr:last-child > td:last-child,
+.table-bordered tbody:last-child tr:last-child > th:last-child,
+.table-bordered tfoot:last-child tr:last-child > td:last-child,
+.table-bordered tfoot:last-child tr:last-child > th:last-child {
+  -webkit-border-bottom-right-radius: 4px;
+  border-bottom-right-radius: 4px;
+  -moz-border-radius-bottomright: 4px; }
+
+.table-bordered tfoot + tbody:last-child tr:last-child td:first-child {
+  -webkit-border-bottom-left-radius: 0;
+  border-bottom-left-radius: 0;
+  -moz-border-radius-bottomleft: 0; }
+
+.table-bordered tfoot + tbody:last-child tr:last-child td:last-child {
+  -webkit-border-bottom-right-radius: 0;
+  border-bottom-right-radius: 0;
+  -moz-border-radius-bottomright: 0; }
+
+.table-bordered caption + thead tr:first-child th:first-child,
+.table-bordered caption + tbody tr:first-child td:first-child,
+.table-bordered colgroup + thead tr:first-child th:first-child,
+.table-bordered colgroup + tbody tr:first-child td:first-child {
+  -webkit-border-top-left-radius: 4px;
+  border-top-left-radius: 4px;
+  -moz-border-radius-topleft: 4px; }
+
+.table-bordered caption + thead tr:first-child th:last-child,
+.table-bordered caption + tbody tr:first-child td:last-child,
+.table-bordered colgroup + thead tr:first-child th:last-child,
+.table-bordered colgroup + tbody tr:first-child td:last-child {
+  -webkit-border-top-right-radius: 4px;
+  border-top-right-radius: 4px;
+  -moz-border-radius-topright: 4px; }
+
+table.docutils th {
+  background-color: #e8e8e8; }
+
+table.docutils tr:hover {
+  background-color: whitesmoke; }
+
+.table-striped tbody > tr:nth-child(odd) > td,
+.table-striped tbody > tr:nth-child(odd) > th {
+  background-color: rgba(252, 248, 244, 0.75); }
+
+.table-hover tbody tr:hover > td,
+.table-hover tbody tr:hover > th {
+  background-color: rgba(241, 222, 204, 0.75); }
+
+table td[class*="span"],
+table th[class*="span"],
+.row-fluid table td[class*="span"],
+.row-fluid table th[class*="span"] {
+  display: table-cell;
+  float: none;
+  margin-left: 0; }
+
+.hero-unit {
+  padding: 60px;
+  margin-bottom: 30px;
+  font-size: 18px;
+  font-weight: 200;
+  line-height: 30px;
+  color: inherit;
+  background-color: rgba(230, 197, 164, 0.75);
+  -webkit-border-radius: 6px;
+  -moz-border-radius: 6px;
+  border-radius: 6px; }
+
+.hero-unit h1 {
+  margin-bottom: 0;
+  font-size: 60px;
+  line-height: 1;
+  letter-spacing: -1px;
+  color: inherit; }
+
+.hero-unit li {
+  line-height: 30px; }
+
+/* rst2html default used to remove borders from tables and images */
+.borderless, table.borderless td, table.borderless th {
+  border: 0; }
 
 table.borderless td, table.borderless th {
   /* Override padding for "table.docutils td" with "! important".
      The right padding separates the table cells. */
-  padding: 0 0.5em 0 0 ! important }
-
-.first { margin-top: 0 ! important }
-.last, .with-subtitle { margin-bottom: 0 ! important }
-.hidden { display: none }
-a.toc-backref { text-decoration: none ; color: black }
-blockquote.epigraph { margin: 2em 5em ; }
-dl.docutils dd { margin-bottom: 0.5em }
-div.abstract { margin: 2em 5em }
-div.abstract p.topic-title { font-weight: bold ; text-align: center }
+  padding: 0 0.5em 0 0 !important; }
+
+.first {
+  /* Override more specific margin styles with "! important". */
+  margin-top: 0 !important; }
+
+.last, .with-subtitle {
+  margin-bottom: 0 !important; }
+
+.hidden {
+  display: none; }
+
+a.toc-backref {
+  text-decoration: none;
+  color: #444444; }
+
+blockquote.epigraph {
+  margin: 2em 5em; }
+
+dl.docutils dd {
+  margin-bottom: 0.5em; }
+
+object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
+  overflow: hidden; }
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+  font-weight: bold }
+*/
+div.abstract {
+  margin: 2em 5em; }
+
+div.abstract p.topic-title {
+  font-weight: bold;
+  text-align: center; }
+
 div.admonition, div.attention, div.caution, div.danger, div.error,
 div.hint, div.important, div.note, div.tip, div.warning {
-  margin: 2em ; border: medium outset ; padding: 1em }
+  margin: 2em;
+  border: medium outset;
+  padding: 1em; }
+
+div.note, div.warning {
+  margin: 1.5em 0px;
+  border: none; }
+
+div.note p.admonition-title,
+div.warning p.admonition-title {
+  display: none; }
+
+/* Clearfix
+ * http://css-tricks.com/snippets/css/clear-fix/
+ */
+div.note:after,
+div.warning:after {
+  content: "";
+  display: table;
+  clear: both; }
+
+div.note p:before,
+div.warning p:before {
+  display: block;
+  float: left;
+  font-size: 4em;
+  line-height: 1em;
+  margin-right: 20px;
+  margin-left: 0em;
+  margin-top: -10px;
+  content: '\0270D';
+  /*handwriting*/ }
+
+div.warning p:before {
+  content: '\026A0';
+  /*warning*/ }
+
 div.admonition p.admonition-title, div.hint p.admonition-title,
 div.important p.admonition-title, div.note p.admonition-title,
-div.tip p.admonition-title { font-weight: bold ; font-family: sans-serif }
+div.tip p.admonition-title {
+  font-weight: bold;
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; }
 
 div.attention p.admonition-title, div.caution p.admonition-title,
 div.danger p.admonition-title, div.error p.admonition-title,
-div.warning p.admonition-title { color: red ; font-weight: bold ;
-  font-family: sans-serif }
+div.warning p.admonition-title, .code .error {
+  color: #b30000;
+  font-weight: bold;
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; }
 
 /* Uncomment (and remove this text!) to get reduced vertical space in
    compound paragraphs.
@@ -228,109 +880,372 @@ div.compound .compound-first, div.compound .compound-middle {
 div.compound .compound-last, div.compound .compound-middle {
   margin-top: 0.5em }
 */
+div.dedication {
+  margin: 2em 5em;
+  text-align: center;
+  font-style: italic; }
+
+div.dedication p.topic-title {
+  font-weight: bold;
+  font-style: normal; }
+
+div.figure {
+  margin-left: 2em;
+  margin-right: 2em; }
+
+div.footer, div.header {
+  clear: both;
+  font-size: smaller; }
+
+div.line-block {
+  display: block;
+  margin-top: 1em;
+  margin-bottom: 1em; }
+
+div.line-block div.line-block {
+  margin-top: 0;
+  margin-bottom: 0;
+  margin-left: 1.5em; }
+
+div.sidebar {
+  margin: 0 0 0.5em 1em;
+  border: medium outset;
+  padding: 1em;
+  background-color: rgba(252, 248, 244, 0.75);
+  width: 40%;
+  float: right;
+  clear: right; }
+
+div.sidebar p.rubric {
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+  font-size: medium; }
+
+div.system-messages {
+  margin: 5em; }
+
+div.system-messages h1 {
+  color: #b30000; }
+
+div.system-message {
+  border: medium outset;
+  padding: 1em; }
+
+div.system-message p.system-message-title {
+  color: #b30000;
+  font-weight: bold; }
+
+div.topic {
+  margin: 2em; }
 
-div.dedication { margin: 2em 5em ; text-align: center ; font-style: italic }
-div.dedication p.topic-title { font-weight: bold ; font-style: normal }
-div.figure { margin-left: 2em ; margin-right: 2em }
-div.footer, div.header { clear: both; font-size: smaller }
-div.line-block { display: block ; margin-top: 1em ; margin-bottom: 1em }
-div.line-block div.line-block { margin-top: 0 ; margin-bottom: 0 ;
-  margin-left: 1.5em }
-div.sidebar { margin-left: 1em ; border: medium outset ;
-  padding: 1em ; background-color: #ffffee ; /*width: 40% ;*/ float: right ;
-  clear: right }
-
-div.sidebar p.rubric { font-family: sans-serif ; font-size: medium }
-div.system-messages { margin: 5em }
-div.system-messages h1 { color: red }
-div.system-message { border: medium outset ; padding: 1em }
-div.system-message p.system-message-title { color: red ; font-weight: bold }
-div.topic { margin: 2em;}
 h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
 h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
-  margin-top: 0.4em }
-h1.title { text-align: center }
-h2.subtitle { text-align: center }
-/* hr.docutils { width: 75% } */
-img.align-left { clear: left }
-img.align-right { clear: right }
-ol.simple, ul.simple { margin-bottom: 1em }
-ol.arabic { list-style: decimal }
-ol.loweralpha { list-style: lower-alpha }
-ol.upperalpha { list-style: upper-alpha }
-ol.lowerroman { list-style: lower-roman }
-ol.upperroman { list-style: upper-roman }
-p.attribution { text-align: right ; margin-left: 50% }
-p.caption { font-style: italic }
-p.credits { font-style: italic ; font-size: smaller }
-p.label { white-space: nowrap }
-p.rubric { font-weight:bold;font-size:larger;color:maroon;text-align:center}
-p.sidebar-title {font-family: sans-serif ;font-weight: bold ;font-size: larger }
-p.sidebar-subtitle {font-family: sans-serif ; font-weight: bold }
+  margin-top: 0.4em; }
+
+h1.title {
+  text-align: center; }
+
+h2.subtitle {
+  text-align: center; }
+
+hr.docutils {
+  width: 75%; }
+
+img.align-left, .figure.align-left, object.align-left {
+  clear: left;
+  float: left;
+  margin-right: 1em; }
+
+img.align-right, .figure.align-right, object.align-right {
+  clear: right;
+  float: right;
+  margin-left: 1em; }
+
+img.align-center, .figure.align-center, object.align-center {
+  display: block;
+  margin-left: auto;
+  margin-right: auto; }
+
+.align-left {
+  text-align: left; }
+
+.align-center {
+  clear: both;
+  text-align: center; }
+
+.align-right {
+  text-align: right; }
+
+/* reset inner alignment in figures */
+div.align-right {
+  text-align: inherit; }
+
+/* div.align-center * { */
+/*   text-align: left } */
+ol.simple, ul.simple {
+  margin-bottom: 1em; }
+
+ol.arabic {
+  list-style: decimal; }
+
+ol.loweralpha {
+  list-style: lower-alpha; }
+
+ol.upperalpha {
+  list-style: upper-alpha; }
+
+ol.lowerroman {
+  list-style: lower-roman; }
+
+ol.upperroman {
+  list-style: upper-roman; }
+
+p.attribution {
+  text-align: right;
+  margin-left: 50%; }
+
+p.caption {
+  font-style: italic; }
+
+p.credits {
+  font-style: italic;
+  font-size: smaller; }
+
+p.label {
+  white-space: nowrap; }
+
+p.rubric {
+  font-weight: bold;
+  font-size: larger;
+  color: maroon;
+  text-align: center; }
+
+p.sidebar-title {
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+  font-weight: bold;
+  font-size: larger; }
+
+p.sidebar-subtitle {
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+  font-weight: bold; }
+
 p.topic-title {
-font-weight: bold;
-background-color: #6D6D6D;
-border-bottom: 1px solid #000000;
-border-top: 1px solid black;
-color: white;
-text-align: center;
-margin: 0;
-}
-pre.address { margin-bottom: 0;margin-top:0;font-family:serif;font-size:100% }
-pre.literal-block, pre.doctest-block {margin-left: 2em ;margin-right: 2em }
-span.classifier {font-family: sans-serif;font-style: oblique }
-span.classifier-delimiter {font-family: sans-serif;font-weight: bold }
-span.interpreted {font-family: sans-serif }
-span.option {white-space: nowrap }
-span.pre {white-space: pre }
-span.problematic {color: red }
+  font-weight: bold; }
+
+pre.address {
+  margin-bottom: 0;
+  margin-top: 0;
+  font: inherit; }
+
+pre.literal-block, pre.doctest-block, pre.math, pre.code {
+  margin-left: 2em;
+  margin-right: 2em; }
+
+pre.code .ln {
+  color: grey; }
+
+/* line numbers */
+pre.code, code {
+  background-color: #eeeeee; }
+
+pre.code .comment, code .comment {
+  color: #5c6576; }
+
+pre.code .keyword, code .keyword {
+  color: #3B0D06;
+  font-weight: bold; }
+
+pre.code .literal.string, code .literal.string {
+  color: #0c5404; }
+
+pre.code .name.builtin, code .name.builtin {
+  color: #352b84; }
+
+pre.code .deleted, code .deleted {
+  background-color: #DEB0A1; }
+
+pre.code .inserted, code .inserted {
+  background-color: #A3D289; }
+
+span.classifier {
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+  font-style: oblique; }
+
+span.classifier-delimiter {
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+  font-weight: bold; }
+
+span.interpreted {
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; }
+
+span.option {
+  white-space: nowrap; }
+
+span.pre {
+  white-space: pre; }
+
+span.problematic {
+  color: #b30000; }
+
 span.section-subtitle {
   /* font-size relative to parent (h1..h6 element) */
-  font-size: 80% }
+  font-size: 80%; }
 
-table.citation { border-left: solid 1px gray; margin-left: 1px }
-table.docinfo {margin: 2em 4em }
-table.docutils {margin-top: 0.5em;margin-bottom: 0.5em; border: 0 solid #9d9d9d; border-collapse: collapse; }
-table.footnote {border-left: solid 1px black;margin-left: 1px }
+table.citation {
+  border-left: solid 1px #666666;
+  margin-left: 1px; }
 
-table.docutils td, table.docutils th,
-table.docinfo td, table.docinfo th {padding-left: 0.5em;padding-right: 0.5em;
-  vertical-align: top;}
+table.docinfo {
+  margin: 0em;
+  margin-top: 2em;
+  margin-bottom: 2em;
+  font-family: "Raleway", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif !important;
+  color: #444444; }
 
-table.docutils td, table.docutils th { border-bottom:1px solid #9D9D9D; }
-/* color: #4d4d4d} */
+table.docutils {
+  margin-top: 0.5em;
+  margin-bottom: 0.5em; }
 
-/* table.docutils td:hover, table.docinfo td:hover {color: #000000} */
-  
+table.footnote {
+  border-left: solid 1px #2d2d2d;
+  margin-left: 1px; }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+  padding-left: 0.5em;
+  padding-right: 0.5em;
+  vertical-align: top; }
 
 table.docutils th.field-name, table.docinfo th.docinfo-name {
-  font-weight: bold;text-align: left;white-space: nowrap;padding-left: 0 }
-  
-table.docutils th
-{
-color: black;
-font-weight:normal;
-background-color: #E3E3E3;
-border-top: 1px solid #1d1d1d;
-border-bottom: 1px solid #1d1d1d;
-}
-  
+  font-weight: 700;
+  text-align: left;
+  white-space: nowrap;
+  padding-left: 0; }
+
 h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
-h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {font-size: 100% }
-ul.auto-toc { list-style-type: none }
-/*a.reference { color: #E00000; font-weight:bold;}
-a.reference:hover {color: #E00000;background-color: #ffff00;display: margin;
-  font-weight:bold;}*/
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+  font-size: 100%; }
+
+ul.auto-toc {
+  list-style-type: none; }
+
+span.DecNumber {
+  color: #252dbe; }
+
+span.BinNumber {
+  color: #252dbe; }
+
+span.HexNumber {
+  color: #252dbe; }
+
+span.OctNumber {
+  color: #252dbe; }
+
+span.FloatNumber {
+  color: #252dbe; }
+
+span.Identifier {
+  color: #3b3b3b; }
+
+span.Keyword {
+  font-weight: 600;
+  color: #5e8f60; }
+
+span.StringLit {
+  color: #a4255b; }
+
+span.LongStringLit {
+  color: #a4255b; }
+
+span.CharLit {
+  color: #a4255b; }
+
+span.EscapeSequence {
+  color: black; }
+
+span.Operator {
+  color: black; }
+
+span.Punctuation {
+  color: black; }
 
+span.Comment, span.LongComment {
+  font-style: italic;
+  font-weight: 400;
+  color: #484a86; }
+
+span.RegularExpression {
+  color: darkviolet; }
+
+span.TagStart {
+  color: darkviolet; }
+
+span.TagEnd {
+  color: darkviolet; }
+
+span.Key {
+  color: #252dbe; }
+
+span.Value {
+  color: #252dbe; }
+
+span.RawData {
+  color: #a4255b; }
+
+span.Assembler {
+  color: #252dbe; }
+
+span.Preprocessor {
+  color: #252dbe; }
+
+span.Directive {
+  color: #252dbe; }
+
+span.Command, span.Rule, span.Hyperlink, span.Label, span.Reference,
+span.Other {
+  color: black; }
+
+/* Pop type, const, proc, and iterator defs in nim def blocks */
+dt pre > span.Identifier, dt pre > span.Operator {
+  color: #155da4;
+  font-weight: 700; }
+
+dt pre > span.Identifier ~ span.Identifier, dt pre > span.Operator ~ span.Identifier {
+  color: inherit;
+  font-weight: inherit; }
+
+dt pre > span.Operator ~ span.Identifier, dt pre > span.Operator ~ span.Operator {
+  color: inherit;
+  font-weight: inherit; }
+
+/* Nim sprite for the footer (taken from main page favicon) */
+.nim-sprite {
+  display: inline-block;
+  height: 12px;
+  width: 12px;
+  background-position: 0 0;
+  background-size: 12px 12px;
+  -webkit-filter: opacity(50%);
+  background-repeat: no-repeat;
+  background-image: url("data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA==");
+  margin-bottom: -5px; }
 </style>
 
 </head>
 <body>
 <div class="document" id="documentId">
-<h1 class="title">$title</h1>
-$content
-<small>Generated: $date $time UTC</small>
+  <div class="container">
+    <h1 class="title">$title</h1>
+    $content
+    <div class="row">
+      <div class="twelve-columns footer">
+        <span class="nim-sprite"></span>
+        <br>
+        <small>Made with Nim. Generated: $date $time UTC</small>
+      </div>
+    </div>
+  </div>
 </div>
+$analytics
 </body>
 </html>
 """
diff --git a/config/nimrod.cfg b/config/nimrod.cfg
deleted file mode 100644
index b7210b329..000000000
--- a/config/nimrod.cfg
+++ /dev/null
@@ -1,136 +0,0 @@
-# Configuration file for the Nim Compiler.
-# (c) 2014 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!
-
-cc = gcc
-
-# example of how to setup a cross-compiler:
-arm.linux.gcc.exe = "arm-linux-gcc"
-arm.linux.gcc.linkerexe = "arm-linux-gcc"
-
-cs:partial
-
-path="$lib/core"
-path="$lib/pure"
-path="$lib/pure/collections"
-path="$lib/pure/concurrency"
-path="$lib/impure"
-path="$lib/wrappers"
-# path="$lib/wrappers/cairo"
-# path="$lib/wrappers/gtk"
-# path="$lib/wrappers/lua"
-# path="$lib/wrappers/opengl"
-path="$lib/wrappers/pcre"
-path="$lib/wrappers/readline"
-path="$lib/wrappers/sdl"
-# path="$lib/wrappers/x11"
-path="$lib/wrappers/zip"
-path="$lib/wrappers/libffi"
-path="$lib/windows"
-path="$lib/posix"
-path="$lib/js"
-path="$lib/pure/unidecode"
-
-@if nimbabel:
-  babelpath="$home/.babel/pkgs/"
-@end
-
-@if release or quick:
-  obj_checks:off
-  field_checks:off
-  range_checks:off
-  bound_checks:off
-  overflow_checks:off
-  assertions:off
-  stacktrace:off
-  linetrace:off
-  debugger:off
-  line_dir:off
-  dead_code_elim:on
-@end
-
-@if release:
-  opt:speed
-@end
-
-# additional options always passed to the compiler:
---parallel_build: "0" # 0 to auto-detect number of processors
-
-hint[LineTooLong]=off
-#hint[XDeclaredButNotUsed]=off
-
-@if unix:
-  @if not bsd:
-    # -fopenmp
-    gcc.options.linker = "-ldl"
-    gpp.options.linker = "-ldl"
-    clang.options.linker = "-ldl"
-    tcc.options.linker = "-ldl"
-  @end
-  @if bsd or haiku:
-    # BSD got posix_spawn only recently, so we deactivate it for osproc:
-    define:useFork
-    # at least NetBSD has problems with thread local storage:
-    tlsEmulation:on
-  @end
-@end
-
-# Configuration for the Intel C/C++ compiler:
-@if windows:
-  icl.options.speed = "/Ox /arch:SSE2"
-  icl.options.always = "/nologo"
-@end
-
-# Configuration for the GNU C/C++ compiler:
-@if windows:
-  #gcc.path = r"$nimrod\dist\mingw\bin"
-  @if gcc:
-    tlsEmulation:on
-  @end
-@end
-
-@if macosx:
-  cc = clang
-  tlsEmulation:on
-  gcc.options.always = "-w -fasm-blocks"
-  gpp.options.always = "-w -fasm-blocks -fpermissive"
-@else:
-  gcc.options.always = "-w"
-  gpp.options.always = "-w -fpermissive"
-@end
-
-gcc.options.speed = "-O3 -fno-strict-aliasing"
-gcc.options.size = "-Os"
-gcc.options.debug = "-g3 -O0"
-
-gpp.options.speed = "-O3 -fno-strict-aliasing"
-gpp.options.size = "-Os"
-gpp.options.debug = "-g3 -O0"
-#passl = "-pg"
-
-# Configuration for the LLVM GCC compiler:
-llvm_gcc.options.debug = "-g"
-llvm_gcc.options.always = "-w"
-llvm_gcc.options.speed = "-O2"
-llvm_gcc.options.size = "-Os"
-
-# Configuration for the LLVM CLang compiler:
-clang.options.debug = "-g"
-clang.options.always = "-w"
-clang.options.speed = "-O3"
-clang.options.size = "-Os"
-
-# Configuration for the Visual C/C++ compiler:
-vcc.options.linker = "/DEBUG /Zi /Fd\"$projectName.pdb\" /F33554432" # set the stack size to 8 MB
-vcc.options.debug = "/Zi /Fd\"$projectName.pdb\""
-vcc.options.always = "/nologo"
-vcc.options.speed = "/Ox /arch:SSE2"
-vcc.options.size = "/O1"
-
-# Configuration for the Tiny C Compiler:
-tcc.options.always = "-w"
diff --git a/copying.txt b/copying.txt
index 254b91c77..d89bace0b 100644
--- a/copying.txt
+++ b/copying.txt
@@ -1,7 +1,7 @@
 =====================================================
-Nimrod -- a Compiler for Nimrod. http://nimrod-lang.org/
+Nim -- a Compiler for Nim. http://nim-lang.org/
 
-Copyright (C) 2006-2014 Andreas Rumpf. All rights reserved.
+Copyright (C) 2006-2015 Andreas Rumpf. All rights reserved.
  
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/doc/advopt.txt b/doc/advopt.txt
index 78c3d571a..195122cc7 100644
--- a/doc/advopt.txt
+++ b/doc/advopt.txt
@@ -12,19 +12,6 @@ Advanced commands:
                             module dependency graph
   //dump                    dump all defined conditionals and search paths
   //check                   checks the project for syntax and semantic
-  //idetools                compiler support for IDEs: possible options:
-    --track:FILE,LINE,COL   track a file/cursor position
-    --trackDirty:DIRTY_FILE,ORIG_FILE,LINE,COL
-                            track a file, currently not saved to disk
-    --suggest               suggest all possible symbols at position
-    --def                   list all possible definitions at position
-    --context               list possible invokation context
-    --usages                list all usages of the symbol at position
-    --eval                  evaluates an expression
-  //serve                   start the compiler as a service mode (CAAS)
-    --server.type:TYPE      either stdin or tcp
-    --server.port:PORT      port for tcp mode, by default 6000
-    --server.address:HOST   binds to that address, by default ""
 
 Advanced options:
   -o, --out:FILE            set the output filename
@@ -48,7 +35,6 @@ Advanced options:
   --os:SYMBOL               set the target operating system (cross-compilation)
   --cpu:SYMBOL              set the target processor (cross-compilation)
   --debuginfo               enables debug information
-  --debugger:on|off         turn Embedded Nim Debugger on|off
   -t, --passC:OPTION        pass an option to the C compiler
   -l, --passL:OPTION        pass an option to the linker
   --cincludes:DIR           modify the C compiler header search path
@@ -66,7 +52,6 @@ Advanced options:
   --threadanalysis:on|off   turn thread analysis on|off
   --tlsEmulation:on|off     turn thread local storage emulation on|off
   --taintMode:on|off        turn taint mode on|off
-  --symbolFiles:on|off      turn symbol files on|off (experimental)
   --implicitStatic:on|off   turn implicit compile time evaluation on|off
   --patterns:on|off         turn pattern matching on|off
   --skipCfg                 do not read the general configuration file
@@ -83,13 +68,11 @@ Advanced options:
   --dynlibOverride:SYMBOL   marks SYMBOL so that dynlib:SYMBOL
                             has no effect and can be statically linked instead;
                             symbol matching is fuzzy so
-                            that --dynlibOverride:lua matches 
+                            that --dynlibOverride:lua matches
                             dynlib: "liblua.so.3"
   --listCmd                 list the commands used to execute external programs
-  --parallelBuild=0|1|...   perform a parallel build
+  --parallelBuild:0|1|...   perform a parallel build
                             value = number of processors (0 for auto-detect)
   --verbosity:0|1|2|3       set Nim's verbosity level (1 is default)
-  --cs:none|partial         set case sensitivity level (default: none);
-                            do not use! this setting affects the whole language
   --experimental            enable experimental language features
   -v, --version             show detailed version information
diff --git a/doc/apis.txt b/doc/apis.txt
index e0510d85f..165279490 100644
--- a/doc/apis.txt
+++ b/doc/apis.txt
@@ -79,10 +79,3 @@ string                  str
 identifier              ident
 indentation             indent
 -------------------     ------------   --------------------------------------
-
-
-Coding Guidelines
-=================
-
-For coding guidelines see the `Internals of the Nim Compiler
-<intern.html#coding-guidelines>`_ documentation.
diff --git a/doc/astspec.txt b/doc/astspec.txt
index 5c4274093..4c27272e2 100644
--- a/doc/astspec.txt
+++ b/doc/astspec.txt
@@ -1,14 +1,14 @@
 The AST in Nim
 =================
 This section describes how the AST is modelled with Nim's type system.
-The AST consists of nodes (``PNimrodNode``) with a variable number of
+The AST consists of nodes (``NimNode``) with a variable number of
 children. Each node has a field named ``kind`` which describes what the node
 contains:
 
 .. code-block:: nim
 
   type
-    TNimrodNodeKind = enum ## kind of a node; only explanatory
+    NimNodeKind = enum     ## kind of a node; only explanatory
       nnkNone,             ## invalid node kind
       nnkEmpty,            ## empty node
       nnkIdent,            ## node contains an identifier
@@ -18,11 +18,11 @@ contains:
       nnkCaseStmt,         ## node represents a case statement
       ...                  ## many more
 
-    PNimrodNode = ref TNimrodNode
-    TNimrodNode {.final.} = object
-      case kind: TNimrodNodeKind       ## the node's kind
+    NimNode = ref NimNodeObj
+    NimNodeObj = object
+      case kind: NimNodeKind           ## the node's kind
       of nnkNone, nnkEmpty, nnkNilLit:
-        nil                            ## node contains no additional fields
+        discard                        ## node contains no additional fields
       of nnkCharLit..nnkInt64Lit:
         intVal: biggestInt             ## the int literal
       of nnkFloatLit..nnkFloat64Lit:
@@ -30,13 +30,13 @@ contains:
       of nnkStrLit..nnkTripleStrLit:
         strVal: string                 ## the string literal
       of nnkIdent:
-        ident: TNimrodIdent            ## the identifier
+        ident: NimIdent                ## the identifier
       of nnkSym:
-        symbol: PNimrodSymbol          ## the symbol (after symbol lookup phase)
+        symbol: NimSymbol              ## the symbol (after symbol lookup phase)
       else:
-        sons: seq[PNimrodNode]         ## the node's sons (or children)
+        sons: seq[NimNode]             ## the node's sons (or children)
 
-For the ``PNimrodNode`` type, the ``[]`` operator has been overloaded:
+For the ``NimNode`` type, the ``[]`` operator has been overloaded:
 ``n[i]`` is ``n``'s ``i``-th child.
 
 To specify the AST for the different Nim constructs, the notation
@@ -73,10 +73,7 @@ Nim expression                   corresponding AST
 -----------------                ---------------------------------------------
 
 Identifiers are ``nnkIdent`` nodes. After the name lookup pass these nodes
-get transferred into ``nnkSym`` nodes. However, a macro receives an AST that
-has not been checked for semantics and thus the identifiers have not been
-looked up. Macros should deal with ``nnkIdent`` nodes and do not need to deal
-with ``nnkSym`` nodes.
+get transferred into ``nnkSym`` nodes.
 
 
 Calls/expressions
@@ -171,13 +168,13 @@ AST:
           nnkStrLit("hallo"))
 
 
-Dereference operator ``^``
---------------------------
+Dereference operator ``[]``
+---------------------------
 
 Concrete syntax:
 
 .. code-block:: nim
-  x^
+  x[]
 
 AST:
 
@@ -573,4 +570,3 @@ Other node kinds are especially designed to make AST manipulations easier.
 These are explained here. 
 
 To be written.
-
diff --git a/doc/backends.txt b/doc/backends.txt
index eb16217cd..c7939baec 100644
--- a/doc/backends.txt
+++ b/doc/backends.txt
@@ -225,7 +225,7 @@ The JavaScript target doesn't have any further interfacing considerations
 since it also has garbage collection, but the C targets require you to
 initialize Nim's internals, which is done calling a ``NimMain`` function.
 Also, C code requires you to specify a forward declaration for functions or
-the compiler will asume certain types for the return value and parameters
+the compiler will assume certain types for the return value and parameters
 which will likely make your program crash at runtime.
 
 The Nim compiler can generate a C interface header through the ``--header``
@@ -335,18 +335,18 @@ Nimcache and C like targets
 
 The C like backends will place their temporary ``.c``, ``.cpp`` or ``.m`` files
 in the ``nimcache`` directory. The naming of these files follows the pattern
-``babelPackageName_`` + ``nimSource``:
+``nimblePackageName_`` + ``nimSource``:
 
-* Filenames for modules imported from `Babel packages
-  <https://github.com/nim-code/babel>`_ will end up with
-  ``babelPackageName_module.c``. For example, if you import the
-  ``argument_parser`` module from the same name Babel package you
+* Filenames for modules imported from `nimble packages
+  <https://github.com/nim-lang/nimble>`_ will end up with
+  ``nimblePackageName_module.c``. For example, if you import the
+  ``argument_parser`` module from the same name nimble package you
   will end up with a ``argument_parser_argument_parser.c`` file
-  under ``nimcache``.  The name of the Babel package comes from the
-  ``proj.babel`` file, the actual contents are not read by the
+  under ``nimcache``.  The name of the nimble package comes from the
+  ``proj.nimble`` file, the actual contents are not read by the
   compiler.
 
-* Filenames for non babel packages (like your project) will be
+* Filenames for non nimble packages (like your project) will be
   renamed from ``.nim`` to have the extension of your target backend
   (from now on ``.c`` for these examples), but otherwise nothing
   else will change. This will quickly break if your project consists
@@ -360,13 +360,13 @@ in the ``nimcache`` directory. The naming of these files follows the pattern
   module <system.html>`_ is always imported automatically. Same for
   the `hashes module <hashes.html>`_ which will be named
   ``stdlib_hashes.c``. The ``stdlib_`` prefix comes from the *fake*
-  ``lib/stdlib.babel`` file.
+  ``lib/stdlib.nimble`` file.
 
-To find the name of a Babel package the compiler searches for a ``*.babel``
+To find the name of a nimble package the compiler searches for a ``*.nimble``
 file in the parent directory hierarchy of whatever module you are compiling.
-Even if you are in a subdirectory of your project, a parent ``*.babel`` file
+Even if you are in a subdirectory of your project, a parent ``*.nimble`` file
 will influence the naming of the nimcache name. This means that on Unix systems
-creating the file ``~/foo.babel`` will automatically prefix all nimcache files
+creating the file ``~/foo.nimble`` will automatically prefix all nimcache files
 not part of another package with the string ``foo_``.
 
 
@@ -427,7 +427,7 @@ Custom data types
 -----------------
 
 Just like strings, custom data types that are to be shared between Nim and
-the backend will need careful consideration of who controlls who. If you want
+the backend will need careful consideration of who controls who. If you want
 to hand a Nim reference to C code, you will need to use `GC_ref
 <system.html#GC_ref>`_ to mark the reference as used, so it does not get
 freed. And for the C backend you will need to expose the `GC_unref
@@ -456,11 +456,7 @@ can then attach a GC to this thread via
 
 .. code-block:: nim
 
-  setStackBottom(addr(someLocal))
-  initGC()
-
-At the moment this support is still experimental so you need to expose these
-functions yourself or submit patches to request a public API. 
+  system.setupForeignThreadGc()
 
 It is **not** safe to disable the garbage collector and enable it after the
 call from your background thread even if the code you are calling is short
diff --git a/doc/basicopt.txt b/doc/basicopt.txt
index e8aaa2e4c..6a905bd53 100644
--- a/doc/basicopt.txt
+++ b/doc/basicopt.txt
@@ -1,11 +1,11 @@
-Usage::
-  nim command [options] [projectfile] [arguments]
+::
+
+    nim command [options] [projectfile] [arguments]
 
 Command:
   //compile, c                compile project with default code generator (C)
   //doc                       generate the documentation for inputfile
   //doc2                      generate the documentation for the whole project
-  //i                         start Nim in interactive mode (limited)
 
 Arguments:
   arguments are passed to the program being run (if --run option is selected)
@@ -13,7 +13,6 @@ Options:
   -p, --path:PATH           add path to search paths
   -d, --define:SYMBOL       define a conditional symbol
   -u, --undef:SYMBOL        undefine a conditional symbol
-  --symbol:SYMBOL           declare a conditional symbol
   -f, --forceBuild          force rebuilding of all modules
   --stackTrace:on|off       turn stack tracing on|off
   --lineTrace:on|off        turn line tracing on|off
@@ -30,10 +29,12 @@ Options:
   --infChecks:on|off        turn Inf checks on|off
   --deadCodeElim:on|off     whole program dead code elimination on|off
   --opt:none|speed|size     optimize not at all or for speed|size
+                            Note: use -d:release for a release build!
+  --debugger:native|endb    use native debugger (gdb) | ENDB (experimental)
   --app:console|gui|lib|staticlib
                             generate a console app|GUI app|DLL|static library
   -r, --run                 run the compiled program with given arguments
   --advanced                show advanced command line switches
   -h, --help                show this help
 
-Note: Even single letter options require the colon: -p:PATH.
+Note, single letter options that take an argument require a colon. E.g. -p:PATH.
diff --git a/doc/docgen.txt b/doc/docgen.txt
index 554f69838..40c464ebd 100644
--- a/doc/docgen.txt
+++ b/doc/docgen.txt
@@ -31,13 +31,13 @@ documentation with only their well-documented code.
 Example:
 
 .. code-block:: nim
-  type TPerson* = object
+  type Person* = object
     ## This type contains a description of a person
     name: string
     age: int
 
 Outputs::
-  TPerson* = object
+  Person* = object
     name: string
     age: int
 
@@ -195,7 +195,7 @@ In the case of Nim's own documentation, the ``txt`` value is just a commit
 hash to append to a formatted URL to https://github.com/Araq/Nim. The
 ``tools/nimweb.nim`` helper queries the current git commit hash during doc
 generation, but since you might be working on an unpublished repository, it
-also allows specifying a ``githash`` value in ``web/nim.ini`` to force a
+also allows specifying a ``githash`` value in ``web/website.ini`` to force a
 specific commit in the output.
 
 
@@ -268,8 +268,8 @@ The relationship of type to suffix is made by the proc ``complexName`` in the
 ``compiler/docgen.nim`` file. Here are some examples of complex names for
 symbols in the `system module <system.html>`_.
 
-* ``type TSignedInt = int | int8 | int16 | int32 | int64`` **=>**
-  `#TSignedInt <system.html#TSignedInt>`_
+* ``type SignedInt = int | int8 | int16 | int32 | int64`` **=>**
+  `#SignedInt <system.html#SignedInt>`_
 * ``var globalRaiseHook: proc (e: ref E_Base): bool {.nimcall.}`` **=>**
   `#globalRaiseHook <system.html#globalRaiseHook>`_
 * ``const NimVersion = "0.0.0"`` **=>**
@@ -307,7 +307,7 @@ columns is:
    Nim's rules (eg. \`^\` like in `the actors module
    <actors.html#^,ptr.TChannel[T]>`_).
 2. Base filename plus anchor hyper link (eg.
-   ``algorithm.html#*,int,TSortOrder``).
+   ``algorithm.html#*,int,SortOrder``).
 3. Optional human readable string to display as hyper link. If the value is not
    present or is the empty string, the hyper link will be rendered
    using the term. Prefix whitespace indicates that this entry is
diff --git a/doc/filters.txt b/doc/filters.txt
index 22df63490..e725321e6 100644
--- a/doc/filters.txt
+++ b/doc/filters.txt
@@ -173,7 +173,7 @@ The template engine is quite flexible. It is easy to produce a procedure that
 writes the template code directly to a file::
 
   #! stdtmpl(emit="f.write") | standard
-  #proc writeHTMLPage(f: TFile, title, currentTab, content: string,
+  #proc writeHTMLPage(f: File, title, currentTab, content: string,
   #                   tabs: openArray[string]) = 
   <head><title>$title</title></head>
   <body>
diff --git a/doc/gc.txt b/doc/gc.txt
index 9398262d9..f51421bcd 100644
--- a/doc/gc.txt
+++ b/doc/gc.txt
@@ -2,11 +2,15 @@
 Nim's Garbage Collector
 ==========================
 
-:Author: Andreas Rumpf

-:Version: |nimversion|

+:Author: Andreas Rumpf
+:Version: |nimversion|
+
+..
+
 
   "The road to hell is paved with good intentions."
 
+
 Introduction
 ============
 
@@ -19,7 +23,7 @@ code generation). The GC **never** scans the whole heap but it may scan the
 delta-subgraph of the heap that changed since its last run.
 
 
-The GC is only triggered in a memory allocation operation. It it not triggered
+The GC is only triggered in a memory allocation operation. It is not triggered
 by some timer and does not run in a background thread.
 
 To force a full collection call ``GC_fullCollect``. Note that it is generally
@@ -83,14 +87,14 @@ is triggered.
 Time measurement
 ----------------
 
-The GC's way of measing time uses (see ``lib/system/timers.nim`` for the 
+The GC's way of measuring time uses (see ``lib/system/timers.nim`` for the 
 implementation):
 
 1) ``QueryPerformanceCounter`` and ``QueryPerformanceFrequency`` on Windows.
 2) ``mach_absolute_time`` on Mac OS X.
 3) ``gettimeofday`` on Posix systems.
 
-As such it supports a resolution of nano seconds internally; however the API
+As such it supports a resolution of nanoseconds internally; however the API
 uses microseconds for convenience. 
 
 
diff --git a/doc/grammar.txt b/doc/grammar.txt
index e751c2d8d..72dc6c974 100644
--- a/doc/grammar.txt
+++ b/doc/grammar.txt
@@ -3,17 +3,13 @@ comma = ',' COMMENT?
 semicolon = ';' COMMENT?
 colon = ':' COMMENT?
 colcom = ':' COMMENT?
-
-operator =  OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9 | OP10
+operator =  OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9
          | 'or' | 'xor' | 'and'
          | 'is' | 'isnot' | 'in' | 'notin' | 'of'
-         | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'addr' | 'static' | '..'
-
+         | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'static' | '..'
 prefixOperator = operator
-
 optInd = COMMENT?
 optPar = (IND{>} | IND{=})?
-
 simpleExpr = arrowExpr (OP0 optInd arrowExpr)*
 arrowExpr = assignExpr (OP1 optInd assignExpr)*
 assignExpr = orExpr (OP2 optInd orExpr)*
@@ -26,20 +22,20 @@ plusExpr = mulExpr (OP8 optInd mulExpr)*
 mulExpr = dollarExpr (OP9 optInd dollarExpr)*
 dollarExpr = primary (OP10 optInd primary)*
 symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
-       | IDENT
+       | IDENT | 'addr' | 'type'
 indexExpr = expr
 indexExprList = indexExpr ^+ comma
 exprColonEqExpr = expr (':'|'=' expr)?
 exprList = expr ^+ comma
-dotExpr = expr '.' optInd ('type' | 'addr' | symbol)
-qualifiedIdent = symbol ('.' optInd ('type' | 'addr' | symbol))?
+dotExpr = expr '.' optInd symbol
+qualifiedIdent = symbol ('.' optInd symbol)?
 exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)?
 setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}'
 castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')'
 parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try'
         | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let'
         | 'when' | 'var' | 'mixin'
-par = '(' optInd (&parKeyw complexOrSimpleStmt ^+ ';' 
+par = '(' optInd (&parKeyw complexOrSimpleStmt ^+ ';'
                  | simpleExpr ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )?
                             | (':' expr)? (',' (exprColonEqExpr comma?)*)?  )?
         optPar ')'
@@ -56,11 +52,11 @@ identOrLiteral = generalizedLit | symbol | literal
 tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
 arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']'
 primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
-              | doBlocks
-              | '.' optInd ('type' | 'addr' | symbol) generalizedLit?
-              | '[' optInd indexExprList optPar ']'
-              | '{' optInd indexExprList optPar '}'
-              | &( '`'|IDENT|literal|'cast') expr # command syntax
+      | doBlocks
+      | '.' optInd symbol generalizedLit?
+      | '[' optInd indexExprList optPar ']'
+      | '{' optInd indexExprList optPar '}'
+      | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax
 condExpr = expr colcom expr optInd
         ('elif' expr colcom expr optInd)*
          'else' colcom expr
@@ -77,6 +73,7 @@ inlTupleDecl = 'tuple'
     [' optInd  (identColonEquals (comma/semicolon)?)*  optPar ']'
 extTupleDecl = 'tuple'
     COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
+tupleClass = 'tuple'
 paramList = '(' declColonEquals ^* (comma/semicolon) ')'
 paramListArrow = paramList? ('->' optInd typeDesc)?
 paramListColon = paramList? (':' optInd typeDesc)?
@@ -89,17 +86,16 @@ expr = (ifExpr
       | caseExpr
       | tryExpr)
       / simpleExpr
-typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'type' | 'tuple'
+typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'tuple'
          | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum'
 primary = typeKeyw typeDescK
         /  prefixOperator* identOrLiteral primarySuffix*
-        / 'addr' primary
         / 'static' primary
         / 'bind' primary
 typeDesc = simpleExpr
 typeDefAux = simpleExpr
-           | 'generic' typeClass
-macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt 
+           | 'concept' typeClass
+macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
                        | IND{=} 'elif' expr ':' stmt
                        | IND{=} 'except' exprList ':' stmt
                        | IND{=} 'else' ':' stmt )*
@@ -167,7 +163,7 @@ objectCase = 'case' identWithPragma ':' typeDesc ':'? COMMENT?
             (IND{>} objectBranches DED
             | IND{=} objectBranches)
 objectPart = IND{>} objectPart^+IND{=} DED
-           / objectWhen / objectCase / 'nil' / declColonEquals
+           / objectWhen / objectCase / 'nil' / 'discard' / declColonEquals
 object = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart
 typeClassParam = ('var')? symbol
 typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
@@ -183,7 +179,7 @@ simpleStmt = ((returnStmt | raiseStmt | yieldStmt | discardStmt | breakStmt
            | continueStmt | pragmaStmt | importStmt | exportStmt | fromStmt
            | includeStmt | commentStmt) / exprStmt) COMMENT?
 complexOrSimpleStmt = (ifStmt | whenStmt | whileStmt
-                    | tryStmt | finallyStmt | exceptStmt | forStmt
+                    | tryStmt | forStmt
                     | blockStmt | staticStmt | deferStmt | asmStmt
                     | 'proc' routine
                     | 'method' routine
diff --git a/doc/idetools.txt b/doc/idetools.txt
index 5429d0c07..2ffe46d4b 100644
--- a/doc/idetools.txt
+++ b/doc/idetools.txt
@@ -27,7 +27,7 @@ integrations <https://github.com/Araq/Nim/wiki/Editor-Support>`_
 already available.
 
 
-Idetools invokation
+Idetools invocation
 ===================
 
 Specifying the location of the query
@@ -35,7 +35,7 @@ Specifying the location of the query
 
 All of the available idetools commands require you to specify a
 query location through the ``--track`` or ``--trackDirty`` switches.
-The general idetools invokations are::
+The general idetools invocations are::
 
     nim idetools --track:FILE,LINE,COL <switches> proj.nim
 
@@ -129,7 +129,7 @@ the suggestions sorted first by scope (from innermost to outermost)
 and then by item name.
 
 
-Invokation context
+Invocation context
 ------------------
 
 The ``--context`` idetools switch is very similar to the suggestions
@@ -145,7 +145,7 @@ The ``--usages`` idetools switch lists all usages of the symbol at
 a position. IDEs can use this to find all the places in the file
 where the symbol is used and offer the user to rename it in all
 places at the same time. Again, a pure string based search and
-replace may catch symbols out of the scope of a funcion/loop.
+replace may catch symbols out of the scope of a function/loop.
 
 For this kind of query the IDE will most likely ignore all the
 type/signature info provided by idetools and concentrate on the
@@ -163,7 +163,7 @@ running/debugged user project.
 Compiler as a service (CAAS)
 ============================
 
-The ocasional use of idetools is acceptable for things like
+The occasional use of idetools is acceptable for things like
 definitions, where the user puts the cursor on a symbol or double
 clicks it and after a second or two the IDE displays where that
 symbol is defined. Such latencies would be terrible for features
@@ -213,7 +213,7 @@ tab characters (``\t``). The values of each column are:
    ``proj.symbolName``.
 4. Type/signature. For variables and enums this will contain the
    type of the symbol, for procs, methods and templates this will
-   contain the full unique signature (e.g. ``proc (TFile)``).
+   contain the full unique signature (e.g. ``proc (File)``).
 5. Full path to the file containing the symbol.
 6. Line where the symbol is located in the file. Lines start to
    count at **1**.
@@ -258,8 +258,8 @@ skEnumField
 
 .. code-block:: nim
     Open(filename, fmWrite)
-    --> col 2: system.TFileMode.fmWrite
-        col 3: TFileMode
+    --> col 2: system.FileMode.fmWrite
+        col 3: FileMode
         col 7: ""
 
 
@@ -296,7 +296,7 @@ posterior instances of the iterator.
       text = "some text"
       letters = toSeq(runes(text))
     --> col 2: unicode.runes
-        col 3: iterator (string): TRune
+        col 3: iterator (string): Rune
         col 7: "iterates over any unicode character of the string `s`."
 
 
@@ -421,9 +421,9 @@ returned by idetools returns also the pragmas for the proc.
 | **Docstring**: docstring if available.
 
 .. code-block:: nim
-    Open(filename, fmWrite)
+    open(filename, fmWrite)
     --> col 2: system.Open
-        col 3: proc (var TFile, string, TFileMode, int): bool
+        col 3: proc (var File, string, FileMode, int): bool
         col 7:
     "Opens a file named `filename` with given `mode`.
 
@@ -487,9 +487,9 @@ skType
 
 .. code-block:: nim
     proc writeTempFile() =
-      var output: TFile
-    --> col 2: system.TFile
-        col 3: TFile
+      var output: File
+    --> col 2: system.File
+        col 3: File
         col 7: ""
 
 
@@ -502,11 +502,11 @@ skVar
 
 .. code-block:: nim
     proc writeTempFile() =
-      var output: TFile
+      var output: File
       output.open("/tmp/somefile", fmWrite)
       output.write("test")
     --> col 2: $MODULE.writeTempFile.output
-        col 3: TFile
+        col 3: File
         col 7: ""
 
 
@@ -533,10 +533,10 @@ run it manually. First you have to compile the tester::
 Running the ``caasdriver`` without parameters will attempt to process
 all the test cases in all three operation modes. If a test succeeds
 nothing will be printed and the process will exit with zero. If any
-test fails, the specific line of the test preceeding the failure
+test fails, the specific line of the test preceding the failure
 and the failure itself will be dumped to stdout, along with a final
 indicator of the success state and operation mode. You can pass the
-parameter ``verbose`` to force all output even on successfull tests.
+parameter ``verbose`` to force all output even on successful tests.
 
 The normal operation mode is called ``ProcRun`` and it involves
 starting a process for each command or query, similar to running
diff --git a/doc/intern.txt b/doc/intern.txt
index 26dd49444..9582fc96f 100644
--- a/doc/intern.txt
+++ b/doc/intern.txt
@@ -136,7 +136,7 @@ are also lots of procs that aid in debugging:
   debug(someType)
   echo symbol.name.s
   debug(symbol)
-  # pretty prints the nimrod ast, but annotates symbol IDs:
+  # pretty prints the Nim ast, but annotates symbol IDs:
   echo renderTree(someNode, {renderIds})
   if n.info ?? "temp.nim":
     # only output when it comes from "temp.nim"
@@ -145,6 +145,19 @@ are also lots of procs that aid in debugging:
     # why does it process temp.nim here?
     writeStackTrace()
 
+To create a new compiler for each run, use ``koch temp``::
+
+  ./koch temp c /tmp/test.nim
+
+``koch temp`` creates a debug build of the compiler, which is useful
+to create stacktraces for compiler debugging.
+
+``koch temp`` returns 125 as the exit code in case the compiler
+compilation fails. This exit code tells ``git bisect`` to skip the
+current commit.::
+
+  git bisect start bad-commit good-commit
+  git bisect ./koch -r c test-source.nim
 
 The compiler's architecture
 ===========================
@@ -223,7 +236,7 @@ too. Type converters fall into this category:
 
 If in the above example module ``B`` is re-compiled, but ``A`` is not then
 ``B`` needs to be aware of ``toBool`` even though  ``toBool`` is not referenced
-in ``B`` *explicitely*. 
+in ``B`` *explicitly*. 
 
 Both the multi method and the type converter problems are solved by storing 
 them in special sections in the ROD file that are loaded *unconditionally*
@@ -357,7 +370,7 @@ needed as the data structures needs to be rebuilt periodically anyway.
 
 Complete traversal is done in this way::
 
-  for each page decriptor d:
+  for each page descriptor d:
     for each bit in d:
       if bit == 1:
         traverse the pointer belonging to this bit
@@ -393,7 +406,7 @@ The generated code looks roughly like this:
     setRef(&r->left)
   }
 
-Note that for systems with a continous stack (which most systems have)
+Note that for systems with a continuous stack (which most systems have)
 the check whether the ref is on the stack is very cheap (only two
 comparisons).
 
diff --git a/doc/keywords.txt b/doc/keywords.txt
index 67ff0ab7f..405bf1981 100644
--- a/doc/keywords.txt
+++ b/doc/keywords.txt
@@ -1,9 +1,9 @@
 addr and as asm atomic
 bind block break
-case cast const continue converter
+case cast concept const continue converter
 defer discard distinct div do
 elif else end enum except export
-finally for from
+finally for from func
 generic
 if import in include interface is isnot iterator
 let
diff --git a/doc/lib.txt b/doc/lib.txt
index aba05c2ba..385e7a91a 100644
--- a/doc/lib.txt
+++ b/doc/lib.txt
@@ -18,7 +18,7 @@ low-level interface to a C library.
 
 Read this `document <apis.html>`_ for a quick overview of the API design.
 
-The `bottom <#babel>`_ of this page includes a list of 3rd party packages
+The `bottom <#nimble>`_ of this page includes a list of 3rd party packages
 created by the Nim community. These packages are a useful addition to the
 modules in the standard library.
 
@@ -154,8 +154,8 @@ Generic Operating System Services
 
 * `streams <streams.html>`_
   This module provides a stream interface and two implementations thereof:
-  the `PFileStream` and the `PStringStream` which implement the stream
-  interface for Nim file objects (`TFile`) and strings. Other modules
+  the `FileStream` and the `StringStream` which implement the stream
+  interface for Nim file objects (`File`) and strings. Other modules
   may provide other implementations for this standard stream interface.
 
 * `marshal <marshal.html>`_
@@ -175,6 +175,9 @@ Generic Operating System Services
   This module implements the ability to monitor a directory/file for changes
   using Posix's inotify API.
 
+* `asyncfile <asyncfile.html>`_
+  This module implements asynchronous file reading and writing using
+  ``asyncdispatch``.
 
 Math libraries
 --------------
@@ -185,10 +188,19 @@ Math libraries
 * `complex <complex.html>`_
   This module implements complex numbers and their mathematical operations.
 
+* `rationals <rationals.html>`_
+  This module implements rational numbers and their mathematical operations.
+
 * `fenv <fenv.html>`_
   Floating-point environment. Handling of floating-point rounding and
   exceptions (overflow, zero-devide, etc.).
 
+* `basic2d <basic2d.html>`_
+  Basic 2d support with vectors, points, matrices and some basic utilities.
+
+* `basic3d <basic3d.html>`_
+  Basic 3d support with vectors, points, matrices and some basic utilities.
+
 
 Internet Protocols and Support
 ------------------------------
@@ -218,9 +230,6 @@ Internet Protocols and Support
 * `smtp <smtp.html>`_
   This module implement a simple SMTP client. 
 
-* `irc <irc.html>`_
-  This module implements an asynchronous IRC client.
-
 * `ftpclient <ftpclient.html>`_
   This module implements an FTP client.
 
@@ -367,7 +376,7 @@ Miscellaneous
 -------------
 
 * `events <events.html>`_
-  This module implements an event system that is not dependant on external
+  This module implements an event system that is not dependent on external
   graphical toolkits.
 
 * `oids <oids.html>`_
@@ -468,12 +477,16 @@ Windows specific
 
 * `windows <windows.html>`_
   Contains a wrapper for the Win32 API.
+* `winlean <winlean.html>`_
+  Contains a wrapper for a small subset of 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.
+* `psapi <psapi.html>`_
+  Contains a wrapper for the ``psapi.h`` header.
 * `nb30 <nb30.html>`_
   This module contains the definitions for portable NetBIOS 3.0 support.
 
@@ -581,12 +594,12 @@ Scientific computing
 * `libsvm <libsvm.html>`_ 
   Low level wrapper for `lib svm <http://www.csie.ntu.edu.tw/~cjlin/libsvm/>`_.
 
-Babel
+Nimble
 ====================
 
-Babel is a package manager for the Nim programming language.
-For instructions on how to install Babel packages see
-`its README <https://github.com/nim-code/babel#readme>`_.
+Nimble is a package manager for the Nim programming language.
+For instructions on how to install Nimble packages see
+`its README <https://github.com/nim-lang/nimble#readme>`_.
 
 Official packages
 -----------------
@@ -598,7 +611,7 @@ compiler.
 .. raw:: html
 
   <div id="officialPkgList"><b>If you are reading this you are missing
-  babelpkglist.js or have javascript disabled in your browser.</b></div>
+  nimblepkglist.js or have javascript disabled in your browser.</b></div>
 
 Unofficial packages
 -------------------
@@ -610,7 +623,7 @@ Nim programming language.
 .. raw:: html
 
   <div id="unofficialPkgList"><b>If you are reading this you are missing
-  babelpkglist.js or have javascript disabled in your browser.</b></div>
+  nimblepkglist.js or have javascript disabled in your browser.</b></div>
 
-  <script type="text/javascript" src="babelpkglist.js"></script>
-  <script type="text/javascript" src="http://build.nim-lang.org/packages?callback=gotPackageList"></script>
+  <script type="text/javascript" src="nimblepkglist.js"></script>
+  <script type="text/javascript" src="http://irclogs.nim-lang.org/packages?callback=gotPackageList"></script>
diff --git a/doc/manual/about.txt b/doc/manual/about.txt
index 13307279b..78167efe3 100644
--- a/doc/manual/about.txt
+++ b/doc/manual/about.txt
@@ -25,9 +25,9 @@ with ``'``. An example::
 
   ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)?
   
-The binary ``^*`` operator is used as a shorthand for 0 or more occurances
+The binary ``^*`` operator is used as a shorthand for 0 or more occurrences
 separated by its second argument; likewise ``^+`` means 1 or more 
-occurances: ``a ^+ b`` is short for ``a (b a)*`` 
+occurrences: ``a ^+ b`` is short for ``a (b a)*`` 
 and ``a ^* b`` is short for ``(a (b a)*)?``. Example::
 
   arrayConstructor = '[' expr ^* ',' ']'
diff --git a/doc/manual/effects.txt b/doc/manual/effects.txt
index 73934ab34..a79f6ea85 100644
--- a/doc/manual/effects.txt
+++ b/doc/manual/effects.txt
@@ -29,9 +29,9 @@ compatibility:
 
 .. code-block:: nim
   type
-    TCallback = proc (s: string) {.raises: [IOError].}
+    Callback = proc (s: string) {.raises: [IOError].}
   var
-    c: TCallback
+    c: Callback
 
   proc p(x: string) =
     raise newException(OSError, "OS")
diff --git a/doc/manual/exceptions.txt b/doc/manual/exceptions.txt
index 7cad1c2b4..0010d5d09 100644
--- a/doc/manual/exceptions.txt
+++ b/doc/manual/exceptions.txt
@@ -47,36 +47,87 @@ the rest of the procedure - that is not within a ``finally`` clause -
 is not executed (if an exception occurs).
 
 
-Standalone except and finally statements
-----------------------------------------
+Try expression
+--------------
 
-``except`` and ``finally`` can also be used as a stand-alone statements.
-Any statements following them in the current block will be considered to be 
-in an implicit try block:
+Try can also be used as an expression; the type of the ``try`` branch then
+needs to fit the types of ``except`` branches, but the type of the ``finally``
+branch always has to be ``void``:
+
+.. code-block:: nim
+  let x = try: parseInt("133a")
+          except: -1
+          finally: echo "hi"
+
+
+To prevent confusing code there is a parsing limitation; if the ``try``
+follows a ``(`` it has to be written as a one liner:
+
+.. code-block:: nim
+  let x = (try: parseInt("133a") except: -1)
+
+
+Except clauses
+--------------
+
+Within an ``except`` clause, it is possible to use
+``getCurrentException`` to retrieve the exception that has been
+raised:
+
+.. code-block:: nim
+  try:
+    # ...
+  except IOError:
+    let e = getCurrentException()
+    # Now use "e"
+
+Note that ``getCurrentException`` always returns a ``ref Exception``
+type. If a variable of the proper type is needed (in the example
+above, ``IOError``), one must convert it explicitly:
+
+.. code-block:: nim
+  try:
+    # ...
+  except IOError:
+    let e = (ref IOError)(getCurrentException())
+    # "e" is now of the proper type
+
+However, this is seldom needed. The most common case is to extract an
+error message from ``e``, and for such situations it is enough to use
+``getCurrentExceptionMsg``:
+
+.. code-block:: nim
+  try:
+    # ...
+  except IOError:
+    echo "I/O error: " & getCurrentExceptionMsg()
+
+
+Defer statement
+---------------
+
+Instead of a ``try finally`` statement a ``defer`` statement can be used.
+
+Any statements following the ``defer`` in the current block will be considered
+to be in an implicit try block:
 
 .. code-block:: nim
   var f = open("numbers.txt")
-  finally: close(f)
-  ...
+  defer: close(f)
+  f.write "abc"
+  f.write "def"
 
-The ``except`` statement has a limitation in this form: one can't specify the
-type of the exception, one has to catch everything. Also, if one wants to use
-both ``finally`` and ``except`` one needs to reverse the usual sequence of the
-statements. Example:
+Is rewritten to:
 
 .. code-block:: nim
-  proc test() =
-    raise newException(Exception, "Hey ho")
-  
-  proc tester() =
-    finally: echo "3. Finally block"
-    except: echo "2. Except block"
-    echo "1. Pre exception"
-    test()
-    echo "4. Post exception"
-  # --> 1, 2, 3 is printed, 4 is never reached
-
-Top level standalone ``finally`` or ``except`` statements are not supported
+  var f = open("numbers.txt")
+  try:
+    f.write "abc"
+    f.write "def"
+  finally:
+    close(f)
+
+Top level ``defer`` statements are not supported
 since it's unclear what such a statement should refer to.
 
 
diff --git a/doc/manual/ffi.txt b/doc/manual/ffi.txt
index 0ad4ebba9..4a4e0316f 100644
--- a/doc/manual/ffi.txt
+++ b/doc/manual/ffi.txt
@@ -57,7 +57,7 @@ instructs the compiler to pass the type by value to procs:
 
 .. code-block:: nim
   type
-    TVector {.bycopy, pure.} = object
+    Vector {.bycopy, pure.} = object
       x, y, z: float
 
 
diff --git a/doc/manual/generics.txt b/doc/manual/generics.txt
index 6f1b2ee0d..2736f88fb 100644
--- a/doc/manual/generics.txt
+++ b/doc/manual/generics.txt
@@ -9,17 +9,17 @@ The following example shows a generic binary tree can be modelled:
 
 .. code-block:: nim
   type
-    TBinaryTree[T] = object      # TBinaryTree is a generic type with
+    BinaryTreeObj[T] = object    # BinaryTreeObj is a generic type with
                                  # with generic param ``T``
-      le, ri: ref TBinaryTree[T] # left and right subtrees; may be nil
+      le, ri: BinaryTree[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
+    BinaryTree[T] = ref BinaryTreeObj[T] # a shorthand for notational convenience
 
-  proc newNode[T](data: T): PBinaryTree[T] = # constructor for a node
+  proc newNode[T](data: T): BinaryTree[T] = # constructor for a node
     new(result)
     result.data = data
 
-  proc add[T](root: var PBinaryTree[T], n: PBinaryTree[T]) =
+  proc add[T](root: var BinaryTree[T], n: BinaryTree[T]) =
     if root == nil:
       root = n
     else:
@@ -40,7 +40,7 @@ The following example shows a generic binary tree can be modelled:
             return
           it = it.ri
 
-  iterator inorder[T](root: PBinaryTree[T]): T =
+  iterator inorder[T](root: BinaryTree[T]): T =
     # inorder traversal of a binary tree
     # recursive iterators are not yet implemented, so this does not work in
     # the current compiler!
@@ -49,7 +49,7 @@ The following example shows a generic binary tree can be modelled:
     if root.ri != nil: yield inorder(root.ri)
 
   var
-    root: PBinaryTree[string] # instantiate a PBinaryTree with the type string
+    root: BinaryTree[string]  # instantiate a BinaryTree with the type string
   add(root, newNode("hallo")) # instantiates generic procs ``newNode`` and
   add(root, newNode("world")) # ``add``
   for str in inorder(root):
@@ -60,14 +60,14 @@ Is operator
 -----------
 
 The ``is`` operator checks for type equivalence at compile time. It is
-therefore very useful for type specialization within generic code: 
+therefore very useful for type specialization within generic code:
 
 .. code-block:: nim
   type
-    TTable[TKey, TValue] = object
-      keys: seq[TKey]
-      values: seq[TValue]
-      when not (TKey is string): # nil value for strings used for optimization
+    Table[Key, Value] = object
+      keys: seq[Key]
+      values: seq[Value]
+      when not (Key is string): # nil value for strings used for optimization
         deletedKeys: seq[bool]
 
 
@@ -75,7 +75,7 @@ Type operator
 -------------
 
 The ``type`` (in many other languages called `typeof`:idx:) operator can
-be used to get the type of an expression: 
+be used to get the type of an expression:
 
 .. code-block:: nim
   var x = 0
@@ -88,7 +88,7 @@ other interpretations:
 
 .. code-block:: nim
   import strutils
-  
+
   # strutils contains both a ``split`` proc and iterator, but since an
   # an iterator is the preferred interpretation, `y` has the type ``string``:
   var y: type("a b c".split)
@@ -98,7 +98,7 @@ Type Classes
 ------------
 
 A type class is a special pseudo-type that can be used to match against
-types in the context of overload resolution or the ``is`` operator. 
+types in the context of overload resolution or the ``is`` operator.
 Nim supports the following built-in type classes:
 
 ==================   ===================================================
@@ -116,7 +116,7 @@ type class           matches
 ``array``            any array type
 ``set``              any set type
 ``seq``              any seq type
-``auto``             any type 
+``auto``             any type
 ==================   ===================================================
 
 Furthermore, every generic type automatically creates a type class of the same
@@ -127,14 +127,14 @@ more complex type classes:
 
 .. code-block:: nim
   # create a type class that will match all tuple and object types
-  type TRecordType = tuple or object
+  type RecordType = tuple or object
 
-  proc printFields(rec: TRecordType) =
+  proc printFields(rec: RecordType) =
     for key, value in fieldPairs(rec):
       echo key, " = ", value
 
 Procedures utilizing type classes in such manner are considered to be
-`implicitly generic`:idx:. They will be instantiated once for each unique 
+`implicitly generic`:idx:. They will be instantiated once for each unique
 combination of param types used within the program.
 
 Nim also allows for type classes and regular types to be specified
@@ -142,7 +142,7 @@ as `type constraints`:idx: of the generic type parameter:
 
 .. code-block:: nim
   proc onlyIntOrString[T: int|string](x, y: T) = discard
-  
+
   onlyIntOrString(450, 616) # valid
   onlyIntOrString(5.0, 0.0) # type mismatch
   onlyIntOrString("xy", 50) # invalid as 'T' cannot be both at the same time
@@ -152,7 +152,7 @@ exactly one concrete type. Here is an example taken directly from the system
 module to illustrate this:
 
 .. code-block:: nim
-  proc `==`*(x, y: tuple): bool = 
+  proc `==`*(x, y: tuple): bool =
     ## requires `x` and `y` to be of the same tuple type
     ## generic ``==`` operator for tuples that is lifted from the components
     ## of `x` and `y`.
@@ -160,8 +160,8 @@ module to illustrate this:
     for a, b in fields(x, y):
       if a != b: result = false
 
-Alternatively, the ``distinct`` type modifier can be applied to the type class 
-to allow each param matching the type class to bind to a different type. 
+Alternatively, the ``distinct`` type modifier can be applied to the type class
+to allow each param matching the type class to bind to a different type.
 
 If a proc param doesn't have a type specified, Nim will use the
 ``distinct auto`` type class (also known as ``any``):
@@ -175,11 +175,11 @@ type parameters of the matched generic type. They can be easily accessed using
 the dot syntax:
 
 .. code-block:: nim
-  type TMatrix[T, Rows, Columns] = object
+  type Matrix[T, Rows, Columns] = object
     ...
 
-  proc `[]`(m: TMatrix, row, col: int): TMatrix.T = 
-    m.data[col * high(TMatrix.Columns) + row]
+  proc `[]`(m: Matrix, row, col: int): Matrix.T =
+    m.data[col * high(Matrix.Columns) + row]
 
 Alternatively, the `type` operator can be used over the proc params for similar
 effect when anonymous or distinct type classes are used.
@@ -189,13 +189,13 @@ type, this results in another more specific type class:
 
 .. code-block:: nim
   seq[ref object]  # Any sequence storing references to any object type
-  
+
   type T1 = auto
   proc foo(s: seq[T1], e: T1)
     # seq[T1] is the same as just `seq`, but T1 will be allowed to bind
     # to a single type, while the signature is being matched
 
-  TMatrix[Ordinal] # Any TMatrix instantiation using integer values
+  Matrix[Ordinal] # Any Matrix instantiation using integer values
 
 As seen in the previous example, in such instantiations, it's not necessary to
 supply all type parameters of the generic type, because any missing ones will
@@ -203,34 +203,33 @@ be inferred to have the equivalent of the `any` type class and thus they will
 match anything without discrimination.
 
 
-User defined type classes
--------------------------
+Concepts
+--------
 
-**Note**: User defined type classes are still in development.
+**Note**: Concepts are still in development.
 
-The user-defined type classes are available in two flavours - declarative and
-imperative. Both are used to specify an arbitrary set of requirements that the
-matched type must satisfy.
+Concepts, also known as "user-defined type classes", are used to specify an
+arbitrary set of requirements that the matched type must satisfy.
 
-Declarative type classes are written in the following form:
+Concepts are written in the following form:
 
 .. code-block:: nim
   type
-    Comparable = generic x, y
+    Comparable = concept x, y
       (x < y) is bool
 
-    Container[T] = generic c
-      c.len is ordinal
+    Container[T] = concept c
+      c.len is Ordinal
       items(c) is iterator
       for value in c:
         type(value) is T
 
-The type class will be matched if:
+The concept is a match if:
 
 a) all of the expressions within the body can be compiled for the tested type
 b) all statically evaluatable boolean expressions in the body must be true
 
-The identifiers following the `generic` keyword represent instances of the
+The identifiers following the ``concept`` keyword represent instances of the
 currently matched type. These instances can act both as variables of the type,
 when used in contexts where a value is expected, and as the type itself when
 used in contexts where a type is expected.
@@ -240,45 +239,21 @@ type signatures of the required operations, but since type inference and
 default parameters are still applied in the provided block, it's also possible
 to encode usage protocols that do not reveal implementation details.
 
-As a special rule providing further convenience when writing type classes, any
+As a special rule providing further convenience when writing concepts, any
 type value appearing in a callable expression will be treated as a variable of
 the designated type for overload resolution purposes, unless the type value was
 passed in its explicit ``typedesc[T]`` form:
 
 .. code-block:: nim
   type
-    OutputStream = generic S
-      write(var S, string)
+    OutputStream = concept s
+      write(var s, string)
 
-Much like generics, the user defined type classes will be instantiated exactly
-once for each tested type and any static code included within them will also be
+Much like generics, concepts are instantiated exactly
+once for each tested type and any static code included within them is also
 executed once.
 
 
-Type inference with type classes
---------------------------------
-
-If a type class is used as the return type of a proc and it won't be bound to
-a concrete type by some of the proc params, Nim will infer the return type
-from the proc body. This is usually used with the ``auto`` type class:
-
-.. code-block:: nim
-  proc makePair(a, b): auto = (first: a, second: b)
-
-The return type will be treated as an additional generic param and can be
-explicitly specified at call sites as any other generic param.
-
-Future versions of Nim may also support overloading based on the return type
-of the overloads. In such settings, the expected result type at call sites may 
-also influence the inferred return type.
-
-..
-  Likewise, if a type class is used in another position where Nim expects a
-  concrete type (e.g. a variable declaration or a type coercion), Nim will try
-  to infer the concrete type by applying the matching algorithm that also used
-  in overload resolution.
-
-
 Symbol lookup in generics
 -------------------------
 
@@ -292,22 +267,22 @@ at definition and the context at instantiation are considered:
 
 .. code-block:: nim
   type
-    TIndex = distinct int
-  
-  proc `==` (a, b: TIndex): bool {.borrow.}
-  
-  var a = (0, 0.TIndex)
-  var b = (0, 0.TIndex)
-  
+    Index = distinct int
+
+  proc `==` (a, b: Index): bool {.borrow.}
+
+  var a = (0, 0.Index)
+  var b = (0, 0.Index)
+
   echo a == b # works!
 
 In the example the generic ``==`` for tuples (as defined in the system module)
 uses the ``==`` operators of the tuple's components. However, the ``==`` for
-the ``TIndex`` type is defined *after* the ``==`` for tuples; yet the example
+the ``Index`` type is defined *after* the ``==`` for tuples; yet the example
 compiles as the instantiation takes the currently defined symbols into account
 too.
 
-A symbol can be forced to be open by a `mixin`:idx: declaration: 
+A symbol can be forced to be open by a `mixin`:idx: declaration:
 
 .. code-block:: nim
   proc create*[T](): ref T =
@@ -321,16 +296,16 @@ A symbol can be forced to be open by a `mixin`:idx: declaration:
 Bind statement
 --------------
 
-The ``bind`` statement is the counterpart to the ``mixin`` statement. It 
+The ``bind`` statement is the counterpart to the ``mixin`` statement. It
 can be used to explicitly declare identifiers that should be bound early (i.e.
 the identifiers should be looked up in the scope of the template/generic
 definition):
 
 .. code-block:: nim
   # Module A
-  var 
+  var
     lastId = 0
-  
+
   template genId*: expr =
     bind lastId
     inc(lastId)
@@ -339,7 +314,7 @@ definition):
 .. code-block:: nim
   # Module B
   import A
-  
+
   echo genId()
 
 But a ``bind`` is rarely useful because symbol binding from the definition
diff --git a/doc/manual/lexing.txt b/doc/manual/lexing.txt
index 4de7936a3..df6d85636 100644
--- a/doc/manual/lexing.txt
+++ b/doc/manual/lexing.txt
@@ -261,9 +261,9 @@ 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 Nim can thus support ``array[char, int]`` or
-``set[char]`` efficiently as many algorithms rely on this feature.  The `TRune`
+``set[char]`` efficiently as many algorithms rely on this feature.  The `Rune`
 type is used for Unicode characters, it can represent any Unicode character.
-``TRune`` is declared in the `unicode module <unicode.html>`_.
+``Rune`` is declared in the `unicode module <unicode.html>`_.
 
 
 Numerical constants
@@ -289,7 +289,7 @@ Numerical constants are of a single type and have the form::
   INT32_LIT = INT_LIT ['\''] ('i' | 'I') '32'
   INT64_LIT = INT_LIT ['\''] ('i' | 'I') '64'
 
-  UINT8_LIT = INT_LIT ['\''] ('u' | 'U')
+  UINT_LIT = INT_LIT ['\''] ('u' | 'U')
   UINT8_LIT = INT_LIT ['\''] ('u' | 'U') '8'
   UINT16_LIT = INT_LIT ['\''] ('u' | 'U') '16'
   UINT32_LIT = INT_LIT ['\''] ('u' | 'U') '32'
diff --git a/doc/manual/modules.txt b/doc/manual/modules.txt
index 95a13a560..70f6026b2 100644
--- a/doc/manual/modules.txt
+++ b/doc/manual/modules.txt
@@ -45,13 +45,19 @@ Import statement
 ~~~~~~~~~~~~~~~~
 
 After the ``import`` statement a list of module names can follow or a single
-module name followed by an ``except`` to prevent some symbols to be imported:
+module name followed by an ``except`` list to prevent some symbols to be
+imported:
 
 .. code-block:: nim
-  import strutils except `%`
+  import strutils except `%`, toUpper
 
   # doesn't work then:
-  echo "$1" % "abc"
+  echo "$1" % "abc".toUpper
+
+
+It is not checked that the ``except`` list is really exported from the module.
+This feature allows to compile against an older version of the module that
+does not export these identifiers.
 
 
 Include statement
@@ -122,22 +128,22 @@ modules don't need to import a module's dependencies:
 
 .. code-block:: nim
   # module B
-  type TMyObject* = object
+  type MyObject* = object
 
 .. code-block:: nim
   # module A
   import B
-  export B.TMyObject
+  export B.MyObject
   
-  proc `$`*(x: TMyObject): string = "my object"
+  proc `$`*(x: MyObject): string = "my object"
 
 
 .. code-block:: nim
   # module C
   import A
   
-  # B.TMyObject has been imported implicitly here: 
-  var x: TMyObject
+  # B.MyObject has been imported implicitly here: 
+  var x: MyObject
   echo($x)
 
 
diff --git a/doc/manual/pragmas.txt b/doc/manual/pragmas.txt
index 6bb1314cd..39aebd826 100644
--- a/doc/manual/pragmas.txt
+++ b/doc/manual/pragmas.txt
@@ -14,7 +14,7 @@ deprecated pragma
 
 The deprecated pragma is used to mark a symbol as deprecated:
 
-.. code-block:: nimrod
+.. code-block:: nim
   proc p() {.deprecated.}
   var x {.deprecated.}: char
 
@@ -22,7 +22,7 @@ It can also be used as a statement. Then it takes a list of *renamings*. The
 upcoming ``nimfix`` tool can automatically update the code and perform these
 renamings:
 
-.. code-block:: nimrod
+.. code-block:: nim
   type
     File = object
     Stream = ref object
@@ -71,14 +71,13 @@ procedural variable.
 
 compileTime pragma
 ------------------
-The ``compileTime`` pragma is used to mark a proc to be used at compile
-time only. No code will be generated for it. Compile time procs are useful
-as helpers for macros.
-
+The ``compileTime`` pragma is used to mark a proc or variable to be used at
+compile time only. No code will be generated for it. Compile time procs are
+useful as helpers for macros.
 
 noReturn pragma
 ---------------
-The ``noreturn`` pragma is used to mark a proc that never returns. 
+The ``noreturn`` pragma is used to mark a proc that never returns.
 
 
 acyclic pragma
@@ -89,12 +88,12 @@ collector to not consider objects of this type as part of a cycle:
 
 .. code-block:: nim
   type
-    PNode = ref TNode
-    TNode {.acyclic, final.} = object
-      left, right: PNode
+    Node = ref NodeObj
+    NodeObj {.acyclic, final.} = object
+      left, right: Node
       data: string
 
-In the example a tree structure is declared with the ``TNode`` type. Note that
+In the example a tree structure is declared with the ``Node`` type. Note that
 the type definition is recursive and the GC has to assume that objects of
 this type may form a cyclic graph. The ``acyclic`` pragma passes the
 information that this cannot happen to the GC. If the programmer uses the
@@ -106,9 +105,9 @@ memory, but nothing worse happens.
 
 .. code-block:: nim
   type
-    PNode = acyclic ref TNode
-    TNode = object
-      left, right: PNode
+    Node = acyclic ref NodeObj
+    NodeObj = object
+      left, right: Node
       data: string
 
 
@@ -122,25 +121,25 @@ shallow pragma
 --------------
 The ``shallow`` pragma affects the semantics of a type: The compiler is
 allowed to make a shallow copy. This can cause serious semantic issues and
-break memory safety! However, it can speed up assignments considerably, 
-because the semantics of Nim require deep copying of sequences and strings. 
+break memory safety! However, it can speed up assignments considerably,
+because the semantics of Nim require deep copying of sequences and strings.
 This can be expensive, especially if sequences are used to build a tree
-structure: 
+structure:
 
 .. code-block:: nim
   type
-    TNodeKind = enum nkLeaf, nkInner
-    TNode {.final, shallow.} = object
-      case kind: TNodeKind
-      of nkLeaf: 
+    NodeKind = enum nkLeaf, nkInner
+    Node {.final, shallow.} = object
+      case kind: NodeKind
+      of nkLeaf:
         strVal: string
-      of nkInner: 
-        children: seq[TNode]
+      of nkInner:
+        children: seq[Node]
 
 
 pure pragma
 -----------
-An object type can be marked with the ``pure`` pragma so that its type 
+An object type can be marked with the ``pure`` pragma so that its type
 field which is used for runtime type identification is omitted. This used to be
 necessary for binary compatibility with other compiled languages.
 
@@ -163,12 +162,12 @@ error pragma
 ------------
 The ``error`` pragma is used to make the compiler output an error message
 with the given content. Compilation does not necessarily abort after an error
-though. 
+though.
 
 The ``error`` pragma can also be used to
 annotate a symbol (like an iterator or proc). The *usage* of the symbol then
 triggers a compile-time error. This is especially useful to rule out that some
-operation is valid due to overloading and type conversions: 
+operation is valid due to overloading and type conversions:
 
 .. code-block:: nim
   ## check that underlying int values are compared and not the pointers:
@@ -201,7 +200,7 @@ The ``line`` pragma can be used to affect line information of the annotated
 statement as seen in stack backtraces:
 
 .. code-block:: nim
-  
+
   template myassert*(cond: expr, msg = "") =
     if not cond:
       # change run-time line information of the 'raise' statement:
@@ -215,26 +214,26 @@ If the ``line`` pragma is used with a parameter, the parameter needs be a
 
 linearScanEnd pragma
 --------------------
-The ``linearScanEnd`` pragma can be used to tell the compiler how to 
+The ``linearScanEnd`` pragma can be used to tell the compiler how to
 compile a Nim `case`:idx: statement. Syntactically it has to be used as a
 statement:
 
 .. code-block:: nim
   case myInt
-  of 0: 
+  of 0:
     echo "most common case"
-  of 1: 
+  of 1:
     {.linearScanEnd.}
     echo "second most common case"
   of 2: echo "unlikely: use branch table"
   else: echo "unlikely too: use branch table for ", myInt
 
-In the example, the case branches ``0`` and ``1`` are much more common than 
-the other cases. Therefore the generated assembler code should test for these 
-values first, so that the CPU's branch predictor has a good chance to succeed 
+In the example, the case branches ``0`` and ``1`` are much more common than
+the other cases. Therefore the generated assembler code should test for these
+values first, so that the CPU's branch predictor has a good chance to succeed
 (avoiding an expensive CPU pipeline stall). The other cases might be put into a
 jump table for O(1) overhead, but at the cost of a (very likely) pipeline
-stall. 
+stall.
 
 The ``linearScanEnd`` pragma should be put into the last branch that should be
 tested against via linear scanning. If put into the last branch of the
@@ -243,8 +242,8 @@ whole ``case`` statement, the whole ``case`` statement uses linear scanning.
 
 computedGoto pragma
 -------------------
-The ``computedGoto`` pragma can be used to tell the compiler how to 
-compile a Nim `case`:idx: in a ``while true`` statement. 
+The ``computedGoto`` pragma can be used to tell the compiler how to
+compile a Nim `case`:idx: in a ``while true`` statement.
 Syntactically it has to be used as a statement inside the loop:
 
 .. code-block:: nim
@@ -278,21 +277,21 @@ Syntactically it has to be used as a statement inside the loop:
       of enumE:
         break
       inc(pc)
-    
+
   vm()
 
 As the example shows ``computedGoto`` is mostly useful for interpreters. If
-the underlying backend (C compiler) does not support the computed goto 
+the underlying backend (C compiler) does not support the computed goto
 extension the pragma is simply ignored.
 
 
 unroll pragma
 -------------
 The ``unroll`` pragma can be used to tell the compiler that it should unroll
-a `for`:idx: or `while`:idx: loop for runtime efficiency: 
+a `for`:idx: or `while`:idx: loop for runtime efficiency:
 
 .. code-block:: nim
-  proc searchChar(s: string, c: char): int = 
+  proc searchChar(s: string, c: char): int =
     for i in 0 .. s.high:
       {.unroll: 4.}
       if s[i] == c: return i
@@ -440,7 +439,7 @@ Example:
 
   Please note that if a callable symbol is never used in this scenario, its body
   will never be compiled. This is the default behavior leading to best compilation
-  times, but if exhaustive compilation of all definitions is required, using 
+  times, but if exhaustive compilation of all definitions is required, using
   ``nim check`` provides this option as well.
 
   Example:
@@ -461,9 +460,9 @@ Example:
 pragma pragma
 -------------
 
-The ``pragma`` pragma can be used to declare user defined pragmas. This is 
-useful because Nim's templates and macros do not affect pragmas. User 
-defined pragmas are in a different module-wide scope than all other symbols. 
+The ``pragma`` pragma can be used to declare user defined pragmas. This is
+useful because Nim's templates and macros do not affect pragmas. User
+defined pragmas are in a different module-wide scope than all other symbols.
 They cannot be imported from a module.
 
 Example:
@@ -473,8 +472,8 @@ Example:
     {.pragma: rtl, exportc, dynlib, cdecl.}
   else:
     {.pragma: rtl, importc, dynlib: "client.dll", cdecl.}
-    
-  proc p*(a, b: int): int {.rtl.} = 
+
+  proc p*(a, b: int): int {.rtl.} =
     result = a+b
 
 In the example a new pragma named ``rtl`` is introduced that either imports
diff --git a/doc/manual/procs.txt b/doc/manual/procs.txt
index d048615eb..9de984ecf 100644
--- a/doc/manual/procs.txt
+++ b/doc/manual/procs.txt
@@ -121,21 +121,21 @@ different; for this a special setter syntax is needed:
 .. code-block:: nim
   
   type
-    TSocket* = object of TObject
+    Socket* = ref object of RootObj
       FHost: int # cannot be accessed from the outside of the module
                  # the `F` prefix is a convention to avoid clashes since
                  # the accessors are named `host`
 
-  proc `host=`*(s: var TSocket, value: int) {.inline.} =
+  proc `host=`*(s: var Socket, value: int) {.inline.} =
     ## setter of hostAddr
     s.FHost = value
   
-  proc host*(s: TSocket): int {.inline.} =
+  proc host*(s: Socket): int {.inline.} =
     ## getter of hostAddr
     s.FHost
 
-  var
-    s: TSocket
+  var s: Socket
+  new s
   s.host = 34  # same as `host=`(s, 34)
 
 
@@ -200,6 +200,8 @@ executable code.
 Do notation
 -----------
 
+**Note:** The future of the ``do`` notation is uncertain.
+
 As a special more convenient notation, proc expressions involved in procedure
 calls can use the ``do`` keyword:
 
@@ -224,11 +226,6 @@ More than one ``do`` block can appear in a single call:
   do:
     # code to undo it
 
-For compatibility with ``stmt`` templates and macros, the ``do`` keyword can be
-omitted if the supplied proc doesn't have any parameters and return value. 
-The compatibility works in the other direction too as the ``do`` syntax can be
-used with macros and templates expecting ``stmt`` blocks.
-
 
 Nonoverloadable builtins
 ------------------------
@@ -241,7 +238,7 @@ simplicity (they require specialized semantic checking)::
 
 Thus they act more like keywords than like ordinary identifiers; unlike a 
 keyword however, a redefinition may `shadow`:idx: the definition in 
-the ``system`` module. From this list the following should be written in dot
+the ``system`` module. From this list the following should not be written in dot
 notation ``x.f`` since ``x`` cannot be type checked before it gets passed
 to ``f``::
 
@@ -354,32 +351,32 @@ dispatch.
 
 .. code-block:: nim
   type
-    Expression = object ## abstract base class for an expression
-    Literal = object of Expression
+    Expression = ref object of RootObj ## abstract base class for an expression
+    Literal = ref object of Expression
       x: int
-    PlusExpr = object of Expression
-      a, b: ref Expression
-      
-  method eval(e: ref Expression): int =
+    PlusExpr = ref object of Expression
+      a, b: Expression
+  
+  method eval(e: Expression): int =
     # override this base method
     quit "to override!"
   
-  method eval(e: ref Literal): int = return e.x
-
-  method eval(e: ref PlusExpr): int =
+  method eval(e: Literal): int = return e.x
+  
+  method eval(e: PlusExpr): int =
     # watch out: relies on dynamic binding
     result = eval(e.a) + eval(e.b)
   
-  proc newLit(x: int): ref Literal =
+  proc newLit(x: int): Literal =
     new(result)
     result.x = x
-    
-  proc newPlus(a, b: ref Expression): ref PlusExpr =
+  
+  proc newPlus(a, b: Expression): PlusExpr =
     new(result)
     result.a = a
     result.b = b
-  
-  echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
+
+echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
   
 In the example the constructors ``newLit`` and ``newPlus`` are procs
 because they should use static binding, but ``eval`` is a method because it
@@ -390,8 +387,8 @@ dispatching:
 
 .. code-block:: nim
   type
-    Thing = object
-    Unit = object of Thing
+    Thing = ref object of RootObj
+    Unit = ref object of Thing
       x: int
       
   method collide(a, b: Thing) {.inline.} =
@@ -403,8 +400,9 @@ dispatching:
   method collide(a: Unit, b: Thing) {.inline.} =
     echo "2"
   
-  var
-    a, b: Unit
+  var a, b: Unit
+  new a
+  new b
   collide(a, b) # output: 2
 
 
@@ -559,6 +557,40 @@ The builtin ``system.finished`` can be used to determine if an iterator has
 finished its operation; no exception is raised on an attempt to invoke an
 iterator that has already finished its work.
 
+Note that ``system.finished`` is error prone to use because it only returns
+``true`` one iteration after the iterator has finished:
+
+.. code-block:: nim
+  iterator mycount(a, b: int): int {.closure.} =
+    var x = a
+    while x <= b:
+      yield x
+      inc x
+
+  var c = mycount # instantiate the iterator
+  while not finished(c):
+    echo c(1, 3)
+
+  # Produces
+  1
+  2
+  3
+  0
+
+Instead this code has be used:
+
+.. code-block:: nim
+  var c = mycount # instantiate the iterator
+  while true:
+    let value = c(1, 3)
+    if finished(c): break # and discard 'value'!
+    echo value
+
+It helps to think that the iterator actually returns a
+pair ``(value, done)`` and ``finished`` is used to access the hidden ``done``
+field.
+
+
 Closure iterators are *resumable functions* and so one has to provide the
 arguments to every call. To get around this limitation one can capture
 parameters of an outer factory proc:
@@ -584,3 +616,23 @@ parameters of an outer factory proc:
   a for loop, the compiler will implicity use the ``auto`` return type if no
   type is given by the user. In contrast, since closure iterators can be used
   as a collaborative tasking system, ``void`` is a valid return type for them.
+
+
+Converters
+==========
+
+A converter is like an ordinary proc except that it enhances 
+the "implicitly convertible" type relation (see `Convertible relation`_):
+
+.. code-block:: nim
+  # bad style ahead: Nim is not C.
+  converter toBool(x: int): bool = x != 0
+
+  if 4:
+    echo "compiles"
+
+
+A converter can also be explicitly invoked for improved readability. Note that
+implicit converter chaining is not supported: If there is a converter from
+type A to type B and from type B to type C the implicit conversion from A to C
+is not provided.
diff --git a/doc/manual/stmts.txt b/doc/manual/stmts.txt
index e31be7121..5e47110e9 100644
--- a/doc/manual/stmts.txt
+++ b/doc/manual/stmts.txt
@@ -2,7 +2,7 @@ Statements and expressions
 ==========================
 
 Nim uses the common statement/expression paradigm: Statements do not
-produce a value in contrast to expressions. However, some expressions are 
+produce a value in contrast to expressions. However, some expressions are
 statements.
 
 Statements are separated into `simple statements`:idx: and
@@ -16,9 +16,9 @@ statements always have to be intended. The details can be found in the grammar.
 Statement list expression
 -------------------------
 
-Statements can also occur in an expression context that looks 
+Statements can also occur in an expression context that looks
 like ``(stmt1; stmt2; ...; ex)``. This is called
-an statement list expression or ``(;)``. The type 
+an statement list expression or ``(;)``. The type
 of ``(stmt1; stmt2; ...; ex)`` is the type of ``ex``. All the other statements
 must be of type ``void``. (One can use ``discard`` to produce a ``void`` type.)
 ``(;)`` does not introduce a new scope.
@@ -30,24 +30,24 @@ Discard statement
 Example:
 
 .. code-block:: nim
-  proc p(x, y: int): int = 
+  proc p(x, y: int): int =
     result = x + y
 
   discard p(3, 4) # discard the return value of `p`
 
 The ``discard`` statement evaluates its expression for side-effects and
-throws the expression's resulting value away. 
+throws the expression's resulting value away.
 
 Ignoring the return value of a procedure without using a discard statement is
 a static error.
 
 The return value can be ignored implicitly if the called proc/iterator has
-been declared with the `discardable`:idx: pragma: 
+been declared with the `discardable`:idx: pragma:
 
 .. code-block:: nim
-  proc p(x, y: int): int {.discardable.} = 
+  proc p(x, y: int): int {.discardable.} =
     result = x + y
-    
+
   p(3, 4) # now valid
 
 An empty ``discard`` statement is often used as a null statement:
@@ -98,11 +98,11 @@ T = enum                        cast[T](0); this may be an invalid value
 
 
 The implicit initialization can be avoided for optimization reasons with the
-`noinit`:idx: pragma: 
+`noinit`:idx: pragma:
 
 .. code-block:: nim
   var
-    a {.noInit.}: array [0..1023, char] 
+    a {.noInit.}: array [0..1023, char]
 
 If a proc is annotated with the ``noinit`` pragma this refers to its implicit
 ``result`` variable:
@@ -113,27 +113,28 @@ If a proc is annotated with the ``noinit`` pragma this refers to its implicit
 
 The implicit initialization can be also prevented by the `requiresInit`:idx:
 type pragma. The compiler requires an explicit initialization then. However
-it does a `control flow analysis`:idx: to prove the variable has been 
+it does a `control flow analysis`:idx: to prove the variable has been
 initialized and does not rely on syntactic properties:
 
 .. code-block:: nim
   type
-    TMyObject = object {.requiresInit.}
-    
+    MyObject = object {.requiresInit.}
+
   proc p() =
     # the following is valid:
-    var x: TMyObject
+    var x: MyObject
     if someCondition():
       x = a()
     else:
       x = a()
     use x
 
+
 let statement
 -------------
 
 A ``let`` statement declares new local and global `single assignment`:idx:
-variables and binds a value to them. The syntax is the of the ``var`` 
+variables and binds a value to them. The syntax is the same as that of the ``var``
 statement, except that the keyword ``var`` is replaced by the keyword ``let``.
 Let variables are not l-values and can thus not be passed to ``var`` parameters
 nor can their address be taken. They cannot be assigned new values.
@@ -141,6 +142,19 @@ nor can their address be taken. They cannot be assigned new values.
 For let variables the same pragmas are available as for ordinary variables.
 
 
+Tuple unpacking
+---------------
+
+In a ``var`` or ``let`` statement tuple unpacking can be performed. The special
+identifier ``_`` can be used to ignore some parts of the tuple:
+
+.. code-block:: nim
+    proc returnsTuple(): (int, int, int) = (4, 2, 3)
+
+    let (x, _, z) = returnsTuple()
+
+
+
 Const section
 -------------
 
@@ -157,33 +171,33 @@ have no side-effect can be used in constant expressions too:
     constEval = contains("abc", 'b') # computed at compile time!
 
 
-The rules for compile-time computability are: 
+The rules for compile-time computability are:
 
 1. Literals are compile-time computable.
 2. Type conversions are compile-time computable.
 3. Procedure calls of the form ``p(X)`` are compile-time computable if
-   ``p`` is a proc without side-effects (see the `noSideEffect pragma`_ 
-   for details) and if ``X`` is a (possibly empty) list of compile-time 
+   ``p`` is a proc without side-effects (see the `noSideEffect pragma`_
+   for details) and if ``X`` is a (possibly empty) list of compile-time
    computable arguments.
 
 
-Constants cannot be of type ``ptr``, ``ref``, ``var`` or ``object``, nor can 
+Constants cannot be of type ``ptr``, ``ref``, ``var`` or ``object``, nor can
 they contain such a type.
 
 
 Static statement/expression
 ---------------------------
 
-A static statement/expression can be used to enforce compile 
+A static statement/expression can be used to enforce compile
 time evaluation explicitly. Enforced compile time evaluation can even evaluate
-code that has side effects: 
+code that has side effects:
 
 .. code-block::
 
   static:
     echo "echo at compile time"
 
-It's a static error if the compiler cannot perform the evaluation at compile 
+It's a static error if the compiler cannot perform the evaluation at compile
 time.
 
 The current implementation poses some restrictions for compile time
@@ -217,7 +231,7 @@ 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.
 
-The scoping for an ``if`` statement is slightly subtle to support an important 
+The scoping for an ``if`` statement is slightly subtle to support an important
 use case. A new scope starts for the ``if``/``elif`` condition and ends after
 the corresponding *then* block:
 
@@ -229,7 +243,7 @@ the corresponding *then* block:
   else:
     # 'm' not declared here
 
-In the example the scopes have been enclosed in ``{|  |}``. 
+In the example the scopes have been enclosed in ``{|  |}``.
 
 
 Case statement
@@ -244,7 +258,7 @@ Example:
     echo("permission denied")
   of "go-for-a-walk":     echo("please yourself")
   else:                   echo("unknown command")
-  
+
   # indentation of the branches is also allowed; and so is an optional colon
   # after the selecting expression:
   case readline(stdin):
@@ -252,15 +266,15 @@ Example:
       echo("permission denied")
     of "go-for-a-walk":     echo("please yourself")
     else:                   echo("unknown command")
-  
+
 
 The ``case`` 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 *slicelist* the corresponding statements
 (after the ``of`` keyword) are executed. If the value is not in any
 given *slicelist* the ``else`` part is executed. If there is no ``else``
-part and not all possible values that ``expr`` can hold occur in a 
-``slicelist``, a static error occurs. This holds only for expressions of 
+part and not all possible values that ``expr`` can hold occur in a
+``slicelist``, a static error occurs. This holds only for expressions of
 ordinal types. "All possible values" of ``expr`` are determined by ``expr``'s
 type. To suppress the static error an ``else`` part with an
 empty ``discard`` statement should be used.
@@ -281,7 +295,7 @@ expanded into a list of its elements:
     of SymChars, '_': echo "an identifier"
     of '0'..'9': echo "a number"
     else: echo "other"
-  
+
   # is equivalent to:
   proc classify(s: string) =
     case s[0]
@@ -580,14 +594,14 @@ A table constructor is syntactic sugar for an array constructor:
 
 .. code-block:: nim
   {"key1": "value1", "key2", "key3": "value2"}
-  
+
   # is the same as:
   [("key1", "value1"), ("key2", "value2"), ("key3", "value2")]
 
 
-The empty table can be written ``{:}`` (in contrast to the empty set 
+The empty table can be written ``{:}`` (in contrast to the empty set
 which is ``{}``) which is thus another way to write as the empty array
-constructor ``[]``. This slightly unusal way of supporting tables 
+constructor ``[]``. This slightly unusal way of supporting tables
 has lots of advantages:
 
 * The order of the (key,value)-pairs is preserved, thus it is easy to
diff --git a/doc/manual/syntax.txt b/doc/manual/syntax.txt
index c975e7f48..24644bce2 100644
--- a/doc/manual/syntax.txt
+++ b/doc/manual/syntax.txt
@@ -12,13 +12,9 @@ Binary operators have 11 different levels of precedence.
 Associativity
 -------------
 
-Binary operators whose first character is ``^`` or its last character
-is ``>`` are right-associative, all other binary operators are left-associative.
+Binary operators whose first character is ``^`` are right-associative, all
+other binary operators are left-associative.
 
-Exception: The single "greater than" ``>`` operator is left-associative too.
-
-Operators ending in ``>`` but longer than a single character are 
-called `arrow like`:idx:.
 
 
 Precedence
@@ -35,9 +31,12 @@ as ``(@x).abc`` whereas ``$x.abc`` is parsed as ``$(x.abc)``.
 For binary operators that are not keywords the precedence is determined by the
 following rules:
 
+Operators ending in either ``->``, ``~>`` or ``=>`` are called
+`arrow like`:idx:, and have the lowest precedence of all operators.
+
 If the operator ends with ``=`` and its first character is none of 
 ``<``, ``>``, ``!``, ``=``, ``~``, ``?``, it is an *assignment operator* which
-has the lowest precedence.
+has the second lowest precedence.
 
 Otherwise precedence is determined by the first character.
 
@@ -45,14 +44,14 @@ Otherwise precedence is determined by the first character.
 Precedence level    Operators                                      First character     Terminal symbol
 ================  ===============================================  ==================  ===============
  10 (highest)                                                      ``$  ^``            OP10
-  9               ``*    /    div   mod   shl  shr  %``            ``* % \  /``        OP9
-  8               ``+    -``                                       ``+  ~  |``         OP8
+  9               ``*    /    div   mod   shl  shr  %``            ``*  %  \  /``      OP9
+  8               ``+    -``                                       ``+  -  ~  |``      OP8
   7               ``&``                                            ``&``               OP7
   6               ``..``                                           ``.``               OP6
-  5               ``==  <= < >= > !=  in notin is isnot not of``   ``= <  > !``        OP5
+  5               ``==  <= < >= > !=  in notin is isnot not of``   ``=  <  >  !``      OP5
   4               ``and``                                                              OP4
   3               ``or xor``                                                           OP3
-  2                                                                ``@  : ?``          OP2
+  2                                                                ``@  :  ?``         OP2
   1               *assignment operator* (like ``+=``, ``*=``)                          OP1
   0 (lowest)      *arrow like operator* (like ``->``, ``=>``)                          OP0
 ================  ===============================================  ==================  ===============
@@ -61,7 +60,7 @@ Precedence level    Operators                                      First charact
 Strong spaces
 -------------
 
-The number of spaces preceeding a non-keyword operator affects precedence
+The number of spaces preceding a non-keyword operator affects precedence
 if the experimental parser directive ``#!strongSpaces`` is used. Indentation
 is not used to determine the number of spaces. If 2 or more operators have the
 same number of preceding spaces the precedence table applies, so ``1 + 3 * 4``
@@ -69,7 +68,7 @@ is still parsed as ``1 + (3 * 4)``, but ``1+3 * 4`` is parsed as ``(1+3) * 4``:
 
 .. code-block:: nim
   #! strongSpaces
-  if foo+4 * 4 == 8 and b&c | 9  ++
+  if foo+4 * 4 == 8  and  b&c | 9  ++
       bar:
     echo ""
   # is parsed as
diff --git a/doc/manual/templates.txt b/doc/manual/templates.txt
index d90c2203e..eeb907ce0 100644
--- a/doc/manual/templates.txt
+++ b/doc/manual/templates.txt
@@ -67,7 +67,7 @@ special ``:`` syntax:
 .. code-block:: nim
 
   template withFile(f, fn, mode: expr, actions: stmt): stmt {.immediate.} =
-    var f: TFile
+    var f: File
     if open(f, fn, mode):
       try:
         actions
@@ -140,12 +140,12 @@ shadowed by the same argument name even when fully qualified:
   # module 'm'
 
   type
-    TLev = enum
+    Lev = enum
       levA, levB
 
   var abclev = levB
 
-  template tstLev(abclev: TLev) =
+  template tstLev(abclev: Lev) =
     echo abclev, " ", m.abclev
 
   tstLev(levA)
@@ -157,12 +157,12 @@ But the global symbol can properly be captured by a ``bind`` statement:
   # module 'm'
 
   type
-    TLev = enum
+    Lev = enum
       levA, levB
 
   var abclev = levB
 
-  template tstLev(abclev: TLev) =
+  template tstLev(abclev: Lev) =
     bind m.abclev
     echo abclev, " ", m.abclev
 
@@ -202,7 +202,7 @@ template parameter, it is an inject'ed symbol:
 .. code-block:: nim
   template withFile(f, fn, mode: expr, actions: stmt): stmt {.immediate.} =
     block:
-      var f: TFile  # since 'f' is a template param, it's injected implicitly
+      var f: File  # since 'f' is a template param, it's injected implicitly
       ...
       
   withFile(txt, "ttempl3.txt", fmWrite):
@@ -250,7 +250,7 @@ Another common example is this:
     yield "Hello"
     yield "World"
 
-  var info = something().toSeq()
+  var info = toSeq(something())
 
 The problem here is that the compiler already decided that ``something()`` as
 an iterator is not callable in this context before ``toSeq`` gets its
diff --git a/doc/manual/threads.txt b/doc/manual/threads.txt
index 245545f6f..fc3040c87 100644
--- a/doc/manual/threads.txt
+++ b/doc/manual/threads.txt
@@ -1,16 +1,16 @@
 Threads
 =======
 
-To enable thread support the ``--threads:on`` command line switch needs to 
-be used. The ``system`` module then contains several threading primitives. 
-See the `threads <threads.html>`_ and `channels <channels.html>`_ modules 
+To enable thread support the ``--threads:on`` command line switch needs to
+be used. The ``system`` module then contains several threading primitives.
+See the `threads <threads.html>`_ and `channels <channels.html>`_ modules
 for the low level thread API. There are also high level parallelism constructs
 available. See `spawn`_ for further details.
 
 Nim's memory model for threads is quite different than that of other common
-programming languages (C, Pascal, Java): Each thread has its own (garbage 
-collected) heap and sharing of memory is restricted to global variables. This 
-helps to prevent race conditions. GC efficiency is improved quite a lot, 
+programming languages (C, Pascal, Java): Each thread has its own (garbage
+collected) heap and sharing of memory is restricted to global variables. This
+helps to prevent race conditions. GC efficiency is improved quite a lot,
 because the GC never has to stop other threads and see what they reference.
 Memory allocation requires no lock at all! This design easily scales to massive
 multicore processors that are becoming the norm.
@@ -22,10 +22,10 @@ Thread pragma
 A proc that is executed as a new thread of execution should be marked by the
 ``thread`` pragma for reasons of readability. The compiler checks for
 violations of the `no heap sharing restriction`:idx:\: This restriction implies
-that it is invalid to construct a data structure that consists of memory 
+that it is invalid to construct a data structure that consists of memory
 allocated from different (thread local) heaps.
 
-A thread proc is passed to ``createThread`` or ``spawn`` and invoked 
+A thread proc is passed to ``createThread`` or ``spawn`` and invoked
 indirectly; so the ``thread`` pragma implies ``procvar``.
 
 
@@ -34,7 +34,7 @@ GC safety
 
 We call a proc ``p`` `GC safe`:idx: when it doesn't access any global variable
 that contains GC'ed memory (``string``, ``seq``, ``ref`` or a closure) either
-directly or indirectly through a call to a GC unsafe proc. 
+directly or indirectly through a call to a GC unsafe proc.
 
 The `gcsafe`:idx: annotation can be used to mark a proc to be gcsafe,
 otherwise this property is inferred by the compiler. Note that ``noSideEfect``
@@ -45,10 +45,9 @@ contain a ``ref`` or ``closure`` type. This enforces
 the *no heap sharing restriction*.
 
 Routines that are imported from C are always assumed to be ``gcsafe``.
-To enable the GC-safety checking the ``--threadAnalysis:on`` command line
-switch must be used. This is a temporary workaround to ease the porting effort
-from old code to the new threading model. In the future the thread analysis
-will always be performed.
+To disable the GC-safety checking the ``--threadAnalysis:off`` command line
+switch can be used. This is a temporary workaround to ease the porting effort
+from old code to the new threading model.
 
 
 Future directions:
@@ -59,13 +58,13 @@ Future directions:
 Threadvar pragma
 ----------------
 
-A global variable can be marked with the ``threadvar`` pragma; it is 
+A global variable can be marked with the ``threadvar`` pragma; it is
 a `thread-local`:idx: variable then:
 
 .. code-block:: nim
   var checkpoints* {.threadvar.}: seq[string]
 
-Due to implementation restrictions thread local variables cannot be 
+Due to implementation restrictions thread local variables cannot be
 initialized within the ``var`` section. (Every thread local variable needs to
 be replicated at thread creation.)
 
@@ -73,7 +72,7 @@ be replicated at thread creation.)
 Threads and exceptions
 ----------------------
 
-The interaction between threads and exceptions is simple: A *handled* exception 
+The interaction between threads and exceptions is simple: A *handled* exception
 in one thread cannot affect any other thread. However, an *unhandled* exception
 in one thread terminates the whole *process*!
 
@@ -82,7 +81,7 @@ in one thread terminates the whole *process*!
 Parallel & Spawn
 ================
 
-Nim has two flavors of parallelism: 
+Nim has two flavors of parallelism:
 1) `Structured`:idx: parallelism via the ``parallel`` statement.
 2) `Unstructured`:idx: parallelism via the standalone ``spawn`` statement.
 
@@ -115,7 +114,7 @@ Spawn statement
 
   proc processLine(line: string) =
     discard "do some heavy lifting here"
-  
+
   for x in lines("myinput.txt"):
     spawn processLine(x)
   sync()
@@ -144,7 +143,7 @@ wait on multiple flow variables at the same time:
 
 .. code-block:: nim
   import threadpool, ...
-  
+
   # wait until 2 out of 3 servers received the update:
   proc main =
     var responses = newSeq[RawFlowVar](3)
@@ -203,8 +202,7 @@ restrictions / changes:
   the ``parallel`` section. This is called the *immutability check*. Currently
   it is not specified what exactly "complex location" means. We need to make
   this an optimization!
-* Every array access has to be provably within bounds. This is called 
+* Every array access has to be provably within bounds. This is called
   the *bounds check*.
 * Slices are optimized so that no copy is performed. This optimization is not
-  yet performed for ordinary slices outside of a ``parallel`` section. Slices
-  are also special in that they currently do not support negative indexes!
+  yet performed for ordinary slices outside of a ``parallel`` section.
diff --git a/doc/manual/trmacros.txt b/doc/manual/trmacros.txt
index 715c9f850..90d01e475 100644
--- a/doc/manual/trmacros.txt
+++ b/doc/manual/trmacros.txt
@@ -223,21 +223,21 @@ all the arguments, but also the matched operators in reverse polish notation:
   import macros
 
   type
-    TMatrix = object
+    Matrix = object
       dummy: int
 
-  proc `*`(a, b: TMatrix): TMatrix = discard
-  proc `+`(a, b: TMatrix): TMatrix = discard
-  proc `-`(a, b: TMatrix): TMatrix = discard
-  proc `$`(a: TMatrix): string = result = $a.dummy
-  proc mat21(): TMatrix =
+  proc `*`(a, b: Matrix): Matrix = discard
+  proc `+`(a, b: Matrix): Matrix = discard
+  proc `-`(a, b: Matrix): Matrix = discard
+  proc `$`(a: Matrix): string = result = $a.dummy
+  proc mat21(): Matrix =
     result.dummy = 21
 
-  macro optM{ (`+`|`-`|`*`) ** a }(a: TMatrix): expr =
+  macro optM{ (`+`|`-`|`*`) ** a }(a: Matrix): expr =
     echo treeRepr(a)
     result = newCall(bindSym"mat21")
 
-  var x, y, z: TMatrix
+  var x, y, z: Matrix
 
   echo x + y * z - x 
 
@@ -267,7 +267,7 @@ parameter is of the type ``varargs`` it is treated specially and it can match
   template optWrite{
     write(f, x)
     ((write|writeln){w})(f, y)
-  }(x, y: varargs[expr], f: TFile, w: expr) =
+  }(x, y: varargs[expr], f: File, w: expr) =
     w(f, x, y)
   
 
@@ -294,7 +294,7 @@ The following example shows how some form of hoisting can be implemented:
 .. code-block:: nim
   import pegs
 
-  template optPeg{peg(pattern)}(pattern: string{lit}): TPeg =
+  template optPeg{peg(pattern)}(pattern: string{lit}): Peg =
     var gl {.global, gensym.} = peg(pattern)
     gl
 
@@ -341,21 +341,21 @@ The ``call`` constraint is particularly useful to implement a move
 optimization for types that have copying semantics:
 
 .. code-block:: nim
-  proc `[]=`*(t: var TTable, key: string, val: string) =
+  proc `[]=`*(t: var Table, key: string, val: string) =
     ## puts a (key, value)-pair into `t`. The semantics of string require
     ## a copy here:
     let idx = findInsertionPosition(key)
     t[idx] = key
     t[idx] = val
 
-  proc `[]=`*(t: var TTable, key: string{call}, val: string{call}) =
+  proc `[]=`*(t: var Table, key: string{call}, val: string{call}) =
     ## puts a (key, value)-pair into `t`. Optimized version that knows that
     ## the strings are unique and thus don't need to be copied:
     let idx = findInsertionPosition(key)
     shallowCopy t[idx], key
     shallowCopy t[idx], val
 
-  var t: TTable
+  var t: Table
   # overloading resolution ensures that the optimized []= is called here:
   t[f()] = g()
 
diff --git a/doc/manual/type_bound_ops.txt b/doc/manual/type_bound_ops.txt
index 64c6c325d..c707979fe 100644
--- a/doc/manual/type_bound_ops.txt
+++ b/doc/manual/type_bound_ops.txt
@@ -21,27 +21,49 @@ helper distinct or object type has to be used for one pointer type.
 operator `=`
 ------------
 
-This operator is the assignment operator. Note that in the contexts 
-like ``let v = expr``, ``var v = expr``, ``parameter = defaultValue`` or for
-parameter passing no assignment is performed. The ``override`` pragma is
-optional for overriding ``=``.
+This operator is the assignment operator. Note that in the contexts
+``result = expr``, ``parameter = defaultValue`` or for
+parameter passing no assignment is performed. For a type ``T`` that has an
+overloaded assignment operator ``var v = T()`` is rewritten
+to ``var v: T; v = T()``; in other words ``var`` and ``let`` contexts do count
+as assignments.
+
+The assignment operator needs to be attached to an object or distinct
+type ``T``. Its signature has to be ``(var T, T)``. Example:
+
+.. code-block:: nim
+  type
+    Concrete = object
+      a, b: string
+
+  proc `=`(d: var Concrete; src: Concrete) =
+    shallowCopy(d.a, src.a)
+    shallowCopy(d.b, src.b)
+    echo "Concrete '=' called"
+
+  var x, y: array[0..2, Concrete]
+  var cA, cB: Concrete
+
+  var cATup, cBTup: tuple[x: int, ha: Concrete]
+
+  x = y
+  cA = cB
+  cATup = cBTup
 
-**Note**: Overriding of operator ``=`` is not yet implemented.
 
 
 destructors
 -----------
 
 A destructor must have a single parameter with a concrete type (the name of a
-generic type is allowed too). The name of the destructor has to be ``destroy``
-and it need to be annotated with the ``override`` pragma.
+generic type is allowed too). The name of the destructor has to be ``=destroy``.
 
-``destroy(v)`` will be automatically invoked for every local stack 
+``=destroy(v)`` will be automatically invoked for every local stack
 variable ``v`` that goes out of scope.
 
-If a structured type features a field with destructable type and 
+If a structured type features a field with destructable type and
 the user has not provided an explicit implementation, a destructor for the
-structured type will be automatically generated. Calls to any base class 
+structured type will be automatically generated. Calls to any base class
 destructors in both user-defined and generated destructors will be inserted.
 
 A destructor is attached to the type it destructs; expressions of this type
@@ -49,17 +71,17 @@ can then only be used in *destructible contexts* and as parameters:
 
 .. code-block:: nim
   type
-    TMyObj = object
+    MyObj = object
       x, y: int
       p: pointer
-      
-  proc destroy(o: var TMyObj) {.override.} =
+
+  proc `=destroy`(o: var MyObj) =
     if o.p != nil: dealloc o.p
-    
-  proc open: TMyObj =
-    result = TMyObj(x: 1, y: 2, p: alloc(3))
- 
-  proc work(o: TMyObj) =
+
+  proc open: MyObj =
+    result = MyObj(x: 1, y: 2, p: alloc(3))
+
+  proc work(o: MyObj) =
     echo o.x
     # No destructor invoked here for 'o' as 'o' is a parameter.
 
@@ -68,7 +90,7 @@ can then only be used in *destructible contexts* and as parameters:
     var x = open()
     # valid: pass 'x' to some other proc:
     work(x)
-    
+
     # Error: usage of a type with a destructor in a non destructible context
     echo open()
 
@@ -85,7 +107,7 @@ be destructed at its scope exit. Later versions of the language will improve
 the support of destructors.
 
 Be aware that destructors are not called for objects allocated with ``new``.
-This may change in future versions of language, but for now the ``finalizer``
+This may change in future versions of language, but for now the `finalizer`:idx:
 parameter to ``new`` has to be used.
 
 **Note**: Destructors are still experimental and the spec might change
@@ -95,7 +117,7 @@ significantly in order to incorporate an escape analysis.
 deepCopy
 --------
 
-``deepCopy`` is a builtin that is invoked whenever data is passed to
+``=deepCopy`` is a builtin that is invoked whenever data is passed to
 a ``spawn``'ed proc to ensure memory safety. The programmer can override its
 behaviour for a specific ``ref`` or ``ptr`` type ``T``. (Later versions of the
 language may weaken this restriction.)
@@ -103,10 +125,10 @@ language may weaken this restriction.)
 The signature has to be:
 
 .. code-block:: nim
-  proc deepCopy(x: T): T {.override.}
+  proc `=deepCopy`(x: T): T
 
-This mechanism is used by most data structures that support shared memory like
-channels to implement thread safe automatic memory management.
+This mechanism will be used by most data structures that support shared memory
+like channels to implement thread safe automatic memory management.
 
 The builtin ``deepCopy`` can even clone closures and their environments. See
 the documentation of `spawn`_ for details.
diff --git a/doc/manual/type_rel.txt b/doc/manual/type_rel.txt
index 74539f907..d1593a02e 100644
--- a/doc/manual/type_rel.txt
+++ b/doc/manual/type_rel.txt
@@ -18,7 +18,7 @@ algorithm (in pseudo-code) determines type equality:
     incl(s, (a,b))
     if a.kind == b.kind:
       case a.kind
-      of int, intXX, float, floatXX, char, string, cstring, pointer, 
+      of int, intXX, float, floatXX, char, string, cstring, pointer,
           bool, nil, void:
         # leaf type: kinds identical; nothing more to check
         result = true
@@ -61,7 +61,7 @@ with an auxiliary set ``s`` is omitted:
   proc typeEqualsOrDistinct(a, b: PType): bool =
     if a.kind == b.kind:
       case a.kind
-      of int, intXX, float, floatXX, char, string, cstring, pointer, 
+      of int, intXX, float, floatXX, char, string, cstring, pointer,
           bool, nil, void:
         # leaf type: kinds identical; nothing more to check
         result = true
@@ -90,7 +90,7 @@ with an auxiliary set ``s`` is omitted:
       result = typeEqualsOrDistinct(a.baseType, b)
     elif b.kind == distinct:
       result = typeEqualsOrDistinct(a, b.baseType)
-      
+
 
 Subtype relation
 ----------------
@@ -145,7 +145,7 @@ algorithm returns true:
 
 A type ``a`` is **explicitly** convertible to type ``b`` iff the following
 algorithm returns true:
- 
+
 .. code-block:: nim
   proc isIntegralType(t: PType): bool =
     result = isOrdinal(t) or t.kind in {float, float32, float64}
@@ -156,8 +156,8 @@ algorithm returns true:
     if typeEqualsOrDistinct(a, b): return true
     if isIntegralType(a) and isIntegralType(b): return true
     if isSubtype(a, b) or isSubtype(b, a): return true
-    
-The convertible relation can be relaxed by a user-defined type 
+
+The convertible relation can be relaxed by a user-defined type
 `converter`:idx:.
 
 .. code-block:: nim
@@ -174,7 +174,7 @@ The convertible relation can be relaxed by a user-defined type
   x = chr.toInt
   echo x # => 97
 
-The type conversion ``T(a)`` is an L-value if ``a`` is an L-value and 
+The type conversion ``T(a)`` is an L-value if ``a`` is an L-value and
 ``typeEqualsOrDistinct(T, type(a))`` holds.
 
 
@@ -186,6 +186,157 @@ An expression ``b`` can be assigned to an expression ``a`` iff ``a`` is an
 
 
 Overloading resolution
-----------------------
+======================
+
+In a call ``p(args)`` the routine ``p`` that matches best is selected. If
+multiple routines match equally well, the ambiguity is reported at compiletime.
+
+Every arg in args needs to match. There are multiple different category how an
+argument can match. Let ``f`` be the formal parameter's type and ``a`` the type
+of the argument.
+
+1. Exact match: ``a`` and ``f`` are of the same type.
+2. Literal match: ``a`` is an integer literal of value ``v``
+   and ``f`` is a signed or unsigned integer type and ``v`` is in ``f``'s
+   range. Or:  ``a`` is a floating point literal of value ``v``
+   and ``f`` is a floating point type and ``v`` is in ``f``'s
+   range.
+3. Generic match: ``f`` is a generic type and ``a`` matches, for
+   instance ``a`` is ``int`` and ``f`` is a generic (constrained) parameter
+   type (like in ``[T]`` or ``[T: int|char]``.
+4. Subrange or subtype match: ``a`` is a ``range[T]`` and ``T``
+   matches ``f`` exactly. Or: ``a`` is a subtype of ``f``.
+5. Integral conversion match: ``a`` is convertible to ``f`` and ``f`` and ``a``
+   is some integer or floating point type.
+6. Conversion match: ``a`` is convertible to ``f``, possibly via a user
+   defined ``converter``.
+
+These matching categories have a priority: An exact match is better than a
+literal match and that is better than a generic match etc. In the following
+``count(p, m)`` counts the number of matches of the matching category ``m``
+for the routine ``p``.
+
+A routine ``p`` matches better than a routine ``q`` if the following
+algorithm returns true::
+
+  for each matching category m in ["exact match", "literal match",
+                                  "generic match", "subtype match",
+                                  "integral match", "conversion match"]:
+    if count(p, m) > count(q, m): return true
+    elif count(p, m) == count(q, m):
+      discard "continue with next category m"
+    else:
+      return false
+  return "ambiguous"
+
+
+Some examples:
+
+.. code-block:: nim
+  proc takesInt(x: int) = echo "int"
+  proc takesInt[T](x: T) = echo "T"
+  proc takesInt(x: int16) = echo "int16"
+
+  takesInt(4) # "int"
+  var x: int32
+  takesInt(x) # "T"
+  var y: int16
+  takesInt(y) # "int16"
+  var z: range[0..4] = 0
+  takesInt(z) # "T"
+
+
+If this algorithm returns "ambiguous" further disambiguation is performed:
+If the argument ``a`` matches both the parameter type ``f`` of ``p``
+and ``g`` of ``q`` via a subtyping relation, the inheritance depth is taken
+into account:
+
+.. code-block:: nim
+  type
+    A = object of RootObj
+    B = object of A
+    C = object of B
+
+  proc p(obj: A) =
+    echo "A"
+
+  proc p(obj: B) =
+    echo "B"
+
+  var c = C()
+  # not ambiguous, calls 'B', not 'A' since B is a subtype of A
+  # but not vice versa:
+  p(c)
+
+  proc pp(obj: A, obj2: B) = echo "A B"
+  proc pp(obj: B, obj2: A) = echo "B A"
+
+  # but this is ambiguous:
+  pp(c, c)
+
+
+Likewise for generic matches the most specialized generic type (that still
+matches) is preferred:
+
+.. code-block:: nim
+  proc gen[T](x: ref ref T) = echo "ref ref T"
+  proc gen[T](x: ref T) = echo "ref T"
+  proc gen[T](x: T) = echo "T"
+
+  var ri: ref int
+  gen(ri) # "ref T"
+
+
+Overloading based on 'var T'
+----------------------------
+
+If the formal parameter ``f`` is of type ``var T`` in addition to the ordinary
+type checking, the argument is checked to be an `l-value`:idx:. ``var T``
+matches better than just ``T`` then.
+
+
+Automatic dereferencing
+-----------------------
+
+If the `experimental mode <experimental pragma>`_ is active and no other match
+is found, the first argument ``a`` is dereferenced automatically if it's a
+pointer type and overloading resolution is tried with ``a[]`` instead.
+
+
+Lazy type resolution for expr
+-----------------------------
+
+**Note**: An `unresolved`:idx: expression is an expression for which no symbol
+lookups and no type checking have been performed.
+
+Since templates and macros that are not declared as ``immediate`` participate
+in overloading resolution it's essential to have a way to pass unresolved
+expressions to a template or macro. This is what the meta-type ``expr``
+accomplishes:
+
+.. code-block:: nim
+  template rem(x: expr) = discard
+
+  rem unresolvedExpression(undeclaredIdentifier)
+
+A parameter of type ``expr`` always matches any argument (as long as there is
+any argument passed to it).
+
+But one has to watch out because other overloads might trigger the
+argument's resolution:
+
+.. code-block:: nim
+  template rem(x: expr) = discard
+  proc rem[T](x: T) = discard
+
+  # undeclared identifier: 'unresolvedExpression'
+  rem unresolvedExpression(undeclaredIdentifier)
+
+``expr`` is the only metatype that is lazy in this sense, the other
+metatypes ``stmt`` and ``typedesc`` are not lazy.
+
+
+Varargs matching
+----------------
 
-To be written.
+See `Varargs`_.
diff --git a/doc/manual/type_sections.txt b/doc/manual/type_sections.txt
index 5413e896e..8420a0098 100644
--- a/doc/manual/type_sections.txt
+++ b/doc/manual/type_sections.txt
@@ -5,15 +5,15 @@ Example:
 
 .. code-block:: nim
   type # example demonstrating 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
+    Node = ref NodeObj # a traced pointer to a NodeObj
+    NodeObj = object
+      le, ri: Node     # left and right subtrees
+      sym: ref Sym     # leaves contain a reference to a Sym
 
-    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
+    Sym = object       # a symbol
+      name: string     # the symbol's name
+      line: int        # the line the symbol was declared in
+      code: Node      # the symbol's abstract syntax tree
 
 A type section begins with the ``type`` keyword. It contains multiple
 type definitions. A type definition binds a type to a name. Type definitions
diff --git a/doc/manual/typedesc.txt b/doc/manual/typedesc.txt
index d1d8bc87a..de1d84d7d 100644
--- a/doc/manual/typedesc.txt
+++ b/doc/manual/typedesc.txt
@@ -6,11 +6,11 @@ static[T]
 
 **Note**: static[T] is still in development.
 
-As their name suggests, static params must be known at compile-time:
+As their name suggests, static parameters must be known at compile-time:
 
 .. code-block:: nim
 
-  proc precompiledRegex(pattern: static[string]): TRegEx =
+  proc precompiledRegex(pattern: static[string]): RegEx =
     var res {.global.} = re(pattern)
     return res
 
@@ -23,23 +23,7 @@ As their name suggests, static params must be known at compile-time:
 
 For the purposes of code generation, all static params are treated as
 generic params - the proc will be compiled separately for each unique
-supplied value (or combination of values). 
-
-Furthermore, the system module defines a `semistatic[T]` type than can be
-used to declare procs accepting both static and run-time values, which can
-optimize their body according to the supplied param using the `isStatic(p)`
-predicate:
-
-.. code-block:: nim
-
-  # The following proc will be compiled once for each unique static
-  # value and also once for the case handling all run-time values:
-
-  proc re(pattern: semistatic[string]): TRegEx =
-    when isStatic(pattern):
-      result = precompiledRegex(pattern)
-    else:
-      result = compile(pattern)
+supplied value (or combination of values).
 
 Static params can also appear in the signatures of generic types:
 
@@ -61,7 +45,7 @@ typedesc
 --------
 
 `typedesc` is a special type allowing one to treat types as compile-time values
-(i.e. if types are compile-time values and all values have a type, then 
+(i.e. if types are compile-time values and all values have a type, then
 typedesc must be their type).
 
 When used as a regular proc param, typedesc acts as a type class. The proc
@@ -74,17 +58,14 @@ instantiation type using the param name:
     echo "allocating ", T.name
     new(result)
 
-  var n = TNode.new
-  var tree = new(TBinaryTree[int])
+  var n = Node.new
+  var tree = new(BinaryTree[int])
 
 When multiple typedesc params are present, they act like a distinct type class
 (i.e. they will bind freely to different types). To force a bind-once behavior
 one can use a named alias or an explicit `typedesc` generic param:
 
 .. code-block:: nim
-
-  # `type1` and `type2` are aliases for typedesc available from system.nim
-  proc acceptOnlyTypePairs(A, B: type1; C, D: type2)
   proc acceptOnlyTypePairs[T: typedesc, U: typedesc](A, B: T; C, D: U)
 
 Once bound, typedesc params can appear in the rest of the proc signature:
@@ -100,7 +81,7 @@ When used with macros and .compileTime. procs on the other hand, the compiler
 does not need to instantiate the code multiple times, because types then can be
 manipulated using the unified internal symbol representation. In such context
 typedesc acts as any other type. One can create variables, store typedesc
-values inside containers and so on. For example, here is how one can create 
+values inside containers and so on. For example, here is how one can create
 a type-safe wrapper for the unsafe `printf` function from C:
 
 .. code-block:: nim
@@ -114,7 +95,7 @@ a type-safe wrapper for the unsafe `printf` function from C:
         of 's': string
         of 'p': pointer
         else: EOutOfRange
-      
+
       var actualType = args[i].getType
       inc i
 
@@ -123,7 +104,7 @@ a type-safe wrapper for the unsafe `printf` function from C:
       elif expectedType != actualType:
         error "type mismatch for argument ", i, ". expected type: ",
               expectedType.name, ", actual type: ", actualType.name
-    
+
     # keep the original callsite, but use cprintf instead
     result = callsite()
     result[0] = newIdentNode(!"cprintf")
diff --git a/doc/manual/types.txt b/doc/manual/types.txt
index b8cde8c37..bdf51941d 100644
--- a/doc/manual/types.txt
+++ b/doc/manual/types.txt
@@ -40,7 +40,7 @@ These integer types are pre-defined:
 
 ``int``
   the generic signed integer type; its size is platform dependent and has the
-  same size as a pointer. This type should be used in general. An integer 
+  same size as a pointer. This type should be used in general. An integer
   literal that has no type suffix is of this type.
 
 intXX
@@ -51,7 +51,7 @@ intXX
 
 ``uint``
   the generic `unsigned integer`:idx: type; its size is platform dependent and
-  has the same size as a pointer. An integer literal with the type 
+  has the same size as a pointer. An integer literal with the type
   suffix ``'u`` is of this type.
 
 uintXX
@@ -59,15 +59,15 @@ uintXX
   (example: uint16 is a 16 bit wide unsigned integer).
   The current implementation supports ``uint8``, ``uint16``, ``uint32``,
   ``uint64``. Literals of these types have the suffix 'uXX.
-  Unsigned operations all wrap around; they cannot lead to over- or 
+  Unsigned operations all wrap around; they cannot lead to over- or
   underflow errors.
 
 
 In addition to the usual arithmetic operators for signed and unsigned integers
-(``+ - *`` etc.) there are also operators that formally work on *signed* 
-integers but treat their arguments as *unsigned*: They are mostly provided 
-for backwards compatibility with older versions of the language that lacked 
-unsigned integer types. These unsigned operations for signed integers use 
+(``+ - *`` etc.) there are also operators that formally work on *signed*
+integers but treat their arguments as *unsigned*: They are mostly provided
+for backwards compatibility with older versions of the language that lacked
+unsigned integer types. These unsigned operations for signed integers use
 the ``%`` suffix as convention:
 
 
@@ -98,7 +98,7 @@ operation                meaning
 kinds of integer types are used: the smaller type is converted to the larger.
 
 A `narrowing type conversion`:idx: converts a larger to a smaller type (for
-example ``int32 -> int16``. A `widening type conversion`:idx: converts a 
+example ``int32 -> int16``. A `widening type conversion`:idx: converts a
 smaller type to a larger type (for example ``int16 -> int32``). In Nim only
 widening type conversions are *implicit*:
 
@@ -111,7 +111,7 @@ widening type conversions are *implicit*:
 
 However, ``int`` literals are implicitly convertible to a smaller integer type
 if the literal's value fits this smaller type and such a conversion is less
-expensive than other implicit conversions, so ``myInt16 + 34`` produces 
+expensive than other implicit conversions, so ``myInt16 + 34`` produces
 an ``int16`` result.
 
 For further details, see `Convertible relation`_.
@@ -137,12 +137,12 @@ determined). Assignments from the base type to one of its subrange types
 A subrange type has the same size as its base type (``int`` in the example).
 
 Nim requires `interval arithmetic`:idx: for subrange types over a set
-of built-in operators that involve constants: ``x %% 3`` is of 
-type ``range[0..2]``. The following built-in operators for integers are 
+of built-in operators that involve constants: ``x %% 3`` is of
+type ``range[0..2]``. The following built-in operators for integers are
 affected by this rule: ``-``, ``+``, ``*``, ``min``, ``max``, ``succ``,
 ``pred``, ``mod``, ``div``, ``%%``, ``and`` (bitwise ``and``).
 
-Bitwise ``and`` only produces a ``range`` if one of its operands is a 
+Bitwise ``and`` only produces a ``range`` if one of its operands is a
 constant *x* so that (x+1) is a number of two.
 (Bitwise ``and`` is then a ``%%`` operation.)
 
@@ -155,7 +155,7 @@ This means that the following code is accepted:
   of 9: echo "C"
   of 10: echo "D"
   # note: no ``else`` required as (x and 3) + 7 has the type: range[7..10]
-  
+
 
 Pre-defined floating point types
 --------------------------------
@@ -186,17 +186,17 @@ The IEEE standard defines five types of floating-point exceptions:
   for example 0.0/0.0, sqrt(-1.0), and log(-37.8).
 * Division by zero: divisor is zero and dividend is a finite nonzero number,
   for example 1.0/0.0.
-* Overflow: operation produces a result that exceeds the range of the exponent, 
+* Overflow: operation produces a result that exceeds the range of the exponent,
   for example MAXDOUBLE+0.0000000000001e308.
-* Underflow: operation produces a result that is too small to be represented 
+* Underflow: operation produces a result that is too small to be represented
   as a normal number, for example, MINDOUBLE * MINDOUBLE.
-* Inexact: operation produces a result that cannot be represented with infinite 
+* Inexact: operation produces a result that cannot be represented with infinite
   precision, for example, 2.0 / 3.0, log(1.1) and 0.1 in input.
 
-The IEEE exceptions are either ignored at runtime or mapped to the 
+The IEEE exceptions are either ignored at runtime or mapped to the
 Nim exceptions: `FloatInvalidOpError`:idx:, `FloatDivByZeroError`:idx:,
 `FloatOverflowError`:idx:, `FloatUnderflowError`:idx:,
-and `FloatInexactError`:idx:. 
+and `FloatInexactError`:idx:.
 These exceptions inherit from the `FloatingPointError`:idx: base class.
 
 Nim provides the pragmas `NaNChecks`:idx: and `InfChecks`:idx: to control
@@ -212,7 +212,7 @@ whether the IEEE exceptions are ignored or trap a Nim exception:
 In the current implementation ``FloatDivByZeroError`` and ``FloatInexactError``
 are never raised. ``FloatOverflowError`` is raised instead of
 ``FloatDivByZeroError``.
-There is also a `floatChecks`:idx: pragma that is a short-cut for the 
+There is also a `floatChecks`:idx: pragma that is a short-cut for the
 combination of ``NaNChecks`` and ``InfChecks`` pragmas. ``floatChecks`` are
 turned off as default.
 
@@ -257,8 +257,8 @@ the resulting programs will still handle UTF-8 properly as UTF-8 was specially
 designed for this.
 Another reason is that Nim can support ``array[char, int]`` or
 ``set[char]`` efficiently as many algorithms rely on this feature. The
-`TRune` type is used for Unicode characters, it can represent any Unicode
-character. ``TRune`` is declared in the `unicode module <unicode.html>`_.
+`Rune` type is used for Unicode characters, it can represent any Unicode
+character. ``Rune`` is declared in the `unicode module <unicode.html>`_.
 
 
 
@@ -303,7 +303,7 @@ and ``pred`` are not available for them either.
 
 
 The compiler supports the built-in stringify operator ``$`` for enumerations.
-The stringify's result can be controlled by explicitly giving the string 
+The stringify's result can be controlled by explicitly giving the string
 values to use:
 
 .. code-block:: nim
@@ -315,12 +315,12 @@ values to use:
       valueC = 2,
       valueD = (3, "abc")
 
-As can be seen from the example, it is possible to both specify a field's 
+As can be seen from the example, it is possible to both specify a field's
 ordinal value and its string value by using a tuple. It is also
 possible to only specify one of them.
 
 An enum can be marked with the ``pure`` pragma so that it's fields are not
-added to the current scope, so they always need to be accessed 
+added to the current scope, so they always need to be accessed
 via ``MyEnum.value``:
 
 .. code-block:: nim
@@ -328,7 +328,7 @@ via ``MyEnum.value``:
   type
     MyEnum {.pure.} = enum
       valueA, valueB, valueC, valueD
-  
+
   echo valueA # error: Unknown identifier
   echo MyEnum.valueA # works
 
@@ -364,22 +364,22 @@ cstring type
 ------------
 The ``cstring`` type represents a pointer to a zero-terminated char array
 compatible to the type ``char*`` in Ansi C. Its primary purpose lies in easy
-interfacing with C. The index operation ``s[i]`` means the i-th *char* of 
+interfacing with C. The index operation ``s[i]`` means the i-th *char* of
 ``s``; however no bounds checking for ``cstring`` is performed making the
 index operation unsafe.
 
-A Nim ``string`` is implicitly convertible 
+A Nim ``string`` is implicitly convertible
 to ``cstring`` for convenience. If a Nim string is passed to a C-style
 variadic proc, it is implicitly converted to ``cstring`` too:
 
 .. code-block:: nim
-  proc printf(formatstr: cstring) {.importc: "printf", varargs, 
+  proc printf(formatstr: cstring) {.importc: "printf", varargs,
                                     header: "<stdio.h>".}
-  
+
   printf("This works %s", "as expected")
 
 Even though the conversion is implicit, it is not *safe*: The garbage collector
-does not consider a ``cstring`` to be a root and may collect the underlying 
+does not consider a ``cstring`` to be a root and may collect the underlying
 memory. However in practice this almost never happens as the GC considers
 stack roots conservatively. One can use the builtin procs ``GC_ref`` and
 ``GC_unref`` to keep the string data alive for the rare cases where it does
@@ -390,7 +390,7 @@ string from a cstring:
 
 .. code-block:: nim
   var str: string = "Hello!"
-  var cstr: cstring = s
+  var cstr: cstring = str
   var newstr: string = $cstr
 
 
@@ -410,9 +410,9 @@ integers from 0 to ``len(A)-1``. An array expression may be constructed by the
 array constructor ``[]``.
 
 Sequences are similar to arrays but of dynamic length which may change
-during runtime (like strings). Sequences are implemented as growable arrays, 
+during runtime (like strings). Sequences are implemented as growable arrays,
 allocating pieces of memory as items are added. A sequence ``S`` is always
-indexed by integers from 0 to ``len(S)-1`` and its bounds are checked. 
+indexed by integers from 0 to ``len(S)-1`` and its bounds are checked.
 Sequences can be constructed by the array constructor ``[]`` in conjunction
 with the array to sequence operator ``@``. Another way to allocate space for a
 sequence is to call the built-in ``newSeq`` procedure.
@@ -452,11 +452,11 @@ Open arrays
 
 Often fixed size arrays turn out to be too inflexible; procedures should
 be able to deal with arrays of different sizes. The `openarray`:idx: type
-allows this; it can only be used for parameters. Openarrays are always 
-indexed with an ``int`` starting at position 0. The ``len``, ``low`` 
-and ``high`` operations are available for open arrays too. Any array with 
-a compatible base type can be passed to an openarray parameter, the index 
-type does not matter. In addition to arrays sequences can also be passed 
+allows this; it can only be used for parameters. Openarrays are always
+indexed with an ``int`` starting at position 0. The ``len``, ``low``
+and ``high`` operations are available for open arrays too. Any array with
+a compatible base type can be passed to an openarray parameter, the index
+type does not matter. In addition to arrays sequences can also be passed
 to an open array parameter.
 
 The openarray type cannot be nested: multidimensional openarrays are not
@@ -467,7 +467,7 @@ Varargs
 -------
 
 A ``varargs`` parameter is an openarray parameter that additionally
-allows to pass a variable number of arguments to a procedure. The compiler 
+allows to pass a variable number of arguments to a procedure. The compiler
 converts the list of arguments to an array implicitly:
 
 .. code-block:: nim
@@ -494,9 +494,27 @@ type conversions in this context:
   # is transformed to:
   myWriteln(stdout, [$123, $"def", $4.0])
 
-In this example ``$`` is applied to any argument that is passed to the 
+In this example ``$`` is applied to any argument that is passed to the
 parameter ``a``. (Note that ``$`` applied to strings is a nop.)
 
+Note that an explicit array constructor passed to a ``varargs`` parameter is
+not wrapped in another implicit array construction:
+
+.. code-block:: nim
+  proc takeV[T](a: varargs[T]) = discard
+
+  takeV([123, 2, 1]) # takeV's T is "int", not "array of int"
+
+
+``varargs[expr]`` is treated specially: It matches a variable list of arguments
+of arbitrary type but *always* constructs an implicit array. This is required
+so that the builtin ``echo`` proc does what is expected:
+
+.. code-block:: nim
+  proc echo*(x: varargs[expr, `$`]) {...}
+
+  echo(@[1, 2, 3])
+  # prints "@[1, 2, 3]" and not "123"
 
 
 Tuples and object types
@@ -509,8 +527,7 @@ 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 *names* of the fields also have to be identical but this might
-change in a future version of the language.
+order. The *names* of the fields also have to be identical.
 
 The assignment operator for tuples copies each component.
 The default assignment operator for objects copies each component. Overloading
@@ -530,7 +547,7 @@ in future versions of the compiler.
   person = ("Peter", 30)
 
 The implementation aligns the fields for best access performance. The alignment
-is compatible with the way the C compiler does it. 
+is compatible with the way the C compiler does it.
 
 For consistency  with ``object`` declarations, tuples in a ``type`` section
 can also be defined with indentation instead of ``[]``:
@@ -551,7 +568,7 @@ the ``of`` operator can be used to determine the object's type.
       name*: string   # the * means that `name` is accessible from other modules
       age: int        # no * means that the field is hidden
 
-    Student = object of Person # a student is a person
+    Student = ref object of Person # a student is a person
       id: int                  # with an id field
 
   var
@@ -570,7 +587,7 @@ Object construction
 -------------------
 
 Objects can also be created with an `object construction expression`:idx: that
-has the syntax ``T(fieldA: valueA, fieldB: valueB, ...)`` where ``T`` is 
+has the syntax ``T(fieldA: valueA, fieldB: valueB, ...)`` where ``T`` is
 an ``object`` type or a ``ref object`` type:
 
 .. code-block:: nim
@@ -590,38 +607,38 @@ An example:
 
   # This is an example how an abstract syntax tree could be modelled in Nim
   type
-    TNodeKind = enum  # the different node types
+    NodeKind = enum  # the different node types
       nkInt,          # a leaf with an integer value
       nkFloat,        # a leaf with a float value
       nkString,       # a leaf with a string value
       nkAdd,          # an addition
       nkSub,          # a subtraction
       nkIf            # an if statement
-    PNode = ref TNode
-    TNode = object
-      case kind: TNodeKind  # the ``kind`` field is the discriminator
+    Node = ref NodeObj
+    NodeObj = object
+      case kind: NodeKind  # the ``kind`` field is the discriminator
       of nkInt: intVal: int
       of nkFloat: floatVal: float
       of nkString: strVal: string
       of nkAdd, nkSub:
-        leftOp, rightOp: PNode
+        leftOp, rightOp: Node
       of nkIf:
-        condition, thenPart, elsePart: PNode
+        condition, thenPart, elsePart: Node
 
   # create a new case object:
-  var n = PNode(kind: nkIf, condition: nil)
+  var n = Node(kind: nkIf, condition: nil)
   # accessing n.thenPart is valid because the ``nkIf`` branch is active:
-  n.thenPart = PNode(kind: nkFloat, floatVal: 2.0)
+  n.thenPart = Node(kind: nkFloat, floatVal: 2.0)
 
-  # the following statement raises an `EInvalidField` exception, because
+  # the following statement raises an `FieldError` exception, because
   # n.kind's value does not fit and the ``nkString`` branch is not active:
   n.strVal = ""
-  
+
   # invalid: would change the active object branch:
   n.kind = nkInt
-  
-  var x = PNode(kind: nkAdd, leftOp: PNode(kind: nkInt, intVal: 4),
-                             rightOp: PNode(kind: nkInt, intVal: 2))
+
+  var x = Node(kind: nkAdd, leftOp: Node(kind: nkInt, intVal: 4),
+                            rightOp: Node(kind: nkInt, intVal: 2))
   # valid: does not change the active object branch:
   x.kind = nkSub
 
@@ -659,8 +676,8 @@ untraced references are *unsafe*. However for certain low-level operations
 Traced references are declared with the **ref** keyword, untraced references
 are declared with the **ptr** keyword.
 
-An empty subscript ``[]`` notation can be used to derefer a reference, 
-the ``addr`` procedure returns the address of an item. An address is always 
+An empty subscript ``[]`` notation 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.
 
@@ -671,17 +688,34 @@ dereferencing operations for reference types:
 .. code-block:: nim
 
   type
-    PNode = ref TNode
-    TNode = object
-      le, ri: PNode
+    Node = ref NodeObj
+    NodeObj = object
+      le, ri: Node
       data: int
 
   var
-    n: PNode
+    n: Node
   new(n)
-  n.data = 9 
+  n.data = 9
   # no need to write n[].data; in fact n[].data is highly discouraged!
 
+Automatic dereferencing is also performed for the first argument of a routine
+call. But currently this feature has to be only enabled
+via ``{.experimental.}``:
+
+.. code-block:: nim
+  {.experimental.}
+
+  proc depth(x: NodeObj): int = ...
+
+  var
+    n: Node
+  new(n)
+  echo n.depth
+  # no need to write n[].depth either
+
+
+
 In order to simplify structural type checking, recursive tuples are not valid:
 
 .. code-block:: nim
@@ -716,10 +750,10 @@ memory manually:
 
 .. code-block:: nim
   type
-    TData = tuple[x, y: int, s: string]
+    Data = tuple[x, y: int, s: string]
 
-  # allocate memory for TData on the heap:
-  var d = cast[ptr TData](alloc0(sizeof(TData)))
+  # allocate memory for Data on the heap:
+  var d = cast[ptr Data](alloc0(sizeof(Data)))
 
   # create a new string on the garbage collected heap:
   d.s = "abc"
@@ -735,7 +769,7 @@ never be freed. The example also demonstrates two important features for low
 level programming: the ``sizeof`` proc returns the size of a type or value
 in bytes. The ``cast`` operator can circumvent the type system: the compiler
 is forced to treat the result of the ``alloc0`` call (which returns an untyped
-pointer) as if it would have the type ``ptr TData``. Casting should only be
+pointer) as if it would have the type ``ptr Data``. Casting should only be
 done if it is unavoidable: it breaks type safety and bugs can lead to
 mysterious crashes.
 
@@ -750,20 +784,20 @@ details like this when mixing garbage collected data with unmanaged memory.
 Not nil annotation
 ------------------
 
-All types for that ``nil`` is a valid value can be annotated to 
+All types for that ``nil`` is a valid value can be annotated to
 exclude ``nil`` as a valid value with the ``not nil`` annotation:
 
 .. code-block:: nim
   type
     PObject = ref TObj not nil
     TProc = (proc (x, y: int)) not nil
-    
+
   proc p(x: PObject) =
     echo "not nil"
-  
+
   # compiler catches this:
   p(nil)
-  
+
   # and also this:
   var x: PObject
   p(x)
@@ -830,7 +864,9 @@ Future directions:
 * Builtin regions like ``private``, ``global`` and ``local`` will
   prove very useful for the upcoming OpenCL target.
 * Builtin "regions" can model ``lent`` and ``unique`` pointers.
-
+* An assignment operator can be attached to a region so that proper write
+  barriers can be generated. This would imply that the GC can be implemented
+  completely in user-space.
 
 
 Procedural type
@@ -850,22 +886,22 @@ Examples:
 
   forEach(printItem)  # this will NOT compile because calling conventions differ
 
-  
+
 .. code-block:: nim
 
   type
-    TOnMouseMove = proc (x, y: int) {.closure.}
-  
+    OnMouseMove = proc (x, y: int) {.closure.}
+
   proc onMouseMove(mouseX, mouseY: int) =
     # has default calling convention
     echo "x: ", mouseX, " y: ", mouseY
-  
-  proc setOnMouseMove(mouseMoveEvent: TOnMouseMove) = discard
-  
+
+  proc setOnMouseMove(mouseMoveEvent: OnMouseMove) = discard
+
   # ok, 'onMouseMove' has the default calling convention, which is compatible
   # to 'closure':
   setOnMouseMove(onMouseMove)
-  
+
 
 A subtle issue with procedural types is that the calling convention of the
 procedure influences the type compatibility: procedural types are only
@@ -931,7 +967,7 @@ of the following conditions hold:
 3) The procedure has a calling convention that differs from ``nimcall``.
 4) The procedure is anonymous.
 
-The rules' purpose is to prevent the case that extending a non-``procvar`` 
+The rules' purpose is to prevent the case that extending a non-``procvar``
 procedure with default parameters breaks client code.
 
 The default calling convention is ``nimcall``, unless it is an inner proc (a
@@ -961,34 +997,34 @@ types are a perfect tool to model different currencies:
 
 .. code-block:: nim
   type
-    TDollar = distinct int
-    TEuro = distinct int
-  
+    Dollar = distinct int
+    Euro = distinct int
+
   var
-    d: TDollar
-    e: TEuro
+    d: Dollar
+    e: Euro
 
   echo d + 12
-  # Error: cannot add a number with no unit and a ``TDollar``
+  # Error: cannot add a number with no unit and a ``Dollar``
 
-Unfortunately, ``d + 12.TDollar`` is not allowed either,
-because ``+`` is defined for ``int`` (among others), not for ``TDollar``. So
+Unfortunately, ``d + 12.Dollar`` is not allowed either,
+because ``+`` is defined for ``int`` (among others), not for ``Dollar``. So
 a ``+`` for dollars needs to be defined:
 
 .. code-block::
-  proc `+` (x, y: TDollar): TDollar =
-    result = TDollar(int(x) + int(y))
+  proc `+` (x, y: Dollar): Dollar =
+    result = Dollar(int(x) + int(y))
 
 It does not make sense to multiply a dollar with a dollar, but with a
 number without unit; and the same holds for division:
 
 .. code-block::
-  proc `*` (x: TDollar, y: int): TDollar =
-    result = TDollar(int(x) * y)
+  proc `*` (x: Dollar, y: int): Dollar =
+    result = Dollar(int(x) * y)
+
+  proc `*` (x: int, y: Dollar): Dollar =
+    result = Dollar(x * int(y))
 
-  proc `*` (x: int, y: TDollar): TDollar =
-    result = TDollar(x * int(y))
-    
   proc `div` ...
 
 This quickly gets tedious. The implementations are trivial and the compiler
@@ -998,22 +1034,22 @@ The pragma `borrow`:idx: has been designed to solve this problem; in principle
 it generates the above trivial implementations:
 
 .. code-block:: nim
-  proc `*` (x: TDollar, y: int): TDollar {.borrow.}
-  proc `*` (x: int, y: TDollar): TDollar {.borrow.}
-  proc `div` (x: TDollar, y: int): TDollar {.borrow.}
+  proc `*` (x: Dollar, y: int): Dollar {.borrow.}
+  proc `*` (x: int, y: Dollar): Dollar {.borrow.}
+  proc `div` (x: Dollar, y: int): Dollar {.borrow.}
 
 The ``borrow`` pragma makes the compiler use the same implementation as
 the proc that deals with the distinct type's base type, so no code is
 generated.
 
-But it seems all this boilerplate code needs to be repeated for the ``TEuro``
+But it seems all this boilerplate code needs to be repeated for the ``Euro``
 currency. This can be solved with templates_.
 
 .. code-block:: nim
   template additive(typ: typedesc): stmt =
     proc `+` *(x, y: typ): typ {.borrow.}
     proc `-` *(x, y: typ): typ {.borrow.}
-    
+
     # unary operators:
     proc `+` *(x: typ): typ {.borrow.}
     proc `-` *(x: typ): typ {.borrow.}
@@ -1035,9 +1071,9 @@ currency. This can be solved with templates_.
     additive(typ)
     multiplicative(typ, base)
     comparable(typ)
-    
-  defineCurrency(TDollar, int)
-  defineCurrency(TEuro, int)
+
+  defineCurrency(Dollar, int)
+  defineCurrency(Euro, int)
 
 
 The borrow pragma can also be used to annotate the distinct type to allow
@@ -1070,7 +1106,7 @@ values is vulnerable to the famous `SQL injection attack`:idx:\:
 .. code-block:: nim
   import strutils
 
-  proc query(db: TDbHandle, statement: string) = ...
+  proc query(db: DbHandle, statement: string) = ...
 
   var
     username: string
@@ -1080,13 +1116,13 @@ values is vulnerable to the famous `SQL injection attack`:idx:\:
 
 This can be avoided by distinguishing strings that contain SQL from strings
 that don't. Distinct types provide a means to introduce a new string type
-``TSQL`` that is incompatible with ``string``:
+``SQL`` that is incompatible with ``string``:
 
 .. code-block:: nim
   type
-    TSQL = distinct string
+    SQL = distinct string
 
-  proc query(db: TDbHandle, statement: TSQL) = ...
+  proc query(db: DbHandle, statement: SQL) = ...
 
   var
     username: string
@@ -1097,28 +1133,28 @@ that don't. Distinct types provide a means to introduce a new string type
 
 It is an essential property of abstract types that they **do not** imply a
 subtype relation between the abtract type and its base type. Explict type
-conversions from ``string`` to ``TSQL`` are allowed:
+conversions from ``string`` to ``SQL`` are allowed:
 
 .. code-block:: nim
   import strutils, sequtils
 
-  proc properQuote(s: string): TSQL =
+  proc properQuote(s: string): SQL =
     # quotes a string properly for an SQL statement
-    return TSQL(s)
+    return SQL(s)
 
-  proc `%` (frmt: TSQL, values: openarray[string]): TSQL =
+  proc `%` (frmt: SQL, values: openarray[string]): SQL =
     # quote each argument:
-    let v = values.mapIt(TSQL, properQuote(it))
+    let v = values.mapIt(SQL, properQuote(it))
     # we need a temporary type for the type conversion :-(
-    type TStrSeq = seq[string]
+    type StrSeq = seq[string]
     # call strutils.`%`:
-    result = TSQL(string(frmt) % TStrSeq(v))
+    result = SQL(string(frmt) % StrSeq(v))
 
-  db.query("SELECT FROM users WHERE name = '$1'".TSQL % [username])
+  db.query("SELECT FROM users WHERE name = '$1'".SQL % [username])
 
 Now we have compile-time checking against SQL injection attacks.  Since
-``"".TSQL`` is transformed to ``TSQL("")`` no new syntax is needed for nice
-looking ``TSQL`` string literals. The hypothetical ``TSQL`` type actually
+``"".SQL`` is transformed to ``SQL("")`` no new syntax is needed for nice
+looking ``SQL`` string literals. The hypothetical ``SQL`` type actually
 exists in the library as the `TSqlQuery type <db_sqlite.html#TSqlQuery>`_ of
 modules like `db_sqlite <db_sqlite.html>`_.
 
@@ -1126,21 +1162,21 @@ modules like `db_sqlite <db_sqlite.html>`_.
 Void type
 ---------
 
-The ``void`` type denotes the absense of any type. Parameters of 
+The ``void`` type denotes the absence of any type. Parameters of
 type ``void`` are treated as non-existent, ``void`` as a return type means that
 the procedure does not return a value:
 
 .. code-block:: nim
   proc nothing(x, y: void): void =
     echo "ha"
-  
+
   nothing() # writes "ha" to stdout
 
 The ``void`` type is particularly useful for generic code:
 
 .. code-block:: nim
   proc callProc[T](p: proc (x: T), x: T) =
-    when T is void: 
+    when T is void:
       p()
     else:
       p(x)
@@ -1150,13 +1186,13 @@ The ``void`` type is particularly useful for generic code:
 
   callProc[int](intProc, 12)
   callProc[void](emptyProc)
-  
+
 However, a ``void`` type cannot be inferred in generic code:
 
 .. code-block:: nim
-  callProc(emptyProc) 
+  callProc(emptyProc)
   # Error: type mismatch: got (proc ())
-  # but expected one of: 
+  # but expected one of:
   # callProc(p: proc (T), x: T)
 
 The ``void`` type is only valid for parameters and return types; other symbols
diff --git a/doc/nimc.txt b/doc/nimc.txt
index 64ed6ce06..fb1873539 100644
--- a/doc/nimc.txt
+++ b/doc/nimc.txt
@@ -1,69 +1,68 @@
-===================================

-   Nim Compiler User Guide

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

-

-:Author: Andreas Rumpf

-:Version: |nimversion|

-

-.. contents::

-

-  "Look at you, hacker. A pathetic creature of meat and bone, panting and

-  sweating as you run through my corridors. How can you challenge a perfect,

-  immortal machine?"

-

-

-Introduction

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

-

-This document describes the usage of the *Nim compiler*

-on the different supported platforms. It is not a definition of the Nim

-programming language (therefore is the `manual <manual.html>`_).

-

-Nim is free software; it is licensed under the

-`MIT License <http://www.opensource.org/licenses/mit-license.php>`_.

-

-

-Compiler Usage

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

-

-Command line switches

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

-Basic command line switches are:

-

-.. include:: basicopt.txt

-

-Advanced command line switches are:

-

-.. include:: advopt.txt

-

+===================================
+   Nim Compiler User Guide
+===================================
+
+:Author: Andreas Rumpf
+:Version: |nimversion|
+
+.. contents::
+
+  "Look at you, hacker. A pathetic creature of meat and bone, panting and
+  sweating as you run through my corridors. How can you challenge a perfect,
+  immortal machine?"
+
+
+Introduction
+============
+
+This document describes the usage of the *Nim compiler*
+on the different supported platforms. It is not a definition of the Nim
+programming language (therefore is the `manual <manual.html>`_).
+
+Nim is free software; it is licensed under the
+`MIT License <http://www.opensource.org/licenses/mit-license.php>`_.
+
+
+Compiler Usage
+==============
+
+Command line switches
+---------------------
+Basic command line switches are:
+
+Usage:
+
+.. include:: basicopt.txt
+
+----
+
+Advanced command line switches are:
+
+.. include:: advopt.txt
+
 
 
 List of warnings
 ----------------
 
 Each warning can be activated individually with ``--warning[NAME]:on|off`` or
-in a ``push`` pragma. 
+in a ``push`` pragma.
 
 ==========================       ============================================
 Name                             Description
 ==========================       ============================================
 CannotOpenFile                   Some file not essential for the compiler's
                                  working could not be opened.
-OctalEscape                      The code contains an unsupported octal 
+OctalEscape                      The code contains an unsupported octal
                                  sequence.
 Deprecated                       The code uses a deprecated symbol.
 ConfigDeprecated                 The project makes use of a deprecated config
                                  file.
-SmallLshouldNotBeUsed            The letter 'l' should not be used as an 
+SmallLshouldNotBeUsed            The letter 'l' should not be used as an
                                  identifier.
-AnalysisLoophole                 The thread analysis was incomplete due to
-                                 an indirect call.
-DifferentHeaps                   The code mixes different local heaps in a
-                                 very dangerous way.
-WriteToForeignHeap               The code contains a threading error. 
-EachIdentIsTuple                 The code contains a confusing ``var`` 
+EachIdentIsTuple                 The code contains a confusing ``var``
                                  declaration.
-ShadowIdent                      A local variable shadows another local 
+ShadowIdent                      A local variable shadows another local
                                  variable of an outer scope.
 User                             Some user defined warning.
 ==========================       ============================================
@@ -99,30 +98,30 @@ enable builds in release mode (``-d:release``) where certain safety checks are
 omitted for better performance. Another common use is the ``-d:ssl`` switch to
 activate `SSL sockets <sockets.html>`_.
 
-

-Configuration files

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

-

-**Note:** The *project file name* is the name of the ``.nim`` file that is 

-passed as a command line argument to the compiler.

-

-

-The ``nim`` executable processes configuration files in the following

-directories (in this order; later files overwrite previous settings):

-

-1) ``$nim/config/nim.cfg``, ``/etc/nim.cfg`` (UNIX) or ``%NIMROD%/config/nim.cfg`` (Windows). This file can be skipped with the ``--skipCfg`` command line option.

-2) ``/home/$user/.config/nim.cfg`` (UNIX) or  ``%APPDATA%/nim.cfg`` (Windows). This file can be skipped with the ``--skipUserCfg`` command line option.

-3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent  directory of the project file's path. These files can be skipped with the ``--skipParentCfg`` command line option.

-4) ``$projectDir/nim.cfg`` where ``$projectDir`` stands for the project  file's path. This file can be skipped with the ``--skipProjCfg`` command line option.

-5) A project can also have a project specific configuration file named ``$project.nim.cfg`` that resides in the same directory as ``$project.nim``. This file can be skipped with the ``--skipProjCfg`` command line option.

-

-

-Command line settings have priority over configuration file settings.

-

-The default build of a project is a `debug build`:idx:. To compile a 

-`release build`:idx: define the ``release`` symbol::

-  

-  nim c -d:release myproject.nim

+
+Configuration files
+-------------------
+
+**Note:** The *project file name* is the name of the ``.nim`` file that is
+passed as a command line argument to the compiler.
+
+
+The ``nim`` executable processes configuration files in the following
+directories (in this order; later files overwrite previous settings):
+
+1) ``$nim/config/nim.cfg``, ``/etc/nim.cfg`` (UNIX) or ``%NIMROD%/config/nim.cfg`` (Windows). This file can be skipped with the ``--skipCfg`` command line option.
+2) ``/home/$user/.config/nim.cfg`` (UNIX) or  ``%APPDATA%/nim.cfg`` (Windows). This file can be skipped with the ``--skipUserCfg`` command line option.
+3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent  directory of the project file's path. These files can be skipped with the ``--skipParentCfg`` command line option.
+4) ``$projectDir/nim.cfg`` where ``$projectDir`` stands for the project  file's path. This file can be skipped with the ``--skipProjCfg`` command line option.
+5) A project can also have a project specific configuration file named ``$project.nim.cfg`` that resides in the same directory as ``$project.nim``. This file can be skipped with the ``--skipProjCfg`` command line option.
+
+
+Command line settings have priority over configuration file settings.
+
+The default build of a project is a `debug build`:idx:. To compile a
+`release build`:idx: define the ``release`` symbol::
+
+  nim c -d:release myproject.nim
 
 
 Search path handling
@@ -134,8 +133,8 @@ found an ambiguity error is produced.
 
 ``nim dump`` shows the contents of the PATH.
 
-However before the PATH is used the current directory is checked for the 
-file's existance. So if PATH contains ``$lib`` and ``$lib/bar`` and the 
+However before the PATH is used the current directory is checked for the
+file's existence. So if PATH contains ``$lib`` and ``$lib/bar`` and the
 directory structure looks like this::
 
   $lib/x.nim
@@ -148,83 +147,83 @@ And ``main`` imports ``x``, ``foo/x`` is imported. If ``other`` imports ``x``
 then both ``$lib/x.nim`` and ``$lib/bar/x.nim`` match and so the compiler
 should reject it. Currently however this check is not implemented and instead
 the first matching file is used.
-

-

-Generated C code directory

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

+
+
+Generated C code directory
+--------------------------
 The generated files that Nim produces all go into a subdirectory called
 ``nimcache`` in your project directory. This makes it easy to delete all
 generated files. Files generated in this directory follow a naming logic which
 you can read about in the `Nim Backend Integration document
 <backends.html#nimcache-naming-logic>`_.
 
-However, the generated C code is not platform independent. C code generated for

-Linux does not compile on Windows, for instance. The comment on top of the

-C file lists the OS, CPU and CC the file has been compiled for.

-

-

-Compilation cache

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

-

-**Warning**: The compilation cache is still highly experimental!

-

-The ``nimcache`` directory may also contain so called `rod`:idx: 

-or `symbol files`:idx:. These files are pre-compiled modules that are used by

-the compiler to perform `incremental compilation`:idx:. This means that only

-modules that have changed since the last compilation (or the modules depending

-on them etc.) are re-compiled. However, per default no symbol files are 

-generated; use the ``--symbolFiles:on`` command line switch to activate them.

-

-Unfortunately due to technical reasons the ``--symbolFiles:on`` needs 

-to *aggregate* some generated C code. This means that the resulting executable

-might contain some cruft even when dead code elimination is turned on. So

-the final release build should be done with ``--symbolFiles:off``.

-

-Due to the aggregation of C code it is also recommended that each project

-resides in its own directory so that the generated ``nimcache`` directory

-is not shared between different projects.

-

-

-Cross compilation

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

-

-To cross compile, use for example::

-

-  nim c --cpu:i386 --os:linux --compile_only --gen_script myproject.nim

-

-Then move the C code and the compile script ``compile_myproject.sh`` to your 

+However, the generated C code is not platform independent. C code generated for
+Linux does not compile on Windows, for instance. The comment on top of the
+C file lists the OS, CPU and CC the file has been compiled for.
+
+
+Compilation cache
+=================
+
+**Warning**: The compilation cache is still highly experimental!
+
+The ``nimcache`` directory may also contain so called `rod`:idx:
+or `symbol files`:idx:. These files are pre-compiled modules that are used by
+the compiler to perform `incremental compilation`:idx:. This means that only
+modules that have changed since the last compilation (or the modules depending
+on them etc.) are re-compiled. However, per default no symbol files are
+generated; use the ``--symbolFiles:on`` command line switch to activate them.
+
+Unfortunately due to technical reasons the ``--symbolFiles:on`` needs
+to *aggregate* some generated C code. This means that the resulting executable
+might contain some cruft even when dead code elimination is turned on. So
+the final release build should be done with ``--symbolFiles:off``.
+
+Due to the aggregation of C code it is also recommended that each project
+resides in its own directory so that the generated ``nimcache`` directory
+is not shared between different projects.
+
+
+Cross compilation
+=================
+
+To cross compile, use for example::
+
+  nim c --cpu:i386 --os:linux --compile_only --gen_script myproject.nim
+
+Then move the C code and the compile script ``compile_myproject.sh`` to your
 Linux i386 machine and run the script.
 
 Another way is to make Nim invoke a cross compiler toolchain::
-  
-  nim c --cpu:arm --os:linux myproject.nim

-  
-For cross compilation, the compiler invokes a C compiler named 
-like ``$cpu.$os.$cc`` (for example arm.linux.gcc) and the configuration 
+
+  nim c --cpu:arm --os:linux myproject.nim
+
+For cross compilation, the compiler invokes a C compiler named
+like ``$cpu.$os.$cc`` (for example arm.linux.gcc) and the configuration
 system is used to provide meaningful defaults. For example for ``ARM`` your
 configuration file should contain something like::
 
   arm.linux.gcc.path = "/usr/bin"
   arm.linux.gcc.exe = "arm-linux-gcc"
   arm.linux.gcc.linkerexe = "arm-linux-gcc"
-

-

-DLL generation

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

-

-Nim supports the generation of DLLs. However, there must be only one 

-instance of the GC per process/address space. This instance is contained in

-``nimrtl.dll``. This means that every generated Nim DLL depends

-on ``nimrtl.dll``. To generate the "nimrtl.dll" file, use the command::

-  

-  nim c -d:release lib/nimrtl.nim

-

-To link against ``nimrtl.dll`` use the command::

-

-  nim c -d:useNimRtl myprog.nim

-

-**Note**: Currently the creation of ``nimrtl.dll`` with thread support has 

-never been tested and is unlikely to work!

+
+
+DLL generation
+==============
+
+Nim supports the generation of DLLs. However, there must be only one
+instance of the GC per process/address space. This instance is contained in
+``nimrtl.dll``. This means that every generated Nim DLL depends
+on ``nimrtl.dll``. To generate the "nimrtl.dll" file, use the command::
+
+  nim c -d:release lib/nimrtl.nim
+
+To link against ``nimrtl.dll`` use the command::
+
+  nim c -d:useNimRtl myprog.nim
+
+**Note**: Currently the creation of ``nimrtl.dll`` with thread support has
+never been tested and is unlikely to work!
 
 
 Additional compilation switches
@@ -243,10 +242,10 @@ Define               Effect
                      version.
 ``useFork``          Makes ``osproc`` use ``fork`` instead of ``posix_spawn``.
 ``useNimRtl``        Compile and link against ``nimrtl.dll``.
-``useMalloc``        Makes Nim use C's `malloc`:idx: instead of Nim's 
+``useMalloc``        Makes Nim use C's `malloc`:idx: instead of Nim's
                      own memory manager. This only works with ``gc:none``.
-``useRealtimeGC``    Enables support of Nim's GC for *soft* realtime 
-                     systems. See the documentation of the `gc <gc.html>`_ 
+``useRealtimeGC``    Enables support of Nim's GC for *soft* realtime
+                     systems. See the documentation of the `gc <gc.html>`_
                      for further information.
 ``nodejs``           The JS target is actually ``node.js``.
 ``ssl``              Enables OpenSSL support for the sockets module.
@@ -254,84 +253,84 @@ Define               Effect
 ``uClibc``           Use uClibc instead of libc. (Relevant for Unix-like OSes)
 ==================   =========================================================
 
-

-

-Additional Features

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

-

-This section describes Nim's additional features that are not listed in the

-Nim manual. Some of the features here only make sense for the C code

-generator and are subject to change.

-

-

-NoDecl pragma

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

-The ``noDecl`` pragma can be applied to almost any symbol (variable, proc,

-type, etc.) and is sometimes useful for interoperability with C:

-It tells Nim that it should not generate a declaration for the symbol in

-the C code. For example:

-

-.. code-block:: Nim

-  var

-    EACCES {.importc, noDecl.}: cint # pretend EACCES was a variable, as

-                                     # Nim does not know its value

-

-However, the ``header`` pragma is often the better alternative.

-

-**Note**: This will not work for the LLVM backend.

-

-

-Header pragma

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

-The ``header`` pragma is very similar to the ``noDecl`` pragma: It can be

-applied to almost any symbol and specifies that it should not be declared

-and instead the generated code should contain an ``#include``:

-

-.. code-block:: Nim

-  type

-    PFile {.importc: "FILE*", header: "<stdio.h>".} = distinct pointer

-      # import C's FILE* type; Nim will treat it as a new pointer type

-

-The ``header`` pragma always expects a string constant. The string contant

-contains the header file: As usual for C, a system header file is enclosed

-in angle brackets: ``<>``. If no angle brackets are given, Nim

-encloses the header file in ``""`` in the generated C code.

-

-**Note**: This will not work for the LLVM backend.

-

-

-IncompleteStruct pragma

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

-The ``incompleteStruct`` pragma tells the compiler to not use the 

-underlying C ``struct`` in a ``sizeof`` expression:

-

-.. code-block:: Nim

-  type

-    TDIR* {.importc: "DIR", header: "<dirent.h>", 

-            final, pure, incompleteStruct.} = object

-

-

-Compile pragma

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

-The ``compile`` pragma can be used to compile and link a C/C++ source file 

-with the project: 

-

-.. code-block:: Nim

-  {.compile: "myfile.cpp".}

-

-**Note**: Nim computes a CRC checksum and only recompiles the file if it 

-has changed. You can use the ``-f`` command line option to force recompilation

-of the file.

-

-

-Link pragma

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

-The ``link`` pragma can be used to link an additional file with the project: 

-

-.. code-block:: Nim

-  {.link: "myfile.o".}

-

-

+
+
+Additional Features
+===================
+
+This section describes Nim's additional features that are not listed in the
+Nim manual. Some of the features here only make sense for the C code
+generator and are subject to change.
+
+
+NoDecl pragma
+-------------
+The ``noDecl`` pragma can be applied to almost any symbol (variable, proc,
+type, etc.) and is sometimes useful for interoperability with C:
+It tells Nim that it should not generate a declaration for the symbol in
+the C code. For example:
+
+.. code-block:: Nim
+  var
+    EACCES {.importc, noDecl.}: cint # pretend EACCES was a variable, as
+                                     # Nim does not know its value
+
+However, the ``header`` pragma is often the better alternative.
+
+**Note**: This will not work for the LLVM backend.
+
+
+Header pragma
+-------------
+The ``header`` pragma is very similar to the ``noDecl`` pragma: It can be
+applied to almost any symbol and specifies that it should not be declared
+and instead the generated code should contain an ``#include``:
+
+.. code-block:: Nim
+  type
+    PFile {.importc: "FILE*", header: "<stdio.h>".} = distinct pointer
+      # import C's FILE* type; Nim will treat it as a new pointer type
+
+The ``header`` pragma always expects a string constant. The string contant
+contains the header file: As usual for C, a system header file is enclosed
+in angle brackets: ``<>``. If no angle brackets are given, Nim
+encloses the header file in ``""`` in the generated C code.
+
+**Note**: This will not work for the LLVM backend.
+
+
+IncompleteStruct pragma
+-----------------------
+The ``incompleteStruct`` pragma tells the compiler to not use the
+underlying C ``struct`` in a ``sizeof`` expression:
+
+.. code-block:: Nim
+  type
+    DIR* {.importc: "DIR", header: "<dirent.h>",
+           final, pure, incompleteStruct.} = object
+
+
+Compile pragma
+--------------
+The ``compile`` pragma can be used to compile and link a C/C++ source file
+with the project:
+
+.. code-block:: Nim
+  {.compile: "myfile.cpp".}
+
+**Note**: Nim computes a CRC checksum and only recompiles the file if it
+has changed. You can use the ``-f`` command line option to force recompilation
+of the file.
+
+
+Link pragma
+-----------
+The ``link`` pragma can be used to link an additional file with the project:
+
+.. code-block:: Nim
+  {.link: "myfile.o".}
+
+
 PassC pragma
 ------------
 The ``passC`` pragma can be used to pass additional parameters to the C
@@ -361,126 +360,334 @@ embed parameters from an external command at compile time:
   {.passL: gorge("pkg-config --libs sdl").}
 
 
-Emit pragma

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

-The ``emit`` pragma can be used to directly affect the output of the 

-compiler's code generator. So it makes your code unportable to other code

-generators/backends. Its usage is highly discouraged! However, it can be

-extremely useful for interfacing with `C++`:idx: or `Objective C`:idx: code.

-

-Example:

-

-.. code-block:: Nim

-  {.emit: """

-  static int cvariable = 420;

-  """.}

-

+Emit pragma
+-----------
+The ``emit`` pragma can be used to directly affect the output of the
+compiler's code generator. So it makes your code unportable to other code
+generators/backends. Its usage is highly discouraged! However, it can be
+extremely useful for interfacing with `C++`:idx: or `Objective C`:idx: code.
+
+Example:
+
+.. code-block:: Nim
+  {.emit: """
+  static int cvariable = 420;
+  """.}
+
   {.push stackTrace:off.}
-  proc embedsC() =

-    var nimVar = 89

-    # use backticks to access Nim symbols within an emit section:

-    {.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimVar`);""".}

+  proc embedsC() =
+    var nimVar = 89
+    # use backticks to access Nim symbols within an emit section:
+    {.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimVar`);""".}
   {.pop.}
-

-  embedsC()

+
+  embedsC()
 
 As can be seen from the example, to Nim symbols can be referred via backticks.
 Use two backticks to produce a single verbatim backtick.
 
-

-ImportCpp pragma

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

+For a toplevel emit statement the section where in the generated C/C++ file
+the code should be emitted can be influenced via the
+prefixes ``/*TYPESECTION*/`` or ``/*VARSECTION*/``:
+
+.. code-block:: Nim
+  {.emit: """/*TYPESECTION*/
+  struct Vector3 {
+  public:
+    Vector3(): x(5) {}
+    Vector3(float x_): x(x_) {}
+    float x;
+  };
+  """.}
+
+  type Vector3 {.importcpp: "Vector3", nodecl} = object
+    x: cfloat
+
+  proc constructVector3(a: cfloat): Vector3 {.importcpp: "Vector3(@)", nodecl}
+
+
+ImportCpp pragma
+----------------
+
+**Note**: `c2nim <c2nim.html>`_ can parse a large subset of C++ and knows
+about the ``importcpp`` pragma pattern language. It is not necessary
+to know all the details described here.
+
+
 Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the
-``importcpp`` pragma can be used to import `C++`:idx: methods. The generated
-code then uses the C++ method calling syntax: ``obj->method(arg)``.  In
-addition with the ``header`` and ``emit`` pragmas this allows *sloppy*
-interfacing with libraries written in C++:
-

-.. code-block:: Nim

-  # Horrible example of how to interface with a C++ engine ... ;-)

-

-  {.link: "/usr/lib/libIrrlicht.so".}

-

-  {.emit: """

-  using namespace irr;

-  using namespace core;

-  using namespace scene;

-  using namespace video;

-  using namespace io;

-  using namespace gui;

-  """.}

-

-  const

-    irr = "<irrlicht/irrlicht.h>"

-

-  type

-    TIrrlichtDevice {.final, header: irr, importc: "IrrlichtDevice".} = object

-    PIrrlichtDevice = ptr TIrrlichtDevice

-

-  proc createDevice(): PIrrlichtDevice {.

-    header: irr, importc: "createDevice".}

-  proc run(device: PIrrlichtDevice): bool {.

-    header: irr, importcpp: "run".}

-  

-The compiler needs to be told to generate C++ (command ``cpp``) for 

-this to work. The conditional symbol ``cpp`` is defined when the compiler

-emits C++ code.

-

-

-ImportObjC pragma

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

+``importcpp`` pragma can be used to import `C++`:idx: methods or C++ symbols
+in general. The generated code then uses the C++ method calling
+syntax: ``obj->method(arg)``.  In combination with the ``header`` and ``emit``
+pragmas this allows *sloppy* interfacing with libraries written in C++:
+
+.. code-block:: Nim
+  # Horrible example of how to interface with a C++ engine ... ;-)
+
+  {.link: "/usr/lib/libIrrlicht.so".}
+
+  {.emit: """
+  using namespace irr;
+  using namespace core;
+  using namespace scene;
+  using namespace video;
+  using namespace io;
+  using namespace gui;
+  """.}
+
+  const
+    irr = "<irrlicht/irrlicht.h>"
+
+  type
+    IrrlichtDeviceObj {.final, header: irr,
+                        importcpp: "IrrlichtDevice".} = object
+    IrrlichtDevice = ptr IrrlichtDeviceObj
+
+  proc createDevice(): IrrlichtDevice {.
+    header: irr, importcpp: "createDevice(@)".}
+  proc run(device: IrrlichtDevice): bool {.
+    header: irr, importcpp: "#.run(@)".}
+
+The compiler needs to be told to generate C++ (command ``cpp``) for
+this to work. The conditional symbol ``cpp`` is defined when the compiler
+emits C++ code.
+
+
+Namespaces
+~~~~~~~~~~
+
+The *sloppy interfacing* example uses ``.emit`` to produce ``using namespace``
+declarations. It is usually much better to instead refer to the imported name
+via the ``namespace::identifier`` notation:
+
+.. code-block:: nim
+  type
+    IrrlichtDeviceObj {.final, header: irr,
+                        importcpp: "irr::IrrlichtDevice".} = object
+
+
+Importcpp for enums
+~~~~~~~~~~~~~~~~~~~
+
+When ``importcpp`` is applied to an enum type the numerical enum values are
+annotated with the C++ enum type, like in this example: ``((TheCppEnum)(3))``.
+(This turned out to be the simplest way to implement it.)
+
+
+Importcpp for procs
+~~~~~~~~~~~~~~~~~~~
+
+Note that the ``importcpp`` variant for procs uses a somewhat cryptic pattern
+language for maximum flexibility:
+
+- A hash ``#`` symbol is replaced by the first or next argument.
+- A dot following the hash ``#.`` indicates that the call should use C++'s dot
+  or arrow notation.
+- An at symbol ``@`` is replaced by the remaining arguments, separated by
+  commas.
+
+For example:
+
+.. code-block:: nim
+  proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "#.CppMethod(@)".}
+  var x: ptr CppObj
+  cppMethod(x[], 1, 2, 3)
+
+Produces:
+
+.. code-block:: C
+  x->CppMethod(1, 2, 3)
+
+As a special rule to keep backwards compatibility with older versions of the
+``importcpp`` pragma, if there is no special pattern
+character (any of ``# ' @``) at all, C++'s
+dot or arrow notation is assumed, so the above example can also be written as:
+
+.. code-block:: nim
+  proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "CppMethod".}
+
+Note that the pattern language naturally also covers C++'s operator overloading
+capabilities:
+
+.. code-block:: nim
+  proc vectorAddition(a, b: Vec3): Vec3 {.importcpp: "# + #".}
+  proc dictLookup(a: Dict, k: Key): Value {.importcpp: "#[#]".}
+
+
+- An apostrophe ``'`` followed by an integer ``i`` in the range 0..9
+  is replaced by the i'th parameter *type*. The 0th position is the result
+  type. This can be used to pass types to C++ function templates. Between
+  the ``'`` and the digit an asterisk can be used to get to the base type
+  of the type. (So it "takes away a star" from the type; ``T*`` becomes ``T``.)
+  Two stars can be used to get to the element type of the element type etc.
+
+For example:
+
+.. code-block:: nim
+
+  type Input {.importcpp: "System::Input".} = object
+  proc getSubsystem*[T](): ptr T {.importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.}
+
+  let x: ptr Input = getSubsystem[Input]()
+
+Produces:
+
+.. code-block:: C
+  x = SystemManager::getSubsystem<System::Input>()
+
+
+- ``#@`` is a special case to support a ``cnew`` operation. It is required so
+  that the call expression is inlined directly, without going through a
+  temporary location. This is only required to circumvent a limitation of the
+  current code generator.
+
+For example C++'s ``new`` operator can be "imported" like this:
+
+.. code-block:: nim
+  proc cnew*[T](x: T): ptr T {.importcpp: "(new '*0#@)", nodecl.}
+
+  # constructor of 'Foo':
+  proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)".}
+
+  let x = cnew constructFoo(3, 4)
+
+Produces:
+
+.. code-block:: C
+  x = new Foo(3, 4)
+
+However, depending on the use case ``new Foo`` can also be wrapped like this
+instead:
+
+.. code-block:: nim
+  proc newFoo(a, b: cint): ptr Foo {.importcpp: "new Foo(@)".}
+
+  let x = newFoo(3, 4)
+
+
+Wrapping constructors
+~~~~~~~~~~~~~~~~~~~~~
+
+Sometimes a C++ class has a private copy constructor and so code like
+``Class c = Class(1,2);`` must not be generated but instead ``Class c(1,2);``.
+For this purpose the Nim proc that wraps a C++ constructor needs to be
+annotated with the `constructor`:idx: pragma. This pragma also helps to generate
+faster C++ code since construction then doesn't invoke the copy constructor:
+
+.. code-block:: nim
+  # a better constructor of 'Foo':
+  proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)", constructor.}
+
+
+Wrapping destructors
+~~~~~~~~~~~~~~~~~~~~
+
+Since Nim generates C++ directly, any destructor is called implicitly by the
+C++ compiler at the scope exits. This means that often one can get away with
+not wrapping the destructor at all! However when it needs to be invoked
+explicitly, it needs to be wrapped. But the pattern language already provides
+everything that is required for that:
+
+.. code-block:: nim
+  proc destroyFoo(this: var Foo) {.importcpp: "#.~Foo()".}
+
+
+Importcpp for objects
+~~~~~~~~~~~~~~~~~~~~~
+
+Generic ``importcpp``'ed objects are mapped to C++ templates. This means that
+you can import C++'s templates rather easily without the need for a pattern
+language for object types:
+
+.. code-block:: nim
+  type
+    StdMap {.importcpp: "std::map", header: "<map>".} [K, V] = object
+  proc `[]=`[K, V](this: var StdMap[K, V]; key: K; val: V) {.
+    importcpp: "#[#] = #", header: "<map>".}
+
+  var x: StdMap[cint, cdouble]
+  x[6] = 91.4
+
+
+Produces:
+
+.. code-block:: C
+  std::map<int, double> x;
+  x[6] = 91.4;
+
+
+- If more precise control is needed, the apostrophe ``'`` can be used in the
+  supplied pattern to denote the concrete type parameters of the generic type.
+  See the usage of the apostrophe operator in proc patterns for more details.
+
+.. code-block:: nim
+
+  type
+    VectorIterator {.importcpp: "std::vector<'0>::iterator".} [T] = object
+
+  var x: VectorIterator[cint]
+
+
+Produces:
+
+.. code-block:: C
+
+  std::vector<int>::iterator x;
+
+
+ImportObjC pragma
+-----------------
 Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the
 ``importobjc`` pragma can be used to import `Objective C`:idx: methods.  The
 generated code then uses the Objective C method calling syntax: ``[obj method
 param1: arg]``.  In addition with the ``header`` and ``emit`` pragmas this
 allows *sloppy* interfacing with libraries written in Objective C:
-

-.. code-block:: Nim

-  # horrible example of how to interface with GNUStep ...

-

-  {.passL: "-lobjc".}

-  {.emit: """

-  #include <objc/Object.h>

-  @interface Greeter:Object

-  {

-  }

-

-  - (void)greet:(long)x y:(long)dummy;

-  @end

-

-  #include <stdio.h>

-  @implementation Greeter

-

-  - (void)greet:(long)x y:(long)dummy

-  {

-	  printf("Hello, World!\n");

-  }

-  @end

-

-  #include <stdlib.h>

-  """.}

-

-  type

-    TId {.importc: "id", header: "<objc/Object.h>", final.} = distinct int

-

-  proc newGreeter: TId {.importobjc: "Greeter new", nodecl.}

-  proc greet(self: TId, x, y: int) {.importobjc: "greet", nodecl.}

-  proc free(self: TId) {.importobjc: "free", nodecl.}

-

-  var g = newGreeter()

-  g.greet(12, 34)

-  g.free()

-

-The compiler needs to be told to generate Objective C (command ``objc``) for 

-this to work. The conditional symbol ``objc`` is defined when the compiler

-emits Objective C code.

+
+.. code-block:: Nim
+  # horrible example of how to interface with GNUStep ...
+
+  {.passL: "-lobjc".}
+  {.emit: """
+  #include <objc/Object.h>
+  @interface Greeter:Object
+  {
+  }
+
+  - (void)greet:(long)x y:(long)dummy;
+  @end
+
+  #include <stdio.h>
+  @implementation Greeter
+
+  - (void)greet:(long)x y:(long)dummy
+  {
+    printf("Hello, World!\n");
+  }
+  @end
+
+  #include <stdlib.h>
+  """.}
+
+  type
+    Id {.importc: "id", header: "<objc/Object.h>", final.} = distinct int
+
+  proc newGreeter: Id {.importobjc: "Greeter new", nodecl.}
+  proc greet(self: Id, x, y: int) {.importobjc: "greet", nodecl.}
+  proc free(self: Id) {.importobjc: "free", nodecl.}
+
+  var g = newGreeter()
+  g.greet(12, 34)
+  g.free()
+
+The compiler needs to be told to generate Objective C (command ``objc``) for
+this to work. The conditional symbol ``objc`` is defined when the compiler
+emits Objective C code.
 
 
 CodegenDecl pragma
 ------------------
 
 The ``codegenDecl`` pragma can be used to directly influence Nim's code
-generator. It receives a format string that determines how the variable or 
+generator. It receives a format string that determines how the variable or
 proc is declared in the generated code:
 
 .. code-block:: nim
@@ -500,108 +707,56 @@ debugging:
 
 .. code-block:: nim
   {.injectStmt: gcInvariants().}
-  
+
   # ... complex code here that produces crashes ...
-

-

-LineDir option

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

-The ``lineDir`` option can be turned on or off. If turned on the

-generated C code contains ``#line`` directives. This may be helpful for

-debugging with GDB.

-

-

-StackTrace option

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

-If the ``stackTrace`` option is turned on, the generated C contains code to

-ensure that proper stack traces are given if the program crashes or an

-uncaught exception is raised.

-

-

-LineTrace option

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

-The ``lineTrace`` option implies the ``stackTrace`` option. If turned on,

-the generated C contains code to ensure that proper stack traces with line

-number information are given if the program crashes or an uncaught exception

-is raised.

-

-Debugger option

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

-The ``debugger`` option enables or disables the *Embedded Nim Debugger*.

-See the documentation of endb_ for further information.

-

-

-Breakpoint pragma

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

-The *breakpoint* pragma was specially added for the sake of debugging with

-ENDB. See the documentation of `endb <endb.html>`_ for further information.

-

-

-Volatile pragma

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

-The ``volatile`` pragma is for variables only. It declares the variable as

-``volatile``, whatever that means in C/C++ (its semantics are not well defined

-in C/C++).

-

-**Note**: This pragma will not exist for the LLVM backend.

-
-
-Source code style
-=================
 
-Nim allows you to `mix freely case and underscores as identifier separators
-<manual.html#identifiers-keywords>`_, so variables named ``MyPrecioussInt`` and
-``my_preciouss_int`` are equivalent:
 
-.. code-block:: Nim
-  var MyPrecioussInt = 3
-  # Following line compiles fine!
-  echo my_preciouss_int
+LineDir option
+--------------
+The ``lineDir`` option can be turned on or off. If turned on the
+generated C code contains ``#line`` directives. This may be helpful for
+debugging with GDB.
 
-Since this can lead to many variants of the same source code (you can use
-`nimgrep <nimgrep.html>`_ instead of your typical ``grep`` to ignore style
-problems) the compiler provides the command ``pretty`` to help unifying the
-style of source code.  Running ``nim pretty ugly_test.nim`` with this
-example will generate a secondary file named ``ugly_test.pretty.nim`` with the
-following content:
 
-.. code-block:: Nim
-  var MyPrecioussInt = 3
-  # Following line compiles fine!
-  echo MyPrecioussInt
-
-During execution the ``pretty`` command will also run on Nim's standard
-library, since it doesn't differentiate the standard library as something
-special, and hence will warn of many *errors* which are out of your hand to
-fix, creating respective ``.pretty.nim`` files all the way. You can ignore
-these errors if they don't belong to your source and simply compare your
-original version to the new pretty one. In fact, running ``pretty`` on our test
-file will show the following::
-
-  Hint: ugly_test [Processing]
-  ugly_test.nim(1, 4) Error: name should be: myPrecioussInt
-  ugly_test.nim(1, 4) Error: name should be: myPrecioussInt
-
-At the moment ``pretty`` will homogenize the style of symbols but will leave
-important changes for you to review. In this case the command is warning that a
-variable name should not start with a capital letter, which is usually reserved
-to `object types <tut2.html#objects>`_. To learn about the accepted `camel case
-style <https://en.wikipedia.org/wiki/Camelcase>`_ read `Coding Guidelines in
-the Internals of Nim Compiler <intern.html#coding-guidelines>`_ or `Coding
-Guidelines <https://github.com/Araq/Nim/wiki/Coding-Guidelines>`_ and `NEP 1
-: Style Guide for Nim Code
-<https://github.com/Araq/Nim/wiki/NEP-1-:-Style-Guide-for-Nim-Code>`_
-from the Nim `GitHub wiki<https://github.com/Araq/Nim/wiki>`_.
-
-This command is safe to run because it will never attempt to overwrite your
-existing sources, but the respective ``.pretty.nim`` files **will** be
-overwritten without notice.
+StackTrace option
+-----------------
+If the ``stackTrace`` option is turned on, the generated C contains code to
+ensure that proper stack traces are given if the program crashes or an
+uncaught exception is raised.
+
+
+LineTrace option
+----------------
+The ``lineTrace`` option implies the ``stackTrace`` option. If turned on,
+the generated C contains code to ensure that proper stack traces with line
+number information are given if the program crashes or an uncaught exception
+is raised.
+
+Debugger option
+---------------
+The ``debugger`` option enables or disables the *Embedded Nim Debugger*.
+See the documentation of endb_ for further information.
+
+
+Breakpoint pragma
+-----------------
+The *breakpoint* pragma was specially added for the sake of debugging with
+ENDB. See the documentation of `endb <endb.html>`_ for further information.
+
+
+Volatile pragma
+---------------
+The ``volatile`` pragma is for variables only. It declares the variable as
+``volatile``, whatever that means in C/C++ (its semantics are not well defined
+in C/C++).
+
+**Note**: This pragma will not exist for the LLVM backend.
 
 
 DynlibOverride
 ==============
 
-By default Nim's ``dynlib`` pragma causes the compiler to generate 
+By default Nim's ``dynlib`` pragma causes the compiler to generate
 ``GetProcAddress`` (or their Unix counterparts)
 calls to bind to a DLL. With the ``dynlibOverride`` command line switch this
 can be prevented and then via ``--passL`` the static library can be linked
@@ -628,139 +783,139 @@ Nim provides the `doc`:idx: and `doc2`:idx: commands to generate HTML
 documentation from ``.nim`` source files. Only exported symbols will appear in
 the output. For more details `see the docgen documentation <docgen.html>`_.
 
-Nim idetools integration

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

-

-Nim provides language integration with external IDEs through the

-idetools command. See the documentation of `idetools <idetools.html>`_

-for further information.

-

-

-Nim interactive mode

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

-

-The Nim compiler supports an interactive mode. This is also known as

-a `REPL`:idx: (*read eval print loop*). If Nim has been built with the 

-``-d:useGnuReadline`` switch, it uses the GNU readline library for terminal

-input management. To start Nim in interactive mode use the command 

-``nim i``. To quit use the ``quit()`` command. To determine whether an input

-line is an incomplete statement to be continued these rules are used:

-

-1. The line ends with ``[-+*/\\<>!\?\|%&$@~,;:=#^]\s*$`` (operator symbol followed by optional whitespace).

-2. The line starts with a space (indentation).

-3. The line is within a triple quoted string literal. However, the detection 

-   does not work if the line contains more than one ``"""``.

+Nim idetools integration
+========================
+
+Nim provides language integration with external IDEs through the
+idetools command. See the documentation of `idetools <idetools.html>`_
+for further information.
+
+
+Nim interactive mode
+====================
+
+The Nim compiler supports an interactive mode. This is also known as
+a `REPL`:idx: (*read eval print loop*). If Nim has been built with the
+``-d:useGnuReadline`` switch, it uses the GNU readline library for terminal
+input management. To start Nim in interactive mode use the command
+``nim i``. To quit use the ``quit()`` command. To determine whether an input
+line is an incomplete statement to be continued these rules are used:
+
+1. The line ends with ``[-+*/\\<>!\?\|%&$@~,;:=#^]\s*$`` (operator symbol followed by optional whitespace).
+2. The line starts with a space (indentation).
+3. The line is within a triple quoted string literal. However, the detection
+   does not work if the line contains more than one ``"""``.
 
 
 Nim for embedded systems
 ========================
 
-The standard library can be avoided to a point where C code generation 
+The standard library can be avoided to a point where C code generation
 for 16bit micro controllers is feasible. Use the `standalone`:idx: target
 (``--os:standalone``) for a bare bones standard library that lacks any
 OS features.
 
-To make the compiler output code for a 16bit target use the ``--cpu:avr`` 
+To make the compiler output code for a 16bit target use the ``--cpu:avr``
 target.
 
 For example, to generate code for an `AVR`:idx: processor use this command::
-  
+
   nim c --cpu:avr --os:standalone --deadCodeElim:on --genScript x.nim
 
-For the ``standalone`` target you need to provide 
-a file ``panicoverride.nim``. 
-See ``tests/manyloc/standalone/panicoverride.nim`` for an example 
+For the ``standalone`` target one needs to provide
+a file ``panicoverride.nim``.
+See ``tests/manyloc/standalone/panicoverride.nim`` for an example
 implementation.
-

+
 
 Nim for realtime systems
 ========================
 
-See the documentation of Nim's soft realtime `GC <gc.html>`_ for further 
+See the documentation of Nim's soft realtime `GC <gc.html>`_ for further
 information.
 
-

-Debugging with Nim

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

-

-Nim comes with its own *Embedded Nim Debugger*. See

-the documentation of endb_ for further information.

-

-

-Optimizing for Nim

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

-

-Nim has no separate optimizer, but the C code that is produced is very

-efficient. Most C compilers have excellent optimizers, so usually it is

-not needed to optimize one's code. Nim has been designed to encourage

-efficient code: The most readable code in Nim is often the most efficient

-too.

-

-However, sometimes one has to optimize. Do it in the following order:

-

-1. switch off the embedded debugger (it is **slow**!)

-2. turn on the optimizer and turn off runtime checks

-3. profile your code to find where the bottlenecks are

-4. try to find a better algorithm

-5. do low-level optimizations

-

-This section can only help you with the last item.

-

-

-Optimizing string handling

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

-

-String assignments are sometimes expensive in Nim: They are required to

-copy the whole string. However, the compiler is often smart enough to not copy

-strings. Due to the argument passing semantics, strings are never copied when

-passed to subroutines. The compiler does not copy strings that are a result from

-a procedure call, because the callee returns a new string anyway.

-Thus it is efficient to do:

-

-.. code-block:: Nim

-  var s = procA() # assignment will not copy the string; procA allocates a new

-                  # string already

-

-However it is not efficient to do:

-

-.. code-block:: Nim

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

-

-For ``let`` symbols a copy is not always necessary:

-

-.. code-block:: Nim

-  let s = varA    # may only copy a pointer if it safe to do so

-

-

-If you know what you're doing, you can also mark single string (or sequence)

-objects as `shallow`:idx:\:

-

-.. code-block:: Nim

-  var s = "abc"

-  shallow(s) # mark 's' as shallow string

-  var x = s  # now might not copy the string!

-  

-Usage of ``shallow`` is always safe once you know the string won't be modified

-anymore, similar to Ruby's `freeze`:idx:.

-

-

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

-if several different string constants are used. So code like this is reasonably

-efficient:

-

-.. code-block:: Nim

-  case normalize(k.key)

-  of "name": c.name = v

-  of "displayname": c.displayName = v

-  of "version": c.version = v

-  of "os": c.oses = split(v, {';'})

-  of "cpu": c.cpus = split(v, {';'})

-  of "authors": c.authors = split(v, {';'})

-  of "description": c.description = v

-  of "app":

-    case normalize(v)

-    of "console": c.app = appConsole

-    of "gui": c.app = appGUI

-    else: quit(errorStr(p, "expected: console or gui"))

-  of "license": c.license = UnixToNativePath(k.value)

-  else: quit(errorStr(p, "unknown variable: " & k.key))

+
+Debugging with Nim
+==================
+
+Nim comes with its own *Embedded Nim Debugger*. See
+the documentation of endb_ for further information.
+
+
+Optimizing for Nim
+==================
+
+Nim has no separate optimizer, but the C code that is produced is very
+efficient. Most C compilers have excellent optimizers, so usually it is
+not needed to optimize one's code. Nim has been designed to encourage
+efficient code: The most readable code in Nim is often the most efficient
+too.
+
+However, sometimes one has to optimize. Do it in the following order:
+
+1. switch off the embedded debugger (it is **slow**!)
+2. turn on the optimizer and turn off runtime checks
+3. profile your code to find where the bottlenecks are
+4. try to find a better algorithm
+5. do low-level optimizations
+
+This section can only help you with the last item.
+
+
+Optimizing string handling
+--------------------------
+
+String assignments are sometimes expensive in Nim: They are required to
+copy the whole string. However, the compiler is often smart enough to not copy
+strings. Due to the argument passing semantics, strings are never copied when
+passed to subroutines. The compiler does not copy strings that are a result from
+a procedure call, because the callee returns a new string anyway.
+Thus it is efficient to do:
+
+.. code-block:: Nim
+  var s = procA() # assignment will not copy the string; procA allocates a new
+                  # string already
+
+However it is not efficient to do:
+
+.. code-block:: Nim
+  var s = varA    # assignment has to copy the whole string into a new buffer!
+
+For ``let`` symbols a copy is not always necessary:
+
+.. code-block:: Nim
+  let s = varA    # may only copy a pointer if it safe to do so
+
+
+If you know what you're doing, you can also mark single string (or sequence)
+objects as `shallow`:idx:\:
+
+.. code-block:: Nim
+  var s = "abc"
+  shallow(s) # mark 's' as shallow string
+  var x = s  # now might not copy the string!
+
+Usage of ``shallow`` is always safe once you know the string won't be modified
+anymore, similar to Ruby's `freeze`:idx:.
+
+
+The compiler optimizes string case statements: A hashing scheme is used for them
+if several different string constants are used. So code like this is reasonably
+efficient:
+
+.. code-block:: Nim
+  case normalize(k.key)
+  of "name": c.name = v
+  of "displayname": c.displayName = v
+  of "version": c.version = v
+  of "os": c.oses = split(v, {';'})
+  of "cpu": c.cpus = split(v, {';'})
+  of "authors": c.authors = split(v, {';'})
+  of "description": c.description = v
+  of "app":
+    case normalize(v)
+    of "console": c.app = appConsole
+    of "gui": c.app = appGUI
+    else: quit(errorStr(p, "expected: console or gui"))
+  of "license": c.license = UnixToNativePath(k.value)
+  else: quit(errorStr(p, "unknown variable: " & k.key))
diff --git a/doc/nimgrep.txt b/doc/nimgrep.txt
index e2f7b228f..2d429e8b5 100644
--- a/doc/nimgrep.txt
+++ b/doc/nimgrep.txt
@@ -25,9 +25,9 @@ Compile nimgrep with the command::
 And copy the executable somewhere in your ``$PATH``.
 
 
-Command line switches

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

-

+Command line switches
+=====================
+
 Usage:
   nimgrep [options] [pattern] [replacement] (file/directory)*
 Options:
@@ -37,7 +37,7 @@ Options:
   --re                pattern is a regular expression (default); extended 
                       syntax for the regular expression is always turned on
   --recursive         process directories recursively
-  --confirm           confirm each occurence/replacement; there is a chance 
+  --confirm           confirm each occurrence/replacement; there is a chance 
                       to abort any time without touching the file
   --stdin             read pattern from stdin (to avoid the shell's confusing
                       quoting rules)
diff --git a/doc/niminst.txt b/doc/niminst.txt
index d743c5187..ca05cc514 100644
--- a/doc/niminst.txt
+++ b/doc/niminst.txt
@@ -190,6 +190,6 @@ Real world example
 The installers for the Nim compiler itself are generated by niminst. Have a
 look at its configuration file:
 
-.. include:: compiler/nim.ini
+.. include:: compiler/installer.ini
      :literal:
 
diff --git a/doc/pegdocs.txt b/doc/pegdocs.txt
index d22d81a5a..118949cad 100644
--- a/doc/pegdocs.txt
+++ b/doc/pegdocs.txt
@@ -213,7 +213,7 @@ example ``*`` should not be greedy, so ``\[.*?\]`` should be used instead.
 PEG construction
 ----------------
 There are two ways to construct a PEG in Nim code:
-(1) Parsing a string into an AST which consists of `TPeg` nodes with the
+(1) Parsing a string into an AST which consists of `Peg` nodes with the
     `peg` proc.
 (2) Constructing the AST directly with proc calls. This method does not
     support constructing rules, only simple expressions and is not as
diff --git a/doc/sets_fragment.txt b/doc/sets_fragment.txt
index 59d434807..84b13e672 100644
--- a/doc/sets_fragment.txt
+++ b/doc/sets_fragment.txt
@@ -8,9 +8,9 @@ can also be used to include elements (and ranges of elements):
 
 .. code-block:: nim
   type
-    TCharSet = set[char]
+    CharSet = set[char]
   var
-    x: TCharSet
+    x: CharSet
   x = {'a'..'z', '0'..'9'} # This constructs a set that contains the
                            # letters from 'a' to 'z' and the digits
                            # from '0' to '9'
diff --git a/doc/tut1.txt b/doc/tut1.txt
index 1a6530e6c..cb5a0c8dd 100644
--- a/doc/tut1.txt
+++ b/doc/tut1.txt
@@ -139,7 +139,7 @@ Numbers
 Numerical literals are written as in most other languages. As a special twist,
 underscores are allowed for better readability: ``1_000_000`` (one million).
 A number that contains a dot (or 'e' or 'E') is a floating point literal:
-``1.0e9`` (one million). Hexadecimal literals are prefixed with ``0x``,
+``1.0e9`` (one billion). Hexadecimal literals are prefixed with ``0x``,
 binary literals with ``0b`` and octal literals with ``0o``. A leading zero
 alone does not produce an octal.
 
@@ -749,7 +749,8 @@ Forward declarations
 --------------------
 
 Every variable, procedure, etc. needs to be declared before it can be used.
-(The reason for this is compilation efficiency.)
+(The reason for this is that it is non-trivial to do better than that in a
+language that supports meta programming as extensively as Nim does.)
 However, this cannot be done for mutually recursive procedures:
 
 .. code-block:: nim
@@ -767,7 +768,7 @@ introduced to the compiler before it is completely defined. The syntax for
 such a forward declaration is simple: just omit the ``=`` and the
 procedure's body.
 
-Later versions of the language may get rid of the need for forward
+Later versions of the language will weaken the requirements for forward
 declarations.
 
 The example also shows that a proc's body can consist of a single expression
@@ -957,6 +958,19 @@ versa. The `toInt <system.html#toInt>`_ and `toFloat <system.html#toFloat>`_
 procs can be used for these conversions.
 
 
+Type Conversion
+---------------
+Conversion between basic types in nim is performed by using the
+type as a function:
+
+.. code-block:: nim
+  var
+    x: int32 = 1.int32   # same as calling int32(1)
+    y: int8  = int8('a') # 'a' == 97'i8
+    z: float = 2.5       # int(2.5) rounds down to 2
+    sum: int = int(x) + int(y) + int(z) # sum == 100
+
+
 Internal type representation
 ============================
 
@@ -1013,17 +1027,16 @@ at runtime by 0, the second by 1 and so on. Example:
 .. code-block:: nim
 
   type
-    TDirection = enum
+    Direction = enum
       north, east, south, west
 
-  var x = south      # `x` is of type `TDirection`; its value is `south`
+  var x = south      # `x` is of type `Direction`; its value is `south`
   echo($x)           # writes "south" to `stdout`
 
-(To prefix a new type with the letter ``T`` is a convention in Nim.)
 All comparison operators can be used with enumeration types.
 
 An enumeration's symbol can be qualified to avoid ambiguities:
-``TDirection.south``.
+``Direction.south``.
 
 The ``$`` operator can convert any enumeration value to its name, the ``ord``
 proc to its underlying integer value.
@@ -1037,7 +1050,7 @@ An explicit ordered enum can have *holes*:
 
 .. code-block:: nim
   type
-    TMyEnum = enum
+    MyEnum = enum
       a = 2, b = 4, c = 89
 
 
@@ -1058,7 +1071,7 @@ Operation             Comment
 ``dec(x, n)``         decrements `x` by `n`; `n` is an integer
 ``succ(x)``           returns the successor of `x`
 ``succ(x, n)``        returns the `n`'th successor of `x`
-``prec(x)``           returns the predecessor of `x`
+``pred(x)``           returns the predecessor of `x`
 ``pred(x, n)``        returns the `n`'th predecessor of `x`
 -----------------     --------------------------------------------------------
 
@@ -1075,11 +1088,11 @@ A subrange type is a range of values from an integer or enumeration type
 
 .. code-block:: nim
   type
-    TSubrange = range[0..5]
+    Subrange = range[0..5]
 
 
-``TSubrange`` is a subrange of ``int`` which can only hold the values 0
-to 5. Assigning any other value to a variable of type ``TSubrange`` is a
+``Subrange`` is a subrange of ``int`` which can only hold the values 0
+to 5. Assigning any other value to a variable of type ``Subrange`` is a
 compile-time or runtime error. Assignments from the base type to one of its
 subrange types (and vice versa) are allowed.
 
@@ -1106,9 +1119,9 @@ Arrays can be constructed via ``[]``:
 .. code-block:: nim
 
   type
-    TIntArray = array[0..5, int] # an array that is indexed with 0..5
+    IntArray = array[0..5, int] # an array that is indexed with 0..5
   var
-    x: TIntArray
+    x: IntArray
   x = [1, 2, 3, 4, 5, 6]
   for i in low(x)..high(x):
     echo(x[i])
@@ -1127,13 +1140,13 @@ array `a` and `high(a) <system.html#high>`_ the highest valid index.
 
 .. code-block:: nim
   type
-    TDirection = enum
+    Direction = enum
       north, east, south, west
-    TBlinkLights = enum
+    BlinkLights = enum
       off, on, slowBlink, mediumBlink, fastBlink
-    TLevelSetting = array[north..west, TBlinkLights]
+    LevelSetting = array[north..west, BlinkLights]
   var
-    level : TLevelSetting
+    level: LevelSetting
   level[north] = on
   level[south] = slowBlink
   level[east] = fastBlink
@@ -1152,9 +1165,9 @@ subdivided in height levels accessed through their integer index:
 
 .. code-block:: nim
   type
-    TLightTower = array[1..10, TLevelSetting]
+    LightTower = array[1..10, LevelSetting]
   var
-    tower: TLightTower
+    tower: LightTower
   tower[1][north] = slowBlink
   tower[1][east] = mediumBlink
   echo len(tower)     # --> 10
@@ -1165,24 +1178,24 @@ subdivided in height levels accessed through their integer index:
   #tower[0][1] = on
 
 Note how the built-in ``len`` proc returns only the array's first dimension
-length.  Another way of defining the ``TLightTower`` to show better its
-nested nature would be to omit the previous definition of the ``TLevelSetting``
+length.  Another way of defining the ``LightTower`` to show better its
+nested nature would be to omit the previous definition of the ``LevelSetting``
 type and instead write it embedded directly as the type of the first dimension:
 
 .. code-block:: nim
   type
-    TLightTower = array[1..10, array[north..west, TBlinkLights]]
+    LightTower = array[1..10, array[north..west, BlinkLights]]
 
 It is quite frequent to have arrays start at zero, so there's a shortcut syntax
 to specify a range from zero to the specified index minus one:
 
 .. code-block:: nim
   type
-    TIntArray = array[0..5, int] # an array that is indexed with 0..5
-    TQuickArray = array[6, int]  # an array that is indexed with 0..5
+    IntArray = array[0..5, int] # an array that is indexed with 0..5
+    QuickArray = array[6, int]  # an array that is indexed with 0..5
   var
-    x: TIntArray
-    y: TQuickArray
+    x: IntArray
+    y: QuickArray
   x = [1, 2, 3, 4, 5, 6]
   y = x
   for i in low(x)..high(x):
@@ -1301,9 +1314,9 @@ Slices
 ------
 
 Slices look similar to subranges types in syntax but are used in a different
-context. A slice is just an object of type TSlice which contains two bounds,
+context. A slice is just an object of type Slice which contains two bounds,
 `a` and `b`. By itself a slice is not very useful, but other collection types
-define operators which accept TSlice objects to define ranges.
+define operators which accept Slice objects to define ranges.
 
 .. code-block:: nim
 
@@ -1311,7 +1324,7 @@ define operators which accept TSlice objects to define ranges.
     a = "Nim is a progamming language"
     b = "Slices are useless."
 
-  echo a[10..15] # --> 'a prog'
+  echo a[7..12] # --> 'a prog'
   b[11.. -2] = "useful"
   echo b # --> 'Slices are useful.'
 
@@ -1338,11 +1351,11 @@ integer.
 .. code-block:: nim
 
   type
-    TPerson = tuple[name: string, age: int] # type representing a person:
-                                            # a person consists of a name
-                                            # and an age
+    Person = tuple[name: string, age: int] # type representing a person:
+                                           # a person consists of a name
+                                           # and an age
   var
-    person: TPerson
+    person: Person
   person = (name: "Peter", age: 30)
   # the same, but less readable:
   person = ("Peter", 30)
@@ -1361,7 +1374,7 @@ integer.
   # The following line does not compile, they are different tuples!
   #person = building
   # --> Error: type mismatch: got (tuple[street: string, number: int])
-  #     but expected 'TPerson'
+  #     but expected 'Person'
   
   # The following works because the field names and types are the same.
   var teacher: tuple[name: string, age: int] = ("Mark", 42)
@@ -1436,16 +1449,16 @@ operators perform implicit dereferencing operations for reference types:
 .. code-block:: nim
 
   type
-    PNode = ref TNode
-    TNode = tuple[le, ri: PNode, data: int]
+    Node = ref NodeObj
+    NodeObj = object 
+      le, ri: PNode
+      data: int
   var
-    n: PNode
+    n: Node
   new(n)
   n.data = 9 
   # no need to write n[].data; in fact n[].data is highly discouraged!
 
-(As a convention, reference types use a 'P' prefix.)
-
 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 <system.html>`_
@@ -1573,11 +1586,11 @@ rules apply:
 
 .. code-block:: nim
   # Module A
-  proc x*(a: int): string = result = $a
+  proc x*(a: int): string = $a
 
 .. code-block:: nim
   # Module B
-  proc x*(a: string): string = result = $a
+  proc x*(a: string): string = $a
 
 .. code-block:: nim
   # Module C
diff --git a/doc/tut2.txt b/doc/tut2.txt
index d8f9071a9..e1ac20074 100644
--- a/doc/tut2.txt
+++ b/doc/tut2.txt
@@ -11,8 +11,7 @@ Nim Tutorial (Part II)
 Introduction
 ============
 
-  "Object-oriented programming is an exceptionally bad idea which could
-  only have originated in California." --Edsger Dijkstra
+  "Repetition renders the ridiculous reasonable." -- Norman Wildberger
 
 
 This document is a tutorial for the advanced constructs of the *Nim*
@@ -36,9 +35,9 @@ Object Oriented Programming
 ===========================
 
 While Nim's support for object oriented programming (OOP) is minimalistic,
-powerful OOP technics can be used. OOP is seen as *one* way to design a
+powerful OOP techniques can be used. OOP is seen as *one* way to design a
 program, not *the only* way. Often a procedural approach leads to simpler
-and more efficient code. In particular, prefering composition over inheritance
+and more efficient code. In particular, preferring composition over inheritance
 is often the better design.
 
 
@@ -57,19 +56,20 @@ Objects have access to their type at runtime. There is an
 
 .. code-block:: nim
   type
-    TPerson = object of TObject
+    Person = ref object of RootObj
       name*: string  # the * means that `name` is accessible from other modules
       age: int       # no * means that the field is hidden from other modules
 
-    TStudent = object of TPerson # TStudent inherits from TPerson
-      id: int                    # with an id field
+    Student = ref object of Person # Student inherits from Person
+      id: int                      # with an id field
 
   var
-    student: TStudent
-    person: TPerson
-  assert(student of TStudent) # is true
+    student: Student
+    person: Person
+  assert(student of Student) # is true
   # object construction:
-  student = TStudent(name: "Anton", age: 5, id: 2)
+  student = Student(name: "Anton", age: 5, id: 2)
+  echo student[]
 
 Object fields that should be visible from outside the defining module have to
 be marked by ``*``. In contrast to tuples, different object types are
@@ -77,12 +77,15 @@ never *equivalent*. New object types can only be defined within a type
 section.
 
 Inheritance is done with the ``object of`` syntax. Multiple inheritance is
-currently not supported. If an object type has no suitable ancestor, ``TObject``
-can be used as its ancestor, but this is only a convention. Objects that have 
-no ancestor are implicitly ``final``. You can use the ``inheritable`` pragma 
-to introduce new object roots apart from ``system.TObject``. (This is used
+currently not supported. If an object type has no suitable ancestor, ``RootObj``
+can be used as its ancestor, but this is only a convention. Objects that have
+no ancestor are implicitly ``final``. You can use the ``inheritable`` pragma
+to introduce new object roots apart from ``system.RootObj``. (This is used
 in the GTK wrapper for instance.)
 
+Ref objects should be used whenever inheritance is used. It isn't strictly
+necessary, but with non-ref objects assignments such as ``let person: Person =
+Student(id: 123)`` will truncate subclass fields.
 
 **Note**: Composition (*has-a* relation) is often preferable to inheritance
 (*is-a* relation) for simple code reuse. Since objects are value types in
@@ -101,15 +104,15 @@ Example:
 
 .. code-block:: nim
   type
-    PNode = ref TNode # a traced reference to a TNode
-    TNode = object
-      le, ri: PNode   # left and right subtrees
-      sym: ref TSym   # leaves contain a reference to a TSym
+    Node = ref NodeObj # a traced reference to a NodeObj
+    NodeObj = object
+      le, ri: Node     # left and right subtrees
+      sym: ref Sym     # leaves contain a reference to a Sym
 
-    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
+    Sym = 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
 
 
 Type conversions
@@ -127,11 +130,11 @@ The syntax for type conversions is ``destination_type(expression_to_convert)``
 (like an ordinary call):
 
 .. code-block:: nim
-  proc getID(x: TPerson): int =
-    TStudent(x).id
+  proc getID(x: Person): int =
+    Student(x).id
 
 The ``InvalidObjectConversionError`` exception is raised if ``x`` is not a
-``TStudent``.
+``Student``.
 
 
 Object variants
@@ -143,18 +146,18 @@ An example:
 
 .. code-block:: nim
 
-  # This is an example how an abstract syntax tree could be modeled in Nim
+  # This is an example how an abstract syntax tree could be modelled in Nim
   type
-    TNodeKind = enum  # the different node types
+    NodeKind = enum  # the different node types
       nkInt,          # a leaf with an integer value
       nkFloat,        # a leaf with a float value
       nkString,       # a leaf with a string value
       nkAdd,          # an addition
       nkSub,          # a subtraction
       nkIf            # an if statement
-    PNode = ref TNode
-    TNode = object
-      case kind: TNodeKind  # the ``kind`` field is the discriminator
+    Node = ref NodeObj
+    NodeObj = object
+      case kind: NodeKind  # the ``kind`` field is the discriminator
       of nkInt: intVal: int
       of nkFloat: floatVal: float
       of nkString: strVal: string
@@ -200,7 +203,7 @@ This method call syntax is not restricted to objects, it can be used
 for any type:
 
 .. code-block:: nim
-  
+
   echo("abc".len) # is the same as echo(len("abc"))
   echo("abc".toUpper())
   echo({'a', 'b', 'c'}.card)
@@ -213,7 +216,7 @@ So "pure object oriented" code is easy to write:
 
 .. code-block:: nim
   import strutils
-  
+
   stdout.writeln("Give a list of numbers (separated by spaces): ")
   stdout.write(stdin.readLine.split.map(parseInt).max.`$`)
   stdout.writeln(" is the maximum!")
@@ -227,23 +230,23 @@ the same. But setting a value is different; for this a special setter syntax
 is needed:
 
 .. code-block:: nim
-  
+
   type
-    TSocket* = object of TObject
+    Socket* = ref object of RootObj
       FHost: int # cannot be accessed from the outside of the module
                  # the `F` prefix is a convention to avoid clashes since
                  # the accessors are named `host`
 
-  proc `host=`*(s: var TSocket, value: int) {.inline.} =
+  proc `host=`*(s: var Socket, value: int) {.inline.} =
     ## setter of hostAddr
     s.FHost = value
-  
-  proc host*(s: TSocket): int {.inline.} =
+
+  proc host*(s: Socket): int {.inline.} =
     ## getter of hostAddr
     s.FHost
 
-  var
-    s: TSocket
+  var s: Socket
+  new s
   s.host = 34  # same as `host=`(s, 34)
 
 (The example also shows ``inline`` procedures.)
@@ -254,10 +257,10 @@ The ``[]`` array access operator can be overloaded to provide
 
 .. code-block:: nim
   type
-    TVector* = object
+    Vector* = object
       x, y, z: float
 
-  proc `[]=`* (v: var TVector, i: int, value: float) =
+  proc `[]=`* (v: var Vector, i: int, value: float) =
     # setter
     case i
     of 0: v.x = value
@@ -265,7 +268,7 @@ The ``[]`` array access operator can be overloaded to provide
     of 2: v.z = value
     else: assert(false)
 
-  proc `[]`* (v: TVector, i: int): float =
+  proc `[]`* (v: Vector, i: int): float =
     # getter
     case i
     of 0: result = v.x
@@ -285,7 +288,7 @@ Procedures always use static dispatch. For dynamic dispatch replace the
 
 .. code-block:: nim
   type
-    PExpr = ref object of TObject ## abstract base class for an expression
+    PExpr = ref object of RootObj ## abstract base class for an expression
     PLiteral = ref object of PExpr
       x: int
     PPlusExpr = ref object of PExpr
@@ -295,18 +298,18 @@ Procedures always use static dispatch. For dynamic dispatch replace the
   method eval(e: PExpr): int =
     # override this base method
     quit "to override!"
-  
+
   method eval(e: PLiteral): int = e.x
   method eval(e: PPlusExpr): int = eval(e.a) + eval(e.b)
-  
+
   proc newLit(x: int): PLiteral = PLiteral(x: x)
   proc newPlus(a, b: PExpr): PPlusExpr = PPlusExpr(a: a, b: b)
-  
+
   echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
-  
+
 Note that in the example the constructors ``newLit`` and ``newPlus`` are procs
-because they should use static binding, but ``eval`` is a method because it
-requires dynamic binding.
+because it makes more sense for them to use static binding, but ``eval`` is a
+method because it requires dynamic binding.
 
 In a multi-method all parameters that have an object type are used for the
 dispatching:
@@ -314,29 +317,30 @@ dispatching:
 .. code-block:: nim
 
   type
-    TThing = object of TObject
-    TUnit = object of TThing
+    Thing = ref object of RootObj
+    Unit = ref object of Thing
       x: int
-      
-  method collide(a, b: TThing) {.inline.} =
+
+  method collide(a, b: Thing) {.inline.} =
     quit "to override!"
-    
-  method collide(a: TThing, b: TUnit) {.inline.} =
+
+  method collide(a: Thing, b: Unit) {.inline.} =
     echo "1"
-  
-  method collide(a: TUnit, b: TThing) {.inline.} =
+
+  method collide(a: Unit, b: Thing) {.inline.} =
     echo "2"
-  
-  var
-    a, b: TUnit
+
+  var a, b: Unit
+  new a
+  new b
   collide(a, b) # output: 2
 
 
 As the example demonstrates, invocation of a multi-method cannot be ambiguous:
 Collide 2 is preferred over collide 1 because the resolution works from left to
-right. Thus ``TUnit, TThing`` is preferred over ``TThing, TUnit``.
+right. Thus ``Unit, Thing`` is preferred over ``Thing, Unit``.
 
-**Perfomance note**: Nim does not produce a virtual method table, but
+**Performance note**: Nim does not produce a virtual method table, but
 generates dispatch trees. This avoids the expensive indirect branch for method
 calls and enables inlining. However, other optimizations like compile time
 evaluation or dead code elimination do not work with methods.
@@ -480,18 +484,18 @@ containers:
 
 .. code-block:: nim
   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] # type that is exported
+    BinaryTreeObj[T] = object # BinaryTree is a generic type with
+                              # with generic param ``T``
+      le, ri: BinaryTree[T]   # left and right subtrees; may be nil
+      data: T                 # the data stored in a node
+    BinaryTree*[T] = ref BinaryTreeObj[T] # type that is exported
 
-  proc newNode*[T](data: T): PBinaryTree[T] =
+  proc newNode*[T](data: T): BinaryTree[T] =
     # constructor for a node
     new(result)
     result.data = data
 
-  proc add*[T](root: var PBinaryTree[T], n: PBinaryTree[T]) =
+  proc add*[T](root: var BinaryTree[T], n: BinaryTree[T]) =
     # insert a node into the tree
     if root == nil:
       root = n
@@ -512,24 +516,24 @@ containers:
             return
           it = it.ri
 
-  proc add*[T](root: var PBinaryTree[T], data: T) =
+  proc add*[T](root: var BinaryTree[T], data: T) =
     # convenience proc:
     add(root, newNode(data))
 
-  iterator preorder*[T](root: PBinaryTree[T]): T =
+  iterator preorder*[T](root: BinaryTree[T]): T =
     # Preorder traversal of a binary tree.
     # Since recursive iterators are not yet implemented,
     # this uses an explicit stack (which is more efficient anyway):
-    var stack: seq[PBinaryTree[T]] = @[root]
+    var stack: seq[BinaryTree[T]] = @[root]
     while stack.len > 0:
       var n = stack.pop()
       while n != nil:
         yield n.data
         add(stack, n.ri)  # push right subtree onto the stack
         n = n.le          # and follow the left pointer
-      
+
   var
-    root: PBinaryTree[string] # instantiate a PBinaryTree with ``string``
+    root: BinaryTree[string] # instantiate a BinaryTree with ``string``
   add(root, newNode("hello")) # instantiates ``newNode`` and ``add``
   add(root, "world")          # instantiates the second ``add`` proc
   for str in preorder(root):
@@ -579,7 +583,7 @@ simple proc for logging:
 
   proc log(msg: string) {.inline.} =
     if debug: stdout.writeln(msg)
-  
+
   var
     x = 4
   log("x has the value: " & $x)
@@ -596,7 +600,7 @@ Turning the ``log`` proc into a template solves this problem:
 
   template log(msg: string) =
     if debug: stdout.writeln(msg)
-  
+
   var
     x = 4
   log("x has the value: " & $x)
@@ -623,11 +627,11 @@ via a special ``:`` syntax:
         close(f)
     else:
       quit("cannot open: " & fn)
-      
+
   withFile(txt, "ttempl3.txt", fmWrite):
     txt.writeln("line 1")
     txt.writeln("line 2")
-  
+
 In the example the two ``writeln`` statements are bound to the ``body``
 parameter. The ``withFile`` template contains boilerplate code and helps to
 avoid a common bug: to forget to close the file. Note how the
@@ -641,7 +645,7 @@ Macros
 Macros enable advanced compile-time code transformations, but they cannot
 change Nim's syntax. However, this is no real restriction because Nim's
 syntax is flexible enough anyway. Macros have to be implemented in pure Nim
-code if `foreign function interface (FFI)
+code if the `foreign function interface (FFI)
 <manual.html#foreign-function-interface>`_ is not enabled in the compiler, but
 other than that restriction (which at some point in the future will go away)
 you can write any kind of Nim code and the compiler will run it at compile
@@ -736,14 +740,6 @@ regular expressions:
     return tkUnknown
 
 
-Term rewriting macros
----------------------
-
-Term rewriting macros can be used to enhance the compilation process
-with user defined optimizations; see this `document <trmacros.html>`_ for 
-further information.
-
-
 Building your first macro
 -------------------------
 
@@ -864,7 +860,7 @@ precisely made for compilation time (just like `gorge <system.html#gorge>`_
 which executes an external program and captures its output).
 
 The interesting thing is that our macro does not return a runtime `Table
-<tables.html#TTable>`_ object. Instead, it builds up Nim source code into
+<tables.html#Table>`_ object. Instead, it builds up Nim source code into
 the ``source`` variable.  For each line of the configuration file a ``const``
 variable will be generated (line 15).  To avoid conflicts we prefix these
 variables with ``cfg``. In essence, what the compiler is doing is replacing
diff --git a/examples/cross_calculator/android/readme.txt b/examples/cross_calculator/android/readme.txt
index f8b16d4fc..51fa9c6fd 100644
--- a/examples/cross_calculator/android/readme.txt
+++ b/examples/cross_calculator/android/readme.txt
@@ -1,20 +1,20 @@
 In this directory you will find the Android platform cross-calculator sample.
 
-Due to the nature of Android being java and nimrod generating C code, the build
+Due to the nature of Android being java and Nim generating C code, the build
 process is slightly more complex because jni code has to be written to bridge
-both languages. In a distant future it may be possible for nimrod to generate
+both languages. In a distant future it may be possible for Nim to generate
 the whole jni bridge, but for the moment this is manual work.
 
-For the jni bridge to work first the java code is compiled with the nimrod code
+For the jni bridge to work first the java code is compiled with the Nim code
 just declared as a native method which will be resolved at runtime. The scripts
-nimbuild.sh and jnibuild.sh are in charge of building the nimrod code and
+nimbuild.sh and jnibuild.sh are in charge of building the Nim code and
 generating the jni bridge from the java code respectively. Finally, the
 ndk-build command from the android ndk tools has to be run to build the binary
-libary which will be installed along the final apk.
+library which will be installed along the final apk.
 
 All these steps are wrapped in the ant build script through the customization
 of the -post-compile rule. If you have the android ndk tools installed and you
-modify scripts/nimbuild.sh to point to the directory where you have nimrod
+modify scripts/nimbuild.sh to point to the directory where you have Nim
 installed on your system, you can simply run "ant debug" to build everything.
 
 Once the apk is built you can install it on your device or emulator with the
diff --git a/examples/cross_calculator/ios/readme.txt b/examples/cross_calculator/ios/readme.txt
index e75db72bf..83538aad7 100644
--- a/examples/cross_calculator/ios/readme.txt
+++ b/examples/cross_calculator/ios/readme.txt
@@ -1,10 +1,10 @@
 In this directory you will find the iOS platform cross-calculator sample.
 
 The iOS version of the code builds a view controller in charge of displaying
-the interface to the user. The nimrod backend code is compiled into C code and
+the interface to the user. The Nim backend code is compiled into C code and
 put into build/nimrod as a pre-build phase of the project.
 
-When the calculate button is used the view controller calls the nimrod code to
+When the calculate button is used the view controller calls the Nim code to
 delegate the logic of the operation and puts the result in a label for display.
 All interface error checks are implemented in the view controller.
 
diff --git a/examples/cross_calculator/ios/src/NRViewController.m b/examples/cross_calculator/ios/src/NRViewController.m
index bd0df7d6b..f629bfc09 100644
--- a/examples/cross_calculator/ios/src/NRViewController.m
+++ b/examples/cross_calculator/ios/src/NRViewController.m
@@ -40,7 +40,7 @@
 	// Dismiss all keyboards.
 	[self backgroundTouched];
 
-	// Call nimrod code, store the result and display it.
+	// Call Nim code, store the result and display it.
 	const int a = [self.aText.text intValue];
 	const int b = [self.bText.text intValue];
 	const int c = myAdd(a, b);
@@ -55,7 +55,7 @@
 	[self.bText resignFirstResponder];
 }
 
-/** Custom loadView method for backwards compatiblity.
+/** Custom loadView method for backwards compatibility.
  * Unfortunately I've been unable to coerce Xcode 4.4 to generate nib files
  * which are compatible with my trusty iOS 3.0 ipod touch so in order to be
  * fully compatible for all devices we have to build the interface manually in
@@ -66,7 +66,7 @@
  * was used on the xib file and slightly modified to fit the original property
  * names. Which means here is a lot of garbage you would never write in real
  * life. Please ignore the following "wall of code" for the purposes of
- * learning Nimrod, this is all just because Apple can't be bothered to
+ * learning Nim, this is all just because Apple can't be bothered to
  * maintain backwards compatibility properly.
  */
 - (void)loadView
@@ -102,7 +102,7 @@
 	label4.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
 	label4.frame = CGRectMake(0.0, 0.0, 320.0, 34.0);
 	label4.tag = 2;
-	label4.text = @"Nimrod Crossplatform Calculator";
+	label4.text = @"Nim Crossplatform Calculator";
 	label4.textAlignment = UITextAlignmentCenter;
 
 	UIButton *background_button = [UIButton buttonWithType:UIButtonTypeCustom];
diff --git a/examples/cross_calculator/lazarus/readme.txt b/examples/cross_calculator/lazarus/readme.txt
index ec222a815..2d5048445 100644
--- a/examples/cross_calculator/lazarus/readme.txt
+++ b/examples/cross_calculator/lazarus/readme.txt
@@ -1,8 +1,8 @@
-This example demonstrates how to use Nimrod with Lazarus. The GUI is generated

-with Lazarus, while the "backend" is written in Nimrod. To compile the example,

+This example demonstrates how to use Nim with Lazarus. The GUI is generated

+with Lazarus, while the "backend" is written in Nim. To compile the example,

 use this command:

 

-  nimrod c --app:gui --no_main --no_linking backend.nim

+  nim c --app:gui --no_main --no_linking backend.nim

 

 Open the ``nimlaz.lpi`` file in Lazarus and run the program.

 

diff --git a/examples/cross_calculator/nimrod_backend/backend.nim b/examples/cross_calculator/nim_backend/backend.nim
index ffa4311f9..ffa4311f9 100644
--- a/examples/cross_calculator/nimrod_backend/backend.nim
+++ b/examples/cross_calculator/nim_backend/backend.nim
diff --git a/examples/cross_calculator/nimrod_commandline/nimrod.cfg b/examples/cross_calculator/nim_commandline/nim.cfg
index c1aedcf6a..41c034430 100644
--- a/examples/cross_calculator/nimrod_commandline/nimrod.cfg
+++ b/examples/cross_calculator/nim_commandline/nim.cfg
@@ -1,4 +1,4 @@
 # Nimrod configuration file.
 # The file is used only to add the path of the backend to the compiler options.
 
-path="../nimrod_backend"
+path="../nim_backend"
diff --git a/examples/cross_calculator/nimrod_commandline/nimcalculator.nim b/examples/cross_calculator/nim_commandline/nimcalculator.nim
index 440834ca8..69d62a90c 100644
--- a/examples/cross_calculator/nimrod_commandline/nimcalculator.nim
+++ b/examples/cross_calculator/nim_commandline/nimcalculator.nim
@@ -21,7 +21,7 @@ type
     cmdParams,          # Two valid parameters were provided
     cmdInteractive      # No parameters were provided, run interactive mode
 
-  TParamConfig = object of TObject
+  TParamConfig = object of RootObj
     action: TCommand      # store the type of operation
     paramA, paramB: int   # possibly store the valid parameters
 
@@ -63,7 +63,7 @@ proc parseCmdLine(): TParamConfig =
           stdout.write USAGE
           quit "Unexpected option: " & key, 2
       of cmdEnd: break
-  except EInvalidValue:
+  except ValueError:
     stdout.write USAGE
     quit "Invalid value " & val &  " for parameter " & key, 3
 
@@ -85,7 +85,7 @@ proc parseUserInput(question: string): int =
     try:
       result = input.parseInt
       break
-    except EInvalidValue:
+    except ValueError:
       if input.len < 1: quit "Blank line detected, quitting.", 0
       echo "Sorry, `$1' doesn't seem to be a valid integer" % input
 
diff --git a/examples/cross_calculator/nimrod_commandline/readme.txt b/examples/cross_calculator/nim_commandline/readme.txt
index 5430e7b47..f95bd962e 100644
--- a/examples/cross_calculator/nimrod_commandline/readme.txt
+++ b/examples/cross_calculator/nim_commandline/readme.txt
@@ -1,10 +1,10 @@
-In this directory you will find the nimrod commandline version of the
+In this directory you will find the nim commandline version of the
 cross-calculator sample.
 
 The commandline interface can be used non interactively through switches, or
 interactively when running the command without parameters.
 
 Compilation is fairly easy despite having the source split in different
-directories. Thanks to the nimrod.cfg file, which adds the ../nimrod_backend
+directories. Thanks to the nim.cfg file, which adds the ../nim_backend
 directory as a search path, you can compile and run the example just fine from
-the command line with 'nimrod c -r nimcalculator.nim'.
+the command line with 'nim c -r nimcalculator.nim'.
diff --git a/examples/cross_calculator/readme.txt b/examples/cross_calculator/readme.txt
index 55c403d0e..12ad558d4 100644
--- a/examples/cross_calculator/readme.txt
+++ b/examples/cross_calculator/readme.txt
@@ -1,13 +1,13 @@
-The cross platform calculator illustrates how to use Nimrod to create a backend

+The cross platform calculator illustrates how to use Nim to create a backend

 called by different native user interfaces.

 

 Since the purpose of the example is to show how the cross platform code

 interacts with Nimrod the actual backend code is just a simple addition proc.

-By keeping your program logic in Nimrod you can easily reuse it in different

+By keeping your program logic in Nim you can easily reuse it in different

 platforms.

 

 To avoid duplication of code, the backend code lies in a separate directory and

 each platform compiles it with a different custom build process, usually

 generating C code in a temporary build directory.

 

-For a more ellaborate and useful example see the cross_todo example.

+For a more elaborate and useful example see the cross_todo example.

diff --git a/examples/cross_todo/nimrod_backend/backend.nim b/examples/cross_todo/nim_backend/backend.nim
index 89e7d0b7e..5b49bc4a9 100644
--- a/examples/cross_todo/nimrod_backend/backend.nim
+++ b/examples/cross_todo/nim_backend/backend.nim
@@ -13,7 +13,7 @@ type
     text*: string             ## Description of the task to do.
     priority*: int            ## The priority can be any user defined integer.
     isDone*: bool             ## Done todos are still kept marked.
-    modificationDate: TTime   ## The modification time can't be modified from
+    modificationDate: Time    ## The modification time can't be modified from
                               ## outside of this module, use the
                               ## getModificationDate accessor.
 
@@ -64,7 +64,7 @@ proc openDatabase*(path: string): TDbConn =
 # - Procs related to TTodo objects
 #
 proc initFromDB(id: int64; text: string; priority: int, isDone: bool;
-               modificationDate: TTime): TTodo =
+               modificationDate: Time): TTodo =
   ## Returns an initialized TTodo object created from database parameters.
   ##
   ## The proc assumes all values are right. Note this proc is NOT exported.
@@ -81,7 +81,7 @@ proc getId*(todo: TTodo): int64 =
   return todo.id
 
 
-proc getModificationDate*(todo: TTodo): TTime =
+proc getModificationDate*(todo: TTodo): Time =
   ## Returns the last modification date of a TTodo entry.
   return todo.modificationDate
 
@@ -91,7 +91,7 @@ proc update*(todo: var TTodo; conn: TDbConn): bool =
   ##
   ## Use this method if you (or another entity) have modified the database and
   ## want to update the object you have with whatever the database has stored.
-  ## Returns true if the update suceeded, or false if the object was not found
+  ## Returns true if the update succeeded, or false if the object was not found
   ## in the database any more, in which case you should probably get rid of the
   ## TTodo object.
   assert(todo.id >= 0, "The identifier of the todo entry can't be negative")
@@ -99,14 +99,14 @@ proc update*(todo: var TTodo; conn: TDbConn): bool =
     FROM Todos WHERE id = ?"""
 
   try:
-    let rows = conn.GetAllRows(query, $todo.id)
+    let rows = conn.getAllRows(query, $todo.id)
     if len(rows) < 1:
       return
     assert(1 == len(rows), "Woah, didn't expect so many rows")
     todo.text = rows[0][0]
     todo.priority = rows[0][1].parseInt
     todo.isDone = rows[0][2].parseBool
-    todo.modificationDate = TTime(rows[0][3].parseInt)
+    todo.modificationDate = Time(rows[0][3].parseInt)
     result = true
   except:
     echo("Something went wrong selecting for id " & $todo.id)
@@ -202,12 +202,12 @@ proc getPagedTodos*(conn: TDbConn; params: TPagedParams;
   #echo("Query " & string(query))
   #echo("args: " & args.join(", "))
 
-  var newId: biggestInt
+  var newId: BiggestInt
   for row in conn.fastRows(query, args):
     let numChars = row[0].parseBiggestInt(newId)
     assert(numChars > 0, "Huh, couldn't parse identifier from database?")
     result.add(initFromDB(int64(newId), row[1], row[2].parseInt,
-        row[3].parseBool, TTime(row[4].parseInt)))
+        row[3].parseBool, Time(row[4].parseInt)))
 
 
 proc getTodo*(conn: TDbConn; todoId: int64): ref TTodo =
diff --git a/examples/cross_todo/nimrod_backend/readme.txt b/examples/cross_todo/nim_backend/readme.txt
index 6529f2e67..16cb592fc 100644
--- a/examples/cross_todo/nimrod_backend/readme.txt
+++ b/examples/cross_todo/nim_backend/readme.txt
@@ -1,4 +1,4 @@
-This directory contains the nimrod backend code for the todo cross platform

+This directory contains the nim backend code for the todo cross platform

 example.

 

 Unlike the cross platform calculator example, this backend features more code,

@@ -8,7 +8,7 @@ The test is not embedded directly in the backend.nim file to avoid being able
 to access internal data types and procs not exported and replicate the

 environment of client code.

 

-In a bigger project with several people you could run `nimrod doc backend.nim`

+In a bigger project with several people you could run `nim doc backend.nim`

 (or use the doc2 command for a whole project) and provide the generated html

 documentation to another programer for her to implement an interface without

 having to look at the source code.

diff --git a/examples/cross_todo/nimrod_backend/testbackend.nim b/examples/cross_todo/nim_backend/testbackend.nim
index 131dda1cf..131dda1cf 100644
--- a/examples/cross_todo/nimrod_backend/testbackend.nim
+++ b/examples/cross_todo/nim_backend/testbackend.nim
diff --git a/examples/cross_todo/nimrod_commandline/nimrod.cfg b/examples/cross_todo/nim_commandline/nim.cfg
index c1aedcf6a..41c034430 100644
--- a/examples/cross_todo/nimrod_commandline/nimrod.cfg
+++ b/examples/cross_todo/nim_commandline/nim.cfg
@@ -1,4 +1,4 @@
 # Nimrod configuration file.
 # The file is used only to add the path of the backend to the compiler options.
 
-path="../nimrod_backend"
+path="../nim_backend"
diff --git a/examples/cross_todo/nimrod_commandline/nimtodo.nim b/examples/cross_todo/nim_commandline/nimtodo.nim
index 1067177c3..4ab17e7a2 100644
--- a/examples/cross_todo/nimrod_commandline/nimtodo.nim
+++ b/examples/cross_todo/nim_commandline/nimtodo.nim
@@ -69,11 +69,11 @@ template parseTodoIdAndSetCommand(newCommand: TCommand): stmt =
   ## Helper to parse a big todo identifier into todoId and set command.
   try:
     let numChars = val.parseBiggestInt(newId)
-    if numChars < 1: raise newException(EInvalidValue, "Empty string?")
+    if numChars < 1: raise newException(ValueError, "Empty string?")
     result.command = newCommand
     result.todoId = newId
-  except EOverflow:
-    raise newException(EInvalidValue, "Value $1 too big" % val)
+  except OverflowError:
+    raise newException(ValueError, "Value $1 too big" % val)
 
 
 template verifySingleCommand(actions: stmt): stmt =
@@ -111,7 +111,7 @@ proc parseCmdLine(): TParamConfig =
     usesListParams = false
     p = initOptParser()
     key, val: TaintedString
-    newId: biggestInt
+    newId: BiggestInt
 
   result.initDefaults
 
@@ -178,7 +178,7 @@ proc parseCmdLine(): TParamConfig =
           abort("Unexpected option '$1'." % [key], 6)
       of cmdEnd:
         break
-  except EInvalidValue:
+  except ValueError:
     abort("Invalid integer value '$1' for parameter '$2'." % [val, key], 7)
 
   if not specifiedCommand:
diff --git a/examples/cross_todo/nimrod_commandline/readme.txt b/examples/cross_todo/nim_commandline/readme.txt
index b4362b8c5..ca4b67521 100644
--- a/examples/cross_todo/nimrod_commandline/readme.txt
+++ b/examples/cross_todo/nim_commandline/readme.txt
@@ -1,4 +1,4 @@
-This directory contains the nimrod commandline version of the todo cross
+This directory contains the Nim commandline version of the todo cross
 platform example.
 
 The commandline interface can be used only through switches, running the binary
@@ -14,6 +14,6 @@ generation switch can be used to fill the database with some basic todo entries
 you can play with.
 
 Compilation is fairly easy despite having the source split in different
-directories. Thanks to the nimrod.cfg file, which adds the ../nimrod_backend
+directories. Thanks to the Nim.cfg file, which adds the ../Nim_backend
 directory as a search path, you can compile and run the example just fine from
-the command line with 'nimrod c -r nimtodo.nim'.
+the command line with 'nim c -r nimtodo.nim'.
diff --git a/examples/cross_todo/readme.txt b/examples/cross_todo/readme.txt
index 326ed816f..2e648a35a 100644
--- a/examples/cross_todo/readme.txt
+++ b/examples/cross_todo/readme.txt
@@ -1,7 +1,7 @@
-The cross platform todo illustrates how to use Nimrod to create a backend

+The cross platform todo illustrates how to use Nim to create a backend

 called by different native user interfaces.

 

 This example builds on the knowledge learned from the cross_calculator example.

-Check it out first to learn how to set up nimrod on different platforms.

+Check it out first to learn how to set up Nim on different platforms.

 Additional implementations are provided at the external

 https://github.com/gradha/nimrod-crossplatform-todo github repository.

diff --git a/examples/curlex.nim b/examples/curlex.nim
index 9dadd9a90..017956818 100644
--- a/examples/curlex.nim
+++ b/examples/curlex.nim
@@ -4,7 +4,7 @@ import
 var hCurl = easy_init()
 if hCurl != nil: 
   discard easy_setopt(hCurl, OPT_VERBOSE, true)
-  discard easy_setopt(hCurl, OPT_URL, "http://force7.de/nimrod")
+  discard easy_setopt(hCurl, OPT_URL, "http://nim-lang.org/")
   discard easy_perform(hCurl)
   easy_cleanup(hCurl)
 
diff --git a/examples/talk/hoisting.nim b/examples/talk/hoisting.nim
index df13ba2cb..54e00884f 100644
--- a/examples/talk/hoisting.nim
+++ b/examples/talk/hoisting.nim
@@ -14,7 +14,7 @@ template optRe{re(x)}(x: string{lit}): Regex =
   g
 
 template `=~`(s: string, pattern: Regex): bool =
-  when not definedInScope(matches):
+  when not declaredInScope(matches):
     var matches {.inject.}: array[maxSubPatterns, string]
   match(s, pattern, matches)
 
diff --git a/icons/nimrod.ico b/icons/nim.ico
index 58cc4314c..58cc4314c 100644
--- a/icons/nimrod.ico
+++ b/icons/nim.ico
Binary files differdiff --git a/icons/nim.rc b/icons/nim.rc
new file mode 100644
index 000000000..c053e08e9
--- /dev/null
+++ b/icons/nim.rc
@@ -0,0 +1,3 @@
+nimicon ICON "nim.ico"
+
+
diff --git a/icons/nimrod.res b/icons/nim.res
index 6eddd053b..6eddd053b 100644
--- a/icons/nimrod.res
+++ b/icons/nim.res
Binary files differdiff --git a/icons/nimrod_icon.o b/icons/nim_icon.o
index c8c364412..c8c364412 100644
--- a/icons/nimrod_icon.o
+++ b/icons/nim_icon.o
Binary files differdiff --git a/icons/nimrod.rc b/icons/nimrod.rc
deleted file mode 100644
index 6f36b8145..000000000
--- a/icons/nimrod.rc
+++ /dev/null
@@ -1,3 +0,0 @@
-nimrodicon ICON "nimrod.ico"
-
-
diff --git a/install.sh.template b/install.sh.template
new file mode 100644
index 000000000..1292abdab
--- /dev/null
+++ b/install.sh.template
@@ -0,0 +1,9 @@
+#!/bin/sh
+set -e
+set -x
+
+if [ "$1" != "" ]; then
+	exec ./koch install "$1"
+else
+	exec ./koch install
+fi
diff --git a/koch.nim b/koch.nim
index 2de93bdea..3ebfb6655 100644
--- a/koch.nim
+++ b/koch.nim
@@ -1,7 +1,7 @@
 #
 #
 #         Maintenance program for Nim
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -18,7 +18,7 @@ when defined(gcc) and defined(windows):
 import
   os, strutils, parseopt, osproc, streams
 
-import "compiler/nversion.nim"
+const VersionAsString = system.NimVersion #"0.10.2"
 
 when defined(withUpdate):
   import httpclient
@@ -30,7 +30,7 @@ const
 +-----------------------------------------------------------------+
 |         Maintenance program for Nim                             |
 |             Version $1|
-|             (c) 2014 Andreas Rumpf                              |
+|             (c) 2015 Andreas Rumpf                              |
 +-----------------------------------------------------------------+
 Build time: $2, $3
 
@@ -40,10 +40,12 @@ Options:
   --help, -h               shows this help and quits
 Possible Commands:
   boot [options]           bootstraps with given command line options
-  install [bindir]         installs to given directory
-  clean                    cleans Nimrod project; removes generated files
-  web [options]            generates the website
+  install [bindir]         installs to given directory; Unix only!
+  clean                    cleans Nim project; removes generated files
+  web [options]            generates the website and the full documentation
+  website [options]        generates only the website
   csource [options]        builds the C sources for installation
+  pdf                      builds the PDF documentation
   zip                      builds the installation ZIP package
   nsis [options]           builds the NSIS Setup installer (for Windows)
   tests [options]          run the testsuite
@@ -57,8 +59,11 @@ Boot options:
   -d:useGnuReadline        use the GNU readline library for interactive mode
                            (not needed on Windows)
   -d:nativeStacktrace      use native stack traces (only for Mac OS X or Linux)
-  -d:noCaas                build Nimrod without CAAS support
+  -d:noCaas                build Nim without CAAS support
   -d:avoidTimeMachine      only for Mac OS X, excludes nimcache dir from backups
+Web options:
+  --googleAnalytics:UA-... add the given google analytics code to the docs. To
+                           build the official docs, use UA-48159761-1
 """
 
 proc exe(f: string): string = return addFileExt(f, ExeExt)
@@ -72,11 +77,11 @@ proc findNim(): string =
   # assume there is a symlink to the exe or something:
   return nim
 
-proc exec(cmd: string) =
+proc exec(cmd: string, errorcode: int = QuitFailure) =
   echo(cmd)
-  if execShellCmd(cmd) != 0: quit("FAILURE")
+  if execShellCmd(cmd) != 0: quit("FAILURE", errorcode)
 
-proc tryExec(cmd: string): bool = 
+proc tryExec(cmd: string): bool =
   echo(cmd)
   result = execShellCmd(cmd) == 0
 
@@ -91,17 +96,17 @@ proc copyExe(source, dest: string) =
 const
   compileNimInst = "-d:useLibzipSrc tools/niminst/niminst"
 
-proc csource(args: string) = 
-  exec("$4 cc $1 -r $3 --var:version=$2 --var:mingw=mingw32 csource compiler/nim.ini $1" %
+proc csource(args: string) =
+  exec("$4 cc $1 -r $3 --var:version=$2 --var:mingw=none csource --main:compiler/nim.nim compiler/installer.ini $1" %
        [args, VersionAsString, compileNimInst, findNim()])
 
 proc zip(args: string) =
-  exec("$3 cc -r $2 --var:version=$1 --var:mingw=mingw32 scripts compiler/nim.ini" %
+  exec("$3 cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" %
        [VersionAsString, compileNimInst, findNim()])
-  exec("$# --var:version=$# --var:mingw=mingw32 zip compiler/nim.ini" %
+  exec("$# --var:version=$# --var:mingw=none --main:compiler/nim.nim zip compiler/installer.ini" %
        ["tools/niminst/niminst".exe, VersionAsString])
-  
-proc buildTool(toolname, args: string) = 
+
+proc buildTool(toolname, args: string) =
   exec("$# cc $# $#" % [findNim(), args, toolname])
   copyFile(dest="bin"/ splitFile(toolname).name.exe, source=toolname.exe)
 
@@ -109,32 +114,35 @@ proc nsis(args: string) =
   # make sure we have generated the niminst executables:
   buildTool("tools/niminst/niminst", args)
   buildTool("tools/nimgrep", args)
-  # produce 'nimrod_debug.exe':
+  # produce 'nim_debug.exe':
   exec "nim c compiler" / "nim.nim"
   copyExe("compiler/nim".exe, "bin/nim_debug".exe)
-  exec(("tools" / "niminst" / "niminst --var:version=$# --var:mingw=mingw32" &
-        " nsis compiler/nim") % VersionAsString)
+  exec(("tools" / "niminst" / "niminst --var:version=$# --var:mingw=mingw$#" &
+        " nsis compiler/nim") % [VersionAsString, $(sizeof(pointer)*8)])
 
-proc install(args: string) = 
-  exec("$# cc -r $# --var:version=$# --var:mingw=mingw32 scripts compiler/nim.ini" %
+proc install(args: string) =
+  exec("$# cc -r $# --var:version=$# --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" %
        [findNim(), compileNimInst, VersionAsString])
   exec("sh ./install.sh $#" % args)
 
 proc web(args: string) =
-  exec("$# cc -r tools/nimweb.nim $# web/nim --putenv:nimversion=$#" %
+  exec("$# cc -r tools/nimweb.nim $# web/website.ini --putenv:nimversion=$#" %
        [findNim(), args, VersionAsString])
 
-# -------------- boot ---------------------------------------------------------
+proc website(args: string) =
+  exec("$# cc -r tools/nimweb.nim $# --website web/website.ini --putenv:nimversion=$#" %
+       [findNim(), args, VersionAsString])
 
-const
-  bootOptions = "" # options to pass to the bootstrap process
+proc pdf(args="") =
+  exec("$# cc -r tools/nimweb.nim $# --pdf web/website.ini --putenv:nimversion=$#" %
+       [findNim(), args, VersionAsString])
+
+# -------------- boot ---------------------------------------------------------
 
-proc findStartNim: string = 
+proc findStartNim: string =
   # we try several things before giving up:
   # * bin/nim
   # * $PATH/nim
-  # * bin/nimrod
-  # * $PATH/nimrod
   # If these fail, we try to build nim with the "build.(sh|bat)" script.
   var nim = "nim".exe
   result = "bin" / nim
@@ -142,36 +150,31 @@ proc findStartNim: string =
   for dir in split(getEnv("PATH"), PathSep):
     if existsFile(dir / nim): return dir / nim
 
-  # try the old "nimrod.exe":
-  var nimrod = "nimrod".exe
-  result = "bin" / nimrod
-  if existsFile(result): return
-  for dir in split(getEnv("PATH"), PathSep):
-    if existsFile(dir / nim): return dir / nimrod
-
   when defined(Posix):
     const buildScript = "build.sh"
-    if existsFile(buildScript): 
+    if existsFile(buildScript):
       if tryExec("./" & buildScript): return "bin" / nim
   else:
     const buildScript = "build.bat"
-    if existsFile(buildScript): 
+    if existsFile(buildScript):
       if tryExec(buildScript): return "bin" / nim
 
   echo("Found no nim compiler and every attempt to build one failed!")
   quit("FAILURE")
 
-proc thVersion(i: int): string = 
+proc thVersion(i: int): string =
   result = ("compiler" / "nim" & $i).exe
-  
+
 proc boot(args: string) =
   var output = "compiler" / "nim".exe
   var finalDest = "bin" / "nim".exe
-  
+  # default to use the 'c' command:
+  let bootOptions = if args.len == 0 or args.startsWith("-"): "c" else: ""
+
   copyExe(findStartNim(), 0.thVersion)
   for i in 0..2:
     echo "iteration: ", i+1
-    exec i.thVersion & " c $# $# compiler" / "nim.nim" % [bootOptions, args]
+    exec i.thVersion & " $# $# compiler" / "nim.nim" % [bootOptions, args]
     if sameFileContent(output, i.thVersion):
       copyExe(output, finalDest)
       echo "executables are equal: SUCCESS!"
@@ -192,7 +195,7 @@ const
     ".bzrignore", "nim", "nim.exe", "koch", "koch.exe", ".gitignore"
   ]
 
-proc cleanAux(dir: string) = 
+proc cleanAux(dir: string) =
   for kind, path in walkDir(dir):
     case kind
     of pcFile:
@@ -203,25 +206,25 @@ proc cleanAux(dir: string) =
           removeFile(path)
     of pcDir:
       case splitPath(path).tail
-      of "nimcache": 
+      of "nimcache":
         echo "removing dir: ", path
         removeDir(path)
       of "dist", ".git", "icons": discard
       else: cleanAux(path)
     else: discard
 
-proc removePattern(pattern: string) = 
-  for f in walkFiles(pattern): 
+proc removePattern(pattern: string) =
+  for f in walkFiles(pattern):
     echo "removing: ", f
     removeFile(f)
 
-proc clean(args: string) = 
+proc clean(args: string) =
   if existsFile("koch.dat"): removeFile("koch.dat")
   removePattern("web/*.html")
   removePattern("doc/*.html")
   cleanAux(getCurrentDir())
   for kind, path in walkDir(getCurrentDir() / "build"):
-    if kind == pcDir: 
+    if kind == pcDir:
       echo "removing dir: ", path
       removeDir(path)
 
@@ -257,20 +260,20 @@ when defined(withUpdate):
           echo("Fetching updates from repo...")
           var pullout = execCmdEx(git & " pull origin master")
           if pullout[1] != 0:
-            quit("An error has occured.")
+            quit("An error has occurred.")
           else:
             if pullout[0].startsWith("Already up-to-date."):
               quit("No new changes fetched from the repo. " &
                    "Local branch must be ahead of it. Exiting...")
       else:
-        quit("An error has occured.")
-      
+        quit("An error has occurred.")
+
     else:
       echo("No repo or executable found!")
       when defined(haveZipLib):
         echo("Falling back.. Downloading source code from repo...")
         # use dom96's httpclient to download zip
-        downloadFile("https://github.com/Araq/Nimrod/zipball/master",
+        downloadFile("https://github.com/Araq/Nim/zipball/master",
                      thisDir / "update.zip")
         try:
           echo("Extracting source code from archive...")
@@ -281,7 +284,7 @@ when defined(withUpdate):
           quit("Error reading archive.")
       else:
         quit("No failback available. Exiting...")
-    
+
     echo("Starting update...")
     boot(args)
     echo("Update complete!")
@@ -308,7 +311,7 @@ proc winRelease() =
 
   run7z("win32", "bin/nim.exe", "bin/c2nim.exe", "bin/nimgrep.exe",
         "bin/nimfix.exe",
-        "bin/babel.exe", "bin/*.dll",
+        "bin/nimble.exe", "bin/*.dll",
         "config", "dist/*.dll", "examples", "lib",
         "readme.txt", "contributors.txt", "copying.txt")
   # second step: XXX build 64 bit version
@@ -328,12 +331,14 @@ proc tests(args: string) =
 proc temp(args: string) =
   var output = "compiler" / "nim".exe
   var finalDest = "bin" / "nim_temp".exe
-  exec("nim c compiler" / "nim")
+  # 125 is the magic number to tell git bisect to skip the current
+  # commit.
+  exec("nim c compiler" / "nim", 125)
   copyExe(output, finalDest)
   if args.len > 0: exec(finalDest & " " & args)
 
-proc showHelp() = 
-  quit(HelpText % [VersionAsString & repeatChar(44-len(VersionAsString)), 
+proc showHelp() =
+  quit(HelpText % [VersionAsString & spaces(44-len(VersionAsString)),
                    CompileDate, CompileTime], QuitSuccess)
 
 var op = initOptParser()
@@ -345,6 +350,11 @@ of cmdArgument:
   of "boot": boot(op.cmdLineRest)
   of "clean": clean(op.cmdLineRest)
   of "web": web(op.cmdLineRest)
+  of "website": website(op.cmdLineRest & " --googleAnalytics:UA-48159761-1")
+  of "web0":
+    # undocumented command for Araq-the-merciful:
+    web(op.cmdLineRest & " --googleAnalytics:UA-48159761-1")
+  of "pdf": pdf()
   of "csource", "csources": csource(op.cmdLineRest)
   of "zip": zip(op.cmdLineRest)
   of "nsis": nsis(op.cmdLineRest)
diff --git a/koch.nimrod.cfg b/koch.nim.cfg
index 1d7acf579..1d7acf579 100644
--- a/koch.nimrod.cfg
+++ b/koch.nim.cfg
diff --git a/lib/core/locks.nim b/lib/core/locks.nim
index 766b7b536..8a809fc84 100644
--- a/lib/core/locks.nim
+++ b/lib/core/locks.nim
@@ -21,7 +21,7 @@ type
     ## is performed. Deprecated, do not use anymore!
   AquireEffect* {.deprecated.} = object of LockEffect  ## \
     ## effect that denotes that some lock is
-    ## aquired. Deprecated, do not use anymore!
+    ## acquired. Deprecated, do not use anymore!
   ReleaseEffect* {.deprecated.} = object of LockEffect ## \
     ## effect that denotes that some lock is
     ## released. Deprecated, do not use anymore!
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index ed5d3c50c..35f0f61c1 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2013 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -15,7 +15,7 @@ include "system/inclrtl"
 ## .. include:: ../doc/astspec.txt
 
 type
-  TNimrodNodeKind* = enum
+  NimNodeKind* = enum
     nnkNone, nnkEmpty, nnkIdent, nnkSym,
     nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit,
     nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkUIntLit, nnkUInt8Lit,
@@ -23,9 +23,9 @@ type
     nnkFloat32Lit, nnkFloat64Lit, nnkFloat128Lit, nnkStrLit, nnkRStrLit,
     nnkTripleStrLit, nnkNilLit, nnkMetaNode, nnkDotCall,
     nnkCommand, nnkCall, nnkCallStrLit, nnkInfix,
-    nnkPrefix, nnkPostfix, nnkHiddenCallConv, 
+    nnkPrefix, nnkPostfix, nnkHiddenCallConv,
     nnkExprEqExpr,
-    nnkExprColonExpr, nnkIdentDefs, nnkVarTuple, 
+    nnkExprColonExpr, nnkIdentDefs, nnkVarTuple,
     nnkPar, nnkObjConstr, nnkCurly, nnkCurlyExpr,
     nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange,
     nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr,
@@ -48,7 +48,7 @@ type
     nnkConstDef, nnkTypeDef,
     nnkYieldStmt, nnkDefer, nnkTryStmt, nnkFinally, nnkRaiseStmt,
     nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt,
-    nnkDiscardStmt, nnkStmtList, 
+    nnkDiscardStmt, nnkStmtList,
     nnkImportStmt,
     nnkImportExceptStmt,
     nnkExportStmt,
@@ -60,159 +60,184 @@ type
     nnkStmtListType, nnkBlockType,
     nnkWith, nnkWithout,
     nnkTypeOfExpr, nnkObjectTy,
-    nnkTupleTy, nnkTypeClassTy, nnkStaticTy,
+    nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy,
     nnkRecList, nnkRecCase, nnkRecWhen,
     nnkRefTy, nnkPtrTy, nnkVarTy,
     nnkConstTy, nnkMutableTy,
     nnkDistinctTy,
-    nnkProcTy, 
+    nnkProcTy,
     nnkIteratorTy,         # iterator type
     nnkSharedTy,           # 'shared T'
     nnkEnumTy,
     nnkEnumFieldDef,
     nnkArglist, nnkPattern
     nnkReturnToken
-  TNimNodeKinds* = set[TNimrodNodeKind]
-  TNimrodTypeKind* = enum
+  NimNodeKinds* = set[NimNodeKind]
+  NimTypeKind* = enum
     ntyNone, ntyBool, ntyChar, ntyEmpty,
     ntyArrayConstr, ntyNil, ntyExpr, ntyStmt,
-    ntyTypeDesc, ntyGenericInvokation, ntyGenericBody, ntyGenericInst,
+    ntyTypeDesc, ntyGenericInvocation, ntyGenericBody, ntyGenericInst,
     ntyGenericParam, ntyDistinct, ntyEnum, ntyOrdinal,
     ntyArray, ntyObject, ntyTuple, ntySet,
     ntyRange, ntyPtr, ntyRef, ntyVar,
     ntySequence, ntyProc, ntyPointer, ntyOpenArray,
     ntyString, ntyCString, ntyForward, ntyInt,
     ntyInt8, ntyInt16, ntyInt32, ntyInt64,
-    ntyFloat, ntyFloat32, ntyFloat64, ntyFloat128
-  TNimTypeKinds* = set[TNimrodTypeKind]
-  TNimrodSymKind* = enum
+    ntyFloat, ntyFloat32, ntyFloat64, ntyFloat128,
+    ntyUInt, ntyUInt8, ntyUInt16, ntyUInt32, ntyUInt64,
+    ntyBigNum,
+    ntyConst, ntyMutable, ntyVarargs,
+    ntyIter,
+    ntyError,
+    ntyBuiltinTypeClass, ntyConcept, ntyConceptInst, ntyComposite,
+    ntyAnd, ntyOr, ntyNot
+
+  TNimTypeKinds* {.deprecated.} = set[NimTypeKind]
+  NimSymKind* = enum
     nskUnknown, nskConditional, nskDynLib, nskParam,
-    nskGenericParam, nskTemp, nskModule, nskType, nskVar, nskLet, 
+    nskGenericParam, nskTemp, nskModule, nskType, nskVar, nskLet,
     nskConst, nskResult,
     nskProc, nskMethod, nskIterator, nskClosureIterator,
     nskConverter, nskMacro, nskTemplate, nskField,
     nskEnumField, nskForVar, nskLabel,
     nskStub
-    
-  TNimSymKinds* = set[TNimrodSymKind]
+
+  TNimSymKinds* {.deprecated.} = set[NimSymKind]
 
 type
-  TNimrodIdent* = object of RootObj
-    ## represents a Nimrod identifier in the AST
+  NimIdent* = object of RootObj
+    ## represents a Nim identifier in the AST
 
-  TNimrodSymbol {.final.} = object # hidden
-  PNimrodSymbol* {.compilerproc.} = ref TNimrodSymbol
-    ## represents a Nimrod *symbol* in the compiler; a *symbol* is a looked-up
+  NimSymObj = object # hidden
+  NimSym* = ref NimSymObj
+    ## represents a Nim *symbol* in the compiler; a *symbol* is a looked-up
     ## *ident*.
 
+{.deprecated: [TNimrodNodeKind: NimNodeKind, TNimNodeKinds: NimNodeKinds,
+    TNimrodTypeKind: NimTypeKind, TNimrodSymKind: NimSymKind,
+    TNimrodIdent: NimIdent, PNimrodSymbol: NimSym].}
+
 const
   nnkLiterals* = {nnkCharLit..nnkNilLit}
   nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
                    nnkCallStrLit}
 
-proc `[]`*(n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild", noSideEffect.}
+proc `[]`*(n: NimNode, i: int): NimNode {.magic: "NChild", noSideEffect.}
   ## get `n`'s `i`'th child.
 
-proc `[]=`*(n: PNimrodNode, i: int, child: PNimrodNode) {.magic: "NSetChild",
+proc `[]=`*(n: NimNode, i: int, child: NimNode) {.magic: "NSetChild",
   noSideEffect.}
   ## set `n`'s `i`'th child to `child`.
 
-proc `!`*(s: string): TNimrodIdent {.magic: "StrToIdent", noSideEffect.}
+proc `!`*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect.}
   ## constructs an identifier from the string `s`
 
-proc `$`*(i: TNimrodIdent): string {.magic: "IdentToStr", noSideEffect.}
-  ## converts a Nimrod identifier to a string
+proc `$`*(i: NimIdent): string {.magic: "IdentToStr", noSideEffect.}
+  ## converts a Nim identifier to a string
 
-proc `$`*(s: PNimrodSymbol): string {.magic: "IdentToStr", noSideEffect.}
-  ## converts a Nimrod symbol to a string
+proc `$`*(s: NimSym): string {.magic: "IdentToStr", noSideEffect.}
+  ## converts a Nim symbol to a string
 
-proc `==`*(a, b: TNimrodIdent): bool {.magic: "EqIdent", noSideEffect.}
-  ## compares two Nimrod identifiers
+proc `==`*(a, b: NimIdent): bool {.magic: "EqIdent", noSideEffect.}
+  ## compares two Nim identifiers
 
-proc `==`*(a, b: PNimrodNode): bool {.magic: "EqNimrodNode", noSideEffect.}
-  ## compares two Nimrod nodes
+proc `==`*(a, b: NimNode): bool {.magic: "EqNimrodNode", noSideEffect.}
+  ## compares two Nim nodes
 
-proc len*(n: PNimrodNode): int {.magic: "NLen", noSideEffect.}
+proc len*(n: NimNode): int {.magic: "NLen", noSideEffect.}
   ## returns the number of children of `n`.
 
-proc add*(father, child: PNimrodNode): PNimrodNode {.magic: "NAdd", discardable,
-  noSideEffect.}
+proc add*(father, child: NimNode): NimNode {.magic: "NAdd", discardable,
+  noSideEffect, locks: 0.}
   ## Adds the `child` to the `father` node. Returns the
   ## father node so that calls can be nested.
 
-proc add*(father: PNimrodNode, children: varargs[PNimrodNode]): PNimrodNode {.
-  magic: "NAddMultiple", discardable, noSideEffect.}
+proc add*(father: NimNode, children: varargs[NimNode]): NimNode {.
+  magic: "NAddMultiple", discardable, noSideEffect, locks: 0.}
   ## Adds each child of `children` to the `father` node.
   ## Returns the `father` node so that calls can be nested.
 
-proc del*(father: PNimrodNode, idx = 0, n = 1) {.magic: "NDel", noSideEffect.}
+proc del*(father: NimNode, idx = 0, n = 1) {.magic: "NDel", noSideEffect.}
   ## deletes `n` children of `father` starting at index `idx`.
 
-proc kind*(n: PNimrodNode): TNimrodNodeKind {.magic: "NKind", noSideEffect.}
+proc kind*(n: NimNode): NimNodeKind {.magic: "NKind", noSideEffect.}
   ## returns the `kind` of the node `n`.
 
-proc intVal*(n: PNimrodNode): BiggestInt {.magic: "NIntVal", noSideEffect.}
-proc floatVal*(n: PNimrodNode): BiggestFloat {.magic: "NFloatVal", noSideEffect.}
-proc symbol*(n: PNimrodNode): PNimrodSymbol {.magic: "NSymbol", noSideEffect.}
-proc ident*(n: PNimrodNode): TNimrodIdent {.magic: "NIdent", noSideEffect.}
-proc typ*(n: PNimrodNode): typedesc {.magic: "NGetType", noSideEffect.}
-proc strVal*(n: PNimrodNode): string  {.magic: "NStrVal", noSideEffect.}
-
-proc `intVal=`*(n: PNimrodNode, val: BiggestInt) {.magic: "NSetIntVal", noSideEffect.}
-proc `floatVal=`*(n: PNimrodNode, val: BiggestFloat) {.magic: "NSetFloatVal", noSideEffect.}
-proc `symbol=`*(n: PNimrodNode, val: PNimrodSymbol) {.magic: "NSetSymbol", noSideEffect.}
-proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent", noSideEffect.}
-#proc `typ=`*(n: PNimrodNode, typ: typedesc) {.magic: "NSetType".}
+proc intVal*(n: NimNode): BiggestInt {.magic: "NIntVal", noSideEffect.}
+proc boolVal*(n: NimNode): bool {.compileTime, noSideEffect.} = n.intVal != 0
+proc floatVal*(n: NimNode): BiggestFloat {.magic: "NFloatVal", noSideEffect.}
+proc symbol*(n: NimNode): NimSym {.magic: "NSymbol", noSideEffect.}
+proc ident*(n: NimNode): NimIdent {.magic: "NIdent", noSideEffect.}
+
+proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.}
+  ## with 'getType' you can access the node's `type`:idx:. A Nim type is
+  ## mapped to a Nim AST too, so it's slightly confusing but it means the same
+  ## API can be used to traverse types. Recursive types are flattened for you
+  ## so there is no danger of infinite recursions during traversal. To
+  ## resolve recursive types, you have to call 'getType' again. To see what
+  ## kind of type it is, call `typeKind` on getType's result.
+
+proc typeKind*(n: NimNode): NimTypeKind {.magic: "NGetType", noSideEffect.}
+  ## Returns the type kind of the node 'n' that should represent a type, that
+  ## means the node should have been obtained via `getType`.
+
+proc strVal*(n: NimNode): string  {.magic: "NStrVal", noSideEffect.}
+
+proc `intVal=`*(n: NimNode, val: BiggestInt) {.magic: "NSetIntVal", noSideEffect.}
+proc `floatVal=`*(n: NimNode, val: BiggestFloat) {.magic: "NSetFloatVal", noSideEffect.}
+proc `symbol=`*(n: NimNode, val: NimSym) {.magic: "NSetSymbol", noSideEffect.}
+proc `ident=`*(n: NimNode, val: NimIdent) {.magic: "NSetIdent", noSideEffect.}
+#proc `typ=`*(n: NimNode, typ: typedesc) {.magic: "NSetType".}
 # this is not sound! Unfortunately forbidding 'typ=' is not enough, as you
 # can easily do:
 #   let bracket = semCheck([1, 2])
 #   let fake = semCheck(2.0)
 #   bracket[0] = fake  # constructs a mixed array with ints and floats!
 
-proc `strVal=`*(n: PNimrodNode, val: string) {.magic: "NSetStrVal", noSideEffect.}
+proc `strVal=`*(n: NimNode, val: string) {.magic: "NSetStrVal", noSideEffect.}
 
-proc newNimNode*(kind: TNimrodNodeKind,
-                 n: PNimrodNode=nil): PNimrodNode {.magic: "NNewNimNode", noSideEffect.}
+proc newNimNode*(kind: NimNodeKind,
+                 n: NimNode=nil): NimNode {.magic: "NNewNimNode", noSideEffect.}
 
-proc copyNimNode*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimNode", noSideEffect.}
-proc copyNimTree*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimTree", noSideEffect.}
+proc copyNimNode*(n: NimNode): NimNode {.magic: "NCopyNimNode", noSideEffect.}
+proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.}
 
-proc error*(msg: string) {.magic: "NError", gcsafe.}
+proc error*(msg: string) {.magic: "NError", benign.}
   ## writes an error message at compile time
 
-proc warning*(msg: string) {.magic: "NWarning", gcsafe.}
+proc warning*(msg: string) {.magic: "NWarning", benign.}
   ## writes a warning message at compile time
 
-proc hint*(msg: string) {.magic: "NHint", gcsafe.}
+proc hint*(msg: string) {.magic: "NHint", benign.}
   ## writes a hint message at compile time
 
-proc newStrLitNode*(s: string): PNimrodNode {.compileTime, noSideEffect.} =
+proc newStrLitNode*(s: string): NimNode {.compileTime, noSideEffect.} =
   ## creates a string literal node from `s`
   result = newNimNode(nnkStrLit)
   result.strVal = s
 
-proc newIntLitNode*(i: BiggestInt): PNimrodNode {.compileTime.} =
+proc newIntLitNode*(i: BiggestInt): NimNode {.compileTime.} =
   ## creates a int literal node from `i`
   result = newNimNode(nnkIntLit)
   result.intVal = i
 
-proc newFloatLitNode*(f: BiggestFloat): PNimrodNode {.compileTime.} =
+proc newFloatLitNode*(f: BiggestFloat): NimNode {.compileTime.} =
   ## creates a float literal node from `f`
   result = newNimNode(nnkFloatLit)
   result.floatVal = f
 
-proc newIdentNode*(i: TNimrodIdent): PNimrodNode {.compileTime.} =
+proc newIdentNode*(i: NimIdent): NimNode {.compileTime.} =
   ## creates an identifier node from `i`
   result = newNimNode(nnkIdent)
   result.ident = i
 
-proc newIdentNode*(i: string): PNimrodNode {.compileTime.} =
+proc newIdentNode*(i: string): NimNode {.compileTime.} =
   ## creates an identifier node from `i`
   result = newNimNode(nnkIdent)
   result.ident = !i
 
 type
-  TBindSymRule* = enum   ## specifies how ``bindSym`` behaves
+  BindSymRule* = enum    ## specifies how ``bindSym`` behaves
     brClosed,            ## only the symbols in current scope are bound
     brOpen,              ## open wrt overloaded symbols, but may be a single
                          ## symbol if not ambiguous (the rules match that of
@@ -221,7 +246,9 @@ type
                          ## if not ambiguous (this cannot be achieved with
                          ## any other means in the language currently)
 
-proc bindSym*(ident: string, rule: TBindSymRule = brClosed): PNimrodNode {.
+{.deprecated: [TBindSymRule: BindSymRule].}
+
+proc bindSym*(ident: string, rule: BindSymRule = brClosed): NimNode {.
               magic: "NBindSym", noSideEffect.}
   ## creates a node that binds `ident` to a symbol node. The bound symbol
   ## may be an overloaded symbol.
@@ -232,48 +259,48 @@ proc bindSym*(ident: string, rule: TBindSymRule = brClosed): PNimrodNode {.
   ## If ``rule == brForceOpen`` always an ``nkOpenSymChoice`` tree is
   ## returned even if the symbol is not ambiguous.
 
-proc genSym*(kind: TNimrodSymKind = nskLet; ident = ""): PNimrodNode {.
+proc genSym*(kind: NimSymKind = nskLet; ident = ""): NimNode {.
   magic: "NGenSym", noSideEffect.}
   ## generates a fresh symbol that is guaranteed to be unique. The symbol
   ## needs to occur in a declaration context.
 
-proc callsite*(): PNimrodNode {.magic: "NCallSite", gcsafe.}
-  ## returns the AST if the invokation expression that invoked this macro.
+proc callsite*(): NimNode {.magic: "NCallSite", benign.}
+  ## returns the AST of the invocation expression that invoked this macro.
 
-proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =
-  ## converts the AST `n` to the concrete Nimrod code and wraps that
+proc toStrLit*(n: NimNode): NimNode {.compileTime.} =
+  ## converts the AST `n` to the concrete Nim code and wraps that
   ## in a string literal node
   return newStrLitNode(repr(n))
 
-proc lineinfo*(n: PNimrodNode): string {.magic: "NLineInfo", noSideEffect.}
+proc lineinfo*(n: NimNode): string {.magic: "NLineInfo", noSideEffect.}
   ## returns the position the node appears in the original source file
   ## in the form filename(line, col)
 
-proc internalParseExpr(s: string): PNimrodNode {.
+proc internalParseExpr(s: string): NimNode {.
   magic: "ParseExprToAst", noSideEffect.}
 
-proc internalParseStmt(s: string): PNimrodNode {.
+proc internalParseStmt(s: string): NimNode {.
   magic: "ParseStmtToAst", noSideEffect.}
 
 proc internalErrorFlag*(): string {.magic: "NError", noSideEffect.}
   ## Some builtins set an error flag. This is then turned into a proper
   ## exception. **Note**: Ordinary application code should not call this.
 
-proc parseExpr*(s: string): PNimrodNode {.noSideEffect, compileTime.} =
+proc parseExpr*(s: string): NimNode {.noSideEffect, compileTime.} =
   ## Compiles the passed string to its AST representation.
   ## Expects a single expression. Raises ``ValueError`` for parsing errors.
   result = internalParseExpr(s)
   let x = internalErrorFlag()
   if x.len > 0: raise newException(ValueError, x)
 
-proc parseStmt*(s: string): PNimrodNode {.noSideEffect, compileTime.} =
+proc parseStmt*(s: string): NimNode {.noSideEffect, compileTime.} =
   ## Compiles the passed string to its AST representation.
   ## Expects one or more statements. Raises ``ValueError`` for parsing errors.
   result = internalParseStmt(s)
   let x = internalErrorFlag()
   if x.len > 0: raise newException(ValueError, x)
 
-proc getAst*(macroOrTemplate: expr): PNimrodNode {.magic: "ExpandToAst", noSideEffect.}
+proc getAst*(macroOrTemplate: expr): NimNode {.magic: "ExpandToAst", noSideEffect.}
   ## Obtains the AST nodes returned from a macro or template invocation.
   ## Example:
   ##
@@ -282,10 +309,10 @@ proc getAst*(macroOrTemplate: expr): PNimrodNode {.magic: "ExpandToAst", noSideE
   ##   macro FooMacro() =
   ##     var ast = getAst(BarTemplate())
 
-proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst", noSideEffect.}
+proc quote*(bl: stmt, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.}
   ## Quasi-quoting operator.
   ## Accepts an expression or a block and returns the AST that represents it.
-  ## Within the quoted AST, you are able to interpolate PNimrodNode expressions
+  ## Within the quoted AST, you are able to interpolate NimNode expressions
   ## from the surrounding scope. If no operator is given, quoting is done using
   ## backticks. Otherwise, the given operator must be used as a prefix operator
   ## for any interpolated expression. The original meaning of the interpolation
@@ -293,7 +320,7 @@ proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst", noSideEffect.
   ## e.g. `@` is escaped as `@@`, `@@` is escaped as `@@@` and so on.
   ##
   ## Example:
-  ##   
+  ##
   ## .. code-block:: nim
   ##
   ##   macro check(ex: expr): stmt =
@@ -312,35 +339,41 @@ proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst", noSideEffect.
   ##     result = quote do:
   ##       if not `ex`:
   ##         echo `info` & ": Check failed: " & `expString`
-  
-proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
+
+proc expectKind*(n: NimNode, k: NimNodeKind) {.compileTime.} =
   ## checks that `n` is of kind `k`. If this is not the case,
   ## compilation aborts with an error message. This is useful for writing
   ## macros that check the AST that is passed to them.
-  if n.kind != k: error("macro expects a node of kind: " & $k)
+  if n.kind != k: error("Expected a node of kind " & $k & ", got " & $n.kind)
 
-proc expectMinLen*(n: PNimrodNode, min: int) {.compileTime.} =
+proc expectMinLen*(n: NimNode, min: int) {.compileTime.} =
   ## checks that `n` has at least `min` children. If this is not the case,
   ## compilation aborts with an error message. This is useful for writing
   ## macros that check its number of arguments.
   if n.len < min: error("macro expects a node with " & $min & " children")
 
-proc expectLen*(n: PNimrodNode, len: int) {.compileTime.} =
+proc expectLen*(n: NimNode, len: int) {.compileTime.} =
   ## checks that `n` has exactly `len` children. If this is not the case,
   ## compilation aborts with an error message. This is useful for writing
   ## macros that check its number of arguments.
   if n.len != len: error("macro expects a node with " & $len & " children")
 
-proc newCall*(theProc: PNimrodNode,
-              args: varargs[PNimrodNode]): PNimrodNode {.compileTime.} =
+proc newTree*(kind: NimNodeKind,
+              children: varargs[NimNode]): NimNode {.compileTime.} =
+  ## produces a new node with children.
+  result = newNimNode(kind)
+  result.add(children)
+
+proc newCall*(theProc: NimNode,
+              args: varargs[NimNode]): NimNode {.compileTime.} =
   ## produces a new call node. `theProc` is the proc that is called with
   ## the arguments ``args[0..]``.
   result = newNimNode(nnkCall)
   result.add(theProc)
   result.add(args)
 
-proc newCall*(theProc: TNimrodIdent,
-              args: varargs[PNimrodNode]): PNimrodNode {.compileTime.} =
+proc newCall*(theProc: NimIdent,
+              args: varargs[NimNode]): NimNode {.compileTime.} =
   ## produces a new call node. `theProc` is the proc that is called with
   ## the arguments ``args[0..]``.
   result = newNimNode(nnkCall)
@@ -348,35 +381,40 @@ proc newCall*(theProc: TNimrodIdent,
   result.add(args)
 
 proc newCall*(theProc: string,
-              args: varargs[PNimrodNode]): PNimrodNode {.compileTime.} =
+              args: varargs[NimNode]): NimNode {.compileTime.} =
   ## produces a new call node. `theProc` is the proc that is called with
   ## the arguments ``args[0..]``.
   result = newNimNode(nnkCall)
   result.add(newIdentNode(theProc))
   result.add(args)
 
-proc newLit*(c: char): PNimrodNode {.compileTime.} =
+proc newLit*(c: char): NimNode {.compileTime.} =
   ## produces a new character literal node.
   result = newNimNode(nnkCharLit)
   result.intVal = ord(c)
 
-proc newLit*(i: BiggestInt): PNimrodNode {.compileTime.} =
+proc newLit*(i: BiggestInt): NimNode {.compileTime.} =
   ## produces a new integer literal node.
   result = newNimNode(nnkIntLit)
   result.intVal = i
 
-proc newLit*(f: BiggestFloat): PNimrodNode {.compileTime.} =
+proc newLit*(b: bool): NimNode {.compileTime.} =
+  ## produces a new boolean literal node.
+  result = newNimNode(nnkIntLit)
+  result.intVal = ord(b)
+
+proc newLit*(f: BiggestFloat): NimNode {.compileTime.} =
   ## produces a new float literal node.
   result = newNimNode(nnkFloatLit)
   result.floatVal = f
 
-proc newLit*(s: string): PNimrodNode {.compileTime.} =
+proc newLit*(s: string): NimNode {.compileTime.} =
   ## produces a new string literal node.
   result = newNimNode(nnkStrLit)
   result.strVal = s
 
-proc nestList*(theProc: TNimrodIdent,
-               x: PNimrodNode): PNimrodNode {.compileTime.} =
+proc nestList*(theProc: NimIdent,
+               x: NimNode): NimNode {.compileTime.} =
   ## nests the list `x` into a tree of call expressions:
   ## ``[a, b, c]`` is transformed into ``theProc(a, theProc(c, d))``.
   var L = x.len
@@ -387,11 +425,11 @@ proc nestList*(theProc: TNimrodIdent,
     # This could easily user code and so should be fixed in evals.nim somehow.
     result = newCall(theProc, x[i], copyNimTree(result))
 
-proc treeRepr*(n: PNimrodNode): string {.compileTime.} =
+proc treeRepr*(n: NimNode): string {.compileTime, benign.} =
   ## Convert the AST `n` to a human-readable tree-like string.
   ##
   ## See also `repr` and `lispRepr`.
-  proc traverse(res: var string, level: int, n: PNimrodNode) =
+  proc traverse(res: var string, level: int, n: NimNode) {.benign.} =
     for i in 0..level-1: res.add "  "
     res.add(($n.kind).substr(3))
 
@@ -412,7 +450,7 @@ proc treeRepr*(n: PNimrodNode): string {.compileTime.} =
   result = ""
   traverse(result, 0, n)
 
-proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
+proc lispRepr*(n: NimNode): string {.compileTime, benign.} =
   ## Convert the AST `n` to a human-readable lisp-like string,
   ##
   ## See also `repr` and `treeRepr`.
@@ -430,10 +468,11 @@ proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
   of nnkSym: add(result, $n.symbol)
   of nnkNone: assert false
   else:
-    add(result, lispRepr(n[0]))
-    for j in 1..n.len-1:
-      add(result, ", ")
-      add(result, lispRepr(n[j]))
+    if n.len > 0:
+      add(result, lispRepr(n[0]))
+      for j in 1..n.len-1:
+        add(result, ", ")
+        add(result, lispRepr(n[j]))
 
   add(result, ")")
 
@@ -458,42 +497,56 @@ macro dumpLispImm*(s: stmt): stmt {.immediate, deprecated.} = echo s.lispRepr
   ## The ``immediate`` version of `dumpLisp`.
 
 
-proc newEmptyNode*(): PNimrodNode {.compileTime, noSideEffect.} =
-  ## Create a new empty node 
+proc newEmptyNode*(): NimNode {.compileTime, noSideEffect.} =
+  ## Create a new empty node
   result = newNimNode(nnkEmpty)
 
-proc newStmtList*(stmts: varargs[PNimrodNode]): PNimrodNode {.compileTime.}=
+proc newStmtList*(stmts: varargs[NimNode]): NimNode {.compileTime.}=
   ## Create a new statement list
   result = newNimNode(nnkStmtList).add(stmts)
 
-proc newBlockStmt*(label, body: PNimrodNode): PNimrodNode {.compileTime.} =
+proc newPar*(exprs: varargs[NimNode]): NimNode {.compileTime.}=
+  ## Create a new parentheses-enclosed expression
+  newNimNode(nnkPar).add(exprs)
+
+proc newBlockStmt*(label, body: NimNode): NimNode {.compileTime.} =
   ## Create a new block statement with label
   return newNimNode(nnkBlockStmt).add(label, body)
 
-proc newBlockStmt*(body: PNimrodNode): PNimrodNode {.compiletime.} =
+proc newBlockStmt*(body: NimNode): NimNode {.compiletime.} =
   ## Create a new block: stmt
   return newNimNode(nnkBlockStmt).add(newEmptyNode(), body)
 
-proc newVarStmt*(name, value: PNimrodNode): PNimrodNode {.compiletime.} =
-  ## Create a new var stmt 
+proc newVarStmt*(name, value: NimNode): NimNode {.compiletime.} =
+  ## Create a new var stmt
   return newNimNode(nnkVarSection).add(
     newNimNode(nnkIdentDefs).add(name, newNimNode(nnkEmpty), value))
 
-proc newLetStmt*(name, value: PNimrodNode): PNimrodNode {.compiletime.} =
-  ## Create a new let stmt 
+proc newLetStmt*(name, value: NimNode): NimNode {.compiletime.} =
+  ## Create a new let stmt
   return newNimNode(nnkLetSection).add(
     newNimNode(nnkIdentDefs).add(name, newNimNode(nnkEmpty), value))
 
-proc newAssignment*(lhs, rhs: PNimrodNode): PNimrodNode {.compileTime.} =
+proc newConstStmt*(name, value: NimNode): NimNode {.compileTime.} =
+  ## Create a new const stmt
+  newNimNode(nnkConstSection).add(
+    newNimNode(nnkConstDef).add(name, newNimNode(nnkEmpty), value))
+
+proc newAssignment*(lhs, rhs: NimNode): NimNode {.compileTime.} =
   return newNimNode(nnkAsgn).add(lhs, rhs)
 
-proc newDotExpr*(a, b: PNimrodNode): PNimrodNode {.compileTime.} = 
+proc newDotExpr*(a, b: NimNode): NimNode {.compileTime.} =
   ## Create new dot expression
   ## a.dot(b) ->  `a.b`
   return newNimNode(nnkDotExpr).add(a, b)
 
-proc newIdentDefs*(name, kind: PNimrodNode; 
-                   default = newEmptyNode()): PNimrodNode {.compileTime.} = 
+proc newColonExpr*(a, b: NimNode): NimNode {.compileTime.} =
+  ## Create new colon expression
+  ## newColonExpr(a, b) ->  `a: b`
+  newNimNode(nnkExprColonExpr).add(a, b)
+
+proc newIdentDefs*(name, kind: NimNode;
+                   default = newEmptyNode()): NimNode {.compileTime.} =
   ## Creates a new ``nnkIdentDefs`` node of a specific kind and value.
   ##
   ## ``nnkIdentDefs`` need to have at least three children, but they can have
@@ -524,32 +577,30 @@ proc newIdentDefs*(name, kind: PNimrodNode;
   ##       newStrLitNode("Hello"))
   newNimNode(nnkIdentDefs).add(name, kind, default)
 
-proc newNilLit*(): PNimrodNode {.compileTime.} =
+proc newNilLit*(): NimNode {.compileTime.} =
   ## New nil literal shortcut
   result = newNimNode(nnkNilLit)
 
-proc high*(node: PNimrodNode): int {.compileTime.} = len(node) - 1
+proc high*(node: NimNode): int {.compileTime.} = len(node) - 1
   ## Return the highest index available for a node
-proc last*(node: PNimrodNode): PNimrodNode {.compileTime.} = node[node.high]
-  ## Return the last item in nodes children. Same as `node[node.high()]` 
+proc last*(node: NimNode): NimNode {.compileTime.} = node[node.high]
+  ## Return the last item in nodes children. Same as `node[node.high()]`
 
 
 const
   RoutineNodes* = {nnkProcDef, nnkMethodDef, nnkDo, nnkLambda, nnkIteratorDef}
   AtomicNodes* = {nnkNone..nnkNilLit}
-  CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand, 
+  CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
     nnkCallStrLit, nnkHiddenCallConv}
 
-from strutils import cmpIgnoreStyle, format
+proc expectKind*(n: NimNode; k: set[NimNodeKind]) {.compileTime.} =
+  assert n.kind in k, "Expected one of " & $k & ", got " & $n.kind
 
-proc expectKind*(n: PNimrodNode; k: set[TNimrodNodeKind]) {.compileTime.} =
-  assert n.kind in k, "Expected one of $1, got $2".format(k, n.kind)
-
-proc newProc*(name = newEmptyNode(); params: openArray[PNimrodNode] = [newEmptyNode()];  
-    body: PNimrodNode = newStmtList(), procType = nnkProcDef): PNimrodNode {.compileTime.} =
+proc newProc*(name = newEmptyNode(); params: openArray[NimNode] = [newEmptyNode()];
+    body: NimNode = newStmtList(), procType = nnkProcDef): NimNode {.compileTime.} =
   ## shortcut for creating a new proc
   ##
-  ## The ``params`` array must start with the return type of the proc, 
+  ## The ``params`` array must start with the return type of the proc,
   ## followed by a list of IdentDefs which specify the params.
   assert procType in RoutineNodes
   result = newNimNode(procType).add(
@@ -561,12 +612,12 @@ proc newProc*(name = newEmptyNode(); params: openArray[PNimrodNode] = [newEmptyN
     newEmptyNode(),
     body)
 
-proc newIfStmt*(branches: varargs[tuple[cond, body: PNimrodNode]]): 
-                PNimrodNode {.compiletime.} =
+proc newIfStmt*(branches: varargs[tuple[cond, body: NimNode]]):
+                NimNode {.compiletime.} =
   ## Constructor for ``if`` statements.
   ##
   ## .. code-block:: nim
-  ##    
+  ##
   ##    newIfStmt(
   ##      (Ident, StmtList),
   ##      ...
@@ -575,37 +626,37 @@ proc newIfStmt*(branches: varargs[tuple[cond, body: PNimrodNode]]):
   result = newNimNode(nnkIfStmt)
   for i in branches:
     result.add(newNimNode(nnkElifBranch).add(i.cond, i.body))
-    
 
-proc copyChildrenTo*(src, dest: PNimrodNode) {.compileTime.}=
+
+proc copyChildrenTo*(src, dest: NimNode) {.compileTime.}=
   ## Copy all children from `src` to `dest`
   for i in 0 .. < src.len:
     dest.add src[i].copyNimTree
 
-template expectRoutine(node: PNimrodNode): stmt =
+template expectRoutine(node: NimNode): stmt =
   expectKind(node, RoutineNodes)
-  
-proc name*(someProc: PNimrodNode): PNimrodNode {.compileTime.} =
+
+proc name*(someProc: NimNode): NimNode {.compileTime.} =
   someProc.expectRoutine
   result = someProc[0]
-proc `name=`*(someProc: PNimrodNode; val: PNimrodNode) {.compileTime.} =
+proc `name=`*(someProc: NimNode; val: NimNode) {.compileTime.} =
   someProc.expectRoutine
   someProc[0] = val
 
-proc params*(someProc: PNimrodNode): PNimrodNode {.compileTime.} =
+proc params*(someProc: NimNode): NimNode {.compileTime.} =
   someProc.expectRoutine
   result = someProc[3]
-proc `params=`* (someProc: PNimrodNode; params: PNimrodNode) {.compileTime.}=
+proc `params=`* (someProc: NimNode; params: NimNode) {.compileTime.}=
   someProc.expectRoutine
   assert params.kind == nnkFormalParams
   someProc[3] = params
 
-proc pragma*(someProc: PNimrodNode): PNimrodNode {.compileTime.} =
+proc pragma*(someProc: NimNode): NimNode {.compileTime.} =
   ## Get the pragma of a proc type
   ## These will be expanded
   someProc.expectRoutine
   result = someProc[4]
-proc `pragma=`*(someProc: PNimrodNode; val: PNimrodNode){.compileTime.}=
+proc `pragma=`*(someProc: NimNode; val: NimNode){.compileTime.}=
   ## Set the pragma of a proc type
   someProc.expectRoutine
   assert val.kind in {nnkEmpty, nnkPragma}
@@ -613,9 +664,9 @@ proc `pragma=`*(someProc: PNimrodNode; val: PNimrodNode){.compileTime.}=
 
 
 template badNodeKind(k; f): stmt{.immediate.} =
-  assert false, "Invalid node kind $# for macros.`$2`".format(k, f)
+  assert false, "Invalid node kind " & $k & " for macros.`" & $f & "`"
 
-proc body*(someProc: PNimrodNode): PNimrodNode {.compileTime.} =
+proc body*(someProc: NimNode): NimNode {.compileTime.} =
   case someProc.kind:
   of RoutineNodes:
     return someProc[6]
@@ -623,11 +674,11 @@ proc body*(someProc: PNimrodNode): PNimrodNode {.compileTime.} =
     return someProc[1]
   of nnkForStmt:
     return someProc.last
-  else: 
+  else:
     badNodeKind someProc.kind, "body"
 
-proc `body=`*(someProc: PNimrodNode, val: PNimrodNode) {.compileTime.} =
-  case someProc.kind 
+proc `body=`*(someProc: NimNode, val: NimNode) {.compileTime.} =
+  case someProc.kind
   of RoutineNodes:
     someProc[6] = val
   of nnkBlockStmt, nnkWhileStmt:
@@ -635,12 +686,12 @@ proc `body=`*(someProc: PNimrodNode, val: PNimrodNode) {.compileTime.} =
   of nnkForStmt:
     someProc[high(someProc)] = val
   else:
-    badNodeKind someProc.kind, "body=" 
+    badNodeKind someProc.kind, "body="
+
+proc basename*(a: NimNode): NimNode {.compiletime, benign.}
 
-proc basename*(a: PNimrodNode): PNimrodNode {.compiletime.}
-  
 
-proc `$`*(node: PNimrodNode): string {.compileTime.} =
+proc `$`*(node: NimNode): string {.compileTime.} =
   ## Get the string of an identifier node
   case node.kind
   of nnkIdent:
@@ -649,32 +700,34 @@ proc `$`*(node: PNimrodNode): string {.compileTime.} =
     result = $node.basename.ident & "*"
   of nnkStrLit..nnkTripleStrLit:
     result = node.strVal
-  else: 
+  of nnkSym:
+    result = $node.symbol
+  else:
     badNodeKind node.kind, "$"
 
-proc ident*(name: string): PNimrodNode {.compileTime,inline.} = newIdentNode(name)
+proc ident*(name: string): NimNode {.compileTime,inline.} = newIdentNode(name)
   ## Create a new ident node from a string
 
-iterator children*(n: PNimrodNode): PNimrodNode {.inline.}=
+iterator children*(n: NimNode): NimNode {.inline.}=
   for i in 0 .. high(n):
     yield n[i]
 
-template findChild*(n: PNimrodNode; cond: expr): PNimrodNode {.
+template findChild*(n: NimNode; cond: expr): NimNode {.
   immediate, dirty.} =
   ## Find the first child node matching condition (or nil).
-  ## 
+  ##
   ## .. code-block:: nim
   ##   var res = findChild(n, it.kind == nnkPostfix and
   ##                          it.basename.ident == !"foo")
   block:
-    var result: PNimrodNode
+    var result: NimNode
     for it in n.children:
-      if cond: 
+      if cond:
         result = it
         break
     result
 
-proc insert*(a: PNimrodNode; pos: int; b: PNimrodNode) {.compileTime.} =
+proc insert*(a: NimNode; pos: int; b: NimNode) {.compileTime.} =
   ## Insert node B into A at pos
   if high(a) < pos:
     ## add some empty nodes first
@@ -689,62 +742,78 @@ proc insert*(a: PNimrodNode; pos: int; b: PNimrodNode) {.compileTime.} =
       a[i + 1] = a[i]
     a[pos] = b
 
-proc basename*(a: PNimrodNode): PNimrodNode =
+proc basename*(a: NimNode): NimNode =
   ## Pull an identifier from prefix/postfix expressions
   case a.kind
   of nnkIdent: return a
   of nnkPostfix, nnkPrefix: return a[1]
-  else: 
-    quit "Do not know how to get basename of ("& treeRepr(a) &")\n"& repr(a)
-    
-proc `basename=`*(a: PNimrodNode; val: string) {.compileTime.}=
+  else:
+    quit "Do not know how to get basename of (" & treeRepr(a) & ")\n" & repr(a)
+
+proc `basename=`*(a: NimNode; val: string) {.compileTime.}=
   case a.kind
   of nnkIdent: macros.`ident=`(a,  !val)
   of nnkPostfix, nnkPrefix: a[1] = ident(val)
   else:
-    quit "Do not know how to get basename of ("& treeRepr(a)& ")\n"& repr(a)
+    quit "Do not know how to get basename of (" & treeRepr(a) & ")\n" & repr(a)
 
-proc postfix*(node: PNimrodNode; op: string): PNimrodNode {.compileTime.} = 
+proc postfix*(node: NimNode; op: string): NimNode {.compileTime.} =
   newNimNode(nnkPostfix).add(ident(op), node)
 
-proc prefix*(node: PNimrodNode; op: string): PNimrodNode {.compileTime.} = 
+proc prefix*(node: NimNode; op: string): NimNode {.compileTime.} =
   newNimNode(nnkPrefix).add(ident(op), node)
 
-proc infix*(a: PNimrodNode; op: string; 
-            b: PNimrodNode): PNimrodNode {.compileTime.} = 
+proc infix*(a: NimNode; op: string;
+            b: NimNode): NimNode {.compileTime.} =
   newNimNode(nnkInfix).add(ident(op), a, b)
 
-proc unpackPostfix*(node: PNimrodNode): tuple[node: PNimrodNode; op: string] {.
+proc unpackPostfix*(node: NimNode): tuple[node: NimNode; op: string] {.
   compileTime.} =
   node.expectKind nnkPostfix
   result = (node[0], $node[1])
 
-proc unpackPrefix*(node: PNimrodNode): tuple[node: PNimrodNode; op: string] {.
+proc unpackPrefix*(node: NimNode): tuple[node: NimNode; op: string] {.
   compileTime.} =
   node.expectKind nnkPrefix
   result = (node[0], $node[1])
 
-proc unpackInfix*(node: PNimrodNode): tuple[left: PNimrodNode; op: string; 
-                                        right: PNimrodNode] {.compileTime.} =
+proc unpackInfix*(node: NimNode): tuple[left: NimNode; op: string;
+                                        right: NimNode] {.compileTime.} =
   assert node.kind == nnkInfix
   result = (node[0], $node[1], node[2])
 
-proc copy*(node: PNimrodNode): PNimrodNode {.compileTime.} =
+proc copy*(node: NimNode): NimNode {.compileTime.} =
   ## An alias for copyNimTree().
   return node.copyNimTree()
 
+proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} =
+  proc toLower(c: char): char {.inline.} =
+    if c in {'A'..'Z'}: result = chr(ord(c) + (ord('a') - ord('A')))
+    else: result = c
+  var i = 0
+  var j = 0
+  while true:
+    while a[i] == '_': inc(i)
+    while b[j] == '_': inc(j) # BUGFIX: typo
+    var aa = toLower(a[i])
+    var bb = toLower(b[j])
+    result = ord(aa) - ord(bb)
+    if result != 0 or aa == '\0': break
+    inc(i)
+    inc(j)
+
 proc eqIdent* (a, b: string): bool = cmpIgnoreStyle(a, b) == 0
   ## Check if two idents are identical.
 
-proc hasArgOfName* (params: PNimrodNode; name: string): bool {.compiletime.}=
+proc hasArgOfName* (params: NimNode; name: string): bool {.compiletime.}=
   ## Search nnkFormalParams for an argument.
   assert params.kind == nnkFormalParams
-  for i in 1 .. <params.len: 
+  for i in 1 .. <params.len:
     template node: expr = params[i]
     if name.eqIdent( $ node[0]):
       return true
 
-proc addIdentIfAbsent*(dest: PNimrodNode, ident: string) {.compiletime.} =
+proc addIdentIfAbsent*(dest: NimNode, ident: string) {.compiletime.} =
   ## Add ident to dest if it is not present. This is intended for use
   ## with pragmas.
   for node in dest.children:
diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim
index f3f00f9f5..c3ff66591 100644
--- a/lib/core/typeinfo.nim
+++ b/lib/core/typeinfo.nim
@@ -7,10 +7,11 @@
 #    distribution, for details about the copyright.
 #
 
-## This module implements an interface to Nim's runtime type information.
+## This module implements an interface to Nim's `runtime type information`:idx:
+## (`RTTI`:idx:).
 ## Note that even though ``TAny`` and its operations hide the nasty low level
 ## details from its clients, it remains inherently unsafe!
-## 
+##
 ## See the `marshal <marshal.html>`_ module for what this module allows you
 ## to do. 
 
@@ -65,9 +66,9 @@ type
   ppointer = ptr pointer
   pbyteArray = ptr array[0.. 0xffff, int8]
 
-  TGenSeq = object
+  TGenericSeq {.importc.} = object
     len, space: int
-  PGenSeq = ptr TGenSeq
+  PGenSeq = ptr TGenericSeq
 
 const
   GenericSeqSize = (2 * sizeof(int))
@@ -268,9 +269,14 @@ iterator fields*(x: TAny): tuple[name: string, any: TAny] =
   # XXX BUG: does not work yet, however is questionable anyway
   when false:
     if x.rawType.kind == tyObject: t = cast[ptr PNimType](x.value)[]
-  var n = t.node
   var ret: seq[tuple[name: cstring, any: TAny]] = @[]
-  fieldsAux(p, n, ret)
+  if t.kind == tyObject:
+    while true:
+      fieldsAux(p, t.node, ret)
+      t = t.base
+      if t.isNil: break
+  else:
+    fieldsAux(p, t.node, ret)
   for name, any in items(ret):
     yield ($name, any)
 
diff --git a/lib/core/unsigned.nim b/lib/core/unsigned.nim
index 7acdf1439..20fcd03aa 100644
--- a/lib/core/unsigned.nim
+++ b/lib/core/unsigned.nim
@@ -11,49 +11,47 @@
 ## To discourage users from using ``unsigned``, it's not part of ``system``,
 ## but an extra import.
 
-type
-  SomeUInt = uint|uint8|uint16|uint32|uint64
-
-proc `not`*[T: SomeUInt](x: T): T {.magic: "BitnotI", noSideEffect.}
+proc `not`*[T: SomeUnsignedInt](x: T): T {.magic: "BitnotI", noSideEffect.}
   ## computes the `bitwise complement` of the integer `x`.
 
-proc `shr`*[T: SomeUInt](x, y: T): T {.magic: "ShrI", noSideEffect.}
+proc `shr`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ShrI", noSideEffect.}
   ## computes the `shift right` operation of `x` and `y`.
 
-proc `shl`*[T: SomeUInt](x, y: T): T {.magic: "ShlI", noSideEffect.}
+proc `shl`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ShlI", noSideEffect.}
   ## computes the `shift left` operation of `x` and `y`.
 
-proc `and`*[T: SomeUInt](x, y: T): T {.magic: "BitandI", noSideEffect.}
+proc `and`*[T: SomeUnsignedInt](x, y: T): T {.magic: "BitandI", noSideEffect.}
   ## computes the `bitwise and` of numbers `x` and `y`.
 
-proc `or`*[T: SomeUInt](x, y: T): T {.magic: "BitorI", noSideEffect.}
+proc `or`*[T: SomeUnsignedInt](x, y: T): T {.magic: "BitorI", noSideEffect.}
   ## computes the `bitwise or` of numbers `x` and `y`.
 
-proc `xor`*[T: SomeUInt](x, y: T): T {.magic: "BitxorI", noSideEffect.}
+proc `xor`*[T: SomeUnsignedInt](x, y: T): T {.magic: "BitxorI", noSideEffect.}
   ## computes the `bitwise xor` of numbers `x` and `y`.
 
-proc `==`*[T: SomeUInt](x, y: T): bool {.magic: "EqI", noSideEffect.}
+proc `==`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "EqI", noSideEffect.}
   ## Compares two unsigned integers for equality.
 
-proc `+`*[T: SomeUInt](x, y: T): T {.magic: "AddU", noSideEffect.}
+proc `+`*[T: SomeUnsignedInt](x, y: T): T {.magic: "AddU", noSideEffect.}
   ## Binary `+` operator for unsigned integers.
 
-proc `-`*[T: SomeUInt](x, y: T): T {.magic: "SubU", noSideEffect.}
+proc `-`*[T: SomeUnsignedInt](x, y: T): T {.magic: "SubU", noSideEffect.}
   ## Binary `-` operator for unsigned integers.
 
-proc `*`*[T: SomeUInt](x, y: T): T {.magic: "MulU", noSideEffect.}
+proc `*`*[T: SomeUnsignedInt](x, y: T): T {.magic: "MulU", noSideEffect.}
   ## Binary `*` operator for unsigned integers.
 
-proc `div`*[T: SomeUInt](x, y: T): T {.magic: "DivU", noSideEffect.}
+proc `div`*[T: SomeUnsignedInt](x, y: T): T {.magic: "DivU", noSideEffect.}
   ## computes the integer division. This is roughly the same as
   ## ``floor(x/y)``.
 
-proc `mod`*[T: SomeUInt](x, y: T): T {.magic: "ModU", noSideEffect.}
+proc `mod`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ModU", noSideEffect.}
   ## computes the integer modulo operation. This is the same as
   ## ``x - (x div y) * y``.
 
-proc `<=`*[T: SomeUInt](x, y: T): bool {.magic: "LeU", noSideEffect.}
+proc `<=`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "LeU", noSideEffect.}
   ## Returns true iff ``x <= y``.
 
-proc `<`*[T: SomeUInt](x, y: T): bool {.magic: "LtU", noSideEffect.}
+proc `<`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "LtU", noSideEffect.}
   ## Returns true iff ``unsigned(x) < unsigned(y)``.
+
diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim
index 968a2923a..b8180cd87 100644
--- a/lib/impure/db_mysql.nim
+++ b/lib/impure/db_mysql.nim
@@ -16,11 +16,11 @@ type
   TDbConn* = PMySQL    ## encapsulates a database connection
   TRow* = seq[string]  ## a row of a dataset. NULL database values will be
                        ## transformed always to the empty string.
-  EDb* = object of EIO ## exception that is raised if a database error occurs
+  EDb* = object of IOError ## exception that is raised if a database error occurs
 
   TSqlQuery* = distinct string ## an SQL query string
 
-  FDb* = object of FIO ## effect that denotes a database operation
+  FDb* = object of IOEffect ## effect that denotes a database operation
   FReadDb* = object of FDb   ## effect that denotes a read operation
   FWriteDb* = object of FDb  ## effect that denotes a write operation
 
@@ -229,3 +229,9 @@ proc open*(connection, user, password, database: string): TDbConn {.
     var errmsg = $mysql.error(result)
     db_mysql.close(result)
     dbError(errmsg)
+
+proc setEncoding*(connection: TDbConn, encoding: string): bool {.
+  tags: [FDb].} =
+  ## sets the encoding of a database connection, returns true for 
+  ## success, false for failure.
+  result = mysql.set_character_set(connection, encoding) == 0
\ No newline at end of file
diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim
index 6691c5703..ffb8bbcda 100644
--- a/lib/impure/db_postgres.nim
+++ b/lib/impure/db_postgres.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -260,3 +260,9 @@ proc open*(connection, user, password, database: string): TDbConn {.
   ## the nim db api.
   result = pqsetdbLogin(nil, nil, nil, nil, database, user, password)
   if pqStatus(result) != CONNECTION_OK: dbError(result) # result = nil
+
+proc setEncoding*(connection: TDbConn, encoding: string): bool {.
+  tags: [FDb].} =
+  ## sets the encoding of a database connection, returns true for 
+  ## success, false for failure.
+  return pqsetClientEncoding(connection, encoding) == 0
\ No newline at end of file
diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim
index bc9e0b591..8536ab6f2 100644
--- a/lib/impure/db_sqlite.nim
+++ b/lib/impure/db_sqlite.nim
@@ -48,6 +48,7 @@ proc dbError*(msg: string) {.noreturn.} =
   raise e
 
 proc dbQuote(s: string): string =
+  if s.isNil: return "NULL"
   result = "'"
   for c in items(s):
     if c == '\'': add(result, "''")
@@ -61,7 +62,7 @@ proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
     if c == '?':
       add(result, dbQuote(args[a]))
       inc(a)
-    else: 
+    else:
       add(result, c)
   
 proc tryExec*(db: TDbConn, query: TSqlQuery, 
@@ -191,8 +192,20 @@ proc open*(connection, user, password, database: string): TDbConn {.
     result = db
   else:
     dbError(db)
-   
-when isMainModule:
+
+proc setEncoding*(connection: TDbConn, encoding: string): bool {.
+  tags: [FDb].} =
+  ## sets the encoding of a database connection, returns true for 
+  ## success, false for failure.
+  ##
+  ## Note that the encoding cannot be changed once it's been set.
+  ## According to SQLite3 documentation, any attempt to change 
+  ## the encoding after the database is created will be silently 
+  ## ignored.
+  exec(connection, sql"PRAGMA encoding = ?", [encoding])
+  result = connection.getValue(sql"PRAGMA encoding") == encoding
+
+when not defined(testing) and isMainModule:
   var db = open("db.sql", "", "", "")
   exec(db, sql"create table tbl1(one varchar(10), two smallint)", [])
   exec(db, sql"insert into tbl1 values('hello!',10)", [])
diff --git a/lib/impure/graphics.nim b/lib/impure/graphics.nim
index dfadb46ee..814c0ebe1 100644
--- a/lib/impure/graphics.nim
+++ b/lib/impure/graphics.nim
@@ -499,7 +499,7 @@ template withEvents*(surf: PSurface, event: expr, actions: stmt): stmt {.
 if sdl.init(sdl.INIT_VIDEO) < 0: raiseEGraphics()
 if sdl_ttf.init() < 0: raiseEGraphics()
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   var surf = newScreenSurface(800, 600)
 
   surf.fillSurface(colWhite)
diff --git a/lib/impure/osinfo_posix.nim b/lib/impure/osinfo_posix.nim
index 1baff8c55..0362fca12 100644
--- a/lib/impure/osinfo_posix.nim
+++ b/lib/impure/osinfo_posix.nim
@@ -1,69 +1,10 @@
-import posix, strutils, os
-
-when false:
-  type
-    Tstatfs {.importc: "struct statfs64", 
-              header: "<sys/statfs.h>", final, pure.} = object
-      f_type: int
-      f_bsize: int
-      f_blocks: int
-      f_bfree: int
-      f_bavail: int
-      f_files: int
-      f_ffree: int
-      f_fsid: int
-      f_namelen: int
-
-  proc statfs(path: string, buf: var Tstatfs): int {.
-    importc, header: "<sys/vfs.h>".}
-
-
-proc getSystemVersion*(): string =
-  result = ""
-  
-  var unix_info: TUtsname
-  
-  if uname(unix_info) != 0:
-    os.raiseOSError(osLastError())
-  
-  if $unix_info.sysname == "Linux":
-    # Linux
-    result.add("Linux ")
-
-    result.add($unix_info.release & " ")
-    result.add($unix_info.machine)
-  elif $unix_info.sysname == "Darwin":
-    # Darwin
-    result.add("Mac OS X ")
-    if "10" in $unix_info.release:
-      result.add("v10.6 Snow Leopard")
-    elif "9" in $unix_info.release:
-      result.add("v10.5 Leopard")
-    elif "8" in $unix_info.release:
-      result.add("v10.4 Tiger")
-    elif "7" in $unix_info.release:
-      result.add("v10.3 Panther")
-    elif "6" in $unix_info.release:
-      result.add("v10.2 Jaguar")
-    elif "1.4" in $unix_info.release:
-      result.add("v10.1 Puma")
-    elif "1.3" in $unix_info.release:
-      result.add("v10.0 Cheetah")
-    elif "0" in $unix_info.release:
-      result.add("Server 1.0 Hera")
-  else:
-    result.add($unix_info.sysname & " " & $unix_info.release)
-    
-    
-when false:
-  var unix_info: TUtsname
-  echo(uname(unix_info))
-  echo(unix_info.sysname)
-  echo("8" in $unix_info.release)
-
-  echo(getSystemVersion())
-
-  var stfs: TStatfs
-  echo(statfs("sysinfo_posix.nim", stfs))
-  echo(stfs.f_files)
-  
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+{.error: "This module has been moved to the 'osinfo' nimble package.".}
diff --git a/lib/impure/osinfo_win.nim b/lib/impure/osinfo_win.nim
index f423a34a3..0362fca12 100644
--- a/lib/impure/osinfo_win.nim
+++ b/lib/impure/osinfo_win.nim
@@ -1,404 +1,10 @@
-# XXX clean up this mess!
-
-import winlean
-
-const
-  INVALID_HANDLE_VALUE = int(- 1) # GetStockObject
-
-type
-  TMEMORYSTATUSEX {.final, pure.} = object
-    dwLength: int32
-    dwMemoryLoad: int32
-    ullTotalPhys: int64
-    ullAvailPhys: int64
-    ullTotalPageFile: int64
-    ullAvailPageFile: int64
-    ullTotalVirtual: int64
-    ullAvailVirtual: int64
-    ullAvailExtendedVirtual: int64
-    
-  SYSTEM_INFO* {.final, pure.} = object
-    wProcessorArchitecture*: int16
-    wReserved*: int16
-    dwPageSize*: int32
-    lpMinimumApplicationAddress*: pointer
-    lpMaximumApplicationAddress*: pointer
-    dwActiveProcessorMask*: int32
-    dwNumberOfProcessors*: int32
-    dwProcessorType*: int32
-    dwAllocationGranularity*: int32
-    wProcessorLevel*: int16
-    wProcessorRevision*: int16
-
-  LPSYSTEM_INFO* = ptr SYSTEM_INFO
-  TSYSTEMINFO* = SYSTEM_INFO
-
-  TMemoryInfo* = object
-    MemoryLoad*: int ## occupied memory, in percent
-    TotalPhysMem*: int64 ## Total Physical memory, in bytes
-    AvailablePhysMem*: int64 ## Available physical memory, in bytes
-    TotalPageFile*: int64 ## The current committed memory limit 
-                          ## for the system or the current process, whichever is smaller, in bytes.
-    AvailablePageFile*: int64 ## The maximum amount of memory the current process can commit, in bytes.
-    TotalVirtualMem*: int64 ## Total virtual memory, in bytes
-    AvailableVirtualMem*: int64 ## Available virtual memory, in bytes
-    
-  TOSVERSIONINFOEX {.final, pure.} = object
-    dwOSVersionInfoSize: int32
-    dwMajorVersion: int32
-    dwMinorVersion: int32
-    dwBuildNumber: int32
-    dwPlatformId: int32
-    szCSDVersion: array[0..127, char]
-    wServicePackMajor: int16
-    wServicePackMinor: int16
-    wSuiteMask: int16
-    wProductType: int8
-    wReserved: char
-    
-  TVersionInfo* = object
-    majorVersion*: int
-    minorVersion*: int
-    buildNumber*: int
-    platformID*: int
-    SPVersion*: string ## Full Service pack version string
-    SPMajor*: int ## Major service pack version
-    SPMinor*: int ## Minor service pack version
-    SuiteMask*: int
-    ProductType*: int
-    
-  TPartitionInfo* = tuple[FreeSpace, TotalSpace: Tfiletime]
-  
-const
-  # SuiteMask - VersionInfo.SuiteMask
-  VER_SUITE_BACKOFFICE* = 0x00000004
-  VER_SUITE_BLADE* = 0x00000400
-  VER_SUITE_COMPUTE_SERVER* = 0x00004000
-  VER_SUITE_DATACENTER* = 0x00000080
-  VER_SUITE_ENTERPRISE* = 0x00000002
-  VER_SUITE_EMBEDDEDNT* = 0x00000040
-  VER_SUITE_PERSONAL* = 0x00000200
-  VER_SUITE_SINGLEUSERTS* = 0x00000100
-  VER_SUITE_SMALLBUSINESS* = 0x00000001
-  VER_SUITE_SMALLBUSINESS_RESTRICTED* = 0x00000020
-  VER_SUITE_STORAGE_SERVER* = 0x00002000
-  VER_SUITE_TERMINAL* = 0x00000010
-  VER_SUITE_WH_SERVER* = 0x00008000
-
-  # ProductType - VersionInfo.ProductType
-  VER_NT_DOMAIN_CONTROLLER* = 0x0000002
-  VER_NT_SERVER* = 0x0000003
-  VER_NT_WORKSTATION* = 0x0000001
-  
-  VER_PLATFORM_WIN32_NT* = 2
-  
-  # Product Info - getProductInfo() - (Remove unused ones ?)
-  PRODUCT_BUSINESS* = 0x00000006
-  PRODUCT_BUSINESS_N* = 0x00000010
-  PRODUCT_CLUSTER_SERVER* = 0x00000012
-  PRODUCT_DATACENTER_SERVER* = 0x00000008
-  PRODUCT_DATACENTER_SERVER_CORE* = 0x0000000C
-  PRODUCT_DATACENTER_SERVER_CORE_V* = 0x00000027
-  PRODUCT_DATACENTER_SERVER_V* = 0x00000025
-  PRODUCT_ENTERPRISE* = 0x00000004
-  PRODUCT_ENTERPRISE_E* = 0x00000046
-  PRODUCT_ENTERPRISE_N* = 0x0000001B
-  PRODUCT_ENTERPRISE_SERVER* = 0x0000000A
-  PRODUCT_ENTERPRISE_SERVER_CORE* = 0x0000000E
-  PRODUCT_ENTERPRISE_SERVER_CORE_V* = 0x00000029
-  PRODUCT_ENTERPRISE_SERVER_IA64* = 0x0000000F
-  PRODUCT_ENTERPRISE_SERVER_V* = 0x00000026
-  PRODUCT_HOME_BASIC* = 0x00000002
-  PRODUCT_HOME_BASIC_E* = 0x00000043
-  PRODUCT_HOME_BASIC_N* = 0x00000005
-  PRODUCT_HOME_PREMIUM* = 0x00000003
-  PRODUCT_HOME_PREMIUM_E* = 0x00000044
-  PRODUCT_HOME_PREMIUM_N* = 0x0000001A
-  PRODUCT_HYPERV* = 0x0000002A
-  PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT* = 0x0000001E
-  PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING* = 0x00000020
-  PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY* = 0x0000001F
-  PRODUCT_PROFESSIONAL* = 0x00000030
-  PRODUCT_PROFESSIONAL_E* = 0x00000045
-  PRODUCT_PROFESSIONAL_N* = 0x00000031
-  PRODUCT_SERVER_FOR_SMALLBUSINESS* = 0x00000018
-  PRODUCT_SERVER_FOR_SMALLBUSINESS_V* = 0x00000023
-  PRODUCT_SERVER_FOUNDATION* = 0x00000021
-  PRODUCT_SMALLBUSINESS_SERVER* = 0x00000009
-  PRODUCT_STANDARD_SERVER* = 0x00000007
-  PRODUCT_STANDARD_SERVER_CORE * = 0x0000000D
-  PRODUCT_STANDARD_SERVER_CORE_V* = 0x00000028
-  PRODUCT_STANDARD_SERVER_V* = 0x00000024
-  PRODUCT_STARTER* = 0x0000000B
-  PRODUCT_STARTER_E* = 0x00000042
-  PRODUCT_STARTER_N* = 0x0000002F
-  PRODUCT_STORAGE_ENTERPRISE_SERVER* = 0x00000017
-  PRODUCT_STORAGE_EXPRESS_SERVER* = 0x00000014
-  PRODUCT_STORAGE_STANDARD_SERVER* = 0x00000015
-  PRODUCT_STORAGE_WORKGROUP_SERVER* = 0x00000016
-  PRODUCT_UNDEFINED* = 0x00000000
-  PRODUCT_ULTIMATE* = 0x00000001
-  PRODUCT_ULTIMATE_E* = 0x00000047
-  PRODUCT_ULTIMATE_N* = 0x0000001C
-  PRODUCT_WEB_SERVER* = 0x00000011
-  PRODUCT_WEB_SERVER_CORE* = 0x0000001D
-  
-  PROCESSOR_ARCHITECTURE_AMD64* = 9 ## x64 (AMD or Intel)
-  PROCESSOR_ARCHITECTURE_IA64* = 6 ## Intel Itanium Processor Family (IPF)
-  PROCESSOR_ARCHITECTURE_INTEL* = 0 ## x86
-  PROCESSOR_ARCHITECTURE_UNKNOWN* = 0xffff ## Unknown architecture.
-  
-  # GetSystemMetrics
-  SM_SERVERR2 = 89 
-  
-proc globalMemoryStatusEx*(lpBuffer: var TMEMORYSTATUSEX){.stdcall, dynlib: "kernel32",
-    importc: "GlobalMemoryStatusEx".}
-    
-proc getMemoryInfo*(): TMemoryInfo =
-  ## Retrieves memory info
-  var statex: TMEMORYSTATUSEX
-  statex.dwLength = sizeof(statex).int32
-
-  globalMemoryStatusEx(statex)
-  result.MemoryLoad = statex.dwMemoryLoad
-  result.TotalPhysMem = statex.ullTotalPhys
-  result.AvailablePhysMem = statex.ullAvailPhys
-  result.TotalPageFile = statex.ullTotalPageFile
-  result.AvailablePageFile = statex.ullAvailPageFile
-  result.TotalVirtualMem = statex.ullTotalVirtual
-  result.AvailableVirtualMem = statex.ullAvailExtendedVirtual
-
-proc getVersionEx*(lpVersionInformation: var TOSVERSIONINFOEX): WINBOOL{.stdcall,
-    dynlib: "kernel32", importc: "GetVersionExA".}
-
-proc getProcAddress*(hModule: int, lpProcName: cstring): pointer{.stdcall,
-    dynlib: "kernel32", importc: "GetProcAddress".}
-
-proc getModuleHandleA*(lpModuleName: cstring): int{.stdcall,
-     dynlib: "kernel32", importc: "GetModuleHandleA".}
-
-proc getVersionInfo*(): TVersionInfo =
-  ## Retrieves operating system info
-  var osvi: TOSVERSIONINFOEX
-  osvi.dwOSVersionInfoSize = sizeof(osvi).int32
-  discard getVersionEx(osvi)
-  result.majorVersion = osvi.dwMajorVersion
-  result.minorVersion = osvi.dwMinorVersion
-  result.buildNumber = osvi.dwBuildNumber
-  result.platformID = osvi.dwPlatformId
-  result.SPVersion = $osvi.szCSDVersion
-  result.SPMajor = osvi.wServicePackMajor
-  result.SPMinor = osvi.wServicePackMinor
-  result.SuiteMask = osvi.wSuiteMask
-  result.ProductType = osvi.wProductType
-
-proc getProductInfo*(majorVersion, minorVersion, SPMajorVersion, 
-                     SPMinorVersion: int): int =
-  ## Retrieves Windows' ProductInfo, this function only works in Vista and 7
-
-  var pGPI = cast[proc (dwOSMajorVersion, dwOSMinorVersion, 
-              dwSpMajorVersion, dwSpMinorVersion: int32, outValue: Pint32)](getProcAddress(
-                getModuleHandleA("kernel32.dll"), "GetProductInfo"))
-                
-  if pGPI != nil:
-    var dwType: int32
-    pGPI(int32(majorVersion), int32(minorVersion), int32(SPMajorVersion), int32(SPMinorVersion), addr(dwType))
-    result = int(dwType)
-  else:
-    return PRODUCT_UNDEFINED
-
-proc getSystemInfo*(lpSystemInfo: LPSYSTEM_INFO){.stdcall, dynlib: "kernel32",
-    importc: "GetSystemInfo".}
-    
-proc getSystemInfo*(): TSYSTEM_INFO =
-  ## Returns the SystemInfo
-
-  # Use GetNativeSystemInfo if it's available
-  var pGNSI = cast[proc (lpSystemInfo: LPSYSTEM_INFO)](getProcAddress(
-                getModuleHandleA("kernel32.dll"), "GetNativeSystemInfo"))
-                
-  var systemi: TSYSTEM_INFO              
-  if pGNSI != nil:
-    pGNSI(addr(systemi))
-  else:
-    getSystemInfo(addr(systemi))
-
-  return systemi
-
-proc getSystemMetrics*(nIndex: int32): int32{.stdcall, dynlib: "user32",
-    importc: "GetSystemMetrics".}
-
-proc `$`*(osvi: TVersionInfo): string =
-  ## Turns a VersionInfo object, into a string
-
-  if osvi.platformID == VER_PLATFORM_WIN32_NT and osvi.majorVersion > 4:
-    result = "Microsoft "
-    
-    var si = getSystemInfo()
-    # Test for the specific product
-    if osvi.majorVersion == 6:
-      if osvi.minorVersion == 0:
-        if osvi.ProductType == VER_NT_WORKSTATION:
-          result.add("Windows Vista ")
-        else: result.add("Windows Server 2008 ")
-      elif osvi.minorVersion == 1:
-        if osvi.ProductType == VER_NT_WORKSTATION:
-          result.add("Windows 7 ")
-        else: result.add("Windows Server 2008 R2 ")
-    
-      var dwType = getProductInfo(osvi.majorVersion, osvi.minorVersion, 0, 0)
-      case dwType
-      of PRODUCT_ULTIMATE:
-        result.add("Ultimate Edition")
-      of PRODUCT_PROFESSIONAL:
-        result.add("Professional")
-      of PRODUCT_HOME_PREMIUM:
-        result.add("Home Premium Edition")
-      of PRODUCT_HOME_BASIC:
-        result.add("Home Basic Edition")
-      of PRODUCT_ENTERPRISE:
-        result.add("Enterprise Edition")
-      of PRODUCT_BUSINESS:
-        result.add("Business Edition")
-      of PRODUCT_STARTER:
-        result.add("Starter Edition")
-      of PRODUCT_CLUSTER_SERVER:
-        result.add("Cluster Server Edition")
-      of PRODUCT_DATACENTER_SERVER:
-        result.add("Datacenter Edition")
-      of PRODUCT_DATACENTER_SERVER_CORE:
-        result.add("Datacenter Edition (core installation)")
-      of PRODUCT_ENTERPRISE_SERVER:
-        result.add("Enterprise Edition")
-      of PRODUCT_ENTERPRISE_SERVER_CORE:
-        result.add("Enterprise Edition (core installation)")
-      of PRODUCT_ENTERPRISE_SERVER_IA64:
-        result.add("Enterprise Edition for Itanium-based Systems")
-      of PRODUCT_SMALLBUSINESS_SERVER:
-        result.add("Small Business Server")
-      of PRODUCT_STANDARD_SERVER:
-        result.add("Standard Edition")
-      of PRODUCT_STANDARD_SERVER_CORE:
-        result.add("Standard Edition (core installation)")
-      of PRODUCT_WEB_SERVER:
-        result.add("Web Server Edition")
-      else:
-        discard
-    # End of Windows 6.*
-
-    if osvi.majorVersion == 5 and osvi.minorVersion == 2:
-      if getSystemMetrics(SM_SERVERR2) != 0:
-        result.add("Windows Server 2003 R2, ")
-      elif (osvi.SuiteMask and VER_SUITE_PERSONAL) != 0: # Not sure if this will work
-        result.add("Windows Storage Server 2003")
-      elif (osvi.SuiteMask and VER_SUITE_WH_SERVER) != 0:
-        result.add("Windows Home Server")
-      elif osvi.ProductType == VER_NT_WORKSTATION and 
-          si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64:
-        result.add("Windows XP Professional x64 Edition")
-      else:
-        result.add("Windows Server 2003, ")
-      
-      # Test for the specific product
-      if osvi.ProductType != VER_NT_WORKSTATION:
-        if ze(si.wProcessorArchitecture) == PROCESSOR_ARCHITECTURE_IA64:
-          if (osvi.SuiteMask and VER_SUITE_DATACENTER) != 0:
-            result.add("Datacenter Edition for Itanium-based Systems")
-          elif (osvi.SuiteMask and VER_SUITE_ENTERPRISE) != 0:
-            result.add("Enterprise Edition for Itanium-based Systems")
-        elif ze(si.wProcessorArchitecture) == PROCESSOR_ARCHITECTURE_AMD64:
-          if (osvi.SuiteMask and VER_SUITE_DATACENTER) != 0:
-            result.add("Datacenter x64 Edition")
-          elif (osvi.SuiteMask and VER_SUITE_ENTERPRISE) != 0:
-            result.add("Enterprise x64 Edition")
-          else:
-            result.add("Standard x64 Edition")
-        else:
-          if (osvi.SuiteMask and VER_SUITE_COMPUTE_SERVER) != 0:
-            result.add("Compute Cluster Edition")
-          elif (osvi.SuiteMask and VER_SUITE_DATACENTER) != 0:
-            result.add("Datacenter Edition")
-          elif (osvi.SuiteMask and VER_SUITE_ENTERPRISE) != 0:
-            result.add("Enterprise Edition")
-          elif (osvi.SuiteMask and VER_SUITE_BLADE) != 0:
-            result.add("Web Edition")
-          else:
-            result.add("Standard Edition")
-    # End of 5.2
-    
-    if osvi.majorVersion == 5 and osvi.minorVersion == 1:
-      result.add("Windows XP ")
-      if (osvi.SuiteMask and VER_SUITE_PERSONAL) != 0:
-        result.add("Home Edition")
-      else:
-        result.add("Professional")
-    # End of 5.1
-    
-    if osvi.majorVersion == 5 and osvi.minorVersion == 0:
-      result.add("Windows 2000 ")
-      if osvi.ProductType == VER_NT_WORKSTATION:
-        result.add("Professional")
-      else:
-        if (osvi.SuiteMask and VER_SUITE_DATACENTER) != 0:
-          result.add("Datacenter Server")
-        elif (osvi.SuiteMask and VER_SUITE_ENTERPRISE) != 0:
-          result.add("Advanced Server")
-        else:
-          result.add("Server")
-    # End of 5.0
-    
-    # Include service pack (if any) and build number.
-    if len(osvi.SPVersion) > 0:
-      result.add(" ")
-      result.add(osvi.SPVersion)
-    
-    result.add(" (build " & $osvi.buildNumber & ")")
-    
-    if osvi.majorVersion >= 6:
-      if ze(si.wProcessorArchitecture) == PROCESSOR_ARCHITECTURE_AMD64:
-        result.add(", 64-bit")
-      elif ze(si.wProcessorArchitecture) == PROCESSOR_ARCHITECTURE_INTEL:
-        result.add(", 32-bit")
-    
-  else:
-    # Windows 98 etc...
-    result = "Unknown version of windows[Kernel version <= 4]"
-    
-
-proc getFileSize*(file: string): BiggestInt =
-  var fileData: TWIN32_FIND_DATA
-
-  when useWinUnicode:
-    var aa = newWideCString(file)
-    var hFile = findFirstFileW(aa, fileData)
-  else:
-    var hFile = findFirstFileA(file, fileData)
-  
-  if hFile == INVALID_HANDLE_VALUE:
-    raise newException(IOError, $getLastError())
-  
-  return fileData.nFileSizeLow
-
-proc getDiskFreeSpaceEx*(lpDirectoryName: cstring, lpFreeBytesAvailableToCaller,
-                         lpTotalNumberOfBytes,
-                         lpTotalNumberOfFreeBytes: var TFiletime): WINBOOL{.
-    stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceExA".}
-
-proc getPartitionInfo*(partition: string): TPartitionInfo =
-  ## Retrieves partition info, for example ``partition`` may be ``"C:\"``
-  var freeBytes, totalBytes, totalFreeBytes: TFiletime 
-  discard getDiskFreeSpaceEx(r"C:\", freeBytes, totalBytes, 
-                               totalFreeBytes)
-  return (freeBytes, totalBytes)
-
-when isMainModule:
-  var r = getMemoryInfo()
-  echo("Memory load: ", r.MemoryLoad, "%")
-  
-  var osvi = getVersionInfo()
-  
-  echo($osvi)
-
-  echo(getFileSize(r"osinfo_win.nim") div 1024 div 1024)
-  
-  echo(rdFileTime(getPartitionInfo(r"C:\")[0]))
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+{.error: "This module has been moved to the 'osinfo' nimble package.".}
diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim
index 07ef13fd9..f4d00979c 100644
--- a/lib/impure/rdstdin.nim
+++ b/lib/impure/rdstdin.nim
@@ -1,21 +1,23 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2012 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
 ## This module contains code for reading from `stdin`:idx:. On UNIX the GNU
-## readline library is wrapped and set up to provide default key bindings 
+## readline library is wrapped and set up to provide default key bindings
 ## (e.g. you can navigate with the arrow keys). On Windows ``system.readLine``
-## is used. This suffices because Windows' console already provides the 
+## is used. This suffices because Windows' console already provides the
 ## wanted functionality.
 
+{.deadCodeElim: on.}
+
 when defined(Windows):
   proc readLineFromStdin*(prompt: string): TaintedString {.
-                          tags: [ReadIOEffect, WriteIOEffect].} = 
+                          tags: [ReadIOEffect, WriteIOEffect].} =
     ## Reads a line from stdin.
     stdout.write(prompt)
     result = readLine(stdin)
@@ -31,9 +33,75 @@ when defined(Windows):
     stdout.write(prompt)
     result = readLine(stdin, line)
 
+  import winlean
+
+  const
+    VK_SHIFT* = 16
+    VK_CONTROL* = 17
+    VK_MENU* = 18
+    KEY_EVENT* = 1
+
+  type
+    KEY_EVENT_RECORD = object
+      bKeyDown: WinBool
+      wRepeatCount: uint16
+      wVirtualKeyCode: uint16
+      wVirtualScanCode: uint16
+      unicodeChar: uint16
+      dwControlKeyState: uint32
+    INPUT_RECORD = object
+      eventType*: int16
+      reserved*: int16
+      event*: KEY_EVENT_RECORD
+      safetyBuffer: array[0..5, DWORD]
+
+  proc readConsoleInputW*(hConsoleInput: THANDLE, lpBuffer: var INPUTRECORD,
+                          nLength: uint32,
+                          lpNumberOfEventsRead: var uint32): WINBOOL{.
+      stdcall, dynlib: "kernel32", importc: "ReadConsoleInputW".}
+
+  proc getch(): uint16 =
+    let hStdin = getStdHandle(STD_INPUT_HANDLE)
+    var
+      irInputRecord: INPUT_RECORD
+      dwEventsRead: uint32
+
+    while readConsoleInputW(hStdin, irInputRecord, 1, dwEventsRead) != 0:
+      if irInputRecord.eventType == KEY_EVENT and
+          irInputRecord.event.wVirtualKeyCode notin {VK_SHIFT, VK_MENU, VK_CONTROL}:
+         result = irInputRecord.event.unicodeChar
+         discard readConsoleInputW(hStdin, irInputRecord, 1, dwEventsRead)
+         return result
+
+  from unicode import toUTF8, Rune, runeLenAt
+
+  proc readPasswordFromStdin*(prompt: string, password: var TaintedString):
+                              bool {.tags: [ReadIOEffect, WriteIOEffect].} =
+    ## Reads a `password` from stdin without printing it. `password` must not
+    ## be ``nil``! Returns ``false`` if the end of the file has been reached,
+    ## ``true`` otherwise.
+    password.setLen(0)
+    stdout.write(prompt)
+    while true:
+      let c = getch()
+      case c.char
+      of '\r', chr(0xA):
+        break
+      of '\b':
+        # ensure we delete the whole UTF-8 character:
+        var i = 0
+        var x = 1
+        while i < password.len:
+          x = runeLenAt(password, i)
+          inc i, x
+        password.setLen(password.len - x)
+      else:
+        password.add(toUTF8(c.Rune))
+    stdout.write "\n"
+
 else:
-  import readline, history
-    
+  import readline, history, termios, unsigned
+
   proc readLineFromStdin*(prompt: string): TaintedString {.
                           tags: [ReadIOEffect, WriteIOEffect].} =
     var buffer = readline.readLine(prompt)
@@ -55,8 +123,26 @@ else:
     result = true
 
   # initialization:
-  # disable auto-complete: 
+  # disable auto-complete:
   proc doNothing(a, b: cint): cint {.cdecl, procvar.} = discard
-  
+
   discard readline.bind_key('\t'.ord, doNothing)
 
+  proc readPasswordFromStdin*(prompt: string, password: var TaintedString):
+                              bool {.tags: [ReadIOEffect, WriteIOEffect].} =
+    password.setLen(0)
+    let fd = stdin.getFileHandle()
+    var cur, old: Termios
+    discard fd.tcgetattr(cur.addr)
+    old = cur
+    cur.c_lflag = cur.c_lflag and not Tcflag(ECHO)
+    discard fd.tcsetattr(TCSADRAIN, cur.addr)
+    stdout.write prompt
+    result = stdin.readLine(password)
+    stdout.write "\n"
+    discard fd.tcsetattr(TCSADRAIN, old.addr)
+
+proc readPasswordFromStdin*(prompt: string): TaintedString =
+  ## Reads a password from stdin without printing it.
+  result = TaintedString("")
+  discard readPasswordFromStdin(prompt, result)
diff --git a/lib/impure/re.nim b/lib/impure/re.nim
index 6e3a69c62..fb95610f6 100644
--- a/lib/impure/re.nim
+++ b/lib/impure/re.nim
@@ -7,8 +7,17 @@
 #    distribution, for details about the copyright.
 #
 
-## Regular expression support for Nim. Consider using the pegs module
-## instead.
+## Regular expression support for Nim. Consider using the pegs module instead.
+##
+## There is an alternative regular expressions library with a more unified API:
+## `nre <https://github.com/flaviut/nre>`_. It may be added to the standard
+## library in the future, instead of `re`.
+##
+## **Note:** The 're' proc defaults to the **extended regular expression
+## syntax** which lets you use whitespace freely to make your regexes readable.
+## However, this means to match whitespace ``\s`` or something similar has
+## to be used.
+##
 ## This module is implemented by providing a wrapper around the
 ## `PRCE (Perl-Compatible Regular Expressions) <http://www.pcre.org>`_
 ## C library. This means that your application will depend on the PRCE
@@ -20,52 +29,52 @@
 ##
 
 import
-  pcre, strutils
+  pcre, strutils, rtarrays
 
 const
-  MaxSubpatterns* = 10
+  MaxSubpatterns* = 20
     ## defines the maximum number of subpatterns that can be captured.
-    ## More subpatterns cannot be captured!
+    ## This limit still exists for ``replacef`` and ``parallelReplace``.
 
 type
   RegexFlag* = enum     ## options for regular expressions
     reIgnoreCase = 0,    ## do caseless matching
-    reMultiLine = 1,     ## ``^`` and ``$`` match newlines within data 
+    reMultiLine = 1,     ## ``^`` and ``$`` match newlines within data
     reDotAll = 2,        ## ``.`` matches anything including NL
     reExtended = 3,      ## ignore whitespace and ``#`` comments
     reStudy = 4          ## study the expression (may be omitted if the
                          ## expression will be used only once)
-    
+  
   RegexDesc = object 
-    h: PPcre
-    e: ptr TExtra
-    
+    h: ptr Pcre
+    e: ptr ExtraData
+  
   Regex* = ref RegexDesc ## a compiled regular expression
-    
+
   RegexError* = object of ValueError
     ## is raised if the pattern is no valid regular expression.
 
 {.deprecated: [TRegexFlag: RegexFlag, TRegexDesc: RegexDesc, TRegex: Regex,
     EInvalidRegEx: RegexError].}
 
-proc raiseInvalidRegex(msg: string) {.noinline, noreturn.} = 
+proc raiseInvalidRegex(msg: string) {.noinline, noreturn.} =
   var e: ref RegexError
   new(e)
   e.msg = msg
   raise e
-  
-proc rawCompile(pattern: string, flags: cint): PPcre =
+
+proc rawCompile(pattern: string, flags: cint): ptr Pcre =
   var
     msg: cstring
     offset: cint
   result = pcre.compile(pattern, flags, addr(msg), addr(offset), nil)
   if result == nil:
-    raiseInvalidRegex($msg & "\n" & pattern & "\n" & repeatChar(offset) & "^\n")
+    raiseInvalidRegex($msg & "\n" & pattern & "\n" & spaces(offset) & "^\n")
 
-proc finalizeRegEx(x: Regex) = 
+proc finalizeRegEx(x: Regex) =
   # XXX This is a hack, but PCRE does not export its "free" function properly.
   # Sigh. The hack relies on PCRE's implementation (see ``pcre_get.c``).
-  # Fortunately the implementation is unlikely to change. 
+  # Fortunately the implementation is unlikely to change.
   pcre.free_substring(cast[cstring](x.h))
   if not isNil(x.e):
     pcre.free_substring(cast[cstring](x.e))
@@ -78,15 +87,16 @@ proc re*(s: string, flags = {reExtended, reStudy}): Regex =
   result.h = rawCompile(s, cast[cint](flags - {reStudy}))
   if reStudy in flags:
     var msg: cstring
-    result.e = pcre.study(result.h, 0, msg)
+    result.e = pcre.study(result.h, 0, addr msg)
     if not isNil(msg): raiseInvalidRegex($msg)
 
 proc matchOrFind(s: string, pattern: Regex, matches: var openArray[string],
                  start, flags: cint): cint =
   var
-    rawMatches: array[0..MaxSubpatterns * 3 - 1, cint]
+    rtarray = initRtArray[cint]((matches.len+1)*3)
+    rawMatches = rtarray.getRawData
     res = pcre.exec(pattern.h, pattern.e, s, len(s).cint, start, flags,
-      cast[ptr cint](addr(rawMatches)), MaxSubpatterns * 3)
+      cast[ptr cint](rawMatches), (matches.len+1).cint*3)
   if res < 0'i32: return res
   for i in 1..int(res)-1:
     var a = rawMatches[i * 2]
@@ -94,17 +104,18 @@ proc matchOrFind(s: string, pattern: Regex, matches: var openArray[string],
     if a >= 0'i32: matches[i-1] = substr(s, int(a), int(b)-1)
     else: matches[i-1] = nil
   return rawMatches[1] - rawMatches[0]
-  
+
 proc findBounds*(s: string, pattern: Regex, matches: var openArray[string],
                  start = 0): tuple[first, last: int] =
-  ## returns the starting position and end position of `pattern` in `s` 
+  ## returns the starting position and end position of `pattern` in `s`
   ## and the captured
   ## substrings in the array `matches`. If it does not match, nothing
   ## is written into `matches` and ``(-1,0)`` is returned.
   var
-    rawMatches: array[0..MaxSubpatterns * 3 - 1, cint]
+    rtarray = initRtArray[cint]((matches.len+1)*3)
+    rawMatches = rtarray.getRawData
     res = pcre.exec(pattern.h, pattern.e, s, len(s).cint, start.cint, 0'i32,
-      cast[ptr cint](addr(rawMatches)), MaxSubpatterns * 3)
+      cast[ptr cint](rawMatches), (matches.len+1).cint*3)
   if res < 0'i32: return (-1, 0)
   for i in 1..int(res)-1:
     var a = rawMatches[i * 2]
@@ -112,18 +123,19 @@ proc findBounds*(s: string, pattern: Regex, matches: var openArray[string],
     if a >= 0'i32: matches[i-1] = substr(s, int(a), int(b)-1)
     else: matches[i-1] = nil
   return (rawMatches[0].int, rawMatches[1].int - 1)
-  
-proc findBounds*(s: string, pattern: Regex, 
+
+proc findBounds*(s: string, pattern: Regex,
                  matches: var openArray[tuple[first, last: int]],
                  start = 0): tuple[first, last: int] =
-  ## returns the starting position and end position of ``pattern`` in ``s`` 
-  ## and the captured substrings in the array `matches`. 
+  ## returns the starting position and end position of ``pattern`` in ``s``
+  ## and the captured substrings in the array `matches`.
   ## If it does not match, nothing is written into `matches` and
   ## ``(-1,0)`` is returned.
   var
-    rawMatches: array[0..MaxSubpatterns * 3 - 1, cint]
+    rtarray = initRtArray[cint]((matches.len+1)*3)
+    rawMatches = rtarray.getRawData
     res = pcre.exec(pattern.h, pattern.e, s, len(s).cint, start.cint, 0'i32,
-      cast[ptr cint](addr(rawMatches)), MaxSubpatterns * 3)
+      cast[ptr cint](rawMatches), (matches.len+1).cint*3)
   if res < 0'i32: return (-1, 0)
   for i in 1..int(res)-1:
     var a = rawMatches[i * 2]
@@ -132,37 +144,27 @@ proc findBounds*(s: string, pattern: Regex,
     else: matches[i-1] = (-1,0)
   return (rawMatches[0].int, rawMatches[1].int - 1)
 
-proc findBounds*(s: string, pattern: Regex, 
+proc findBounds*(s: string, pattern: Regex,
                  start = 0): tuple[first, last: int] =
   ## returns the starting position of `pattern` in `s`. If it does not
   ## match, ``(-1,0)`` is returned.
   var
-    rawMatches: array[0..3 - 1, cint]
+    rtarray = initRtArray[cint](3)
+    rawMatches = rtarray.getRawData
     res = pcre.exec(pattern.h, nil, s, len(s).cint, start.cint, 0'i32,
-      cast[ptr cint](addr(rawMatches)), 3)
+      cast[ptr cint](rawMatches), 3)
   if res < 0'i32: return (int(res), 0)
   return (int(rawMatches[0]), int(rawMatches[1]-1))
-  
+
 proc matchOrFind(s: string, pattern: Regex, start, flags: cint): cint =
-  var rawMatches: array [0..MaxSubpatterns * 3 - 1, cint]
+  var
+    rtarray = initRtArray[cint](3)
+    rawMatches = rtarray.getRawData
   result = pcre.exec(pattern.h, pattern.e, s, len(s).cint, start, flags,
-                    cast[ptr cint](addr(rawMatches)), MaxSubpatterns * 3)
+                    cast[ptr cint](rawMatches), 3)
   if result >= 0'i32:
     result = rawMatches[1] - rawMatches[0]
 
-proc match*(s: string, pattern: Regex, matches: var openArray[string],
-           start = 0): bool =
-  ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and
-  ## the captured substrings in the array ``matches``. If it does not
-  ## match, nothing is written into ``matches`` and ``false`` is
-  ## returned.
-  return matchOrFind(s, pattern, matches, start.cint, 
-                     pcre.ANCHORED) == cint(s.len - start)
-
-proc match*(s: string, pattern: Regex, start = 0): bool =
-  ## returns ``true`` if ``s[start..]`` matches the ``pattern``.
-  return matchOrFind(s, pattern, start.cint, pcre.ANCHORED) == cint(s.len-start)
-
 proc matchLen*(s: string, pattern: Regex, matches: var openArray[string],
               start = 0): int =
   ## the same as ``match``, but it returns the length of the match,
@@ -173,18 +175,31 @@ proc matchLen*(s: string, pattern: Regex, matches: var openArray[string],
 proc matchLen*(s: string, pattern: Regex, start = 0): int =
   ## the same as ``match``, but it returns the length of the match,
   ## if there is no match, -1 is returned. Note that a match length
-  ## of zero can happen. 
+  ## of zero can happen.
   return matchOrFind(s, pattern, start.cint, pcre.ANCHORED)
 
+proc match*(s: string, pattern: Regex, start = 0): bool =
+  ## returns ``true`` if ``s[start..]`` matches the ``pattern``.
+  result = matchLen(s, pattern, start) != -1
+
+proc match*(s: string, pattern: Regex, matches: var openArray[string],
+           start = 0): bool =
+  ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and
+  ## the captured substrings in the array ``matches``. If it does not
+  ## match, nothing is written into ``matches`` and ``false`` is
+  ## returned.
+  result = matchLen(s, pattern, matches, start) != -1
+
 proc find*(s: string, pattern: Regex, matches: var openArray[string],
            start = 0): int =
   ## returns the starting position of ``pattern`` in ``s`` and the captured
   ## substrings in the array ``matches``. If it does not match, nothing
   ## is written into ``matches`` and -1 is returned.
   var
-    rawMatches: array[0..MaxSubpatterns * 3 - 1, cint]
+    rtarray = initRtArray[cint]((matches.len+1)*3)
+    rawMatches = rtarray.getRawData
     res = pcre.exec(pattern.h, pattern.e, s, len(s).cint, start.cint, 0'i32,
-      cast[ptr cint](addr(rawMatches)), MaxSubpatterns * 3)
+      cast[ptr cint](rawMatches), (matches.len+1).cint*3)
   if res < 0'i32: return res
   for i in 1..int(res)-1:
     var a = rawMatches[i * 2]
@@ -197,29 +212,33 @@ proc find*(s: string, pattern: Regex, start = 0): int =
   ## returns the starting position of ``pattern`` in ``s``. If it does not
   ## match, -1 is returned.
   var
-    rawMatches: array[0..3 - 1, cint]
+    rtarray = initRtArray[cint](3)
+    rawMatches = rtarray.getRawData
     res = pcre.exec(pattern.h, nil, s, len(s).cint, start.cint, 0'i32,
-      cast[ptr cint](addr(rawMatches)), 3)
+      cast[ptr cint](rawMatches), 3)
   if res < 0'i32: return res
   return rawMatches[0]
-  
-iterator findAll*(s: string, pattern: Regex, start = 0): string = 
+
+iterator findAll*(s: string, pattern: Regex, start = 0): string =
   ## Yields all matching *substrings* of `s` that match `pattern`.
   ##
   ## Note that since this is an iterator you should not modify the string you
   ## are iterating over: bad things could happen.
-  var i = int32(start)
-  var rawMatches: array[0..MaxSubpatterns * 3 - 1, cint]
+  var
+    i = int32(start)
+    rtarray = initRtArray[cint](3)
+    rawMatches = rtarray.getRawData
   while true:
     let res = pcre.exec(pattern.h, pattern.e, s, len(s).cint, i, 0'i32,
-      cast[ptr cint](addr(rawMatches)), MaxSubpatterns * 3)
+      cast[ptr cint](rawMatches), 3)
     if res < 0'i32: break
     let a = rawMatches[0]
     let b = rawMatches[1]
+    if a == b and a == i: break
     yield substr(s, int(a), int(b)-1)
     i = b
 
-proc findAll*(s: string, pattern: Regex, start = 0): seq[string] = 
+proc findAll*(s: string, pattern: Regex, start = 0): seq[string] =
   ## returns all matching *substrings* of `s` that match `pattern`.
   ## If it does not match, @[] is returned.
   accumulateResult(findAll(s, pattern, start))
@@ -227,13 +246,13 @@ proc findAll*(s: string, pattern: Regex, start = 0): seq[string] =
 when not defined(nimhygiene):
   {.pragma: inject.}
 
-template `=~` *(s: string, pattern: Regex): expr = 
-  ## This calls ``match`` with an implicit declared ``matches`` array that 
-  ## can be used in the scope of the ``=~`` call: 
-  ## 
+template `=~` *(s: string, pattern: Regex): expr =
+  ## This calls ``match`` with an implicit declared ``matches`` array that
+  ## can be used in the scope of the ``=~`` call:
+  ##
   ## .. code-block:: nim
   ##
-  ##   if line =~ re"\s*(\w+)\s*\=\s*(\w+)": 
+  ##   if line =~ re"\s*(\w+)\s*\=\s*(\w+)":
   ##     # matches a key=value pair:
   ##     echo("Key: ", matches[0])
   ##     echo("Value: ", matches[1])
@@ -245,9 +264,9 @@ template `=~` *(s: string, pattern: Regex): expr =
   ##   else:
   ##     echo("syntax error")
   ##
-  bind MaxSubPatterns
+  bind MaxSubpatterns
   when not declaredInScope(matches):
-    var matches {.inject.}: array[0..MaxSubpatterns-1, string]
+    var matches {.inject.}: array[MaxSubpatterns, string]
   match(s, pattern, matches)
 
 # ------------------------- more string handling ------------------------------
@@ -271,11 +290,11 @@ proc endsWith*(s: string, suffix: Regex): bool =
     if matchLen(s, suffix, i) == s.len - i: return true
 
 proc replace*(s: string, sub: Regex, by = ""): string =
-  ## Replaces `sub` in `s` by the string `by`. Captures cannot be 
+  ## Replaces `sub` in `s` by the string `by`. Captures cannot be
   ## accessed in `by`. Examples:
   ##
   ## .. code-block:: nim
-  ##   "var1=key; var2=key2".replace(re"(\w+)'='(\w+)")
+  ##   "var1=key; var2=key2".replace(re"(\w+)=(\w+)")
   ##
   ## Results in:
   ##
@@ -291,13 +310,13 @@ proc replace*(s: string, sub: Regex, by = ""): string =
     add(result, by)
     prev = match.last + 1
   add(result, substr(s, prev))
-  
+
 proc replacef*(s: string, sub: Regex, by: string): string =
   ## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by`
   ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
   ##
   ## .. code-block:: nim
-  ## "var1=key; var2=key2".replacef(re"(\w+)'='(\w+)", "$1<-$2$2")
+  ##   "var1=key; var2=key2".replacef(re"(\w+)=(\w+)", "$1<-$2$2")
   ##
   ## Results in:
   ##
@@ -305,7 +324,7 @@ proc replacef*(s: string, sub: Regex, by: string): string =
   ##
   ## "var1<-keykey; val2<-key2key2"
   result = ""
-  var caps: array[0..MaxSubpatterns-1, string]
+  var caps: array[MaxSubpatterns, string]
   var prev = 0
   while true:
     var match = findBounds(s, sub, caps, prev)
@@ -316,28 +335,14 @@ proc replacef*(s: string, sub: Regex, by: string): string =
     addf(result, by, caps)
     prev = match.last + 1
   add(result, substr(s, prev))
-  when false:
-    result = ""
-    var i = 0
-    var caps: array[0..MaxSubpatterns-1, string]
-    while i < s.len:
-      var x = matchLen(s, sub, caps, i)
-      if x <= 0:
-        add(result, s[i])
-        inc(i)
-      else:
-        addf(result, by, caps)
-        inc(i, x)
-    # substr the rest:
-    add(result, substr(s, i))
-  
+
 proc parallelReplace*(s: string, subs: openArray[
-                      tuple[pattern: Regex, repl: string]]): string = 
+                      tuple[pattern: Regex, repl: string]]): string =
   ## Returns a modified copy of `s` with the substitutions in `subs`
   ## applied in parallel.
   result = ""
   var i = 0
-  var caps: array[0..MaxSubpatterns-1, string]
+  var caps: array[MaxSubpatterns, string]
   while i < s.len:
     block searchSubs:
       for j in 0..high(subs):
@@ -349,8 +354,8 @@ proc parallelReplace*(s: string, subs: openArray[
       add(result, s[i])
       inc(i)
   # copy the rest:
-  add(result, substr(s, i))  
-  
+  add(result, substr(s, i))
+
 proc transformFile*(infile, outfile: string,
                     subs: openArray[tuple[pattern: Regex, repl: string]]) =
   ## reads in the file `infile`, performs a parallel replacement (calls
@@ -358,7 +363,7 @@ proc transformFile*(infile, outfile: string,
   ## error occurs. This is supposed to be used for quick scripting.
   var x = readFile(infile).string
   writeFile(outfile, x.parallelReplace(subs))
-  
+
 iterator split*(s: string, sep: Regex): string =
   ## Splits the string `s` into substrings.
   ##
@@ -372,64 +377,73 @@ iterator split*(s: string, sep: Regex): string =
   ## Results in:
   ##
   ## .. code-block:: nim
+  ##   ""
   ##   "this"
   ##   "is"
   ##   "an"
   ##   "example"
+  ##   ""
   ##
   var
-    first = 0
-    last = 0
+    first = -1
+    last = -1
   while last < len(s):
     var x = matchLen(s, sep, last)
     if x > 0: inc(last, x)
     first = last
+    if x == 0: inc(last)
     while last < len(s):
-      inc(last)
       x = matchLen(s, sep, last)
-      if x > 0: break
-    if first < last:
+      if x >= 0: break
+      inc(last)
+    if first <= last:
       yield substr(s, first, last-1)
 
 proc split*(s: string, sep: Regex): seq[string] =
   ## Splits the string `s` into substrings.
   accumulateResult(split(s, sep))
-  
-proc escapeRe*(s: string): string = 
-  ## escapes `s` so that it is matched verbatim when used as a regular 
+
+proc escapeRe*(s: string): string =
+  ## escapes `s` so that it is matched verbatim when used as a regular
   ## expression.
   result = ""
   for c in items(s):
     case c
     of 'a'..'z', 'A'..'Z', '0'..'9', '_':
       result.add(c)
-    else: 
+    else:
       result.add("\\x")
       result.add(toHex(ord(c), 2))
-  
+
 const ## common regular expressions
-  reIdentifier* = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b"  ## describes an identifier
-  reNatural* = r"\b\d+\b" ## describes a natural number
-  reInteger* = r"\b[-+]?\d+\b" ## describes an integer
-  reHex* = r"\b0[xX][0-9a-fA-F]+\b" ## describes a hexadecimal number
-  reBinary* = r"\b0[bB][01]+\b" ## describes a binary number (example: 0b11101)
-  reOctal* = r"\b0[oO][0-7]+\b" ## describes an octal number (example: 0o777)
-  reFloat* = r"\b[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\b"
+  reIdentifier* {.deprecated.} = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b"
+    ## describes an identifier
+  reNatural* {.deprecated.} = r"\b\d+\b"
+    ## describes a natural number
+  reInteger* {.deprecated.} = r"\b[-+]?\d+\b"
+    ## describes an integer
+  reHex* {.deprecated.} = r"\b0[xX][0-9a-fA-F]+\b"
+    ## describes a hexadecimal number
+  reBinary* {.deprecated.} = r"\b0[bB][01]+\b"
+    ## describes a binary number (example: 0b11101)
+  reOctal* {.deprecated.} = r"\b0[oO][0-7]+\b"
+    ## describes an octal number (example: 0o777)
+  reFloat* {.deprecated.} = r"\b[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\b"
     ## describes a floating point number
-  reEmail* = r"\b[a-zA-Z0-9!#$%&'*+/=?^_`{|}~\-]+(?:\. &" &
-             r"[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)" &
-             r"*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+" &
-             r"(?:[a-zA-Z]{2}|com|org|" &
-             r"net|gov|mil|biz|info|mobi|name|aero|jobs|museum)\b"
+  reEmail* {.deprecated.} = r"\b[a-zA-Z0-9!#$%&'*+/=?^_`{|}~\-]+(?:\. &" &
+                            r"[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@" &
+                            r"(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+" &
+                            r"(?:[a-zA-Z]{2}|com|org|net|gov|mil|biz|" &
+                            r"info|mobi|name|aero|jobs|museum)\b"
     ## describes a common email address
-  reURL* = r"\b(http(s)?|ftp|gopher|telnet|file|notes|ms\-help):" &
-           r"((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-\=\\\.\&]*\b"
+  reURL* {.deprecated.} = r"\b(http(s)?|ftp|gopher|telnet|file|notes|ms-help)" &
+                          r":((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-\=\\\.\&]*\b"
     ## describes an URL
 
 when isMainModule:
   assert match("(a b c)", re"\( .* \)")
   assert match("WHiLe", re("while", {reIgnoreCase}))
-  
+
   assert "0158787".match(re"\d+")
   assert "ABC 0232".match(re"\w+\s+\d+")
   assert "ABC".match(re"\d+ | \w+")
@@ -438,21 +452,21 @@ when isMainModule:
 
   var pattern = re"[a-z0-9]+\s*=\s*[a-z0-9]+"
   assert matchLen("key1=  cal9", pattern) == 11
-  
+
   assert find("_____abc_______", re"abc") == 5
-  
-  var matches: array[0..5, string]
-  if match("abcdefg", re"c(d)ef(g)", matches, 2): 
+
+  var matches: array[6, string]
+  if match("abcdefg", re"c(d)ef(g)", matches, 2):
     assert matches[0] == "d"
     assert matches[1] == "g"
   else:
     assert false
-  
+
   if "abc" =~ re"(a)bcxyz|(\w+)":
     assert matches[1] == "abc"
   else:
     assert false
-  
+
   if "abc" =~ re"(cba)?.*":
     assert matches[0] == nil
   else: assert false
@@ -460,17 +474,37 @@ when isMainModule:
   if "abc" =~ re"().*":
     assert matches[0] == ""
   else: assert false
-    
+
   assert "var1=key; var2=key2".endsWith(re"\w+=\w+")
   assert("var1=key; var2=key2".replacef(re"(\w+)=(\w+)", "$1<-$2$2") ==
          "var1<-keykey; var2<-key2key2")
   assert("var1=key; var2=key2".replace(re"(\w+)=(\w+)", "$1<-$2$2") ==
          "$1<-$2$2; $1<-$2$2")
 
+  var accum: seq[string] = @[]
   for word in split("00232this02939is39an22example111", re"\d+"):
-    writeln(stdout, word)
+    accum.add(word)
+  assert(accum == @["", "this", "is", "an", "example", ""])
+
+  accum = @[]
+  for word in split("AAA :   : BBB", re"\s*:\s*"):
+    accum.add(word)
+  assert(accum == @["AAA", "", "BBB"])
 
   for x in findAll("abcdef", re"^{.}", 3):
     assert x == "d"
+  accum = @[]
   for x in findAll("abcdef", re".", 3):
-    echo x
+    accum.add(x)
+  assert(accum == @["d", "e", "f"])
+
+  assert("XYZ".find(re"^\d*") == 0)
+  assert("XYZ".match(re"^\d*") == true)
+
+  block:
+    var matches: array[16, string]
+    if match("abcdefghijklmnop", re"(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)(m)(n)(o)(p)", matches):
+      for i in 0..matches.high:
+        assert matches[i] == $chr(i + 'a'.ord)
+    else:
+      assert false
diff --git a/lib/impure/ssl.nim b/lib/impure/ssl.nim
index bb7cfc0d3..d318a1979 100644
--- a/lib/impure/ssl.nim
+++ b/lib/impure/ssl.nim
@@ -82,7 +82,7 @@ proc close*(sock: TSecureSocket) =
     ERR_print_errors_fp(stderr)
     raiseOSError(osLastError())
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   var s: TSecureSocket
   echo connect(s, "smtp.gmail.com", 465)
   
diff --git a/lib/js/dom.nim b/lib/js/dom.nim
index 91b260a64..94f4fa29c 100644
--- a/lib/js/dom.nim
+++ b/lib/js/dom.nim
@@ -36,8 +36,11 @@ type
     onsubmit*: proc (event: ref TEvent) {.nimcall.}
     onunload*: proc (event: ref TEvent) {.nimcall.}
 
-  TWindow* {.importc.} = object of TEventHandlers
-    document*: ref TDocument
+    addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent), useCapture: bool = false) {.nimcall.}
+
+  Window* = ref WindowObj
+  WindowObj {.importc.} = object of TEventHandlers
+    document*: Document
     event*: ref TEvent
     history*: ref THistory
     location*: ref TLocation
@@ -65,7 +68,7 @@ type
     confirm*: proc (msg: cstring): bool {.nimcall.}
     disableExternalCapture*: proc () {.nimcall.}
     enableExternalCapture*: proc () {.nimcall.}
-    find*: proc (text: cstring, caseSensitive = false, 
+    find*: proc (text: cstring, caseSensitive = false,
                  backwards = false) {.nimcall.}
     focus*: proc () {.nimcall.}
     forward*: proc () {.nimcall.}
@@ -74,7 +77,7 @@ type
     moveBy*: proc (x, y: int) {.nimcall.}
     moveTo*: proc (x, y: int) {.nimcall.}
     open*: proc (uri, windowname: cstring,
-                 properties: cstring = nil): ref TWindow {.nimcall.}
+                 properties: cstring = nil): Window {.nimcall.}
     print*: proc () {.nimcall.}
     prompt*: proc (text, default: cstring): cstring {.nimcall.}
     releaseEvents*: proc (eventMask: int) {.nimcall.}
@@ -88,9 +91,65 @@ type
     stop*: proc () {.nimcall.}
     frames*: seq[TFrame]
 
-  TFrame* {.importc.} = object of TWindow
+  Frame* = ref FrameObj
+  FrameObj {.importc.} = object of WindowObj
+
+  ClassList* {.importc.} = object of RootObj
+    add*: proc (class: cstring) {.nimcall.}
+    remove*: proc (class: cstring) {.nimcall.}
+    contains*: proc (class: cstring):bool {.nimcall.}
+    toggle*: proc (class: cstring) {.nimcall.}
+
+  TNodeType* = enum
+    ElementNode = 1,
+    AttributeNode,
+    TextNode,
+    CDATANode,
+    EntityRefNode,
+    EntityNode,
+    ProcessingInstructionNode,
+    CommentNode,
+    DocumentNode,
+    DocumentTypeNode,
+    DocumentFragmentNode,
+    NotationNode
+
+  Node* = ref NodeObj
+  NodeObj {.importc.} = object of TEventHandlers
+    attributes*: seq[Node]
+    childNodes*: seq[Node]
+    children*: seq[Node]
+    data*: cstring
+    firstChild*: Node
+    lastChild*: Node
+    nextSibling*: Node
+    nodeName*: cstring
+    nodeType*: TNodeType
+    nodeValue*: cstring
+    parentNode*: Node
+    previousSibling*: Node
+    appendChild*: proc (child: Node) {.nimcall.}
+    appendData*: proc (data: cstring) {.nimcall.}
+    cloneNode*: proc (copyContent: bool): Node {.nimcall.}
+    deleteData*: proc (start, len: int) {.nimcall.}
+    getAttribute*: proc (attr: cstring): cstring {.nimcall.}
+    getAttributeNode*: proc (attr: cstring): Node {.nimcall.}
+    hasChildNodes*: proc (): bool {.nimcall.}
+    innerHTML*: cstring
+    insertBefore*: proc (newNode, before: Node) {.nimcall.}
+    insertData*: proc (position: int, data: cstring) {.nimcall.}
+    removeAttribute*: proc (attr: cstring) {.nimcall.}
+    removeAttributeNode*: proc (attr: Node) {.nimcall.}
+    removeChild*: proc (child: Node) {.nimcall.}
+    replaceChild*: proc (newNode, oldNode: Node) {.nimcall.}
+    replaceData*: proc (start, len: int, text: cstring) {.nimcall.}
+    scrollIntoView*: proc () {.nimcall.}
+    setAttribute*: proc (name, value: cstring) {.nimcall.}
+    setAttributeNode*: proc (attr: Node) {.nimcall.}
+    style*: ref TStyle
 
-  TDocument* {.importc.} = object of TEventHandlers
+  Document* = ref DocumentObj
+  DocumentObj {.importc.} = object of NodeObj
     alinkColor*: cstring
     bgColor*: cstring
     charset*: cstring
@@ -104,12 +163,13 @@ type
     URL*: cstring
     vlinkColor*: cstring
     captureEvents*: proc (eventMask: int) {.nimcall.}
-    createAttribute*: proc (identifier: cstring): ref TNode {.nimcall.}
-    createElement*: proc (identifier: cstring): ref TNode {.nimcall.}
-    createTextNode*: proc (identifier: cstring): ref TNode {.nimcall.}
-    getElementById*: proc (id: cstring): ref TNode {.nimcall.}
-    getElementsByName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
-    getElementsByTagName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
+    createAttribute*: proc (identifier: cstring): Node {.nimcall.}
+    createElement*: proc (identifier: cstring): Element {.nimcall.}
+    createTextNode*: proc (identifier: cstring): Node {.nimcall.}
+    getElementById*: proc (id: cstring): Element {.nimcall.}
+    getElementsByName*: proc (name: cstring): seq[Element] {.nimcall.}
+    getElementsByTagName*: proc (name: cstring): seq[Element] {.nimcall.}
+    getElementsByClassName*: proc (name: cstring): seq[Element] {.nimcall.}
     getSelection*: proc (): cstring {.nimcall.}
     handleEvent*: proc (event: ref TEvent) {.nimcall.}
     open*: proc () {.nimcall.}
@@ -117,24 +177,43 @@ type
     routeEvent*: proc (event: ref TEvent) {.nimcall.}
     write*: proc (text: cstring) {.nimcall.}
     writeln*: proc (text: cstring) {.nimcall.}
-    anchors*: seq[ref TAnchor]
-    forms*: seq[ref TForm]
-    images*: seq[ref TImage]
+    anchors*: seq[AnchorElement]
+    forms*: seq[FormElement]
+    images*: seq[ImageElement]
     applets*: seq[ref TApplet]
-    embeds*: seq[ref TEmbed]
-    links*: seq[ref TLink]
+    embeds*: seq[EmbedElement]
+    links*: seq[LinkElement]
 
-  TLink* {.importc.} = object of RootObj
+  Element* = ref ElementObj
+  ElementObj {.importc.} = object of NodeObj
+    classList*: ref Classlist
+    checked*: bool
+    defaultChecked*: bool
+    defaultValue*: cstring
+    disabled*: bool
+    form*: FormElement
     name*: cstring
+    readOnly*: bool
+    blur*: proc () {.nimcall.}
+    click*: proc () {.nimcall.}
+    focus*: proc () {.nimcall.}
+    handleEvent*: proc (event: ref TEvent) {.nimcall.}
+    select*: proc () {.nimcall.}
+    options*: seq[OptionElement]
+    getElementsByTagName*: proc (name: cstring): seq[Element] {.nimcall.}
+    getElementsByClassName*: proc (name: cstring): seq[Element] {.nimcall.}
+
+  LinkElement* = ref LinkObj
+  LinkObj {.importc.} = object of ElementObj
     target*: cstring
     text*: cstring
     x*: int
     y*: int
 
-  TEmbed* {.importc.} = object of RootObj
+  EmbedElement* = ref EmbedObj
+  EmbedObj {.importc.} = object of ElementObj
     height*: int
     hspace*: int
-    name*: cstring
     src*: cstring
     width*: int
     `type`*: cstring
@@ -142,104 +221,42 @@ type
     play*: proc () {.nimcall.}
     stop*: proc () {.nimcall.}
 
-  TAnchor* {.importc.} = object of RootObj
-    name*: cstring
+  AnchorElement* = ref AnchorObj
+  AnchorObj {.importc.} = object of ElementObj
     text*: cstring
     x*, y*: int
 
   TApplet* {.importc.} = object of RootObj
 
-  TElement* {.importc.} = object of TEventHandlers
-    checked*: bool
-    defaultChecked*: bool
-    defaultValue*: cstring
-    disabled*: bool
-    form*: ref TForm
-    name*: cstring
-    readOnly*: bool
-    `type`*: cstring
-    value*: cstring
-    blur*: proc () {.nimcall.}
-    click*: proc () {.nimcall.}
-    focus*: proc () {.nimcall.}
-    handleEvent*: proc (event: ref TEvent) {.nimcall.}
-    select*: proc () {.nimcall.}
-    options*: seq[ref TOption]
-
-  TOption* {.importc.} = object of RootObj
+  OptionElement* = ref OptionObj
+  OptionObj {.importc.} = object of ElementObj
     defaultSelected*: bool
     selected*: bool
     selectedIndex*: int
     text*: cstring
     value*: cstring
 
-  TForm* {.importc.} = object of TEventHandlers
+  FormElement* = ref FormObj
+  FormObj {.importc.} = object of ElementObj
     action*: cstring
     encoding*: cstring
     `method`*: cstring
-    name*: cstring
     target*: cstring
-    handleEvent*: proc (event: ref TEvent) {.nimcall.}
     reset*: proc () {.nimcall.}
     submit*: proc () {.nimcall.}
-    elements*: seq[ref TElement]
+    elements*: seq[Element]
 
-  TImage* {.importc.} = object of TEventHandlers
+  ImageElement* = ref ImageObj
+  ImageObj {.importc.} = object of ElementObj
     border*: int
     complete*: bool
     height*: int
     hspace*: int
     lowsrc*: cstring
-    name*: cstring
     src*: cstring
     vspace*: int
     width*: int
-    handleEvent*: proc (event: ref TEvent) {.nimcall.}
 
-  TNodeType* = enum
-    ElementNode = 1,
-    AttributeNode,
-    TextNode,
-    CDATANode,
-    EntityRefNode,
-    EntityNode,
-    ProcessingInstructionNode,
-    CommentNode,
-    DocumentNode,
-    DocumentTypeNode,
-    DocumentFragmentNode,
-    NotationNode
-  TNode* {.importc.} = object of RootObj
-    attributes*: seq[ref TNode]
-    childNodes*: seq[ref TNode]
-    data*: cstring
-    firstChild*: ref TNode
-    lastChild*: ref TNode
-    nextSibling*: ref TNode
-    nodeName*: cstring
-    nodeType*: TNodeType
-    nodeValue*: cstring
-    parentNode*: ref TNode
-    previousSibling*: ref TNode
-    appendChild*: proc (child: ref TNode) {.nimcall.}
-    appendData*: proc (data: cstring) {.nimcall.}
-    cloneNode*: proc (copyContent: bool) {.nimcall.}
-    deleteData*: proc (start, len: int) {.nimcall.}
-    getAttribute*: proc (attr: cstring): cstring {.nimcall.}
-    getAttributeNode*: proc (attr: cstring): ref TNode {.nimcall.}
-    getElementsByTagName*: proc (): seq[ref TNode] {.nimcall.}
-    hasChildNodes*: proc (): bool {.nimcall.}
-    innerHTML*: cstring
-    insertBefore*: proc (newNode, before: ref TNode) {.nimcall.}
-    insertData*: proc (position: int, data: cstring) {.nimcall.}
-    removeAttribute*: proc (attr: cstring) {.nimcall.}
-    removeAttributeNode*: proc (attr: ref TNode) {.nimcall.}
-    removeChild*: proc (child: ref TNode) {.nimcall.}
-    replaceChild*: proc (newNode, oldNode: ref TNode) {.nimcall.}
-    replaceData*: proc (start, len: int, text: cstring) {.nimcall.}
-    setAttribute*: proc (name, value: cstring) {.nimcall.}
-    setAttributeNode*: proc (attr: ref TNode) {.nimcall.}
-    style*: ref TStyle
 
   TStyle* {.importc.} = object of RootObj
     background*: cstring
@@ -336,6 +353,7 @@ type
     setAttribute*: proc (attr, value: cstring, caseSensitive=false) {.nimcall.}
 
   TEvent* {.importc.} = object of RootObj
+    target*: Node
     altKey*, ctrlKey*, shiftKey*: bool
     button*: int
     clientX*, clientY*: int
@@ -433,8 +451,8 @@ type
   TInterval* {.importc.} = object of RootObj
 
 var
-  window* {.importc, nodecl.}: ref TWindow
-  document* {.importc, nodecl.}: ref TDocument
+  window* {.importc, nodecl.}: Window
+  document* {.importc, nodecl.}: Document
   navigator* {.importc, nodecl.}: ref TNavigator
   screen* {.importc, nodecl.}: ref TScreen
 
@@ -450,3 +468,18 @@ proc isFinite*(x: BiggestFloat): bool {.importc, nodecl.}
 proc isNaN*(x: BiggestFloat): bool {.importc, nodecl.}
 proc parseFloat*(s: cstring): BiggestFloat {.importc, nodecl.}
 proc parseInt*(s: cstring): int {.importc, nodecl.}
+proc parseInt*(s: cstring, radix: int):int {.importc, nodecl.}
+
+
+type
+  TWindow* {.deprecated.} = WindowObj
+  TFrame* {.deprecated.} = FrameObj
+  TNode* {.deprecated.} = NodeObj
+  TDocument* {.deprecated.} = DocumentObj
+  TElement* {.deprecated.} = ElementObj
+  TLink* {.deprecated.} = LinkObj
+  TEmbed* {.deprecated.} = EmbedObj
+  TAnchor* {.deprecated.} = AnchorObj
+  TOption* {.deprecated.} = OptionObj
+  TForm* {.deprecated.} = FormObj
+  TImage* {.deprecated.} = ImageObj
diff --git a/lib/nimbase.h b/lib/nimbase.h
index ac90081d8..e9dad0bb7 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -1,7 +1,7 @@
 /*
 
             Nim's Runtime Library
-        (c) Copyright 2014 Andreas Rumpf
+        (c) Copyright 2015 Andreas Rumpf
 
     See the file "copying.txt", included in this
     distribution, for details about the copyright.
@@ -67,7 +67,7 @@ __clang__
 #endif
 
 #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
-#  define NIM_THREADVAR __declspec(thread) 
+#  define NIM_THREADVAR __declspec(thread)
 #else
 #  define NIM_THREADVAR __thread
 #endif
@@ -103,7 +103,11 @@ __clang__
 #  define N_FASTCALL_PTR(rettype, name) rettype (__fastcall *name)
 #  define N_SAFECALL_PTR(rettype, name) rettype (__safecall *name)
 
-#  define N_LIB_EXPORT  extern __declspec(dllexport)
+#  ifdef __cplusplus
+#    define N_LIB_EXPORT  extern "C" __declspec(dllexport)
+#  else
+#    define N_LIB_EXPORT  extern __declspec(dllexport)
+#  endif
 #  define N_LIB_IMPORT  extern __declspec(dllimport)
 #else
 #  define N_CDECL(rettype, name) rettype name
@@ -118,7 +122,11 @@ __clang__
 #  define N_FASTCALL_PTR(rettype, name) rettype (*name)
 #  define N_SAFECALL_PTR(rettype, name) rettype (*name)
 
-#  define N_LIB_EXPORT  extern
+#  ifdef __cplusplus
+#    define N_LIB_EXPORT  extern "C"
+#  else
+#    define N_LIB_EXPORT  extern
+#  endif
 #  define N_LIB_IMPORT  extern
 #endif
 
@@ -345,7 +353,7 @@ struct TFrame {
 #define nimln(n, file) \
   F.line = n; F.filename = file;
 
-#define NIM_POSIX_INIT  __attribute__((constructor)) 
+#define NIM_POSIX_INIT  __attribute__((constructor))
 
 #if defined(_MSCVER) && defined(__i386__)
 __declspec(naked) int __fastcall NimXadd(volatile int* pNum, int val) {
@@ -379,8 +387,8 @@ static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); }
 #  define GC_GUARD
 #endif
 
-/* Test to see if nimrod and the C compiler agree on the size of a pointer.
-   On disagreement, your C compiler will say something like: 
+/* Test to see if Nim and the C compiler agree on the size of a pointer.
+   On disagreement, your C compiler will say something like:
    "error: 'assert_numbits' declared as an array with a negative size" */
 typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8 ? 1 : -1];
 #endif
@@ -390,3 +398,14 @@ typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(
 #else
 #  define NIM_EXTERNC
 #endif
+
+/* ---------------- platform specific includes ----------------------- */
+
+/* VxWorks related includes */
+#if defined(__VXWORKS__)
+#  include <sys/types.h>
+#  include <types/vxWind.h>
+#  include <tool/gnu/toolMacros.h>
+#elif defined(__FreeBSD__)
+#  include <sys/types.h>
+#endif
diff --git a/lib/nimrtl.nimrod.cfg b/lib/nimrtl.nim.cfg
index b60de183a..b60de183a 100644
--- a/lib/nimrtl.nimrod.cfg
+++ b/lib/nimrtl.nim.cfg
diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim
index 9c482575a..9485f3912 100644
--- a/lib/packages/docutils/highlite.nim
+++ b/lib/packages/docutils/highlite.nim
@@ -14,14 +14,14 @@
 import
   strutils
 
-type 
-  TTokenClass* = enum 
-    gtEof, gtNone, gtWhitespace, gtDecNumber, gtBinNumber, gtHexNumber, 
-    gtOctNumber, gtFloatNumber, gtIdentifier, gtKeyword, gtStringLit, 
+type
+  TTokenClass* = enum
+    gtEof, gtNone, gtWhitespace, gtDecNumber, gtBinNumber, gtHexNumber,
+    gtOctNumber, gtFloatNumber, gtIdentifier, gtKeyword, gtStringLit,
     gtLongStringLit, gtCharLit, gtEscapeSequence, # escape sequence like \xff
-    gtOperator, gtPunctuation, gtComment, gtLongComment, gtRegularExpression, 
-    gtTagStart, gtTagEnd, gtKey, gtValue, gtRawData, gtAssembler, 
-    gtPreprocessor, gtDirective, gtCommand, gtRule, gtHyperlink, gtLabel, 
+    gtOperator, gtPunctuation, gtComment, gtLongComment, gtRegularExpression,
+    gtTagStart, gtTagEnd, gtKey, gtValue, gtRawData, gtAssembler,
+    gtPreprocessor, gtDirective, gtCommand, gtRule, gtHyperlink, gtLabel,
     gtReference, gtOther
   TGeneralTokenizer* = object of RootObj
     kind*: TTokenClass
@@ -30,39 +30,40 @@ type
     pos: int
     state: TTokenClass
 
-  TSourceLanguage* = enum 
+  TSourceLanguage* = enum
     langNone, langNim, langNimrod, langCpp, langCsharp, langC, langJava
 
-const 
+const
   sourceLanguageToStr*: array[TSourceLanguage, string] = ["none",
     "Nim", "Nimrod", "C++", "C#", "C", "Java"]
-  tokenClassToStr*: array[TTokenClass, string] = ["Eof", "None", "Whitespace", 
-    "DecNumber", "BinNumber", "HexNumber", "OctNumber", "FloatNumber", 
-    "Identifier", "Keyword", "StringLit", "LongStringLit", "CharLit", 
-    "EscapeSequence", "Operator", "Punctuation", "Comment", "LongComment", 
-    "RegularExpression", "TagStart", "TagEnd", "Key", "Value", "RawData", 
-    "Assembler", "Preprocessor", "Directive", "Command", "Rule", "Hyperlink", 
+  tokenClassToStr*: array[TTokenClass, string] = ["Eof", "None", "Whitespace",
+    "DecNumber", "BinNumber", "HexNumber", "OctNumber", "FloatNumber",
+    "Identifier", "Keyword", "StringLit", "LongStringLit", "CharLit",
+    "EscapeSequence", "Operator", "Punctuation", "Comment", "LongComment",
+    "RegularExpression", "TagStart", "TagEnd", "Key", "Value", "RawData",
+    "Assembler", "Preprocessor", "Directive", "Command", "Rule", "Hyperlink",
     "Label", "Reference", "Other"]
 
   # The following list comes from doc/keywords.txt, make sure it is
   # synchronized with this array by running the module itself as a test case.
   nimKeywords = ["addr", "and", "as", "asm", "atomic", "bind", "block",
-    "break", "case", "cast", "const", "continue", "converter",
+    "break", "case", "cast", "concept", "const", "continue", "converter",
     "defer", "discard", "distinct", "div", "do",
     "elif", "else", "end", "enum", "except", "export",
-    "finally", "for", "from", "generic", "if", "import", "in", "include",
+    "finally", "for", "from", "func",
+    "generic", "if", "import", "in", "include",
     "interface", "is", "isnot", "iterator", "let", "macro", "method",
     "mixin", "mod", "nil", "not", "notin", "object", "of", "or", "out", "proc",
     "ptr", "raise", "ref", "return", "shl", "shr", "static",
     "template", "try", "tuple", "type", "using", "var", "when", "while", "with",
     "without", "xor", "yield"]
 
-proc getSourceLanguage*(name: string): TSourceLanguage = 
-  for i in countup(succ(low(TSourceLanguage)), high(TSourceLanguage)): 
-    if cmpIgnoreStyle(name, sourceLanguageToStr[i]) == 0: 
+proc getSourceLanguage*(name: string): TSourceLanguage =
+  for i in countup(succ(low(TSourceLanguage)), high(TSourceLanguage)):
+    if cmpIgnoreStyle(name, sourceLanguageToStr[i]) == 0:
       return i
   result = langNone
-  
+
 proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: cstring) =
   g.buf = buf
   g.kind = low(TTokenClass)
@@ -73,52 +74,52 @@ proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: cstring) =
   while g.buf[pos] in {' ', '\x09'..'\x0D'}: inc(pos)
   g.pos = pos
 
-proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: string) = 
+proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: string) =
   initGeneralTokenizer(g, cstring(buf))
 
-proc deinitGeneralTokenizer*(g: var TGeneralTokenizer) = 
+proc deinitGeneralTokenizer*(g: var TGeneralTokenizer) =
   discard
 
-proc nimGetKeyword(id: string): TTokenClass = 
+proc nimGetKeyword(id: string): TTokenClass =
   for k in nimKeywords:
     if cmpIgnoreStyle(id, k) == 0: return gtKeyword
   result = gtIdentifier
   when false:
     var i = getIdent(id)
     if (i.id >= ord(tokKeywordLow) - ord(tkSymbol)) and
-        (i.id <= ord(tokKeywordHigh) - ord(tkSymbol)): 
+        (i.id <= ord(tokKeywordHigh) - ord(tkSymbol)):
       result = gtKeyword
-    else: 
+    else:
       result = gtIdentifier
-  
-proc nimNumberPostfix(g: var TGeneralTokenizer, position: int): int = 
+
+proc nimNumberPostfix(g: var TGeneralTokenizer, position: int): int =
   var pos = position
-  if g.buf[pos] == '\'': 
+  if g.buf[pos] == '\'':
     inc(pos)
     case g.buf[pos]
-    of 'f', 'F': 
+    of 'f', 'F':
       g.kind = gtFloatNumber
       inc(pos)
       if g.buf[pos] in {'0'..'9'}: inc(pos)
       if g.buf[pos] in {'0'..'9'}: inc(pos)
-    of 'i', 'I': 
+    of 'i', 'I':
       inc(pos)
       if g.buf[pos] in {'0'..'9'}: inc(pos)
       if g.buf[pos] in {'0'..'9'}: inc(pos)
-    else: 
+    else:
       discard
   result = pos
 
-proc nimNumber(g: var TGeneralTokenizer, position: int): int = 
+proc nimNumber(g: var TGeneralTokenizer, position: int): int =
   const decChars = {'0'..'9', '_'}
   var pos = position
   g.kind = gtDecNumber
   while g.buf[pos] in decChars: inc(pos)
-  if g.buf[pos] == '.': 
+  if g.buf[pos] == '.':
     g.kind = gtFloatNumber
     inc(pos)
     while g.buf[pos] in decChars: inc(pos)
-  if g.buf[pos] in {'e', 'E'}: 
+  if g.buf[pos] in {'e', 'E'}:
     g.kind = gtFloatNumber
     inc(pos)
     if g.buf[pos] in {'+', '-'}: inc(pos)
@@ -126,150 +127,150 @@ proc nimNumber(g: var TGeneralTokenizer, position: int): int =
   result = nimNumberPostfix(g, pos)
 
 const
-  OpChars  = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.', 
+  OpChars  = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
               '|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'}
 
-proc nimNextToken(g: var TGeneralTokenizer) = 
-  const 
+proc nimNextToken(g: var TGeneralTokenizer) =
+  const
     hexChars = {'0'..'9', 'A'..'F', 'a'..'f', '_'}
     octChars = {'0'..'7', '_'}
     binChars = {'0'..'1', '_'}
     SymChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
   var pos = g.pos
   g.start = g.pos
-  if g.state == gtStringLit: 
+  if g.state == gtStringLit:
     g.kind = gtStringLit
-    while true: 
+    while true:
       case g.buf[pos]
-      of '\\': 
+      of '\\':
         g.kind = gtEscapeSequence
         inc(pos)
         case g.buf[pos]
-        of 'x', 'X': 
+        of 'x', 'X':
           inc(pos)
           if g.buf[pos] in hexChars: inc(pos)
           if g.buf[pos] in hexChars: inc(pos)
-        of '0'..'9': 
+        of '0'..'9':
           while g.buf[pos] in {'0'..'9'}: inc(pos)
-        of '\0': 
+        of '\0':
           g.state = gtNone
         else: inc(pos)
-        break 
-      of '\0', '\x0D', '\x0A': 
+        break
+      of '\0', '\x0D', '\x0A':
         g.state = gtNone
-        break 
-      of '\"': 
+        break
+      of '\"':
         inc(pos)
         g.state = gtNone
-        break 
+        break
       else: inc(pos)
-  else: 
+  else:
     case g.buf[pos]
-    of ' ', '\x09'..'\x0D': 
+    of ' ', '\x09'..'\x0D':
       g.kind = gtWhitespace
       while g.buf[pos] in {' ', '\x09'..'\x0D'}: inc(pos)
-    of '#': 
+    of '#':
       g.kind = gtComment
       while not (g.buf[pos] in {'\0', '\x0A', '\x0D'}): inc(pos)
-    of 'a'..'z', 'A'..'Z', '_', '\x80'..'\xFF': 
+    of 'a'..'z', 'A'..'Z', '_', '\x80'..'\xFF':
       var id = ""
-      while g.buf[pos] in SymChars + {'_'}: 
+      while g.buf[pos] in SymChars + {'_'}:
         add(id, g.buf[pos])
         inc(pos)
-      if (g.buf[pos] == '\"'): 
-        if (g.buf[pos + 1] == '\"') and (g.buf[pos + 2] == '\"'): 
+      if (g.buf[pos] == '\"'):
+        if (g.buf[pos + 1] == '\"') and (g.buf[pos + 2] == '\"'):
           inc(pos, 3)
           g.kind = gtLongStringLit
-          while true: 
+          while true:
             case g.buf[pos]
-            of '\0': 
-              break 
-            of '\"': 
+            of '\0':
+              break
+            of '\"':
               inc(pos)
-              if g.buf[pos] == '\"' and g.buf[pos+1] == '\"' and 
-                  g.buf[pos+2] != '\"': 
+              if g.buf[pos] == '\"' and g.buf[pos+1] == '\"' and
+                  g.buf[pos+2] != '\"':
                 inc(pos, 2)
-                break 
+                break
             else: inc(pos)
-        else: 
+        else:
           g.kind = gtRawData
           inc(pos)
-          while not (g.buf[pos] in {'\0', '\x0A', '\x0D'}): 
+          while not (g.buf[pos] in {'\0', '\x0A', '\x0D'}):
             if g.buf[pos] == '"' and g.buf[pos+1] != '"': break
             inc(pos)
           if g.buf[pos] == '\"': inc(pos)
-      else: 
+      else:
         g.kind = nimGetKeyword(id)
-    of '0': 
+    of '0':
       inc(pos)
       case g.buf[pos]
-      of 'b', 'B': 
+      of 'b', 'B':
         inc(pos)
         while g.buf[pos] in binChars: inc(pos)
         pos = nimNumberPostfix(g, pos)
-      of 'x', 'X': 
+      of 'x', 'X':
         inc(pos)
         while g.buf[pos] in hexChars: inc(pos)
         pos = nimNumberPostfix(g, pos)
-      of 'o', 'O': 
+      of 'o', 'O':
         inc(pos)
         while g.buf[pos] in octChars: inc(pos)
         pos = nimNumberPostfix(g, pos)
       else: pos = nimNumber(g, pos)
-    of '1'..'9': 
+    of '1'..'9':
       pos = nimNumber(g, pos)
-    of '\'': 
+    of '\'':
       inc(pos)
       g.kind = gtCharLit
-      while true: 
+      while true:
         case g.buf[pos]
-        of '\0', '\x0D', '\x0A': 
-          break 
-        of '\'': 
+        of '\0', '\x0D', '\x0A':
+          break
+        of '\'':
           inc(pos)
-          break 
-        of '\\': 
+          break
+        of '\\':
           inc(pos, 2)
         else: inc(pos)
-    of '\"': 
+    of '\"':
       inc(pos)
-      if (g.buf[pos] == '\"') and (g.buf[pos + 1] == '\"'): 
+      if (g.buf[pos] == '\"') and (g.buf[pos + 1] == '\"'):
         inc(pos, 2)
         g.kind = gtLongStringLit
-        while true: 
+        while true:
           case g.buf[pos]
-          of '\0': 
-            break 
-          of '\"': 
+          of '\0':
+            break
+          of '\"':
             inc(pos)
-            if g.buf[pos] == '\"' and g.buf[pos+1] == '\"' and 
-                g.buf[pos+2] != '\"': 
+            if g.buf[pos] == '\"' and g.buf[pos+1] == '\"' and
+                g.buf[pos+2] != '\"':
               inc(pos, 2)
-              break 
+              break
           else: inc(pos)
-      else: 
+      else:
         g.kind = gtStringLit
-        while true: 
+        while true:
           case g.buf[pos]
-          of '\0', '\x0D', '\x0A': 
-            break 
-          of '\"': 
+          of '\0', '\x0D', '\x0A':
+            break
+          of '\"':
             inc(pos)
-            break 
-          of '\\': 
+            break
+          of '\\':
             g.state = g.kind
-            break 
+            break
           else: inc(pos)
-    of '(', ')', '[', ']', '{', '}', '`', ':', ',', ';': 
+    of '(', ')', '[', ']', '{', '}', '`', ':', ',', ';':
       inc(pos)
       g.kind = gtPunctuation
-    of '\0': 
+    of '\0':
       g.kind = gtEof
-    else: 
-      if g.buf[pos] in OpChars: 
+    else:
+      if g.buf[pos] in OpChars:
         g.kind = gtOperator
         while g.buf[pos] in OpChars: inc(pos)
-      else: 
+      else:
         inc(pos)
         g.kind = gtNone
   g.length = pos - g.pos
@@ -277,211 +278,211 @@ proc nimNextToken(g: var TGeneralTokenizer) =
     assert false, "nimNextToken: produced an empty token"
   g.pos = pos
 
-proc generalNumber(g: var TGeneralTokenizer, position: int): int = 
+proc generalNumber(g: var TGeneralTokenizer, position: int): int =
   const decChars = {'0'..'9'}
   var pos = position
   g.kind = gtDecNumber
   while g.buf[pos] in decChars: inc(pos)
-  if g.buf[pos] == '.': 
+  if g.buf[pos] == '.':
     g.kind = gtFloatNumber
     inc(pos)
     while g.buf[pos] in decChars: inc(pos)
-  if g.buf[pos] in {'e', 'E'}: 
+  if g.buf[pos] in {'e', 'E'}:
     g.kind = gtFloatNumber
     inc(pos)
     if g.buf[pos] in {'+', '-'}: inc(pos)
     while g.buf[pos] in decChars: inc(pos)
   result = pos
 
-proc generalStrLit(g: var TGeneralTokenizer, position: int): int = 
-  const 
+proc generalStrLit(g: var TGeneralTokenizer, position: int): int =
+  const
     decChars = {'0'..'9'}
     hexChars = {'0'..'9', 'A'..'F', 'a'..'f'}
   var pos = position
   g.kind = gtStringLit
   var c = g.buf[pos]
   inc(pos)                    # skip " or '
-  while true: 
+  while true:
     case g.buf[pos]
-    of '\0': 
-      break 
-    of '\\': 
+    of '\0':
+      break
+    of '\\':
       inc(pos)
       case g.buf[pos]
-      of '\0': 
-        break 
-      of '0'..'9': 
+      of '\0':
+        break
+      of '0'..'9':
         while g.buf[pos] in decChars: inc(pos)
-      of 'x', 'X': 
+      of 'x', 'X':
         inc(pos)
         if g.buf[pos] in hexChars: inc(pos)
         if g.buf[pos] in hexChars: inc(pos)
       else: inc(pos, 2)
-    else: 
-      if g.buf[pos] == c: 
+    else:
+      if g.buf[pos] == c:
         inc(pos)
-        break 
-      else: 
+        break
+      else:
         inc(pos)
   result = pos
 
-proc isKeyword(x: openArray[string], y: string): int = 
+proc isKeyword(x: openArray[string], y: string): int =
   var a = 0
   var b = len(x) - 1
-  while a <= b: 
+  while a <= b:
     var mid = (a + b) div 2
     var c = cmp(x[mid], y)
-    if c < 0: 
+    if c < 0:
       a = mid + 1
-    elif c > 0: 
+    elif c > 0:
       b = mid - 1
-    else: 
+    else:
       return mid
   result = - 1
 
-proc isKeywordIgnoreCase(x: openArray[string], y: string): int = 
+proc isKeywordIgnoreCase(x: openArray[string], y: string): int =
   var a = 0
   var b = len(x) - 1
-  while a <= b: 
+  while a <= b:
     var mid = (a + b) div 2
     var c = cmpIgnoreCase(x[mid], y)
-    if c < 0: 
+    if c < 0:
       a = mid + 1
-    elif c > 0: 
+    elif c > 0:
       b = mid - 1
-    else: 
+    else:
       return mid
   result = - 1
 
-type 
-  TTokenizerFlag = enum 
+type
+  TTokenizerFlag = enum
     hasPreprocessor, hasNestedComments
   TTokenizerFlags = set[TTokenizerFlag]
 
-proc clikeNextToken(g: var TGeneralTokenizer, keywords: openArray[string], 
-                    flags: TTokenizerFlags) = 
-  const 
+proc clikeNextToken(g: var TGeneralTokenizer, keywords: openArray[string],
+                    flags: TTokenizerFlags) =
+  const
     hexChars = {'0'..'9', 'A'..'F', 'a'..'f'}
     octChars = {'0'..'7'}
     binChars = {'0'..'1'}
     symChars = {'A'..'Z', 'a'..'z', '0'..'9', '_', '\x80'..'\xFF'}
   var pos = g.pos
   g.start = g.pos
-  if g.state == gtStringLit: 
+  if g.state == gtStringLit:
     g.kind = gtStringLit
-    while true: 
+    while true:
       case g.buf[pos]
-      of '\\': 
+      of '\\':
         g.kind = gtEscapeSequence
         inc(pos)
         case g.buf[pos]
-        of 'x', 'X': 
+        of 'x', 'X':
           inc(pos)
           if g.buf[pos] in hexChars: inc(pos)
           if g.buf[pos] in hexChars: inc(pos)
-        of '0'..'9': 
+        of '0'..'9':
           while g.buf[pos] in {'0'..'9'}: inc(pos)
-        of '\0': 
+        of '\0':
           g.state = gtNone
         else: inc(pos)
-        break 
-      of '\0', '\x0D', '\x0A': 
+        break
+      of '\0', '\x0D', '\x0A':
         g.state = gtNone
-        break 
-      of '\"': 
+        break
+      of '\"':
         inc(pos)
         g.state = gtNone
-        break 
+        break
       else: inc(pos)
-  else: 
+  else:
     case g.buf[pos]
-    of ' ', '\x09'..'\x0D': 
+    of ' ', '\x09'..'\x0D':
       g.kind = gtWhitespace
       while g.buf[pos] in {' ', '\x09'..'\x0D'}: inc(pos)
-    of '/': 
+    of '/':
       inc(pos)
-      if g.buf[pos] == '/': 
+      if g.buf[pos] == '/':
         g.kind = gtComment
         while not (g.buf[pos] in {'\0', '\x0A', '\x0D'}): inc(pos)
-      elif g.buf[pos] == '*': 
+      elif g.buf[pos] == '*':
         g.kind = gtLongComment
         var nested = 0
         inc(pos)
-        while true: 
+        while true:
           case g.buf[pos]
-          of '*': 
+          of '*':
             inc(pos)
-            if g.buf[pos] == '/': 
+            if g.buf[pos] == '/':
               inc(pos)
-              if nested == 0: break 
-          of '/': 
+              if nested == 0: break
+          of '/':
             inc(pos)
-            if g.buf[pos] == '*': 
+            if g.buf[pos] == '*':
               inc(pos)
               if hasNestedComments in flags: inc(nested)
-          of '\0': 
-            break 
+          of '\0':
+            break
           else: inc(pos)
-    of '#': 
+    of '#':
       inc(pos)
-      if hasPreprocessor in flags: 
+      if hasPreprocessor in flags:
         g.kind = gtPreprocessor
         while g.buf[pos] in {' ', '\t'}: inc(pos)
         while g.buf[pos] in symChars: inc(pos)
-      else: 
+      else:
         g.kind = gtOperator
-    of 'a'..'z', 'A'..'Z', '_', '\x80'..'\xFF': 
+    of 'a'..'z', 'A'..'Z', '_', '\x80'..'\xFF':
       var id = ""
-      while g.buf[pos] in symChars: 
+      while g.buf[pos] in symChars:
         add(id, g.buf[pos])
         inc(pos)
       if isKeyword(keywords, id) >= 0: g.kind = gtKeyword
       else: g.kind = gtIdentifier
-    of '0': 
+    of '0':
       inc(pos)
       case g.buf[pos]
-      of 'b', 'B': 
+      of 'b', 'B':
         inc(pos)
         while g.buf[pos] in binChars: inc(pos)
         if g.buf[pos] in {'A'..'Z', 'a'..'z'}: inc(pos)
-      of 'x', 'X': 
+      of 'x', 'X':
         inc(pos)
         while g.buf[pos] in hexChars: inc(pos)
         if g.buf[pos] in {'A'..'Z', 'a'..'z'}: inc(pos)
-      of '0'..'7': 
+      of '0'..'7':
         inc(pos)
         while g.buf[pos] in octChars: inc(pos)
         if g.buf[pos] in {'A'..'Z', 'a'..'z'}: inc(pos)
-      else: 
+      else:
         pos = generalNumber(g, pos)
         if g.buf[pos] in {'A'..'Z', 'a'..'z'}: inc(pos)
-    of '1'..'9': 
+    of '1'..'9':
       pos = generalNumber(g, pos)
       if g.buf[pos] in {'A'..'Z', 'a'..'z'}: inc(pos)
-    of '\'': 
+    of '\'':
       pos = generalStrLit(g, pos)
       g.kind = gtCharLit
-    of '\"': 
+    of '\"':
       inc(pos)
       g.kind = gtStringLit
-      while true: 
+      while true:
         case g.buf[pos]
-        of '\0': 
-          break 
-        of '\"': 
+        of '\0':
+          break
+        of '\"':
           inc(pos)
-          break 
-        of '\\': 
+          break
+        of '\\':
           g.state = g.kind
-          break 
+          break
         else: inc(pos)
-    of '(', ')', '[', ']', '{', '}', ':', ',', ';', '.': 
+    of '(', ')', '[', ']', '{', '}', ':', ',', ';', '.':
       inc(pos)
       g.kind = gtPunctuation
-    of '\0': 
+    of '\0':
       g.kind = gtEof
-    else: 
-      if g.buf[pos] in OpChars: 
+    else:
+      if g.buf[pos] in OpChars:
         g.kind = gtOperator
         while g.buf[pos] in OpChars: inc(pos)
       else:
@@ -492,55 +493,55 @@ proc clikeNextToken(g: var TGeneralTokenizer, keywords: openArray[string],
     assert false, "clikeNextToken: produced an empty token"
   g.pos = pos
 
-proc cNextToken(g: var TGeneralTokenizer) = 
-  const 
-    keywords: array[0..36, 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", "unsigned", "void", 
+proc cNextToken(g: var TGeneralTokenizer) =
+  const
+    keywords: array[0..36, 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", "unsigned", "void",
       "volatile", "while"]
   clikeNextToken(g, keywords, {hasPreprocessor})
 
-proc cppNextToken(g: var TGeneralTokenizer) = 
-  const 
-    keywords: array[0..47, 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", "short", "signed", "sizeof", "static", 
-      "struct", "switch", "template", "this", "throw", "try", "typedef", 
+proc cppNextToken(g: var TGeneralTokenizer) =
+  const
+    keywords: array[0..47, 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", "short", "signed", "sizeof", "static",
+      "struct", "switch", "template", "this", "throw", "try", "typedef",
       "union", "unsigned", "virtual", "void", "volatile", "while"]
   clikeNextToken(g, keywords, {hasPreprocessor})
 
-proc csharpNextToken(g: var TGeneralTokenizer) = 
-  const 
-    keywords: array[0..76, 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", 
+proc csharpNextToken(g: var TGeneralTokenizer) =
+  const
+    keywords: array[0..76, 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"]
   clikeNextToken(g, keywords, {hasPreprocessor})
 
-proc javaNextToken(g: var TGeneralTokenizer) = 
-  const 
-    keywords: array[0..52, 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", "synchronized", "this", "throw", "throws", "transient", "true", 
+proc javaNextToken(g: var TGeneralTokenizer) =
+  const
+    keywords: array[0..52, 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", "synchronized", "this", "throw", "throws", "transient", "true",
       "try", "void", "volatile", "while"]
   clikeNextToken(g, keywords, {})
 
-proc getNextToken*(g: var TGeneralTokenizer, lang: TSourceLanguage) = 
+proc getNextToken*(g: var TGeneralTokenizer, lang: TSourceLanguage) =
   case lang
   of langNone: assert false
   of langNim, langNimrod: nimNextToken(g)
@@ -548,15 +549,17 @@ proc getNextToken*(g: var TGeneralTokenizer, lang: TSourceLanguage) =
   of langCsharp: csharpNextToken(g)
   of langC: cNextToken(g)
   of langJava: javaNextToken(g)
-  
+
 when isMainModule:
   var keywords: seq[string]
   # Try to work running in both the subdir or at the root.
   for filename in ["doc/keywords.txt", "../../../doc/keywords.txt"]:
-    except: echo filename, " not found"
-    let input = string(readFile(filename))
-    keywords = input.split()
-    break
+    try:
+      let input = string(readFile(filename))
+      keywords = input.split()
+      break
+    except:
+      echo filename, " not found"
   doAssert(not keywords.isNil, "Couldn't read any keywords.txt file!")
   doAssert keywords.len == nimKeywords.len, "No matching lengths"
   for i in 0..keywords.len-1:
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
index 95d49bad7..2ee94ba13 100644
--- a/lib/packages/docutils/rst.nim
+++ b/lib/packages/docutils/rst.nim
@@ -11,25 +11,25 @@
 ## subset is implemented. Some features of the `markdown`:idx: wiki syntax are
 ## also supported.
 
-import 
+import
   os, strutils, rstast
 
 type
-  TRstParseOption* = enum     ## options for the RST parser 
+  TRstParseOption* = enum     ## options for the RST parser
     roSkipPounds,             ## skip ``#`` at line beginning (documentation
                               ## embedded in Nim comments)
     roSupportSmilies,         ## make the RST parser support smilies like ``:)``
     roSupportRawDirective,    ## support the ``raw`` directive (don't support
                               ## it for sandboxing)
     roSupportMarkdown         ## support additional features of markdown
-  
+
   TRstParseOptions* = set[TRstParseOption]
-  
+
   TMsgClass* = enum
-    mcHint = "Hint", 
-    mcWarning = "Warning", 
+    mcHint = "Hint",
+    mcWarning = "Warning",
     mcError = "Error"
-  
+
   TMsgKind* = enum          ## the possible messages
     meCannotOpenFile,
     meExpected,
@@ -41,20 +41,20 @@ type
     mwUnknownSubstitution,
     mwUnsupportedLanguage,
     mwUnsupportedField
-  
+
   TMsgHandler* = proc (filename: string, line, col: int, msgKind: TMsgKind,
                        arg: string) {.nimcall.} ## what to do in case of an error
   TFindFileHandler* = proc (filename: string): string {.nimcall.}
 
 const
   messages: array [TMsgKind, string] = [
-    meCannotOpenFile: "cannot open '$1'", 
+    meCannotOpenFile: "cannot open '$1'",
     meExpected: "'$1' expected",
     meGridTableNotImplemented: "grid table is not implemented",
-    meNewSectionExpected: "new section expected", 
+    meNewSectionExpected: "new section expected",
     meGeneralParseError: "general parse error",
     meInvalidDirective: "invalid directive: '$1'",
-    mwRedefinitionOfLabel: "redefinition of label '$1'", 
+    mwRedefinitionOfLabel: "redefinition of label '$1'",
     mwUnknownSubstitution: "unknown substitution '$1'",
     mwUnsupportedLanguage: "language '$1' not supported",
     mwUnsupportedField: "field '$1' not supported"
@@ -67,7 +67,7 @@ proc getArgument*(n: PRstNode): string
 
 # ----------------------------- scanner part --------------------------------
 
-const 
+const
   SymChars: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
   SmileyStartChars: set[char] = {':', ';', '8'}
   Smilies = {
@@ -111,14 +111,14 @@ const
   }
 
 type
-  TTokType = enum 
+  TTokType = enum
     tkEof, tkIndent, tkWhite, tkWord, tkAdornment, tkPunct, tkOther
   TToken = object             # a RST token
     kind*: TTokType           # the type of the token
     ival*: int                # the indentation or parsed integer value
     symbol*: string           # the parsed symbol as string
     line*, col*: int          # line and column of the token
-  
+
   TTokenSeq = seq[TToken]
   TLexer = object of RootObj
     buf*: cstring
@@ -127,61 +127,61 @@ type
     skipPounds*: bool
 
 
-proc getThing(L: var TLexer, tok: var TToken, s: set[char]) = 
+proc getThing(L: var TLexer, tok: var TToken, s: set[char]) =
   tok.kind = tkWord
   tok.line = L.line
   tok.col = L.col
   var pos = L.bufpos
-  while true: 
+  while true:
     add(tok.symbol, L.buf[pos])
     inc(pos)
-    if L.buf[pos] notin s: break 
+    if L.buf[pos] notin s: break
   inc(L.col, pos - L.bufpos)
   L.bufpos = pos
 
-proc getAdornment(L: var TLexer, tok: var TToken) = 
+proc getAdornment(L: var TLexer, tok: var TToken) =
   tok.kind = tkAdornment
   tok.line = L.line
   tok.col = L.col
   var pos = L.bufpos
   var c = L.buf[pos]
-  while true: 
+  while true:
     add(tok.symbol, L.buf[pos])
     inc(pos)
-    if L.buf[pos] != c: break 
+    if L.buf[pos] != c: break
   inc(L.col, pos - L.bufpos)
   L.bufpos = pos
 
-proc getIndentAux(L: var TLexer, start: int): int = 
+proc getIndentAux(L: var TLexer, start: int): int =
   var pos = start
-  var buf = L.buf                 
+  var buf = L.buf
   # skip the newline (but include it in the token!)
-  if buf[pos] == '\x0D': 
+  if buf[pos] == '\x0D':
     if buf[pos + 1] == '\x0A': inc(pos, 2)
     else: inc(pos)
-  elif buf[pos] == '\x0A': 
+  elif buf[pos] == '\x0A':
     inc(pos)
-  if L.skipPounds: 
+  if L.skipPounds:
     if buf[pos] == '#': inc(pos)
     if buf[pos] == '#': inc(pos)
-  while true: 
+  while true:
     case buf[pos]
-    of ' ', '\x0B', '\x0C': 
+    of ' ', '\x0B', '\x0C':
       inc(pos)
       inc(result)
-    of '\x09': 
+    of '\x09':
       inc(pos)
       result = result - (result mod 8) + 8
-    else: 
+    else:
       break                   # EndOfFile also leaves the loop
-  if buf[pos] == '\0': 
+  if buf[pos] == '\0':
     result = 0
-  elif (buf[pos] == '\x0A') or (buf[pos] == '\x0D'): 
+  elif (buf[pos] == '\x0A') or (buf[pos] == '\x0D'):
     # look at the next line for proper indentation:
     result = getIndentAux(L, pos)
   L.bufpos = pos              # no need to set back buf
-  
-proc getIndent(L: var TLexer, tok: var TToken) = 
+
+proc getIndent(L: var TLexer, tok: var TToken) =
   tok.col = 0
   tok.kind = tkIndent         # skip the newline (but include it in the token!)
   tok.ival = getIndentAux(L, L.bufpos)
@@ -189,87 +189,87 @@ proc getIndent(L: var TLexer, tok: var TToken) =
   tok.line = L.line
   L.col = tok.ival
   tok.ival = max(tok.ival - L.baseIndent, 0)
-  tok.symbol = "\n" & repeatChar(tok.ival)
+  tok.symbol = "\n" & spaces(tok.ival)
 
-proc rawGetTok(L: var TLexer, tok: var TToken) = 
+proc rawGetTok(L: var TLexer, tok: var TToken) =
   tok.symbol = ""
   tok.ival = 0
   var c = L.buf[L.bufpos]
   case c
-  of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '0'..'9': 
+  of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '0'..'9':
     getThing(L, tok, SymChars)
-  of ' ', '\x09', '\x0B', '\x0C': 
+  of ' ', '\x09', '\x0B', '\x0C':
     getThing(L, tok, {' ', '\x09'})
     tok.kind = tkWhite
-    if L.buf[L.bufpos] in {'\x0D', '\x0A'}: 
+    if L.buf[L.bufpos] in {'\x0D', '\x0A'}:
       rawGetTok(L, tok)       # ignore spaces before \n
-  of '\x0D', '\x0A': 
+  of '\x0D', '\x0A':
     getIndent(L, tok)
-  of '!', '\"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', 
+  of '!', '\"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.',
      '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{',
-     '|', '}', '~': 
+     '|', '}', '~':
     getAdornment(L, tok)
     if len(tok.symbol) <= 3: tok.kind = tkPunct
-  else: 
+  else:
     tok.line = L.line
     tok.col = L.col
-    if c == '\0': 
+    if c == '\0':
       tok.kind = tkEof
-    else: 
+    else:
       tok.kind = tkOther
       add(tok.symbol, c)
       inc(L.bufpos)
       inc(L.col)
   tok.col = max(tok.col - L.baseIndent, 0)
 
-proc getTokens(buffer: string, skipPounds: bool, tokens: var TTokenSeq): int = 
+proc getTokens(buffer: string, skipPounds: bool, tokens: var TTokenSeq): int =
   var L: TLexer
   var length = len(tokens)
   L.buf = cstring(buffer)
   L.line = 0                  # skip UTF-8 BOM
-  if (L.buf[0] == '\xEF') and (L.buf[1] == '\xBB') and (L.buf[2] == '\xBF'): 
+  if (L.buf[0] == '\xEF') and (L.buf[1] == '\xBB') and (L.buf[2] == '\xBF'):
     inc(L.bufpos, 3)
   L.skipPounds = skipPounds
-  if skipPounds: 
-    if L.buf[L.bufpos] == '#': 
+  if skipPounds:
+    if L.buf[L.bufpos] == '#':
       inc(L.bufpos)
       inc(result)
-    if L.buf[L.bufpos] == '#': 
+    if L.buf[L.bufpos] == '#':
       inc(L.bufpos)
       inc(result)
     L.baseIndent = 0
-    while L.buf[L.bufpos] == ' ': 
+    while L.buf[L.bufpos] == ' ':
       inc(L.bufpos)
       inc(L.baseIndent)
       inc(result)
-  while true: 
+  while true:
     inc(length)
     setLen(tokens, length)
     rawGetTok(L, tokens[length - 1])
-    if tokens[length - 1].kind == tkEof: break 
-  if tokens[0].kind == tkWhite: 
+    if tokens[length - 1].kind == tkEof: break
+  if tokens[0].kind == tkWhite:
     # BUGFIX
     tokens[0].ival = len(tokens[0].symbol)
     tokens[0].kind = tkIndent
 
 type
   TLevelMap = array[char, int]
-  TSubstitution = object 
+  TSubstitution = object
     key*: string
     value*: PRstNode
 
-  TSharedState = object 
+  TSharedState = object
     options: TRstParseOptions   # parsing options
     uLevel, oLevel: int         # counters for the section levels
     subs: seq[TSubstitution]    # substitutions
     refs: seq[TSubstitution]    # references
     underlineToLevel: TLevelMap # Saves for each possible title adornment
                                 # character its level in the
-                                # current document. 
+                                # current document.
                                 # This is for single underline adornments.
-    overlineToLevel: TLevelMap  # Saves for each possible title adornment 
+    overlineToLevel: TLevelMap  # Saves for each possible title adornment
                                 # character its level in the current
-                                # document. 
+                                # document.
                                 # This is for over-underline adornments.
     msgHandler: TMsgHandler     # How to handle errors.
     findFile: TFindFileHandler  # How to find files.
@@ -293,7 +293,7 @@ proc whichMsgClass*(k: TMsgKind): TMsgClass =
   of 'w', 'W': result = mcWarning
   of 'h', 'H': result = mcHint
   else: assert false, "msgkind does not fit naming scheme"
-  
+
 proc defaultMsgHandler*(filename: string, line, col: int, msgkind: TMsgKind,
                         arg: string) {.procvar.} =
   let mc = msgkind.whichMsgClass
@@ -302,31 +302,31 @@ proc defaultMsgHandler*(filename: string, line, col: int, msgkind: TMsgKind,
   if mc == mcError: raise newException(EParseError, message)
   else: writeln(stdout, message)
 
-proc defaultFindFile*(filename: string): string {.procvar.} = 
+proc defaultFindFile*(filename: string): string {.procvar.} =
   if existsFile(filename): result = filename
   else: result = ""
 
 proc newSharedState(options: TRstParseOptions,
                     findFile: TFindFileHandler,
-                    msgHandler: TMsgHandler): PSharedState = 
+                    msgHandler: TMsgHandler): PSharedState =
   new(result)
   result.subs = @[]
   result.refs = @[]
   result.options = options
   result.msgHandler = if not isNil(msgHandler): msgHandler else: defaultMsgHandler
   result.findFile = if not isNil(findFile): findFile else: defaultFindFile
-  
-proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string) = 
-  p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line, 
+
+proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string) =
+  p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line,
                              p.col + p.tok[p.idx].col, msgKind, arg)
 
-proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string, line, col: int) = 
+proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string, line, col: int) =
   p.s.msgHandler(p.filename, p.line + line,
                              p.col + col, msgKind, arg)
 
-proc rstMessage(p: TRstParser, msgKind: TMsgKind) = 
-  p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line, 
-                             p.col + p.tok[p.idx].col, msgKind, 
+proc rstMessage(p: TRstParser, msgKind: TMsgKind) =
+  p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line,
+                             p.col + p.tok[p.idx].col, msgKind,
                              p.tok[p.idx].symbol)
 
 when false:
@@ -334,16 +334,16 @@ when false:
     assert p.indentStack[0] == 0
     for i in 1 .. high(p.indentStack): assert p.indentStack[i] < 1_000
 
-proc currInd(p: TRstParser): int = 
+proc currInd(p: TRstParser): int =
   result = p.indentStack[high(p.indentStack)]
 
-proc pushInd(p: var TRstParser, ind: int) = 
+proc pushInd(p: var TRstParser, ind: int) =
   add(p.indentStack, ind)
 
 proc popInd(p: var TRstParser) =
   if len(p.indentStack) > 1: setLen(p.indentStack, len(p.indentStack) - 1)
-  
-proc initParser(p: var TRstParser, sharedState: PSharedState) = 
+
+proc initParser(p: var TRstParser, sharedState: PSharedState) =
   p.indentStack = @[0]
   p.tok = @[]
   p.idx = 0
@@ -353,150 +353,150 @@ proc initParser(p: var TRstParser, sharedState: PSharedState) =
   p.line = 1
   p.s = sharedState
 
-proc addNodesAux(n: PRstNode, result: var string) = 
-  if n.kind == rnLeaf: 
+proc addNodesAux(n: PRstNode, result: var string) =
+  if n.kind == rnLeaf:
     add(result, n.text)
-  else: 
+  else:
     for i in countup(0, len(n) - 1): addNodesAux(n.sons[i], result)
-  
-proc addNodes(n: PRstNode): string = 
+
+proc addNodes(n: PRstNode): string =
   result = ""
   addNodesAux(n, result)
 
-proc rstnodeToRefnameAux(n: PRstNode, r: var string, b: var bool) = 
-  if n.kind == rnLeaf: 
-    for i in countup(0, len(n.text) - 1): 
+proc rstnodeToRefnameAux(n: PRstNode, r: var string, b: var bool) =
+  if n.kind == rnLeaf:
+    for i in countup(0, len(n.text) - 1):
       case n.text[i]
-      of '0'..'9': 
-        if b: 
+      of '0'..'9':
+        if b:
           add(r, '-')
           b = false
         if len(r) == 0: add(r, 'Z')
         add(r, n.text[i])
-      of 'a'..'z': 
-        if b: 
+      of 'a'..'z':
+        if b:
           add(r, '-')
           b = false
         add(r, n.text[i])
-      of 'A'..'Z': 
-        if b: 
+      of 'A'..'Z':
+        if b:
           add(r, '-')
           b = false
         add(r, chr(ord(n.text[i]) - ord('A') + ord('a')))
-      else: 
+      else:
         if (len(r) > 0): b = true
-  else: 
+  else:
     for i in countup(0, len(n) - 1): rstnodeToRefnameAux(n.sons[i], r, b)
-  
-proc rstnodeToRefname(n: PRstNode): string = 
+
+proc rstnodeToRefname(n: PRstNode): string =
   result = ""
   var b = false
   rstnodeToRefnameAux(n, result, b)
 
-proc findSub(p: var TRstParser, n: PRstNode): int = 
-  var key = addNodes(n)           
+proc findSub(p: var TRstParser, n: PRstNode): int =
+  var key = addNodes(n)
   # the spec says: if no exact match, try one without case distinction:
-  for i in countup(0, high(p.s.subs)): 
-    if key == p.s.subs[i].key: 
+  for i in countup(0, high(p.s.subs)):
+    if key == p.s.subs[i].key:
       return i
-  for i in countup(0, high(p.s.subs)): 
-    if cmpIgnoreStyle(key, p.s.subs[i].key) == 0: 
+  for i in countup(0, high(p.s.subs)):
+    if cmpIgnoreStyle(key, p.s.subs[i].key) == 0:
       return i
   result = -1
 
-proc setSub(p: var TRstParser, key: string, value: PRstNode) = 
+proc setSub(p: var TRstParser, key: string, value: PRstNode) =
   var length = len(p.s.subs)
-  for i in countup(0, length - 1): 
-    if key == p.s.subs[i].key: 
+  for i in countup(0, length - 1):
+    if key == p.s.subs[i].key:
       p.s.subs[i].value = value
-      return 
+      return
   setLen(p.s.subs, length + 1)
   p.s.subs[length].key = key
   p.s.subs[length].value = value
 
-proc setRef(p: var TRstParser, key: string, value: PRstNode) = 
+proc setRef(p: var TRstParser, key: string, value: PRstNode) =
   var length = len(p.s.refs)
-  for i in countup(0, length - 1): 
+  for i in countup(0, length - 1):
     if key == p.s.refs[i].key:
       if p.s.refs[i].value.addNodes != value.addNodes:
         rstMessage(p, mwRedefinitionOfLabel, key)
 
       p.s.refs[i].value = value
-      return 
+      return
   setLen(p.s.refs, length + 1)
   p.s.refs[length].key = key
   p.s.refs[length].value = value
 
-proc findRef(p: var TRstParser, key: string): PRstNode = 
-  for i in countup(0, high(p.s.refs)): 
-    if key == p.s.refs[i].key: 
+proc findRef(p: var TRstParser, key: string): PRstNode =
+  for i in countup(0, high(p.s.refs)):
+    if key == p.s.refs[i].key:
       return p.s.refs[i].value
 
-proc newLeaf(p: var TRstParser): PRstNode = 
+proc newLeaf(p: var TRstParser): PRstNode =
   result = newRstNode(rnLeaf, p.tok[p.idx].symbol)
 
-proc getReferenceName(p: var TRstParser, endStr: string): PRstNode = 
+proc getReferenceName(p: var TRstParser, endStr: string): PRstNode =
   var res = newRstNode(rnInner)
-  while true: 
+  while true:
     case p.tok[p.idx].kind
-    of tkWord, tkOther, tkWhite: 
+    of tkWord, tkOther, tkWhite:
       add(res, newLeaf(p))
-    of tkPunct: 
-      if p.tok[p.idx].symbol == endStr: 
+    of tkPunct:
+      if p.tok[p.idx].symbol == endStr:
         inc(p.idx)
-        break 
-      else: 
+        break
+      else:
         add(res, newLeaf(p))
-    else: 
+    else:
       rstMessage(p, meExpected, endStr)
-      break 
+      break
     inc(p.idx)
   result = res
 
-proc untilEol(p: var TRstParser): PRstNode = 
+proc untilEol(p: var TRstParser): PRstNode =
   result = newRstNode(rnInner)
-  while not (p.tok[p.idx].kind in {tkIndent, tkEof}): 
+  while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
     add(result, newLeaf(p))
     inc(p.idx)
 
-proc expect(p: var TRstParser, tok: string) = 
+proc expect(p: var TRstParser, tok: string) =
   if p.tok[p.idx].symbol == tok: inc(p.idx)
   else: rstMessage(p, meExpected, tok)
-  
-proc isInlineMarkupEnd(p: TRstParser, markup: string): bool = 
+
+proc isInlineMarkupEnd(p: TRstParser, markup: string): bool =
   result = p.tok[p.idx].symbol == markup
-  if not result: 
+  if not result:
     return                    # Rule 3:
   result = not (p.tok[p.idx - 1].kind in {tkIndent, tkWhite})
-  if not result: 
+  if not result:
     return                    # Rule 4:
   result = (p.tok[p.idx + 1].kind in {tkIndent, tkWhite, tkEof}) or
       (p.tok[p.idx + 1].symbol[0] in
-      {'\'', '\"', ')', ']', '}', '>', '-', '/', '\\', ':', '.', ',', ';', '!', 
+      {'\'', '\"', ')', ']', '}', '>', '-', '/', '\\', ':', '.', ',', ';', '!',
        '?', '_'})
-  if not result: 
+  if not result:
     return                    # Rule 7:
-  if p.idx > 0: 
-    if (markup != "``") and (p.tok[p.idx - 1].symbol == "\\"): 
+  if p.idx > 0:
+    if (markup != "``") and (p.tok[p.idx - 1].symbol == "\\"):
       result = false
 
-proc isInlineMarkupStart(p: TRstParser, markup: string): bool = 
+proc isInlineMarkupStart(p: TRstParser, markup: string): bool =
   var d: char
   result = p.tok[p.idx].symbol == markup
-  if not result: 
+  if not result:
     return                    # Rule 1:
   result = (p.idx == 0) or (p.tok[p.idx - 1].kind in {tkIndent, tkWhite}) or
       (p.tok[p.idx - 1].symbol[0] in
       {'\'', '\"', '(', '[', '{', '<', '-', '/', ':', '_'})
-  if not result: 
+  if not result:
     return                    # Rule 2:
   result = not (p.tok[p.idx + 1].kind in {tkIndent, tkWhite, tkEof})
-  if not result: 
+  if not result:
     return                    # Rule 5 & 7:
-  if p.idx > 0: 
-    if p.tok[p.idx - 1].symbol == "\\": 
+  if p.idx > 0:
+    if p.tok[p.idx - 1].symbol == "\\":
       result = false
-    else: 
+    else:
       var c = p.tok[p.idx - 1].symbol[0]
       case c
       of '\'', '\"': d = c
@@ -507,7 +507,7 @@ proc isInlineMarkupStart(p: TRstParser, markup: string): bool =
       else: d = '\0'
       if d != '\0': result = p.tok[p.idx + 1].symbol[0] != d
 
-proc match(p: TRstParser, start: int, expr: string): bool = 
+proc match(p: TRstParser, start: int, expr: string): bool =
   # regular expressions are:
   # special char     exact match
   # 'w'              tkWord
@@ -521,7 +521,7 @@ proc match(p: TRstParser, start: int, expr: string): bool =
   var i = 0
   var j = start
   var last = len(expr) - 1
-  while i <= last: 
+  while i <= last:
     case expr[i]
     of 'w': result = p.tok[j].kind == tkWord
     of ' ': result = p.tok[j].kind == tkWhite
@@ -531,75 +531,75 @@ proc match(p: TRstParser, start: int, expr: string): bool =
     of 'o': result = p.tok[j].kind == tkOther
     of 'T': result = true
     of 'E': result = p.tok[j].kind in {tkEof, tkWhite, tkIndent}
-    of 'e': 
+    of 'e':
       result = (p.tok[j].kind == tkWord) or (p.tok[j].symbol == "#")
-      if result: 
+      if result:
         case p.tok[j].symbol[0]
         of 'a'..'z', 'A'..'Z': result = len(p.tok[j].symbol) == 1
         of '0'..'9': result = allCharsInSet(p.tok[j].symbol, {'0'..'9'})
         else: discard
-    else: 
+    else:
       var c = expr[i]
       var length = 0
-      while (i <= last) and (expr[i] == c): 
+      while (i <= last) and (expr[i] == c):
         inc(i)
         inc(length)
       dec(i)
       result = (p.tok[j].kind in {tkPunct, tkAdornment}) and
           (len(p.tok[j].symbol) == length) and (p.tok[j].symbol[0] == c)
-    if not result: return 
+    if not result: return
     inc(j)
     inc(i)
   result = true
-  
-proc fixupEmbeddedRef(n, a, b: PRstNode) = 
+
+proc fixupEmbeddedRef(n, a, b: PRstNode) =
   var sep = - 1
-  for i in countdown(len(n) - 2, 0): 
-    if n.sons[i].text == "<": 
+  for i in countdown(len(n) - 2, 0):
+    if n.sons[i].text == "<":
       sep = i
-      break 
+      break
   var incr = if (sep > 0) and (n.sons[sep - 1].text[0] == ' '): 2 else: 1
   for i in countup(0, sep - incr): add(a, n.sons[i])
   for i in countup(sep + 1, len(n) - 2): add(b, n.sons[i])
-  
-proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode = 
+
+proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
   result = n
-  if isInlineMarkupEnd(p, "_"): 
+  if isInlineMarkupEnd(p, "_") or isInlineMarkupEnd(p, "__"):
     inc(p.idx)
     if p.tok[p.idx-2].symbol == "`" and p.tok[p.idx-3].symbol == ">":
       var a = newRstNode(rnInner)
       var b = newRstNode(rnInner)
       fixupEmbeddedRef(n, a, b)
-      if len(a) == 0: 
+      if len(a) == 0:
         result = newRstNode(rnStandaloneHyperlink)
         add(result, b)
-      else: 
+      else:
         result = newRstNode(rnHyperlink)
         add(result, a)
         add(result, b)
         setRef(p, rstnodeToRefname(a), b)
-    elif n.kind == rnInterpretedText: 
+    elif n.kind == rnInterpretedText:
       n.kind = rnRef
-    else: 
+    else:
       result = newRstNode(rnRef)
       add(result, n)
-  elif match(p, p.idx, ":w:"): 
+  elif match(p, p.idx, ":w:"):
     # a role:
-    if p.tok[p.idx + 1].symbol == "idx": 
+    if p.tok[p.idx + 1].symbol == "idx":
       n.kind = rnIdx
-    elif p.tok[p.idx + 1].symbol == "literal": 
+    elif p.tok[p.idx + 1].symbol == "literal":
       n.kind = rnInlineLiteral
-    elif p.tok[p.idx + 1].symbol == "strong": 
+    elif p.tok[p.idx + 1].symbol == "strong":
       n.kind = rnStrongEmphasis
-    elif p.tok[p.idx + 1].symbol == "emphasis": 
+    elif p.tok[p.idx + 1].symbol == "emphasis":
       n.kind = rnEmphasis
     elif (p.tok[p.idx + 1].symbol == "sub") or
-        (p.tok[p.idx + 1].symbol == "subscript"): 
+        (p.tok[p.idx + 1].symbol == "subscript"):
       n.kind = rnSub
     elif (p.tok[p.idx + 1].symbol == "sup") or
-        (p.tok[p.idx + 1].symbol == "supscript"): 
+        (p.tok[p.idx + 1].symbol == "supscript"):
       n.kind = rnSup
-    else: 
+    else:
       result = newRstNode(rnGeneralRole)
       n.kind = rnInner
       add(result, n)
@@ -614,7 +614,7 @@ proc matchVerbatim(p: TRstParser, start: int, expr: string): int =
     inc j, p.tok[result].symbol.len
     inc result
   if j < expr.len: result = 0
-  
+
 proc parseSmiley(p: var TRstParser): PRstNode =
   if p.tok[p.idx].symbol[0] notin SmileyStartChars: return
   for key, val in items(Smilies):
@@ -636,17 +636,17 @@ proc isUrl(p: TRstParser, i: int): bool =
     (p.tok[i+3].kind == tkWord) and
     (p.tok[i].symbol in ["http", "https", "ftp", "telnet", "file"])
 
-proc parseUrl(p: var TRstParser, father: PRstNode) = 
+proc parseUrl(p: var TRstParser, father: PRstNode) =
   #if p.tok[p.idx].symbol[strStart] == '<':
   if isUrl(p, p.idx):
     var n = newRstNode(rnStandaloneHyperlink)
-    while true: 
+    while true:
       case p.tok[p.idx].kind
       of tkWord, tkAdornment, tkOther: discard
-      of tkPunct: 
+      of tkPunct:
         if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}:
           break
-      else: break 
+      else: break
       add(n, newLeaf(p))
       inc(p.idx)
     add(father, n)
@@ -655,13 +655,13 @@ proc parseUrl(p: var TRstParser, father: PRstNode) =
     inc(p.idx)
     if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
     add(father, n)
-  
-proc parseBackslash(p: var TRstParser, father: PRstNode) = 
+
+proc parseBackslash(p: var TRstParser, father: PRstNode) =
   assert(p.tok[p.idx].kind == tkPunct)
-  if p.tok[p.idx].symbol == "\\\\": 
+  if p.tok[p.idx].symbol == "\\\\":
     add(father, newRstNode(rnLeaf, "\\"))
     inc(p.idx)
-  elif p.tok[p.idx].symbol == "\\": 
+  elif p.tok[p.idx].symbol == "\\":
     # XXX: Unicode?
     inc(p.idx)
     if p.tok[p.idx].kind != tkWhite: add(father, newLeaf(p))
@@ -674,13 +674,13 @@ when false:
   proc parseAdhoc(p: var TRstParser, father: PRstNode, verbatim: bool) =
     if not verbatim and isURL(p, p.idx):
       var n = newRstNode(rnStandaloneHyperlink)
-      while true: 
+      while true:
         case p.tok[p.idx].kind
         of tkWord, tkAdornment, tkOther: nil
-        of tkPunct: 
+        of tkPunct:
           if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}:
             break
-        else: break 
+        else: break
         add(n, newLeaf(p))
         inc(p.idx)
       add(father, n)
@@ -694,33 +694,33 @@ when false:
       if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
       add(father, n)
 
-proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string, 
-                interpretBackslash: bool) = 
+proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string,
+                interpretBackslash: bool) =
   let
     line = p.tok[p.idx].line
     col = p.tok[p.idx].col
   inc p.idx
-  while true: 
+  while true:
     case p.tok[p.idx].kind
-    of tkPunct: 
-      if isInlineMarkupEnd(p, postfix): 
+    of tkPunct:
+      if isInlineMarkupEnd(p, postfix):
         inc(p.idx)
-        break 
-      elif interpretBackslash: 
+        break
+      elif interpretBackslash:
         parseBackslash(p, father)
-      else: 
+      else:
         add(father, newLeaf(p))
         inc(p.idx)
-    of tkAdornment, tkWord, tkOther: 
+    of tkAdornment, tkWord, tkOther:
       add(father, newLeaf(p))
       inc(p.idx)
-    of tkIndent: 
+    of tkIndent:
       add(father, newRstNode(rnLeaf, " "))
       inc(p.idx)
-      if p.tok[p.idx].kind == tkIndent: 
+      if p.tok[p.idx].kind == tkIndent:
         rstMessage(p, meExpected, postfix, line, col)
-        break 
-    of tkWhite: 
+        break
+    of tkWhite:
       add(father, newRstNode(rnLeaf, " "))
       inc(p.idx)
     else: rstMessage(p, meExpected, postfix, line, col)
@@ -753,20 +753,20 @@ proc parseMarkdownCodeblock(p: var TRstParser): PRstNode =
   result = newRstNode(rnCodeBlock)
   add(result, args)
   add(result, nil)
-  add(result, lb)  
-  
-proc parseInline(p: var TRstParser, father: PRstNode) = 
+  add(result, lb)
+
+proc parseInline(p: var TRstParser, father: PRstNode) =
   case p.tok[p.idx].kind
-  of tkPunct: 
+  of tkPunct:
     if isInlineMarkupStart(p, "***"):
       var n = newRstNode(rnTripleEmphasis)
       parseUntil(p, n, "***", true)
       add(father, n)
-    elif isInlineMarkupStart(p, "**"): 
+    elif isInlineMarkupStart(p, "**"):
       var n = newRstNode(rnStrongEmphasis)
       parseUntil(p, n, "**", true)
       add(father, n)
-    elif isInlineMarkupStart(p, "*"): 
+    elif isInlineMarkupStart(p, "*"):
       var n = newRstNode(rnEmphasis)
       parseUntil(p, n, "*", true)
       add(father, n)
@@ -777,12 +777,12 @@ proc parseInline(p: var TRstParser, father: PRstNode) =
       var n = newRstNode(rnInlineLiteral)
       parseUntil(p, n, "``", false)
       add(father, n)
-    elif isInlineMarkupStart(p, "`"): 
+    elif isInlineMarkupStart(p, "`"):
       var n = newRstNode(rnInterpretedText)
       parseUntil(p, n, "`", true)
       n = parsePostfix(p, n)
       add(father, n)
-    elif isInlineMarkupStart(p, "|"): 
+    elif isInlineMarkupStart(p, "|"):
       var n = newRstNode(rnSubstitutionReferences)
       parseUntil(p, n, "|", false)
       add(father, n)
@@ -800,7 +800,7 @@ proc parseInline(p: var TRstParser, father: PRstNode) =
         add(father, n)
         return
     parseUrl(p, father)
-  of tkAdornment, tkOther, tkWhite: 
+  of tkAdornment, tkOther, tkWhite:
     if roSupportSmilies in p.s.options:
       let n = parseSmiley(p)
       if n != nil:
@@ -809,75 +809,75 @@ proc parseInline(p: var TRstParser, father: PRstNode) =
     add(father, newLeaf(p))
     inc(p.idx)
   else: discard
-  
-proc getDirective(p: var TRstParser): string = 
-  if p.tok[p.idx].kind == tkWhite and p.tok[p.idx+1].kind == tkWord: 
+
+proc getDirective(p: var TRstParser): string =
+  if p.tok[p.idx].kind == tkWhite and p.tok[p.idx+1].kind == tkWord:
     var j = p.idx
     inc(p.idx)
     result = p.tok[p.idx].symbol
     inc(p.idx)
-    while p.tok[p.idx].kind in {tkWord, tkPunct, tkAdornment, tkOther}: 
-      if p.tok[p.idx].symbol == "::": break 
+    while p.tok[p.idx].kind in {tkWord, tkPunct, tkAdornment, tkOther}:
+      if p.tok[p.idx].symbol == "::": break
       add(result, p.tok[p.idx].symbol)
       inc(p.idx)
     if p.tok[p.idx].kind == tkWhite: inc(p.idx)
-    if p.tok[p.idx].symbol == "::": 
+    if p.tok[p.idx].symbol == "::":
       inc(p.idx)
       if (p.tok[p.idx].kind == tkWhite): inc(p.idx)
-    else: 
+    else:
       p.idx = j               # set back
       result = ""             # error
-  else: 
+  else:
     result = ""
-  
-proc parseComment(p: var TRstParser): PRstNode = 
+
+proc parseComment(p: var TRstParser): PRstNode =
   case p.tok[p.idx].kind
-  of tkIndent, tkEof: 
-    if p.tok[p.idx].kind != tkEof and p.tok[p.idx + 1].kind == tkIndent: 
+  of tkIndent, tkEof:
+    if p.tok[p.idx].kind != tkEof and p.tok[p.idx + 1].kind == tkIndent:
       inc(p.idx)              # empty comment
-    else: 
+    else:
       var indent = p.tok[p.idx].ival
-      while true: 
+      while true:
         case p.tok[p.idx].kind
-        of tkEof: 
-          break 
-        of tkIndent: 
-          if (p.tok[p.idx].ival < indent): break 
-        else: 
+        of tkEof:
+          break
+        of tkIndent:
+          if (p.tok[p.idx].ival < indent): break
+        else:
           discard
         inc(p.idx)
   else:
     while p.tok[p.idx].kind notin {tkIndent, tkEof}: inc(p.idx)
   result = nil
 
-type 
+type
   TDirKind = enum             # must be ordered alphabetically!
     dkNone, dkAuthor, dkAuthors, dkCode, dkCodeBlock, dkContainer, dkContents,
     dkFigure, dkImage, dkInclude, dkIndex, dkRaw, dkTitle
 
-const 
+const
   DirIds: array[0..12, string] = ["", "author", "authors", "code",
     "code-block", "container", "contents", "figure", "image", "include",
     "index", "raw", "title"]
 
-proc getDirKind(s: string): TDirKind = 
+proc getDirKind(s: string): TDirKind =
   let i = find(DirIds, s)
   if i >= 0: result = TDirKind(i)
   else: result = dkNone
-  
-proc parseLine(p: var TRstParser, father: PRstNode) = 
-  while true: 
+
+proc parseLine(p: var TRstParser, father: PRstNode) =
+  while true:
     case p.tok[p.idx].kind
     of tkWhite, tkWord, tkOther, tkPunct: parseInline(p, father)
-    else: break 
+    else: break
 
-proc parseUntilNewline(p: var TRstParser, father: PRstNode) = 
-  while true: 
+proc parseUntilNewline(p: var TRstParser, father: PRstNode) =
+  while true:
     case p.tok[p.idx].kind
     of tkWhite, tkWord, tkAdornment, tkOther, tkPunct: parseInline(p, father)
     of tkEof, tkIndent: break
-  
-proc parseSection(p: var TRstParser, result: PRstNode)
+
+proc parseSection(p: var TRstParser, result: PRstNode) {.gcsafe.}
 proc parseField(p: var TRstParser): PRstNode =
   ## Returns a parsed rnField node.
   ##
@@ -888,9 +888,9 @@ proc parseField(p: var TRstParser): PRstNode =
   parseUntil(p, fieldname, ":", false)
   var fieldbody = newRstNode(rnFieldBody)
   if p.tok[p.idx].kind != tkIndent: parseLine(p, fieldbody)
-  if p.tok[p.idx].kind == tkIndent: 
+  if p.tok[p.idx].kind == tkIndent:
     var indent = p.tok[p.idx].ival
-    if indent > col: 
+    if indent > col:
       pushInd(p, indent)
       parseSection(p, fieldbody)
       popInd(p)
@@ -909,14 +909,14 @@ proc parseFields(p: var TRstParser): PRstNode =
     var col = if atStart: p.tok[p.idx].col else: p.tok[p.idx].ival
     result = newRstNode(rnFieldList)
     if not atStart: inc(p.idx)
-    while true: 
+    while true:
       add(result, parseField(p))
       if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
-          (p.tok[p.idx + 1].symbol == ":"): 
+          (p.tok[p.idx + 1].symbol == ":"):
         inc(p.idx)
-      else: 
-        break 
-  
+      else:
+        break
+
 proc getFieldValue*(n: PRstNode): string =
   ## Returns the value of a specific ``rnField`` node.
   ##
@@ -929,122 +929,122 @@ proc getFieldValue*(n: PRstNode): string =
   assert n.sons[1].kind == rnFieldBody
   result = addNodes(n.sons[1]).strip
 
-proc getFieldValue(n: PRstNode, fieldname: string): string = 
+proc getFieldValue(n: PRstNode, fieldname: string): string =
   result = ""
-  if n.sons[1] == nil: return 
-  if (n.sons[1].kind != rnFieldList): 
+  if n.sons[1] == nil: return
+  if (n.sons[1].kind != rnFieldList):
     #InternalError("getFieldValue (2): " & $n.sons[1].kind)
     # We don't like internal errors here anymore as that would break the forum!
     return
-  for i in countup(0, len(n.sons[1]) - 1): 
+  for i in countup(0, len(n.sons[1]) - 1):
     var f = n.sons[1].sons[i]
-    if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) == 0: 
+    if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) == 0:
       result = addNodes(f.sons[1])
       if result == "": result = "\x01\x01" # indicates that the field exists
-      return 
+      return
 
-proc getArgument(n: PRstNode): string = 
+proc getArgument(n: PRstNode): string =
   if n.sons[0] == nil: result = ""
   else: result = addNodes(n.sons[0])
-  
-proc parseDotDot(p: var TRstParser): PRstNode
-proc parseLiteralBlock(p: var TRstParser): PRstNode = 
+
+proc parseDotDot(p: var TRstParser): PRstNode {.gcsafe.}
+proc parseLiteralBlock(p: var TRstParser): PRstNode =
   result = newRstNode(rnLiteralBlock)
   var n = newRstNode(rnLeaf, "")
-  if p.tok[p.idx].kind == tkIndent: 
+  if p.tok[p.idx].kind == tkIndent:
     var indent = p.tok[p.idx].ival
     inc(p.idx)
-    while true: 
+    while true:
       case p.tok[p.idx].kind
-      of tkEof: 
-        break 
-      of tkIndent: 
-        if (p.tok[p.idx].ival < indent): 
-          break 
-        else: 
+      of tkEof:
+        break
+      of tkIndent:
+        if (p.tok[p.idx].ival < indent):
+          break
+        else:
           add(n.text, "\n")
-          add(n.text, repeatChar(p.tok[p.idx].ival - indent))
+          add(n.text, spaces(p.tok[p.idx].ival - indent))
           inc(p.idx)
-      else: 
+      else:
         add(n.text, p.tok[p.idx].symbol)
         inc(p.idx)
-  else: 
-    while not (p.tok[p.idx].kind in {tkIndent, tkEof}): 
+  else:
+    while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
       add(n.text, p.tok[p.idx].symbol)
       inc(p.idx)
   add(result, n)
 
-proc getLevel(map: var TLevelMap, lvl: var int, c: char): int = 
-  if map[c] == 0: 
+proc getLevel(map: var TLevelMap, lvl: var int, c: char): int =
+  if map[c] == 0:
     inc(lvl)
     map[c] = lvl
   result = map[c]
 
-proc tokenAfterNewline(p: TRstParser): int = 
+proc tokenAfterNewline(p: TRstParser): int =
   result = p.idx
-  while true: 
+  while true:
     case p.tok[result].kind
-    of tkEof: 
-      break 
-    of tkIndent: 
+    of tkEof:
+      break
+    of tkIndent:
       inc(result)
-      break 
+      break
     else: inc(result)
-  
-proc isLineBlock(p: TRstParser): bool = 
+
+proc isLineBlock(p: TRstParser): bool =
   var j = tokenAfterNewline(p)
   result = (p.tok[p.idx].col == p.tok[j].col) and (p.tok[j].symbol == "|") or
       (p.tok[j].col > p.tok[p.idx].col)
 
-proc predNL(p: TRstParser): bool = 
+proc predNL(p: TRstParser): bool =
   result = true
   if p.idx > 0:
     result = p.tok[p.idx-1].kind == tkIndent and
         p.tok[p.idx-1].ival == currInd(p)
-  
-proc isDefList(p: TRstParser): bool = 
+
+proc isDefList(p: TRstParser): bool =
   var j = tokenAfterNewline(p)
   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 != "::")
 
-proc isOptionList(p: TRstParser): bool = 
+proc isOptionList(p: TRstParser): bool =
   result = match(p, p.idx, "-w") or match(p, p.idx, "--w") or
            match(p, p.idx, "/w") or match(p, p.idx, "//w")
 
-proc whichSection(p: TRstParser): TRstNodeKind = 
+proc whichSection(p: TRstParser): TRstNodeKind =
   case p.tok[p.idx].kind
-  of tkAdornment: 
+  of tkAdornment:
     if match(p, p.idx + 1, "ii"): result = rnTransition
     elif match(p, p.idx + 1, " a"): result = rnTable
     elif match(p, p.idx + 1, "i"): result = rnOverline
     else: result = rnLeaf
-  of tkPunct: 
-    if match(p, tokenAfterNewline(p), "ai"): 
+  of tkPunct:
+    if match(p, tokenAfterNewline(p), "ai"):
       result = rnHeadline
-    elif p.tok[p.idx].symbol == "::": 
+    elif p.tok[p.idx].symbol == "::":
       result = rnLiteralBlock
     elif 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): 
+        (p.tok[p.idx].symbol == "-")) and (p.tok[p.idx + 1].kind == tkWhite):
       result = rnBulletList
-    elif (p.tok[p.idx].symbol == "|") and isLineBlock(p): 
+    elif (p.tok[p.idx].symbol == "|") and isLineBlock(p):
       result = rnLineBlock
-    elif (p.tok[p.idx].symbol == "..") and predNL(p): 
+    elif (p.tok[p.idx].symbol == "..") and predNL(p):
       result = rnDirective
     elif match(p, p.idx, ":w:") and predNL(p):
       # (p.tok[p.idx].symbol == ":")
       result = rnFieldList
-    elif match(p, p.idx, "(e) "): 
+    elif match(p, p.idx, "(e) "):
       result = rnEnumList
-    elif match(p, p.idx, "+a+"): 
+    elif match(p, p.idx, "+a+"):
       result = rnGridTable
       rstMessage(p, meGridTableNotImplemented)
-    elif isDefList(p): 
+    elif isDefList(p):
       result = rnDefList
-    elif isOptionList(p): 
+    elif isOptionList(p):
       result = rnOptionList
-    else: 
+    else:
       result = rnParagraph
   of tkWord, tkOther, tkWhite:
     if match(p, tokenAfterNewline(p), "ai"): result = rnHeadline
@@ -1052,58 +1052,58 @@ proc whichSection(p: TRstParser): TRstNodeKind =
     elif isDefList(p): result = rnDefList
     else: result = rnParagraph
   else: result = rnLeaf
-  
-proc parseLineBlock(p: var TRstParser): PRstNode = 
+
+proc parseLineBlock(p: var TRstParser): PRstNode =
   result = nil
-  if p.tok[p.idx + 1].kind == tkWhite: 
+  if p.tok[p.idx + 1].kind == tkWhite:
     var col = p.tok[p.idx].col
     result = newRstNode(rnLineBlock)
     pushInd(p, p.tok[p.idx + 2].col)
     inc(p.idx, 2)
-    while true: 
+    while true:
       var item = newRstNode(rnLineBlockItem)
       parseSection(p, item)
       add(result, item)
       if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
           (p.tok[p.idx + 1].symbol == "|") and
-          (p.tok[p.idx + 2].kind == tkWhite): 
+          (p.tok[p.idx + 2].kind == tkWhite):
         inc(p.idx, 3)
-      else: 
-        break 
+      else:
+        break
     popInd(p)
 
-proc parseParagraph(p: var TRstParser, result: PRstNode) = 
-  while true: 
+proc parseParagraph(p: var TRstParser, result: PRstNode) =
+  while true:
     case p.tok[p.idx].kind
-    of tkIndent: 
-      if p.tok[p.idx + 1].kind == tkIndent: 
+    of tkIndent:
+      if p.tok[p.idx + 1].kind == tkIndent:
         inc(p.idx)
-        break 
-      elif (p.tok[p.idx].ival == currInd(p)): 
+        break
+      elif (p.tok[p.idx].ival == currInd(p)):
         inc(p.idx)
         case whichSection(p)
-        of rnParagraph, rnLeaf, rnHeadline, rnOverline, rnDirective: 
+        of rnParagraph, rnLeaf, rnHeadline, rnOverline, rnDirective:
           add(result, newRstNode(rnLeaf, " "))
-        of rnLineBlock: 
+        of rnLineBlock:
           addIfNotNil(result, parseLineBlock(p))
-        else: break 
-      else: 
-        break 
-    of tkPunct: 
+        else: break
+      else:
+        break
+    of tkPunct:
       if (p.tok[p.idx].symbol == "::") and
           (p.tok[p.idx + 1].kind == tkIndent) and
-          (currInd(p) < p.tok[p.idx + 1].ival): 
+          (currInd(p) < p.tok[p.idx + 1].ival):
         add(result, newRstNode(rnLeaf, ":"))
         inc(p.idx)            # skip '::'
         add(result, parseLiteralBlock(p))
-        break 
-      else: 
+        break
+      else:
         parseInline(p, result)
-    of tkWhite, tkWord, tkAdornment, tkOther: 
+    of tkWhite, tkWord, tkAdornment, tkOther:
       parseInline(p, result)
     else: break
 
-proc parseHeadline(p: var TRstParser): PRstNode = 
+proc parseHeadline(p: var TRstParser): PRstNode =
   result = newRstNode(rnHeadline)
   parseUntilNewline(p, result)
   assert(p.tok[p.idx].kind == tkIndent)
@@ -1112,31 +1112,31 @@ proc parseHeadline(p: var TRstParser): PRstNode =
   inc(p.idx, 2)
   result.level = getLevel(p.s.underlineToLevel, p.s.uLevel, c)
 
-type 
+type
   TIntSeq = seq[int]
 
-proc tokEnd(p: TRstParser): int = 
+proc tokEnd(p: TRstParser): int =
   result = p.tok[p.idx].col + len(p.tok[p.idx].symbol) - 1
 
-proc getColumns(p: var TRstParser, cols: var TIntSeq) = 
+proc getColumns(p: var TRstParser, cols: var TIntSeq) =
   var L = 0
-  while true: 
+  while true:
     inc(L)
     setLen(cols, L)
     cols[L - 1] = tokEnd(p)
     assert(p.tok[p.idx].kind == tkAdornment)
     inc(p.idx)
-    if p.tok[p.idx].kind != tkWhite: break 
+    if p.tok[p.idx].kind != tkWhite: break
     inc(p.idx)
-    if p.tok[p.idx].kind != tkAdornment: break 
-  if p.tok[p.idx].kind == tkIndent: inc(p.idx)                
+    if p.tok[p.idx].kind != tkAdornment: break
+  if p.tok[p.idx].kind == tkIndent: inc(p.idx)
   # last column has no limit:
   cols[L - 1] = 32000
 
-proc parseDoc(p: var TRstParser): PRstNode
+proc parseDoc(p: var TRstParser): PRstNode {.gcsafe.}
 
-proc parseSimpleTable(p: var TRstParser): PRstNode = 
-  var 
+proc parseSimpleTable(p: var TRstParser): PRstNode =
+  var
     cols: TIntSeq
     row: seq[string]
     i, last, line: int
@@ -1148,36 +1148,36 @@ proc parseSimpleTable(p: var TRstParser): PRstNode =
   row = @[]
   a = nil
   c = p.tok[p.idx].symbol[0]
-  while true: 
-    if p.tok[p.idx].kind == tkAdornment: 
+  while true:
+    if p.tok[p.idx].kind == tkAdornment:
       last = tokenAfterNewline(p)
-      if p.tok[last].kind in {tkEof, tkIndent}: 
+      if p.tok[last].kind in {tkEof, tkIndent}:
         # skip last adornment line:
         p.idx = last
-        break 
+        break
       getColumns(p, cols)
       setLen(row, len(cols))
-      if a != nil: 
+      if a != nil:
         for j in 0..len(a)-1: a.sons[j].kind = rnTableHeaderCell
-    if p.tok[p.idx].kind == tkEof: break 
+    if p.tok[p.idx].kind == tkEof: break
     for j in countup(0, high(row)): row[j] = ""
     # the following while loop iterates over the lines a single cell may span:
     line = p.tok[p.idx].line
-    while true: 
+    while true:
       i = 0
-      while not (p.tok[p.idx].kind in {tkIndent, tkEof}): 
-        if (tokEnd(p) <= cols[i]): 
+      while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
+        if (tokEnd(p) <= cols[i]):
           add(row[i], p.tok[p.idx].symbol)
           inc(p.idx)
-        else: 
+        else:
           if p.tok[p.idx].kind == tkWhite: inc(p.idx)
           inc(i)
       if p.tok[p.idx].kind == tkIndent: inc(p.idx)
-      if tokEnd(p) <= cols[0]: break 
-      if p.tok[p.idx].kind in {tkEof, tkAdornment}: break 
+      if tokEnd(p) <= cols[0]: break
+      if p.tok[p.idx].kind in {tkEof, tkAdornment}: break
       for j in countup(1, high(row)): add(row[j], '\x0A')
     a = newRstNode(rnTableRow)
-    for j in countup(0, high(row)): 
+    for j in countup(0, high(row)):
       initParser(q, p.s)
       q.col = cols[j]
       q.line = line - 1
@@ -1188,95 +1188,95 @@ proc parseSimpleTable(p: var TRstParser): PRstNode =
       add(a, b)
     add(result, a)
 
-proc parseTransition(p: var TRstParser): PRstNode = 
+proc parseTransition(p: var TRstParser): PRstNode =
   result = newRstNode(rnTransition)
   inc(p.idx)
   if p.tok[p.idx].kind == tkIndent: inc(p.idx)
   if p.tok[p.idx].kind == tkIndent: inc(p.idx)
-  
-proc parseOverline(p: var TRstParser): PRstNode = 
+
+proc parseOverline(p: var TRstParser): PRstNode =
   var c = p.tok[p.idx].symbol[0]
   inc(p.idx, 2)
   result = newRstNode(rnOverline)
-  while true: 
+  while true:
     parseUntilNewline(p, result)
-    if p.tok[p.idx].kind == tkIndent: 
+    if p.tok[p.idx].kind == tkIndent:
       inc(p.idx)
-      if p.tok[p.idx - 1].ival > currInd(p): 
+      if p.tok[p.idx - 1].ival > currInd(p):
         add(result, newRstNode(rnLeaf, " "))
-      else: 
-        break 
-    else: 
-      break 
+      else:
+        break
+    else:
+      break
   result.level = getLevel(p.s.overlineToLevel, p.s.oLevel, c)
-  if p.tok[p.idx].kind == tkAdornment: 
+  if p.tok[p.idx].kind == tkAdornment:
     inc(p.idx)                # XXX: check?
     if p.tok[p.idx].kind == tkIndent: inc(p.idx)
-  
-proc parseBulletList(p: var TRstParser): PRstNode = 
+
+proc parseBulletList(p: var TRstParser): PRstNode =
   result = nil
-  if p.tok[p.idx + 1].kind == tkWhite: 
+  if p.tok[p.idx + 1].kind == tkWhite:
     var bullet = p.tok[p.idx].symbol
     var col = p.tok[p.idx].col
     result = newRstNode(rnBulletList)
     pushInd(p, p.tok[p.idx + 2].col)
     inc(p.idx, 2)
-    while true: 
+    while true:
       var item = newRstNode(rnBulletItem)
       parseSection(p, item)
       add(result, item)
       if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
           (p.tok[p.idx + 1].symbol == bullet) and
-          (p.tok[p.idx + 2].kind == tkWhite): 
+          (p.tok[p.idx + 2].kind == tkWhite):
         inc(p.idx, 3)
-      else: 
-        break 
+      else:
+        break
     popInd(p)
 
-proc parseOptionList(p: var TRstParser): PRstNode = 
+proc parseOptionList(p: var TRstParser): PRstNode =
   result = newRstNode(rnOptionList)
-  while true: 
+  while true:
     if isOptionList(p):
       var a = newRstNode(rnOptionGroup)
       var b = newRstNode(rnDescription)
       var c = newRstNode(rnOptionListItem)
       if match(p, p.idx, "//w"): inc(p.idx)
-      while not (p.tok[p.idx].kind in {tkIndent, tkEof}): 
-        if (p.tok[p.idx].kind == tkWhite) and (len(p.tok[p.idx].symbol) > 1): 
+      while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
+        if (p.tok[p.idx].kind == tkWhite) and (len(p.tok[p.idx].symbol) > 1):
           inc(p.idx)
-          break 
+          break
         add(a, newLeaf(p))
         inc(p.idx)
       var j = tokenAfterNewline(p)
       if (j > 0) and (p.tok[j - 1].kind == tkIndent) and
-          (p.tok[j - 1].ival > currInd(p)): 
+          (p.tok[j - 1].ival > currInd(p)):
         pushInd(p, p.tok[j - 1].ival)
         parseSection(p, b)
         popInd(p)
-      else: 
+      else:
         parseLine(p, b)
       if (p.tok[p.idx].kind == tkIndent): inc(p.idx)
       add(c, a)
       add(c, b)
       add(result, c)
-    else: 
-      break 
-  
-proc parseDefinitionList(p: var TRstParser): PRstNode = 
+    else:
+      break
+
+proc parseDefinitionList(p: var TRstParser): PRstNode =
   result = nil
   var j = tokenAfterNewline(p) - 1
   if (j >= 1) and (p.tok[j].kind == tkIndent) and
-      (p.tok[j].ival > currInd(p)) and (p.tok[j - 1].symbol != "::"): 
+      (p.tok[j].ival > currInd(p)) and (p.tok[j - 1].symbol != "::"):
     var col = p.tok[p.idx].col
     result = newRstNode(rnDefList)
-    while true: 
+    while true:
       j = p.idx
       var a = newRstNode(rnDefName)
       parseLine(p, a)
       if (p.tok[p.idx].kind == tkIndent) and
           (p.tok[p.idx].ival > currInd(p)) and
           (p.tok[p.idx + 1].symbol != "::") and
-          not (p.tok[p.idx + 1].kind in {tkIndent, tkEof}): 
+          not (p.tok[p.idx + 1].kind in {tkIndent, tkEof}):
         pushInd(p, p.tok[p.idx].ival)
         var b = newRstNode(rnDefBody)
         parseSection(p, b)
@@ -1285,74 +1285,74 @@ proc parseDefinitionList(p: var TRstParser): PRstNode =
         add(c, b)
         add(result, c)
         popInd(p)
-      else: 
+      else:
         p.idx = j
-        break 
-      if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col): 
+        break
+      if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col):
         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+1].kind != tkIndent: 
+            p.tok[j-1].symbol != "::" and p.tok[j+1].kind != tkIndent:
           discard
-        else: 
-          break 
+        else:
+          break
     if len(result) == 0: result = nil
-  
-proc parseEnumList(p: var TRstParser): PRstNode = 
-  const 
+
+proc parseEnumList(p: var TRstParser): PRstNode =
+  const
     wildcards: array[0..2, string] = ["(e) ", "e) ", "e. "]
     wildpos: array[0..2, int] = [1, 0, 0]
   result = nil
   var w = 0
-  while w <= 2: 
-    if match(p, p.idx, wildcards[w]): break 
+  while w <= 2:
+    if match(p, p.idx, wildcards[w]): break
     inc(w)
-  if w <= 2: 
+  if w <= 2:
     var col = p.tok[p.idx].col
     result = newRstNode(rnEnumList)
     inc(p.idx, wildpos[w] + 3)
     var j = tokenAfterNewline(p)
-    if (p.tok[j].col == p.tok[p.idx].col) or match(p, j, wildcards[w]): 
+    if (p.tok[j].col == p.tok[p.idx].col) or match(p, j, wildcards[w]):
       pushInd(p, p.tok[p.idx].col)
-      while true: 
+      while true:
         var item = newRstNode(rnEnumItem)
         parseSection(p, item)
         add(result, item)
         if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
-            match(p, p.idx + 1, wildcards[w]): 
+            match(p, p.idx + 1, wildcards[w]):
           inc(p.idx, wildpos[w] + 4)
-        else: 
-          break 
+        else:
+          break
       popInd(p)
-    else: 
+    else:
       dec(p.idx, wildpos[w] + 3)
       result = nil
 
-proc sonKind(father: PRstNode, i: int): TRstNodeKind = 
+proc sonKind(father: PRstNode, i: int): TRstNodeKind =
   result = rnLeaf
   if i < len(father): result = father.sons[i].kind
-  
-proc parseSection(p: var TRstParser, result: PRstNode) = 
-  while true: 
+
+proc parseSection(p: var TRstParser, result: PRstNode) =
+  while true:
     var leave = false
     assert(p.idx >= 0)
-    while p.tok[p.idx].kind == tkIndent: 
-      if currInd(p) == p.tok[p.idx].ival: 
+    while p.tok[p.idx].kind == tkIndent:
+      if currInd(p) == p.tok[p.idx].ival:
         inc(p.idx)
-      elif p.tok[p.idx].ival > currInd(p): 
+      elif p.tok[p.idx].ival > currInd(p):
         pushInd(p, p.tok[p.idx].ival)
         var a = newRstNode(rnBlockQuote)
         parseSection(p, a)
         add(result, a)
         popInd(p)
-      else: 
+      else:
         leave = true
         break
     if leave or p.tok[p.idx].kind == tkEof: break
     var a: PRstNode = nil
     var k = whichSection(p)
     case k
-    of rnLiteralBlock: 
+    of rnLiteralBlock:
       inc(p.idx)              # skip '::'
       a = parseLiteralBlock(p)
     of rnBulletList: a = parseBulletList(p)
@@ -1362,7 +1362,7 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
     of rnLeaf: rstMessage(p, meNewSectionExpected)
     of rnParagraph: discard
     of rnDefList: a = parseDefinitionList(p)
-    of rnFieldList: 
+    of rnFieldList:
       if p.idx > 0: dec(p.idx)
       a = parseFields(p)
     of rnTransition: a = parseTransition(p)
@@ -1373,35 +1373,35 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
     else:
       #InternalError("rst.parseSection()")
       discard
-    if a == nil and k != rnDirective: 
+    if a == nil and k != rnDirective:
       a = newRstNode(rnParagraph)
       parseParagraph(p, a)
     addIfNotNil(result, a)
-  if sonKind(result, 0) == rnParagraph and sonKind(result, 1) != rnParagraph: 
+  if sonKind(result, 0) == rnParagraph and sonKind(result, 1) != rnParagraph:
     result.sons[0].kind = rnInner
-  
-proc parseSectionWrapper(p: var TRstParser): PRstNode = 
+
+proc parseSectionWrapper(p: var TRstParser): PRstNode =
   result = newRstNode(rnInner)
   parseSection(p, result)
-  while (result.kind == rnInner) and (len(result) == 1): 
+  while (result.kind == rnInner) and (len(result) == 1):
     result = result.sons[0]
-  
+
 proc `$`(t: TToken): string =
   result = $t.kind & ' ' & (if isNil(t.symbol): "NIL" else: t.symbol)
 
-proc parseDoc(p: var TRstParser): PRstNode = 
+proc parseDoc(p: var TRstParser): PRstNode =
   result = parseSectionWrapper(p)
-  if p.tok[p.idx].kind != tkEof: 
+  if p.tok[p.idx].kind != tkEof:
     when false:
       assert isAllocatedPtr(cast[pointer](p.tok))
       for i in 0 .. high(p.tok):
-        assert isNil(p.tok[i].symbol) or 
+        assert isNil(p.tok[i].symbol) or
                isAllocatedPtr(cast[pointer](p.tok[i].symbol))
       echo "index: ", p.idx, " length: ", high(p.tok), "##",
           p.tok[p.idx-1], p.tok[p.idx], p.tok[p.idx+1]
     #assert isAllocatedPtr(cast[pointer](p.indentStack))
     rstMessage(p, meGeneralParseError)
-  
+
 type
   TDirFlag = enum
     hasArg, hasOptions, argIsFile, argIsWord
@@ -1421,55 +1421,55 @@ proc parseDirective(p: var TRstParser, flags: TDirFlags): PRstNode =
   result = newRstNode(rnDirective)
   var args: PRstNode = nil
   var options: PRstNode = nil
-  if hasArg in flags: 
+  if hasArg in flags:
     args = newRstNode(rnDirArg)
-    if argIsFile in flags: 
-      while true: 
+    if argIsFile in flags:
+      while true:
         case p.tok[p.idx].kind
-        of tkWord, tkOther, tkPunct, tkAdornment: 
+        of tkWord, tkOther, tkPunct, tkAdornment:
           add(args, newLeaf(p))
           inc(p.idx)
-        else: break 
+        else: break
     elif argIsWord in flags:
       while p.tok[p.idx].kind == tkWhite: inc(p.idx)
-      if p.tok[p.idx].kind == tkWord: 
+      if p.tok[p.idx].kind == tkWord:
         add(args, newLeaf(p))
         inc(p.idx)
       else:
         args = nil
-    else: 
+    else:
       parseLine(p, args)
   add(result, args)
-  if hasOptions in flags: 
+  if hasOptions in flags:
     if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival >= 3) and
-        (p.tok[p.idx + 1].symbol == ":"): 
+        (p.tok[p.idx + 1].symbol == ":"):
       options = parseFields(p)
   add(result, options)
-  
-proc indFollows(p: TRstParser): bool = 
+
+proc indFollows(p: TRstParser): bool =
   result = p.tok[p.idx].kind == tkIndent and p.tok[p.idx].ival > currInd(p)
-  
-proc parseDirective(p: var TRstParser, flags: TDirFlags, 
-                    contentParser: TSectionParser): PRstNode = 
+
+proc parseDirective(p: var TRstParser, flags: TDirFlags,
+                    contentParser: TSectionParser): PRstNode =
   ## Returns a generic rnDirective tree.
   ##
   ## The children are rnDirArg, rnFieldList and rnLineBlock. Any might be nil.
   result = parseDirective(p, flags)
-  if not isNil(contentParser) and indFollows(p): 
+  if not isNil(contentParser) and indFollows(p):
     pushInd(p, p.tok[p.idx].ival)
     var content = contentParser(p)
     popInd(p)
     add(result, content)
-  else: 
+  else:
     add(result, nil)
 
-proc parseDirBody(p: var TRstParser, contentParser: TSectionParser): PRstNode = 
-  if indFollows(p): 
+proc parseDirBody(p: var TRstParser, contentParser: TSectionParser): PRstNode =
+  if indFollows(p):
     pushInd(p, p.tok[p.idx].ival)
     result = contentParser(p)
     popInd(p)
-  
-proc dirInclude(p: var TRstParser): PRstNode = 
+
+proc dirInclude(p: var TRstParser): PRstNode =
   #
   #The following options are recognized:
   #
@@ -1490,18 +1490,18 @@ proc dirInclude(p: var TRstParser): PRstNode =
   var n = parseDirective(p, {hasArg, argIsFile, hasOptions}, nil)
   var filename = strip(addNodes(n.sons[0]))
   var path = p.s.findFile(filename)
-  if path == "": 
+  if path == "":
     rstMessage(p, meCannotOpenFile, filename)
-  else: 
+  else:
     # XXX: error handling; recursive file inclusion!
-    if getFieldValue(n, "literal") != "": 
+    if getFieldValue(n, "literal") != "":
       result = newRstNode(rnLiteralBlock)
       add(result, newRstNode(rnLeaf, readFile(path)))
     else:
       var q: TRstParser
       initParser(q, p.s)
       q.filename = filename
-      q.col += getTokens(readFile(path), false, q.tok) 
+      q.col += getTokens(readFile(path), false, q.tok)
       # workaround a GCC bug; more like the interior pointer bug?
       #if find(q.tok[high(q.tok)].symbol, "\0\x01\x02") > 0:
       #  InternalError("Too many binary zeros in include file")
@@ -1526,7 +1526,7 @@ proc dirCodeBlock(p: var TRstParser, nimrodExtension = false): PRstNode =
   ## file.
   result = parseDirective(p, {hasArg, hasOptions}, parseLiteralBlock)
   var filename = strip(getFieldValue(result, "file"))
-  if filename != "": 
+  if filename != "":
     var path = p.s.findFile(filename)
     if path == "": rstMessage(p, meCannotOpenFile, filename)
     var n = newRstNode(rnLiteralBlock)
@@ -1548,49 +1548,49 @@ proc dirCodeBlock(p: var TRstParser, nimrodExtension = false): PRstNode =
 
   result.kind = rnCodeBlock
 
-proc dirContainer(p: var TRstParser): PRstNode = 
+proc dirContainer(p: var TRstParser): PRstNode =
   result = parseDirective(p, {hasArg}, parseSectionWrapper)
   assert(result.kind == rnDirective)
   assert(len(result) == 3)
   result.kind = rnContainer
 
-proc dirImage(p: var TRstParser): PRstNode = 
+proc dirImage(p: var TRstParser): PRstNode =
   result = parseDirective(p, {hasOptions, hasArg, argIsFile}, nil)
   result.kind = rnImage
 
-proc dirFigure(p: var TRstParser): PRstNode = 
-  result = parseDirective(p, {hasOptions, hasArg, argIsFile}, 
+proc dirFigure(p: var TRstParser): PRstNode =
+  result = parseDirective(p, {hasOptions, hasArg, argIsFile},
                           parseSectionWrapper)
   result.kind = rnFigure
 
-proc dirTitle(p: var TRstParser): PRstNode = 
+proc dirTitle(p: var TRstParser): PRstNode =
   result = parseDirective(p, {hasArg}, nil)
   result.kind = rnTitle
 
-proc dirContents(p: var TRstParser): PRstNode = 
+proc dirContents(p: var TRstParser): PRstNode =
   result = parseDirective(p, {hasArg}, nil)
   result.kind = rnContents
 
-proc dirIndex(p: var TRstParser): PRstNode = 
+proc dirIndex(p: var TRstParser): PRstNode =
   result = parseDirective(p, {}, parseSectionWrapper)
   result.kind = rnIndex
 
 proc dirRawAux(p: var TRstParser, result: var PRstNode, kind: TRstNodeKind,
-               contentParser: TSectionParser) = 
+               contentParser: TSectionParser) =
   var filename = getFieldValue(result, "file")
-  if filename.len > 0: 
+  if filename.len > 0:
     var path = p.s.findFile(filename)
-    if path.len == 0: 
+    if path.len == 0:
       rstMessage(p, meCannotOpenFile, filename)
-    else: 
+    else:
       var f = readFile(path)
       result = newRstNode(kind)
       add(result, newRstNode(rnLeaf, f))
-  else:      
+  else:
     result.kind = kind
     add(result, parseDirBody(p, contentParser))
 
-proc dirRaw(p: var TRstParser): PRstNode = 
+proc dirRaw(p: var TRstParser): PRstNode =
   #
   #The following options are recognized:
   #
@@ -1603,19 +1603,19 @@ proc dirRaw(p: var TRstParser): PRstNode =
   if result.sons[0] != nil:
     if cmpIgnoreCase(result.sons[0].sons[0].text, "html") == 0:
       dirRawAux(p, result, rnRawHtml, parseLiteralBlock)
-    elif cmpIgnoreCase(result.sons[0].sons[0].text, "latex") == 0: 
+    elif cmpIgnoreCase(result.sons[0].sons[0].text, "latex") == 0:
       dirRawAux(p, result, rnRawLatex, parseLiteralBlock)
     else:
       rstMessage(p, meInvalidDirective, result.sons[0].sons[0].text)
   else:
     dirRawAux(p, result, rnRaw, parseSectionWrapper)
 
-proc parseDotDot(p: var TRstParser): PRstNode = 
+proc parseDotDot(p: var TRstParser): PRstNode =
   result = nil
   var col = p.tok[p.idx].col
   inc(p.idx)
   var d = getDirective(p)
-  if d != "": 
+  if d != "":
     pushInd(p, col)
     case getDirKind(d)
     of dkInclude: result = dirInclude(p)
@@ -1634,66 +1634,66 @@ proc parseDotDot(p: var TRstParser): PRstNode =
     of dkIndex: result = dirIndex(p)
     else: rstMessage(p, meInvalidDirective, d)
     popInd(p)
-  elif match(p, p.idx, " _"): 
+  elif match(p, p.idx, " _"):
     # hyperlink target:
     inc(p.idx, 2)
     var a = getReferenceName(p, ":")
     if p.tok[p.idx].kind == tkWhite: inc(p.idx)
     var b = untilEol(p)
     setRef(p, rstnodeToRefname(a), b)
-  elif match(p, p.idx, " |"): 
+  elif match(p, p.idx, " |"):
     # substitution definitions:
     inc(p.idx, 2)
     var a = getReferenceName(p, "|")
     var b: PRstNode
     if p.tok[p.idx].kind == tkWhite: inc(p.idx)
-    if cmpIgnoreStyle(p.tok[p.idx].symbol, "replace") == 0: 
+    if cmpIgnoreStyle(p.tok[p.idx].symbol, "replace") == 0:
       inc(p.idx)
       expect(p, "::")
       b = untilEol(p)
-    elif cmpIgnoreStyle(p.tok[p.idx].symbol, "image") == 0: 
+    elif cmpIgnoreStyle(p.tok[p.idx].symbol, "image") == 0:
       inc(p.idx)
       b = dirImage(p)
-    else: 
+    else:
       rstMessage(p, meInvalidDirective, p.tok[p.idx].symbol)
     setSub(p, addNodes(a), b)
-  elif match(p, p.idx, " ["): 
+  elif match(p, p.idx, " ["):
     # footnotes, citations
     inc(p.idx, 2)
     var a = getReferenceName(p, "]")
     if p.tok[p.idx].kind == tkWhite: inc(p.idx)
     var b = untilEol(p)
     setRef(p, rstnodeToRefname(a), b)
-  else: 
+  else:
     result = parseComment(p)
-  
-proc resolveSubs(p: var TRstParser, n: PRstNode): PRstNode = 
+
+proc resolveSubs(p: var TRstParser, n: PRstNode): PRstNode =
   result = n
-  if n == nil: return 
+  if n == nil: return
   case n.kind
-  of rnSubstitutionReferences: 
+  of rnSubstitutionReferences:
     var x = findSub(p, n)
-    if x >= 0: 
+    if x >= 0:
       result = p.s.subs[x].value
-    else: 
+    else:
       var key = addNodes(n)
       var e = getEnv(key)
       if e != "": result = newRstNode(rnLeaf, e)
       else: rstMessage(p, mwUnknownSubstitution, key)
-  of rnRef: 
+  of rnRef:
     var y = findRef(p, rstnodeToRefname(n))
-    if y != nil: 
+    if y != nil:
       result = newRstNode(rnHyperlink)
       n.kind = rnInner
       add(result, n)
       add(result, y)
-  of rnLeaf: 
+  of rnLeaf:
     discard
-  of rnContents: 
+  of rnContents:
     p.hasToc = true
-  else: 
+  else:
     for i in countup(0, len(n) - 1): n.sons[i] = resolveSubs(p, n.sons[i])
-  
+
 proc rstParse*(text, filename: string,
                line, column: int, hasToc: var bool,
                options: TRstParseOptions,
diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim
index 52af672df..c3956ab8b 100644
--- a/lib/packages/docutils/rstast.nim
+++ b/lib/packages/docutils/rstast.nim
@@ -30,7 +30,7 @@ type
     rnField,                  # a field item
     rnFieldName,              # consisting of a field name ...
     rnFieldBody,              # ... and a field body
-    rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString, 
+    rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString,
     rnOptionArgument, rnDescription, rnLiteralBlock, rnQuotedLiteralBlock,
     rnLineBlock,              # the | thingie
     rnLineBlockItem,          # sons of the | thing
@@ -50,7 +50,7 @@ type
                               #     * `file#id <file#id>'_
     rnSubstitutionDef,        # a definition of a substitution
     rnGeneralRole,            # Inline markup:
-    rnSub, rnSup, rnIdx, 
+    rnSub, rnSup, rnIdx,
     rnEmphasis,               # "*"
     rnStrongEmphasis,         # "**"
     rnTripleEmphasis,         # "***"
@@ -71,25 +71,25 @@ type
     level*: int               ## valid for some node kinds
     sons*: TRstNodeSeq        ## the node's sons
 
-proc len*(n: PRstNode): int = 
+proc len*(n: PRstNode): int =
   result = len(n.sons)
 
-proc newRstNode*(kind: TRstNodeKind): PRstNode = 
+proc newRstNode*(kind: TRstNodeKind): PRstNode =
   new(result)
   result.sons = @[]
   result.kind = kind
 
-proc newRstNode*(kind: TRstNodeKind, s: string): PRstNode = 
+proc newRstNode*(kind: TRstNodeKind, s: string): PRstNode =
   result = newRstNode(kind)
   result.text = s
 
-proc lastSon*(n: PRstNode): PRstNode = 
+proc lastSon*(n: PRstNode): PRstNode =
   result = n.sons[len(n.sons)-1]
 
 proc add*(father, son: PRstNode) =
   add(father.sons, son)
 
-proc addIfNotNil*(father, son: PRstNode) = 
+proc addIfNotNil*(father, son: PRstNode) =
   if son != nil: add(father, son)
 
 
@@ -98,62 +98,63 @@ type
     indent: int
     verbatim: int
 
-proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string)
+proc renderRstToRst(d: var TRenderContext, n: PRstNode,
+                    result: var string) {.gcsafe.}
 
-proc renderRstSons(d: var TRenderContext, n: PRstNode, result: var string) = 
-  for i in countup(0, len(n) - 1): 
+proc renderRstSons(d: var TRenderContext, n: PRstNode, result: var string) =
+  for i in countup(0, len(n) - 1):
     renderRstToRst(d, n.sons[i], result)
-  
+
 proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
   # this is needed for the index generation; it may also be useful for
   # debugging, but most code is already debugged...
-  const 
+  const
     lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+']
   if n == nil: return
-  var ind = repeatChar(d.indent)
+  var ind = spaces(d.indent)
   case n.kind
-  of rnInner: 
+  of rnInner:
     renderRstSons(d, n, result)
   of rnHeadline:
     result.add("\n")
     result.add(ind)
-    
+
     let oldLen = result.len
     renderRstSons(d, n, result)
     let headlineLen = result.len - oldLen
 
     result.add("\n")
     result.add(ind)
-    result.add repeatChar(headlineLen, lvlToChar[n.level])
+    result.add repeat(lvlToChar[n.level], headlineLen)
   of rnOverline:
     result.add("\n")
     result.add(ind)
 
     var headline = ""
     renderRstSons(d, n, headline)
-    
-    let lvl = repeatChar(headline.len - d.indent, lvlToChar[n.level])
+
+    let lvl = repeat(lvlToChar[n.level], headline.len - d.indent)
     result.add(lvl)
     result.add("\n")
     result.add(headline)
-    
+
     result.add("\n")
     result.add(ind)
     result.add(lvl)
-  of rnTransition: 
+  of rnTransition:
     result.add("\n\n")
     result.add(ind)
-    result.add repeatChar(78-d.indent, '-')
+    result.add repeat('-', 78-d.indent)
     result.add("\n\n")
   of rnParagraph:
     result.add("\n\n")
     result.add(ind)
     renderRstSons(d, n, result)
-  of rnBulletItem: 
+  of rnBulletItem:
     inc(d.indent, 2)
     var tmp = ""
     renderRstSons(d, n, tmp)
-    if tmp.len > 0: 
+    if tmp.len > 0:
       result.add("\n")
       result.add(ind)
       result.add("* ")
@@ -163,22 +164,22 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
     inc(d.indent, 4)
     var tmp = ""
     renderRstSons(d, n, tmp)
-    if tmp.len > 0: 
+    if tmp.len > 0:
       result.add("\n")
       result.add(ind)
       result.add("(#) ")
       result.add(tmp)
     dec(d.indent, 4)
-  of rnOptionList, rnFieldList, rnDefList, rnDefItem, rnLineBlock, rnFieldName, 
-     rnFieldBody, rnStandaloneHyperlink, rnBulletList, rnEnumList: 
+  of rnOptionList, rnFieldList, rnDefList, rnDefItem, rnLineBlock, rnFieldName,
+     rnFieldBody, rnStandaloneHyperlink, rnBulletList, rnEnumList:
     renderRstSons(d, n, result)
-  of rnDefName: 
+  of rnDefName:
     result.add("\n\n")
     result.add(ind)
     renderRstSons(d, n, result)
   of rnDefBody:
     inc(d.indent, 2)
-    if n.sons[0].kind != rnBulletList: 
+    if n.sons[0].kind != rnBulletList:
       result.add("\n")
       result.add(ind)
       result.add("  ")
@@ -187,20 +188,20 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
   of rnField:
     var tmp = ""
     renderRstToRst(d, n.sons[0], tmp)
-    
+
     var L = max(tmp.len + 3, 30)
     inc(d.indent, L)
-    
+
     result.add "\n"
     result.add ind
     result.add ':'
     result.add tmp
     result.add ':'
-    result.add repeatChar(L - tmp.len - 2)
+    result.add spaces(L - tmp.len - 2)
     renderRstToRst(d, n.sons[1], result)
-    
+
     dec(d.indent, L)
-  of rnLineBlockItem: 
+  of rnLineBlockItem:
     result.add("\n")
     result.add(ind)
     result.add("| ")
@@ -209,11 +210,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
     inc(d.indent, 2)
     renderRstSons(d, n, result)
     dec(d.indent, 2)
-  of rnRef: 
+  of rnRef:
     result.add("`")
     renderRstSons(d, n, result)
     result.add("`_")
-  of rnHyperlink: 
+  of rnHyperlink:
     result.add('`')
     renderRstToRst(d, n.sons[0], result)
     result.add(" <")
@@ -225,23 +226,23 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
     result.add("`:")
     renderRstToRst(d, n.sons[1],result)
     result.add(':')
-  of rnSub: 
+  of rnSub:
     result.add('`')
     renderRstSons(d, n, result)
     result.add("`:sub:")
-  of rnSup: 
+  of rnSup:
     result.add('`')
     renderRstSons(d, n, result)
     result.add("`:sup:")
-  of rnIdx: 
+  of rnIdx:
     result.add('`')
     renderRstSons(d, n, result)
     result.add("`:idx:")
-  of rnEmphasis: 
+  of rnEmphasis:
     result.add("*")
     renderRstSons(d, n, result)
     result.add("*")
-  of rnStrongEmphasis: 
+  of rnStrongEmphasis:
     result.add("**")
     renderRstSons(d, n, result)
     result.add("**")
@@ -249,11 +250,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
     result.add("***")
     renderRstSons(d, n, result)
     result.add("***")
-  of rnInterpretedText: 
+  of rnInterpretedText:
     result.add('`')
     renderRstSons(d, n, result)
     result.add('`')
-  of rnInlineLiteral: 
+  of rnInlineLiteral:
     inc(d.verbatim)
     result.add("``")
     renderRstSons(d, n, result)
@@ -266,11 +267,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
       result.add("\\\\") # XXX: escape more special characters!
     else:
       result.add(n.text)
-  of rnIndex: 
+  of rnIndex:
     result.add("\n\n")
     result.add(ind)
     result.add(".. index::\n")
-    
+
     inc(d.indent, 3)
     if n.sons[2] != nil: renderRstSons(d, n.sons[2], result)
     dec(d.indent, 3)
@@ -280,7 +281,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
     result.add(".. contents::")
   else:
     result.add("Error: cannot render: " & $n.kind)
-  
+
 proc renderRstToRst*(n: PRstNode, result: var string) =
   ## renders `n` into its string representation and appends to `result`.
   var d: TRenderContext
@@ -302,7 +303,7 @@ proc renderRstToJsonNode(node: PRstNode): JsonNode =
 
 proc renderRstToJson*(node: PRstNode): string =
   ## Writes the given RST node as JSON that is in the form
-  ## :: 
+  ## ::
   ##   {
   ##     "kind":string node.kind,
   ##     "text":optional string node.text,
diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim
index fc60b3672..9e96d8a63 100644
--- a/lib/packages/docutils/rstgen.nim
+++ b/lib/packages/docutils/rstgen.nim
@@ -34,14 +34,14 @@ type
   TOutputTarget* = enum ## which document type to generate
     outHtml,            # output is HTML
     outLatex            # output is Latex
-  
-  TTocEntry = object 
+
+  TTocEntry = object
     n*: PRstNode
     refname*, header*: string
 
-  TMetaEnum* = enum 
+  TMetaEnum* = enum
     metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion
-    
+
   TRstGenerator* = object of RootObj
     target*: TOutputTarget
     config*: StringTableRef
@@ -60,7 +60,7 @@ type
     seenIndexTerms: Table[string, int] ## \
     ## Keeps count of same text index terms to generate different identifiers
     ## for hyperlinks. See renderIndexTerm proc for details.
-  
+
   PDoc = var TRstGenerator ## Alias to type less.
 
   CodeBlockParams = object ## Stores code block params.
@@ -136,7 +136,7 @@ proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
     g.currentSection = "Module " & fileParts.name
   g.seenIndexTerms = initTable[string, int]()
   g.msgHandler = msgHandler
-  
+
   let s = config["split.item.toc"]
   if s != "": g.splitAfter = parseInt(s)
   for i in low(g.meta)..high(g.meta): g.meta[i] = ""
@@ -147,23 +147,23 @@ proc writeIndexFile*(g: var TRstGenerator, outfile: string) =
   ## You previously need to add entries to the index with the `setIndexTerm()
   ## <#setIndexTerm>`_ proc. If the index is empty the file won't be created.
   if g.theIndex.len > 0: writeFile(outfile, g.theIndex)
-  
-proc addXmlChar(dest: var string, c: char) = 
+
+proc addXmlChar(dest: var string, c: char) =
   case c
   of '&': add(dest, "&amp;")
   of '<': add(dest, "&lt;")
   of '>': add(dest, "&gt;")
   of '\"': add(dest, "&quot;")
   else: add(dest, c)
-  
-proc addRtfChar(dest: var string, c: char) = 
+
+proc addRtfChar(dest: var string, c: char) =
   case c
   of '{': add(dest, "\\{")
   of '}': add(dest, "\\}")
   of '\\': add(dest, "\\\\")
   else: add(dest, c)
-  
-proc addTexChar(dest: var string, c: char) = 
+
+proc addTexChar(dest: var string, c: char) =
   case c
   of '_': add(dest, "\\_")
   of '{': add(dest, "\\symbol{123}")
@@ -183,54 +183,54 @@ proc addTexChar(dest: var string, c: char) =
 
 var splitter*: string = "<wbr />"
 
-proc escChar*(target: TOutputTarget, dest: var string, c: char) {.inline.} = 
+proc escChar*(target: TOutputTarget, dest: var string, c: char) {.inline.} =
   case target
   of outHtml:  addXmlChar(dest, c)
   of outLatex: addTexChar(dest, c)
-  
-proc nextSplitPoint*(s: string, start: int): int = 
+
+proc nextSplitPoint*(s: string, start: int): int =
   result = start
-  while result < len(s) + 0: 
+  while result < len(s) + 0:
     case s[result]
-    of '_': return 
-    of 'a'..'z': 
-      if result + 1 < len(s) + 0: 
-        if s[result + 1] in {'A'..'Z'}: return 
+    of '_': return
+    of 'a'..'z':
+      if result + 1 < len(s) + 0:
+        if s[result + 1] in {'A'..'Z'}: return
     else: discard
     inc(result)
   dec(result)                 # last valid index
-  
-proc esc*(target: TOutputTarget, s: string, splitAfter = -1): string = 
+
+proc esc*(target: TOutputTarget, s: string, splitAfter = -1): string =
   result = ""
-  if splitAfter >= 0: 
+  if splitAfter >= 0:
     var partLen = 0
     var j = 0
-    while j < len(s): 
+    while j < len(s):
       var k = nextSplitPoint(s, j)
-      if (splitter != " ") or (partLen + k - j + 1 > splitAfter): 
+      if (splitter != " ") or (partLen + k - j + 1 > splitAfter):
         partLen = 0
         add(result, splitter)
       for i in countup(j, k): escChar(target, result, s[i])
       inc(partLen, k - j + 1)
       j = k + 1
-  else: 
+  else:
     for i in countup(0, len(s) - 1): escChar(target, result, s[i])
 
 
 proc disp(target: TOutputTarget, xml, tex: string): string =
-  if target != outLatex: result = xml 
+  if target != outLatex: result = xml
   else: result = tex
-  
-proc dispF(target: TOutputTarget, xml, tex: string, 
-           args: varargs[string]): string = 
-  if target != outLatex: result = xml % args 
+
+proc dispF(target: TOutputTarget, xml, tex: string,
+           args: varargs[string]): string =
+  if target != outLatex: result = xml % args
   else: result = tex % args
-  
-proc dispA(target: TOutputTarget, dest: var string, 
+
+proc dispA(target: TOutputTarget, dest: var string,
            xml, tex: string, args: varargs[string]) =
   if target != outLatex: addf(dest, xml, args)
   else: addf(dest, tex, args)
-  
+
 proc `or`(x, y: string): string {.inline.} =
   result = if x.isNil: y else: x
 
@@ -248,7 +248,7 @@ proc renderRstToOut*(d: var TRstGenerator, n: PRstNode, result: var string)
   ##   renderRstToOut(gen, rst, generatedHTML)
   ##   echo generatedHTML
 
-proc renderAux(d: PDoc, n: PRstNode, result: var string) = 
+proc renderAux(d: PDoc, n: PRstNode, result: var string) =
   for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], result)
 
 proc renderAux(d: PDoc, n: PRstNode, frmtA, frmtB: string, result: var string) =
@@ -347,7 +347,7 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) =
   var term = ""
   renderAux(d, n, term)
   setIndexTerm(d, id, term, d.currentSection)
-  dispA(d.target, result, "<span id=\"$1\">$2</span>", "$2\\label{$1}", 
+  dispA(d.target, result, "<span id=\"$1\">$2</span>", "$2\\label{$1}",
         [id, term])
 
 type
@@ -417,10 +417,12 @@ proc generateSymbolIndex(symbols: seq[TIndexEntry]): string =
   result = ""
   var i = 0
   while i < symbols.len:
-    result.addf("<dt><span>$1:</span></dt><ul class=\"simple\"><dd>\n",
-                [symbols[i].keyword])
+    let keyword= symbols[i].keyword
+    let cleaned_keyword = keyword[1..keyword.high - 1]
+    result.addf("<dt><a name=\"$2\" href=\"#$2\"><span>$1:</span></a></dt><ul class=\"simple\"><dd>\n",
+                [keyword, cleaned_keyword])
     var j = i
-    while j < symbols.len and symbols[i].keyword == symbols[j].keyword:
+    while j < symbols.len and keyword == symbols[j].keyword:
       let
         url = symbols[j].link
         text = if not symbols[j].linkTitle.isNil: symbols[j].linkTitle else: url
@@ -459,9 +461,9 @@ proc indentToLevel(level: var int, newLevel: int): string =
   if level == newLevel:
     return
   if newLevel > level:
-    result = repeatStr(newLevel - level, "<ul>")
+    result = repeat("<ul>", newLevel - level)
   else:
-    result = repeatStr(level - newLevel, "</ul>")
+    result = repeat("</ul>", level - newLevel)
   level = newLevel
 
 proc generateDocumentationTOC(entries: seq[TIndexEntry]): string =
@@ -654,7 +656,7 @@ proc mergeIndexes*(dir: string): string =
     result.add("<h2>API symbols</h2>\n")
     result.add(generateSymbolIndex(symbols))
 
-  
+
 # ----------------------------------------------------------------------------
 
 proc stripTOCHTML(s: string): string =
@@ -675,11 +677,18 @@ proc stripTOCHTML(s: string): string =
     result.delete(first, last)
     first = result.find('<', first)
 
-proc renderHeadline(d: PDoc, n: PRstNode, result: var string) = 
+proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
   var tmp = ""
   for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp)
   d.currentSection = tmp
-  var refname = rstnodeToRefname(n)
+  # Find the last higher level section for unique reference name
+  var sectionPrefix = ""
+  for i in countdown(d.tocPart.high, 0):
+    let n2 = d.tocPart[i].n
+    if n2.level < n.level:
+      sectionPrefix = rstnodeToRefname(n2) & "-"
+      break
+  var refname = sectionPrefix & rstnodeToRefname(n)
   if d.hasToc:
     var length = len(d.tocPart)
     setLen(d.tocPart, length + 1)
@@ -688,20 +697,20 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
     d.tocPart[length].header = tmp
 
     dispA(d.target, result, "\n<h$1><a class=\"toc-backref\" " &
-      "id=\"$2\" href=\"#$2_toc\">$3</a></h$1>", "\\rsth$4{$3}\\label{$2}\n",
+      "id=\"$2\" href=\"#$2\">$3</a></h$1>", "\\rsth$4{$3}\\label{$2}\n",
       [$n.level, d.tocPart[length].refname, tmp, $chr(n.level - 1 + ord('A'))])
   else:
-    dispA(d.target, result, "\n<h$1 id=\"$2\">$3</h$1>", 
+    dispA(d.target, result, "\n<h$1 id=\"$2\">$3</h$1>",
                             "\\rsth$4{$3}\\label{$2}\n", [
-        $n.level, refname, tmp, 
+        $n.level, refname, tmp,
         $chr(n.level - 1 + ord('A'))])
 
   # Generate index entry using spaces to indicate TOC level for the output HTML.
   assert n.level >= 0
   setIndexTerm(d, refname, tmp.stripTOCHTML,
-    repeatChar(max(0, n.level), ' ') & tmp)
+    spaces(max(0, n.level)) & tmp)
 
-proc renderOverline(d: PDoc, n: PRstNode, result: var string) = 
+proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
   if d.meta[metaTitle].len == 0:
     for i in countup(0, len(n)-1):
       renderRstToOut(d, n.sons[i], d.meta[metaTitle])
@@ -714,14 +723,14 @@ proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
     var tmp = ""
     for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp)
     d.currentSection = tmp
-    dispA(d.target, result, "<h$1 id=\"$2\"><center>$3</center></h$1>", 
+    dispA(d.target, result, "<h$1 id=\"$2\"><center>$3</center></h$1>",
                    "\\rstov$4{$3}\\label{$2}\n", [$n.level,
         rstnodeToRefname(n), tmp, $chr(n.level - 1 + ord('A'))])
-  
 
-proc renderTocEntry(d: PDoc, e: TTocEntry, result: var string) = 
+
+proc renderTocEntry(d: PDoc, e: TTocEntry, result: var string) =
   dispA(d.target, result,
-    "<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n", 
+    "<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n",
     "\\item\\label{$1_toc} $2\\ref{$1}\n", [e.refname, e.header])
 
 proc renderTocEntries*(d: var TRstGenerator, j: var int, lvl: int,
@@ -750,33 +759,33 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) =
   var options = ""
   var s = getFieldValue(n, "scale")
   if s.valid: dispA(d.target, options, " scale=\"$1\"", " scale=$1", [strip(s)])
-  
+
   s = getFieldValue(n, "height")
   if s.valid: dispA(d.target, options, " height=\"$1\"", " height=$1", [strip(s)])
-  
+
   s = getFieldValue(n, "width")
   if s.valid: dispA(d.target, options, " width=\"$1\"", " width=$1", [strip(s)])
-  
+
   s = getFieldValue(n, "alt")
   if s.valid: dispA(d.target, options, " alt=\"$1\"", "", [strip(s)])
-  
+
   s = getFieldValue(n, "align")
   if s.valid: dispA(d.target, options, " align=\"$1\"", "", [strip(s)])
-  
+
   if options.len > 0: options = dispF(d.target, "$1", "[$1]", [options])
 
   let arg = getArgument(n)
   if arg.valid:
-    dispA(d.target, result, "<img src=\"$1\"$2 />", "\\includegraphics$2{$1}", 
+    dispA(d.target, result, "<img src=\"$1\"$2 />", "\\includegraphics$2{$1}",
           [arg, options])
   if len(n) >= 3: renderRstToOut(d, n.sons[2], result)
-  
+
 proc renderSmiley(d: PDoc, n: PRstNode, result: var string) =
   dispA(d.target, result,
-    """<img src="$1" width="15" 
+    """<img src="$1" width="15"
         height="17" hspace="2" vspace="2" class="smiley" />""",
     "\\includegraphics{$1}", [d.config["doc.smiley_format"] % n.text])
-  
+
 proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) =
   ## Parses useful fields which can appear before a code block.
   ##
@@ -836,7 +845,7 @@ proc buildLinesHTMLTable(params: CodeBlockParams, code: string):
 
   var codeLines = 1 + code.strip.countLines
   assert codeLines > 0
-  result.beginTable = """<table><tbody><tr><td class="blob-line-nums"><pre>"""
+  result.beginTable = """<table class="line-nums-table"><tbody><tr><td class="blob-line-nums"><pre>"""
   var line = params.startLine
   while codeLines > 0:
     result.beginTable.add($line & "\n")
@@ -871,11 +880,11 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
   else:
     var g: TGeneralTokenizer
     initGeneralTokenizer(g, m.text)
-    while true: 
+    while true:
       getNextToken(g, params.lang)
       case g.kind
-      of gtEof: break 
-      of gtNone, gtWhitespace: 
+      of gtEof: break
+      of gtNone, gtWhitespace:
         add(result, substr(m.text, g.start, g.length + g.start - 1))
       else:
         dispA(d.target, result, "<span class=\"$2\">$1</span>", "\\span$2{$1}", [
@@ -884,36 +893,36 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
     deinitGeneralTokenizer(g)
   dispA(d.target, result, blockEnd, "\n\\end{rstpre}\n")
 
-proc renderContainer(d: PDoc, n: PRstNode, result: var string) = 
+proc renderContainer(d: PDoc, n: PRstNode, result: var string) =
   var tmp = ""
   renderRstToOut(d, n.sons[2], tmp)
   var arg = strip(getArgument(n))
-  if arg == "": 
+  if arg == "":
     dispA(d.target, result, "<div>$1</div>", "$1", [tmp])
   else:
     dispA(d.target, result, "<div class=\"$1\">$2</div>", "$2", [arg, tmp])
-  
-proc texColumns(n: PRstNode): string = 
+
+proc texColumns(n: PRstNode): string =
   result = ""
   for i in countup(1, len(n)): add(result, "|X")
-  
-proc renderField(d: PDoc, n: PRstNode, result: var string) = 
+
+proc renderField(d: PDoc, n: PRstNode, result: var string) =
   var b = false
-  if d.target == outLatex: 
+  if d.target == outLatex:
     var fieldname = addNodes(n.sons[0])
     var fieldval = esc(d.target, strip(addNodes(n.sons[1])))
-    if cmpIgnoreStyle(fieldname, "author") == 0 or 
+    if cmpIgnoreStyle(fieldname, "author") == 0 or
        cmpIgnoreStyle(fieldname, "authors") == 0:
       if d.meta[metaAuthor].len == 0:
         d.meta[metaAuthor] = fieldval
         b = true
-    elif cmpIgnoreStyle(fieldname, "version") == 0: 
+    elif cmpIgnoreStyle(fieldname, "version") == 0:
       if d.meta[metaVersion].len == 0:
         d.meta[metaVersion] = fieldval
         b = true
   if not b:
     renderAux(d, n, "<tr>$1</tr>\n", "$1", result)
-  
+
 proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
   if n == nil: return
   case n.kind
@@ -938,54 +947,54 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
   of rnDefBody: renderAux(d, n, "<dd>$1</dd>\n", "$1\n", result)
   of rnFieldList:
     var tmp = ""
-    for i in countup(0, len(n) - 1): 
+    for i in countup(0, len(n) - 1):
       renderRstToOut(d, n.sons[i], tmp)
-    if tmp.len != 0: 
+    if tmp.len != 0:
       dispA(d.target, result,
           "<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>", 
-          "\\begin{description}$1\\end{description}\n", 
+          "</tbody></table>",
+          "\\begin{description}$1\\end{description}\n",
           [tmp])
   of rnField: renderField(d, n, result)
-  of rnFieldName: 
+  of rnFieldName:
     renderAux(d, n, "<th class=\"docinfo-name\">$1:</th>",
                     "\\item[$1:]", result)
-  of rnFieldBody: 
+  of rnFieldBody:
     renderAux(d, n, "<td>$1</td>", " $1\n", result)
-  of rnIndex: 
+  of rnIndex:
     renderRstToOut(d, n.sons[2], result)
-  of rnOptionList: 
-    renderAux(d, n, "<table frame=\"void\">$1</table>", 
+  of rnOptionList:
+    renderAux(d, n, "<table frame=\"void\">$1</table>",
       "\\begin{description}\n$1\\end{description}\n", result)
-  of rnOptionListItem: 
+  of rnOptionListItem:
     renderAux(d, n, "<tr>$1</tr>\n", "$1", result)
-  of rnOptionGroup: 
+  of rnOptionGroup:
     renderAux(d, n, "<th align=\"left\">$1</th>", "\\item[$1]", result)
-  of rnDescription: 
+  of rnDescription:
     renderAux(d, n, "<td align=\"left\">$1</td>\n", " $1\n", result)
-  of rnOption, rnOptionString, rnOptionArgument: 
+  of rnOption, rnOptionString, rnOptionArgument:
     doAssert false, "renderRstToOut"
   of rnLiteralBlock:
-    renderAux(d, n, "<pre>$1</pre>\n", 
+    renderAux(d, n, "<pre>$1</pre>\n",
                     "\\begin{rstpre}\n$1\n\\end{rstpre}\n", result)
-  of rnQuotedLiteralBlock: 
+  of rnQuotedLiteralBlock:
     doAssert false, "renderRstToOut"
-  of rnLineBlock: 
+  of rnLineBlock:
     renderAux(d, n, "<p>$1</p>", "$1\n\n", result)
-  of rnLineBlockItem: 
+  of rnLineBlockItem:
     renderAux(d, n, "$1<br />", "$1\\\\\n", result)
-  of rnBlockQuote: 
-    renderAux(d, n, "<blockquote><p>$1</p></blockquote>\n", 
+  of rnBlockQuote:
+    renderAux(d, n, "<blockquote><p>$1</p></blockquote>\n",
                     "\\begin{quote}$1\\end{quote}\n", result)
-  of rnTable, rnGridTable: 
-    renderAux(d, n, 
-      "<table border=\"1\" class=\"docutils\">$1</table>", 
+  of rnTable, rnGridTable:
+    renderAux(d, n,
+      "<table border=\"1\" class=\"docutils\">$1</table>",
       "\\begin{table}\\begin{rsttab}{" &
         texColumns(n) & "|}\n\\hline\n$1\\end{rsttab}\\end{table}", result)
-  of rnTableRow: 
+  of rnTableRow:
     if len(n) >= 1:
       if d.target == outLatex:
         #var tmp = ""
@@ -998,25 +1007,25 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
         result.add("<tr>")
         renderAux(d, n, result)
         result.add("</tr>\n")
-  of rnTableDataCell: 
+  of rnTableDataCell:
     renderAux(d, n, "<td>$1</td>", "$1", result)
-  of rnTableHeaderCell: 
+  of rnTableHeaderCell:
     renderAux(d, n, "<th>$1</th>", "\\textbf{$1}", result)
-  of rnLabel: 
+  of rnLabel:
     doAssert false, "renderRstToOut" # used for footnotes and other
-  of rnFootnote: 
+  of rnFootnote:
     doAssert false, "renderRstToOut" # a footnote
-  of rnCitation: 
+  of rnCitation:
     doAssert false, "renderRstToOut" # similar to footnote
-  of rnRef: 
+  of rnRef:
     var tmp = ""
     renderAux(d, n, tmp)
     dispA(d.target, result,
       "<a class=\"reference external\" href=\"#$2\">$1</a>",
       "$1\\ref{$2}", [tmp, rstnodeToRefname(n)])
-  of rnStandaloneHyperlink: 
-    renderAux(d, n, 
-      "<a class=\"reference external\" href=\"$1\">$1</a>", 
+  of rnStandaloneHyperlink:
+    renderAux(d, n,
+      "<a class=\"reference external\" href=\"$1\">$1</a>",
       "\\href{$1}{$1}", result)
   of rnHyperlink:
     var tmp0 = ""
@@ -1033,11 +1042,11 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
   of rnRawLatex:
     if d.target == outLatex:
       result.add addNodes(lastSon(n))
-      
+
   of rnImage, rnFigure: renderImage(d, n, result)
   of rnCodeBlock: renderCodeBlock(d, n, result)
   of rnContainer: renderContainer(d, n, result)
-  of rnSubstitutionReferences, rnSubstitutionDef: 
+  of rnSubstitutionReferences, rnSubstitutionDef:
     renderAux(d, n, "|$1|", "|$1|", result)
   of rnDirective:
     renderAux(d, n, "", "", result)
@@ -1054,15 +1063,15 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
   of rnStrongEmphasis:
     renderAux(d, n, "<strong>$1</strong>", "\\textbf{$1}", result)
   of rnTripleEmphasis:
-    renderAux(d, n, "<strong><em>$1</em></strong>", 
+    renderAux(d, n, "<strong><em>$1</em></strong>",
                     "\\textbf{emph{$1}}", result)
   of rnInterpretedText:
     renderAux(d, n, "<cite>$1</cite>", "\\emph{$1}", result)
   of rnIdx:
     renderIndexTerm(d, n, result)
-  of rnInlineLiteral: 
-    renderAux(d, n, 
-      "<tt class=\"docutils literal\"><span class=\"pre\">$1</span></tt>", 
+  of rnInlineLiteral:
+    renderAux(d, n,
+      "<tt class=\"docutils literal\"><span class=\"pre\">$1</span></tt>",
       "\\texttt{$1}", result)
   of rnSmiley: renderSmiley(d, n, result)
   of rnLeaf: result.add(esc(d.target, n.text))
@@ -1073,55 +1082,55 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
 
 # -----------------------------------------------------------------------------
 
-proc getVarIdx(varnames: openArray[string], id: string): int = 
-  for i in countup(0, high(varnames)): 
-    if cmpIgnoreStyle(varnames[i], id) == 0: 
+proc getVarIdx(varnames: openArray[string], id: string): int =
+  for i in countup(0, high(varnames)):
+    if cmpIgnoreStyle(varnames[i], id) == 0:
       return i
   result = -1
 
-proc formatNamedVars*(frmt: string, varnames: openArray[string], 
-                      varvalues: openArray[string]): string = 
+proc formatNamedVars*(frmt: string, varnames: openArray[string],
+                      varvalues: openArray[string]): string =
   var i = 0
   var L = len(frmt)
   result = ""
   var num = 0
-  while i < L: 
-    if frmt[i] == '$': 
+  while i < L:
+    if frmt[i] == '$':
       inc(i)                  # skip '$'
       case frmt[i]
-      of '#': 
+      of '#':
         add(result, varvalues[num])
         inc(num)
         inc(i)
-      of '$': 
+      of '$':
         add(result, "$")
         inc(i)
-      of '0'..'9': 
+      of '0'..'9':
         var j = 0
-        while true: 
+        while true:
           j = (j * 10) + ord(frmt[i]) - ord('0')
           inc(i)
-          if i > L-1 or frmt[i] notin {'0'..'9'}: break 
+          if i > L-1 or frmt[i] notin {'0'..'9'}: break
         if j > high(varvalues) + 1:
           raise newException(ValueError, "invalid index: " & $j)
         num = j
         add(result, varvalues[j - 1])
-      of 'A'..'Z', 'a'..'z', '\x80'..'\xFF': 
+      of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
         var id = ""
-        while true: 
+        while true:
           add(id, frmt[i])
           inc(i)
-          if frmt[i] notin {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}: break 
+          if frmt[i] notin {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}: break
         var idx = getVarIdx(varnames, id)
-        if idx >= 0: 
+        if idx >= 0:
           add(result, varvalues[idx])
         else:
           raise newException(ValueError, "unknown substitution var: " & id)
-      of '{': 
+      of '{':
         var id = ""
         inc(i)
-        while frmt[i] != '}': 
-          if frmt[i] == '\0': 
+        while frmt[i] != '}':
+          if frmt[i] == '\0':
             raise newException(ValueError, "'}' expected")
           add(id, frmt[i])
           inc(i)
@@ -1129,12 +1138,12 @@ proc formatNamedVars*(frmt: string, varnames: openArray[string],
                               # search for the variable:
         var idx = getVarIdx(varnames, id)
         if idx >= 0: add(result, varvalues[idx])
-        else: 
+        else:
           raise newException(ValueError, "unknown substitution var: " & id)
       else:
         raise newException(ValueError, "unknown substitution: $" & $frmt[i])
     var start = i
-    while i < L: 
+    while i < L:
       if frmt[i] != '$': inc(i)
       else: break
     if i-1 >= start: add(result, substr(frmt, start, i - 1))
@@ -1143,7 +1152,7 @@ proc formatNamedVars*(frmt: string, varnames: openArray[string],
 proc defaultConfig*(): StringTableRef =
   ## Returns a default configuration for embedded HTML generation.
   ##
-  ## The returned ``StringTableRef`` contains the paramters used by the HTML
+  ## The returned ``StringTableRef`` contains the parameters used by the HTML
   ## engine to build the final output. For information on what these parameters
   ## are and their purpose, please look up the file ``config/nimdoc.cfg``
   ## bundled with the compiler.
@@ -1154,10 +1163,10 @@ proc defaultConfig*(): StringTableRef =
   ## pages, while this proc returns just the content for procs like
   ## ``rstToHtml`` to generate the bare minimum HTML.
   result = newStringTable(modeStyleInsensitive)
-  
+
   template setConfigVar(key, val: expr) =
     result[key] = val
-  
+
   # If you need to modify these values, it might be worth updating the template
   # file in config/nimdoc.cfg.
   setConfigVar("split.item.toc", "20")
@@ -1205,7 +1214,7 @@ $content
 
 # ---------- forum ---------------------------------------------------------
 
-proc rstToHtml*(s: string, options: TRstParseOptions, 
+proc rstToHtml*(s: string, options: TRstParseOptions,
                 config: StringTableRef): string =
   ## Converts an input rst string into embeddable HTML.
   ##
@@ -1227,13 +1236,13 @@ proc rstToHtml*(s: string, options: TRstParseOptions,
   ## output you have to create your own ``TRstGenerator`` with
   ## ``initRstGenerator`` and related procs.
 
-  proc myFindFile(filename: string): string = 
+  proc myFindFile(filename: string): string =
     # we don't find any files in online mode:
     result = ""
 
   const filen = "input"
   var d: TRstGenerator
-  initRstGenerator(d, outHtml, config, filen, options, myFindFile, 
+  initRstGenerator(d, outHtml, config, filen, options, myFindFile,
                    rst.defaultMsgHandler)
   var dummyHasToc = false
   var rst = rstParse(s, filen, 0, 1, dummyHasToc, options)
@@ -1242,5 +1251,6 @@ proc rstToHtml*(s: string, options: TRstParseOptions,
 
 
 when isMainModule:
-  echo rstToHtml("*Hello* **world**!", {},
-    newStringTable(modeStyleInsensitive))
+  assert rstToHtml("*Hello* **world**!", {},
+    newStringTable(modeStyleInsensitive)) ==
+    "<em>Hello</em> <strong>world</strong>!"
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index deb120372..0c7b84090 100644
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -70,17 +70,20 @@ const
   STDIN_FILENO* = 0  ## File number of stdin;
   STDOUT_FILENO* = 1 ## File number of stdout;
 
-when defined(endb):
-  # to not break bootstrapping again ...
-  type
-    TDIR* {.importc: "DIR", header: "<dirent.h>",
-            final, pure, incompleteStruct.} = object
-      ## A type representing a directory stream.
-else:
-  type
-    TDIR* {.importc: "DIR", header: "<dirent.h>",
-            final, pure.} = object
-      ## A type representing a directory stream.
+  DT_UNKNOWN* = 0 ## Unknown file type.
+  DT_FIFO* = 1    ## Named pipe, or FIFO.
+  DT_CHR* = 2     ## Character device.
+  DT_DIR* = 4     ## Directory.
+  DT_BLK* = 6     ## Block device.
+  DT_REG* = 8     ## Regular file.
+  DT_LNK* = 10    ## Symbolic link.
+  DT_SOCK* = 12   ## UNIX domain socket.
+  DT_WHT* = 14
+
+type
+  TDIR* {.importc: "DIR", header: "<dirent.h>",
+          incompleteStruct.} = object
+    ## A type representing a directory stream.
 
 type
   SocketHandle* = distinct cint # The type used to represent socket descriptors
@@ -91,6 +94,12 @@ type
   Tdirent* {.importc: "struct dirent",
              header: "<dirent.h>", final, pure.} = object ## dirent_t struct
     d_ino*: Tino  ## File serial number.
+    when defined(linux) or defined(macosx) or defined(bsd):
+      d_reclen*: cshort ## Length of this record. (not POSIX)
+      d_type*: int8 ## Type of file; not supported by all filesystem types.
+                    ## (not POSIX)
+      when defined(linux) or defined(bsd):
+        d_off*: TOff  ## Not an offset. Value that ``telldir()`` would return.
     d_name*: array [0..255, char] ## Name of entry.
 
   Tflock* {.importc: "struct flock", final, pure,
@@ -1405,14 +1414,6 @@ var
     ## Report status of stopped child process.
   WEXITSTATUS* {.importc, header: "<sys/wait.h>".}: cint
     ## Return exit status.
-  WIFCONTINUED* {.importc, header: "<sys/wait.h>".}: cint
-    ## True if child has been continued.
-  WIFEXITED* {.importc, header: "<sys/wait.h>".}: cint
-    ## True if child exited normally.
-  WIFSIGNALED* {.importc, header: "<sys/wait.h>".}: cint
-    ## True if child exited due to uncaught signal.
-  WIFSTOPPED* {.importc, header: "<sys/wait.h>".}: cint
-    ## True if child is currently stopped.
   WSTOPSIG* {.importc, header: "<sys/wait.h>".}: cint
     ## Return signal number that caused process to stop.
   WTERMSIG* {.importc, header: "<sys/wait.h>".}: cint
@@ -1559,6 +1560,14 @@ var
   MSG_OOB* {.importc, header: "<sys/socket.h>".}: cint
     ## Out-of-band data.
 
+proc WIFCONTINUED*(s:cint) : bool {.importc, header: "<sys/wait.h>".}
+  ## True if child has been continued.
+proc WIFEXITED*(s:cint) : bool {.importc, header: "<sys/wait.h>".}
+  ## True if child exited normally.
+proc WIFSIGNALED*(s:cint) : bool {.importc, header: "<sys/wait.h>".}
+  ## True if child exited due to uncaught signal.
+proc WIFSTOPPED*(s:cint) : bool {.importc, header: "<sys/wait.h>".}
+  ## True if child is currently stopped.
 
 when defined(linux):
   var
@@ -1570,9 +1579,12 @@ else:
 
 
 when defined(macosx):
+  # We can't use the NOSIGNAL flag in the ``send`` function, it has no effect
+  # Instead we should use SO_NOSIGPIPE in setsockopt
+  const
+    MSG_NOSIGNAL* = 0'i32
   var
-    MSG_HAVEMORE* {.importc, header: "<sys/socket.h>".}: cint
-    MSG_NOSIGNAL* = MSG_HAVEMORE
+    SO_NOSIGPIPE* {.importc, header: "<sys/socket.h>".}: cint
 else:
   var
     MSG_NOSIGNAL* {.importc, header: "<sys/socket.h>".}: cint
@@ -1739,7 +1751,10 @@ when hasSpawnH:
   when defined(linux):
     # better be safe than sorry; Linux has this flag, macosx doesn't, don't
     # know about the other OSes
-    var POSIX_SPAWN_USEVFORK* {.importc, header: "<spawn.h>".}: cint
+
+    # Non-GNU systems like TCC and musl-libc  don't define __USE_GNU, so we
+    # can't get the magic number from spawn.h
+    const POSIX_SPAWN_USEVFORK* = cint(0x40)
   else:
     # macosx lacks this, so we define the constant to be 0 to not affect
     # OR'ing of flags:
diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim
new file mode 100644
index 000000000..710b2fa6b
--- /dev/null
+++ b/lib/posix/termios.nim
@@ -0,0 +1,261 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+{.deadCodeElim: on.}
+import posix
+
+type
+  Speed* = cuint
+  Tcflag* = cuint
+
+const
+  NCCS* = 32
+
+type
+  Termios* {.importc: "struct termios", header: "<termios.h>".} = object
+    c_iflag*: Tcflag        # input mode flags
+    c_oflag*: Tcflag        # output mode flags
+    c_cflag*: Tcflag        # control mode flags
+    c_lflag*: Tcflag        # local mode flags
+    c_line*: cuchar         # line discipline
+    c_cc*: array[NCCS, cuchar]  # control characters
+
+# cc characters
+
+const
+  VINTR* = 0
+  VQUIT* = 1
+  VERASE* = 2
+  VKILL* = 3
+  VEOF* = 4
+  VTIME* = 5
+  VMIN* = 6
+  VSWTC* = 7
+  VSTART* = 8
+  VSTOP* = 9
+  VSUSP* = 10
+  VEOL* = 11
+  VREPRINT* = 12
+  VDISCARD* = 13
+  VWERASE* = 14
+  VLNEXT* = 15
+  VEOL2* = 16
+
+# iflag bits
+
+const
+  IGNBRK* = 1
+  BRKINT* = 2
+  IGNPAR* = 4
+  PARMRK* = 10
+  INPCK* = 20
+  ISTRIP* = 40
+  INLCR* = 100
+  IGNCR* = 200
+  ICRNL* = 400
+  IUCLC* = 1000
+  IXON* = 2000
+  IXANY* = 4000
+  IXOFF* = 10000
+  IMAXBEL* = 20000
+  IUTF8* = 40000
+
+# oflag bits
+
+const
+  OPOST* = 1
+  OLCUC* = 2
+  ONLCR* = 4
+  OCRNL* = 10
+  ONOCR* = 20
+  ONLRET* = 40
+  OFILL* = 100
+  OFDEL* = 200
+  NLDLY* = 400
+  NL0* = 0
+  NL1* = 400
+  CRDLY* = 3000
+  CR0* = 0
+  CR1* = 1000
+  CR2* = 2000
+  CR3* = 3000
+  TABDLY* = 14000
+  TAB0* = 0
+  TAB1* = 4000
+  TAB2* = 10000
+  TAB3* = 14000
+  BSDLY* = 20000
+  BS0* = 0
+  BS1* = 20000
+  FFDLY* = 0o000000100000
+  FF0* = 0
+  FF1* = 0o000000100000
+  VTDLY* = 40000
+  VT0* = 0
+  VT1* = 40000
+  XTABS* = 14000
+
+# cflag bit meaning
+
+const
+  CBAUD* = 10017
+  B0* = 0
+  B50* = 1
+  B75* = 2
+  B110* = 3
+  B134* = 4
+  B150* = 5
+  B200* = 6
+  B300* = 7
+  B600* = 10
+  B1200* = 11
+  B1800* = 12
+  B2400* = 13
+  B4800* = 14
+  B9600* = 15
+  B19200* = 16
+  B38400* = 17
+  EXTA* = B19200
+  EXTB* = B38400
+  CSIZE* = 60
+  CS5* = 0
+  CS6* = 20
+  CS7* = 40
+  CS8* = 60
+  CSTOPB* = 100
+  CREAD* = 200
+  PARENB* = 400
+  PARODD* = 1000
+  HUPCL* = 2000
+  CLOCAL* = 4000
+  CBAUDEX* = 10000
+  B57600* = 10001
+  B115200* = 10002
+  B230400* = 10003
+  B460800* = 10004
+  B500000* = 10005
+  B576000* = 10006
+  B921600* = 10007
+  B1000000* = 10010
+  B1152000* = 10011
+  B1500000* = 10012
+  B2000000* = 10013
+  B2500000* = 10014
+  B3000000* = 10015
+  B3500000* = 10016
+  B4000000* = 10017
+  MAX_BAUD* = B4000000
+  CIBAUD* = 2003600000
+  CMSPAR* = 0o010000000000
+  CRTSCTS* = 0o020000000000
+
+# lflag bits
+
+const
+  ISIG* = 1
+  ICANON* = 2
+  XCASE* = 4
+  ECHO* = 10
+  ECHOE* = 20
+  ECHOK* = 40
+  ECHONL* = 100
+  NOFLSH* = 200
+  TOSTOP* = 400
+  ECHOCTL* = 1000
+  ECHOPRT* = 2000
+  ECHOKE* = 4000
+  FLUSHO* = 10000
+  PENDIN* = 40000
+  IEXTEN* = 0o000000100000
+  EXTPROC* = 0o000000200000
+
+# tcflow() and TCXONC use these
+
+const
+  TCOOFF* = 0
+  TCOON* = 1
+  TCIOFF* = 2
+  TCION* = 3
+
+# tcflush() and TCFLSH use these
+
+const
+  TCIFLUSH* = 0
+  TCOFLUSH* = 1
+  TCIOFLUSH* = 2
+
+# tcsetattr uses these
+
+const
+  TCSANOW* = 0
+  TCSADRAIN* = 1
+  TCSAFLUSH* = 2
+
+# Compare a character C to a value VAL from the `cc' array in a
+#   `struct termios'.  If VAL is _POSIX_VDISABLE, no character can match it.
+
+template cceq*(val, c: expr): expr =
+  c == val and val != POSIX_VDISABLE
+
+# Return the output baud rate stored in *TERMIOS_P.
+
+proc cfGetOspeed*(termios: ptr Termios): Speed {.importc: "cfgetospeed",
+    header: "<termios.h>".}
+# Return the input baud rate stored in *TERMIOS_P.
+
+proc cfGetIspeed*(termios: ptr Termios): Speed {.importc: "cfgetispeed",
+    header: "<termios.h>".}
+# Set the output baud rate stored in *TERMIOS_P to SPEED.
+
+proc cfSetOspeed*(termios: ptr Termios; speed: Speed): cint {.
+    importc: "cfsetospeed", header: "<termios.h>".}
+# Set the input baud rate stored in *TERMIOS_P to SPEED.
+
+proc cfSetIspeed*(termios: ptr Termios; speed: Speed): cint {.
+    importc: "cfsetispeed", header: "<termios.h>".}
+# Set both the input and output baud rates in *TERMIOS_OP to SPEED.
+
+proc cfSetSpeed*(termios: ptr Termios; speed: Speed): cint {.
+    importc: "cfsetspeed", header: "<termios.h>".}
+# Put the state of FD into *TERMIOS_P.
+
+proc tcGetAttr*(fd: cint; termios: ptr Termios): cint {.
+    importc: "tcgetattr", header: "<termios.h>".}
+# Set the state of FD to *TERMIOS_P.
+#   Values for OPTIONAL_ACTIONS (TCSA*) are in <bits/termios.h>.
+
+proc tcSetAttr*(fd: cint; optional_actions: cint; termios: ptr Termios): cint {.
+    importc: "tcsetattr", header: "<termios.h>".}
+# Set *TERMIOS_P to indicate raw mode.
+
+proc cfMakeRaw*(termios: ptr Termios) {.importc: "cfmakeraw",
+    header: "<termios.h>".}
+# Send zero bits on FD.
+
+proc tcSendBreak*(fd: cint; duration: cint): cint {.importc: "tcsendbreak",
+    header: "<termios.h>".}
+# Wait for pending output to be written on FD.
+#
+#   This function is a cancellation point and therefore not marked with
+#  .
+
+proc tcDrain*(fd: cint): cint {.importc: "tcdrain", header: "<termios.h>".}
+# Flush pending data on FD.
+#   Values for QUEUE_SELECTOR (TC{I,O,IO}FLUSH) are in <bits/termios.h>.
+
+proc tcFlush*(fd: cint; queue_selector: cint): cint {.importc: "tcflush",
+    header: "<termios.h>".}
+# Suspend or restart transmission on FD.
+#   Values for ACTION (TC[IO]{OFF,ON}) are in <bits/termios.h>.
+
+proc tcFlow*(fd: cint; action: cint): cint {.importc: "tcflow",
+    header: "<termios.h>".}
+# Get process group ID for session leader for controlling terminal FD.
+
+proc tcGetSid*(fd: cint): TPid {.importc: "tcgetsid", header: "<termios.h>".}
diff --git a/lib/pure/actors.nim b/lib/pure/actors.nim
index f2c50ce4c..294c24741 100644
--- a/lib/pure/actors.nim
+++ b/lib/pure/actors.nim
@@ -200,7 +200,7 @@ template schedule =
   if minIdx >= 0:
     p.actors[minIdx].i.send(t)
   else:
-    raise newException(EDeadThread, "cannot send message; thread died")
+    raise newException(DeadThreadError, "cannot send message; thread died")
 
 proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut], input: TIn,
                        action: proc (input: TIn): TOut {.thread.}
@@ -221,7 +221,7 @@ proc spawn*[TIn](p: var TActorPool[TIn, void], input: TIn,
   setupTask()
   schedule()
   
-when isMainModule:
+when not defined(testing) and isMainModule:
   var
     a: TActorPool[int, void]
   createActorPool(a)
diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim
index 0358a9a81..f7ccb9234 100644
--- a/lib/pure/algorithm.nim
+++ b/lib/pure/algorithm.nim
@@ -11,20 +11,20 @@
 
 type
   SortOrder* = enum   ## sort order
-    Descending, Ascending 
+    Descending, Ascending
 
 {.deprecated: [TSortOrder: SortOrder].}
 
 
-proc `*`*(x: int, order: SortOrder): int {.inline.} = 
+proc `*`*(x: int, order: SortOrder): int {.inline.} =
   ## flips `x` if ``order == Descending``;
   ## if ``order == Ascending`` then `x` is returned.
-  ## `x` is supposed to be the result of a comparator, ie ``< 0`` for 
+  ## `x` is supposed to be the result of a comparator, ie ``< 0`` for
   ## *less than*, ``== 0`` for *equal*, ``> 0`` for *greater than*.
   var y = order.ord - 1
   result = (x xor y) - y
 
-proc reverse*[T](a: var openArray[T], first, last: int) =
+proc reverse*[T](a: var openArray[T], first, last: Natural) =
   ## reverses the array ``a[first..last]``.
   var x = first
   var y = last
@@ -37,11 +37,11 @@ proc reverse*[T](a: var openArray[T]) =
   ## reverses the array `a`.
   reverse(a, 0, a.high)
 
-proc reversed*[T](a: openArray[T], first, last: int): seq[T] =
+proc reversed*[T](a: openArray[T], first, last: Natural): seq[T] =
   ## returns the reverse of the array `a[first..last]`.
   result = newSeq[T](last - first + 1)
-  var x = first
-  var y = last
+  var x = first.int
+  var y = last.int
   while x <= last:
     result[x] = a[y]
     dec(y)
@@ -73,14 +73,15 @@ const
   onlySafeCode = true
 
 proc lowerBound*[T](a: openArray[T], key: T, cmp: proc(x,y: T): int {.closure.}): int =
-  ## same as binarySearch except that if key is not in `a` then this 
+  ## same as binarySearch except that if key is not in `a` then this
   ## returns the location where `key` would be if it were. In other
-  ## words if you have a sorted sequence and you call insert(thing, elm, lowerBound(thing, elm))
-  ## the sequence will still be sorted
+  ## words if you have a sorted sequence and you call
+  ## insert(thing, elm, lowerBound(thing, elm))
+  ## the sequence will still be sorted.
+  ##
+  ## `cmp` is the comparator function to use, the expected return values are
+  ## the same as that of system.cmp.
   ##
-  ## `cmp` is the comparator function to use, the expected return values are the same as
-  ## that of system.cmp
-  ## 
   ## example::
   ##
   ##   var arr = @[1,2,3,5,6,7,8,9]
@@ -102,9 +103,9 @@ proc lowerBound*[T](a: openArray[T], key: T, cmp: proc(x,y: T): int {.closure.})
       count = step
 
 proc lowerBound*[T](a: openArray[T], key: T): int = lowerBound(a, key, cmp[T])
-proc merge[T](a, b: var openArray[T], lo, m, hi: int, 
+proc merge[T](a, b: var openArray[T], lo, m, hi: int,
               cmp: proc (x, y: T): int {.closure.}, order: SortOrder) =
-  template `<-` (a, b: expr) = 
+  template `<-` (a, b: expr) =
     when false:
       a = b
     elif onlySafeCode:
@@ -151,10 +152,10 @@ proc merge[T](a, b: var openArray[T], lo, m, hi: int,
 proc sort*[T](a: var openArray[T],
               cmp: proc (x, y: T): int {.closure.},
               order = SortOrder.Ascending) =
-  ## Default Nim sort. The sorting is guaranteed to be stable and 
+  ## Default Nim sort. The sorting is guaranteed to be stable and
   ## the worst case is guaranteed to be O(n log n).
   ## The current implementation uses an iterative
-  ## mergesort to achieve this. It uses a temporary sequence of 
+  ## mergesort to achieve this. It uses a temporary sequence of
   ## length ``a.len div 2``. Currently Nim does not support a
   ## sensible default argument for ``cmp``, so you have to provide one
   ## of your own. However, the ``system.cmp`` procs can be used:
@@ -187,6 +188,48 @@ proc sort*[T](a: var openArray[T],
       dec(m, s*2)
     s = s*2
 
+proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.},
+                order = SortOrder.Ascending): seq[T] =
+  ## returns `a` sorted by `cmp` in the specified `order`.
+  result = newSeq[T](a.len)
+  for i in 0 .. a.high:
+    result[i] = a[i]
+  sort(result, cmp, order)
+
+template sortedByIt*(seq1, op: expr): expr =
+  ## Convenience template around the ``sorted`` proc to reduce typing.
+  ##
+  ## The template injects the ``it`` variable which you can use directly in an
+  ## expression. Example:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   type Person = tuple[name: string, age: int]
+  ##   var
+  ##     p1: Person = (name: "p1", age: 60)
+  ##     p2: Person = (name: "p2", age: 20)
+  ##     p3: Person = (name: "p3", age: 30)
+  ##     p4: Person = (name: "p4", age: 30)
+  ##
+  ##   people = @[p1,p2,p4,p3]
+  ##
+  ##   echo people.sortedByIt(it.name)
+  ##
+  ## Because the underlying ``cmp()`` is defined for tuples you can do
+  ## a nested sort like in the following example:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   echo people.sortedByIt((it.age, it.name))
+  ##
+  var result {.gensym.} = sorted(seq1, proc(x, y: type(seq1[0])): int =
+    var it {.inject.} = x
+    let a = op
+    it = y
+    let b = op
+    result = cmp(a, b))
+  result
+
 proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
   ## produces the Cartesian product of the array. Warning: complexity
   ## may explode.
@@ -210,13 +253,72 @@ proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
   while true:
     while indexes[index] == -1:
       indexes[index] = initial[index]
-      index +=1
+      index += 1
       if index == x.len: return
-      indexes[index] -=1
+      indexes[index] -= 1
     for ni, i in indexes:
       next[ni] = x[ni][i]
     var res: seq[T]
     shallowCopy(res, next)
     result.add(res)
     index = 0
-    indexes[index] -=1
+    indexes[index] -= 1
+
+proc nextPermutation*[T](x: var openarray[T]): bool {.discardable.} =
+  ## Calculates the next lexicographic permutation, directly modifying ``x``.
+  ## The result is whether a permutation happened, otherwise we have reached
+  ## the last-ordered permutation.
+  ##
+  ## .. code-block:: nim
+  ##
+  ##     var v = @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+  ##     v.nextPermutation()
+  ##     echo v
+  if x.len < 2:
+    return false
+
+  var i = x.high
+  while i > 0 and x[i-1] >= x[i]:
+    dec i
+
+  if i == 0:
+    return false
+
+  var j = x.high
+  while j >= i and x[j] <= x[i-1]:
+    dec j
+
+  swap x[j], x[i-1]
+  x.reverse(i, x.high)
+
+  result = true
+
+proc prevPermutation*[T](x: var openarray[T]): bool {.discardable.} =
+  ## Calculates the previous lexicographic permutation, directly modifying
+  ## ``x``.  The result is whether a permutation happened, otherwise we have
+  ## reached the first-ordered permutation.
+  ##
+  ## .. code-block:: nim
+  ##
+  ##     var v = @[0, 1, 2, 3, 4, 5, 6, 7, 9, 8]
+  ##     v.prevPermutation()
+  ##     echo v
+  if x.len < 2:
+    return false
+
+  var i = x.high
+  while i > 0 and x[i-1] <= x[i]:
+    dec i
+
+  if i == 0:
+    return false
+
+  x.reverse(i, x.high)
+
+  var j = x.high
+  while j >= i and x[j-1] < x[i-1]:
+    dec j
+
+  swap x[i-1], x[j]
+
+  result = true
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 41b20cb35..27f77cef2 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Dominik Picheta
+#        (c) Copyright 2015 Dominik Picheta
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -121,7 +121,7 @@ export Port, SocketFlag
 ##
 ## Limitations/Bugs
 ## ----------------
-## 
+##
 ## * ``except`` statement (without `try`) does not work inside async procedures.
 ## * The effect system (``raises: []``) does not work with async procedures.
 ## * Can't await in a ``except`` body
@@ -379,7 +379,7 @@ when defined(windows) or defined(nimdoc):
     if p.handles.len == 0 and p.timers.len == 0:
       raise newException(ValueError,
         "No handles or timers registered in dispatcher.")
-    
+
     let llTimeout =
       if timeout ==  -1: winlean.INFINITE
       else: timeout.int32
@@ -419,12 +419,12 @@ when defined(windows) or defined(nimdoc):
   var acceptExPtr: pointer = nil
   var getAcceptExSockAddrsPtr: pointer = nil
 
-  proc initPointer(s: SocketHandle, func: var pointer, guid: var TGUID): bool =
+  proc initPointer(s: SocketHandle, fun: var pointer, guid: var TGUID): bool =
     # Ref: https://github.com/powdahound/twisted/blob/master/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.c
     var bytesRet: Dword
-    func = nil
+    fun = nil
     result = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, addr guid,
-                      sizeof(TGUID).Dword, addr func, sizeof(pointer).Dword,
+                      sizeof(TGUID).Dword, addr fun, sizeof(pointer).Dword,
                       addr bytesRet, nil, nil) == 0
 
   proc initAll() =
@@ -436,16 +436,16 @@ when defined(windows) or defined(nimdoc):
     if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS):
       raiseOSError(osLastError())
 
-  proc connectEx(s: SocketHandle, name: ptr TSockAddr, namelen: cint, 
+  proc connectEx(s: SocketHandle, name: ptr SockAddr, namelen: cint,
                   lpSendBuffer: pointer, dwSendDataLength: Dword,
                   lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool =
     if connectExPtr.isNil: raise newException(ValueError, "Need to initialise ConnectEx().")
-    let func =
-      cast[proc (s: SocketHandle, name: ptr TSockAddr, namelen: cint, 
+    let fun =
+      cast[proc (s: SocketHandle, name: ptr SockAddr, namelen: cint,
          lpSendBuffer: pointer, dwSendDataLength: Dword,
          lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](connectExPtr)
 
-    result = func(s, name, namelen, lpSendBuffer, dwSendDataLength, lpdwBytesSent,
+    result = fun(s, name, namelen, lpSendBuffer, dwSendDataLength, lpdwBytesSent,
          lpOverlapped)
 
   proc acceptEx(listenSock, acceptSock: SocketHandle, lpOutputBuffer: pointer,
@@ -453,30 +453,30 @@ when defined(windows) or defined(nimdoc):
                  dwRemoteAddressLength: Dword, lpdwBytesReceived: PDword,
                  lpOverlapped: POVERLAPPED): bool =
     if acceptExPtr.isNil: raise newException(ValueError, "Need to initialise AcceptEx().")
-    let func =
+    let fun =
       cast[proc (listenSock, acceptSock: SocketHandle, lpOutputBuffer: pointer,
                  dwReceiveDataLength, dwLocalAddressLength,
                  dwRemoteAddressLength: Dword, lpdwBytesReceived: PDword,
                  lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](acceptExPtr)
-    result = func(listenSock, acceptSock, lpOutputBuffer, dwReceiveDataLength,
+    result = fun(listenSock, acceptSock, lpOutputBuffer, dwReceiveDataLength,
         dwLocalAddressLength, dwRemoteAddressLength, lpdwBytesReceived,
         lpOverlapped)
 
   proc getAcceptExSockaddrs(lpOutputBuffer: pointer,
       dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength: Dword,
-      LocalSockaddr: ptr ptr TSockAddr, LocalSockaddrLength: LPInt,
-      RemoteSockaddr: ptr ptr TSockAddr, RemoteSockaddrLength: LPInt) =
+      LocalSockaddr: ptr ptr SockAddr, LocalSockaddrLength: LPInt,
+      RemoteSockaddr: ptr ptr SockAddr, RemoteSockaddrLength: LPInt) =
     if getAcceptExSockAddrsPtr.isNil:
       raise newException(ValueError, "Need to initialise getAcceptExSockAddrs().")
 
-    let func =
+    let fun =
       cast[proc (lpOutputBuffer: pointer,
                  dwReceiveDataLength, dwLocalAddressLength,
-                 dwRemoteAddressLength: Dword, LocalSockaddr: ptr ptr TSockAddr,
-                 LocalSockaddrLength: LPInt, RemoteSockaddr: ptr ptr TSockAddr,
+                 dwRemoteAddressLength: Dword, LocalSockaddr: ptr ptr SockAddr,
+                 LocalSockaddrLength: LPInt, RemoteSockaddr: ptr ptr SockAddr,
                 RemoteSockaddrLength: LPInt) {.stdcall,gcsafe.}](getAcceptExSockAddrsPtr)
-    
-    func(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength,
+
+    fun(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength,
                   dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength,
                   RemoteSockaddr, RemoteSockaddrLength)
 
@@ -489,12 +489,12 @@ when defined(windows) or defined(nimdoc):
     verifyPresence(socket)
     var retFuture = newFuture[void]("connect")
     # Apparently ``ConnectEx`` expects the socket to be initially bound:
-    var saddr: Tsockaddr_in
+    var saddr: Sockaddr_in
     saddr.sin_family = int16(toInt(af))
     saddr.sin_port = 0
     saddr.sin_addr.s_addr = INADDR_ANY
-    if bindAddr(socket.SocketHandle, cast[ptr TSockAddr](addr(saddr)),
-                  sizeof(saddr).TSockLen) < 0'i32:
+    if bindAddr(socket.SocketHandle, cast[ptr SockAddr](addr(saddr)),
+                  sizeof(saddr).SockLen) < 0'i32:
       raiseOSError(osLastError())
 
     var aiList = getAddrInfo(address, port, af)
@@ -514,9 +514,9 @@ when defined(windows) or defined(nimdoc):
             else:
               retFuture.fail(newException(OSError, osErrorMsg(errcode)))
       )
-      
+
       var ret = connectEx(socket.SocketHandle, it.ai_addr,
-                          sizeof(Tsockaddr_in).cint, nil, 0, nil,
+                          sizeof(Sockaddr_in).cint, nil, 0, nil,
                           cast[POVERLAPPED](ol))
       if ret:
         # Request to connect completed immediately.
@@ -565,7 +565,7 @@ when defined(windows) or defined(nimdoc):
     var dataBuf: TWSABuf
     dataBuf.buf = cast[cstring](alloc0(size))
     dataBuf.len = size
-    
+
     var bytesReceived: Dword
     var flagsio = flags.toOSFlags().Dword
     var ol = PCustomOverlapped()
@@ -606,15 +606,15 @@ when defined(windows) or defined(nimdoc):
           retFuture.fail(newException(OSError, osErrorMsg(err)))
     elif ret == 0 and bytesReceived == 0 and dataBuf.buf[0] == '\0':
       # We have to ensure that the buffer is empty because WSARecv will tell
-      # us immediatelly when it was disconnected, even when there is still
+      # us immediately when it was disconnected, even when there is still
       # data in the buffer.
       # We want to give the user as much data as we can. So we only return
       # the empty string (which signals a disconnection) when there is
       # nothing left to read.
       retFuture.complete("")
-      # TODO: "For message-oriented sockets, where a zero byte message is often 
-      # allowable, a failure with an error code of WSAEDISCON is used to 
-      # indicate graceful closure." 
+      # TODO: "For message-oriented sockets, where a zero byte message is often
+      # allowable, a failure with an error code of WSAEDISCON is used to
+      # indicate graceful closure."
       # ~ http://msdn.microsoft.com/en-us/library/ms741688%28v=vs.85%29.aspx
     else:
       # Request to read completed immediately.
@@ -700,17 +700,17 @@ when defined(windows) or defined(nimdoc):
     var lpOutputBuf = newString(lpOutputLen)
     var dwBytesReceived: Dword
     let dwReceiveDataLength = 0.Dword # We don't want any data to be read.
-    let dwLocalAddressLength = Dword(sizeof (Tsockaddr_in) + 16)
-    let dwRemoteAddressLength = Dword(sizeof(Tsockaddr_in) + 16)
+    let dwLocalAddressLength = Dword(sizeof (Sockaddr_in) + 16)
+    let dwRemoteAddressLength = Dword(sizeof(Sockaddr_in) + 16)
 
     template completeAccept(): stmt {.immediate, dirty.} =
       var listenSock = socket
       let setoptRet = setsockopt(clientSock, SOL_SOCKET,
           SO_UPDATE_ACCEPT_CONTEXT, addr listenSock,
-          sizeof(listenSock).TSockLen)
+          sizeof(listenSock).SockLen)
       if setoptRet != 0: raiseOSError(osLastError())
 
-      var localSockaddr, remoteSockaddr: ptr TSockAddr
+      var localSockaddr, remoteSockaddr: ptr SockAddr
       var localLen, remoteLen: int32
       getAcceptExSockaddrs(addr lpOutputBuf[0], dwReceiveDataLength,
                            dwLocalAddressLength, dwRemoteAddressLength,
@@ -719,7 +719,7 @@ when defined(windows) or defined(nimdoc):
       register(clientSock.TAsyncFD)
       # TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186
       retFuture.complete(
-        (address: $inet_ntoa(cast[ptr Tsockaddr_in](remoteSockAddr).sin_addr),
+        (address: $inet_ntoa(cast[ptr Sockaddr_in](remoteSockAddr).sin_addr),
          client: clientSock.TAsyncFD)
       )
 
@@ -748,7 +748,7 @@ when defined(windows) or defined(nimdoc):
 
     # http://msdn.microsoft.com/en-us/library/windows/desktop/ms737524%28v=vs.85%29.aspx
     let ret = acceptEx(socket.SocketHandle, clientSock, addr lpOutputBuf[0],
-                       dwReceiveDataLength, 
+                       dwReceiveDataLength,
                        dwLocalAddressLength,
                        dwRemoteAddressLength,
                        addr dwBytesReceived, cast[POVERLAPPED](ol))
@@ -803,7 +803,7 @@ else:
   else:
     from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK,
                       MSG_NOSIGNAL
-  
+
   type
     TAsyncFD* = distinct cint
     TCallback = proc (fd: TAsyncFD): bool {.closure,gcsafe.}
@@ -841,6 +841,8 @@ else:
   proc newAsyncRawSocket*(domain: cint, typ: cint, protocol: cint): TAsyncFD =
     result = newRawSocket(domain, typ, protocol).TAsyncFD
     result.SocketHandle.setBlocking(false)
+    when defined(macosx):
+        result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
     register(result)
 
   proc newAsyncRawSocket*(domain: Domain = AF_INET,
@@ -848,8 +850,10 @@ else:
                protocol: Protocol = IPPROTO_TCP): TAsyncFD =
     result = newRawSocket(domain, typ, protocol).TAsyncFD
     result.SocketHandle.setBlocking(false)
+    when defined(macosx):
+        result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
     register(result)
-  
+
   proc closeSocket*(sock: TAsyncFD) =
     let disp = getGlobalDispatcher()
     sock.SocketHandle.close()
@@ -864,20 +868,24 @@ else:
       raise newException(ValueError, "File descriptor not registered.")
     p.selector[fd.SocketHandle].data.PData.readCBs.add(cb)
     update(fd, p.selector[fd.SocketHandle].events + {EvRead})
-  
+
   proc addWrite*(fd: TAsyncFD, cb: TCallback) =
     let p = getGlobalDispatcher()
     if fd.SocketHandle notin p.selector:
       raise newException(ValueError, "File descriptor not registered.")
     p.selector[fd.SocketHandle].data.PData.writeCBs.add(cb)
     update(fd, p.selector[fd.SocketHandle].events + {EvWrite})
-  
+
   proc poll*(timeout = 500) =
     let p = getGlobalDispatcher()
     for info in p.selector.select(timeout):
       let data = PData(info.key.data)
       assert data.fd == info.key.fd.TAsyncFD
       #echo("In poll ", data.fd.cint)
+      if EvError in info.events:
+        closeSocket(data.fd)
+        continue
+
       if EvRead in info.events:
         # Callback may add items to ``data.readCBs`` which causes issues if
         # we are iterating over ``data.readCBs`` at the same time. We therefore
@@ -888,7 +896,7 @@ else:
           if not cb(data.fd):
             # Callback wants to be called again.
             data.readCBs.add(cb)
-      
+
       if EvWrite in info.events:
         let currentCBs = data.writeCBs
         data.writeCBs = @[]
@@ -896,7 +904,7 @@ else:
           if not cb(data.fd):
             # Callback wants to be called again.
             data.writeCBs.add(cb)
-      
+
       if info.key in p.selector:
         var newEvents: set[Event]
         if data.readCBs.len != 0: newEvents = {EvRead}
@@ -909,16 +917,16 @@ else:
         discard
 
     processTimers(p)
-  
+
   proc connect*(socket: TAsyncFD, address: string, port: Port,
     af = AF_INET): Future[void] =
     var retFuture = newFuture[void]("connect")
-    
+
     proc cb(fd: TAsyncFD): bool =
       # We have connected.
       retFuture.complete()
       return true
-    
+
     var aiList = getAddrInfo(address, port, af)
     var success = false
     var lastError: OSErrorCode
@@ -948,14 +956,13 @@ else:
   proc recv*(socket: TAsyncFD, size: int,
              flags = {SocketFlag.SafeDisconn}): Future[string] =
     var retFuture = newFuture[string]("recv")
-    
+
     var readBuffer = newString(size)
 
     proc cb(sock: TAsyncFD): bool =
       result = true
       let res = recv(sock.SocketHandle, addr readBuffer[0], size.cint,
                      flags.toOSFlags())
-      #echo("recv cb res: ", res)
       if res < 0:
         let lastError = osLastError()
         if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}:
@@ -979,9 +986,9 @@ else:
   proc send*(socket: TAsyncFD, data: string,
              flags = {SocketFlag.SafeDisconn}): Future[void] =
     var retFuture = newFuture[void]("send")
-    
+
     var written = 0
-    
+
     proc cb(sock: TAsyncFD): bool =
       result = true
       let netSize = data.len-written
@@ -1060,6 +1067,17 @@ proc accept*(socket: TAsyncFD,
 
 # -- Await Macro
 
+proc skipUntilStmtList(node: NimNode): NimNode {.compileTime.} =
+  # Skips a nest of StmtList's.
+  result = node
+  if node[0].kind == nnkStmtList:
+    result = skipUntilStmtList(node[0])
+
+proc skipStmtList(node: NimNode): NimNode {.compileTime.} =
+  result = node
+  if node[0].kind == nnkStmtList:
+    result = node[0]
+
 template createCb(retFutureSym, iteratorNameSym,
                    name: expr): stmt {.immediate.} =
   var nameIterVar = iteratorNameSym
@@ -1083,11 +1101,11 @@ template createCb(retFutureSym, iteratorNameSym,
   cb()
   #{.pop.}
 proc generateExceptionCheck(futSym,
-    tryStmt, rootReceiver, fromNode: PNimrodNode): PNimrodNode {.compileTime.} =
+    tryStmt, rootReceiver, fromNode: NimNode): NimNode {.compileTime.} =
   if tryStmt.kind == nnkNilLit:
     result = rootReceiver
   else:
-    var exceptionChecks: seq[tuple[cond, body: PNimrodNode]] = @[]
+    var exceptionChecks: seq[tuple[cond, body: NimNode]] = @[]
     let errorNode = newDotExpr(futSym, newIdentNode("error"))
     for i in 1 .. <tryStmt.len:
       let exceptBranch = tryStmt[i]
@@ -1095,7 +1113,7 @@ proc generateExceptionCheck(futSym,
         exceptionChecks.add((newIdentNode("true"), exceptBranch[0]))
       else:
         var exceptIdentCount = 0
-        var ifCond: PNimrodNode
+        var ifCond: NimNode
         for i in 0 .. <exceptBranch.len:
           let child = exceptBranch[i]
           if child.kind == nnkIdent:
@@ -1129,10 +1147,10 @@ proc generateExceptionCheck(futSym,
     )
     result.add elseNode
 
-template createVar(result: var PNimrodNode, futSymName: string,
-                   asyncProc: PNimrodNode,
+template createVar(result: var NimNode, futSymName: string,
+                   asyncProc: NimNode,
                    valueReceiver, rootReceiver: expr,
-                   fromNode: PNimrodNode) =
+                   fromNode: NimNode) =
   result = newNimNode(nnkStmtList, fromNode)
   var futSym = genSym(nskVar, "future")
   result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y
@@ -1140,9 +1158,9 @@ template createVar(result: var PNimrodNode, futSymName: string,
   valueReceiver = newDotExpr(futSym, newIdentNode("read")) # -> future<x>.read
   result.add generateExceptionCheck(futSym, tryStmt, rootReceiver, fromNode)
 
-proc processBody(node, retFutureSym: PNimrodNode,
+proc processBody(node, retFutureSym: NimNode,
                  subTypeIsVoid: bool,
-                 tryStmt: PNimrodNode): PNimrodNode {.compileTime.} =
+                 tryStmt: NimNode): NimNode {.compileTime.} =
   #echo(node.treeRepr)
   result = node
   case node.kind
@@ -1168,7 +1186,7 @@ proc processBody(node, retFutureSym: PNimrodNode,
         result = newNimNode(nnkYieldStmt, node).add(node[1]) # -> yield x
       of nnkCall, nnkCommand:
         # await foo(p, x)
-        var futureValue: PNimrodNode
+        var futureValue: NimNode
         result.createVar("future" & $node[1][0].toStrLit, node[1], futureValue,
                   futureValue, node)
       else:
@@ -1207,33 +1225,60 @@ proc processBody(node, retFutureSym: PNimrodNode,
   of nnkTryStmt:
     # try: await x; except: ...
     result = newNimNode(nnkStmtList, node)
-    proc processForTry(n: PNimrodNode, i: var int,
-                       res: PNimrodNode): bool {.compileTime.} =
+    template wrapInTry(n, tryBody: expr) =
+      var temp = n
+      n[0] = tryBody
+      tryBody = temp
+
+      # Transform ``except`` body.
+      # TODO: Could we perform some ``await`` transformation here to get it
+      # working in ``except``?
+      tryBody[1] = processBody(n[1], retFutureSym, subTypeIsVoid, nil)
+
+    proc processForTry(n: NimNode, i: var int,
+                       res: NimNode): bool {.compileTime.} =
+      ## Transforms the body of the tryStmt. Does not transform the
+      ## body in ``except``.
+      ## Returns true if the tryStmt node was transformed into an ifStmt.
       result = false
-      while i < n[0].len:
-        var processed = processBody(n[0][i], retFutureSym, subTypeIsVoid, n)
-        if processed.kind != n[0][i].kind or processed.len != n[0][i].len:
+      var skipped = n.skipStmtList()
+      while i < skipped.len:
+        var processed = processBody(skipped[i], retFutureSym,
+                                    subTypeIsVoid, n)
+
+        # Check if we transformed the node into an exception check.
+        # This suggests skipped[i] contains ``await``.
+        if processed.kind != skipped[i].kind or processed.len != skipped[i].len:
+          processed = processed.skipUntilStmtList()
           expectKind(processed, nnkStmtList)
           expectKind(processed[2][1], nnkElse)
           i.inc
-          discard processForTry(n, i, processed[2][1][0])
+
+          if not processForTry(n, i, processed[2][1][0]):
+            # We need to wrap the nnkElse nodes back into a tryStmt.
+            # As they are executed if an exception does not happen
+            # inside the awaited future.
+            # The following code will wrap the nodes inside the
+            # original tryStmt.
+            wrapInTry(n, processed[2][1][0])
+
           res.add processed
           result = true
         else:
-          res.add n[0][i]
+          res.add skipped[i]
           i.inc
     var i = 0
     if not processForTry(node, i, result):
-      var temp = node
-      temp[0] = result
-      result = temp
+      # If the tryStmt hasn't been transformed we can just put the body
+      # back into it.
+      wrapInTry(node, result)
     return
   else: discard
 
   for i in 0 .. <result.len:
-    result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, tryStmt)
+    result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, nil)
 
-proc getName(node: PNimrodNode): string {.compileTime.} =
+proc getName(node: NimNode): string {.compileTime.} =
   case node.kind
   of nnkPostfix:
     return $node[1].ident
@@ -1273,29 +1318,40 @@ macro async*(prc: stmt): stmt {.immediate.} =
     if returnType.kind == nnkEmpty: newIdentNode("void")
     else: returnType[1]
   outerProcBody.add(
-    newVarStmt(retFutureSym, 
+    newVarStmt(retFutureSym,
       newCall(
         newNimNode(nnkBracketExpr, prc[6]).add(
           newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`.
           subRetType),
       newLit(prc[0].getName)))) # Get type from return type of this proc
-  
-  # -> iterator nameIter(): FutureBase {.closure.} = 
+
+  # -> iterator nameIter(): FutureBase {.closure.} =
+  # ->   {.push warning[resultshadowed]: off.}
   # ->   var result: T
+  # ->   {.pop.}
   # ->   <proc_body>
   # ->   complete(retFuture, result)
   var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter")
   var procBody = prc[6].processBody(retFutureSym, subtypeIsVoid, nil)
   if not subtypeIsVoid:
-    procBody.insert(0, newNimNode(nnkVarSection, prc[6]).add(
+    procBody.insert(0, newNimNode(nnkPragma).add(newIdentNode("push"),
+      newNimNode(nnkExprColonExpr).add(newNimNode(nnkBracketExpr).add(
+        newIdentNode("warning"), newIdentNode("resultshadowed")),
+      newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.}
+
+    procBody.insert(1, newNimNode(nnkVarSection, prc[6]).add(
       newIdentDefs(newIdentNode("result"), returnType[1]))) # -> var result: T
+
+    procBody.insert(2, newNimNode(nnkPragma).add(
+      newIdentNode("pop"))) # -> {.pop.})
+
     procBody.add(
       newCall(newIdentNode("complete"),
         retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result)
   else:
     # -> complete(retFuture)
     procBody.add(newCall(newIdentNode("complete"), retFutureSym))
-  
+
   var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
                                 procBody, nnkIteratorDef)
   closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure"))
@@ -1309,7 +1365,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
 
   # -> return retFuture
   outerProcBody.add newNimNode(nnkReturnStmt, prc[6][prc[6].len-1]).add(retFutureSym)
-  
+
   result = prc
 
   # Remove the 'async' pragma.
@@ -1325,7 +1381,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
   result[6] = outerProcBody
 
   #echo(treeRepr(result))
-  #if prc[0].getName == "catch":
+  #if prc[0].getName == "test":
   #  echo(toStrLit(result))
 
 proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
@@ -1335,7 +1391,7 @@ proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
   ## If a full line is read ``\r\L`` is not
   ## added to ``line``, however if solely ``\r\L`` is read then ``line``
   ## will be set to it.
-  ## 
+  ##
   ## If the socket is disconnected, ``line`` will be set to ``""``.
   ##
   ## If the socket is disconnected in the middle of a line (before ``\r\L``
@@ -1346,7 +1402,7 @@ proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
   ##
   ## **Note**: This procedure is mostly used for testing. You likely want to
   ## use ``asyncnet.recvLine`` instead.
-  
+
   template addNLIfEmpty(): stmt =
     if result.len == 0:
       result.add("\c\L")
diff --git a/lib/pure/asyncdispatch.nimrod.cfg b/lib/pure/asyncdispatch.nim.cfg
index e88f8eec3..e88f8eec3 100644
--- a/lib/pure/asyncdispatch.nimrod.cfg
+++ b/lib/pure/asyncdispatch.nim.cfg
diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim
index c09cb5a35..25e121183 100644
--- a/lib/pure/asyncfile.nim
+++ b/lib/pure/asyncfile.nim
@@ -1,13 +1,13 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Dominik Picheta
+#        (c) Copyright 2015 Dominik Picheta
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
-## This module implements asynchronous file handling.
+## This module implements asynchronous file reading and writing.
 ##
 ## .. code-block:: Nim
 ##    import asyncfile, asyncdispatch, os
@@ -24,18 +24,18 @@
 
 import asyncdispatch, os
 
-when defined(windows):
+when defined(windows) or defined(nimdoc):
   import winlean
 else:
   import posix
 
 type
-  AsyncFile = ref object
+  AsyncFile* = ref object
     fd: TAsyncFd
     offset: int64
 
-when defined(windows):
-  proc getDesiredAccess(mode: TFileMode): int32 =
+when defined(windows) or defined(nimdoc):
+  proc getDesiredAccess(mode: FileMode): int32 =
     case mode
     of fmRead:
       result = GENERIC_READ
@@ -44,7 +44,7 @@ when defined(windows):
     of fmReadWrite, fmReadWriteExisting:
       result = GENERIC_READ or GENERIC_WRITE
 
-  proc getCreationDisposition(mode: TFileMode, filename: string): int32 =
+  proc getCreationDisposition(mode: FileMode, filename: string): int32 =
     case mode
     of fmRead, fmReadWriteExisting:
       OPEN_EXISTING
@@ -54,7 +54,7 @@ when defined(windows):
       else:
         CREATE_NEW
 else:
-  proc getPosixFlags(mode: TFileMode): cint =
+  proc getPosixFlags(mode: FileMode): cint =
     case mode
     of fmRead:
       result = O_RDONLY
@@ -70,18 +70,18 @@ else:
 
 proc getFileSize(f: AsyncFile): int64 =
   ## Retrieves the specified file's size.
-  when defined(windows):
+  when defined(windows) or defined(nimdoc):
     var high: DWord
     let low = getFileSize(f.fd.THandle, addr high)
     if low == INVALID_FILE_SIZE:
-      raiseOSError()
+      raiseOSError(osLastError())
     return (high shl 32) or low
 
 proc openAsync*(filename: string, mode = fmRead): AsyncFile =
   ## Opens a file specified by the path in ``filename`` using
   ## the specified ``mode`` asynchronously.
   new result
-  when defined(windows):
+  when defined(windows) or defined(nimdoc):
     let flags = FILE_FLAG_OVERLAPPED or FILE_ATTRIBUTE_NORMAL
     let desiredAccess = getDesiredAccess(mode)
     let creationDisposition = getCreationDisposition(mode, filename)
@@ -95,7 +95,7 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile =
           nil, creationDisposition, flags, 0).TAsyncFd
 
     if result.fd.THandle == INVALID_HANDLE_VALUE:
-      raiseOSError()
+      raiseOSError(osLastError())
 
     register(result.fd)
 
@@ -108,7 +108,7 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile =
     let perm = S_IRUSR or S_IWUSR or S_IRGRP or S_IWGRP or S_IROTH
     result.fd = open(filename, flags, perm).TAsyncFD
     if result.fd.cint == -1:
-      raiseOSError()
+      raiseOSError(osLastError())
 
     register(result.fd)
 
@@ -120,7 +120,7 @@ proc read*(f: AsyncFile, size: int): Future[string] =
   ## returned.
   var retFuture = newFuture[string]("asyncfile.read")
 
-  when defined(windows):
+  when defined(windows) or defined(nimdoc):
     var buffer = alloc0(size)
 
     var ol = PCustomOverlapped()
@@ -185,7 +185,7 @@ proc read*(f: AsyncFile, size: int): Future[string] =
       if res < 0:
         let lastError = osLastError()
         if lastError.int32 != EAGAIN:
-          retFuture.fail(newException(EOS, osErrorMsg(lastError)))
+          retFuture.fail(newException(OSError, osErrorMsg(lastError)))
         else:
           result = false # We still want this callback to be called.
       elif res == 0:
@@ -224,10 +224,10 @@ proc setFilePos*(f: AsyncFile, 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. 
   f.offset = pos
-  when not defined(windows):
+  when not defined(windows) and not defined(nimdoc):
     let ret = lseek(f.fd.cint, pos, SEEK_SET)
     if ret == -1:
-      raiseOSError()
+      raiseOSError(osLastError())
 
 proc readAll*(f: AsyncFile): Future[string] {.async.} =
   ## Reads all data from the specified file.
@@ -245,7 +245,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
   ## specified file.
   var retFuture = newFuture[void]("asyncfile.write")
   var copy = data
-  when defined(windows):
+  when defined(windows) or defined(nimdoc):
     var buffer = alloc0(data.len)
     copyMem(buffer, addr copy[0], data.len)
 
@@ -299,7 +299,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
       if res < 0:
         let lastError = osLastError()
         if lastError.int32 != EAGAIN:
-          retFuture.fail(newException(EOS, osErrorMsg(lastError)))
+          retFuture.fail(newException(OSError, osErrorMsg(lastError)))
         else:
           result = false # We still want this callback to be called.
       else:
@@ -316,10 +316,10 @@ proc write*(f: AsyncFile, data: string): Future[void] =
 
 proc close*(f: AsyncFile) =
   ## Closes the file specified.
-  when defined(windows):
+  when defined(windows) or defined(nimdoc):
     if not closeHandle(f.fd.THandle).bool:
-      raiseOSError()
+      raiseOSError(osLastError())
   else:
     if close(f.fd.cint) == -1:
-      raiseOSError()
+      raiseOSError(osLastError())
 
diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim
index fc38dc31a..daf69d59f 100644
--- a/lib/pure/asyncftpclient.nim
+++ b/lib/pure/asyncftpclient.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Dominik Picheta
+#        (c) Copyright 2015 Dominik Picheta
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
@@ -61,8 +61,8 @@ proc pasv(ftp: AsyncFtpClient) {.async.} =
   assertReply(pasvMsg, "227")
   var betweenParens = captureBetween(pasvMsg.string, '(', ')')
   var nums = betweenParens.split(',')
-  var ip = nums[0.. -3]
-  var port = nums[-2.. -1]
+  var ip = nums[0.. ^3]
+  var port = nums[^2.. ^1]
   var properPort = port[0].parseInt()*256+port[1].parseInt()
   await ftp.dsock.connect(ip.join("."), Port(properPort.toU16))
   ftp.dsockConnected = true
@@ -149,7 +149,7 @@ proc createDir*(ftp: AsyncFtpClient, dir: string, recursive = false){.async.} =
     assertReply reply, "257"
 
 proc chmod*(ftp: AsyncFtpClient, path: string,
-            permissions: set[TFilePermission]) {.async.} =
+            permissions: set[FilePermission]) {.async.} =
   ## Changes permission of ``path`` to ``permissions``.
   var userOctal = 0
   var groupOctal = 0
@@ -188,7 +188,7 @@ proc retrText*(ftp: AsyncFtpClient, file: string): Future[string] {.async.} =
 
   result = await ftp.getLines()
 
-proc getFile(ftp: AsyncFtpClient, file: TFile, total: BiggestInt,
+proc getFile(ftp: AsyncFtpClient, file: File, total: BiggestInt,
              onProgressChanged: ProgressChangedProc) {.async.} =
   assert ftp.dsockConnected
   var progress = 0
@@ -240,7 +240,7 @@ proc retrFile*(ftp: AsyncFtpClient, file, dest: string,
 
   await getFile(ftp, destFile, fileSize, onProgressChanged)
 
-proc doUpload(ftp: AsyncFtpClient, file: TFile,
+proc doUpload(ftp: AsyncFtpClient, file: File,
               onProgressChanged: ProgressChangedProc) {.async.} =
   assert ftp.dsockConnected
 
@@ -300,7 +300,7 @@ proc newAsyncFtpClient*(address: string, port = Port(21),
   result.dsockConnected = false
   result.csock = newAsyncSocket()
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test")
   proc main(ftp: AsyncFtpClient) {.async.} =
     await ftp.connect()
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
index e0f3b6fc2..dc5a55dcc 100644
--- a/lib/pure/asynchttpserver.nim
+++ b/lib/pure/asynchttpserver.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Dominik Picheta
+#        (c) Copyright 2015 Dominik Picheta
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -17,8 +17,10 @@
 ## as the response body.
 ##
 ## .. code-block::nim
+##    import asynchttpserver, asyncdispatch
+##
 ##    var server = newAsyncHttpServer()
-##    proc cb(req: TRequest) {.async.} =
+##    proc cb(req: Request) {.async.} =
 ##      await req.respond(Http200, "Hello World")
 ##
 ##    asyncCheck server.serve(Port(8080), cb)
@@ -27,25 +29,52 @@
 import strtabs, asyncnet, asyncdispatch, parseutils, uri, strutils
 type
   Request* = object
-    client*: PAsyncSocket # TODO: Separate this into a Response object?
+    client*: AsyncSocket # TODO: Separate this into a Response object?
     reqMethod*: string
-    headers*: PStringTable
+    headers*: StringTableRef
     protocol*: tuple[orig: string, major, minor: int]
-    url*: TUri
+    url*: Uri
     hostname*: string ## The hostname of the client that made the request.
     body*: string
 
   AsyncHttpServer* = ref object
-    socket: PAsyncSocket
+    socket: AsyncSocket
     reuseAddr: bool
 
   HttpCode* = enum
+    Http100 = "100 Continue",
+    Http101 = "101 Switching Protocols",
     Http200 = "200 OK",
-    Http303 = "303 Moved",
+    Http201 = "201 Created",
+    Http202 = "202 Accepted",
+    Http204 = "204 No Content",
+    Http205 = "205 Reset Content",
+    Http206 = "206 Partial Content",
+    Http300 = "300 Multiple Choices",
+    Http301 = "301 Moved Permanently",
+    Http302 = "302 Found",
+    Http303 = "303 See Other",
+    Http304 = "304 Not Modified",
+    Http305 = "305 Use Proxy",
+    Http307 = "307 Temporary Redirect",
     Http400 = "400 Bad Request",
+    Http401 = "401 Unauthorized",
+    Http403 = "403 Forbidden",
     Http404 = "404 Not Found",
+    Http405 = "405 Method Not Allowed",
+    Http406 = "406 Not Acceptable",
+    Http407 = "407 Proxy Authentication Required",
+    Http408 = "408 Request Timeout",
+    Http409 = "409 Conflict",
+    Http410 = "410 Gone",
+    Http411 = "411 Length Required",
+    Http418 = "418 I'm a teapot",
     Http500 = "500 Internal Server Error",
-    Http502 = "502 Bad Gateway"
+    Http501 = "501 Not Implemented",
+    Http502 = "502 Bad Gateway",
+    Http503 = "503 Service Unavailable",
+    Http504 = "504 Gateway Timeout",
+    Http505 = "505 HTTP Version Not Supported"
 
   HttpVersion* = enum
     HttpVer11,
@@ -55,7 +84,7 @@ type
   THttpCode: HttpCode, THttpVersion: HttpVersion].}
 
 proc `==`*(protocol: tuple[orig: string, major, minor: int],
-           ver: THttpVersion): bool =
+           ver: HttpVersion): bool =
   let major =
     case ver
     of HttpVer11, HttpVer10: 1
@@ -65,23 +94,23 @@ proc `==`*(protocol: tuple[orig: string, major, minor: int],
     of HttpVer10: 0
   result = protocol.major == major and protocol.minor == minor
 
-proc newAsyncHttpServer*(reuseAddr = true): PAsyncHttpServer =
+proc newAsyncHttpServer*(reuseAddr = true): AsyncHttpServer =
   ## Creates a new ``AsyncHttpServer`` instance.
   new result
   result.reuseAddr = reuseAddr
 
-proc addHeaders(msg: var string, headers: PStringTable) =
+proc addHeaders(msg: var string, headers: StringTableRef) =
   for k, v in headers:
     msg.add(k & ": " & v & "\c\L")
 
-proc sendHeaders*(req: TRequest, headers: PStringTable): Future[void] =
+proc sendHeaders*(req: Request, headers: StringTableRef): Future[void] =
   ## Sends the specified headers to the requesting client.
   var msg = ""
   addHeaders(msg, headers)
   return req.client.send(msg)
 
-proc respond*(req: TRequest, code: THttpCode,
-        content: string, headers: PStringTable = newStringTable()) {.async.} =
+proc respond*(req: Request, code: HttpCode,
+        content: string, headers = newStringTable()) {.async.} =
   ## Responds to the request with the specified ``HttpCode``, headers and
   ## content.
   ##
@@ -92,7 +121,7 @@ proc respond*(req: TRequest, code: THttpCode,
   msg.addHeaders(customHeaders)
   await req.client.send(msg & "\c\L" & content)
 
-proc newRequest(): TRequest =
+proc newRequest(): Request =
   result.headers = newStringTable(modeCaseInsensitive)
   result.hostname = ""
   result.body = ""
@@ -107,20 +136,20 @@ proc parseHeader(line: string): tuple[key, value: string] =
 proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
   var i = protocol.skipIgnoreCase("HTTP/")
   if i != 5:
-    raise newException(EInvalidValue, "Invalid request protocol. Got: " &
+    raise newException(ValueError, "Invalid request protocol. Got: " &
         protocol)
   result.orig = protocol
   i.inc protocol.parseInt(result.major, i)
   i.inc # Skip .
   i.inc protocol.parseInt(result.minor, i)
 
-proc sendStatus(client: PAsyncSocket, status: string): Future[void] =
+proc sendStatus(client: AsyncSocket, status: string): Future[void] =
   client.send("HTTP/1.1 " & status & "\c\L")
 
-proc processClient(client: PAsyncSocket, address: string,
-                   callback: proc (request: TRequest):
+proc processClient(client: AsyncSocket, address: string,
+                   callback: proc (request: Request):
                       Future[void] {.closure, gcsafe.}) {.async.} =
-  while not client.closed:
+  while not client.isClosed:
     # GET /path HTTP/1.1
     # Header: val
     # \n
@@ -160,7 +189,7 @@ proc processClient(client: PAsyncSocket, address: string,
     request.url = parseUri(path)
     try:
       request.protocol = protocol.parseProtocol()
-    except EInvalidValue:
+    except ValueError:
       asyncCheck request.respond(Http400, "Invalid request protocol. Got: " &
           protocol)
       continue
@@ -206,8 +235,8 @@ proc processClient(client: PAsyncSocket, address: string,
       request.client.close()
       break
 
-proc serve*(server: PAsyncHttpServer, port: Port,
-            callback: proc (request: TRequest): Future[void] {.closure,gcsafe.},
+proc serve*(server: AsyncHttpServer, port: Port,
+            callback: proc (request: Request): Future[void] {.closure,gcsafe.},
             address = "") {.async.} =
   ## Starts the process of listening for incoming HTTP connections on the
   ## specified address and port.
@@ -227,14 +256,14 @@ proc serve*(server: PAsyncHttpServer, port: Port,
     #echo(f.isNil)
     #echo(f.repr)
 
-proc close*(server: PAsyncHttpServer) =
+proc close*(server: AsyncHttpServer) =
   ## Terminates the async http server instance.
   server.socket.close()
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   proc main =
     var server = newAsyncHttpServer()
-    proc cb(req: TRequest) {.async.} =
+    proc cb(req: Request) {.async.} =
       #echo(req.reqMethod, " ", req.url)
       #echo(req.headers)
       let headers = {"Date": "Tue, 29 Apr 2014 23:40:08 GMT",
diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim
index 4c25952a8..6ae2c608b 100644
--- a/lib/pure/asyncio.nim
+++ b/lib/pure/asyncio.nim
@@ -10,11 +10,16 @@ include "system/inclrtl"
 
 import sockets, os
 
+##
+## **Warning:** This module is deprecated since version 0.10.2.
+## Use the brand new `asyncdispatch <asyncdispatch.html>`_ module together
+## with the `asyncnet <asyncnet.html>`_ module.
+
 ## This module implements an asynchronous event loop together with asynchronous
 ## sockets which use this event loop.
 ## It is akin to Python's asyncore module. Many modules that use sockets
-## have an implementation for this module, those modules should all have a 
-## ``register`` function which you should use to add the desired objects to a 
+## have an implementation for this module, those modules should all have a
+## ``register`` function which you should use to add the desired objects to a
 ## dispatcher which you created so
 ## that you can receive the events associated with that module's object.
 ##
@@ -22,19 +27,19 @@ import sockets, os
 ## function in a while loop.
 ##
 ## **Note:** Most modules have tasks which need to be ran regularly, this is
-## why you should not call ``poll`` with a infinite timeout, or even a 
+## why you should not call ``poll`` with a infinite timeout, or even a
 ## very long one. In most cases the default timeout is fine.
 ##
 ## **Note:** This module currently only supports select(), this is limited by
 ## FD_SETSIZE, which is usually 1024. So you may only be able to use 1024
 ## sockets at a time.
-## 
+##
 ## Most (if not all) modules that use asyncio provide a userArg which is passed
 ## on with the events. The type that you set userArg to must be inheriting from
 ## ``RootObj``!
 ##
-## **Note:** If you want to provide async ability to your module please do not 
-## use the ``Delegate`` object, instead use ``AsyncSocket``. It is possible 
+## **Note:** If you want to provide async ability to your module please do not
+## use the ``Delegate`` object, instead use ``AsyncSocket``. It is possible
 ## that in the future this type's fields will not be exported therefore breaking
 ## your code.
 ##
@@ -54,11 +59,11 @@ import sockets, os
 ## socket which will give you the client which is connecting. You should then
 ## set any events that you want to use on that client and add it to your dispatcher
 ## using the ``register`` procedure.
-## 
+##
 ## An example ``handleAccept`` follows:
-## 
+##
 ## .. code-block:: nim
-##   
+##
 ##    var disp = newDispatcher()
 ##    ...
 ##    proc handleAccept(s: AsyncSocket) =
@@ -69,7 +74,7 @@ import sockets, os
 ##      client.handleRead = ...
 ##      disp.register(client)
 ##    ...
-## 
+##
 ## For client sockets you should only be interested in the ``handleRead`` and
 ## ``handleConnect`` events. The former gets called whenever the socket has
 ## received messages and can be read from and the latter gets called whenever
@@ -78,18 +83,20 @@ import sockets, os
 ##
 ## Getting a blocking client from an AsyncSocket
 ## =============================================
-## 
+##
 ## If you need a asynchronous server socket but you wish to process the clients
 ## synchronously then you can use the ``getSocket`` converter to get
 ## a ``Socket`` from the ``AsyncSocket`` object, this can then be combined
 ## with ``accept`` like so:
 ##
 ## .. code-block:: nim
-##    
+##
 ##    proc handleAccept(s: AsyncSocket) =
 ##      var client: Socket
 ##      getSocket(s).accept(client)
 
+{.deprecated.}
+
 when defined(windows):
   from winlean import TimeVal, SocketHandle, FD_SET, FD_ZERO, TFdSet,
     FD_ISSET, select
@@ -106,11 +113,11 @@ type
     handleWrite*: proc (h: RootRef) {.nimcall, gcsafe.}
     handleError*: proc (h: RootRef) {.nimcall, gcsafe.}
     hasDataBuffered*: proc (h: RootRef): bool {.nimcall, gcsafe.}
-    
+
     open*: bool
     task*: proc (h: RootRef) {.nimcall, gcsafe.}
     mode*: FileMode
-    
+
   Delegate* = ref DelegateObj
 
   Dispatcher* = ref DispatcherObj
@@ -137,7 +144,7 @@ type
     deleg: Delegate
 
   SocketStatus* = enum
-    SockIdle, SockConnecting, SockConnected, SockListening, SockClosed, 
+    SockIdle, SockConnecting, SockConnected, SockListening, SockClosed,
     SockUDPBound
 
 {.deprecated: [TDelegate: DelegateObj, PDelegate: Delegate,
@@ -169,8 +176,8 @@ proc newAsyncSocket(): AsyncSocket =
   result.lineBuffer = "".TaintedString
   result.sendBuffer = ""
 
-proc asyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM, 
-                  protocol: Protocol = IPPROTO_TCP, 
+proc asyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
+                  protocol: Protocol = IPPROTO_TCP,
                   buffered = true): AsyncSocket =
   ## Initialises an AsyncSocket object. If a socket cannot be initialised
   ## EOS is raised.
@@ -229,7 +236,7 @@ proc asyncSockHandleWrite(h: RootRef) =
     if AsyncSocket(h).socket.isSSL and not
          AsyncSocket(h).socket.gotHandshake:
       return
-  
+
   if AsyncSocket(h).info == SockConnecting:
     AsyncSocket(h).handleConnect(AsyncSocket(h))
     AsyncSocket(h).info = SockConnected
@@ -249,10 +256,10 @@ proc asyncSockHandleWrite(h: RootRef) =
           # do nothing instead.
           discard
         elif bytesSent != sock.sendBuffer.len:
-          sock.sendBuffer = sock.sendBuffer[bytesSent .. -1]
+          sock.sendBuffer = sock.sendBuffer[bytesSent .. ^1]
         elif bytesSent == sock.sendBuffer.len:
           sock.sendBuffer = ""
-        
+
         if AsyncSocket(h).handleWrite != nil:
           AsyncSocket(h).handleWrite(AsyncSocket(h))
       except OSError:
@@ -277,7 +284,7 @@ when defined(ssl):
       else:
         # handshake will set socket's ``sslNoHandshake`` field.
         discard AsyncSocket(h).socket.handshake()
-        
+
 
 proc asyncSockTask(h: RootRef) =
   when defined(ssl):
@@ -370,9 +377,9 @@ proc acceptAddr*(server: AsyncSocket, client: var AsyncSocket,
 
   if c == invalidSocket: raiseSocketError(server.socket)
   c.setBlocking(false) # TODO: Needs to be tested.
-  
+
   # deleg.open is set in ``toDelegate``.
-  
+
   client.socket = c
   client.lineBuffer = "".TaintedString
   client.sendBuffer = ""
@@ -386,7 +393,7 @@ proc accept*(server: AsyncSocket, client: var AsyncSocket) =
 proc acceptAddr*(server: AsyncSocket): tuple[sock: AsyncSocket,
                                               address: string] {.deprecated.} =
   ## Equivalent to ``sockets.acceptAddr``.
-  ## 
+  ##
   ## **Deprecated since version 0.9.0:** Please use the function above.
   var client = newAsyncSocket()
   var address: string = ""
@@ -434,17 +441,17 @@ proc isConnected*(s: AsyncSocket): bool =
   ## Determines whether ``s`` is connected.
   return s.info == SockConnected
 proc isListening*(s: AsyncSocket): bool =
-  ## Determines whether ``s`` is listening for incoming connections.  
+  ## Determines whether ``s`` is listening for incoming connections.
   return s.info == SockListening
 proc isConnecting*(s: AsyncSocket): bool =
-  ## Determines whether ``s`` is connecting.  
+  ## Determines whether ``s`` is connecting.
   return s.info == SockConnecting
 proc isClosed*(s: AsyncSocket): bool =
   ## Determines whether ``s`` has been closed.
   return s.info == SockClosed
 proc isSendDataBuffered*(s: AsyncSocket): bool =
   ## Determines whether ``s`` has data waiting to be sent, i.e. whether this
-  ## socket's sendBuffer contains data. 
+  ## socket's sendBuffer contains data.
   return s.sendBuffer.len != 0
 
 proc setHandleWrite*(s: AsyncSocket,
@@ -543,7 +550,7 @@ proc send*(sock: AsyncSocket, data: string) =
     sock.sendBuffer.add(data)
     sock.deleg.mode = fmReadWrite
   elif bytesSent != data.len:
-    sock.sendBuffer.add(data[bytesSent .. -1])
+    sock.sendBuffer.add(data[bytesSent .. ^1])
     sock.deleg.mode = fmReadWrite
 
 proc timeValFromMilliseconds(timeout = 500): Timeval =
@@ -554,10 +561,10 @@ proc timeValFromMilliseconds(timeout = 500): Timeval =
 
 proc createFdSet(fd: var TFdSet, s: seq[Delegate], m: var int) =
   FD_ZERO(fd)
-  for i in items(s): 
+  for i in items(s):
     m = max(m, int(i.fd))
     FD_SET(i.fd, fd)
-   
+
 proc pruneSocketSet(s: var seq[Delegate], fd: var TFdSet) =
   var i = 0
   var L = s.len
@@ -569,16 +576,16 @@ proc pruneSocketSet(s: var seq[Delegate], fd: var TFdSet) =
       inc(i)
   setLen(s, L)
 
-proc select(readfds, writefds, exceptfds: var seq[Delegate], 
+proc select(readfds, writefds, exceptfds: var seq[Delegate],
              timeout = 500): int =
   var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
-  
+
   var rd, wr, ex: TFdSet
   var m = 0
   createFdSet(rd, readfds, m)
   createFdSet(wr, writefds, m)
   createFdSet(ex, exceptfds, m)
-  
+
   if timeout != -1:
     result = int(select(cint(m+1), addr(rd), addr(wr), addr(ex), addr(tv)))
   else:
@@ -592,7 +599,7 @@ proc poll*(d: Dispatcher, timeout: int = 500): bool =
   ## This function checks for events on all the delegates in the `PDispatcher`.
   ## It then proceeds to call the correct event handler.
   ##
-  ## This function returns ``True`` if there are file descriptors that are still 
+  ## This function returns ``True`` if there are file descriptors that are still
   ## open, otherwise ``False``. File descriptors that have been
   ## closed are immediately removed from the dispatcher automatically.
   ##
@@ -604,7 +611,7 @@ proc poll*(d: Dispatcher, timeout: int = 500): bool =
   var readDg, writeDg, errorDg: seq[Delegate] = @[]
   var len = d.delegates.len
   var dc = 0
-  
+
   while dc < len:
     let deleg = d.delegates[dc]
     if (deleg.mode != fmWrite or deleg.mode != fmAppend) and deleg.open:
@@ -618,20 +625,20 @@ proc poll*(d: Dispatcher, timeout: int = 500): bool =
       # File/socket has been closed. Remove it from dispatcher.
       d.delegates[dc] = d.delegates[len-1]
       dec len
-      
+
   d.delegates.setLen(len)
-  
+
   var hasDataBufferedCount = 0
   for d in d.delegates:
     if d.hasDataBuffered(d.deleVal):
       hasDataBufferedCount.inc()
       d.handleRead(d.deleVal)
   if hasDataBufferedCount > 0: return true
-  
+
   if readDg.len() == 0 and writeDg.len() == 0:
     ## TODO: Perhaps this shouldn't return if errorDg has something?
     return false
-  
+
   if select(readDg, writeDg, errorDg, timeout) != 0:
     for i in 0..len(d.delegates)-1:
       if i > len(d.delegates)-1: break # One delegate might've been removed.
@@ -644,7 +651,7 @@ proc poll*(d: Dispatcher, timeout: int = 500): bool =
         deleg.handleWrite(deleg.deleVal)
       if deleg notin errorDg:
         deleg.handleError(deleg.deleVal)
-  
+
   # Execute tasks
   for i in items(d.delegates):
     i.task(i.deleVal)
@@ -653,11 +660,11 @@ proc len*(disp: Dispatcher): int =
   ## Retrieves the amount of delegates in ``disp``.
   return disp.delegates.len
 
-when isMainModule:
+when not defined(testing) and isMainModule:
 
   proc testConnect(s: AsyncSocket, no: int) =
     echo("Connected! " & $no)
-  
+
   proc testRead(s: AsyncSocket, no: int) =
     echo("Reading! " & $no)
     var data = ""
@@ -668,38 +675,38 @@ when isMainModule:
     echo(data)
     echo("Finished reading! " & $no)
 
-  proc testAccept(s: AsyncSocket, disp: PDispatcher, no: int) =
+  proc testAccept(s: AsyncSocket, disp: Dispatcher, no: int) =
     echo("Accepting client! " & $no)
     var client: AsyncSocket
     new(client)
     var address = ""
     s.acceptAddr(client, address)
     echo("Accepted ", address)
-    client.handleRead = 
+    client.handleRead =
       proc (s: AsyncSocket) =
         testRead(s, 2)
     disp.register(client)
 
   proc main =
     var d = newDispatcher()
-    
+
     var s = asyncSocket()
-    s.connect("amber.tenthbit.net", TPort(6667))
-    s.handleConnect = 
+    s.connect("amber.tenthbit.net", Port(6667))
+    s.handleConnect =
       proc (s: AsyncSocket) =
         testConnect(s, 1)
-    s.handleRead = 
+    s.handleRead =
       proc (s: AsyncSocket) =
         testRead(s, 1)
     d.register(s)
-    
+
     var server = asyncSocket()
     server.handleAccept =
-      proc (s: AsyncSocket) = 
+      proc (s: AsyncSocket) =
         testAccept(s, d, 78)
-    server.bindAddr(TPort(5555))
+    server.bindAddr(Port(5555))
     server.listen()
     d.register(server)
-    
+
     while d.poll(-1): discard
   main()
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index fd29e0a22..39d05d36b 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Dominik Picheta
+#        (c) Copyright 2015 Dominik Picheta
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -69,13 +69,13 @@ type
   # TODO: I would prefer to just do:
   # AsyncSocket* {.borrow: `.`.} = distinct Socket. But that doesn't work.
   AsyncSocketDesc  = object
-    fd*: SocketHandle
-    closed*: bool ## determines whether this socket has been closed
-    case isBuffered*: bool ## determines whether this socket is buffered.
+    fd: SocketHandle
+    closed: bool ## determines whether this socket has been closed
+    case isBuffered: bool ## determines whether this socket is buffered.
     of true:
-      buffer*: array[0..BufferSize, char]
-      currPos*: int # current index in buffer
-      bufLen*: int # current length of buffer
+      buffer: array[0..BufferSize, char]
+      currPos: int # current index in buffer
+      bufLen: int # current length of buffer
     of false: nil
     case isSsl: bool
     of true:
@@ -91,7 +91,8 @@ type
 
 # TODO: Save AF, domain etc info and reuse it in procs which need it like connect.
 
-proc newSocket(fd: TAsyncFD, isBuff: bool): AsyncSocket =
+proc newAsyncSocket*(fd: TAsyncFD, isBuff: bool): AsyncSocket =
+  ## Creates a new ``AsyncSocket`` based on the supplied params.
   assert fd != osInvalidSocket.TAsyncFD
   new(result)
   result.fd = fd.SocketHandle
@@ -102,11 +103,17 @@ proc newSocket(fd: TAsyncFD, isBuff: bool): AsyncSocket =
 proc newAsyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
     protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket =
   ## Creates a new asynchronous socket.
-  result = newSocket(newAsyncRawSocket(domain, typ, protocol), buffered)
+  ##
+  ## This procedure will also create a brand new file descriptor for
+  ## this socket.
+  result = newAsyncSocket(newAsyncRawSocket(domain, typ, protocol), buffered)
 
 proc newAsyncSocket*(domain, typ, protocol: cint, buffered = true): AsyncSocket =
   ## Creates a new asynchronous socket.
-  result = newSocket(newAsyncRawSocket(domain, typ, protocol), buffered)
+  ##
+  ## This procedure will also create a brand new file descriptor for
+  ## this socket.
+  result = newAsyncSocket(newAsyncRawSocket(domain, typ, protocol), buffered)
 
 when defined(ssl):
   proc getSslError(handle: SslPtr, err: cint): cint =
@@ -275,7 +282,7 @@ proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}):
         retFuture.fail(future.readError)
       else:
         let resultTup = (future.read.address,
-                         newSocket(future.read.client, socket.isBuffered))
+                         newAsyncSocket(future.read.client, socket.isBuffered))
         retFuture.complete(resultTup)
   return retFuture
 
@@ -399,13 +406,13 @@ proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {.
 
 proc close*(socket: AsyncSocket) =
   ## Closes the socket.
-  socket.fd.TAsyncFD.closeSocket()
+  defer:
+    socket.fd.TAsyncFD.closeSocket()
   when defined(ssl):
     if socket.isSSL:
       let res = SslShutdown(socket.sslHandle)
       if res == 0:
-        if SslShutdown(socket.sslHandle) != 1:
-          raiseSslError()
+        discard
       elif res != 1:
         raiseSslError()
   socket.closed = true # TODO: Add extra debugging checks for this.
@@ -439,7 +446,19 @@ proc setSockOpt*(socket: AsyncSocket, opt: SOBool, value: bool,
   var valuei = cint(if value: 1 else: 0)
   setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei)
 
-when isMainModule:
+proc isSsl*(socket: AsyncSocket): bool =
+  ## Determines whether ``socket`` is a SSL socket.
+  socket.isSsl
+
+proc getFd*(socket: AsyncSocket): SocketHandle =
+  ## Returns the socket's file descriptor.
+  return socket.fd
+
+proc isClosed*(socket: AsyncSocket): bool =
+  ## Determines whether the socket has been closed.
+  return socket.closed
+
+when not defined(testing) and isMainModule:
   type
     TestCases = enum
       HighClient, LowClient, LowServer
diff --git a/lib/pure/basic2d.nim b/lib/pure/basic2d.nim
index f2fc1566b..a344cd053 100644
--- a/lib/pure/basic2d.nim
+++ b/lib/pure/basic2d.nim
@@ -18,7 +18,7 @@ import strutils
 ##
 ## Quick start example:
 ##   
-##   # Create a matrix wich first rotates, then scales and at last translates
+##   # Create a matrix which first rotates, then scales and at last translates
 ##   
 ##   var m:TMatrix2d=rotate(DEG90) & scale(2.0) & move(100.0,200.0)
 ##   
@@ -256,7 +256,7 @@ proc `$`* (t:TMatrix2d):string {.noInit.} =
 
 proc isUniform*(t:TMatrix2d,tol=1.0e-6):bool=
   ## Checks if the transform is uniform, that is 
-  ## perpendicular axes of equal lenght, which means (for example)
+  ## perpendicular axes of equal length, which means (for example)
   ## it cannot transform a circle into an ellipse.
   ## `tol` is used as tolerance for both equal length comparison 
   ## and perp. comparison.
@@ -305,7 +305,7 @@ proc equals*(m1:TMatrix2d,m2:TMatrix2d,tol=1.0e-6):bool=
     abs(m1.ty-m2.ty)<=tol
     
 proc `=~`*(m1,m2:TMatrix2d):bool=
-  ## Checks if `m1`and `m2` is aproximately equal, using a
+  ## Checks if `m1`and `m2` is approximately equal, using a
   ## tolerance of 1e-6.
   equals(m1,m2)
 
diff --git a/lib/pure/basic3d.nim b/lib/pure/basic3d.nim
index c00764fc5..18ebed67b 100644
--- a/lib/pure/basic3d.nim
+++ b/lib/pure/basic3d.nim
@@ -23,7 +23,7 @@ import times
 ##
 ## Quick start example:
 ##   
-##   # Create a matrix wich first rotates, then scales and at last translates
+##   # Create a matrix which first rotates, then scales and at last translates
 ##   
 ##   var m:TMatrix3d=rotate(PI,vector3d(1,1,2.5)) & scale(2.0) & move(100.0,200.0,300.0)
 ##   
@@ -320,7 +320,7 @@ proc rotateZ*(angle:float):TMatrix3d {.noInit.}=
     
 proc isUniform*(m:TMatrix3d,tol=1.0e-6):bool=
   ## Checks if the transform is uniform, that is 
-  ## perpendicular axes of equal lenght, which means (for example)
+  ## perpendicular axes of equal length, which means (for example)
   ## it cannot transform a sphere into an ellipsoid.
   ## `tol` is used as tolerance for both equal length comparison 
   ## and perpendicular comparison.
@@ -483,7 +483,7 @@ proc equals*(m1:TMatrix3d,m2:TMatrix3d,tol=1.0e-6):bool=
     abs(m1.tw-m2.tw)<=tol
 
 proc `=~`*(m1,m2:TMatrix3d):bool=
-  ## Checks if `m1` and `m2` is aproximately equal, using a
+  ## Checks if `m1` and `m2` is approximately equal, using a
   ## tolerance of 1e-6.
   equals(m1,m2)
   
@@ -788,7 +788,7 @@ proc angleTo*(v1,v2:TVector3d):float=
 proc arbitraryAxis*(norm:TVector3d):TMatrix3d {.noInit.}=
   ## Computes the rotation matrix that would transform
   ## world z vector into `norm`. The inverse of this matrix
-  ## is useful to tranform a planar 3d object to 2d space.
+  ## is useful to transform a planar 3d object to 2d space.
   ## This is the same algorithm used to interpret DXF and DWG files.
   const lim=1.0/64.0
   var ax,ay,az:TVector3d
@@ -812,7 +812,7 @@ proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}=
   ## Computes the bisector between v1 and v2 as a normalized vector.
   ## If one of the input vectors has zero length, a normalized version
   ## of the other is returned. If both input vectors has zero length, 
-  ## an arbitrary normalized vector `v1`is returned.
+  ## an arbitrary normalized vector `v1` is returned.
   var
     vmag1=v1.len
     vmag2=v2.len
diff --git a/lib/pure/browsers.nim b/lib/pure/browsers.nim
index 52035ee48..c6a603318 100644
--- a/lib/pure/browsers.nim
+++ b/lib/pure/browsers.nim
@@ -42,7 +42,7 @@ proc openDefaultBrowser*(url: string) =
     for b in getEnv("BROWSER").string.split(PathSep):
       try:
         # we use ``startProcess`` here because we don't want to block!
-        discard startProcess(command=b, args=[url], options={poUseShell})
+        discard startProcess(command=b, args=[url], options={poUsePath})
         return
       except OSError:
         discard
diff --git a/lib/pure/collections/LockFreeHash.nim b/lib/pure/collections/LockFreeHash.nim
index 5640838b1..0df97c685 100644
--- a/lib/pure/collections/LockFreeHash.nim
+++ b/lib/pure/collections/LockFreeHash.nim
@@ -404,7 +404,7 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
     #echo("tomb old slot then set in new table") 
     nextTable = copySlotAndCheck(table,idx)
     return setVal(nextTable, key, val, expVal, match)
-  # Finaly ready to add new val to table
+  # Finally ready to add new val to table
   while true:
     if match and oldVal != expVal:
       #echo("set failed, no match  oldVal= " & $oldVal & " expVal= " & $expVal)
@@ -525,7 +525,7 @@ proc get*[K,V](table: var PConcTable[K,V], key: var K): V =
 
 
 #Tests ----------------------------
-when isMainModule:
+when not defined(testing) and isMainModule:
   import locks, times, mersenne
   
   const 
diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim
index 8f506409b..7e3f23851 100644
--- a/lib/pure/collections/critbits.nim
+++ b/lib/pure/collections/critbits.nim
@@ -12,7 +12,7 @@
 ## by Adam Langley.
 
 type
-  NodeObj[T] = object {.pure, final, acyclic.}
+  NodeObj[T] = object {.acyclic.}
     byte: int ## byte index of the difference
     otherbits: char
     case isLeaf: bool
@@ -23,11 +23,10 @@ type
         val: T
     
   Node[T] = ref NodeObj[T]
-  CritBitTree*[T] = object {.
-      pure, final.} ## The crit bit tree can either be used
-                    ## as a mapping from strings to
-                    ## some type ``T`` or as a set of
-                    ## strings if ``T`` is void.
+  CritBitTree*[T] = object ## The crit bit tree can either be used
+                           ## as a mapping from strings to
+                           ## some type ``T`` or as a set of
+                           ## strings if ``T`` is void.
     root: Node[T]
     count: int
 
@@ -175,7 +174,7 @@ proc excl*[T](c: var CritBitTree[T], key: string) =
 iterator leaves[T](n: Node[T]): Node[T] =
   if n != nil:
     # XXX actually we could compute the necessary stack size in advance:
-    # it's rougly log2(c.count).
+    # it's roughly log2(c.count).
     var stack = @[n]
     while stack.len > 0: 
       var it = stack.pop
@@ -287,18 +286,19 @@ proc `$`*[T](c: CritBitTree[T]): string =
     result.add("}")
 
 when isMainModule:
+  import sequtils
+
   var r: CritBitTree[void]
   r.incl "abc"
   r.incl "xyz"
   r.incl "def"
   r.incl "definition"
   r.incl "prefix"
+
   doAssert r.contains"def"
-  #r.del "def"
 
-  for w in r.items:
-    echo w
-    
-  for w in r.itemsWithPrefix("de"):
-    echo w
+  r.excl "def"
+
+  assert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"]
 
+  assert toSeq(r.itemsWithPrefix("de")) == @["definition"]
diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim
index 5d9c3f445..25f6616a6 100644
--- a/lib/pure/collections/intsets.nim
+++ b/lib/pure/collections/intsets.nim
@@ -8,18 +8,18 @@
 #
 
 ## The ``intsets`` module implements an efficient int set implemented as a
-## sparse bit set.
+## `sparse bit set`:idx:.
 ## **Note**: Since Nim currently does not allow the assignment operator to
 ## be overloaded, ``=`` for int sets performs some rather meaningless shallow
 ## copy; use ``assign`` to get a deep copy.
 
 import
-  os, hashes, math
+  hashes, math
 
 type
   BitScalar = int
 
-const 
+const
   InitIntSetSize = 8         # must be a power of two!
   TrunkShift = 9
   BitsPerTrunk = 1 shl TrunkShift # needs to be a power of 2 and
@@ -31,11 +31,11 @@ const
 
 type
   PTrunk = ref TTrunk
-  TTrunk {.final.} = object 
+  TTrunk {.final.} = object
     next: PTrunk             # all nodes are connected with this pointer
     key: int                 # start address at bit 0
     bits: array[0..IntsPerTrunk - 1, BitScalar] # a bit vector
-  
+
   TTrunkSeq = seq[PTrunk]
   IntSet* = object ## an efficient set of 'int' implemented as a sparse bit set
     counter, max: int
@@ -44,42 +44,42 @@ type
 
 {.deprecated: [TIntSet: IntSet].}
 
-proc mustRehash(length, counter: int): bool {.inline.} = 
+proc mustRehash(length, counter: int): bool {.inline.} =
   assert(length > counter)
   result = (length * 2 < counter * 3) or (length - counter < 4)
 
-proc nextTry(h, maxHash: THash): THash {.inline.} = 
-  result = ((5 * h) + 1) and maxHash 
+proc nextTry(h, maxHash: THash): THash {.inline.} =
+  result = ((5 * h) + 1) and maxHash
 
-proc intSetGet(t: IntSet, key: int): PTrunk = 
+proc intSetGet(t: IntSet, key: int): PTrunk =
   var h = key and t.max
-  while t.data[h] != nil: 
-    if t.data[h].key == key: 
+  while t.data[h] != nil:
+    if t.data[h].key == key:
       return t.data[h]
     h = nextTry(h, t.max)
   result = nil
 
-proc intSetRawInsert(t: IntSet, data: var TTrunkSeq, desc: PTrunk) = 
+proc intSetRawInsert(t: IntSet, data: var TTrunkSeq, desc: PTrunk) =
   var h = desc.key and t.max
-  while data[h] != nil: 
+  while data[h] != nil:
     assert(data[h] != desc)
     h = nextTry(h, t.max)
   assert(data[h] == nil)
   data[h] = desc
 
-proc intSetEnlarge(t: var IntSet) = 
+proc intSetEnlarge(t: var IntSet) =
   var n: TTrunkSeq
   var oldMax = t.max
   t.max = ((t.max + 1) * 2) - 1
   newSeq(n, t.max + 1)
-  for i in countup(0, oldMax): 
+  for i in countup(0, oldMax):
     if t.data[i] != nil: intSetRawInsert(t, n, t.data[i])
   swap(t.data, n)
 
-proc intSetPut(t: var IntSet, key: int): PTrunk = 
+proc intSetPut(t: var IntSet, key: int): PTrunk =
   var h = key and t.max
-  while t.data[h] != nil: 
-    if t.data[h].key == key: 
+  while t.data[h] != nil:
+    if t.data[h].key == key:
       return t.data[h]
     h = nextTry(h, t.max)
   if mustRehash(t.max + 1, t.counter): intSetEnlarge(t)
@@ -94,43 +94,43 @@ proc intSetPut(t: var IntSet, key: int): PTrunk =
   t.data[h] = result
 
 proc contains*(s: IntSet, key: int): bool =
-  ## returns true iff `key` is in `s`.  
+  ## returns true iff `key` is in `s`.
   var t = intSetGet(s, `shr`(key, TrunkShift))
-  if t != nil: 
+  if t != nil:
     var u = key and TrunkMask
     result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
-  else: 
+  else:
     result = false
-  
-proc incl*(s: var IntSet, key: int) = 
+
+proc incl*(s: var IntSet, key: int) =
   ## includes an element `key` in `s`.
   var t = intSetPut(s, `shr`(key, TrunkShift))
   var u = key and TrunkMask
   t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
       `shl`(1, u and IntMask)
 
-proc excl*(s: var IntSet, key: int) = 
+proc excl*(s: var IntSet, key: int) =
   ## excludes `key` from the set `s`.
   var t = intSetGet(s, `shr`(key, TrunkShift))
-  if t != nil: 
+  if t != nil:
     var u = key and TrunkMask
     t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] and
         not `shl`(1, u and IntMask)
 
-proc containsOrIncl*(s: var IntSet, key: int): bool = 
+proc containsOrIncl*(s: var IntSet, key: int): bool =
   ## returns true if `s` contains `key`, otherwise `key` is included in `s`
   ## and false is returned.
   var t = intSetGet(s, `shr`(key, TrunkShift))
-  if t != nil: 
+  if t != nil:
     var u = key and TrunkMask
     result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
-    if not result: 
+    if not result:
       t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
           `shl`(1, u and IntMask)
-  else: 
+  else:
     incl(s, key)
     result = false
-    
+
 proc initIntSet*: IntSet =
   ## creates a new int set that is empty.
   newSeq(result.data, InitIntSetSize)
@@ -140,14 +140,14 @@ proc initIntSet*: IntSet =
 
 proc assign*(dest: var IntSet, src: IntSet) =
   ## copies `src` to `dest`. `dest` does not need to be initialized by
-  ## `initIntSet`. 
+  ## `initIntSet`.
   dest.counter = src.counter
   dest.max = src.max
   newSeq(dest.data, src.data.len)
-  
+
   var it = src.head
   while it != nil:
-    
+
     var h = it.key and dest.max
     while dest.data[h] != nil: h = nextTry(h, dest.max)
     assert(dest.data[h] == nil)
@@ -168,7 +168,7 @@ iterator items*(s: IntSet): int {.inline.} =
   while r != nil:
     var i = 0
     while i <= high(r.bits):
-      var w = r.bits[i] 
+      var w = r.bits[i]
       # taking a copy of r.bits[i] here is correct, because
       # modifying operations are not allowed during traversation
       var j = 0
@@ -191,20 +191,28 @@ proc `$`*(s: IntSet): string =
   ## The `$` operator for int sets.
   dollarImpl()
 
-proc empty*(s: IntSet): bool {.inline.} =
+proc empty*(s: IntSet): bool {.inline, deprecated.} =
   ## returns true if `s` is empty. This is safe to call even before
-  ## the set has been initialized with `initIntSet`.
+  ## the set has been initialized with `initIntSet`. Note this never
+  ## worked reliably and so is deprecated.
   result = s.counter == 0
 
 when isMainModule:
+  import sequtils, algorithm
+
   var x = initIntSet()
   x.incl(1)
   x.incl(2)
   x.incl(7)
   x.incl(1056)
-  for e in items(x): echo e
 
-  var y: TIntSet
+  var xs = toSeq(items(x))
+  xs.sort(cmp[int])
+  assert xs == @[1, 2, 7, 1056]
+
+  var y: IntSet
   assign(y, x)
-  for e in items(y): echo e
+  var ys = toSeq(items(y))
+  ys.sort(cmp[int])
+  assert ys == @[1, 2, 7, 1056]
 
diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim
index 929de5973..535d5e21d 100644
--- a/lib/pure/collections/lists.nim
+++ b/lib/pure/collections/lists.nim
@@ -32,7 +32,7 @@ type
     head*, tail*: DoublyLinkedNode[T]
 
   SinglyLinkedRing*[T] = object ## a singly linked ring
-    head*: SinglyLinkedNode[T]
+    head*, tail*: SinglyLinkedNode[T]
   
   DoublyLinkedRing*[T] = object ## a doubly linked ring
     head*: DoublyLinkedNode[T]
@@ -122,6 +122,22 @@ iterator items*[T](L: DoublyLinkedRing[T]): T =
   ## yields every value of `L`.
   itemsRingImpl()
 
+iterator mitems*[T](L: var DoublyLinkedList[T]): var T =
+  ## yields every value of `L` so that you can modify it.
+  itemsListImpl()
+
+iterator mitems*[T](L: var SinglyLinkedList[T]): var T =
+  ## yields every value of `L` so that you can modify it.
+  itemsListImpl()
+
+iterator mitems*[T](L: var SinglyLinkedRing[T]): var T =
+  ## yields every value of `L` so that you can modify it.
+  itemsRingImpl()
+
+iterator mitems*[T](L: var DoublyLinkedRing[T]): var T =
+  ## yields every value of `L` so that you can modify it.
+  itemsRingImpl()
+
 iterator nodes*[T](L: SinglyLinkedList[T]): SinglyLinkedNode[T] = 
   ## iterates over every node of `x`. Removing the current node from the
   ## list during traversal is supported.
@@ -251,13 +267,31 @@ proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
   if n.prev != nil: n.prev.next = n.next
 
 
+proc append*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = 
+  ## appends a node `n` to `L`. Efficiency: O(1).
+  if L.head != nil:
+    n.next = L.head
+    assert(L.tail != nil)
+    L.tail.next = n
+    L.tail = n
+  else:
+    n.next = n
+    L.head = n
+    L.tail = n
+
+proc append*[T](L: var SinglyLinkedRing[T], value: T) = 
+  ## appends a value to `L`. Efficiency: O(1).
+  append(L, newSinglyLinkedNode(value))
+
 proc prepend*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = 
   ## prepends a node `n` to `L`. Efficiency: O(1).
-  if L.head != nil: 
-    n.next = L.head    
-    L.head.next = n
-  else: 
+  if L.head != nil:
+    n.next = L.head
+    assert(L.tail != nil)
+    L.tail.next = n
+  else:
     n.next = n
+    L.tail = n
   L.head = n
 
 proc prepend*[T](L: var SinglyLinkedRing[T], value: T) = 
diff --git a/lib/pure/collections/queues.nim b/lib/pure/collections/queues.nim
index 38e0b4212..af5e7b6cd 100644
--- a/lib/pure/collections/queues.nim
+++ b/lib/pure/collections/queues.nim
@@ -7,7 +7,9 @@
 #    distribution, for details about the copyright.
 #
 
-## Implementation of a queue. The underlying implementation uses a ``seq``.
+## Implementation of a `queue`:idx:. The underlying implementation uses a ``seq``.
+## Note: For inter thread communication use
+## a `TChannel <channels.html>`_ instead.
 
 import math
 
@@ -37,6 +39,15 @@ iterator items*[T](q: Queue[T]): T =
     yield q.data[i]
     i = (i + 1) and q.mask
 
+iterator mitems*[T](q: var Queue[T]): var T =
+  ## yields every element of `q`.
+  var i = q.rd
+  var c = q.count
+  while c > 0:
+    dec c
+    yield q.data[i]
+    i = (i + 1) and q.mask
+
 proc add*[T](q: var Queue[T], item: T) =
   ## adds an `item` to the end of the queue `q`.
   var cap = q.mask+1
diff --git a/lib/pure/collections/rtarrays.nim b/lib/pure/collections/rtarrays.nim
new file mode 100644
index 000000000..9d8085643
--- /dev/null
+++ b/lib/pure/collections/rtarrays.nim
@@ -0,0 +1,36 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+## Module that implements a fixed length array whose size
+## is determined at runtime. Note: This is not ready for other people to use!
+
+const
+  ArrayPartSize = 10
+
+type
+  RtArray*[T] = object  ##
+    L: Natural
+    spart: seq[T]
+    apart: array [ArrayPartSize, T]
+  UncheckedArray* {.unchecked.}[T] = array[0..100_000_000, T]
+
+template usesSeqPart(x): expr = x.L > ArrayPartSize
+
+proc initRtArray*[T](len: Natural): RtArray[T] =
+  result.L = len
+  if usesSeqPart(result):
+    newSeq(result.spart, len)
+
+proc getRawData*[T](x: var RtArray[T]): ptr UncheckedArray[T] =
+  if usesSeqPart(x): cast[ptr UncheckedArray[T]](addr(x.spart[0]))
+  else: cast[ptr UncheckedArray[T]](addr(x.apart[0]))
+
+#proc len*[T](x: RtArray[T]): int = x.L
+
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index befc9bacb..e9cd2cb3c 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -47,6 +47,24 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
       result[i] = itm
       inc(i)
 
+proc repeat*[T](s: seq[T], n: Natural): seq[T] =
+  ## Returns a new sequence with the items of `s` repeated `n` times.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:
+  ##
+  ##   let
+  ##     s = @[1, 2, 3]
+  ##     total = s.repeat(3)
+  ##   assert total == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
+  result = newSeq[T](n * s.len)
+  var o = 0
+  for x in 1..n:
+    for e in s:
+      result[o] = e
+      inc o
+
 proc deduplicate*[T](seq1: seq[T]): seq[T] =
   ## Returns a new sequence without duplicates.
   ##
@@ -63,7 +81,7 @@ proc deduplicate*[T](seq1: seq[T]): seq[T] =
     if not result.contains(itm): result.add(itm)
 
 {.deprecated: [distnct: deduplicate].}
-    
+
 proc zip*[S, T](seq1: seq[S], seq2: seq[T]): seq[tuple[a: S, b: T]] =
   ## Returns a new sequence with a combination of the two input sequences.
   ##
@@ -86,7 +104,7 @@ proc zip*[S, T](seq1: seq[S], seq2: seq[T]): seq[tuple[a: S, b: T]] =
   newSeq(result, m)
   for i in 0 .. m-1: result[i] = (seq1[i], seq2[i])
 
-proc distribute*[T](s: seq[T], num: int, spread = true): seq[seq[T]] =
+proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
   ## Splits and distributes a sequence `s` into `num` sub sequences.
   ##
   ## Returns a sequence of `num` sequences. For some input values this is the
@@ -113,11 +131,12 @@ proc distribute*[T](s: seq[T], num: int, spread = true): seq[seq[T]] =
   ##   assert numbers.distribute(6)[0] == @[1, 2]
   ##   assert numbers.distribute(6)[5] == @[7]
   assert(not s.isNil, "`s` can't be nil")
-  assert(num > 0, "`num` has to be greater than zero")
   if num < 2:
     result = @[s]
     return
 
+  let num = int(num) # XXX probably only needed because of .. bug
+
   # Create the result and calculate the stride size and the remainder if any.
   result = newSeq[seq[T]](num)
   var
@@ -162,7 +181,7 @@ iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T =
   ##   for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
   ##     echo($n)
   ##   # echoes 4, 8, 4 in separate lines
-  for i in countup(0, len(seq1) -1):
+  for i in countup(0, len(seq1)-1):
     var item = seq1[i]
     if pred(item): yield seq1[i]
 
@@ -209,7 +228,7 @@ proc delete*[T](s: var seq[T], first=0, last=0) =
   ##   var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
   ##   dest.delete(3, 8)
   ##   assert outcome == dest
-  
+
   var i = first
   var j = last+1
   var newLen = len(s)-j+i
@@ -227,12 +246,12 @@ proc insert*[T](dest: var seq[T], src: openArray[T], pos=0) =
   ##
   ##.. code-block::
   ##   var dest = @[1,1,1,1,1,1,1,1]
-  ##   let 
+  ##   let
   ##     src = @[2,2,2,2,2,2]
   ##     outcome = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
   ##   dest.insert(src, 3)
   ##   assert dest == outcome
-  
+
   var j = len(dest) - 1
   var i = len(dest) + len(src) - 1
   dest.setLen(i + 1)
@@ -320,7 +339,7 @@ template foldl*(sequence, operation: expr): expr =
   ##
   ## The ``operation`` parameter should be an expression which uses the
   ## variables ``a`` and ``b`` for each step of the fold. Since this is a left
-  ## fold, for non associative binary operations like substraction think that
+  ## fold, for non associative binary operations like subtraction think that
   ## the sequence of numbers 1, 2 and 3 will be parenthesized as (((1) - 2) -
   ## 3).  Example:
   ##
@@ -328,12 +347,12 @@ template foldl*(sequence, operation: expr): expr =
   ##   let
   ##     numbers = @[5, 9, 11]
   ##     addition = foldl(numbers, a + b)
-  ##     substraction = foldl(numbers, a - b)
+  ##     subtraction = foldl(numbers, a - b)
   ##     multiplication = foldl(numbers, a * b)
   ##     words = @["nim", "is", "cool"]
   ##     concatenation = foldl(words, a & b)
   ##   assert addition == 25, "Addition is (((5)+9)+11)"
-  ##   assert substraction == -15, "Substraction is (((5)-9)-11)"
+  ##   assert subtraction == -15, "Subtraction is (((5)-9)-11)"
   ##   assert multiplication == 495, "Multiplication is (((5)*9)*11)"
   ##   assert concatenation == "nimiscool"
   assert sequence.len > 0, "Can't fold empty sequences"
@@ -356,7 +375,7 @@ template foldr*(sequence, operation: expr): expr =
   ##
   ## The ``operation`` parameter should be an expression which uses the
   ## variables ``a`` and ``b`` for each step of the fold. Since this is a right
-  ## fold, for non associative binary operations like substraction think that
+  ## fold, for non associative binary operations like subtraction think that
   ## the sequence of numbers 1, 2 and 3 will be parenthesized as (1 - (2 -
   ## (3))). Example:
   ##
@@ -364,12 +383,12 @@ template foldr*(sequence, operation: expr): expr =
   ##   let
   ##     numbers = @[5, 9, 11]
   ##     addition = foldr(numbers, a + b)
-  ##     substraction = foldr(numbers, a - b)
+  ##     subtraction = foldr(numbers, a - b)
   ##     multiplication = foldr(numbers, a * b)
   ##     words = @["nim", "is", "cool"]
   ##     concatenation = foldr(words, a & b)
   ##   assert addition == 25, "Addition is (5+(9+(11)))"
-  ##   assert substraction == 7, "Substraction is (5-(9-(11)))"
+  ##   assert subtraction == 7, "Subtraction is (5-(9-(11)))"
   ##   assert multiplication == 495, "Multiplication is (5*(9*(11)))"
   ##   assert concatenation == "nimiscool"
   assert sequence.len > 0, "Can't fold empty sequences"
@@ -382,7 +401,7 @@ template foldr*(sequence, operation: expr): expr =
     result = operation
   result
 
-template mapIt*(seq1, typ, pred: expr): expr =
+template mapIt*(seq1, typ, op: expr): expr =
   ## Convenience template around the ``map`` proc to reduce typing.
   ##
   ## The template injects the ``it`` variable which you can use directly in an
@@ -397,10 +416,10 @@ template mapIt*(seq1, typ, pred: expr): expr =
   ##   assert strings == @["4", "8", "12", "16"]
   var result {.gensym.}: seq[typ] = @[]
   for it {.inject.} in items(seq1):
-    result.add(pred)
+    result.add(op)
   result
 
-template mapIt*(varSeq, pred: expr) =
+template mapIt*(varSeq, op: expr) =
   ## Convenience template around the mutable ``map`` proc to reduce typing.
   ##
   ## The template injects the ``it`` variable which you can use directly in an
@@ -413,7 +432,7 @@ template mapIt*(varSeq, pred: expr) =
   ##   assert nums[0] + nums[3] == 15
   for i in 0 .. <len(varSeq):
     let it {.inject.} = varSeq[i]
-    varSeq[i] = pred
+    varSeq[i] = op
 
 template newSeqWith*(len: int, init: expr): expr =
   ## creates a new sequence, calling `init` to initialize each value. Example:
@@ -473,9 +492,8 @@ when isMainModule:
 
   block: # filter iterator test
     let numbers = @[1, 4, 5, 8, 9, 7, 4]
-    for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
-      echo($n)
-    # echoes 4, 8, 4 in separate lines
+    assert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) ==
+      @[4, 8, 4]
 
   block: # keepIf test
     var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
@@ -507,12 +525,12 @@ when isMainModule:
     let
       numbers = @[5, 9, 11]
       addition = foldl(numbers, a + b)
-      substraction = foldl(numbers, a - b)
+      subtraction = foldl(numbers, a - b)
       multiplication = foldl(numbers, a * b)
       words = @["nim", "is", "cool"]
       concatenation = foldl(words, a & b)
     assert addition == 25, "Addition is (((5)+9)+11)"
-    assert substraction == -15, "Substraction is (((5)-9)-11)"
+    assert subtraction == -15, "Subtraction is (((5)-9)-11)"
     assert multiplication == 495, "Multiplication is (((5)*9)*11)"
     assert concatenation == "nimiscool"
 
@@ -520,12 +538,12 @@ when isMainModule:
     let
       numbers = @[5, 9, 11]
       addition = foldr(numbers, a + b)
-      substraction = foldr(numbers, a - b)
+      subtraction = foldr(numbers, a - b)
       multiplication = foldr(numbers, a * b)
       words = @["nim", "is", "cool"]
       concatenation = foldr(words, a & b)
     assert addition == 25, "Addition is (5+(9+(11)))"
-    assert substraction == 7, "Substraction is (5-(9-(11)))"
+    assert subtraction == 7, "Subtraction is (5-(9-(11)))"
     assert multiplication == 495, "Multiplication is (5*(9*(11)))"
     assert concatenation == "nimiscool"
 
@@ -534,12 +552,12 @@ when isMainModule:
     var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
     dest.delete(3, 8)
     assert outcome == dest, """\
-    Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1] 
+    Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1]
     is [1,1,1,1,1,1,1,1]"""
 
   block: # insert tests
     var dest = @[1,1,1,1,1,1,1,1]
-    let 
+    let
       src = @[2,2,2,2,2,2]
       outcome = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
     dest.insert(src, 3)
@@ -587,4 +605,15 @@ when isMainModule:
     seq2D[0][1] = true
     doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
 
-  echo "Finished doc tests"
+  block: # repeat tests
+    let
+      a = @[1, 2, 3]
+      b: seq[int] = @[]
+
+    doAssert a.repeat(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
+    doAssert a.repeat(0) == @[]
+    #doAssert a.repeat(-1) == @[] # will not compile!
+    doAssert b.repeat(3) == @[]
+
+  when not defined(testing):
+    echo "Finished doc tests"
diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim
index 92ef3152d..280e0eeba 100644
--- a/lib/pure/collections/sets.nim
+++ b/lib/pure/collections/sets.nim
@@ -7,7 +7,8 @@
 #    distribution, for details about the copyright.
 #
 
-## The ``sets`` module implements an efficient hash set and ordered hash set.
+## The ``sets`` module implements an efficient `hash set`:idx: and
+## ordered hash set.
 ##
 ## Hash sets are different from the `built in set type
 ## <manual.html#set-type>`_. Sets allow you to store any value that can be
@@ -23,9 +24,12 @@ import
 when not defined(nimhygiene):
   {.pragma: dirty.}
 
+# For "integer-like A" that are too big for intsets/bit-vectors to be practical,
+# it would be best to shrink hcode to the same size as the integer.  Larger
+# codes should never be needed, and this can pack more entries per cache-line.
+# Losing hcode entirely is also possible - if some element value is forbidden.
 type
-  SlotEnum = enum seEmpty, seFilled, seDeleted
-  KeyValuePair[A] = tuple[slot: SlotEnum, key: A]
+  KeyValuePair[A] = tuple[hcode: THash, key: A]
   KeyValuePairSeq[A] = seq[KeyValuePair[A]]
   HashSet* {.myShallow.}[A] = object ## \
     ## A generic hash set.
@@ -37,6 +41,14 @@ type
 
 {.deprecated: [TSet: HashSet].}
 
+# hcode for real keys cannot be zero.  hcode==0 signifies an empty slot.  These
+# two procs retain clarity of that encoding without the space cost of an enum.
+proc isEmpty(hcode: THash): bool {.inline.} =
+  result = hcode == 0
+
+proc isFilled(hcode: THash): bool {.inline.} =
+  result = hcode != 0
+
 proc isValid*[A](s: HashSet[A]): bool =
   ## Returns `true` if the set has been initialized with `initSet <#initSet>`_.
   ##
@@ -93,7 +105,7 @@ iterator items*[A](s: HashSet[A]): A =
   ##   # --> {(a: 1, b: 3), (a: 0, b: 4)}
   assert s.isValid, "The set needs to be initialized."
   for h in 0..high(s.data):
-    if s.data[h].slot == seFilled: yield s.data[h].key
+    if isFilled(s.data[h].hcode): yield s.data[h].key
 
 const
   growthFactor = 2
@@ -102,25 +114,44 @@ proc mustRehash(length, counter: int): bool {.inline.} =
   assert(length > counter)
   result = (length * 2 < counter * 3) or (length - counter < 4)
 
-proc nextTry(h, maxHash: THash): THash {.inline.} =
-  result = ((5 * h) + 1) and maxHash
+proc rightSize*(count: Natural): int {.inline.} =
+  ## Return the value of `initialSize` to support `count` items.
+  ##
+  ## If more items are expected to be added, simply add that
+  ## expected extra amount to the parameter before calling this.
+  ##
+  ## Internally, we want mustRehash(rightSize(x), x) == false.
+  result = nextPowerOfTwo(count * 3 div 2  +  4)
 
-template rawGetImpl() {.dirty.} =
-  var h: THash = hash(key) and high(s.data) # start with real hash value
-  while s.data[h].slot != seEmpty:
-    if s.data[h].key == key and s.data[h].slot == seFilled:
+proc nextTry(h, maxHash: THash): THash {.inline.} =
+  result = (h + 1) and maxHash
+
+template rawGetKnownHCImpl() {.dirty.} =
+  var h: THash = hc and high(s.data)  # start with real hash value
+  while isFilled(s.data[h].hcode):
+    # Compare hc THEN key with boolean short circuit. This makes the common case
+    # zero ==key's for missing (e.g.inserts) and exactly one ==key for present.
+    # It does slow down succeeding lookups by one extra THash cmp&and..usually
+    # just a few clock cycles, generally worth it for any non-integer-like A.
+    if s.data[h].hcode == hc and s.data[h].key == key:  # compare hc THEN key
       return h
     h = nextTry(h, high(s.data))
-  result = -1
+  result = -1 - h                   # < 0 => MISSING; insert idx = -1 - result
+
+template rawGetImpl() {.dirty.} =
+  hc = hash(key)
+  if hc == 0:       # This almost never taken branch should be very predictable.
+    hc = 314159265  # Value doesn't matter; Any non-zero favorite is fine.
+  rawGetKnownHCImpl()
 
 template rawInsertImpl() {.dirty.} =
-  var h: THash = hash(key) and high(data)
-  while data[h].slot == seFilled:
-    h = nextTry(h, high(data))
   data[h].key = key
-  data[h].slot = seFilled
+  data[h].hcode = hc
 
-proc rawGet[A](s: HashSet[A], key: A): int =
+proc rawGetKnownHC[A](s: HashSet[A], key: A, hc: THash): int {.inline.} =
+  rawGetKnownHCImpl()
+
+proc rawGet[A](s: HashSet[A], key: A, hc: var THash): int {.inline.} =
   rawGetImpl()
 
 proc mget*[A](s: var HashSet[A], key: A): var A =
@@ -129,7 +160,8 @@ proc mget*[A](s: var HashSet[A], key: A): var A =
   ## when one overloaded 'hash' and '==' but still needs reference semantics
   ## for sharing.
   assert s.isValid, "The set needs to be initialized."
-  var index = rawGet(s, key)
+  var hc: THash
+  var index = rawGet(s, key, hc)
   if index >= 0: result = s.data[index].key
   else: raise newException(KeyError, "key not found: " & $key)
 
@@ -146,33 +178,43 @@ proc contains*[A](s: HashSet[A], key: A): bool =
   ##   values.excl(2)
   ##   assert(not values.contains(2))
   assert s.isValid, "The set needs to be initialized."
-  var index = rawGet(s, key)
+  var hc: THash
+  var index = rawGet(s, key, hc)
   result = index >= 0
 
-proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A) =
+proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A,
+                  hc: THash, h: THash) =
   rawInsertImpl()
 
 proc enlarge[A](s: var HashSet[A]) =
   var n: KeyValuePairSeq[A]
   newSeq(n, len(s.data) * growthFactor)
-  for i in countup(0, high(s.data)):
-    if s.data[i].slot == seFilled: rawInsert(s, n, s.data[i].key)
-  swap(s.data, n)
+  swap(s.data, n)                   # n is now old seq
+  for i in countup(0, high(n)):
+    if isFilled(n[i].hcode):
+      var j = -1 - rawGetKnownHC(s, n[i].key, n[i].hcode)
+      rawInsert(s, s.data, n[i].key, n[i].hcode, j)
 
 template inclImpl() {.dirty.} =
-  var index = rawGet(s, key)
+  var hc: THash
+  var index = rawGet(s, key, hc)
   if index < 0:
-    if mustRehash(len(s.data), s.counter): enlarge(s)
-    rawInsert(s, s.data, key)
+    if mustRehash(len(s.data), s.counter):
+      enlarge(s)
+      index = rawGetKnownHC(s, key, hc)
+    rawInsert(s, s.data, key, hc, -1 - index)
     inc(s.counter)
 
 template containsOrInclImpl() {.dirty.} =
-  var index = rawGet(s, key)
+  var hc: THash
+  var index = rawGet(s, key, hc)
   if index >= 0:
     result = true
   else:
-    if mustRehash(len(s.data), s.counter): enlarge(s)
-    rawInsert(s, s.data, key)
+    if mustRehash(len(s.data), s.counter):
+      enlarge(s)
+      index = rawGetKnownHC(s, key, hc)
+    rawInsert(s, s.data, key, hc, -1 - index)
     inc(s.counter)
 
 proc incl*[A](s: var HashSet[A], key: A) =
@@ -203,6 +245,11 @@ proc incl*[A](s: var HashSet[A], other: HashSet[A]) =
   assert other.isValid, "The set `other` needs to be initialized."
   for item in other: incl(s, item)
 
+template doWhile(a: expr, b: stmt): stmt =
+  while true:
+    b
+    if not a: break
+
 proc excl*[A](s: var HashSet[A], key: A) =
   ## Excludes `key` from the set `s`.
   ##
@@ -214,10 +261,22 @@ proc excl*[A](s: var HashSet[A], key: A) =
   ##   s.excl(2)
   ##   assert s.len == 3
   assert s.isValid, "The set needs to be initialized."
-  var index = rawGet(s, key)
-  if index >= 0:
-    s.data[index].slot = seDeleted
+  var hc: THash
+  var i = rawGet(s, key, hc)
+  var msk = high(s.data)
+  if i >= 0:
+    s.data[i].hcode = 0
     dec(s.counter)
+    while true:         # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1
+      var j = i         # The correctness of this depends on (h+1) in nextTry,
+      var r = j         # though may be adaptable to other simple sequences.
+      s.data[i].hcode = 0              # mark current EMPTY
+      doWhile ((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)):
+        i = (i + 1) and msk            # increment mod table size
+        if isEmpty(s.data[i].hcode):   # end of collision cluster; So all done
+          return
+        r = s.data[i].hcode and msk    # "home" location of key@i
+      shallowCopy(s.data[j], s.data[i]) # data[j] will be marked EMPTY next loop
 
 proc excl*[A](s: var HashSet[A], other: HashSet[A]) =
   ## Excludes everything in `other` from `s`.
@@ -253,10 +312,10 @@ proc containsOrIncl*[A](s: var HashSet[A], key: A): bool =
 proc init*[A](s: var HashSet[A], initialSize=64) =
   ## Initializes a hash set.
   ##
-  ## The `initialSize` parameter needs to be a power of too. You can use
-  ## `math.nextPowerOfTwo() <math.html#nextPowerOfTwo>`_ to guarantee that at
-  ## runtime. All set variables have to be initialized before you can use them
-  ## with other procs from this module with the exception of `isValid()
+  ## The `initialSize` parameter needs to be a power of two. You can use
+  ## `math.nextPowerOfTwo() <math.html#nextPowerOfTwo>`_ or `rightSize` to
+  ## guarantee that at runtime. All set variables must be initialized before
+  ## use with other procs from this module with the exception of `isValid()
   ## <#isValid,TSet[A]>`_ and `len() <#len,TSet[A]>`_.
   ##
   ## You can call this proc on a previously initialized hash set, which will
@@ -294,7 +353,7 @@ proc toSet*[A](keys: openArray[A]): HashSet[A] =
   ##   var numbers = toSet([1, 2, 3, 4, 5])
   ##   assert numbers.contains(2)
   ##   assert numbers.contains(4)
-  result = initSet[A](nextPowerOfTwo(keys.len+10))
+  result = initSet[A](rightSize(keys.len))
   for key in items(keys): result.incl(key)
 
 template dollarImpl(): stmt {.dirty.} =
@@ -493,7 +552,7 @@ proc map*[A, B](data: HashSet[A], op: proc (x: A): B {.closure.}): HashSet[B] =
 
 type
   OrderedKeyValuePair[A] = tuple[
-    slot: SlotEnum, next: int, key: A]
+    hcode: THash, next: int, key: A]
   OrderedKeyValuePairSeq[A] = seq[OrderedKeyValuePair[A]]
   OrderedSet* {.myShallow.}[A] = object ## \
     ## A generic hash set that remembers insertion order.
@@ -545,7 +604,7 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} =
   var h = s.first
   while h >= 0:
     var nxt = s.data[h].next
-    if s.data[h].slot == seFilled: yieldStmt
+    if isFilled(s.data[h].hcode): yieldStmt
     h = nxt
 
 iterator items*[A](s: OrderedSet[A]): A =
@@ -570,7 +629,10 @@ iterator items*[A](s: OrderedSet[A]): A =
   forAllOrderedPairs:
     yield s.data[h].key
 
-proc rawGet[A](s: OrderedSet[A], key: A): int =
+proc rawGetKnownHC[A](s: OrderedSet[A], key: A, hc: THash): int {.inline.} =
+  rawGetKnownHCImpl()
+
+proc rawGet[A](s: OrderedSet[A], key: A, hc: var THash): int {.inline.} =
   rawGetImpl()
 
 proc contains*[A](s: OrderedSet[A], key: A): bool =
@@ -584,11 +646,12 @@ proc contains*[A](s: OrderedSet[A], key: A): bool =
   ##   values.incl(2)
   ##   assert values.contains(2)
   assert s.isValid, "The set needs to be initialized."
-  var index = rawGet(s, key)
+  var hc: THash
+  var index = rawGet(s, key, hc)
   result = index >= 0
 
-proc rawInsert[A](s: var OrderedSet[A], 
-                  data: var OrderedKeyValuePairSeq[A], key: A) =
+proc rawInsert[A](s: var OrderedSet[A], data: var OrderedKeyValuePairSeq[A],
+                  key: A, hc: THash, h: THash) =
   rawInsertImpl()
   data[h].next = -1
   if s.first < 0: s.first = h
@@ -601,12 +664,13 @@ proc enlarge[A](s: var OrderedSet[A]) =
   var h = s.first
   s.first = -1
   s.last = -1
+  swap(s.data, n)
   while h >= 0:
-    var nxt = s.data[h].next
-    if s.data[h].slot == seFilled: 
-      rawInsert(s, n, s.data[h].key)
+    var nxt = n[h].next
+    if isFilled(n[h].hcode):
+      var j = -1 - rawGetKnownHC(s, n[h].key, n[h].hcode)
+      rawInsert(s, s.data, n[h].key, n[h].hcode, j)
     h = nxt
-  swap(s.data, n)
 
 proc incl*[A](s: var OrderedSet[A], key: A) =
   ## Includes an element `key` in `s`.
@@ -654,10 +718,10 @@ proc containsOrIncl*[A](s: var OrderedSet[A], key: A): bool =
 proc init*[A](s: var OrderedSet[A], initialSize=64) =
   ## Initializes an ordered hash set.
   ##
-  ## The `initialSize` parameter needs to be a power of too. You can use
-  ## `math.nextPowerOfTwo() <math.html#nextPowerOfTwo>`_ to guarantee that at
-  ## runtime. All set variables have to be initialized before you can use them
-  ## with other procs from this module with the exception of `isValid()
+  ## The `initialSize` parameter needs to be a power of two. You can use
+  ## `math.nextPowerOfTwo() <math.html#nextPowerOfTwo>`_ or `rightSize` to
+  ## guarantee that at runtime. All set variables must be initialized before
+  ## use with other procs from this module with the exception of `isValid()
   ## <#isValid,TOrderedSet[A]>`_ and `len() <#len,TOrderedSet[A]>`_.
   ##
   ## You can call this proc on a previously initialized ordered hash set to
@@ -697,7 +761,7 @@ proc toOrderedSet*[A](keys: openArray[A]): OrderedSet[A] =
   ##   var numbers = toOrderedSet([1, 2, 3, 4, 5])
   ##   assert numbers.contains(2)
   ##   assert numbers.contains(4)
-  result = initOrderedSet[A](nextPowerOfTwo(keys.len+10))
+  result = initOrderedSet[A](rightSize(keys.len))
   for key in items(keys): result.incl(key)
 
 proc `$`*[A](s: OrderedSet[A]): string =
@@ -725,7 +789,7 @@ proc `==`*[A](s, t: OrderedSet[A]): bool =
   while h >= 0 and g >= 0:
     var nxh = s.data[h].next
     var nxg = t.data[g].next
-    if s.data[h].slot == seFilled and s.data[g].slot == seFilled:
+    if isFilled(s.data[h].hcode) and isFilled(s.data[g].hcode):
       if s.data[h].key == s.data[g].key:
         inc compared
       else:
@@ -734,172 +798,179 @@ proc `==`*[A](s, t: OrderedSet[A]): bool =
     g = nxg
   result = compared == s.counter
 
-proc testModule() =
-  ## Internal micro test to validate docstrings and such.
-  block isValidTest:
-    var options: HashSet[string]
-    proc savePreferences(options: HashSet[string]) =
-      assert options.isValid, "Pass an initialized set!"
-    options = initSet[string]()
-    options.savePreferences
-
-  block lenTest:
-    var values: HashSet[int]
-    assert(not values.isValid)
-    assert values.len == 0
-    assert values.card == 0
-
-  block setIterator:
-    type pair = tuple[a, b: int]
-    var a, b = initSet[pair]()
-    a.incl((2, 3))
-    a.incl((3, 2))
-    a.incl((2, 3))
-    for x, y in a.items:
-      b.incl((x - 2, y + 1))
-    assert a.len == b.card
-    assert a.len == 2
-    #echo b
-
-  block setContains:
-    var values = initSet[int]()
-    assert(not values.contains(2))
-    values.incl(2)
-    assert values.contains(2)
-    values.excl(2)
-    assert(not values.contains(2))
-
-    values.incl(4)
-    var others = toSet([6, 7])
-    values.incl(others)
-    assert values.len == 3
-
-    values.init
-    assert values.containsOrIncl(2) == false
-    assert values.containsOrIncl(2) == true
-    var
-      a = toSet([1, 2])
-      b = toSet([1])
-    b.incl(2)
-    assert a == b
-
-  block exclusions:
-    var s = toSet([2, 3, 6, 7])
-    s.excl(2)
-    s.excl(2)
-    assert s.len == 3
-
-    var
-      numbers = toSet([1, 2, 3, 4, 5])
-      even = toSet([2, 4, 6, 8])
-    numbers.excl(even)
-    #echo numbers
-    # --> {1, 3, 5}
-
-  block toSeqAndString:
-    var a = toSet([2, 4, 5])
-    var b = initSet[int]()
-    for x in [2, 4, 5]: b.incl(x)
-    assert($a == $b)
-    #echo a
-    #echo toSet(["no", "esc'aping", "is \" provided"])
-
-  #block orderedToSeqAndString:
-  #  echo toOrderedSet([2, 4, 5])
-  #  echo toOrderedSet(["no", "esc'aping", "is \" provided"])
-
-  block setOperations:
-    var
-      a = toSet(["a", "b"])
-      b = toSet(["b", "c"])
-      c = union(a, b)
-    assert c == toSet(["a", "b", "c"])
-    var d = intersection(a, b)
-    assert d == toSet(["b"])
-    var e = difference(a, b)
-    assert e == toSet(["a"])
-    var f = symmetricDifference(a, b)
-    assert f == toSet(["a", "c"])
-    assert d < a and d < b
-    assert((a < a) == false)
-    assert d <= a and d <= b
-    assert((a <= a))
-    # Alias test.
-    assert a + b == toSet(["a", "b", "c"])
-    assert a * b == toSet(["b"])
-    assert a - b == toSet(["a"])
-    assert a -+- b == toSet(["a", "c"])
-    assert disjoint(a, b) == false
-    assert disjoint(a, b - a) == true
-
-  block mapSet:
-    var a = toSet([1, 2, 3])
-    var b = a.map(proc (x: int): string = $x)
-    assert b == toSet(["1", "2", "3"])
-
-  block isValidTest:
-    var cards: OrderedSet[string]
-    proc saveTarotCards(cards: OrderedSet[string]) =
-      assert cards.isValid, "Pass an initialized set!"
-    cards = initOrderedSet[string]()
-    cards.saveTarotCards
-
-  block lenTest:
-    var values: OrderedSet[int]
-    assert(not values.isValid)
-    assert values.len == 0
-    assert values.card == 0
-
-  block setIterator:
-    type pair = tuple[a, b: int]
-    var a, b = initOrderedSet[pair]()
-    a.incl((2, 3))
-    a.incl((3, 2))
-    a.incl((2, 3))
-    for x, y in a.items:
-      b.incl((x - 2, y + 1))
-    assert a.len == b.card
-    assert a.len == 2
-
-  #block orderedSetIterator:
-  #  var a = initOrderedSet[int]()
-  #  for value in [9, 2, 1, 5, 1, 8, 4, 2]:
-  #    a.incl(value)
-  #  for value in a.items:
-  #    echo "Got ", value
-
-  block setContains:
-    var values = initOrderedSet[int]()
-    assert(not values.contains(2))
-    values.incl(2)
-    assert values.contains(2)
-
-  block toSeqAndString:
-    var a = toOrderedSet([2, 4, 5])
-    var b = initOrderedSet[int]()
-    for x in [2, 4, 5]: b.incl(x)
-    assert($a == $b)
-    assert(a == b) # https://github.com/Araq/Nimrod/issues/1413
-
-  block initBlocks:
-    var a: OrderedSet[int]
-    a.init(4)
-    a.incl(2)
-    a.init
-    assert a.len == 0 and a.isValid
-    a = initOrderedSet[int](4)
-    a.incl(2)
-    assert a.len == 1
-
-    var b: HashSet[int]
-    b.init(4)
-    b.incl(2)
-    b.init
-    assert b.len == 0 and b.isValid
-    b = initSet[int](4)
-    b.incl(2)
-    assert b.len == 1
-
-  echo "Micro tests run successfully."
-
-when isMainModule and not defined(release): testModule()
+when isMainModule and not defined(release):
+  proc testModule() =
+    ## Internal micro test to validate docstrings and such.
+    block isValidTest:
+      var options: HashSet[string]
+      proc savePreferences(options: HashSet[string]) =
+        assert options.isValid, "Pass an initialized set!"
+      options = initSet[string]()
+      options.savePreferences
+
+    block lenTest:
+      var values: HashSet[int]
+      assert(not values.isValid)
+      assert values.len == 0
+      assert values.card == 0
+
+    block setIterator:
+      type pair = tuple[a, b: int]
+      var a, b = initSet[pair]()
+      a.incl((2, 3))
+      a.incl((3, 2))
+      a.incl((2, 3))
+      for x, y in a.items:
+        b.incl((x - 2, y + 1))
+      assert a.len == b.card
+      assert a.len == 2
+      #echo b
+
+    block setContains:
+      var values = initSet[int]()
+      assert(not values.contains(2))
+      values.incl(2)
+      assert values.contains(2)
+      values.excl(2)
+      assert(not values.contains(2))
+
+      values.incl(4)
+      var others = toSet([6, 7])
+      values.incl(others)
+      assert values.len == 3
+
+      values.init
+      assert values.containsOrIncl(2) == false
+      assert values.containsOrIncl(2) == true
+      var
+        a = toSet([1, 2])
+        b = toSet([1])
+      b.incl(2)
+      assert a == b
+
+    block exclusions:
+      var s = toSet([2, 3, 6, 7])
+      s.excl(2)
+      s.excl(2)
+      assert s.len == 3
+
+      var
+        numbers = toSet([1, 2, 3, 4, 5])
+        even = toSet([2, 4, 6, 8])
+      numbers.excl(even)
+      #echo numbers
+      # --> {1, 3, 5}
+
+    block toSeqAndString:
+      var a = toSet([2, 4, 5])
+      var b = initSet[int]()
+      for x in [2, 4, 5]: b.incl(x)
+      assert($a == $b)
+      #echo a
+      #echo toSet(["no", "esc'aping", "is \" provided"])
+
+    #block orderedToSeqAndString:
+    #  echo toOrderedSet([2, 4, 5])
+    #  echo toOrderedSet(["no", "esc'aping", "is \" provided"])
+
+    block setOperations:
+      var
+        a = toSet(["a", "b"])
+        b = toSet(["b", "c"])
+        c = union(a, b)
+      assert c == toSet(["a", "b", "c"])
+      var d = intersection(a, b)
+      assert d == toSet(["b"])
+      var e = difference(a, b)
+      assert e == toSet(["a"])
+      var f = symmetricDifference(a, b)
+      assert f == toSet(["a", "c"])
+      assert d < a and d < b
+      assert((a < a) == false)
+      assert d <= a and d <= b
+      assert((a <= a))
+      # Alias test.
+      assert a + b == toSet(["a", "b", "c"])
+      assert a * b == toSet(["b"])
+      assert a - b == toSet(["a"])
+      assert a -+- b == toSet(["a", "c"])
+      assert disjoint(a, b) == false
+      assert disjoint(a, b - a) == true
+
+    block mapSet:
+      var a = toSet([1, 2, 3])
+      var b = a.map(proc (x: int): string = $x)
+      assert b == toSet(["1", "2", "3"])
+
+    block isValidTest:
+      var cards: OrderedSet[string]
+      proc saveTarotCards(cards: OrderedSet[string]) =
+        assert cards.isValid, "Pass an initialized set!"
+      cards = initOrderedSet[string]()
+      cards.saveTarotCards
+
+    block lenTest:
+      var values: OrderedSet[int]
+      assert(not values.isValid)
+      assert values.len == 0
+      assert values.card == 0
+
+    block setIterator:
+      type pair = tuple[a, b: int]
+      var a, b = initOrderedSet[pair]()
+      a.incl((2, 3))
+      a.incl((3, 2))
+      a.incl((2, 3))
+      for x, y in a.items:
+        b.incl((x - 2, y + 1))
+      assert a.len == b.card
+      assert a.len == 2
+
+    #block orderedSetIterator:
+    #  var a = initOrderedSet[int]()
+    #  for value in [9, 2, 1, 5, 1, 8, 4, 2]:
+    #    a.incl(value)
+    #  for value in a.items:
+    #    echo "Got ", value
+
+    block setContains:
+      var values = initOrderedSet[int]()
+      assert(not values.contains(2))
+      values.incl(2)
+      assert values.contains(2)
+
+    block toSeqAndString:
+      var a = toOrderedSet([2, 4, 5])
+      var b = initOrderedSet[int]()
+      for x in [2, 4, 5]: b.incl(x)
+      assert($a == $b)
+      assert(a == b) # https://github.com/Araq/Nimrod/issues/1413
+
+    block initBlocks:
+      var a: OrderedSet[int]
+      a.init(4)
+      a.incl(2)
+      a.init
+      assert a.len == 0 and a.isValid
+      a = initOrderedSet[int](4)
+      a.incl(2)
+      assert a.len == 1
+
+      var b: HashSet[int]
+      b.init(4)
+      b.incl(2)
+      b.init
+      assert b.len == 0 and b.isValid
+      b = initSet[int](4)
+      b.incl(2)
+      assert b.len == 1
+
+    for i in 0 .. 32:
+      var s = rightSize(i)
+      if s <= i or mustRehash(s, i):
+        echo "performance issue: rightSize() will not elide enlarge() at ", i
+
+    when not defined(testing):
+      echo "Micro tests run successfully."
+
+  testModule()
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index 41dfdaca6..232e52c89 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -1,14 +1,21 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2013 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
-## The ``tables`` module implements an efficient hash table that is
-## a mapping from keys to values.
+## The ``tables`` module implements variants of an efficient `hash table`:idx:
+## (also often named `dictionary`:idx: in other programming languages) that is
+## a mapping from keys to values. ``Table`` is the usual hash table,
+## ``OrderedTable`` is like ``Table`` but remembers insertion order
+## and ``CountTable`` is a mapping from a key to its number of occurrences.
+## For consistency with every other data type in Nim these have **value**
+## semantics, this means that ``=`` performs a copy of the hash table.
+## For **reference** semantics use the ``Ref`` variant: ``TableRef``,
+## ``OrderedTableRef``, ``CountTableRef``.
 ##
 ## If you are using simple standard types like ``int`` or ``string`` for the
 ## keys of the table you won't have any problems, but as soon as you try to use
@@ -24,9 +31,15 @@
 ##
 ## What is happening here is that the types used for table keys require to have
 ## a ``hash()`` proc which will convert them to a `THash <hashes.html#THash>`_
-## value, and the compiler is listing all the hash functions it knows. After
-## you add such a proc for your custom type everything will work. See this
-## example:
+## value, and the compiler is listing all the hash functions it knows.
+## Additionally there has to be a ``==`` operator that provides the same
+## semantics as its corresponding ``hash`` proc.
+##
+## After you add ``hash`` and ``==`` for your custom type everything will work.
+## Currently however ``hash`` for objects is not defined, whereas
+## ``system.==`` for objects does exist and performs a "deep" comparison (every
+## field is compared) which is usually what you want. So in the following
+## example implementing only ``hash`` suffices:
 ##
 ## .. code-block::
 ##   type
@@ -51,9 +64,6 @@
 ##   p2.firstName = "소진"
 ##   p2.lastName = "ë°•"
 ##   salaries[p2] = 45_000
-##
-## **Note:** The data types declared here have *value semantics*: This means
-## that ``=`` performs a copy of the hash table.
 
 import
   hashes, math
@@ -61,8 +71,7 @@ import
 {.pragma: myShallow.}
 
 type
-  SlotEnum = enum seEmpty, seFilled, seDeleted
-  KeyValuePair[A, B] = tuple[slot: SlotEnum, key: A, val: B]
+  KeyValuePair[A, B] = tuple[hcode: THash, key: A, val: B]
   KeyValuePairSeq[A, B] = seq[KeyValuePair[A, B]]
   Table* {.myShallow.}[A, B] = object ## generic hash table
     data: KeyValuePairSeq[A, B]
@@ -74,35 +83,43 @@ type
 when not defined(nimhygiene):
   {.pragma: dirty.}
 
+# hcode for real keys cannot be zero.  hcode==0 signifies an empty slot.  These
+# two procs retain clarity of that encoding without the space cost of an enum.
+proc isEmpty(hcode: THash): bool {.inline.} =
+  result = hcode == 0
+
+proc isFilled(hcode: THash): bool {.inline.} =
+  result = hcode != 0
+
 proc len*[A, B](t: Table[A, B]): int =
   ## returns the number of keys in `t`.
   result = t.counter
 
-iterator pairs*[A, B](t: Table[A, B]): tuple[key: A, val: B] =
+iterator pairs*[A, B](t: Table[A, B]): (A, B) =
   ## iterates over any (key, value) pair in the table `t`.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
+    if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
 
-iterator mpairs*[A, B](t: var Table[A, B]): tuple[key: A, val: var B] =
+iterator mpairs*[A, B](t: var Table[A, B]): (A, var B) =
   ## iterates over any (key, value) pair in the table `t`. The values
   ## can be modified.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
+    if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
 
 iterator keys*[A, B](t: Table[A, B]): A =
   ## iterates over any key in the table `t`.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield t.data[h].key
+    if isFilled(t.data[h].hcode): yield t.data[h].key
 
 iterator values*[A, B](t: Table[A, B]): B =
   ## iterates over any value in the table `t`.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield t.data[h].val
+    if isFilled(t.data[h].hcode): yield t.data[h].val
 
 iterator mvalues*[A, B](t: var Table[A, B]): var B =
   ## iterates over any value in the table `t`. The values can be modified.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield t.data[h].val
+    if isFilled(t.data[h].hcode): yield t.data[h].val
 
 const
   growthFactor = 2
@@ -111,26 +128,57 @@ proc mustRehash(length, counter: int): bool {.inline.} =
   assert(length > counter)
   result = (length * 2 < counter * 3) or (length - counter < 4)
 
+proc rightSize*(count: Natural): int {.inline.} =
+  ## Return the value of `initialSize` to support `count` items.
+  ##
+  ## If more items are expected to be added, simply add that
+  ## expected extra amount to the parameter before calling this.
+  ##
+  ## Internally, we want mustRehash(rightSize(x), x) == false.
+  result = nextPowerOfTwo(count * 3 div 2  +  4)
+
 proc nextTry(h, maxHash: THash): THash {.inline.} =
-  result = ((5 * h) + 1) and maxHash
+  result = (h + 1) and maxHash
+
+template rawGetKnownHCImpl() {.dirty.} =
+  var h: THash = hc and high(t.data)   # start with real hash value
+  while isFilled(t.data[h].hcode):
+    # Compare hc THEN key with boolean short circuit. This makes the common case
+    # zero ==key's for missing (e.g.inserts) and exactly one ==key for present.
+    # It does slow down succeeding lookups by one extra THash cmp&and..usually
+    # just a few clock cycles, generally worth it for any non-integer-like A.
+    if t.data[h].hcode == hc and t.data[h].key == key:
+      return h
+    h = nextTry(h, high(t.data))
+  result = -1 - h                   # < 0 => MISSING; insert idx = -1 - result
 
 template rawGetImpl() {.dirty.} =
-  var h: THash = hash(key) and high(t.data) # start with real hash value
-  while t.data[h].slot != seEmpty:
-    if t.data[h].key == key and t.data[h].slot == seFilled:
-      return h
+  hc = hash(key)
+  if hc == 0:       # This almost never taken branch should be very predictable.
+    hc = 314159265  # Value doesn't matter; Any non-zero favorite is fine.
+  rawGetKnownHCImpl()
+
+template rawGetDeepImpl() {.dirty.} =   # Search algo for unconditional add
+  hc = hash(key)
+  if hc == 0:
+    hc = 314159265
+  var h: THash = hc and high(t.data)
+  while isFilled(t.data[h].hcode):
     h = nextTry(h, high(t.data))
-  result = -1
+  result = h
 
 template rawInsertImpl() {.dirty.} =
-  var h: THash = hash(key) and high(data)
-  while data[h].slot == seFilled:
-    h = nextTry(h, high(data))
   data[h].key = key
   data[h].val = val
-  data[h].slot = seFilled
+  data[h].hcode = hc
 
-proc rawGet[A, B](t: Table[A, B], key: A): int =
+proc rawGetKnownHC[A, B](t: Table[A, B], key: A, hc: THash): int {.inline.} =
+  rawGetKnownHCImpl()
+
+proc rawGetDeep[A, B](t: Table[A, B], key: A, hc: var THash): int {.inline.} =
+  rawGetDeepImpl()
+
+proc rawGet[A, B](t: Table[A, B], key: A, hc: var THash): int {.inline.} =
   rawGetImpl()
 
 proc `[]`*[A, B](t: Table[A, B], key: A): B =
@@ -138,63 +186,91 @@ proc `[]`*[A, B](t: Table[A, B], key: A): B =
   ## default empty value for the type `B` is returned
   ## and no exception is raised. One can check with ``hasKey`` whether the key
   ## exists.
-  var index = rawGet(t, key)
+  var hc: THash
+  var index = rawGet(t, key, hc)
   if index >= 0: result = t.data[index].val
 
 proc mget*[A, B](t: var Table[A, B], key: A): var B =
   ## retrieves the value at ``t[key]``. The value can be modified.
-  ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
-  var index = rawGet(t, key)
+  ## If `key` is not in `t`, the ``KeyError`` exception is raised.
+  var hc: THash
+  var index = rawGet(t, key, hc)
   if index >= 0: result = t.data[index].val
-  else: raise newException(KeyError, "key not found: " & $key)
+  else:
+    when compiles($key):
+      raise newException(KeyError, "key not found: " & $key)
+    else:
+      raise newException(KeyError, "key not found")
 
 iterator allValues*[A, B](t: Table[A, B]; key: A): B =
   ## iterates over any value in the table `t` that belongs to the given `key`.
   var h: THash = hash(key) and high(t.data)
-  while t.data[h].slot != seEmpty:
-    if t.data[h].key == key and t.data[h].slot == seFilled:
+  while isFilled(t.data[h].hcode):
+    if t.data[h].key == key:
       yield t.data[h].val
     h = nextTry(h, high(t.data))
 
 proc hasKey*[A, B](t: Table[A, B], key: A): bool =
   ## returns true iff `key` is in the table `t`.
-  result = rawGet(t, key) >= 0
+  var hc: THash
+  result = rawGet(t, key, hc) >= 0
 
 proc rawInsert[A, B](t: var Table[A, B], data: var KeyValuePairSeq[A, B],
-                     key: A, val: B) =
+                     key: A, val: B, hc: THash, h: THash) =
   rawInsertImpl()
 
 proc enlarge[A, B](t: var Table[A, B]) =
   var n: KeyValuePairSeq[A, B]
   newSeq(n, len(t.data) * growthFactor)
-  for i in countup(0, high(t.data)):
-    if t.data[i].slot == seFilled: rawInsert(t, n, t.data[i].key, t.data[i].val)
   swap(t.data, n)
+  for i in countup(0, high(n)):
+    if isFilled(n[i].hcode):
+      var j = -1 - rawGetKnownHC(t, n[i].key, n[i].hcode)
+      rawInsert(t, t.data, n[i].key, n[i].val, n[i].hcode, j)
 
 template addImpl() {.dirty.} =
   if mustRehash(len(t.data), t.counter): enlarge(t)
-  rawInsert(t, t.data, key, val)
+  var hc: THash
+  var j = rawGetDeep(t, key, hc)
+  rawInsert(t, t.data, key, val, hc, j)
+  inc(t.counter)
+
+template maybeRehashPutImpl() {.dirty.} =
+  if mustRehash(len(t.data), t.counter):
+    enlarge(t)
+    index = rawGetKnownHC(t, key, hc)
+  index = -1 - index                  # important to transform for mgetOrPutImpl
+  rawInsert(t, t.data, key, val, hc, index)
   inc(t.counter)
 
 template putImpl() {.dirty.} =
-  var index = rawGet(t, key)
-  if index >= 0:
-    t.data[index].val = val
-  else:
-    addImpl()
-
-when false:
-  # not yet used:
-  template hasKeyOrPutImpl() {.dirty.} =
-    var index = rawGet(t, key)
-    if index >= 0:
-      t.data[index].val = val
-      result = true
-    else:
-      if mustRehash(len(t.data), t.counter): enlarge(t)
-      rawInsert(t, t.data, key, val)
-      inc(t.counter)
-      result = false
+  var hc: THash
+  var index = rawGet(t, key, hc)
+  if index >= 0: t.data[index].val = val
+  else: maybeRehashPutImpl()
+
+template mgetOrPutImpl() {.dirty.} =
+  var hc: THash
+  var index = rawGet(t, key, hc)
+  if index < 0: maybeRehashPutImpl()    # not present: insert (flipping index)
+  result = t.data[index].val            # either way return modifiable val
+
+template hasKeyOrPutImpl() {.dirty.} =
+  var hc: THash
+  var index = rawGet(t, key, hc)
+  if index < 0:
+    result = false
+    maybeRehashPutImpl()
+  else: result = true
+
+proc mgetOrPut*[A, B](t: var Table[A, B], key: A, val: B): var B =
+  ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
+  ## returning a value which can be modified.
+  mgetOrPutImpl()
+
+proc hasKeyOrPut*[A, B](t: var Table[A, B], key: A, val: B): bool =
+  ## returns true iff `key` is in the table, otherwise inserts `value`.
+  hasKeyOrPutImpl()
 
 proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) =
   ## puts a (key, value)-pair into `t`.
@@ -203,28 +279,45 @@ proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) =
 proc add*[A, B](t: var Table[A, B], key: A, val: B) =
   ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
   addImpl()
-  
+
+template doWhile(a: expr, b: stmt): stmt =
+  while true:
+    b
+    if not a: break
+
 proc del*[A, B](t: var Table[A, B], key: A) =
   ## deletes `key` from hash table `t`.
-  let index = rawGet(t, key)
-  if index >= 0:
-    t.data[index].slot = seDeleted
+  var hc: THash
+  var i = rawGet(t, key, hc)
+  let msk = high(t.data)
+  if i >= 0:
+    t.data[i].hcode = 0
     dec(t.counter)
+    while true:         # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1
+      var j = i         # The correctness of this depends on (h+1) in nextTry,
+      var r = j         # though may be adaptable to other simple sequences.
+      t.data[i].hcode = 0              # mark current EMPTY
+      doWhile ((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)):
+        i = (i + 1) and msk            # increment mod table size
+        if isEmpty(t.data[i].hcode):   # end of collision cluster; So all done
+          return
+        r = t.data[i].hcode and msk    # "home" location of key@i
+      shallowCopy(t.data[j], t.data[i]) # data[j] will be marked EMPTY next loop
 
 proc initTable*[A, B](initialSize=64): Table[A, B] =
   ## creates a new hash table that is empty.
   ##
   ## `initialSize` needs to be a power of two. If you need to accept runtime
   ## values for this you could use the ``nextPowerOfTwo`` proc from the
-  ## `math <math.html>`_ module.
+  ## `math <math.html>`_ module or the ``rightSize`` proc from this module.
   assert isPowerOfTwo(initialSize)
   result.counter = 0
   newSeq(result.data, initialSize)
 
-proc toTable*[A, B](pairs: openArray[tuple[key: A, 
-                    val: B]]): Table[A, B] =
+proc toTable*[A, B](pairs: openArray[(A,
+                    B)]): Table[A, B] =
   ## creates a new hash table that contains the given `pairs`.
-  result = initTable[A, B](nextPowerOfTwo(pairs.len+10))
+  result = initTable[A, B](rightSize(pairs.len))
   for key, val in items(pairs): result[key] = val
 
 template dollarImpl(): stmt {.dirty.} =
@@ -242,7 +335,7 @@ template dollarImpl(): stmt {.dirty.} =
 proc `$`*[A, B](t: Table[A, B]): string =
   ## The `$` operator for hash tables.
   dollarImpl()
-  
+
 template equalsImpl() =
   if s.counter == t.counter:
     # different insertion orders mean different 'data' seqs, so we have
@@ -252,10 +345,10 @@ template equalsImpl() =
       if not t.hasKey(key): return false
       if t[key] != val: return false
     return true
-  
+
 proc `==`*[A, B](s, t: Table[A, B]): bool =
   equalsImpl()
-  
+
 proc indexBy*[A, B, C](collection: A, index: proc(x: B): C): Table[C, B] =
   ## Index the collection with the proc provided.
   # TODO: As soon as supported, change collection: A to collection: A[B]
@@ -267,31 +360,31 @@ proc len*[A, B](t: TableRef[A, B]): int =
   ## returns the number of keys in `t`.
   result = t.counter
 
-iterator pairs*[A, B](t: TableRef[A, B]): tuple[key: A, val: B] =
+iterator pairs*[A, B](t: TableRef[A, B]): (A, B) =
   ## iterates over any (key, value) pair in the table `t`.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
+    if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
 
-iterator mpairs*[A, B](t: TableRef[A, B]): tuple[key: A, val: var B] =
+iterator mpairs*[A, B](t: TableRef[A, B]): (A, var B) =
   ## iterates over any (key, value) pair in the table `t`. The values
   ## can be modified.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
+    if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
 
 iterator keys*[A, B](t: TableRef[A, B]): A =
   ## iterates over any key in the table `t`.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield t.data[h].key
+    if isFilled(t.data[h].hcode): yield t.data[h].key
 
 iterator values*[A, B](t: TableRef[A, B]): B =
   ## iterates over any value in the table `t`.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield t.data[h].val
+    if isFilled(t.data[h].hcode): yield t.data[h].val
 
 iterator mvalues*[A, B](t: TableRef[A, B]): var B =
   ## iterates over any value in the table `t`. The values can be modified.
   for h in 0..high(t.data):
-    if t.data[h].slot == seFilled: yield t.data[h].val
+    if isFilled(t.data[h].hcode): yield t.data[h].val
 
 proc `[]`*[A, B](t: TableRef[A, B], key: A): B =
   ## retrieves the value at ``t[key]``. If `key` is not in `t`,
@@ -305,6 +398,15 @@ proc mget*[A, B](t: TableRef[A, B], key: A): var B =
   ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
   t[].mget(key)
 
+proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B =
+  ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
+  ## returning a value which can be modified.
+  t[].mgetOrPut(key, val)
+
+proc hasKeyOrPut*[A, B](t: var TableRef[A, B], key: A, val: B): bool =
+  ## returns true iff `key` is in the table, otherwise inserts `value`.
+  t[].hasKeyOrPut(key, val)
+
 proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
   ## returns true iff `key` is in the table `t`.
   result = t[].hasKey(key)
@@ -316,7 +418,7 @@ proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: B) =
 proc add*[A, B](t: TableRef[A, B], key: A, val: B) =
   ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
   t[].add(key, val)
-  
+
 proc del*[A, B](t: TableRef[A, B], key: A) =
   ## deletes `key` from hash table `t`.
   t[].del(key)
@@ -325,7 +427,7 @@ proc newTable*[A, B](initialSize=64): TableRef[A, B] =
   new(result)
   result[] = initTable[A, B](initialSize)
 
-proc newTable*[A, B](pairs: openArray[tuple[key: A, val: B]]): TableRef[A, B] =
+proc newTable*[A, B](pairs: openArray[(A, B)]): TableRef[A, B] =
   ## creates a new hash table that contains the given `pairs`.
   new(result)
   result[] = toTable[A, B](pairs)
@@ -337,7 +439,7 @@ proc `$`*[A, B](t: TableRef[A, B]): string =
 proc `==`*[A, B](s, t: TableRef[A, B]): bool =
   if isNil(s): result = isNil(t)
   elif isNil(t): result = false
-  else: result = equalsImpl()
+  else: equalsImpl()
 
 proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B] =
   ## Index the collection with the proc provided.
@@ -350,7 +452,7 @@ proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B]
 
 type
   OrderedKeyValuePair[A, B] = tuple[
-    slot: SlotEnum, next: int, key: A, val: B]
+    hcode: THash, next: int, key: A, val: B]
   OrderedKeyValuePairSeq[A, B] = seq[OrderedKeyValuePair[A, B]]
   OrderedTable* {.
       myShallow.}[A, B] = object ## table that remembers insertion order
@@ -368,16 +470,16 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} =
   var h = t.first
   while h >= 0:
     var nxt = t.data[h].next
-    if t.data[h].slot == seFilled: yieldStmt
+    if isFilled(t.data[h].hcode): yieldStmt
     h = nxt
 
-iterator pairs*[A, B](t: OrderedTable[A, B]): tuple[key: A, val: B] =
+iterator pairs*[A, B](t: OrderedTable[A, B]): (A, B) =
   ## iterates over any (key, value) pair in the table `t` in insertion
   ## order.
   forAllOrderedPairs:
     yield (t.data[h].key, t.data[h].val)
 
-iterator mpairs*[A, B](t: var OrderedTable[A, B]): tuple[key: A, val: var B] =
+iterator mpairs*[A, B](t: var OrderedTable[A, B]): (A, var B) =
   ## iterates over any (key, value) pair in the table `t` in insertion
   ## order. The values can be modified.
   forAllOrderedPairs:
@@ -399,7 +501,13 @@ iterator mvalues*[A, B](t: var OrderedTable[A, B]): var B =
   forAllOrderedPairs:
     yield t.data[h].val
 
-proc rawGet[A, B](t: OrderedTable[A, B], key: A): int =
+proc rawGetKnownHC[A, B](t: OrderedTable[A, B], key: A, hc: THash): int =
+  rawGetKnownHCImpl()
+
+proc rawGetDeep[A, B](t: OrderedTable[A, B], key: A, hc: var THash): int {.inline.} =
+  rawGetDeepImpl()
+
+proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var THash): int =
   rawGetImpl()
 
 proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B =
@@ -407,23 +515,26 @@ proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B =
   ## default empty value for the type `B` is returned
   ## and no exception is raised. One can check with ``hasKey`` whether the key
   ## exists.
-  var index = rawGet(t, key)
+  var hc: THash
+  var index = rawGet(t, key, hc)
   if index >= 0: result = t.data[index].val
 
 proc mget*[A, B](t: var OrderedTable[A, B], key: A): var B =
   ## retrieves the value at ``t[key]``. The value can be modified.
   ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
-  var index = rawGet(t, key)
+  var hc: THash
+  var index = rawGet(t, key, hc)
   if index >= 0: result = t.data[index].val
   else: raise newException(KeyError, "key not found: " & $key)
 
 proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
   ## returns true iff `key` is in the table `t`.
-  result = rawGet(t, key) >= 0
+  var hc: THash
+  result = rawGet(t, key, hc) >= 0
 
-proc rawInsert[A, B](t: var OrderedTable[A, B], 
+proc rawInsert[A, B](t: var OrderedTable[A, B],
                      data: var OrderedKeyValuePairSeq[A, B],
-                     key: A, val: B) =
+                     key: A, val: B, hc: THash, h: THash) =
   rawInsertImpl()
   data[h].next = -1
   if t.first < 0: t.first = h
@@ -436,12 +547,13 @@ proc enlarge[A, B](t: var OrderedTable[A, B]) =
   var h = t.first
   t.first = -1
   t.last = -1
+  swap(t.data, n)
   while h >= 0:
-    var nxt = t.data[h].next
-    if t.data[h].slot == seFilled: 
-      rawInsert(t, n, t.data[h].key, t.data[h].val)
+    var nxt = n[h].next
+    if isFilled(n[h].hcode):
+      var j = -1 - rawGetKnownHC(t, n[h].key, n[h].hcode)
+      rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j)
     h = nxt
-  swap(t.data, n)
 
 proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: B) =
   ## puts a (key, value)-pair into `t`.
@@ -451,30 +563,39 @@ proc add*[A, B](t: var OrderedTable[A, B], key: A, val: B) =
   ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
   addImpl()
 
+proc mgetOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): var B =
+  ## retrieves value at ``t[key]`` or puts ``value`` if not present, either way
+  ## returning a value which can be modified.
+  mgetOrPutImpl()
+
+proc hasKeyOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): bool =
+  ## returns true iff `key` is in the table, otherwise inserts `value`.
+  hasKeyOrPutImpl()
+
 proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] =
   ## creates a new ordered hash table that is empty.
   ##
   ## `initialSize` needs to be a power of two. If you need to accept runtime
   ## values for this you could use the ``nextPowerOfTwo`` proc from the
-  ## `math <math.html>`_ module.
+  ## `math <math.html>`_ module or the ``rightSize`` proc from this module.
   assert isPowerOfTwo(initialSize)
   result.counter = 0
   result.first = -1
   result.last = -1
   newSeq(result.data, initialSize)
 
-proc toOrderedTable*[A, B](pairs: openArray[tuple[key: A, 
-                           val: B]]): OrderedTable[A, B] =
+proc toOrderedTable*[A, B](pairs: openArray[(A,
+                           B)]): OrderedTable[A, B] =
   ## creates a new ordered hash table that contains the given `pairs`.
-  result = initOrderedTable[A, B](nextPowerOfTwo(pairs.len+10))
+  result = initOrderedTable[A, B](rightSize(pairs.len))
   for key, val in items(pairs): result[key] = val
 
 proc `$`*[A, B](t: OrderedTable[A, B]): string =
   ## The `$` operator for ordered hash tables.
   dollarImpl()
 
-proc sort*[A, B](t: var OrderedTable[A, B], 
-                 cmp: proc (x,y: tuple[key: A, val: B]): int) =
+proc sort*[A, B](t: var OrderedTable[A, B],
+                 cmp: proc (x,y: (A, B)): int) =
   ## sorts `t` according to `cmp`. This modifies the internal list
   ## that kept the insertion order, so insertion order is lost after this
   ## call but key lookup and insertions remain possible after `sort` (in
@@ -496,7 +617,7 @@ proc sort*[A, B](t: var OrderedTable[A, B],
       while i < insize:
         inc(psize)
         q = t.data[q].next
-        if q < 0: break 
+        if q < 0: break
         inc(i)
       qsize = insize
       while psize > 0 or (qsize > 0 and q >= 0):
@@ -504,7 +625,7 @@ proc sort*[A, B](t: var OrderedTable[A, B],
           e = q; q = t.data[q].next; dec(qsize)
         elif qsize == 0 or q < 0:
           e = p; p = t.data[p].next; dec(psize)
-        elif cmp((t.data[p].key, t.data[p].val), 
+        elif cmp((t.data[p].key, t.data[p].val),
                  (t.data[q].key, t.data[q].val)) <= 0:
           e = p; p = t.data[p].next; dec(psize)
         else:
@@ -527,16 +648,16 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} =
   var h = t.first
   while h >= 0:
     var nxt = t.data[h].next
-    if t.data[h].slot == seFilled: yieldStmt
+    if isFilled(t.data[h].hcode): yieldStmt
     h = nxt
 
-iterator pairs*[A, B](t: OrderedTableRef[A, B]): tuple[key: A, val: B] =
+iterator pairs*[A, B](t: OrderedTableRef[A, B]): (A, B) =
   ## iterates over any (key, value) pair in the table `t` in insertion
   ## order.
   forAllOrderedPairs:
     yield (t.data[h].key, t.data[h].val)
 
-iterator mpairs*[A, B](t: OrderedTableRef[A, B]): tuple[key: A, val: var B] =
+iterator mpairs*[A, B](t: OrderedTableRef[A, B]): (A, var B) =
   ## iterates over any (key, value) pair in the table `t` in insertion
   ## order. The values can be modified.
   forAllOrderedPairs:
@@ -570,6 +691,15 @@ proc mget*[A, B](t: OrderedTableRef[A, B], key: A): var B =
   ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
   result = t[].mget(key)
 
+proc mgetOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): var B =
+  ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
+  ## returning a value which can be modified.
+  result = t[].mgetOrPut(key, val)
+
+proc hasKeyOrPut*[A, B](t: var OrderedTableRef[A, B], key: A, val: B): bool =
+  ## returns true iff `key` is in the table, otherwise inserts `val`.
+  result = t[].hasKeyOrPut(key, val)
+
 proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool =
   ## returns true iff `key` is in the table `t`.
   result = t[].hasKey(key)
@@ -587,22 +717,21 @@ proc newOrderedTable*[A, B](initialSize=64): OrderedTableRef[A, B] =
   ##
   ## `initialSize` needs to be a power of two. If you need to accept runtime
   ## values for this you could use the ``nextPowerOfTwo`` proc from the
-  ## `math <math.html>`_ module.
+  ## `math <math.html>`_ module or the ``rightSize`` proc from this module.
   new(result)
   result[] = initOrderedTable[A, B]()
 
-proc newOrderedTable*[A, B](pairs: openArray[tuple[key: A, 
-                           val: B]]): OrderedTableRef[A, B] =
+proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTableRef[A, B] =
   ## creates a new ordered hash table that contains the given `pairs`.
-  result = newOrderedTable[A, B](nextPowerOfTwo(pairs.len+10))
+  result = newOrderedTable[A, B](rightSize(pairs.len))
   for key, val in items(pairs): result[key] = val
 
 proc `$`*[A, B](t: OrderedTableRef[A, B]): string =
   ## The `$` operator for ordered hash tables.
   dollarImpl()
 
-proc sort*[A, B](t: OrderedTableRef[A, B], 
-                 cmp: proc (x,y: tuple[key: A, val: B]): int) =
+proc sort*[A, B](t: OrderedTableRef[A, B],
+                 cmp: proc (x,y: (A, B)): int) =
   ## sorts `t` according to `cmp`. This modifies the internal list
   ## that kept the insertion order, so insertion order is lost after this
   ## call but key lookup and insertions remain possible after `sort` (in
@@ -624,12 +753,12 @@ proc len*[A](t: CountTable[A]): int =
   ## returns the number of keys in `t`.
   result = t.counter
 
-iterator pairs*[A](t: CountTable[A]): tuple[key: A, val: int] =
+iterator pairs*[A](t: CountTable[A]): (A, int) =
   ## iterates over any (key, value) pair in the table `t`.
   for h in 0..high(t.data):
     if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
 
-iterator mpairs*[A](t: var CountTable[A]): tuple[key: A, val: var int] =
+iterator mpairs*[A](t: var CountTable[A]): (A, var int) =
   ## iterates over any (key, value) pair in the table `t`. The values can
   ## be modified.
   for h in 0..high(t.data):
@@ -655,7 +784,7 @@ proc rawGet[A](t: CountTable[A], key: A): int =
   while t.data[h].val != 0:
     if t.data[h].key == key: return h
     h = nextTry(h, high(t.data))
-  result = -1
+  result = -1 - h                   # < 0 => MISSING; insert idx = -1 - result
 
 proc `[]`*[A](t: CountTable[A], key: A): int =
   ## retrieves the value at ``t[key]``. If `key` is not in `t`,
@@ -692,28 +821,34 @@ proc enlarge[A](t: var CountTable[A]) =
 proc `[]=`*[A](t: var CountTable[A], key: A, val: int) =
   ## puts a (key, value)-pair into `t`. `val` has to be positive.
   assert val > 0
-  putImpl()
+  var h = rawGet(t, key)
+  if h >= 0:
+    t.data[h].val = val
+  else:
+    h = -1 - h
+    t.data[h].key = key
+    t.data[h].val = val
 
 proc initCountTable*[A](initialSize=64): CountTable[A] =
   ## creates a new count table that is empty.
   ##
   ## `initialSize` needs to be a power of two. If you need to accept runtime
   ## values for this you could use the ``nextPowerOfTwo`` proc from the
-  ## `math <math.html>`_ module.
+  ## `math <math.html>`_ module or the ``rightSize`` proc in this module.
   assert isPowerOfTwo(initialSize)
   result.counter = 0
   newSeq(result.data, initialSize)
 
 proc toCountTable*[A](keys: openArray[A]): CountTable[A] =
   ## creates a new count table with every key in `keys` having a count of 1.
-  result = initCountTable[A](nextPowerOfTwo(keys.len+10))
+  result = initCountTable[A](rightSize(keys.len))
   for key in items(keys): result[key] = 1
 
 proc `$`*[A](t: CountTable[A]): string =
   ## The `$` operator for count tables.
   dollarImpl()
 
-proc inc*[A](t: var CountTable[A], key: A, val = 1) = 
+proc inc*[A](t: var CountTable[A], key: A, val = 1) =
   ## increments `t[key]` by `val`.
   var index = rawGet(t, key)
   if index >= 0:
@@ -766,12 +901,12 @@ proc len*[A](t: CountTableRef[A]): int =
   ## returns the number of keys in `t`.
   result = t.counter
 
-iterator pairs*[A](t: CountTableRef[A]): tuple[key: A, val: int] =
+iterator pairs*[A](t: CountTableRef[A]): (A, int) =
   ## iterates over any (key, value) pair in the table `t`.
   for h in 0..high(t.data):
     if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
 
-iterator mpairs*[A](t: CountTableRef[A]): tuple[key: A, val: var int] =
+iterator mpairs*[A](t: CountTableRef[A]): (A, var int) =
   ## iterates over any (key, value) pair in the table `t`. The values can
   ## be modified.
   for h in 0..high(t.data):
@@ -817,28 +952,28 @@ proc newCountTable*[A](initialSize=64): CountTableRef[A] =
   ##
   ## `initialSize` needs to be a power of two. If you need to accept runtime
   ## values for this you could use the ``nextPowerOfTwo`` proc from the
-  ## `math <math.html>`_ module.
+  ## `math <math.html>`_ module or the ``rightSize`` method in this module.
   new(result)
   result[] = initCountTable[A](initialSize)
 
 proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] =
   ## creates a new count table with every key in `keys` having a count of 1.
-  result = newCountTable[A](nextPowerOfTwo(keys.len+10))
+  result = newCountTable[A](rightSize(keys.len))
   for key in items(keys): result[key] = 1
 
 proc `$`*[A](t: CountTableRef[A]): string =
   ## The `$` operator for count tables.
   dollarImpl()
 
-proc inc*[A](t: CountTableRef[A], key: A, val = 1) = 
+proc inc*[A](t: CountTableRef[A], key: A, val = 1) =
   ## increments `t[key]` by `val`.
   t[].inc(key, val)
 
-proc smallest*[A](t: CountTableRef[A]): tuple[key: A, val: int] =
+proc smallest*[A](t: CountTableRef[A]): (A, int) =
   ## returns the largest (key,val)-pair. Efficiency: O(n)
   t[].smallest
 
-proc largest*[A](t: CountTableRef[A]): tuple[key: A, val: int] =
+proc largest*[A](t: CountTableRef[A]): (A, int) =
   ## returns the (key,val)-pair with the largest `val`. Efficiency: O(n)
   t[].largest
 
@@ -849,6 +984,22 @@ proc sort*[A](t: CountTableRef[A]) =
   ## `t` in the sorted order.
   t[].sort
 
+proc merge*[A](s: var CountTable[A], t: CountTable[A]) =
+  ## merges the second table into the first one
+  for key, value in t:
+    s.inc(key, value)
+
+proc merge*[A](s, t: CountTable[A]): CountTable[A] =
+  ## merges the two tables into a new one
+  result = initCountTable[A](nextPowerOfTwo(max(s.len, t.len)))
+  for table in @[s, t]:
+    for key, value in table:
+      result.inc(key, value)
+
+proc merge*[A](s, t: CountTableRef[A]) =
+  ## merges the second table into the first one
+  s[].merge(t[])
+
 when isMainModule:
   type
     Person = object
@@ -877,3 +1028,48 @@ when isMainModule:
   s2[p2] = 45_000
   s3[p1] = 30_000
   s3[p2] = 45_000
+
+  var
+    t1 = initCountTable[string]()
+    t2 = initCountTable[string]()
+  t1.inc("foo")
+  t1.inc("bar", 2)
+  t1.inc("baz", 3)
+  t2.inc("foo", 4)
+  t2.inc("bar")
+  t2.inc("baz", 11)
+  merge(t1, t2)
+  assert(t1["foo"] == 5)
+  assert(t1["bar"] == 3)
+  assert(t1["baz"] == 14)
+
+  let
+    t1r = newCountTable[string]()
+    t2r = newCountTable[string]()
+  t1r.inc("foo")
+  t1r.inc("bar", 2)
+  t1r.inc("baz", 3)
+  t2r.inc("foo", 4)
+  t2r.inc("bar")
+  t2r.inc("baz", 11)
+  merge(t1r, t2r)
+  assert(t1r["foo"] == 5)
+  assert(t1r["bar"] == 3)
+  assert(t1r["baz"] == 14)
+
+  var
+    t1l = initCountTable[string]()
+    t2l = initCountTable[string]()
+  t1l.inc("foo")
+  t1l.inc("bar", 2)
+  t1l.inc("baz", 3)
+  t2l.inc("foo", 4)
+  t2l.inc("bar")
+  t2l.inc("baz", 11)
+  let
+    t1merging = t1l
+    t2merging = t2l
+  let merged = merge(t1merging, t2merging)
+  assert(merged["foo"] == 5)
+  assert(merged["bar"] == 3)
+  assert(merged["baz"] == 14)
diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim
index 7942255cb..f24cc0072 100644
--- a/lib/pure/colors.nim
+++ b/lib/pure/colors.nim
@@ -46,7 +46,7 @@ proc `+`*(a, b: Color): Color =
   colorOp(satPlus)
   
 proc `-`*(a, b: Color): Color =
-  ## substracts two colors: This uses saturated artithmetic, so that each color
+  ## subtracts two colors: This uses saturated artithmetic, so that each color
   ## component cannot overflow (255 is used as a maximum).
   colorOp(satMinus)
   
@@ -392,7 +392,7 @@ proc parseColor*(name: string): Color =
     result = Color(parseHexInt(name))
   else:
     var idx = binaryStrSearch(colorNames, name)
-    if idx < 0: raise newException(ValueError, "unkown color: " & name)
+    if idx < 0: raise newException(ValueError, "unknown color: " & name)
     result = colorNames[idx][1]
 
 proc isColor*(name: string): bool =
diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim
index a8709e098..8577bf7a1 100644
--- a/lib/pure/complex.nim
+++ b/lib/pure/complex.nim
@@ -19,10 +19,7 @@ import
   math
  
 const
-  EPS = 5.0e-6 ## Epsilon used for float comparisons (should be smaller
-               ## if float is really float64, but w/ the current version
-               ## it seems to be float32?)
-
+  EPS = 1.0e-7 ## Epsilon used for float comparisons.
 
 type
   Complex* = tuple[re, im: float]
@@ -30,6 +27,11 @@ type
 
 {.deprecated: [TComplex: Complex].}
 
+proc toComplex*(x: SomeInteger): Complex =
+  ## Convert some integer ``x`` to a complex number.
+  result.re = x
+  result.im = 0
+
 proc `==` *(x, y: Complex): bool =
   ## Compare two complex numbers `x` and `y` for equality.
   result = x.re == y.re and x.im == y.im
@@ -174,6 +176,12 @@ proc abs*(z: Complex): float =
     result = y * sqrt(1.0 + temp * temp)
 
 
+proc conjugate*(z: Complex): Complex =
+  ## Conjugate of complex number `z`.
+  result.re = z.re
+  result.im = -z.im
+
+
 proc sqrt*(z: Complex): Complex =
   ## Square root for a complex number `z`.
   var x, y, w, r: float
@@ -266,27 +274,101 @@ proc tan*(z: Complex): Complex =
   ## Returns the tangent of `z`.
   result = sin(z)/cos(z)
 
+proc arctan*(z: Complex): Complex =
+  ## Returns the inverse tangent of `z`.
+  var i: Complex = (0.0,1.0)
+  result = 0.5*i*(ln(1-i*z)-ln(1+i*z))
+
 proc cot*(z: Complex): Complex =
   ## Returns the cotangent of `z`.
   result = cos(z)/sin(z)
 
+proc arccot*(z: Complex): Complex =
+  ## Returns the inverse cotangent of `z`.
+  var i: Complex = (0.0,1.0)
+  result = 0.5*i*(ln(1-i/z)-ln(1+i/z))
+
 proc sec*(z: Complex): Complex =
   ## Returns the secant of `z`.
   result = 1.0/cos(z)
 
+proc arcsec*(z: Complex): Complex =
+  ## Returns the inverse secant of `z`.
+  var i: Complex = (0.0,1.0)
+  result = -i*ln(i*sqrt(1-1/(z*z))+1/z)
+
 proc csc*(z: Complex): Complex =
   ## Returns the cosecant of `z`.
   result = 1.0/sin(z)
 
+proc arccsc*(z: Complex): Complex =
+  ## Returns the inverse cosecant of `z`.
+  var i: Complex = (0.0,1.0)
+  result = -i*ln(sqrt(1-1/(z*z))+i/z)
+
 
 proc sinh*(z: Complex): Complex =
   ## Returns the hyperbolic sine of `z`.
   result = 0.5*(exp(z)-exp(-z))
 
+proc arcsinh*(z: Complex): Complex =
+  ## Returns the inverse hyperbolic sine of `z`.
+  result = ln(z+sqrt(z*z+1))
+
 proc cosh*(z: Complex): Complex =
   ## Returns the hyperbolic cosine of `z`.
   result = 0.5*(exp(z)+exp(-z))
 
+proc arccosh*(z: Complex): Complex =
+  ## Returns the inverse hyperbolic cosine of `z`.
+  result = ln(z+sqrt(z*z-1))
+
+proc tanh*(z: Complex): Complex =
+  ## Returns the hyperbolic tangent of `z`.
+  result = sinh(z)/cosh(z)
+
+proc arctanh*(z: Complex): Complex =
+  ## Returns the inverse hyperbolic tangent of `z`.
+  result = 0.5*(ln((1+z)/(1-z)))
+
+proc sech*(z: Complex): Complex =
+  ## Returns the hyperbolic secant of `z`.
+  result = 2/(exp(z)+exp(-z))
+
+proc arcsech*(z: Complex): Complex =
+  ## Returns the inverse hyperbolic secant of `z`.
+  result = ln(1/z+sqrt(1/z+1)*sqrt(1/z-1))
+
+proc csch*(z: Complex): Complex =
+  ## Returns the hyperbolic cosecant of `z`.
+  result = 2/(exp(z)-exp(-z))
+
+proc arccsch*(z: Complex): Complex =
+  ## Returns the inverse hyperbolic cosecant of `z`.
+  result = ln(1/z+sqrt(1/(z*z)+1))
+
+proc coth*(z: Complex): Complex =
+  ## Returns the hyperbolic cotangent of `z`.
+  result = cosh(z)/sinh(z)
+
+proc arccoth*(z: Complex): Complex =
+  ## Returns the inverse hyperbolic cotangent of `z`.
+  result = 0.5*(ln(1+1/z)-ln(1-1/z))
+
+proc phase*(z: Complex): float =
+  ## Returns the phase of `z`.
+  arctan2(z.im, z.re)
+
+proc polar*(z: Complex): tuple[r, phi: float] =
+  ## Returns `z` in polar coordinates.
+  result.r = abs(z)
+  result.phi = phase(z)
+
+proc rect*(r: float, phi: float): Complex =
+  ## Returns the complex number with polar coordinates `r` and `phi`.
+  result.re = r * cos(phi)
+  result.im = r * sin(phi)
+
 
 proc `$`*(z: Complex): string =
   ## Returns `z`'s string representation as ``"(re, im)"``.
@@ -306,41 +388,56 @@ when isMainModule:
   var tt = (10.0, 20.0)
   var ipi = (0.0, -PI)
  
-  assert( a         == a )
-  assert( (a-a)     == z )
-  assert( (a+b)     == z )
-  assert( (a/b)     == m1 )
-  assert( (1.0/a)   == (0.2, -0.4) )
-  assert( (a*b)     == (3.0, -4.0) )
-  assert( 10.0*a    == tt )
-  assert( a*10.0    == tt )
-  assert( tt/10.0   == a )
+  assert( a == a )
+  assert( (a-a) == z )
+  assert( (a+b) == z )
+  assert( (a/b) == m1 )
+  assert( (1.0/a) == (0.2, -0.4) )
+  assert( (a*b) == (3.0, -4.0) )
+  assert( 10.0*a == tt )
+  assert( a*10.0 == tt )
+  assert( tt/10.0 == a )
   assert( oo+(-1.0) == i )
   assert( (-1.0)+oo == i )
-  assert( abs(oo)   == sqrt(2.0) )
-  assert( sqrt(m1)  == i )
-  assert( exp(ipi)  =~ m1 )
+  assert( abs(oo) == sqrt(2.0) )
+  assert( conjugate(a) == (1.0, -2.0) )
+  assert( sqrt(m1) == i )
+  assert( exp(ipi) =~ m1 )
  
-  assert( pow(a,b)   =~ (-3.72999124927876, -1.68815826725068) )
-  assert( pow(z,a)   =~ (0.0, 0.0) )
-  assert( pow(z,z)   =~ (1.0, 0.0) )
+  assert( pow(a,b) =~ (-3.72999124927876, -1.68815826725068) )
+  assert( pow(z,a) =~ (0.0, 0.0) )
+  assert( pow(z,z) =~ (1.0, 0.0) )
   assert( pow(a,one) =~ a )
-  assert( pow(a,m1)  =~ (0.2, -0.4) )
+  assert( pow(a,m1) =~ (0.2, -0.4) )
 
-  assert( ln(a)    =~ (0.804718956217050, 1.107148717794090) )
+  assert( ln(a) =~ (0.804718956217050, 1.107148717794090) )
   assert( log10(a) =~ (0.349485002168009, 0.480828578784234) )
-  assert( log2(a)  =~ (1.16096404744368, 1.59727796468811) )
-
-  assert( sin(a)    =~ (3.16577851321617, 1.95960104142161) )
-  assert( cos(a)    =~ (2.03272300701967, -3.05189779915180) )
-  assert( tan(a)    =~ (0.0338128260798967, 1.0147936161466335) )
-  assert( cot(a)    =~ 1.0/tan(a) )
-  assert( sec(a)    =~ 1.0/cos(a) )
-  assert( csc(a)    =~ 1.0/sin(a) )
+  assert( log2(a) =~ (1.16096404744368, 1.59727796468811) )
+
+  assert( sin(a) =~ (3.16577851321617, 1.95960104142161) )
+  assert( cos(a) =~ (2.03272300701967, -3.05189779915180) )
+  assert( tan(a) =~ (0.0338128260798967, 1.0147936161466335) )
+  assert( cot(a) =~ 1.0/tan(a) )
+  assert( sec(a) =~ 1.0/cos(a) )
+  assert( csc(a) =~ 1.0/sin(a) )
   assert( arcsin(a) =~ (0.427078586392476, 1.528570919480998) )
   assert( arccos(a) =~ (1.14371774040242, -1.52857091948100) )
+  assert( arctan(a) =~ (1.338972522294494, 0.402359478108525) )
 
-  assert( cosh(a) =~ (-0.642148124715520, 1.068607421382778) ) 
+  assert( cosh(a) =~ (-0.642148124715520, 1.068607421382778) )
   assert( sinh(a) =~ (-0.489056259041294, 1.403119250622040) )
-
-
+  assert( tanh(a) =~ (1.1667362572409199,-0.243458201185725) )
+  assert( sech(a) =~ 1/cosh(a) )
+  assert( csch(a) =~ 1/sinh(a) )
+  assert( coth(a) =~ 1/tanh(a) )
+  assert( arccosh(a) =~ (1.528570919480998, 1.14371774040242) )
+  assert( arcsinh(a) =~ (1.469351744368185, 1.06344002357775) )
+  assert( arctanh(a) =~ (0.173286795139986, 1.17809724509617) )
+  assert( arcsech(a) =~ arccosh(1/a) )
+  assert( arccsch(a) =~ arcsinh(1/a) )
+  assert( arccoth(a) =~ arctanh(1/a) )
+
+  assert( phase(a) == 1.1071487177940904 )
+  var t = polar(a)
+  assert( rect(t.r, t.phi) =~ a )
+  assert( rect(1.0, 2.0) =~ (-0.4161468365471424, 0.9092974268256817) )
diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim
index ac5fa5dd9..6f2bc4491 100644
--- a/lib/pure/concurrency/cpuinfo.nim
+++ b/lib/pure/concurrency/cpuinfo.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
diff --git a/lib/pure/concurrency/cpuload.nim b/lib/pure/concurrency/cpuload.nim
index 88fb4a064..7ce5e01b7 100644
--- a/lib/pure/concurrency/cpuload.nim
+++ b/lib/pure/concurrency/cpuload.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -78,7 +78,7 @@ proc advice*(s: var ThreadPoolState): ThreadPoolAdvice =
     result = doNothing
   inc s.calls
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   proc busyLoop() =
     while true:
       discard random(80)
diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim
index 28ef25d95..9f1e53fb8 100644
--- a/lib/pure/concurrency/threadpool.nim
+++ b/lib/pure/concurrency/threadpool.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -65,7 +65,9 @@ proc barrierEnter(b: ptr Barrier) {.compilerProc, inline.} =
 proc barrierLeave(b: ptr Barrier) {.compilerProc, inline.} =
   atomicInc b.left
   when not defined(x86): fence()
-  if b.interest and b.left == b.entered: signal(b.cv)
+  # We may not have seen the final value of b.entered yet,
+  # so we need to check for >= instead of ==.
+  if b.interest and b.left >= b.entered: signal(b.cv)
 
 proc openBarrier(b: ptr Barrier) {.compilerProc, inline.} =
   b.entered = 0
@@ -202,7 +204,7 @@ proc nimFlowVarSignal(fv: FlowVarBase) {.compilerProc.} =
     inc fv.ai.cv.counter
     release(fv.ai.cv.L)
     signal(fv.ai.cv.c)
-  if fv.usesSemaphore: 
+  if fv.usesSemaphore:
     signal(fv.cv)
 
 proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) =
diff --git a/lib/pure/concurrency/threadpool.nim.cfg b/lib/pure/concurrency/threadpool.nim.cfg
new file mode 100644
index 000000000..aed303eef
--- /dev/null
+++ b/lib/pure/concurrency/threadpool.nim.cfg
@@ -0,0 +1 @@
+--threads:on
diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim
index 6247efed2..9983c4a04 100644
--- a/lib/pure/cookies.nim
+++ b/lib/pure/cookies.nim
@@ -56,6 +56,12 @@ proc setCookie*(key, value: string, expires: TimeInfo,
 when isMainModule:
   var tim = Time(int(getTime()) + 76 * (60 * 60 * 24))
 
-  echo(setCookie("test", "value", tim.getGMTime()))
+  let cookie = setCookie("test", "value", tim.getGMTime())
+  when not defined(testing):
+    echo cookie
+  let start = "Set-Cookie: test=value; Expires="
+  assert cookie[0..start.high] == start
   
-  echo parseCookies("uid=1; kp=2")
+  let table = parseCookies("uid=1; kp=2")
+  assert table["uid"] == "1"
+  assert table["kp"] == "2"
diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim
index 958a4133b..2a6134615 100644
--- a/lib/pure/encodings.nim
+++ b/lib/pure/encodings.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -301,7 +301,7 @@ proc getCurrentEncoding*(): string =
   
 proc open*(destEncoding = "UTF-8", srcEncoding = "CP1252"): EncodingConverter =
   ## opens a converter that can convert from `srcEncoding` to `destEncoding`.
-  ## Raises `EIO` if it cannot fullfill the request.
+  ## Raises `EIO` if it cannot fulfill the request.
   when not defined(windows):
     result = iconvOpen(destEncoding, srcEncoding)
     if result == nil:
@@ -451,7 +451,7 @@ proc convert*(s: string, destEncoding = "UTF-8",
   finally:
     close(c)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   let
     orig = "öäüß"
     cp1252 = convert(orig, "CP1252", "UTF-8")
diff --git a/lib/pure/events.nim b/lib/pure/events.nim
index 47dc6ba3f..44e9ed286 100644
--- a/lib/pure/events.nim
+++ b/lib/pure/events.nim
@@ -9,7 +9,7 @@
 
 ## :Author: Alex Mitchell
 ##
-## This module implements an event system that is not dependant on external
+## This module implements an event system that is not dependent on external
 ## graphical toolkits. It was originally called ``NimEE`` because 
 ## it was inspired by Python's PyEE module. There are two ways you can use
 ## events: one is a python-inspired way; the other is more of a C-style way.
@@ -51,20 +51,20 @@ proc initEventHandler*(name: string): EventHandler =
   result.handlers = @[]
   result.name = name
 
-proc addHandler*(handler: var EventHandler, func: proc(e: EventArgs) {.closure.}) =
+proc addHandler*(handler: var EventHandler, fn: proc(e: EventArgs) {.closure.}) =
   ## Adds the callback to the specified event handler.
-  handler.handlers.add(func)
+  handler.handlers.add(fn)
 
-proc removeHandler*(handler: var EventHandler, func: proc(e: EventArgs) {.closure.}) =
+proc removeHandler*(handler: var EventHandler, fn: proc(e: EventArgs) {.closure.}) =
   ## Removes the callback from the specified event handler.
   for i in countup(0, len(handler.handlers) -1):
-    if func == handler.handlers[i]:
+    if fn == handler.handlers[i]:
       handler.handlers.del(i)
       break
     
-proc containsHandler*(handler: var EventHandler, func: proc(e: EventArgs) {.closure.}): bool =
+proc containsHandler*(handler: var EventHandler, fn: proc(e: EventArgs) {.closure.}): bool =
   ## Checks if a callback is registered to this event handler.
-  return handler.handlers.contains(func)
+  return handler.handlers.contains(fn)
 
 
 proc clearHandlers*(handler: var EventHandler) =
@@ -76,21 +76,21 @@ proc getEventHandler(emitter: var EventEmitter, event: string): int =
     if emitter.s[k].name == event: return k
   return -1
 
-proc on*(emitter: var EventEmitter, event: string, func: proc(e: EventArgs) {.closure.}) =
+proc on*(emitter: var EventEmitter, event: string, fn: proc(e: EventArgs) {.closure.}) =
   ## Assigns a event handler with the specified callback. If the event
   ## doesn't exist, it will be created.
   var i = getEventHandler(emitter, event)
   if i < 0:
     var eh = initEventHandler(event)
-    addHandler(eh, func)
+    addHandler(eh, fn)
     emitter.s.add(eh)
   else:
-    addHandler(emitter.s[i], func)
+    addHandler(emitter.s[i], fn)
   
 proc emit*(emitter: var EventEmitter, eventhandler: var EventHandler, 
            args: EventArgs) =
   ## Fires an event handler with specified event arguments.
-  for func in items(eventhandler.handlers): func(args)
+  for fn in items(eventhandler.handlers): fn(args)
 
 proc emit*(emitter: var EventEmitter, event: string, args: EventArgs) =
   ## Fires an event handler with specified event arguments.
diff --git a/lib/pure/fenv.nim b/lib/pure/fenv.nim
index 415ef455e..f8f115ecc 100644
--- a/lib/pure/fenv.nim
+++ b/lib/pure/fenv.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -101,3 +101,81 @@ proc feupdateenv*(envp: ptr Tfenv): cint {.importc, header: "<fenv.h>".}
   ## Save current exceptions in temporary storage, install environment
   ## represented by object pointed to by `envp` and raise exceptions
   ## according to saved exceptions.
+
+var FP_RADIX_INTERNAL {. importc: "FLT_RADIX" header: "<float.h>" .} : int
+
+template fpRadix* : int = FP_RADIX_INTERNAL
+  ## The (integer) value of the radix used to represent any floating
+  ## point type on the architecture used to build the program.
+
+var FLT_MANT_DIG {. importc: "FLT_MANT_DIG" header: "<float.h>" .} : int
+var FLT_DIG {. importc: "FLT_DIG" header: "<float.h>" .} : int
+var FLT_MIN_EXP {. importc: "FLT_MIN_EXP" header: "<float.h>" .} : int
+var FLT_MAX_EXP {. importc: "FLT_MAX_EXP" header: "<float.h>" .} : int
+var FLT_MIN_10_EXP {. importc: "FLT_MIN_10_EXP" header: "<float.h>" .} : int
+var FLT_MAX_10_EXP {. importc: "FLT_MAX_10_EXP" header: "<float.h>" .} : int
+var FLT_MIN {. importc: "FLT_MIN" header: "<float.h>" .} : cfloat
+var FLT_MAX {. importc: "FLT_MAX" header: "<float.h>" .} : cfloat
+var FLT_EPSILON {. importc: "FLT_EPSILON" header: "<float.h>" .} : cfloat
+
+var DBL_MANT_DIG {. importc: "DBL_MANT_DIG" header: "<float.h>" .} : int
+var DBL_DIG {. importc: "DBL_DIG" header: "<float.h>" .} : int
+var DBL_MIN_EXP {. importc: "DBL_MIN_EXP" header: "<float.h>" .} : int
+var DBL_MAX_EXP {. importc: "DBL_MAX_EXP" header: "<float.h>" .} : int
+var DBL_MIN_10_EXP {. importc: "DBL_MIN_10_EXP" header: "<float.h>" .} : int
+var DBL_MAX_10_EXP {. importc: "DBL_MAX_10_EXP" header: "<float.h>" .} : int
+var DBL_MIN {. importc: "DBL_MIN" header: "<float.h>" .} : cdouble
+var DBL_MAX {. importc: "DBL_MAX" header: "<float.h>" .} : cdouble
+var DBL_EPSILON {. importc: "DBL_EPSILON" header: "<float.h>" .} : cdouble
+
+template mantissaDigits*(T : typedesc[float32]) : int = FLT_MANT_DIG
+  ## Number of digits (in base ``floatingPointRadix``) in the mantissa
+  ## of 32-bit floating-point numbers.
+template digits*(T : typedesc[float32]) : int = FLT_DIG
+  ## Number of decimal digits that can be represented in a
+  ## 32-bit floating-point type without losing precision.
+template minExponent*(T : typedesc[float32]) : int = FLT_MIN_EXP
+  ## Minimum (negative) exponent for 32-bit floating-point numbers.
+template maxExponent*(T : typedesc[float32]) : int = FLT_MAX_EXP
+  ## Maximum (positive) exponent for 32-bit floating-point numbers.
+template min10Exponent*(T : typedesc[float32]) : int = FLT_MIN_10_EXP
+  ## Minimum (negative) exponent in base 10 for 32-bit floating-point
+  ## numbers.
+template max10Exponent*(T : typedesc[float32]) : int = FLT_MAX_10_EXP
+  ## Maximum (positive) exponent in base 10 for 32-bit floating-point
+  ## numbers.
+template minimumPositiveValue*(T : typedesc[float32]) : float32 = FLT_MIN
+  ## The smallest positive (nonzero) number that can be represented in a
+  ## 32-bit floating-point type.
+template maximumPositiveValue*(T : typedesc[float32]) : float32 = FLT_MAX
+  ## The largest positive number that can be represented in a 32-bit
+  ## floating-point type.
+template epsilon*(T : typedesc[float32]): float32 = FLT_EPSILON
+  ## The difference between 1.0 and the smallest number greater than
+  ## 1.0 that can be represented in a 32-bit floating-point type.
+
+template mantissaDigits*(T : typedesc[float64]) : int = DBL_MANT_DIG
+  ## Number of digits (in base ``floatingPointRadix``) in the mantissa
+  ## of 64-bit floating-point numbers.
+template digits*(T : typedesc[float64]) : int = DBL_DIG
+  ## Number of decimal digits that can be represented in a
+  ## 64-bit floating-point type without losing precision.
+template minExponent*(T : typedesc[float64]) : int = DBL_MIN_EXP
+  ## Minimum (negative) exponent for 64-bit floating-point numbers.
+template maxExponent*(T : typedesc[float64]) : int = DBL_MAX_EXP
+  ## Maximum (positive) exponent for 64-bit floating-point numbers.
+template min10Exponent*(T : typedesc[float64]) : int = DBL_MIN_10_EXP
+  ## Minimum (negative) exponent in base 10 for 64-bit floating-point
+  ## numbers.
+template max10Exponent*(T : typedesc[float64]) : int = DBL_MAX_10_EXP
+  ## Maximum (positive) exponent in base 10 for 64-bit floating-point
+  ## numbers.
+template minimumPositiveValue*(T : typedesc[float64]) : float64 = DBL_MIN
+  ## The smallest positive (nonzero) number that can be represented in a
+  ## 64-bit floating-point type.
+template maximumPositiveValue*(T : typedesc[float64]) : float64 = DBL_MAX
+  ## The largest positive number that can be represented in a 64-bit
+  ## floating-point type.
+template epsilon*(T : typedesc[float64]): float64 = DBL_EPSILON
+  ## The difference between 1.0 and the smallest number greater than
+  ## 1.0 that can be represented in a 64-bit floating-point type.
diff --git a/lib/pure/fsmonitor.nim b/lib/pure/fsmonitor.nim
index bf4aef61c..83779eb9c 100644
--- a/lib/pure/fsmonitor.nim
+++ b/lib/pure/fsmonitor.nim
@@ -29,7 +29,7 @@ type
   FSMonitorObj = object of RootObj
     fd: cint
     handleEvent: proc (m: FSMonitor, ev: MonitorEvent) {.closure.}
-    targets: TTable[cint, string]
+    targets: Table[cint, string]
   
   MonitorEventType* = enum ## Monitor event type
     MonitorAccess,       ## File was accessed.
@@ -64,7 +64,7 @@ type
 const
   MaxEvents = 100
 
-proc newMonitor*(): PFSMonitor =
+proc newMonitor*(): FSMonitor =
   ## Creates a new file system monitor.
   new(result)
   result.targets = initTable[cint, string]()
@@ -72,7 +72,7 @@ proc newMonitor*(): PFSMonitor =
   if result.fd < 0:
     raiseOSError(osLastError())
 
-proc add*(monitor: PFSMonitor, target: string,
+proc add*(monitor: FSMonitor, target: string,
                filters = {MonitorAll}): cint {.discardable.} =
   ## Adds ``target`` which may be a directory or a file to the list of
   ## watched paths of ``monitor``.
@@ -99,14 +99,14 @@ proc add*(monitor: PFSMonitor, target: string,
     raiseOSError(osLastError())
   monitor.targets.add(result, target)
 
-proc del*(monitor: PFSMonitor, wd: cint) =
+proc del*(monitor: FSMonitor, wd: cint) =
   ## Removes watched directory or file as specified by ``wd`` from ``monitor``.
   ##
   ## If ``wd`` is not a part of ``monitor`` an EOS error is raised.
   if inotifyRmWatch(monitor.fd, wd) < 0:
     raiseOSError(osLastError())
 
-proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] =
+proc getEvent(m: FSMonitor, fd: cint): seq[MonitorEvent] =
   result = @[]
   let size = (sizeof(TINotifyEvent)+2000)*MaxEvents
   var buffer = newString(size)
@@ -118,7 +118,7 @@ proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] =
   var i = 0
   while i < le:
     var event = cast[ptr TINotifyEvent](addr(buffer[i]))
-    var mev: TMonitorEvent
+    var mev: MonitorEvent
     mev.wd = event.wd
     if event.len.int != 0:
       let cstr = event.name.addr.cstring
@@ -137,7 +137,7 @@ proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] =
       # Find the MovedFrom event.
       mev.oldPath = movedFrom[event.cookie.cint].old
       mev.newPath = "" # Set later
-      # Delete it from the TTable
+      # Delete it from the Table
       movedFrom.del(event.cookie.cint)
     elif (event.mask.int and IN_ACCESS) != 0: mev.kind = MonitorAccess
     elif (event.mask.int and IN_ATTRIB) != 0: mev.kind = MonitorAttrib
@@ -164,26 +164,26 @@ proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] =
   # If movedFrom events have not been matched with a moveTo. File has
   # been moved to an unwatched location, emit a MonitorDelete.
   for cookie, t in pairs(movedFrom):
-    var mev: TMonitorEvent
+    var mev: MonitorEvent
     mev.kind = MonitorDelete
     mev.wd = t.wd
     mev.name = t.old
     result.add(mev)
 
-proc FSMonitorRead(h: PObject) =
-  var events = PFSMonitor(h).getEvent(PFSMonitor(h).fd)
-  #var newEv: TMonitorEvent
+proc FSMonitorRead(h: RootRef) =
+  var events = FSMonitor(h).getEvent(FSMonitor(h).fd)
+  #var newEv: MonitorEvent
   for ev in events:
-    var target = PFSMonitor(h).targets[ev.wd]
+    var target = FSMonitor(h).targets[ev.wd]
     var newEv = ev
     if newEv.kind == MonitorMoved:
       newEv.oldPath = target / newEv.oldPath
       newEv.newPath = target / newEv.name
     else:
       newEv.fullName = target / newEv.name
-    PFSMonitor(h).handleEvent(PFSMonitor(h), newEv)
+    FSMonitor(h).handleEvent(FSMonitor(h), newEv)
 
-proc toDelegate(m: PFSMonitor): PDelegate =
+proc toDelegate(m: FSMonitor): Delegate =
   result = newDelegate()
   result.deleVal = m
   result.fd = (type(result.fd))(m.fd)
@@ -191,20 +191,20 @@ proc toDelegate(m: PFSMonitor): PDelegate =
   result.handleRead = FSMonitorRead
   result.open = true
 
-proc register*(d: PDispatcher, monitor: PFSMonitor,
-               handleEvent: proc (m: PFSMonitor, ev: TMonitorEvent) {.closure.}) =
+proc register*(d: Dispatcher, monitor: FSMonitor,
+               handleEvent: proc (m: FSMonitor, ev: MonitorEvent) {.closure.}) =
   ## Registers ``monitor`` with dispatcher ``d``.
   monitor.handleEvent = handleEvent
   var deleg = toDelegate(monitor)
   d.register(deleg)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   proc main =
     var disp = newDispatcher()
     var monitor = newMonitor()
     echo monitor.add("/home/dom/inotifytests/")
     disp.register(monitor,
-      proc (m: PFSMonitor, ev: TMonitorEvent) =
+      proc (m: FSMonitor, ev: MonitorEvent) =
         echo("Got event: ", ev.kind)
         if ev.kind == MonitorMoved:
           echo("From ", ev.oldPath, " to ", ev.newPath)
diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim
index 975eae7e2..b46f8343c 100644
--- a/lib/pure/ftpclient.nim
+++ b/lib/pure/ftpclient.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Dominik Picheta
+#        (c) Copyright 2015 Dominik Picheta
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
@@ -15,8 +15,8 @@ from rawsockets import nil
 from asyncdispatch import PFuture
 
 ## This module **partially** implements an FTP client as specified
-## by `RFC 959 <http://tools.ietf.org/html/rfc959>`_. 
-## 
+## by `RFC 959 <http://tools.ietf.org/html/rfc959>`_.
+##
 ## This module provides both a synchronous and asynchronous implementation.
 ## The asynchronous implementation requires you to use the ``asyncFTPClient``
 ## function. You are then required to register the ``AsyncFTPClient`` with a
@@ -27,7 +27,7 @@ from asyncdispatch import PFuture
 ## file transfers, calls to functions which use the command socket will block.
 ##
 ## Here is some example usage of this module:
-## 
+##
 ## .. code-block:: Nim
 ##    var ftp = ftpClient("example.org", user = "user", pass = "pass")
 ##    ftp.connect()
@@ -51,7 +51,7 @@ type
       port*: rawsockets.Port
     else:
       port*: Port
-    
+
     jobInProgress*: bool
     job*: FTPJob[SockType]
 
@@ -91,7 +91,7 @@ type
     of EvLines:
       lines*: string ## Lines that have been transferred.
     of EvRetr, EvStore: ## Retr/Store operation finished.
-      nil 
+      nil
     of EvTransferProgress:
       bytesTotal*: BiggestInt     ## Bytes total.
       bytesFinished*: BiggestInt  ## Bytes transferred.
@@ -107,7 +107,7 @@ type
   EInvalidReply: ReplyError, EFTP: FTPError
 ].}
 
-proc ftpClient*(address: string, port = TPort(21),
+proc ftpClient*(address: string, port = Port(21),
                 user, pass = ""): FtpClient =
   ## Create a ``FtpClient`` object.
   new(result)
@@ -120,10 +120,10 @@ proc ftpClient*(address: string, port = TPort(21),
   result.csock = socket()
   if result.csock == invalidSocket: raiseOSError(osLastError())
 
-template blockingOperation(sock: TSocket, body: stmt) {.immediate.} =
+template blockingOperation(sock: Socket, body: stmt) {.immediate.} =
   body
 
-template blockingOperation(sock: asyncio.PAsyncSocket, body: stmt) {.immediate.} =
+template blockingOperation(sock: asyncio.AsyncSocket, body: stmt) {.immediate.} =
   sock.setBlocking(true)
   body
   sock.setBlocking(false)
@@ -145,14 +145,14 @@ proc send*[T](ftp: FtpBase[T], m: string): TaintedString =
 
 proc assertReply(received: TaintedString, expected: string) =
   if not received.string.startsWith(expected):
-    raise newException(EInvalidReply,
+    raise newException(ReplyError,
                        "Expected reply '$1' got: $2" % [
                        expected, received.string])
 
 proc assertReply(received: TaintedString, expected: varargs[string]) =
   for i in items(expected):
     if received.string.startsWith(i): return
-  raise newException(EInvalidReply,
+  raise newException(ReplyError,
                      "Expected reply '$1' got: $2" %
                      [expected.join("' or '"), received.string])
 
@@ -161,7 +161,7 @@ proc createJob[T](ftp: FtpBase[T],
                           nimcall,gcsafe.},
                cmd: FTPJobType) =
   if ftp.jobInProgress:
-    raise newException(EFTP, "Unable to do two jobs at once.")
+    raise newException(FTPError, "Unable to do two jobs at once.")
   ftp.jobInProgress = true
   new(ftp.job)
   ftp.job.prc = prc
@@ -182,11 +182,11 @@ proc deleteJob[T](ftp: FtpBase[T]) =
     ftp.job.file.close()
   ftp.dsock.close()
 
-proc handleTask(s: PAsyncSocket, ftp: PAsyncFTPClient) =
+proc handleTask(s: AsyncSocket, ftp: AsyncFTPClient) =
   if ftp.jobInProgress:
     if ftp.job.typ in {JRetr, JStore}:
       if epochTime() - ftp.job.lastProgressReport >= 1.0:
-        var r: TFTPEvent
+        var r: FTPEvent
         ftp.job.lastProgressReport = epochTime()
         r.typ = EvTransferProgress
         r.bytesTotal = ftp.job.total
@@ -195,57 +195,57 @@ proc handleTask(s: PAsyncSocket, ftp: PAsyncFTPClient) =
         r.filename = ftp.job.filename
         r.currentJob = ftp.job.typ
         ftp.job.oneSecond = 0
-        ftp.handleEvent(PAsyncFTPClient(ftp), r)
+        ftp.handleEvent(ftp, r)
 
-proc handleWrite(s: PAsyncSocket, ftp: PAsyncFTPClient) =
+proc handleWrite(s: AsyncSocket, ftp: AsyncFTPClient) =
   if ftp.jobInProgress:
     if ftp.job.typ == JStore:
       assert (not ftp.job.prc(ftp, true))
 
-proc handleConnect(s: PAsyncSocket, ftp: PAsyncFTPClient) =
+proc handleConnect(s: AsyncSocket, ftp: AsyncFTPClient) =
   ftp.dsockConnected = true
   assert(ftp.jobInProgress)
   if ftp.job.typ == JStore:
-    s.setHandleWrite(proc (s: PAsyncSocket) = handleWrite(s, ftp))
+    s.setHandleWrite(proc (s: AsyncSocket) = handleWrite(s, ftp))
   else:
     s.delHandleWrite()
 
-proc handleRead(s: PAsyncSocket, ftp: PAsyncFTPClient) =
+proc handleRead(s: AsyncSocket, ftp: AsyncFTPClient) =
   assert ftp.jobInProgress
   assert ftp.job.typ != JStore
-  # This can never return true, because it shouldn't check for code 
+  # This can never return true, because it shouldn't check for code
   # 226 from csock.
   assert(not ftp.job.prc(ftp, true))
 
 proc pasv[T](ftp: FtpBase[T]) =
   ## Negotiate a data connection.
-  when T is TSocket:
+  when T is Socket:
     ftp.dsock = socket()
     if ftp.dsock == invalidSocket: raiseOSError(osLastError())
-  elif T is PAsyncSocket:
+  elif T is AsyncSocket:
     ftp.dsock = asyncSocket()
     ftp.dsock.handleRead =
-      proc (s: PAsyncSocket) =
+      proc (s: AsyncSocket) =
         handleRead(s, ftp)
     ftp.dsock.handleConnect =
-      proc (s: PAsyncSocket) =
+      proc (s: AsyncSocket) =
         handleConnect(s, ftp)
     ftp.dsock.handleTask =
-      proc (s: PAsyncSocket) =
+      proc (s: AsyncSocket) =
         handleTask(s, ftp)
     ftp.disp.register(ftp.dsock)
   else:
     {.fatal: "Incorrect socket instantiation".}
-  
+
   var pasvMsg = ftp.send("PASV").string.strip.TaintedString
   assertReply(pasvMsg, "227")
   var betweenParens = captureBetween(pasvMsg.string, '(', ')')
   var nums = betweenParens.split(',')
-  var ip = nums[0.. -3]
-  var port = nums[-2.. -1]
+  var ip = nums[0.. ^3]
+  var port = nums[^2.. ^1]
   var properPort = port[0].parseInt()*256+port[1].parseInt()
-  ftp.dsock.connect(ip.join("."), TPort(properPort.toU16))
-  when T is PAsyncSocket:
+  ftp.dsock.connect(ip.join("."), Port(properPort.toU16))
+  when T is AsyncSocket:
     ftp.dsockConnected = false
   else:
     ftp.dsockConnected = true
@@ -255,10 +255,10 @@ proc normalizePathSep(path: string): string =
 
 proc connect*[T](ftp: FtpBase[T]) =
   ## Connect to the FTP server specified by ``ftp``.
-  when T is PAsyncSocket:
+  when T is AsyncSocket:
     blockingOperation(ftp.csock):
       ftp.csock.connect(ftp.address, ftp.port)
-  elif T is TSocket:
+  elif T is Socket:
     ftp.csock.connect(ftp.address, ftp.port)
   else:
     {.fatal: "Incorrect socket instantiation".}
@@ -292,13 +292,13 @@ proc getLines[T](ftp: FtpBase[T], async: bool = false): bool =
   ## It doesn't if `async` is true, because it doesn't check for 226 then.
   if ftp.dsockConnected:
     var r = TaintedString""
-    when T is PAsyncSocket:
+    when T is AsyncSocket:
       if ftp.asyncDSock.readLine(r):
         if r.string == "":
           ftp.dsockConnected = false
         else:
           ftp.job.lines.add(r.string & "\n")
-    elif T is TSocket:
+    elif T is Socket:
       assert(not async)
       ftp.dsock.readLine(r)
       if r.string == "":
@@ -307,9 +307,9 @@ proc getLines[T](ftp: FtpBase[T], async: bool = false): bool =
         ftp.job.lines.add(r.string & "\n")
     else:
       {.fatal: "Incorrect socket instantiation".}
-  
+
   if not async:
-    var readSocks: seq[TSocket] = @[ftp.csock]
+    var readSocks: seq[Socket] = @[ftp.csock]
     # This is only needed here. Asyncio gets this socket...
     blockingOperation(ftp.csock):
       if readSocks.select(1) != 0 and ftp.csock in readSocks:
@@ -372,7 +372,7 @@ proc createDir*[T](ftp: FtpBase[T], dir: string, recursive: bool = false) =
     assertReply reply, "257"
 
 proc chmod*[T](ftp: FtpBase[T], path: string,
-            permissions: set[TFilePermission]) =
+            permissions: set[FilePermission]) =
   ## Changes permission of ``path`` to ``permissions``.
   var userOctal = 0
   var groupOctal = 0
@@ -396,7 +396,7 @@ proc chmod*[T](ftp: FtpBase[T], path: string,
 proc list*[T](ftp: FtpBase[T], dir: string = "", async = false): string =
   ## Lists all files in ``dir``. If ``dir`` is ``""``, uses the current
   ## working directory. If ``async`` is true, this function will return
-  ## immediately and it will be your job to call asyncio's 
+  ## immediately and it will be your job to call asyncio's
   ## ``poll`` to progress this operation.
   ftp.createJob(getLines[T], JRetrText)
   ftp.pasv()
@@ -417,7 +417,7 @@ proc retrText*[T](ftp: FtpBase[T], file: string, async = false): string =
   ftp.createJob(getLines[T], JRetrText)
   ftp.pasv()
   assertReply ftp.send("RETR " & file.normalizePathSep), ["125", "150"]
-  
+
   if not async:
     while not ftp.job.prc(ftp, false): discard
     result = ftp.job.lines
@@ -431,12 +431,12 @@ proc getFile[T](ftp: FtpBase[T], async = false): bool =
     var bytesRead = 0
     var returned = false
     if async:
-      when T is TSocket:
-        raise newException(EFTP, "FTPClient must be async.")
+      when T is Socket:
+        raise newException(FTPError, "FTPClient must be async.")
       else:
         bytesRead = ftp.dsock.recvAsync(r, BufferSize)
         returned = bytesRead != -1
-    else: 
+    else:
       bytesRead = ftp.dsock.recv(r, BufferSize)
       returned = true
     let r2 = r.string
@@ -447,9 +447,9 @@ proc getFile[T](ftp: FtpBase[T], async = false): bool =
     elif returned and r2 == "":
       ftp.dsockConnected = false
 
-  when T is TSocket:
+  when T is Socket:
     if not async:
-      var readSocks: seq[TSocket] = @[ftp.csock]
+      var readSocks: seq[Socket] = @[ftp.csock]
       blockingOperation(ftp.csock):
         if readSocks.select(1) != 0 and ftp.csock in readSocks:
           assertReply ftp.expectReply(), "226"
@@ -458,7 +458,7 @@ proc getFile[T](ftp: FtpBase[T], async = false): bool =
 proc retrFile*[T](ftp: FtpBase[T], file, dest: string, async = false) =
   ## Downloads ``file`` and saves it to ``dest``. Usage of this function
   ## asynchronously is recommended to view the progress of the download.
-  ## The ``EvRetr`` event is passed to the specified ``handleEvent`` function 
+  ## The ``EvRetr`` event is passed to the specified ``handleEvent`` function
   ## when the download is finished, and the ``filename`` field will be equal
   ## to ``file``.
   ftp.createJob(getFile[T], JRetr)
@@ -467,11 +467,11 @@ proc retrFile*[T](ftp: FtpBase[T], file, dest: string, async = false) =
   var reply = ftp.send("RETR " & file.normalizePathSep)
   assertReply reply, ["125", "150"]
   if {'(', ')'} notin reply.string:
-    raise newException(EInvalidReply, "Reply has no file size.")
+    raise newException(ReplyError, "Reply has no file size.")
   var fileSize: BiggestInt
   if reply.string.captureBetween('(', ')').parseBiggestInt(fileSize) == 0:
-    raise newException(EInvalidReply, "Reply has no file size.")
-    
+    raise newException(ReplyError, "Reply has no file size.")
+
   ftp.job.total = fileSize
   ftp.job.lastProgressReport = epochTime()
   ftp.job.filename = file.normalizePathSep
@@ -488,7 +488,7 @@ proc doUpload[T](ftp: FtpBase[T], async = false): bool =
       if bytesSent == ftp.job.toStore.len:
         ftp.job.toStore = ""
       elif bytesSent != ftp.job.toStore.len and bytesSent != 0:
-        ftp.job.toStore = ftp.job.toStore[bytesSent .. -1]
+        ftp.job.toStore = ftp.job.toStore[bytesSent .. ^1]
       ftp.job.progress.inc(bytesSent)
       ftp.job.oneSecond.inc(bytesSent)
     else:
@@ -499,12 +499,12 @@ proc doUpload[T](ftp: FtpBase[T], async = false): bool =
         # File finished uploading.
         ftp.dsock.close()
         ftp.dsockConnected = false
-  
+
         if not async:
           assertReply ftp.expectReply(), "226"
           return true
         return false
-    
+
       if not async:
         ftp.dsock.send(s)
       else:
@@ -512,9 +512,9 @@ proc doUpload[T](ftp: FtpBase[T], async = false): bool =
         if bytesSent == 0:
           ftp.job.toStore.add(s)
         elif bytesSent != s.len:
-          ftp.job.toStore.add(s[bytesSent .. -1])
+          ftp.job.toStore.add(s[bytesSent .. ^1])
         len = bytesSent
-      
+
       ftp.job.progress.inc(len)
       ftp.job.oneSecond.inc(len)
 
@@ -522,8 +522,8 @@ proc store*[T](ftp: FtpBase[T], file, dest: string, async = false) =
   ## Uploads ``file`` to ``dest`` on the remote FTP server. Usage of this
   ## function asynchronously is recommended to view the progress of
   ## the download.
-  ## The ``EvStore`` event is passed to the specified ``handleEvent`` function 
-  ## when the upload is finished, and the ``filename`` field will be 
+  ## The ``EvStore`` event is passed to the specified ``handleEvent`` function
+  ## when the upload is finished, and the ``filename`` field will be
   ## equal to ``file``.
   ftp.createJob(doUpload[T], JStore)
   ftp.job.file = open(file)
@@ -531,7 +531,7 @@ proc store*[T](ftp: FtpBase[T], file, dest: string, async = false) =
   ftp.job.lastProgressReport = epochTime()
   ftp.job.filename = file
   ftp.pasv()
-  
+
   assertReply ftp.send("STOR " & dest.normalizePathSep), ["125", "150"]
 
   if not async:
@@ -545,10 +545,10 @@ proc close*[T](ftp: FtpBase[T]) =
   ftp.csock.close()
   ftp.dsock.close()
 
-proc csockHandleRead(s: PAsyncSocket, ftp: PAsyncFTPClient) =
+proc csockHandleRead(s: AsyncSocket, ftp: AsyncFTPClient) =
   if ftp.jobInProgress:
     assertReply ftp.expectReply(), "226" # Make sure the transfer completed.
-    var r: TFTPEvent
+    var r: FTPEvent
     case ftp.job.typ
     of JRetrText:
       r.typ = EvLines
@@ -557,21 +557,21 @@ proc csockHandleRead(s: PAsyncSocket, ftp: PAsyncFTPClient) =
       r.typ = EvRetr
       r.filename = ftp.job.filename
       if ftp.job.progress != ftp.job.total:
-        raise newException(EFTP, "Didn't download full file.")
+        raise newException(FTPError, "Didn't download full file.")
     of JStore:
       r.typ = EvStore
       r.filename = ftp.job.filename
       if ftp.job.progress != ftp.job.total:
-        raise newException(EFTP, "Didn't upload full file.")
+        raise newException(FTPError, "Didn't upload full file.")
     ftp.deleteJob()
-    
+
     ftp.handleEvent(ftp, r)
 
-proc asyncFTPClient*(address: string, port = TPort(21),
+proc asyncFTPClient*(address: string, port = Port(21),
                      user, pass = "",
-    handleEvent: proc (ftp: PAsyncFTPClient, ev: TFTPEvent) {.closure,gcsafe.} = 
-      (proc (ftp: PAsyncFTPClient, ev: TFTPEvent) = discard)): PAsyncFTPClient =
-  ## Create a ``PAsyncFTPClient`` object.
+    handleEvent: proc (ftp: AsyncFTPClient, ev: FTPEvent) {.closure,gcsafe.} =
+      (proc (ftp: AsyncFTPClient, ev: FTPEvent) = discard)): AsyncFTPClient =
+  ## Create a ``AsyncFTPClient`` object.
   ##
   ## Use this if you want to use asyncio's dispatcher.
   var dres: AsyncFtpClient
@@ -588,7 +588,7 @@ proc asyncFTPClient*(address: string, port = TPort(21),
       csockHandleRead(s, dres)
   result = dres
 
-proc register*(d: PDispatcher, ftp: PAsyncFTPClient): PDelegate {.discardable.} =
+proc register*(d: Dispatcher, ftp: AsyncFTPClient): Delegate {.discardable.} =
   ## Registers ``ftp`` with dispatcher ``d``.
   ftp.disp = d
   return ftp.disp.register(ftp.csock)
@@ -617,7 +617,7 @@ when isMainModule:
           echo d.len
         else: assert(false)
     var ftp = asyncFTPClient("example.com", user = "foo", pass = "bar", handleEvent = hev)
-    
+
     d.register(ftp)
     d.len.echo()
     ftp.connect()
@@ -629,7 +629,7 @@ when isMainModule:
       if not d.poll(): break
   main()
 
-when isMainModule and false:
+when not defined(testing) and isMainModule:
   var ftp = ftpClient("example.com", user = "foo", pass = "bar")
   ftp.connect()
   echo ftp.pwd()
diff --git a/lib/pure/future.nim b/lib/pure/future.nim
index 34b76e41d..661afd7b3 100644
--- a/lib/pure/future.nim
+++ b/lib/pure/future.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Dominik Picheta
+#        (c) Copyright 2015 Dominik Picheta
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -12,7 +12,7 @@
 
 import macros
 
-proc createProcType(p, b: PNimrodNode): PNimrodNode {.compileTime.} =
+proc createProcType(p, b: NimNode): NimNode {.compileTime.} =
   #echo treeRepr(p)
   #echo treeRepr(b)
   result = newNimNode(nnkProcTy)
@@ -44,7 +44,7 @@ proc createProcType(p, b: PNimrodNode): PNimrodNode {.compileTime.} =
     formalParams.add identDefs
   else:
     error("Incorrect type list in proc type declaration.")
-  
+
   result.add formalParams
   result.add newEmptyNode()
   #echo(treeRepr(result))
@@ -59,10 +59,10 @@ macro `=>`*(p, b: expr): expr {.immediate.} =
   ##     f(2, 2)
   ##
   ##   passTwoAndTwo((x, y) => x + y) # 4
-  
+
   #echo treeRepr(p)
   #echo(treeRepr(b))
-  var params: seq[PNimrodNode] = @[newIdentNode("auto")]
+  var params: seq[NimNode] = @[newIdentNode("auto")]
 
   case p.kind
   of nnkPar:
@@ -77,7 +77,17 @@ macro `=>`*(p, b: expr): expr {.immediate.} =
         identDefs.add(c)
         identDefs.add(newEmptyNode())
         identDefs.add(newEmptyNode())
+      of nnkInfix:
+        if c[0].kind == nnkIdent and c[0].ident == !"->":
+          var procTy = createProcType(c[1], c[2])
+          params[0] = procTy[0][0]
+          for i in 1 .. <procTy[0].len:
+            params.add(procTy[0][i])
+        else:
+          error("Expected proc type (->) got (" & $c[0].ident & ").")
+        break
       else:
+        echo treeRepr c
         error("Incorrect procedure parameter list.")
       params.add(identDefs)
   of nnkIdent:
@@ -108,7 +118,7 @@ macro `->`*(p, b: expr): expr {.immediate.} =
   ##
   ##   proc pass2(f: (float, float) -> float): float =
   ##     f(2, 2)
-  ##   
+  ##
   ##   # is the same as:
   ##
   ##   proc pass2(f: proc (x, y: float): float): float =
@@ -145,7 +155,6 @@ macro `[]`*(lc: ListComprehension, comp, typ: expr): expr =
 
   for i in countdown(comp[2].len-1, 0):
     let x = comp[2][i]
-    expectKind(x, nnkInfix)
     expectMinLen(x, 1)
     if x[0].kind == nnkIdent and $x[0].ident == "<-":
       expectLen(x, 3)
diff --git a/lib/pure/gentabs.nim b/lib/pure/gentabs.nim
index a6128efc9..8c89a0ac3 100644
--- a/lib/pure/gentabs.nim
+++ b/lib/pure/gentabs.nim
@@ -186,8 +186,19 @@ when isMainModule:
   assert( z["first"]["one"] == 1)   # retrieve from first inner table
   assert( z["second"]["red"] == 10) # retrieve from second inner table
   
-  for k,v in pairs(z):
-    echo( "$# ($#) ->" % [k,$len(v)] )
-    #for k2,v2 in pairs(v):
-    #  echo( "   $# <-> $#" % [k2,$v2] )
-  echo()
+  var output = ""
+  for k, v in pairs(z):
+    output.add( "$# ($#) ->\n" % [k,$len(v)] )
+    for k2,v2 in pairs(v):
+      output.add( "  $# <-> $#\n" % [k2,$v2] )
+
+  let expected = unindent """
+    first (3) ->
+      two <-> 2
+      three <-> 3
+      one <-> 1
+    second (2) ->
+      red <-> 10
+      blue <-> 20
+  """
+  assert output == expected
diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim
index 30daaf2dc..a16342d44 100644
--- a/lib/pure/hashes.nim
+++ b/lib/pure/hashes.nim
@@ -33,8 +33,8 @@
 ##  proc hash(x: Something): THash =
 ##    ## Computes a THash from `x`.
 ##    var h: THash = 0
-##    h = h &! hash(x.foo)
-##    h = h &! hash(x.bar)
+##    h = h !& hash(x.foo)
+##    h = h !& hash(x.bar)
 ##    result = !$h
 
 import 
diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim
index a1440b6f4..e6c15371e 100644
--- a/lib/pure/htmlgen.nim
+++ b/lib/pure/htmlgen.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -12,7 +12,7 @@
 ## as ``from htmlgen import nil`` and then fully qualify the macros.
 ##
 ##
-## This module implements a simple `XML`:idx: and `HTML`:idx: code 
+## This module implements a simple `XML`:idx: and `HTML`:idx: code
 ## generator. Each commonly used HTML tag has a corresponding macro
 ## that generates a string with its HTML representation.
 ##
@@ -21,9 +21,9 @@
 ## .. code-block:: Nim
 ##   var nim = "Nim"
 ##   echo h1(a(href="http://nim-lang.org", nim))
-##  
+##
 ## Writes the string::
-##   
+##
 ##   <h1><a href="http://nim-lang.org">Nim</a></h1>
 ##
 
@@ -36,16 +36,16 @@ const
     "onmouseover onmousemove onmouseout onkeypress onkeydown onkeyup "
   commonAttr* = coreAttr & eventAttr
 
-proc getIdent(e: PNimrodNode): string {.compileTime.} = 
+proc getIdent(e: NimNode): string {.compileTime.} =
   case e.kind
   of nnkIdent: result = normalize($e.ident)
-  of nnkAccQuoted: 
+  of nnkAccQuoted:
     result = getIdent(e[0])
     for i in 1 .. e.len-1:
       result.add getIdent(e[i])
   else: error("cannot extract identifier from node: " & toStrLit(e).strVal)
 
-proc delete[T](s: var seq[T], attr: T): bool = 
+proc delete[T](s: var seq[T], attr: T): bool =
   var idx = find(s, attr)
   if idx >= 0:
     var L = s.len
@@ -53,10 +53,10 @@ proc delete[T](s: var seq[T], attr: T): bool =
     setLen(s, L-1)
     result = true
 
-proc xmlCheckedTag*(e: PNimrodNode, tag: string, optAttr = "", reqAttr = "",
-    isLeaf = false): PNimrodNode {.compileTime.} =
+proc xmlCheckedTag*(e: NimNode, tag: string, optAttr = "", reqAttr = "",
+    isLeaf = false): NimNode {.compileTime.} =
   ## use this procedure to define a new XML tag
-  
+
   # copy the attributes; when iterating over them these lists
   # will be modified, so that each attribute is only given one value
   var req = split(reqAttr)
@@ -66,7 +66,7 @@ proc xmlCheckedTag*(e: PNimrodNode, tag: string, optAttr = "", reqAttr = "",
   result.add(newStrLitNode(tag))
   # first pass over attributes:
   for i in 1..e.len-1:
-    if e[i].kind == nnkExprEqExpr: 
+    if e[i].kind == nnkExprEqExpr:
       var name = getIdent(e[i][0])
       if delete(req, name) or delete(opt, name):
         result.add(newStrLitNode(" "))
@@ -81,7 +81,7 @@ proc xmlCheckedTag*(e: PNimrodNode, tag: string, optAttr = "", reqAttr = "",
     error(req[0] & " attribute for '" & tag & "' element expected")
   if isLeaf:
     for i in 1..e.len-1:
-      if e[i].kind != nnkExprEqExpr: 
+      if e[i].kind != nnkExprEqExpr:
         error("element " & tag & " cannot be nested")
     result.add(newStrLitNode(" />"))
   else:
@@ -95,395 +95,396 @@ proc xmlCheckedTag*(e: PNimrodNode, tag: string, optAttr = "", reqAttr = "",
   result = nestList(!"&", result)
 
 
-macro a*(e: expr): expr {.immediate.} = 
+macro a*(e: expr): expr {.immediate.} =
   ## generates the HTML ``a`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "a", "href charset type hreflang rel rev " &
     "accesskey tabindex" & commonAttr)
 
-macro acronym*(e: expr): expr {.immediate.} = 
+macro acronym*(e: expr): expr {.immediate.} =
   ## generates the HTML ``acronym`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "acronym", commonAttr)
 
-macro address*(e: expr): expr {.immediate.} = 
+macro address*(e: expr): expr {.immediate.} =
   ## generates the HTML ``address`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "address", commonAttr)
 
-macro area*(e: expr): expr {.immediate.} = 
+macro area*(e: expr): expr {.immediate.} =
   ## generates the HTML ``area`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "area", "shape coords href nohref" &
     " accesskey tabindex" & commonAttr, "alt", true)
 
-macro b*(e: expr): expr {.immediate.} = 
+macro b*(e: expr): expr {.immediate.} =
   ## generates the HTML ``b`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "b", commonAttr)
 
-macro base*(e: expr): expr {.immediate.} = 
+macro base*(e: expr): expr {.immediate.} =
   ## generates the HTML ``base`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "base", "", "href", true)
 
-macro big*(e: expr): expr {.immediate.} = 
+macro big*(e: expr): expr {.immediate.} =
   ## generates the HTML ``big`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "big", commonAttr)
 
-macro blockquote*(e: expr): expr {.immediate.} = 
+macro blockquote*(e: expr): expr {.immediate.} =
   ## generates the HTML ``blockquote`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "blockquote", " cite" & commonAttr)
 
-macro body*(e: expr): expr {.immediate.} = 
+macro body*(e: expr): expr {.immediate.} =
   ## generates the HTML ``body`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "body", commonAttr)
 
-macro br*(e: expr): expr {.immediate.} = 
+macro br*(e: expr): expr {.immediate.} =
   ## generates the HTML ``br`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "br", "", "", true)
 
-macro button*(e: expr): expr {.immediate.} = 
+macro button*(e: expr): expr {.immediate.} =
   ## generates the HTML ``button`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "button", "accesskey tabindex " &
     "disabled name type value" & commonAttr)
 
-macro caption*(e: expr): expr {.immediate.} = 
+macro caption*(e: expr): expr {.immediate.} =
   ## generates the HTML ``caption`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "caption", commonAttr)
 
-macro cite*(e: expr): expr {.immediate.} = 
+macro cite*(e: expr): expr {.immediate.} =
   ## generates the HTML ``cite`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "cite", commonAttr)
 
-macro code*(e: expr): expr {.immediate.} = 
+macro code*(e: expr): expr {.immediate.} =
   ## generates the HTML ``code`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "code", commonAttr)
 
-macro col*(e: expr): expr {.immediate.} = 
+macro col*(e: expr): expr {.immediate.} =
   ## generates the HTML ``col`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "col", "span align valign" & commonAttr, "", true)
 
-macro colgroup*(e: expr): expr {.immediate.} = 
+macro colgroup*(e: expr): expr {.immediate.} =
   ## generates the HTML ``colgroup`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "colgroup", "span align valign" & commonAttr)
 
-macro dd*(e: expr): expr {.immediate.} = 
+macro dd*(e: expr): expr {.immediate.} =
   ## generates the HTML ``dd`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "dd", commonAttr)
 
-macro del*(e: expr): expr {.immediate.} = 
+macro del*(e: expr): expr {.immediate.} =
   ## generates the HTML ``del`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "del", "cite datetime" & commonAttr)
 
-macro dfn*(e: expr): expr {.immediate.} = 
+macro dfn*(e: expr): expr {.immediate.} =
   ## generates the HTML ``dfn`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "dfn", commonAttr)
 
-macro `div`*(e: expr): expr {.immediate.} = 
+macro `div`*(e: expr): expr {.immediate.} =
   ## generates the HTML ``div`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "div", commonAttr)
 
-macro dl*(e: expr): expr {.immediate.} = 
+macro dl*(e: expr): expr {.immediate.} =
   ## generates the HTML ``dl`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "dl", commonAttr)
 
-macro dt*(e: expr): expr {.immediate.} = 
+macro dt*(e: expr): expr {.immediate.} =
   ## generates the HTML ``dt`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "dt", commonAttr)
 
-macro em*(e: expr): expr {.immediate.} = 
+macro em*(e: expr): expr {.immediate.} =
   ## generates the HTML ``em`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "em", commonAttr)
 
-macro fieldset*(e: expr): expr {.immediate.} = 
+macro fieldset*(e: expr): expr {.immediate.} =
   ## generates the HTML ``fieldset`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "fieldset", commonAttr)
 
-macro form*(e: expr): expr {.immediate.} = 
+macro form*(e: expr): expr {.immediate.} =
   ## generates the HTML ``form`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "form", "method encype accept accept-charset" & 
+  result = xmlCheckedTag(e, "form", "method encype accept accept-charset" &
     commonAttr, "action")
 
-macro h1*(e: expr): expr {.immediate.} = 
+macro h1*(e: expr): expr {.immediate.} =
   ## generates the HTML ``h1`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "h1", commonAttr)
 
-macro h2*(e: expr): expr {.immediate.} = 
+macro h2*(e: expr): expr {.immediate.} =
   ## generates the HTML ``h2`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "h2", commonAttr)
 
-macro h3*(e: expr): expr {.immediate.} = 
+macro h3*(e: expr): expr {.immediate.} =
   ## generates the HTML ``h3`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "h3", commonAttr)
 
-macro h4*(e: expr): expr {.immediate.} = 
+macro h4*(e: expr): expr {.immediate.} =
   ## generates the HTML ``h4`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "h4", commonAttr)
 
-macro h5*(e: expr): expr {.immediate.} = 
+macro h5*(e: expr): expr {.immediate.} =
   ## generates the HTML ``h5`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "h5", commonAttr)
 
-macro h6*(e: expr): expr {.immediate.} = 
+macro h6*(e: expr): expr {.immediate.} =
   ## generates the HTML ``h6`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "h6", commonAttr)
 
-macro head*(e: expr): expr {.immediate.} = 
+macro head*(e: expr): expr {.immediate.} =
   ## generates the HTML ``head`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "head", "profile")
 
-macro html*(e: expr): expr {.immediate.} = 
+macro html*(e: expr): expr {.immediate.} =
   ## generates the HTML ``html`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "html", "xmlns", "")
 
-macro hr*(e: expr): expr {.immediate.} = 
+macro hr*(): expr {.immediate.} =
   ## generates the HTML ``hr`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "hr", commonAttr, "", true)
 
-macro i*(e: expr): expr {.immediate.} = 
+macro i*(e: expr): expr {.immediate.} =
   ## generates the HTML ``i`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "i", commonAttr)
 
-macro img*(e: expr): expr {.immediate.} = 
+macro img*(e: expr): expr {.immediate.} =
   ## generates the HTML ``img`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "img", "longdesc height width", "src alt", true)
 
-macro input*(e: expr): expr {.immediate.} = 
+macro input*(e: expr): expr {.immediate.} =
   ## generates the HTML ``input`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "input", "name type value checked maxlength src" &
     " alt accept disabled readonly accesskey tabindex" & commonAttr, "", true)
 
-macro ins*(e: expr): expr {.immediate.} = 
+macro ins*(e: expr): expr {.immediate.} =
   ## generates the HTML ``ins`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "ins", "cite datetime" & commonAttr)
 
-macro kbd*(e: expr): expr {.immediate.} = 
+macro kbd*(e: expr): expr {.immediate.} =
   ## generates the HTML ``kbd`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "kbd", commonAttr)
 
-macro label*(e: expr): expr {.immediate.} = 
+macro label*(e: expr): expr {.immediate.} =
   ## generates the HTML ``label`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "label", "for accesskey" & commonAttr)
 
-macro legend*(e: expr): expr {.immediate.} = 
+macro legend*(e: expr): expr {.immediate.} =
   ## generates the HTML ``legend`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "legend", "accesskey" & commonAttr)
 
-macro li*(e: expr): expr {.immediate.} = 
+macro li*(e: expr): expr {.immediate.} =
   ## generates the HTML ``li`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "li", commonAttr)
 
-macro link*(e: expr): expr {.immediate.} = 
+macro link*(e: expr): expr {.immediate.} =
   ## generates the HTML ``link`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "link", "href charset hreflang type rel rev media" & 
+  result = xmlCheckedTag(e, "link", "href charset hreflang type rel rev media" &
     commonAttr, "", true)
 
-macro map*(e: expr): expr {.immediate.} = 
+macro map*(e: expr): expr {.immediate.} =
   ## generates the HTML ``map`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "map", "class title" & eventAttr, "id", false)
 
-macro meta*(e: expr): expr {.immediate.} = 
+macro meta*(e: expr): expr {.immediate.} =
   ## generates the HTML ``meta`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "meta", "name http-equiv scheme", "content", true)
 
-macro noscript*(e: expr): expr {.immediate.} = 
+macro noscript*(e: expr): expr {.immediate.} =
   ## generates the HTML ``noscript`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "noscript", commonAttr)
 
-macro `object`*(e: expr): expr {.immediate.} = 
+macro `object`*(e: expr): expr {.immediate.} =
   ## generates the HTML ``object`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "object", "classid data codebase declare type " &
     "codetype archive standby width height name tabindex" & commonAttr)
 
-macro ol*(e: expr): expr {.immediate.} = 
+macro ol*(e: expr): expr {.immediate.} =
   ## generates the HTML ``ol`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "ol", commonAttr)
 
-macro optgroup*(e: expr): expr {.immediate.} = 
+macro optgroup*(e: expr): expr {.immediate.} =
   ## generates the HTML ``optgroup`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "optgroup", "disabled" & commonAttr, "label", false)
 
-macro option*(e: expr): expr {.immediate.} = 
+macro option*(e: expr): expr {.immediate.} =
   ## generates the HTML ``option`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "option", "selected value" & commonAttr)
 
-macro p*(e: expr): expr {.immediate.} = 
+macro p*(e: expr): expr {.immediate.} =
   ## generates the HTML ``p`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "p", commonAttr)
 
-macro param*(e: expr): expr {.immediate.} = 
+macro param*(e: expr): expr {.immediate.} =
   ## generates the HTML ``param`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "param", "value id type valuetype", "name", true)
 
-macro pre*(e: expr): expr {.immediate.} = 
+macro pre*(e: expr): expr {.immediate.} =
   ## generates the HTML ``pre`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "pre", commonAttr)
 
-macro q*(e: expr): expr {.immediate.} = 
+macro q*(e: expr): expr {.immediate.} =
   ## generates the HTML ``q`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "q", "cite" & commonAttr)
 
-macro samp*(e: expr): expr {.immediate.} = 
+macro samp*(e: expr): expr {.immediate.} =
   ## generates the HTML ``samp`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "samp", commonAttr)
 
-macro script*(e: expr): expr {.immediate.} = 
+macro script*(e: expr): expr {.immediate.} =
   ## generates the HTML ``script`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "script", "src charset defer", "type", false)
 
-macro select*(e: expr): expr {.immediate.} = 
+macro select*(e: expr): expr {.immediate.} =
   ## generates the HTML ``select`` element.
   let e = callsite()
-  result = xmlCheckedTag(e, "select", "name size multiple disabled tabindex" & 
+  result = xmlCheckedTag(e, "select", "name size multiple disabled tabindex" &
     commonAttr)
 
-macro small*(e: expr): expr {.immediate.} = 
+macro small*(e: expr): expr {.immediate.} =
   ## generates the HTML ``small`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "small", commonAttr)
 
-macro span*(e: expr): expr {.immediate.} = 
+macro span*(e: expr): expr {.immediate.} =
   ## generates the HTML ``span`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "span", commonAttr)
 
-macro strong*(e: expr): expr {.immediate.} = 
+macro strong*(e: expr): expr {.immediate.} =
   ## generates the HTML ``strong`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "strong", commonAttr)
 
-macro style*(e: expr): expr {.immediate.} = 
+macro style*(e: expr): expr {.immediate.} =
   ## generates the HTML ``style`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "style", "media title", "type")
 
-macro sub*(e: expr): expr {.immediate.} = 
+macro sub*(e: expr): expr {.immediate.} =
   ## generates the HTML ``sub`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "sub", commonAttr)
 
-macro sup*(e: expr): expr {.immediate.} = 
+macro sup*(e: expr): expr {.immediate.} =
   ## generates the HTML ``sup`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "sup", commonAttr)
 
-macro table*(e: expr): expr {.immediate.} = 
+macro table*(e: expr): expr {.immediate.} =
   ## generates the HTML ``table`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "table", "summary border cellpadding cellspacing" &
     " frame rules width" & commonAttr)
 
-macro tbody*(e: expr): expr {.immediate.} = 
+macro tbody*(e: expr): expr {.immediate.} =
   ## generates the HTML ``tbody`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "tbody", "align valign" & commonAttr)
 
-macro td*(e: expr): expr {.immediate.} = 
+macro td*(e: expr): expr {.immediate.} =
   ## generates the HTML ``td`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "td", "colspan rowspan abbr axis headers scope" &
     " align valign" & commonAttr)
 
-macro textarea*(e: expr): expr {.immediate.} = 
+macro textarea*(e: expr): expr {.immediate.} =
   ## generates the HTML ``textarea`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "textarea", " name disabled readonly accesskey" &
     " tabindex" & commonAttr, "rows cols", false)
 
-macro tfoot*(e: expr): expr {.immediate.} = 
+macro tfoot*(e: expr): expr {.immediate.} =
   ## generates the HTML ``tfoot`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "tfoot", "align valign" & commonAttr)
 
-macro th*(e: expr): expr {.immediate.} = 
+macro th*(e: expr): expr {.immediate.} =
   ## generates the HTML ``th`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "th", "colspan rowspan abbr axis headers scope" &
     " align valign" & commonAttr)
 
-macro thead*(e: expr): expr {.immediate.} = 
+macro thead*(e: expr): expr {.immediate.} =
   ## generates the HTML ``thead`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "thead", "align valign" & commonAttr)
 
-macro title*(e: expr): expr {.immediate.} = 
+macro title*(e: expr): expr {.immediate.} =
   ## generates the HTML ``title`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "title")
 
-macro tr*(e: expr): expr {.immediate.} = 
+macro tr*(e: expr): expr {.immediate.} =
   ## generates the HTML ``tr`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "tr", "align valign" & commonAttr)
 
-macro tt*(e: expr): expr {.immediate.} = 
+macro tt*(e: expr): expr {.immediate.} =
   ## generates the HTML ``tt`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "tt", commonAttr)
 
-macro ul*(e: expr): expr {.immediate.} = 
+macro ul*(e: expr): expr {.immediate.} =
   ## generates the HTML ``ul`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "ul", commonAttr)
 
-macro `var`*(e: expr): expr {.immediate.} = 
+macro `var`*(e: expr): expr {.immediate.} =
   ## generates the HTML ``var`` element.
   let e = callsite()
   result = xmlCheckedTag(e, "var", commonAttr)
 
 when isMainModule:
-  var nim = "Nim"
-  echo h1(a(href="http://nim-lang.org", nim))
-  echo form(action="test", `accept-charset` = "Content-Type")
-
+  let nim = "Nim"
+  assert h1(a(href="http://nim-lang.org", nim)) ==
+    """<h1><a href="http://nim-lang.org">Nim</a></h1>"""
+  assert form(action="test", `accept-charset` = "Content-Type") ==
+    """<form action="test" accept-charset="Content-Type"></form>"""
diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim
index e2cbb4949..9719181b8 100644
--- a/lib/pure/htmlparser.nim
+++ b/lib/pure/htmlparser.nim
@@ -552,7 +552,7 @@ proc parse(x: var XmlParser, errors: var seq[string]): XmlNode =
 proc parseHtml*(s: Stream, filename: string, 
                 errors: var seq[string]): XmlNode = 
   ## parses the XML from stream `s` and returns a ``PXmlNode``. Every
-  ## occured parsing error is added to the `errors` sequence.
+  ## occurred parsing error is added to the `errors` sequence.
   var x: XmlParser
   open(x, s, filename, {reportComments, reportWhitespace})
   next(x)
@@ -581,7 +581,7 @@ proc parseHtml*(s: Stream): XmlNode =
 
 proc loadHtml*(path: string, errors: var seq[string]): XmlNode = 
   ## Loads and parses HTML from file specified by ``path``, and returns 
-  ## a ``PXmlNode``.  Every occured parsing error is added to
+  ## a ``PXmlNode``.  Every occurred parsing error is added to
   ## the `errors` sequence.
   var s = newFileStream(path, fmRead)
   if s == nil: raise newException(IOError, "Unable to read file: " & path)
@@ -593,7 +593,7 @@ proc loadHtml*(path: string): XmlNode =
   var errors: seq[string] = @[]
   result = loadHtml(path, errors)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   import os
 
   var errors: seq[string] = @[]  
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 2b161778c..9c27ecdab 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -32,21 +32,12 @@
 ## the server.
 ##
 ## .. code-block:: Nim
-##   var headers: string = "Content-Type: multipart/form-data; boundary=xyz\c\L"
-##   var body: string = "--xyz\c\L"
-##   # soap 1.2 output
-##   body.add("Content-Disposition: form-data; name=\"output\"\c\L")
-##   body.add("\c\Lsoap12\c\L")
+##   var data = newMultipartData()
+##   data["output"] = "soap12"
+##   data["uploaded_file"] = ("test.html", "text/html",
+##     "<html><head></head><body><p>test</p></body></html>")
 ##
-##   # html
-##   body.add("--xyz\c\L")
-##   body.add("Content-Disposition: form-data; name=\"uploaded_file\";" &
-##            " filename=\"test.html\"\c\L")
-##   body.add("Content-Type: text/html\c\L")
-##   body.add("\c\L<html><head></head><body><p>test</p></body></html>\c\L")
-##   body.add("--xyz--")
-##
-##   echo(postContent("http://validator.w3.org/check", headers, body))
+##   echo postContent("http://validator.w3.org/check", multipart=data)
 ##
 ## Asynchronous HTTP requests
 ## ==========================
@@ -88,10 +79,9 @@
 ## constructor should be used for this purpose. However,
 ## currently only basic authentication is supported.
 
-import sockets, strutils, parseurl, parseutils, strtabs, base64, os
+import net, strutils, uri, parseutils, strtabs, base64, os, mimetypes, math
 import asyncnet, asyncdispatch
 import rawsockets
-from net import nil
 
 type
   Response* = tuple[
@@ -101,9 +91,13 @@ type
     body: string]
 
   Proxy* = ref object
-    url*: Url
+    url*: Uri
     auth*: string
 
+  MultipartEntries* = openarray[tuple[name, content: string]]
+  MultipartData* = ref object
+    content: seq[string]
+
   ProtocolError* = object of IOError   ## exception that is raised when server
                                        ## does not conform to the implemented
                                        ## protocol
@@ -157,7 +151,9 @@ proc parseChunks(s: Socket, timeout: int): string =
       else:
         httpError("Invalid chunk size: " & chunkSizeStr)
       inc(i)
-    if chunkSize <= 0: break
+    if chunkSize <= 0:
+      s.skip(2, timeout) # Skip \c\L
+      break
     result.setLen(ri+chunkSize)
     var bytesRead = 0
     while bytesRead != chunkSize:
@@ -231,7 +227,7 @@ proc parseResponse(s: Socket, getBody: bool, timeout: int): Response =
       inc(linei, le)
       # Status code
       linei.inc skipWhitespace(line, linei)
-      result.status = line[linei .. -1]
+      result.status = line[linei .. ^1]
       parsedStatus = true
     else:
       # Parse headers
@@ -242,7 +238,7 @@ proc parseResponse(s: Socket, getBody: bool, timeout: int): Response =
       if line[linei] != ':': httpError("invalid headers")
       inc(linei) # Skip :
 
-      result.headers[name] = line[linei.. -1].strip()
+      result.headers[name] = line[linei.. ^1].strip()
   if not fullyRead:
     httpError("Connection was closed before full request has been made")
   if getBody:
@@ -279,21 +275,128 @@ else:
 
 proc newProxy*(url: string, auth = ""): Proxy =
   ## Constructs a new ``TProxy`` object.
-  result = Proxy(url: parseUrl(url), auth: auth)
+  result = Proxy(url: parseUri(url), auth: auth)
+
+proc newMultipartData*: MultipartData =
+  ## Constructs a new ``MultipartData`` object.
+  MultipartData(content: @[])
+
+proc add*(p: var MultipartData, name, content: string, filename: string = nil,
+          contentType: string = nil) =
+  ## Add a value to the multipart data. Raises a `ValueError` exception if
+  ## `name`, `filename` or `contentType` contain newline characters.
+
+  if {'\c','\L'} in name:
+    raise newException(ValueError, "name contains a newline character")
+  if filename != nil and {'\c','\L'} in filename:
+    raise newException(ValueError, "filename contains a newline character")
+  if contentType != nil and {'\c','\L'} in contentType:
+    raise newException(ValueError, "contentType contains a newline character")
+
+  var str = "Content-Disposition: form-data; name=\"" & name & "\""
+  if filename != nil:
+    str.add("; filename=\"" & filename & "\"")
+  str.add("\c\L")
+  if contentType != nil:
+    str.add("Content-Type: " & contentType & "\c\L")
+  str.add("\c\L" & content & "\c\L")
+
+  p.content.add(str)
+
+proc add*(p: var MultipartData, xs: MultipartEntries): MultipartData
+         {.discardable.} =
+  ## Add a list of multipart entries to the multipart data `p`. All values are
+  ## added without a filename and without a content type.
+  ##
+  ## .. code-block:: Nim
+  ##   data.add({"action": "login", "format": "json"})
+  for name, content in xs.items:
+    p.add(name, content)
+  result = p
+
+proc newMultipartData*(xs: MultipartEntries): MultipartData =
+  ## Create a new multipart data object and fill it with the entries `xs`
+  ## directly.
+  ##
+  ## .. code-block:: Nim
+  ##   var data = newMultipartData({"action": "login", "format": "json"})
+  result = MultipartData(content: @[])
+  result.add(xs)
+
+proc addFiles*(p: var MultipartData, xs: openarray[tuple[name, file: string]]):
+              MultipartData {.discardable.} =
+  ## Add files to a multipart data object. The file will be opened from your
+  ## disk, read and sent with the automatically determined MIME type. Raises an
+  ## `IOError` if the file cannot be opened or reading fails. To manually
+  ## specify file content, filename and MIME type, use `[]=` instead.
+  ##
+  ## .. code-block:: Nim
+  ##   data.addFiles({"uploaded_file": "public/test.html"})
+  var m = newMimetypes()
+  for name, file in xs.items:
+    var contentType: string
+    let (dir, fName, ext) = splitFile(file)
+    if ext.len > 0:
+      contentType = m.getMimetype(ext[1..ext.high], nil)
+    p.add(name, readFile(file), fName & ext, contentType)
+  result = p
+
+proc `[]=`*(p: var MultipartData, name, content: string) =
+  ## Add a multipart entry to the multipart data `p`. The value is added
+  ## without a filename and without a content type.
+  ##
+  ## .. code-block:: Nim
+  ##   data["username"] = "NimUser"
+  p.add(name, content)
+
+proc `[]=`*(p: var MultipartData, name: string,
+            file: tuple[name, contentType, content: string]) =
+  ## Add a file to the multipart data `p`, specifying filename, contentType and
+  ## content manually.
+  ##
+  ## .. code-block:: Nim
+  ##   data["uploaded_file"] = ("test.html", "text/html",
+  ##     "<html><head></head><body><p>test</p></body></html>")
+  p.add(name, file.content, file.name, file.contentType)
 
-proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
-              body = "",
-              sslContext: SSLContext = defaultSSLContext,
-              timeout = -1, userAgent = defUserAgent,
-              proxy: Proxy = nil): Response =
-  ## | Requests ``url`` with the specified ``httpMethod``.
-  ## | Extra headers can be specified and must be seperated by ``\c\L``
+proc format(p: MultipartData): tuple[header, body: string] =
+  if p == nil or p.content == nil or p.content.len == 0:
+    return ("", "")
+
+  # Create boundary that is not in the data to be formatted
+  var bound: string
+  while true:
+    bound = $random(int.high)
+    var found = false
+    for s in p.content:
+      if bound in s:
+        found = true
+    if not found:
+      break
+
+  result.header = "Content-Type: multipart/form-data; boundary=" & bound & "\c\L"
+  result.body = ""
+  for s in p.content:
+    result.body.add("--" & bound & "\c\L" & s)
+  result.body.add("--" & bound & "--\c\L")
+
+proc request*(url: string, httpMethod: string, extraHeaders = "",
+              body = "", sslContext = defaultSSLContext, timeout = -1,
+              userAgent = defUserAgent, proxy: Proxy = nil): Response =
+  ## | Requests ``url`` with the custom method string specified by the
+  ## | ``httpMethod`` parameter.
+  ## | Extra headers can be specified and must be separated by ``\c\L``
   ## | An optional timeout can be specified in miliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
-  var r = if proxy == nil: parseUrl(url) else: proxy.url
-  var headers = substr($httpMethod, len("http"))
+  var r = if proxy == nil: parseUri(url) else: proxy.url
+  var headers = substr(httpMethod, len("http"))
+  # TODO: Use generateHeaders further down once it supports proxies.
   if proxy == nil:
-    headers.add(" /" & r.path & r.query)
+    headers.add ' '
+    if r.path[0] != '/': headers.add '/'
+    headers.add(r.path)
+    if r.query.len > 0:
+      headers.add("?" & r.query)
   else:
     headers.add(" " & url)
 
@@ -308,18 +411,18 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
   add(headers, extraHeaders)
   add(headers, "\c\L")
 
-  var s = socket()
-  if s == invalidSocket: raiseOSError(osLastError())
-  var port = sockets.Port(80)
+  var s = newSocket()
+  if s == nil: raiseOSError(osLastError())
+  var port = net.Port(80)
   if r.scheme == "https":
     when defined(ssl):
       sslContext.wrapSocket(s)
-      port = sockets.Port(443)
+      port = net.Port(443)
     else:
       raise newException(HttpRequestError,
                 "SSL support is not available. Cannot connect over SSL.")
   if r.port != "":
-    port = sockets.Port(r.port.parseInt)
+    port = net.Port(r.port.parseInt)
 
   if timeout == -1:
     s.connect(r.hostname, port)
@@ -329,9 +432,19 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
   if body != "":
     s.send(body)
 
-  result = parseResponse(s, httpMethod != httpHEAD, timeout)
+  result = parseResponse(s, httpMethod != "httpHEAD", timeout)
   s.close()
 
+proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
+              body = "", sslContext = defaultSSLContext, timeout = -1,
+              userAgent = defUserAgent, proxy: Proxy = nil): Response =
+  ## | Requests ``url`` with the specified ``httpMethod``.
+  ## | Extra headers can be specified and must be separated by ``\c\L``
+  ## | An optional timeout can be specified in miliseconds, if reading from the
+  ## server takes longer than specified an ETimeout exception will be raised.
+  result = request(url, $httpMethod, extraHeaders, body, sslContext, timeout,
+                   userAgent, proxy)
+
 proc redirection(status: string): bool =
   const redirectionNRs = ["301", "302", "303", "307"]
   for i in items(redirectionNRs):
@@ -342,9 +455,9 @@ proc getNewLocation(lastUrl: string, headers: StringTableRef): string =
   result = headers["Location"]
   if result == "": httpError("location header expected")
   # Relative URLs. (Not part of the spec, but soon will be.)
-  let r = parseURL(result)
+  let r = parseUri(result)
   if r.hostname == "" and r.path != "":
-    let origParsed = parseURL(lastUrl)
+    let origParsed = parseUri(lastUrl)
     result = origParsed.hostname & "/" & r.path
 
 proc get*(url: string, extraHeaders = "", maxRedirects = 5,
@@ -386,22 +499,37 @@ proc post*(url: string, extraHeaders = "", body = "",
            maxRedirects = 5,
            sslContext: SSLContext = defaultSSLContext,
            timeout = -1, userAgent = defUserAgent,
-           proxy: Proxy = nil): Response =
+           proxy: Proxy = nil,
+           multipart: MultipartData = nil): Response =
   ## | POSTs ``body`` to the ``url`` and returns a ``Response`` object.
   ## | This proc adds the necessary Content-Length header.
   ## | This proc also handles redirection.
   ## | Extra headers can be specified and must be separated by ``\c\L``.
   ## | An optional timeout can be specified in miliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
-  var xh = extraHeaders & "Content-Length: " & $len(body) & "\c\L"
-  result = request(url, httpPOST, xh, body, sslContext, timeout, userAgent,
+  ## | The optional ``multipart`` parameter can be used to create
+  ## ``multipart/form-data`` POSTs comfortably.
+  let (mpHeaders, mpBody) = format(multipart)
+
+  template withNewLine(x): expr =
+    if x.len > 0 and not x.endsWith("\c\L"):
+      x & "\c\L"
+    else:
+      x
+
+  var xb = mpBody.withNewLine() & body
+
+  var xh = extraHeaders.withNewLine() & mpHeaders.withNewLine() &
+    withNewLine("Content-Length: " & $len(xb))
+
+  result = request(url, httpPOST, xh, xb, sslContext, timeout, userAgent,
                    proxy)
   var lastUrl = ""
   for i in 1..maxRedirects:
     if result.status.redirection():
       let redirectTo = getNewLocation(lastURL, result.headers)
       var meth = if result.status != "307": httpGet else: httpPost
-      result = request(redirectTo, meth, xh, body, sslContext, timeout,
+      result = request(redirectTo, meth, xh, xb, sslContext, timeout,
                        userAgent, proxy)
       lastUrl = redirectTo
 
@@ -409,14 +537,17 @@ proc postContent*(url: string, extraHeaders = "", body = "",
                   maxRedirects = 5,
                   sslContext: SSLContext = defaultSSLContext,
                   timeout = -1, userAgent = defUserAgent,
-                  proxy: Proxy = nil): string =
+                  proxy: Proxy = nil,
+                  multipart: MultipartData = nil): string =
   ## | POSTs ``body`` to ``url`` and returns the response's body as a string
   ## | Raises exceptions for the status codes ``4xx`` and ``5xx``
   ## | Extra headers can be specified and must be separated by ``\c\L``.
   ## | An optional timeout can be specified in miliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
+  ## | The optional ``multipart`` parameter can be used to create
+  ## ``multipart/form-data`` POSTs comfortably.
   var r = post(url, extraHeaders, body, maxRedirects, sslContext, timeout,
-               userAgent, proxy)
+               userAgent, proxy, multipart)
   if r.status[0] in {'4','5'}:
     raise newException(HttpRequestError, r.status)
   else:
@@ -437,11 +568,16 @@ proc downloadFile*(url: string, outputFilename: string,
   else:
     fileError("Unable to open file")
 
-proc generateHeaders(r: Url, httpMethod: HttpMethod,
+proc generateHeaders(r: Uri, httpMethod: string,
                      headers: StringTableRef): string =
-  result = substr($httpMethod, len("http"))
+  # TODO: Use this in the blocking HttpClient once it supports proxies.
+  result = substr(httpMethod, len("http"))
   # TODO: Proxies
-  result.add(" /" & r.path & r.query)
+  result.add ' '
+  if r.path[0] != '/': result.add '/'
+  result.add(r.path)
+  if r.query.len > 0:
+    result.add("?" & r.query)
   result.add(" HTTP/1.1\c\L")
 
   add(result, "Host: " & r.hostname & "\c\L")
@@ -455,7 +591,7 @@ type
   AsyncHttpClient* = ref object
     socket: AsyncSocket
     connected: bool
-    currentURL: Url ## Where we are currently connected.
+    currentURL: Uri ## Where we are currently connected.
     headers*: StringTableRef
     maxRedirects: int
     userAgent: string
@@ -499,7 +635,6 @@ proc recvFull(socket: AsyncSocket, size: int): Future[string] {.async.} =
 
 proc parseChunks(client: AsyncHttpClient): Future[string] {.async.} =
   result = ""
-  var ri = 0
   while true:
     var chunkSize = 0
     var chunkSizeStr = await client.socket.recvLine()
@@ -523,7 +658,9 @@ proc parseChunks(client: AsyncHttpClient): Future[string] {.async.} =
       else:
         httpError("Invalid chunk size: " & chunkSizeStr)
       inc(i)
-    if chunkSize <= 0: break
+    if chunkSize <= 0:
+      discard await recvFull(client.socket, 2) # Skip \c\L
+      break
     result.add await recvFull(client.socket, chunkSize)
     discard await recvFull(client.socket, 2) # Skip \c\L
     # Trailer headers will only be sent if the request specifies that we want
@@ -588,7 +725,7 @@ proc parseResponse(client: AsyncHttpClient,
       inc(linei, le)
       # Status code
       linei.inc skipWhitespace(line, linei)
-      result.status = line[linei .. -1]
+      result.status = line[linei .. ^1]
       parsedStatus = true
     else:
       # Parse headers
@@ -599,7 +736,7 @@ proc parseResponse(client: AsyncHttpClient,
       if line[linei] != ':': httpError("invalid headers")
       inc(linei) # Skip :
 
-      result.headers[name] = line[linei.. -1].strip()
+      result.headers[name] = line[linei.. ^1].strip()
   if not fullyRead:
     httpError("Connection was closed before full request has been made")
   if getBody:
@@ -607,7 +744,7 @@ proc parseResponse(client: AsyncHttpClient,
   else:
     result.body = ""
 
-proc newConnection(client: AsyncHttpClient, url: Url) {.async.} =
+proc newConnection(client: AsyncHttpClient, url: Uri) {.async.} =
   if client.currentURL.hostname != url.hostname or
       client.currentURL.scheme != url.scheme:
     if client.connected: client.close()
@@ -633,29 +770,41 @@ proc newConnection(client: AsyncHttpClient, url: Url) {.async.} =
     client.currentURL = url
     client.connected = true
 
-proc request*(client: AsyncHttpClient, url: string, httpMethod = httpGET,
+proc request*(client: AsyncHttpClient, url: string, httpMethod: string,
               body = ""): Future[Response] {.async.} =
   ## Connects to the hostname specified by the URL and performs a request
-  ## using the method specified.
+  ## using the custom method string specified by ``httpMethod``.
   ##
   ## Connection will kept alive. Further requests on the same ``client`` to
   ## the same hostname will not require a new connection to be made. The
   ## connection can be closed by using the ``close`` procedure.
   ##
   ## The returned future will complete once the request is completed.
-  let r = parseUrl(url)
+  let r = parseUri(url)
   await newConnection(client, r)
 
   if not client.headers.hasKey("user-agent") and client.userAgent != "":
     client.headers["User-Agent"] = client.userAgent
 
-  var headers = generateHeaders(r, httpMethod, client.headers)
+  var headers = generateHeaders(r, $httpMethod, client.headers)
 
   await client.socket.send(headers)
   if body != "":
     await client.socket.send(body)
 
-  result = await parseResponse(client, httpMethod != httpHEAD)
+  result = await parseResponse(client, httpMethod != "httpHEAD")
+
+proc request*(client: AsyncHttpClient, url: string, httpMethod = httpGET,
+              body = ""): Future[Response] =
+  ## Connects to the hostname specified by the URL and performs a request
+  ## using the method specified.
+  ##
+  ## Connection will kept alive. Further requests on the same ``client`` to
+  ## the same hostname will not require a new connection to be made. The
+  ## connection can be closed by using the ``close`` procedure.
+  ##
+  ## The returned future will complete once the request is completed.
+  result = request(client, url, $httpMethod, body)
 
 proc get*(client: AsyncHttpClient, url: string): Future[Response] {.async.} =
   ## Connects to the hostname specified by the URL and performs a GET request.
@@ -670,7 +819,7 @@ proc get*(client: AsyncHttpClient, url: string): Future[Response] {.async.} =
       result = await client.request(redirectTo, httpGET)
       lastUrl = redirectTo
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   when true:
     # Async
     proc main() {.async.} =
@@ -704,18 +853,9 @@ when isMainModule:
     #var r = get("http://validator.w3.org/check?uri=http%3A%2F%2Fgoogle.com&
     #  charset=%28detect+automatically%29&doctype=Inline&group=0")
 
-    var headers: string = "Content-Type: multipart/form-data; boundary=xyz\c\L"
-    var body: string = "--xyz\c\L"
-    # soap 1.2 output
-    body.add("Content-Disposition: form-data; name=\"output\"\c\L")
-    body.add("\c\Lsoap12\c\L")
-
-    # html
-    body.add("--xyz\c\L")
-    body.add("Content-Disposition: form-data; name=\"uploaded_file\";" &
-             " filename=\"test.html\"\c\L")
-    body.add("Content-Type: text/html\c\L")
-    body.add("\c\L<html><head></head><body><p>test</p></body></html>\c\L")
-    body.add("--xyz--")
-
-    echo(postContent("http://validator.w3.org/check", headers, body))
+    var data = newMultipartData()
+    data["output"] = "soap12"
+    data["uploaded_file"] = ("test.html", "text/html",
+      "<html><head></head><body><p>test</p></body></html>")
+
+    echo postContent("http://validator.w3.org/check", multipart=data)
diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim
index 38a068ea1..dc76c9228 100644
--- a/lib/pure/httpserver.nim
+++ b/lib/pure/httpserver.nim
@@ -363,7 +363,7 @@ proc run*(handleRequest: proc (client: Socket,
           port = Port(80)) =
   ## encapsulates the server object and main loop
   var s: TServer
-  open(s, port)
+  open(s, port, reuseAddr = true)
   #echo("httpserver running on port ", s.port)
   while true:
     next(s)
@@ -514,7 +514,7 @@ proc close*(h: PAsyncHTTPServer) =
   ## Closes the ``PAsyncHTTPServer``.
   h.asyncSocket.close()
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   var counter = 0
 
   var s: TServer
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 385787d6c..5d824d6f8 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -1,15 +1,15 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf, Dominik Picheta
+#        (c) Copyright 2015 Andreas Rumpf, Dominik Picheta
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
 ## This module implements a simple high performance `JSON`:idx:
-## parser. JSON (JavaScript Object Notation) is a lightweight 
-## data-interchange format that is easy for humans to read and write 
+## parser. JSON (JavaScript Object Notation) is a lightweight
+## data-interchange format that is easy for humans to read and write
 ## (unlike XML). It is easy for machines to parse and generate.
 ## JSON is based on a subset of the JavaScript Programming Language,
 ## Standard ECMA-262 3rd Edition - December 1999.
@@ -30,13 +30,32 @@
 ##
 ##   1.3000000000000000e+00
 ##   true
+##
+## This module can also be used to comfortably create JSON using the `%*`
+## operator:
+##
+## .. code-block:: nim
+##
+##   var hisName = "John"
+##   let herAge = 31
+##   var j = %*
+##     [
+##       {
+##         "name": hisName,
+##         "age": 30
+##       },
+##       {
+##         "name": "Susan",
+##         "age": herAge
+##       }
+##     ]
+
+import
+  hashes, strutils, lexbase, streams, unicode, macros
 
-import 
-  hashes, strutils, lexbase, streams, unicode
-
-type 
+type
   JsonEventKind* = enum  ## enumeration of all events that may occur when parsing
-    jsonError,           ## an error ocurred during parsing
+    jsonError,           ## an error occurred during parsing
     jsonEof,             ## end of file reached
     jsonString,          ## a string literal
     jsonInt,             ## an integer literal
@@ -48,7 +67,7 @@ type
     jsonObjectEnd,       ## end of an object: the ``}`` token
     jsonArrayStart,      ## start of an array: the ``[`` token
     jsonArrayEnd         ## start of an array: the ``]`` token
-    
+
   TTokKind = enum        # must be synchronized with TJsonEventKind!
     tkError,
     tkEof,
@@ -64,7 +83,7 @@ type
     tkBracketRi,
     tkColon,
     tkComma
-    
+
   JsonError* = enum        ## enumeration that lists all errors that can occur
     errNone,               ## no error
     errInvalidToken,       ## invalid token
@@ -77,8 +96,8 @@ type
     errEOC_Expected,       ## ``*/`` expected
     errEofExpected,        ## EOF expected
     errExprExpected        ## expr expected
-    
-  ParserState = enum 
+
+  ParserState = enum
     stateEof, stateStart, stateObject, stateArray, stateExpectArrayComma,
     stateExpectObjectComma, stateExpectColon, stateExpectValue
 
@@ -92,7 +111,7 @@ type
 
 {.deprecated: [TJsonEventKind: JsonEventKind, TJsonError: JsonError,
   TJsonParser: JsonParser].}
- 
+
 const
   errorMessages: array [JsonError, string] = [
     "no error",
@@ -127,56 +146,56 @@ proc open*(my: var JsonParser, input: Stream, filename: string) =
   my.state = @[stateStart]
   my.kind = jsonError
   my.a = ""
-  
-proc close*(my: var JsonParser) {.inline.} = 
+
+proc close*(my: var JsonParser) {.inline.} =
   ## closes the parser `my` and its associated input stream.
   lexbase.close(my)
 
-proc str*(my: JsonParser): string {.inline.} = 
-  ## returns the character data for the events: ``jsonInt``, ``jsonFloat``, 
+proc str*(my: JsonParser): string {.inline.} =
+  ## returns the character data for the events: ``jsonInt``, ``jsonFloat``,
   ## ``jsonString``
   assert(my.kind in {jsonInt, jsonFloat, jsonString})
   return my.a
 
-proc getInt*(my: JsonParser): BiggestInt {.inline.} = 
+proc getInt*(my: JsonParser): BiggestInt {.inline.} =
   ## returns the number for the event: ``jsonInt``
   assert(my.kind == jsonInt)
   return parseBiggestInt(my.a)
 
-proc getFloat*(my: JsonParser): float {.inline.} = 
+proc getFloat*(my: JsonParser): float {.inline.} =
   ## returns the number for the event: ``jsonFloat``
   assert(my.kind == jsonFloat)
   return parseFloat(my.a)
 
-proc kind*(my: JsonParser): JsonEventKind {.inline.} = 
+proc kind*(my: JsonParser): JsonEventKind {.inline.} =
   ## returns the current event type for the JSON parser
   return my.kind
-  
-proc getColumn*(my: JsonParser): int {.inline.} = 
+
+proc getColumn*(my: JsonParser): int {.inline.} =
   ## get the current column the parser has arrived at.
   result = getColNumber(my, my.bufpos)
 
-proc getLine*(my: JsonParser): int {.inline.} = 
+proc getLine*(my: JsonParser): int {.inline.} =
   ## get the current line the parser has arrived at.
   result = my.lineNumber
 
-proc getFilename*(my: JsonParser): string {.inline.} = 
+proc getFilename*(my: JsonParser): string {.inline.} =
   ## get the filename of the file that the parser processes.
   result = my.filename
-  
-proc errorMsg*(my: JsonParser): string = 
+
+proc errorMsg*(my: JsonParser): string =
   ## returns a helpful error message for the event ``jsonError``
   assert(my.kind == jsonError)
   result = "$1($2, $3) Error: $4" % [
     my.filename, $getLine(my), $getColumn(my), errorMessages[my.err]]
 
-proc errorMsgExpected*(my: JsonParser, e: string): string = 
+proc errorMsgExpected*(my: JsonParser, e: string): string =
   ## returns an error message "`e` expected" in the same format as the
-  ## other error messages 
+  ## other error messages
   result = "$1($2, $3) Error: $4" % [
     my.filename, $getLine(my), $getColumn(my), e & " expected"]
 
-proc handleHexChar(c: char, x: var int): bool = 
+proc handleHexChar(c: char, x: var int): bool =
   result = true # Success
   case c
   of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
@@ -189,8 +208,8 @@ proc parseString(my: var JsonParser): TTokKind =
   var pos = my.bufpos + 1
   var buf = my.buf
   while true:
-    case buf[pos] 
-    of '\0': 
+    case buf[pos]
+    of '\0':
       my.err = errQuoteExpected
       result = tkError
       break
@@ -199,21 +218,21 @@ proc parseString(my: var JsonParser): TTokKind =
       break
     of '\\':
       case buf[pos+1]
-      of '\\', '"', '\'', '/': 
+      of '\\', '"', '\'', '/':
         add(my.a, buf[pos+1])
         inc(pos, 2)
       of 'b':
         add(my.a, '\b')
-        inc(pos, 2)      
+        inc(pos, 2)
       of 'f':
         add(my.a, '\f')
-        inc(pos, 2)      
+        inc(pos, 2)
       of 'n':
         add(my.a, '\L')
-        inc(pos, 2)      
+        inc(pos, 2)
       of 'r':
         add(my.a, '\C')
-        inc(pos, 2)    
+        inc(pos, 2)
       of 't':
         add(my.a, '\t')
         inc(pos, 2)
@@ -225,15 +244,15 @@ proc parseString(my: var JsonParser): TTokKind =
         if handleHexChar(buf[pos], r): inc(pos)
         if handleHexChar(buf[pos], r): inc(pos)
         add(my.a, toUTF8(Rune(r)))
-      else: 
+      else:
         # don't bother with the error
         add(my.a, buf[pos])
         inc(pos)
-    of '\c': 
+    of '\c':
       pos = lexbase.handleCR(my, pos)
       buf = my.buf
       add(my.a, '\c')
-    of '\L': 
+    of '\L':
       pos = lexbase.handleLF(my, pos)
       buf = my.buf
       add(my.a, '\L')
@@ -241,25 +260,25 @@ proc parseString(my: var JsonParser): TTokKind =
       add(my.a, buf[pos])
       inc(pos)
   my.bufpos = pos # store back
-  
-proc skip(my: var JsonParser) = 
+
+proc skip(my: var JsonParser) =
   var pos = my.bufpos
   var buf = my.buf
-  while true: 
+  while true:
     case buf[pos]
-    of '/': 
-      if buf[pos+1] == '/': 
+    of '/':
+      if buf[pos+1] == '/':
         # skip line comment:
         inc(pos, 2)
         while true:
-          case buf[pos] 
-          of '\0': 
+          case buf[pos]
+          of '\0':
             break
-          of '\c': 
+          of '\c':
             pos = lexbase.handleCR(my, pos)
             buf = my.buf
             break
-          of '\L': 
+          of '\L':
             pos = lexbase.handleLF(my, pos)
             buf = my.buf
             break
@@ -269,44 +288,44 @@ proc skip(my: var JsonParser) =
         # skip long comment:
         inc(pos, 2)
         while true:
-          case buf[pos] 
-          of '\0': 
+          case buf[pos]
+          of '\0':
             my.err = errEOC_Expected
             break
-          of '\c': 
+          of '\c':
             pos = lexbase.handleCR(my, pos)
             buf = my.buf
-          of '\L': 
+          of '\L':
             pos = lexbase.handleLF(my, pos)
             buf = my.buf
           of '*':
             inc(pos)
-            if buf[pos] == '/': 
+            if buf[pos] == '/':
               inc(pos)
               break
           else:
             inc(pos)
-      else: 
+      else:
         break
-    of ' ', '\t': 
+    of ' ', '\t':
       inc(pos)
-    of '\c':  
+    of '\c':
       pos = lexbase.handleCR(my, pos)
       buf = my.buf
-    of '\L': 
+    of '\L':
       pos = lexbase.handleLF(my, pos)
       buf = my.buf
     else:
       break
   my.bufpos = pos
 
-proc parseNumber(my: var JsonParser) = 
+proc parseNumber(my: var JsonParser) =
   var pos = my.bufpos
   var buf = my.buf
-  if buf[pos] == '-': 
+  if buf[pos] == '-':
     add(my.a, '-')
     inc(pos)
-  if buf[pos] == '.': 
+  if buf[pos] == '.':
     add(my.a, "0.")
     inc(pos)
   else:
@@ -331,7 +350,7 @@ proc parseNumber(my: var JsonParser) =
       inc(pos)
   my.bufpos = pos
 
-proc parseName(my: var JsonParser) = 
+proc parseName(my: var JsonParser) =
   var pos = my.bufpos
   var buf = my.buf
   if buf[pos] in IdentStartChars:
@@ -340,11 +359,11 @@ proc parseName(my: var JsonParser) =
       inc(pos)
   my.bufpos = pos
 
-proc getTok(my: var JsonParser): TTokKind = 
+proc getTok(my: var JsonParser): TTokKind =
   setLen(my.a, 0)
   skip(my) # skip whitespace, comments
   case my.buf[my.bufpos]
-  of '-', '.', '0'..'9': 
+  of '-', '.', '0'..'9':
     parseNumber(my)
     if {'.', 'e', 'E'} in my.a:
       result = tkFloat
@@ -374,17 +393,17 @@ proc getTok(my: var JsonParser): TTokKind =
     result = tkEof
   of 'a'..'z', 'A'..'Z', '_':
     parseName(my)
-    case my.a 
+    case my.a
     of "null": result = tkNull
     of "true": result = tkTrue
     of "false": result = tkFalse
     else: result = tkError
-  else: 
+  else:
     inc(my.bufpos)
     result = tkError
   my.tok = result
 
-proc next*(my: var JsonParser) = 
+proc next*(my: var JsonParser) =
   ## retrieves the first/next event. This controls the parser.
   var tk = getTok(my)
   var i = my.state.len-1
@@ -397,13 +416,13 @@ proc next*(my: var JsonParser) =
     else:
       my.kind = jsonError
       my.err = errEofExpected
-  of stateStart: 
-    # tokens allowed? 
+  of stateStart:
+    # tokens allowed?
     case tk
     of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull:
       my.state[i] = stateEof # expect EOF next!
       my.kind = JsonEventKind(ord(tk))
-    of tkBracketLe: 
+    of tkBracketLe:
       my.state.add(stateArray) # we expect any
       my.kind = jsonArrayStart
     of tkCurlyLe:
@@ -414,12 +433,12 @@ proc next*(my: var JsonParser) =
     else:
       my.kind = jsonError
       my.err = errEofExpected
-  of stateObject: 
+  of stateObject:
     case tk
     of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull:
       my.state.add(stateExpectColon)
       my.kind = JsonEventKind(ord(tk))
-    of tkBracketLe: 
+    of tkBracketLe:
       my.state.add(stateExpectColon)
       my.state.add(stateArray)
       my.kind = jsonArrayStart
@@ -438,7 +457,7 @@ proc next*(my: var JsonParser) =
     of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull:
       my.state.add(stateExpectArrayComma) # expect value next!
       my.kind = JsonEventKind(ord(tk))
-    of tkBracketLe: 
+    of tkBracketLe:
       my.state.add(stateExpectArrayComma)
       my.state.add(stateArray)
       my.kind = jsonArrayStart
@@ -453,8 +472,8 @@ proc next*(my: var JsonParser) =
       my.kind = jsonError
       my.err = errBracketRiExpected
   of stateExpectArrayComma:
-    case tk 
-    of tkComma: 
+    case tk
+    of tkComma:
       discard my.state.pop()
       next(my)
     of tkBracketRi:
@@ -465,8 +484,8 @@ proc next*(my: var JsonParser) =
       my.kind = jsonError
       my.err = errBracketRiExpected
   of stateExpectObjectComma:
-    case tk 
-    of tkComma: 
+    case tk
+    of tkComma:
       discard my.state.pop()
       next(my)
     of tkCurlyRi:
@@ -476,9 +495,9 @@ proc next*(my: var JsonParser) =
     else:
       my.kind = jsonError
       my.err = errCurlyRiExpected
-  of stateExpectColon: 
-    case tk 
-    of tkColon: 
+  of stateExpectColon:
+    case tk
+    of tkColon:
       my.state[i] = stateExpectValue
       next(my)
     else:
@@ -489,7 +508,7 @@ proc next*(my: var JsonParser) =
     of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull:
       my.state[i] = stateExpectObjectComma
       my.kind = JsonEventKind(ord(tk))
-    of tkBracketLe: 
+    of tkBracketLe:
       my.state[i] = stateExpectObjectComma
       my.state.add(stateArray)
       my.kind = jsonArrayStart
@@ -513,8 +532,8 @@ type
     JString,
     JObject,
     JArray
-    
-  JsonNode* = ref JsonNodeObj ## JSON node 
+
+  JsonNode* = ref JsonNodeObj ## JSON node
   JsonNodeObj* {.acyclic.} = object
     case kind*: JsonNodeKind
     of JString:
@@ -586,6 +605,49 @@ proc newJArray*(): JsonNode =
   result.kind = JArray
   result.elems = @[]
 
+proc getStr*(n: JsonNode, default: string = ""): string =
+  ## Retrieves the string value of a `JString JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JString``.
+  if n.kind != JString: return default
+  else: return n.str
+
+proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
+  ## Retrieves the int value of a `JInt JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JInt``.
+  if n.kind != JInt: return default
+  else: return n.num
+
+proc getFNum*(n: JsonNode, default: float = 0.0): float =
+  ## Retrieves the float value of a `JFloat JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JFloat``.
+  if n.kind != JFloat: return default
+  else: return n.fnum
+
+proc getBVal*(n: JsonNode, default: bool = false): bool =
+  ## Retrieves the bool value of a `JBool JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JBool``.
+  if n.kind != JBool: return default
+  else: return n.bval
+
+proc getFields*(n: JsonNode,
+    default: seq[tuple[key: string, val: JsonNode]] = @[]):
+        seq[tuple[key: string, val: JsonNode]] =
+  ## Retrieves the key, value pairs of a `JObject JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JObject``.
+  if n.kind != JObject: return default
+  else: return n.fields
+
+proc getElems*(n: JsonNode, default: seq[JsonNode] = @[]): seq[JsonNode] =
+  ## Retrieves the int value of a `JArray JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JArray``.
+  if n.kind != JArray: return default
+  else: return n.elems
 
 proc `%`*(s: string): JsonNode =
   ## Generic constructor for JSON data. Creates a new `JString JsonNode`.
@@ -625,12 +687,35 @@ proc `%`*(elements: openArray[JsonNode]): JsonNode =
   newSeq(result.elems, elements.len)
   for i, p in pairs(elements): result.elems[i] = p
 
+proc toJson(x: NimNode): NimNode {.compiletime.} =
+  case x.kind
+  of nnkBracket:
+    result = newNimNode(nnkBracket)
+    for i in 0 .. <x.len:
+      result.add(toJson(x[i]))
+
+  of nnkTableConstr:
+    result = newNimNode(nnkTableConstr)
+    for i in 0 .. <x.len:
+      assert x[i].kind == nnkExprColonExpr
+      result.add(newNimNode(nnkExprColonExpr).add(x[i][0]).add(toJson(x[i][1])))
+
+  else:
+    result = x
+
+  result = prefix(result, "%")
+
+macro `%*`*(x: expr): expr =
+  ## Convert an expression to a JsonNode directly, without having to specify
+  ## `%` for every element.
+  result = toJson(x)
+
 proc `==`* (a,b: JsonNode): bool =
   ## Check two nodes for equality
   if a.isNil:
     if b.isNil: return true
     return false
-  elif b.isNil or a.kind != b.kind: 
+  elif b.isNil or a.kind != b.kind:
     return false
   else:
     return case a.kind
@@ -667,7 +752,7 @@ proc hash* (n:JsonNode): THash =
   of JNull:
     result = hash(0)
 
-proc len*(n: JsonNode): int = 
+proc len*(n: JsonNode): int =
   ## If `n` is a `JArray`, it returns the number of elements.
   ## If `n` is a `JObject`, it returns the number of pairs.
   ## Else it returns 0.
@@ -685,7 +770,7 @@ proc `[]`*(node: JsonNode, name: string): JsonNode =
     if key == name:
       return item
   return nil
-  
+
 proc `[]`*(node: JsonNode, index: int): JsonNode =
   ## Gets the node at `index` in an Array. Result is undefined if `index`
   ## is out of bounds
@@ -702,12 +787,12 @@ proc hasKey*(node: JsonNode, key: string): bool =
 proc existsKey*(node: JsonNode, key: string): bool {.deprecated.} = node.hasKey(key)
   ## Deprecated for `hasKey`
 
-proc add*(father, child: JsonNode) = 
-  ## Adds `child` to a JArray node `father`. 
+proc add*(father, child: JsonNode) =
+  ## Adds `child` to a JArray node `father`.
   assert father.kind == JArray
   father.elems.add(child)
 
-proc add*(obj: JsonNode, key: string, val: JsonNode) = 
+proc add*(obj: JsonNode, key: string, val: JsonNode) =
   ## Adds ``(key, val)`` pair to the JObject node `obj`. For speed
   ## reasons no check for duplicate keys is performed!
   ## But ``[]=`` performs the check.
@@ -718,27 +803,30 @@ proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) =
   ## Sets a field from a `JObject`. Performs a check for duplicate keys.
   assert(obj.kind == JObject)
   for i in 0..obj.fields.len-1:
-    if obj.fields[i].key == key: 
+    if obj.fields[i].key == key:
       obj.fields[i].val = val
       return
   obj.fields.add((key, val))
 
-proc `{}`*(node: JsonNode, key: string): JsonNode =
-  ## Transverses the node and gets the given value. If any of the
-  ## names does not exist, returns nil
+proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
+  ## Traverses the node and gets the given value. If any of the
+  ## keys do not exist, returns nil. Also returns nil if one of the
+  ## intermediate data structures is not an object
   result = node
-  if isNil(node): return nil
-  result = result[key]
-
-proc `{}=`*(node: JsonNode, names: varargs[string], value: JsonNode) =
-  ## Transverses the node and tries to set the value at the given location
-  ## to `value` If any of the names are missing, they are added
+  for key in keys:
+    if isNil(result) or result.kind!=JObject:
+      return nil    
+    result=result[key]
+
+proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) =
+  ## Traverses the node and tries to set the value at the given location
+  ## to `value` If any of the keys are missing, they are added
   var node = node
-  for i in 0..(names.len-2):
-    if isNil(node[names[i]]):
-      node[names[i]] = newJObject()
-    node = node[names[i]]
-  node[names[names.len-1]] = value
+  for i in 0..(keys.len-2):
+    if isNil(node[keys[i]]):
+      node[keys[i]] = newJObject()
+    node = node[keys[i]]
+  node[keys[keys.len-1]] = value
 
 proc delete*(obj: JsonNode, key: string) =
   ## Deletes ``obj[key]`` preserving the order of the other (key, value)-pairs.
@@ -773,17 +861,17 @@ proc copy*(p: JsonNode): JsonNode =
 
 # ------------- pretty printing ----------------------------------------------
 
-proc indent(s: var string, i: int) = 
-  s.add(repeatChar(i))
+proc indent(s: var string, i: int) =
+  s.add(spaces(i))
 
 proc newIndent(curr, indent: int, ml: bool): int =
   if ml: return curr + indent
   else: return indent
 
-proc nl(s: var string, ml: bool) = 
+proc nl(s: var string, ml: bool) =
   if ml: s.add("\n")
 
-proc escapeJson*(s: string): string = 
+proc escapeJson*(s: string): string =
   ## Converts a string `s` to its JSON representation.
   result = newStringOfCap(s.len + s.len shr 3)
   result.add("\"")
@@ -800,13 +888,13 @@ proc escapeJson*(s: string): string =
       result.add(toHex(r, 4))
   result.add("\"")
 
-proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true, 
+proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true,
               lstArr = false, currIndent = 0) =
   case node.kind
   of JObject:
     if currIndent != 0 and not lstArr: result.nl(ml)
     result.indent(currIndent) # Indentation
-    if node.fields.len > 0:  
+    if node.fields.len > 0:
       result.add("{")
       result.nl(ml) # New line
       for i in 0..len(node.fields)-1:
@@ -814,17 +902,17 @@ proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true,
           result.add(", ")
           result.nl(ml) # New Line
         # Need to indent more than {
-        result.indent(newIndent(currIndent, indent, ml)) 
+        result.indent(newIndent(currIndent, indent, ml))
         result.add(escapeJson(node.fields[i].key))
         result.add(": ")
-        toPretty(result, node.fields[i].val, indent, ml, false, 
+        toPretty(result, node.fields[i].val, indent, ml, false,
                  newIndent(currIndent, indent, ml))
       result.nl(ml)
       result.indent(currIndent) # indent the same as {
       result.add("}")
     else:
       result.add("{}")
-  of JString: 
+  of JString:
     if lstArr: result.indent(currIndent)
     result.add(escapeJson(node.str))
   of JInt:
@@ -864,7 +952,7 @@ proc pretty*(node: JsonNode, indent = 2): string =
 proc `$`*(node: JsonNode): string =
   ## Converts `node` to its JSON Representation on one line.
   result = ""
-  toPretty(result, node, 1, false)
+  toPretty(result, node, 0, false)
 
 iterator items*(node: JsonNode): JsonNode =
   ## Iterator for the items of `node`. `node` has to be a JArray.
@@ -872,17 +960,31 @@ iterator items*(node: JsonNode): JsonNode =
   for i in items(node.elems):
     yield i
 
+iterator mitems*(node: var JsonNode): var JsonNode =
+  ## Iterator for the items of `node`. `node` has to be a JArray. Items can be
+  ## modified.
+  assert node.kind == JArray
+  for i in mitems(node.elems):
+    yield i
+
 iterator pairs*(node: JsonNode): tuple[key: string, val: JsonNode] =
   ## Iterator for the child elements of `node`. `node` has to be a JObject.
   assert node.kind == JObject
   for key, val in items(node.fields):
     yield (key, val)
 
-proc eat(p: var JsonParser, tok: TTokKind) = 
+iterator mpairs*(node: var JsonNode): var tuple[key: string, val: JsonNode] =
+  ## Iterator for the child elements of `node`. `node` has to be a JObject.
+  ## Items can be modified
+  assert node.kind == JObject
+  for keyVal in mitems(node.fields):
+    yield keyVal
+
+proc eat(p: var JsonParser, tok: TTokKind) =
   if p.tok == tok: discard getTok(p)
   else: raiseParseErr(p, tokToStr[tok])
 
-proc parseJson(p: var JsonParser): JsonNode = 
+proc parseJson(p: var JsonParser): JsonNode =
   ## Parses JSON from a JSON Parser `p`.
   case p.tok
   of tkString:
@@ -899,17 +1001,17 @@ proc parseJson(p: var JsonParser): JsonNode =
   of tkTrue:
     result = newJBool(true)
     discard getTok(p)
-  of tkFalse: 
+  of tkFalse:
     result = newJBool(false)
     discard getTok(p)
-  of tkNull: 
+  of tkNull:
     result = newJNull()
     discard getTok(p)
-  of tkCurlyLe: 
+  of tkCurlyLe:
     result = newJObject()
     discard getTok(p)
-    while p.tok != tkCurlyRi: 
-      if p.tok != tkString: 
+    while p.tok != tkCurlyRi:
+      if p.tok != tkString:
         raiseParseErr(p, "string literal as key expected")
       var key = p.a
       discard getTok(p)
@@ -922,7 +1024,7 @@ proc parseJson(p: var JsonParser): JsonNode =
   of tkBracketLe:
     result = newJArray()
     discard getTok(p)
-    while p.tok != tkBracketRi: 
+    while p.tok != tkBracketRi:
       result.add(parseJson(p))
       if p.tok != tkComma: break
       discard getTok(p)
@@ -1042,28 +1144,31 @@ when false:
     of jsonObjectEnd: echo("}")
     of jsonArrayStart: echo("[")
     of jsonArrayEnd: echo("]")
-    
+
   close(x)
 
-# { "json": 5 } 
+# { "json": 5 }
 # To get that we shall use, obj["json"]
 
 when isMainModule:
   #var node = parse("{ \"test\": null }")
   #echo(node.existsKey("test56"))
+  
   var parsed = parseFile("tests/testdata/jsontest.json")
   var parsed2 = parseFile("tests/testdata/jsontest2.json")
-  echo(parsed)
-  echo()
-  echo(pretty(parsed, 2))
-  echo()
-  echo(parsed["keyÄÖöoßß"])
-  echo()
-  echo(pretty(parsed2))
-  try:
-    echo(parsed["key2"][12123])
-    raise newException(ValueError, "That line was expected to fail")
-  except IndexError: echo()
+
+  when not defined(testing):
+    echo(parsed)
+    echo()
+    echo(pretty(parsed, 2))
+    echo()
+    echo(parsed["keyÄÖöoßß"])
+    echo()
+    echo(pretty(parsed2))
+    try:
+      echo(parsed["key2"][12123])
+      raise newException(ValueError, "That line was expected to fail")
+    except IndexError: echo()
 
   let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd" }"""
   # nil passthrough
@@ -1087,11 +1192,51 @@ when isMainModule:
   except:
     assert(false, "EInvalidIndex thrown for valid index")
 
-  discard """
-  while true:
-    var json = stdin.readLine()
-    var node = parse(json)
-    echo(node)
-    echo()
-    echo()
-  """
+  assert(testJson{"b"}.str=="asd", "Couldn't fetch a singly nested key with {}") 
+  assert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil") 
+  assert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
+  assert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
+  assert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
+  assert(testJson{"a"}==parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found")
+  assert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil")
+ 
+  # Generator:
+  var j = %* [{"name": "John", "age": 30}, {"name": "Susan", "age": 31}]
+  assert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}] 
+
+  var j2 = %*
+    [
+      {
+        "name": "John",
+        "age": 30
+      },
+      {
+        "name": "Susan",
+        "age": 31
+      }
+    ]
+  assert j2 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
+
+  var name = "John"
+  let herAge = 30
+  const hisAge = 31
+
+  var j3 = %*
+    [ { "name": "John"
+      , "age": herAge
+      }
+    , { "name": "Susan"
+      , "age": hisAge
+      }
+    ]
+  assert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
+  
+  when not defined(testing):
+    discard """
+    while true:
+      var json = stdin.readLine()
+      var node = parse(json)
+      echo(node)
+      echo()
+      echo()
+    """
diff --git a/lib/pure/lexbase.nim b/lib/pure/lexbase.nim
index a3a3d7b5c..23a87d9f8 100644
--- a/lib/pure/lexbase.nim
+++ b/lib/pure/lexbase.nim
@@ -165,5 +165,5 @@ proc getCurrentLine(L: BaseLexer, marker: bool = true): string =
     inc(i)
   add(result, "\n")
   if marker:
-    add(result, repeatChar(getColNumber(L, L.bufpos)) & "^\n")
+    add(result, spaces(getColNumber(L, L.bufpos)) & "^\n")
 
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
index 9247f69c5..a2ea53472 100644
--- a/lib/pure/logging.nim
+++ b/lib/pure/logging.nim
@@ -1,16 +1,16 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf, Dominik Picheta
+#        (c) Copyright 2015 Andreas Rumpf, Dominik Picheta
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
 ## This module implements a simple logger. It has been designed to be as simple
-## as possible to avoid bloat, if this library does not fullfill your needs,
+## as possible to avoid bloat, if this library does not fulfill your needs,
 ## write your own.
-## 
+##
 ## Format strings support the following variables which must be prefixed with
 ## the dollar operator (``$``):
 ##
@@ -21,23 +21,26 @@
 ## $time         Current time
 ## $app          ``os.getAppFilename()``
 ## ============  =======================
-## 
+##
 ##
 ## The following example demonstrates logging to three different handlers
 ## simultaneously:
 ##
 ## .. code-block:: nim
-##     
+##
 ##    var L = newConsoleLogger()
 ##    var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
 ##    var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
-##    handlers.add(L)
-##    handlers.add(fL)
-##    handlers.add(rL)
+##    addHandler(L)
+##    addHandler(fL)
+##    addHandler(rL)
 ##    info("920410:52 accepted")
 ##    warn("4 8 15 16 23 4-- Error")
 ##    error("922044:16 SYSTEM FAILURE")
 ##    fatal("SYSTEM FAILURE SYSTEM FAILURE")
+##
+## **Warning:** The global list of handlers is a thread var, this means that
+## the handlers must be re-added in each thread.
 
 import strutils, os, times
 
@@ -61,20 +64,20 @@ const
 
 type
   Logger* = ref object of RootObj ## abstract logger; the base type of all loggers
-    levelThreshold*: Level    ## only messages of level >= levelThreshold 
+    levelThreshold*: Level    ## only messages of level >= levelThreshold
                               ## should be processed
     fmtStr: string ## = defaultFmtStr by default, see substituteLog for $date etc.
-    
+
   ConsoleLogger* = ref object of Logger ## logger that writes the messages to the
                                         ## console
-  
+
   FileLogger* = ref object of Logger ## logger that writes the messages to a file
     f: File
-  
-  RollingFileLogger* = ref object of FileLogger ## logger that writes the 
+
+  RollingFileLogger* = ref object of FileLogger ## logger that writes the
                                                 ## messages to a file and
                                                 ## performs log rotation
-    maxLines: int # maximum number of lines    
+    maxLines: int # maximum number of lines
     curLine : int
     baseName: string # initial filename
     baseMode: FileMode # initial file mode
@@ -83,22 +86,22 @@ type
 {.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger,
     PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].}
 
-proc substituteLog(frmt: string): string = 
+proc substituteLog(frmt: string): string =
   ## converts $date to the current date
   ## converts $time to the current time
   ## converts $app to getAppFilename()
-  ## converts 
+  ## converts
   result = newStringOfCap(frmt.len + 20)
   var i = 0
-  while i < frmt.len: 
-    if frmt[i] != '$': 
+  while i < frmt.len:
+    if frmt[i] != '$':
       result.add(frmt[i])
       inc(i)
     else:
       inc(i)
       var v = ""
       var app = getAppFilename()
-      while frmt[i] in IdentChars: 
+      while frmt[i] in IdentChars:
         v.add(toLower(frmt[i]))
         inc(i)
       case v
@@ -111,12 +114,12 @@ proc substituteLog(frmt: string): string =
 
 method log*(logger: Logger, level: Level,
             frmt: string, args: varargs[string, `$`]) {.
-            raises: [Exception], 
+            raises: [Exception],
             tags: [TimeEffect, WriteIOEffect, ReadIOEffect].} =
   ## Override this method in custom loggers. Default implementation does
   ## nothing.
   discard
-  
+
 method log*(logger: ConsoleLogger, level: Level,
             frmt: string, args: varargs[string, `$`]) =
   ## Logs to the console using ``logger`` only.
@@ -124,14 +127,14 @@ method log*(logger: ConsoleLogger, level: Level,
     writeln(stdout, LevelNames[level], " ", substituteLog(logger.fmtStr),
             frmt % args)
 
-method log*(logger: FileLogger, level: Level, 
+method log*(logger: FileLogger, level: Level,
             frmt: string, args: varargs[string, `$`]) =
   ## Logs to a file using ``logger`` only.
   if level >= logger.levelThreshold:
     writeln(logger.f, LevelNames[level], " ",
             substituteLog(logger.fmtStr), frmt % args)
 
-proc defaultFilename*(): string = 
+proc defaultFilename*(): string =
   ## Returns the default filename for a logger.
   var (path, name, ext) = splitFile(getAppFilename())
   result = changeFileExt(path / name, "log")
@@ -142,10 +145,10 @@ proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): Console
   result.fmtStr = fmtStr
   result.levelThreshold = levelThreshold
 
-proc newFileLogger*(filename = defaultFilename(), 
+proc newFileLogger*(filename = defaultFilename(),
                     mode: FileMode = fmAppend,
                     levelThreshold = lvlAll,
-                    fmtStr = defaultFmtStr): FileLogger = 
+                    fmtStr = defaultFmtStr): FileLogger =
   ## Creates a new file logger. This logger logs to a file.
   new(result)
   result.levelThreshold = levelThreshold
@@ -167,14 +170,14 @@ proc countFiles(filename: string): int =
     if kind == pcFile:
       let llfn = name & ext & ExtSep
       if path.extractFilename.startsWith(llfn):
-        let numS = path.extractFilename[llfn.len .. -1]
+        let numS = path.extractFilename[llfn.len .. ^1]
         try:
           let num = parseInt(numS)
           if num > result:
             result = num
         except ValueError: discard
 
-proc newRollingFileLogger*(filename = defaultFilename(), 
+proc newRollingFileLogger*(filename = defaultFilename(),
                            mode: FileMode = fmReadWrite,
                            levelThreshold = lvlAll,
                            fmtStr = defaultFmtStr,
@@ -183,15 +186,15 @@ proc newRollingFileLogger*(filename = defaultFilename(),
   ## a new log file will be started and the old will be renamed.
   new(result)
   result.levelThreshold = levelThreshold
-  result.fmtStr = defaultFmtStr
+  result.fmtStr = fmtStr
   result.maxLines = maxLines
   result.f = open(filename, mode)
   result.curLine = 0
   result.baseName = filename
   result.baseMode = mode
-  
+
   result.logFiles = countFiles(filename)
-  
+
   if mode == fmAppend:
     # We need to get a line count because we will be appending to the file.
     result.curLine = countLogLines(result)
@@ -203,7 +206,7 @@ proc rotate(logger: RollingFileLogger) =
     moveFile(dir / (name & ext & srcSuff),
              dir / (name & ext & ExtSep & $(i+1)))
 
-method log*(logger: RollingFileLogger, level: Level, 
+method log*(logger: RollingFileLogger, level: Level,
             frmt: string, args: varargs[string, `$`]) =
   ## Logs to a file using rolling ``logger`` only.
   if level >= logger.levelThreshold:
@@ -213,18 +216,17 @@ method log*(logger: RollingFileLogger, level: Level,
       logger.logFiles.inc
       logger.curLine = 0
       logger.f = open(logger.baseName, logger.baseMode)
-    
-    writeln(logger.f, LevelNames[level], " ", frmt % args)
+
+    writeln(logger.f, LevelNames[level], " ",substituteLog(logger.fmtStr), frmt % args)
     logger.curLine.inc
 
 # --------
 
-var
-  level* = lvlAll  ## global log filter
-  handlers*: seq[Logger] = @[] ## handlers with their own log levels
+var level {.threadvar.}: Level   ## global log filter
+var handlers {.threadvar.}: seq[Logger] ## handlers with their own log levels
 
 proc logLoop(level: Level, frmt: string, args: varargs[string, `$`]) =
-  for logger in items(handlers): 
+  for logger in items(handlers):
     if level >= logger.levelThreshold:
       log(logger, level, frmt, args)
 
@@ -233,7 +235,7 @@ template log*(level: Level, frmt: string, args: varargs[string, `$`]) =
   bind logLoop
   bind `%`
   bind logging.level
-  
+
   if level >= logging.level:
     logLoop(level, frmt, args)
 
@@ -241,33 +243,49 @@ template debug*(frmt: string, args: varargs[string, `$`]) =
   ## Logs a debug message to all registered handlers.
   log(lvlDebug, frmt, args)
 
-template info*(frmt: string, args: varargs[string, `$`]) = 
+template info*(frmt: string, args: varargs[string, `$`]) =
   ## Logs an info message to all registered handlers.
   log(lvlInfo, frmt, args)
 
-template warn*(frmt: string, args: varargs[string, `$`]) = 
+template warn*(frmt: string, args: varargs[string, `$`]) =
   ## Logs a warning message to all registered handlers.
   log(lvlWarn, frmt, args)
 
-template error*(frmt: string, args: varargs[string, `$`]) = 
+template error*(frmt: string, args: varargs[string, `$`]) =
   ## Logs an error message to all registered handlers.
   log(lvlError, frmt, args)
-  
-template fatal*(frmt: string, args: varargs[string, `$`]) =  
+
+template fatal*(frmt: string, args: varargs[string, `$`]) =
   ## Logs a fatal error message to all registered handlers.
   log(lvlFatal, frmt, args)
 
+proc addHandler*(handler: Logger) =
+  ## Adds ``handler`` to the list of handlers.
+  if handlers.isNil: handlers = @[]
+  handlers.add(handler)
+
+proc getHandlers*(): seq[Logger] =
+  ## Returns a list of all the registered handlers.
+  return handlers
+
+proc setLogFilter*(lvl: Level) =
+  ## Sets the global log filter.
+  level = lvl
+
+proc getLogFilter*(): Level =
+  ## Gets the global log filter.
+  return level
 
 # --------------
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   var L = newConsoleLogger()
   var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
   var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
-  handlers.add(L)
-  handlers.add(fL)
-  handlers.add(rL)
+  addHandler(L)
+  addHandler(fL)
+  addHandler(rL)
   for i in 0 .. 25:
     info("hello" & $i, [])
-  
+
 
diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim
index 02abda722..bf9e33296 100644
--- a/lib/pure/marshal.nim
+++ b/lib/pure/marshal.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -244,7 +244,7 @@ proc to*[T](data: string): T =
   var tab = initTable[BiggestInt, pointer]()
   loadAny(newStringStream(data), toAny(result), tab)
   
-when isMainModule:
+when not defined(testing) and isMainModule:
   template testit(x: expr) = echo($$to[type(x)]($$x))
 
   var x: array[0..4, array[0..4, string]] = [
diff --git a/lib/pure/matchers.nim b/lib/pure/matchers.nim
index 46fc9985c..d55963c15 100644
--- a/lib/pure/matchers.nim
+++ b/lib/pure/matchers.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -42,7 +42,7 @@ proc validEmailAddress*(s: string): bool {.noSideEffect,
   case toLower(x)
   of "com", "org", "net", "gov", "mil", "biz", "info", "mobi", "name",
      "aero", "jobs", "museum": return true
-  return false
+  else: return false
 
 proc parseInt*(s: string, value: var int, validRange: Slice[int]) {.
   noSideEffect, rtl, extern: "nmatchParseInt".} =
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index 987c35d1c..daa108460 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -93,9 +93,9 @@ proc nextPowerOfTwo*(x: int): int {.noSideEffect.} =
   result = x - 1 
   when defined(cpu64):
     result = result or (result shr 32)
-  when sizeof(int) > 16:
+  when sizeof(int) > 2:
     result = result or (result shr 16)
-  when sizeof(int) > 8:
+  when sizeof(int) > 1:
     result = result or (result shr 8)
   result = result or (result shr 4)
   result = result or (result shr 2)
@@ -129,29 +129,30 @@ proc variance*(x: openArray[float]): float {.noSideEffect.} =
     result = result + diff*diff
   result = result / toFloat(len(x))
 
-proc random*(max: int): int {.gcsafe.}
+proc random*(max: int): int {.benign.}
   ## 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 random*(max: float): float {.gcsafe.}
+proc random*(max: float): float {.benign.}
   ## returns a random number in the range 0..<max. 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. This has a 16-bit resolution on windows
   ## and a 48-bit resolution on other platforms.
 
-proc randomize*() {.gcsafe.}
+proc randomize*() {.benign.}
   ## initializes the random number generator with a "random"
   ## number, i.e. a tickcount. Note: Does nothing for the JavaScript target,
   ## as JavaScript does not support this.
   
-proc randomize*(seed: int) {.gcsafe.}
+proc randomize*(seed: int) {.benign.}
   ## initializes the random number generator with a specific seed.
   ## Note: Does nothing for the JavaScript target,
   ## as JavaScript does not support this.
 
+{.push noSideEffect.}
 when not defined(JS):
   proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".}
     ## computes the square root of `x`.
@@ -273,6 +274,8 @@ else:
     var y = exp(2.0*x)
     return (y-1.0)/(y+1.0)
 
+{.pop.}
+
 proc `mod`*(x, y: float): float =
   result = if y == 0.0: x else: x - y * (x/y).floor
 
@@ -280,7 +283,7 @@ proc random*[T](x: Slice[T]): T =
   ## For a slice `a .. b` returns a value in the range `a .. b-1`.
   result = random(x.b - x.a) + x.a
 
-proc random[T](a: openArray[T]): T =
+proc random*[T](a: openArray[T]): T =
   ## returns a random element from the openarray `a`.
   result = a[random(a.low..a.len)]
 
@@ -329,6 +332,31 @@ proc standardDeviation*(s: RunningStat): float =
 {.pop.}
 {.pop.}
 
+proc `^`*[T](x, y: T): T =
+  ## Computes ``x`` to the power ``y`. ``x`` must be non-negative, use
+  ## `pow <#pow,float,float>` for negative exponents.
+  assert y >= 0
+  var (x, y) = (x, y)
+  result = 1
+
+  while y != 0:
+    if (y and 1) != 0:
+      result *= x
+    y = y shr 1
+    x *= x
+
+proc gcd*[T](x, y: T): T =
+  ## Computes the greatest common divisor of ``x`` and ``y``.
+  var (x,y) = (x,y)
+  while y != 0:
+    x = x mod y
+    swap x, y
+  abs x
+
+proc lcm*[T](x, y: T): T =
+  ## Computes the least common multiple of ``x`` and ``y``.
+  x div gcd(x, y) * y
+
 when isMainModule and not defined(JS):
   proc gettime(dummy: ptr cint): cint {.importc: "time", header: "<time.h>".}
 
@@ -344,4 +372,10 @@ when isMainModule and not defined(JS):
   randomize(seed)
   for i in 0..SIZE-1:
     assert buf[i] == random(high(int)), "non deterministic random seeding"
-  echo "random values equal after reseeding"
+
+  when not defined(testing):
+    echo "random values equal after reseeding"
+
+  # Check for no side effect annotation
+  proc mySqrt(num: float): float {.noSideEffect.} =
+    return sqrt(num)
diff --git a/lib/pure/md5.nim b/lib/pure/md5.nim
index 3b5453957..5ee301b15 100644
--- a/lib/pure/md5.nim
+++ b/lib/pure/md5.nim
@@ -9,18 +9,20 @@
 
 ## Module for computing MD5 checksums.
 
-type 
-  MD5State = array[0..3, int32]
-  MD5Block = array[0..15, int32]
-  MD5CBits = array[0..7, int8]
-  MD5Digest* = array[0..15, int8]
-  MD5Buffer = array[0..63, int8]
-  MD5Context* {.final.} = object 
+import unsigned
+
+type
+  MD5State = array[0..3, uint32]
+  MD5Block = array[0..15, uint32]
+  MD5CBits = array[0..7, uint8]
+  MD5Digest* = array[0..15, uint8]
+  MD5Buffer = array[0..63, uint8]
+  MD5Context* {.final.} = object
     state: MD5State
-    count: array[0..1, int32]
+    count: array[0..1, uint32]
     buffer: MD5Buffer
 
-const 
+const
   padding: cstring = "\x80\0\0\0" &
                      "\0\0\0\0\0\0\0\0" &
                      "\0\0\0\0\0\0\0\0" &
@@ -31,60 +33,60 @@ const
                      "\0\0\0\0\0\0\0\0" &
                      "\0\0\0\0"
 
-proc F(x, y, z: int32): int32 {.inline.} = 
+proc F(x, y, z: uint32): uint32 {.inline.} =
   result = (x and y) or ((not x) and z)
 
-proc G(x, y, z: int32): int32 {.inline.} = 
+proc G(x, y, z: uint32): uint32 {.inline.} =
   result = (x and z) or (y and (not z))
 
-proc H(x, y, z: int32): int32 {.inline.} = 
+proc H(x, y, z: uint32): uint32 {.inline.} =
   result = x xor y xor z
 
-proc I(x, y, z: int32): int32 {.inline.} = 
+proc I(x, y, z: uint32): uint32 {.inline.} =
   result = y xor (x or (not z))
 
-proc rot(x: var int32, n: int8) {.inline.} = 
-  x = toU32(x shl ze(n)) or (x shr toU32(32 -% ze(n)))
+proc rot(x: var uint32, n: uint8) {.inline.} =
+  x = (x shl n) or (x shr (32'u32 - n))
 
-proc FF(a: var int32, b, c, d, x: int32, s: int8, ac: int32) = 
-  a = a +% F(b, c, d) +% x +% ac
+proc FF(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
+  a = a + F(b, c, d) + x + ac
   rot(a, s)
-  a = a +% b
+  a = a + b
 
-proc GG(a: var int32, b, c, d, x: int32, s: int8, ac: int32) = 
-  a = a +% G(b, c, d) +% x +% ac
+proc GG(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
+  a = a + G(b, c, d) + x + ac
   rot(a, s)
-  a = a +% b
+  a = a + b
 
-proc HH(a: var int32, b, c, d, x: int32, s: int8, ac: int32) = 
-  a = a +% H(b, c, d) +% x +% ac
+proc HH(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
+  a = a + H(b, c, d) + x + ac
   rot(a, s)
-  a = a +% b
+  a = a + b
 
-proc II(a: var int32, b, c, d, x: int32, s: int8, ac: int32) = 
-  a = a +% I(b, c, d) +% x +% ac
+proc II(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
+  a = a + I(b, c, d) + x + ac
   rot(a, s)
-  a = a +% b
+  a = a + b
 
-proc encode(dest: var MD5Block, src: cstring) = 
+proc encode(dest: var MD5Block, src: cstring) =
   var j = 0
   for i in 0..high(dest):
-    dest[i] = toU32(ord(src[j]) or 
-                ord(src[j+1]) shl 8 or
-                ord(src[j+2]) shl 16 or
-                ord(src[j+3]) shl 24)
+    dest[i] = uint32(ord(src[j])) or
+              uint32(ord(src[j+1])) shl 8 or
+              uint32(ord(src[j+2])) shl 16 or
+              uint32(ord(src[j+3])) shl 24
     inc(j, 4)
 
-proc decode(dest: var openArray[int8], src: openArray[int32]) = 
+proc decode(dest: var openArray[uint8], src: openArray[uint32]) =
   var i = 0
   for j in 0..high(src):
-    dest[i] = toU8(src[j] and 0xff'i32)
-    dest[i+1] = toU8(src[j] shr 8'i32 and 0xff'i32)
-    dest[i+2] = toU8(src[j] shr 16'i32 and 0xff'i32)
-    dest[i+3] = toU8(src[j] shr 24'i32 and 0xff'i32)
+    dest[i] = src[j] and 0xff'u32
+    dest[i+1] = src[j] shr 8 and 0xff'u32
+    dest[i+2] = src[j] shr 16 and 0xff'u32
+    dest[i+3] = src[j] shr 24 and 0xff'u32
     inc(i, 4)
 
-proc transform(buffer: pointer, state: var MD5State) = 
+proc transform(buffer: pointer, state: var MD5State) =
   var
     myBlock: MD5Block
   encode(myBlock, cast[cstring](buffer))
@@ -92,111 +94,111 @@ proc transform(buffer: pointer, state: var MD5State) =
   var b = state[1]
   var c = state[2]
   var d = state[3]
-  FF(a, b, c, d, myBlock[0], 7'i8, 0xD76AA478'i32)
-  FF(d, a, b, c, myBlock[1], 12'i8, 0xE8C7B756'i32)
-  FF(c, d, a, b, myBlock[2], 17'i8, 0x242070DB'i32)
-  FF(b, c, d, a, myBlock[3], 22'i8, 0xC1BDCEEE'i32)
-  FF(a, b, c, d, myBlock[4], 7'i8, 0xF57C0FAF'i32)
-  FF(d, a, b, c, myBlock[5], 12'i8, 0x4787C62A'i32)
-  FF(c, d, a, b, myBlock[6], 17'i8, 0xA8304613'i32)
-  FF(b, c, d, a, myBlock[7], 22'i8, 0xFD469501'i32)
-  FF(a, b, c, d, myBlock[8], 7'i8, 0x698098D8'i32)
-  FF(d, a, b, c, myBlock[9], 12'i8, 0x8B44F7AF'i32)
-  FF(c, d, a, b, myBlock[10], 17'i8, 0xFFFF5BB1'i32)
-  FF(b, c, d, a, myBlock[11], 22'i8, 0x895CD7BE'i32)
-  FF(a, b, c, d, myBlock[12], 7'i8, 0x6B901122'i32)
-  FF(d, a, b, c, myBlock[13], 12'i8, 0xFD987193'i32)
-  FF(c, d, a, b, myBlock[14], 17'i8, 0xA679438E'i32)
-  FF(b, c, d, a, myBlock[15], 22'i8, 0x49B40821'i32)
-  GG(a, b, c, d, myBlock[1], 5'i8, 0xF61E2562'i32)
-  GG(d, a, b, c, myBlock[6], 9'i8, 0xC040B340'i32)
-  GG(c, d, a, b, myBlock[11], 14'i8, 0x265E5A51'i32)
-  GG(b, c, d, a, myBlock[0], 20'i8, 0xE9B6C7AA'i32)
-  GG(a, b, c, d, myBlock[5], 5'i8, 0xD62F105D'i32)
-  GG(d, a, b, c, myBlock[10], 9'i8, 0x02441453'i32)
-  GG(c, d, a, b, myBlock[15], 14'i8, 0xD8A1E681'i32)
-  GG(b, c, d, a, myBlock[4], 20'i8, 0xE7D3FBC8'i32)
-  GG(a, b, c, d, myBlock[9], 5'i8, 0x21E1CDE6'i32)
-  GG(d, a, b, c, myBlock[14], 9'i8, 0xC33707D6'i32)
-  GG(c, d, a, b, myBlock[3], 14'i8, 0xF4D50D87'i32)
-  GG(b, c, d, a, myBlock[8], 20'i8, 0x455A14ED'i32)
-  GG(a, b, c, d, myBlock[13], 5'i8, 0xA9E3E905'i32)
-  GG(d, a, b, c, myBlock[2], 9'i8, 0xFCEFA3F8'i32)
-  GG(c, d, a, b, myBlock[7], 14'i8, 0x676F02D9'i32)
-  GG(b, c, d, a, myBlock[12], 20'i8, 0x8D2A4C8A'i32)
-  HH(a, b, c, d, myBlock[5], 4'i8, 0xFFFA3942'i32)
-  HH(d, a, b, c, myBlock[8], 11'i8, 0x8771F681'i32)
-  HH(c, d, a, b, myBlock[11], 16'i8, 0x6D9D6122'i32)
-  HH(b, c, d, a, myBlock[14], 23'i8, 0xFDE5380C'i32)
-  HH(a, b, c, d, myBlock[1], 4'i8, 0xA4BEEA44'i32)
-  HH(d, a, b, c, myBlock[4], 11'i8, 0x4BDECFA9'i32)
-  HH(c, d, a, b, myBlock[7], 16'i8, 0xF6BB4B60'i32)
-  HH(b, c, d, a, myBlock[10], 23'i8, 0xBEBFBC70'i32)
-  HH(a, b, c, d, myBlock[13], 4'i8, 0x289B7EC6'i32)
-  HH(d, a, b, c, myBlock[0], 11'i8, 0xEAA127FA'i32)
-  HH(c, d, a, b, myBlock[3], 16'i8, 0xD4EF3085'i32)
-  HH(b, c, d, a, myBlock[6], 23'i8, 0x04881D05'i32)
-  HH(a, b, c, d, myBlock[9], 4'i8, 0xD9D4D039'i32)
-  HH(d, a, b, c, myBlock[12], 11'i8, 0xE6DB99E5'i32)
-  HH(c, d, a, b, myBlock[15], 16'i8, 0x1FA27CF8'i32)
-  HH(b, c, d, a, myBlock[2], 23'i8, 0xC4AC5665'i32)
-  II(a, b, c, d, myBlock[0], 6'i8, 0xF4292244'i32)
-  II(d, a, b, c, myBlock[7], 10'i8, 0x432AFF97'i32)
-  II(c, d, a, b, myBlock[14], 15'i8, 0xAB9423A7'i32)
-  II(b, c, d, a, myBlock[5], 21'i8, 0xFC93A039'i32)
-  II(a, b, c, d, myBlock[12], 6'i8, 0x655B59C3'i32)
-  II(d, a, b, c, myBlock[3], 10'i8, 0x8F0CCC92'i32)
-  II(c, d, a, b, myBlock[10], 15'i8, 0xFFEFF47D'i32)
-  II(b, c, d, a, myBlock[1], 21'i8, 0x85845DD1'i32)
-  II(a, b, c, d, myBlock[8], 6'i8, 0x6FA87E4F'i32)
-  II(d, a, b, c, myBlock[15], 10'i8, 0xFE2CE6E0'i32)
-  II(c, d, a, b, myBlock[6], 15'i8, 0xA3014314'i32)
-  II(b, c, d, a, myBlock[13], 21'i8, 0x4E0811A1'i32)
-  II(a, b, c, d, myBlock[4], 6'i8, 0xF7537E82'i32)
-  II(d, a, b, c, myBlock[11], 10'i8, 0xBD3AF235'i32)
-  II(c, d, a, b, myBlock[2], 15'i8, 0x2AD7D2BB'i32)
-  II(b, c, d, a, myBlock[9], 21'i8, 0xEB86D391'i32)
-  state[0] = state[0] +% a
-  state[1] = state[1] +% b
-  state[2] = state[2] +% c
-  state[3] = state[3] +% d
-  
-proc md5Init*(c: var MD5Context) = 
-  ## initializes a MD5Context  
-  c.state[0] = 0x67452301'i32
-  c.state[1] = 0xEFCDAB89'i32
-  c.state[2] = 0x98BADCFE'i32
-  c.state[3] = 0x10325476'i32
-  c.count[0] = 0'i32
-  c.count[1] = 0'i32
+  FF(a, b, c, d, myBlock[0], 7'u8, 0xD76AA478'u32)
+  FF(d, a, b, c, myBlock[1], 12'u8, 0xE8C7B756'u32)
+  FF(c, d, a, b, myBlock[2], 17'u8, 0x242070DB'u32)
+  FF(b, c, d, a, myBlock[3], 22'u8, 0xC1BDCEEE'u32)
+  FF(a, b, c, d, myBlock[4], 7'u8, 0xF57C0FAF'u32)
+  FF(d, a, b, c, myBlock[5], 12'u8, 0x4787C62A'u32)
+  FF(c, d, a, b, myBlock[6], 17'u8, 0xA8304613'u32)
+  FF(b, c, d, a, myBlock[7], 22'u8, 0xFD469501'u32)
+  FF(a, b, c, d, myBlock[8], 7'u8, 0x698098D8'u32)
+  FF(d, a, b, c, myBlock[9], 12'u8, 0x8B44F7AF'u32)
+  FF(c, d, a, b, myBlock[10], 17'u8, 0xFFFF5BB1'u32)
+  FF(b, c, d, a, myBlock[11], 22'u8, 0x895CD7BE'u32)
+  FF(a, b, c, d, myBlock[12], 7'u8, 0x6B901122'u32)
+  FF(d, a, b, c, myBlock[13], 12'u8, 0xFD987193'u32)
+  FF(c, d, a, b, myBlock[14], 17'u8, 0xA679438E'u32)
+  FF(b, c, d, a, myBlock[15], 22'u8, 0x49B40821'u32)
+  GG(a, b, c, d, myBlock[1], 5'u8, 0xF61E2562'u32)
+  GG(d, a, b, c, myBlock[6], 9'u8, 0xC040B340'u32)
+  GG(c, d, a, b, myBlock[11], 14'u8, 0x265E5A51'u32)
+  GG(b, c, d, a, myBlock[0], 20'u8, 0xE9B6C7AA'u32)
+  GG(a, b, c, d, myBlock[5], 5'u8, 0xD62F105D'u32)
+  GG(d, a, b, c, myBlock[10], 9'u8, 0x02441453'u32)
+  GG(c, d, a, b, myBlock[15], 14'u8, 0xD8A1E681'u32)
+  GG(b, c, d, a, myBlock[4], 20'u8, 0xE7D3FBC8'u32)
+  GG(a, b, c, d, myBlock[9], 5'u8, 0x21E1CDE6'u32)
+  GG(d, a, b, c, myBlock[14], 9'u8, 0xC33707D6'u32)
+  GG(c, d, a, b, myBlock[3], 14'u8, 0xF4D50D87'u32)
+  GG(b, c, d, a, myBlock[8], 20'u8, 0x455A14ED'u32)
+  GG(a, b, c, d, myBlock[13], 5'u8, 0xA9E3E905'u32)
+  GG(d, a, b, c, myBlock[2], 9'u8, 0xFCEFA3F8'u32)
+  GG(c, d, a, b, myBlock[7], 14'u8, 0x676F02D9'u32)
+  GG(b, c, d, a, myBlock[12], 20'u8, 0x8D2A4C8A'u32)
+  HH(a, b, c, d, myBlock[5], 4'u8, 0xFFFA3942'u32)
+  HH(d, a, b, c, myBlock[8], 11'u8, 0x8771F681'u32)
+  HH(c, d, a, b, myBlock[11], 16'u8, 0x6D9D6122'u32)
+  HH(b, c, d, a, myBlock[14], 23'u8, 0xFDE5380C'u32)
+  HH(a, b, c, d, myBlock[1], 4'u8, 0xA4BEEA44'u32)
+  HH(d, a, b, c, myBlock[4], 11'u8, 0x4BDECFA9'u32)
+  HH(c, d, a, b, myBlock[7], 16'u8, 0xF6BB4B60'u32)
+  HH(b, c, d, a, myBlock[10], 23'u8, 0xBEBFBC70'u32)
+  HH(a, b, c, d, myBlock[13], 4'u8, 0x289B7EC6'u32)
+  HH(d, a, b, c, myBlock[0], 11'u8, 0xEAA127FA'u32)
+  HH(c, d, a, b, myBlock[3], 16'u8, 0xD4EF3085'u32)
+  HH(b, c, d, a, myBlock[6], 23'u8, 0x04881D05'u32)
+  HH(a, b, c, d, myBlock[9], 4'u8, 0xD9D4D039'u32)
+  HH(d, a, b, c, myBlock[12], 11'u8, 0xE6DB99E5'u32)
+  HH(c, d, a, b, myBlock[15], 16'u8, 0x1FA27CF8'u32)
+  HH(b, c, d, a, myBlock[2], 23'u8, 0xC4AC5665'u32)
+  II(a, b, c, d, myBlock[0], 6'u8, 0xF4292244'u32)
+  II(d, a, b, c, myBlock[7], 10'u8, 0x432AFF97'u32)
+  II(c, d, a, b, myBlock[14], 15'u8, 0xAB9423A7'u32)
+  II(b, c, d, a, myBlock[5], 21'u8, 0xFC93A039'u32)
+  II(a, b, c, d, myBlock[12], 6'u8, 0x655B59C3'u32)
+  II(d, a, b, c, myBlock[3], 10'u8, 0x8F0CCC92'u32)
+  II(c, d, a, b, myBlock[10], 15'u8, 0xFFEFF47D'u32)
+  II(b, c, d, a, myBlock[1], 21'u8, 0x85845DD1'u32)
+  II(a, b, c, d, myBlock[8], 6'u8, 0x6FA87E4F'u32)
+  II(d, a, b, c, myBlock[15], 10'u8, 0xFE2CE6E0'u32)
+  II(c, d, a, b, myBlock[6], 15'u8, 0xA3014314'u32)
+  II(b, c, d, a, myBlock[13], 21'u8, 0x4E0811A1'u32)
+  II(a, b, c, d, myBlock[4], 6'u8, 0xF7537E82'u32)
+  II(d, a, b, c, myBlock[11], 10'u8, 0xBD3AF235'u32)
+  II(c, d, a, b, myBlock[2], 15'u8, 0x2AD7D2BB'u32)
+  II(b, c, d, a, myBlock[9], 21'u8, 0xEB86D391'u32)
+  state[0] = state[0] + a
+  state[1] = state[1] + b
+  state[2] = state[2] + c
+  state[3] = state[3] + d
+
+proc md5Init*(c: var MD5Context) =
+  ## initializes a MD5Context
+  c.state[0] = 0x67452301'u32
+  c.state[1] = 0xEFCDAB89'u32
+  c.state[2] = 0x98BADCFE'u32
+  c.state[3] = 0x10325476'u32
+  c.count[0] = 0'u32
+  c.count[1] = 0'u32
   zeroMem(addr(c.buffer), sizeof(MD5buffer))
 
-proc md5Update*(c: var MD5Context, input: cstring, len: int) = 
+proc md5Update*(c: var MD5Context, input: cstring, len: int) =
   ## updates the MD5Context with the `input` data of length `len`
   var input = input
-  var Index = (c.count[0] shr 3) and 0x3F
-  c.count[0] = c.count[0] +% toU32(len shl 3)
-  if c.count[0] < (len shl 3): c.count[1] = c.count[1] +% 1'i32
-  c.count[1] = c.count[1] +% toU32(len shr 29)
+  var Index = int((c.count[0] shr 3) and 0x3F)
+  c.count[0] = c.count[0] + (uint32(len) shl 3)
+  if c.count[0] < (uint32(len) shl 3): c.count[1] = c.count[1] + 1'u32
+  c.count[1] = c.count[1] + (uint32(len) shr 29)
   var PartLen = 64 - Index
-  if len >= PartLen: 
+  if len >= PartLen:
     copyMem(addr(c.buffer[Index]), input, PartLen)
     transform(addr(c.buffer), c.state)
     var i = PartLen
-    while i + 63 < len: 
+    while i + 63 < len:
       transform(addr(input[i]), c.state)
       inc(i, 64)
     copyMem(addr(c.buffer[0]), addr(input[i]), len-i)
   else:
     copyMem(addr(c.buffer[Index]), addr(input[0]), len)
 
-proc md5Final*(c: var MD5Context, digest: var MD5Digest) = 
+proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
   ## finishes the MD5Context and stores the result in `digest`
   var
     Bits: MD5CBits
     PadLen: int
   decode(Bits, c.count)
-  var Index = (c.count[0] shr 3) and 0x3F
+  var Index = int((c.count[0] shr 3) and 0x3F)
   if Index < 56: PadLen = 56 - Index
   else: PadLen = 120 - Index
   md5Update(c, padding, PadLen)
@@ -204,34 +206,34 @@ proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
   decode(digest, c.state)
   zeroMem(addr(c), sizeof(MD5Context))
 
-proc toMD5*(s: string): MD5Digest = 
+proc toMD5*(s: string): MD5Digest =
   ## computes the MD5Digest value for a string `s`
   var c: MD5Context
   md5Init(c)
   md5Update(c, cstring(s), len(s))
   md5Final(c, result)
-  
-proc `$`*(D: MD5Digest): string = 
+
+proc `$`*(d: MD5Digest): string =
   ## converts a MD5Digest value into its string representation
   const digits = "0123456789abcdef"
   result = ""
-  for i in 0..15: 
-    add(result, digits[(D[i] shr 4) and 0xF])
-    add(result, digits[D[i] and 0xF])
+  for i in 0..15:
+    add(result, digits[(d[i] shr 4) and 0xF])
+    add(result, digits[d[i] and 0xF])
 
-proc getMD5*(s: string): string =  
+proc getMD5*(s: string): string =
   ## computes an MD5 value of `s` and returns its string representation
-  var 
+  var
     c: MD5Context
     d: MD5Digest
   md5Init(c)
   md5Update(c, cstring(s), len(s))
   md5Final(c, d)
   result = $d
-  
-proc `==`*(D1, D2: MD5Digest): bool =  
+
+proc `==`*(D1, D2: MD5Digest): bool =
   ## checks if two MD5Digest values are identical
-  for i in 0..15: 
+  for i in 0..15:
     if D1[i] != D2[i]: return false
   return true
 
@@ -241,5 +243,3 @@ when isMainModule:
   assert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") ==
     "7e716d0e702df0505fc72e2b89467910")
   assert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e")
-
-
diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim
index 24dbfb6d3..d49dfae9f 100644
--- a/lib/pure/memfiles.nim
+++ b/lib/pure/memfiles.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Nim Contributors
+#        (c) Copyright 2015 Nim Contributors
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
diff --git a/lib/pure/mersenne.nim b/lib/pure/mersenne.nim
index a6a781cb8..74112e304 100644
--- a/lib/pure/mersenne.nim
+++ b/lib/pure/mersenne.nim
@@ -32,7 +32,7 @@ proc getNum*(m: var MersenneTwister): int =
   return int(y)
 
 # Test
-when isMainModule:
+when not defined(testing) and isMainModule:
   var mt = newMersenneTwister(2525)
 
   for i in 0..99:
diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim
index a52ba4ebe..642419e64 100644
--- a/lib/pure/mimetypes.nim
+++ b/lib/pure/mimetypes.nim
@@ -518,5 +518,5 @@ proc register*(mimedb: var MimeDB, ext: string, mimetype: string) =
 
 when isMainModule:
   var m = newMimetypes()
-  echo m.getMimetype("mp4")
-  echo m.getExt("text/html")
+  assert m.getMimetype("mp4") == "video/mp4"
+  assert m.getExt("text/html") == "html"
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index 8afc6c5c5..ffbc6e320 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Dominik Picheta
+#        (c) Copyright 2015 Dominik Picheta
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -44,23 +44,24 @@ const
 
 type
   SocketImpl* = object ## socket type
-    fd*: SocketHandle
-    case isBuffered*: bool # determines whether this socket is buffered.
+    fd: SocketHandle
+    case isBuffered: bool # determines whether this socket is buffered.
     of true:
-      buffer*: array[0..BufferSize, char]
-      currPos*: int # current index in buffer
-      bufLen*: int # current length of buffer
+      buffer: array[0..BufferSize, char]
+      currPos: int # current index in buffer
+      bufLen: int # current length of buffer
     of false: nil
     when defined(ssl):
-      case isSsl*: bool
+      case isSsl: bool
       of true:
-        sslHandle*: SSLPtr
-        sslContext*: SSLContext
-        sslNoHandshake*: bool # True if needs handshake.
-        sslHasPeekChar*: bool
-        sslPeekChar*: char
+        sslHandle: SSLPtr
+        sslContext: SSLContext
+        sslNoHandshake: bool # True if needs handshake.
+        sslHasPeekChar: bool
+        sslPeekChar: char
       of false: nil
-  
+    lastError: OSErrorCode ## stores the last error on this socket
+
   Socket* = ref SocketImpl
 
   SOBool* = enum ## Boolean socket options.
@@ -80,6 +81,23 @@ type
     TReadLineResult: ReadLineResult, TSOBool: SOBool, PSocket: Socket,
     TSocketImpl: SocketImpl].}
 
+type
+  IpAddressFamily* {.pure.} = enum ## Describes the type of an IP address
+    IPv6, ## IPv6 address
+    IPv4  ## IPv4 address
+
+  TIpAddress* = object ## stores an arbitrary IP address    
+    case family*: IpAddressFamily ## the type of the IP address (IPv4 or IPv6)
+    of IpAddressFamily.IPv6:
+      address_v6*: array[0..15, uint8] ## Contains the IP address in bytes in
+                                       ## case of IPv6
+    of IpAddressFamily.IPv4:
+      address_v4*: array[0..3, uint8] ## Contains the IP address in bytes in
+                                      ## case of IPv4
+
+proc isIpAddress*(address_str: string): bool {.tags: [].}
+proc parseIpAddress*(address_str: string): TIpAddress
+
 proc isDisconnectionError*(flags: set[SocketFlag],
     lastError: OSErrorCode): bool =
   ## Determines whether ``lastError`` is a disconnection error. Only does this
@@ -100,7 +118,8 @@ proc toOSFlags*(socketFlags: set[SocketFlag]): cint =
       result = result or MSG_PEEK
     of SocketFlag.SafeDisconn: continue
 
-proc createSocket(fd: SocketHandle, isBuff: bool): Socket =
+proc newSocket(fd: SocketHandle, isBuff: bool): Socket =
+  ## Creates a new socket as specified by the params.
   assert fd != osInvalidSocket
   new(result)
   result.fd = fd
@@ -115,17 +134,17 @@ proc newSocket*(domain, typ, protocol: cint, buffered = true): Socket =
   let fd = newRawSocket(domain, typ, protocol)
   if fd == osInvalidSocket:
     raiseOSError(osLastError())
-  result = createSocket(fd, buffered)
+  result = newSocket(fd, buffered)
 
 proc newSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
-             protocol: Protocol = IPPROTO_TCP, buffered = true): Socket =
+                protocol: Protocol = IPPROTO_TCP, buffered = true): Socket =
   ## Creates a new socket.
   ##
   ## If an error occurs EOS will be raised.
   let fd = newRawSocket(domain, typ, protocol)
   if fd == osInvalidSocket:
     raiseOSError(osLastError())
-  result = createSocket(fd, buffered)
+  result = newSocket(fd, buffered)
 
 when defined(ssl):
   CRYPTO_malloc_init()
@@ -230,6 +249,15 @@ when defined(ssl):
     if SSLSetFd(socket.sslHandle, socket.fd) != 1:
       raiseSSLError()
 
+proc getSocketError*(socket: Socket): OSErrorCode =
+  ## Checks ``osLastError`` for a valid error. If it has been reset it uses
+  ## the last error stored in the socket object.
+  result = osLastError()
+  if result == 0.OSErrorCode:
+    result = socket.lastError
+  if result == 0.OSErrorCode:
+    raise newException(OSError, "No valid socket error code available")
+
 proc socketError*(socket: Socket, err: int = -1, async = false,
                   lastError = (-1).OSErrorCode) =
   ## Raises an OSError based on the error code returned by ``SSLGetError``
@@ -256,12 +284,26 @@ proc socketError*(socket: Socket, err: int = -1, async = false,
           else: raiseSSLError("Not enough data on socket.")
         of SSL_ERROR_WANT_X509_LOOKUP:
           raiseSSLError("Function for x509 lookup has been called.")
-        of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
+        of SSL_ERROR_SYSCALL:
+          var errStr = "IO error has occurred "
+          let sslErr = ErrPeekLastError()
+          if sslErr == 0 and err == 0:
+            errStr.add "because an EOF was observed that violates the protocol"
+          elif sslErr == 0 and err == -1:
+            errStr.add "in the BIO layer"
+          else:
+            let errStr = $ErrErrorString(sslErr, nil)
+            raiseSSLError(errStr & ": " & errStr)
+          let osMsg = osErrorMsg osLastError()
+          if osMsg != "":
+            errStr.add ". The OS reports: " & osMsg
+          raise newException(OSError, errStr)
+        of SSL_ERROR_SSL:
           raiseSSLError()
         else: raiseSSLError("Unknown Error")
   
   if err == -1 and not (when defined(ssl): socket.isSSL else: false):
-    let lastE = if lastError.int == -1: osLastError() else: lastError
+    var lastE = if lastError.int == -1: getSocketError(socket) else: lastError
     if async:
       when useWinVersion:
         if lastE.int32 == WSAEWOULDBLOCK:
@@ -279,7 +321,8 @@ proc listen*(socket: Socket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
   ## queue of pending connections.
   ##
   ## Raises an EOS error upon failure.
-  if listen(socket.fd, backlog) < 0'i32: raiseOSError(osLastError())
+  if rawsockets.listen(socket.fd, backlog) < 0'i32:
+    raiseOSError(osLastError())
 
 proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
   tags: [ReadIOEffect].} =
@@ -306,7 +349,8 @@ proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
     dealloc(aiList)
 
 proc acceptAddr*(server: Socket, client: var Socket, address: var string,
-                 flags = {SocketFlag.SafeDisconn}) {.tags: [ReadIOEffect].} =
+                 flags = {SocketFlag.SafeDisconn}) {.
+                 tags: [ReadIOEffect], gcsafe, locks: 0.} =
   ## Blocks until a connection is being made from a client. When a connection
   ## is made sets ``client`` to the client socket and ``address`` to the address
   ## of the connecting client.
@@ -418,15 +462,23 @@ proc accept*(server: Socket, client: var Socket,
 
 proc close*(socket: Socket) =
   ## Closes a socket.
-  socket.fd.close()
-  when defined(ssl):
-    if socket.isSSL:
-      let res = SSLShutdown(socket.sslHandle)
-      if res == 0:
-        if SSLShutdown(socket.sslHandle) != 1:
-          socketError(socket)
-      elif res != 1:
-        socketError(socket)
+  try:
+    when defined(ssl):
+      if socket.isSSL:
+        ErrClearError()
+        # As we are closing the underlying socket immediately afterwards,
+        # it is valid, under the TLS standard, to perform a unidirectional
+        # shutdown i.e not wait for the peers "close notify" alert with a second
+        # call to SSLShutdown
+        let res = SSLShutdown(socket.sslHandle)
+        SSLFree(socket.sslHandle)
+        socket.sslHandle = nil
+        if res == 0:
+          discard
+        elif res != 1:
+          socketError(socket, res)
+  finally:
+    socket.fd.close()
 
 proc toCInt*(opt: SOBool): cint =
   ## Converts a ``SOBool`` into its Socket Option cint representation.
@@ -476,6 +528,12 @@ proc connect*(socket: Socket, address: string, port = Port(0),
   
   when defined(ssl):
     if socket.isSSL:
+      # RFC3546 for SNI specifies that IP addresses are not allowed.
+      if not isIpAddress(address):
+        # Discard result in case OpenSSL version doesn't support SNI, or we're
+        # not using TLSv1+
+        discard SSL_set_tlsext_host_name(socket.sslHandle, address)
+
       let ret = SSLConnect(socket.sslHandle)
       socketError(socket, ret)
 
@@ -547,6 +605,10 @@ proc readIntoBuf(socket: Socket, flags: int32): int =
       result = recv(socket.fd, addr(socket.buffer), cint(socket.buffer.high), flags)
   else:
     result = recv(socket.fd, addr(socket.buffer), cint(socket.buffer.high), flags)
+  if result < 0:
+    # Save it in case it gets reset (the Nim codegen occassionally may call
+    # Win API functions which reset it).
+    socket.lastError = osLastError()
   if result <= 0:
     socket.bufLen = 0
     socket.currPos = 0
@@ -602,6 +664,9 @@ proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ReadIOEffect]
         result = recv(socket.fd, data, size.cint, 0'i32)
     else:
       result = recv(socket.fd, data, size.cint, 0'i32)
+    if result < 0:
+      # Save the error in case it gets reset.
+      socket.lastError = osLastError()
 
 proc waitFor(socket: Socket, waited: var float, timeout, size: int,
              funcName: string): int {.tags: [TimeEffect].} =
@@ -674,7 +739,7 @@ proc recv*(socket: Socket, data: var string, size: int, timeout = -1,
   result = recv(socket, cstring(data), size, timeout)
   if result < 0:
     data.setLen(0)
-    let lastError = osLastError()
+    let lastError = getSocketError(socket)
     if flags.isDisconnectionError(lastError): return
     socket.socketError(result, lastError = lastError)
   data.setLen(result)
@@ -722,7 +787,7 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1,
       line.add("\c\L")
 
   template raiseSockError(): stmt {.dirty, immediate.} =
-    let lastError = osLastError()
+    let lastError = getSocketError(socket)
     if flags.isDisconnectionError(lastError): setLen(line.string, 0); return
     socket.socketError(n, lastError = lastError)
 
@@ -865,7 +930,7 @@ proc connectAsync(socket: Socket, name: string, port = Port(0),
                   af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
   ## A variant of ``connect`` for non-blocking sockets.
   ##
-  ## This procedure will immediatelly return, it will not block until a connection
+  ## This procedure will immediately return, it will not block until a connection
   ## is made. It is up to the caller to make sure the connection has been established
   ## by checking (using ``select``) whether the socket is writeable.
   ##
@@ -917,26 +982,16 @@ proc connect*(socket: Socket, address: string, port = Port(0), timeout: int,
         doAssert socket.handshake()
   socket.fd.setBlocking(true)
 
-proc isSSL*(socket: Socket): bool = return socket.isSSL
+proc isSsl*(socket: Socket): bool = 
   ## Determines whether ``socket`` is a SSL socket.
+  when defined(ssl):
+    result = socket.isSSL
+  else:
+    result = false
 
-proc getFD*(socket: Socket): SocketHandle = return socket.fd
+proc getFd*(socket: Socket): SocketHandle = return socket.fd
   ## Returns the socket's file descriptor
 
-type
-  IpAddressFamily* {.pure.} = enum ## Describes the type of an IP address
-    IPv6, ## IPv6 address
-    IPv4  ## IPv4 address
-
-  TIpAddress* = object ## stores an arbitrary IP address    
-    case family*: IpAddressFamily ## the type of the IP address (IPv4 or IPv6)
-    of IpAddressFamily.IPv6:
-      address_v6*: array[0..15, uint8] ## Contains the IP address in bytes in
-                                       ## case of IPv6
-    of IpAddressFamily.IPv4:
-      address_v4*: array[0..3, uint8] ## Contains the IP address in bytes in
-                                      ## case of IPv4
-
 proc IPv4_any*(): TIpAddress =
   ## Returns the IPv4 any address, which can be used to listen on all available
   ## network adapters
@@ -1195,7 +1250,7 @@ proc parseIPv6Address(address_str: string): TIpAddress =
     raise newException(ValueError,
       "Invalid IP Address. The address consists of too many groups")
 
-proc parseIpAddress*(address_str: string): TIpAddress =
+proc parseIpAddress(address_str: string): TIpAddress =
   ## Parses an IP address
   ## Raises EInvalidValue on error
   if address_str == nil:
@@ -1204,3 +1259,13 @@ proc parseIpAddress*(address_str: string): TIpAddress =
     return parseIPv6Address(address_str)
   else:
     return parseIPv4Address(address_str)
+
+
+proc isIpAddress(address_str: string): bool =
+  ## Checks if a string is an IP address
+  ## Returns true if it is, false otherwise
+  try:
+    discard parseIpAddress(address_str)
+  except ValueError:
+    return false
+  return true
diff --git a/lib/pure/nimprof.nim b/lib/pure/nimprof.nim
index 3598cdd3a..cce2a20ae 100644
--- a/lib/pure/nimprof.nim
+++ b/lib/pure/nimprof.nim
@@ -132,7 +132,7 @@ else:
   proc hook(st: TStackTrace) {.nimcall.} =
     if interval == 0:
       hookAux(st, 1)
-    elif getTicks() - t0 > interval:
+    elif int64(t0) == 0 or getTicks() - t0 > interval:
       hookAux(st, 1)
       t0 = getTicks()
 
diff --git a/lib/pure/nimprof.nimrod.cfg b/lib/pure/nimprof.nim.cfg
index 1589e7394..1589e7394 100644
--- a/lib/pure/nimprof.nimrod.cfg
+++ b/lib/pure/nimprof.nim.cfg
diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim
index 0dc8e3c15..ac90dd16b 100644
--- a/lib/pure/oids.nim
+++ b/lib/pure/oids.nim
@@ -88,6 +88,6 @@ proc generatedTime*(oid: Oid): Time =
   bigEndian32(addr(tmp), addr(dummy))
   result = Time(tmp)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   let xo = genOid()
   echo xo.generatedTime
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index b5eead91d..f53abe81d 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -185,7 +185,7 @@ const
 proc osErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} =
   ## Retrieves the operating system's error flag, ``errno``.
   ## On Windows ``GetLastError`` is checked before ``errno``.
-  ## Returns "" if no error occured.
+  ## Returns "" if no error occurred.
   ##
   ## **Deprecated since version 0.9.4**: use the other ``osErrorMsg`` proc.
 
@@ -211,13 +211,13 @@ proc osErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} =
 {.push warning[deprecated]: off.}
 proc raiseOSError*(msg: string = "") {.noinline, rtl, extern: "nos$1",
                                        deprecated.} =
-  ## raises an EOS exception with the given message ``msg``.
+  ## raises an OSError exception with the given message ``msg``.
   ## If ``msg == ""``, the operating system's error flag
   ## (``errno``) is converted to a readable error message. On Windows
   ## ``GetLastError`` is checked before ``errno``.
   ## If no error flag is set, the message ``unknown OS error`` is used.
   ##
-  ## **Deprecated since version 0.9.4**: use the other ``OSError`` proc.
+  ## **Deprecated since version 0.9.4**: use the other ``raiseOSError`` proc.
   if len(msg) == 0:
     var m = osErrorMsg()
     raise newException(OSError, if m.len > 0: m else: "unknown OS error")
@@ -234,7 +234,7 @@ proc `$`*(err: OSErrorCode): string {.borrow.}
 proc osErrorMsg*(errorCode: OSErrorCode): string =
   ## Converts an OS error code into a human readable string.
   ##
-  ## The error code can be retrieved using the ``OSLastError`` proc.
+  ## The error code can be retrieved using the ``osLastError`` proc.
   ##
   ## If conversion fails, or ``errorCode`` is ``0`` then ``""`` will be
   ## returned.
@@ -262,10 +262,10 @@ proc osErrorMsg*(errorCode: OSErrorCode): string =
       result = $os.strerror(errorCode.int32)
 
 proc raiseOSError*(errorCode: OSErrorCode) =
-  ## Raises an ``EOS`` exception. The ``errorCode`` will determine the
-  ## message, ``OSErrorMsg`` will be used to get this message.
+  ## Raises an ``OSError`` exception. The ``errorCode`` will determine the
+  ## message, ``osErrorMsg`` will be used to get this message.
   ##
-  ## The error code can be retrieved using the ``OSLastError`` proc.
+  ## The error code can be retrieved using the ``osLastError`` proc.
   ##
   ## If the error code is ``0`` or an error message could not be retrieved,
   ## the message ``unknown OS error`` will be used.
@@ -502,7 +502,7 @@ proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [].} =
       raiseOSError(osLastError())
 
 proc setCurrentDir*(newDir: string) {.inline, tags: [].} =
-  ## Sets the `current working directory`:idx:; `EOS` is raised if
+  ## Sets the `current working directory`:idx:; `OSError` is raised if
   ## `newDir` cannot been set.
   when defined(Windows):
     when useWinUnicode:
@@ -575,7 +575,7 @@ proc `/` * (head, tail: string): string {.noSideEffect.} =
 proc splitPath*(path: string): tuple[head, tail: string] {.
   noSideEffect, rtl, extern: "nos$1".} =
   ## Splits a directory into (head, tail), so that
-  ## ``joinPath(head, tail) == path``.
+  ## ``head / tail == path`` (except for edge cases like "/usr").
   ##
   ## Examples:
   ##
@@ -599,7 +599,7 @@ proc splitPath*(path: string): tuple[head, tail: string] {.
 
 proc parentDirPos(path: string): int =
   var q = 1
-  if path[len(path)-1] in {DirSep, AltSep}: q = 2
+  if len(path) >= 1 and path[len(path)-1] in {DirSep, AltSep}: q = 2
   for i in countdown(len(path)-q, 0):
     if path[i] in {DirSep, AltSep}: return i
   result = -1
@@ -715,7 +715,7 @@ proc extractFilename*(path: string): string {.
 
 proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
   tags: [ReadDirEffect].} =
-  ## Returns the full path of `filename`, raises EOS in case of an error.
+  ## Returns the full path of `filename`, raises OSError in case of an error.
   when defined(windows):
     const bufsize = 3072'i32
     when useWinUnicode:
@@ -884,7 +884,7 @@ proc sameFileContent*(path1, path2: string): bool {.rtl, extern: "nos$1",
   close(b)
 
 type
-  TFilePermission* = enum  ## file access permission; modelled after UNIX
+  FilePermission* = enum   ## file access permission; modelled after UNIX
     fpUserExec,            ## execute access for the file owner
     fpUserWrite,           ## write access for the file owner
     fpUserRead,            ## read access for the file owner
@@ -895,7 +895,9 @@ type
     fpOthersWrite,         ## write access for others
     fpOthersRead           ## read access for others
 
-proc getFilePermissions*(filename: string): set[TFilePermission] {.
+{.deprecated: [TFilePermission: FilePermission].}
+
+proc getFilePermissions*(filename: string): set[FilePermission] {.
   rtl, extern: "nos$1", tags: [ReadDirEffect].} =
   ## retrieves file permissions for `filename`. `OSError` is raised in case of
   ## an error. On Windows, only the ``readonly`` flag is checked, every other
@@ -927,7 +929,7 @@ proc getFilePermissions*(filename: string): set[TFilePermission] {.
     else:
       result = {fpUserExec..fpOthersRead}
   
-proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {.
+proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {.
   rtl, extern: "nos$1", tags: [WriteDirEffect].} =
   ## sets the file permissions for `filename`. `OSError` is raised in case of
   ## an error. On Windows, only the ``readonly`` flag is changed, depending on
@@ -967,7 +969,7 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
   tags: [ReadIOEffect, WriteIOEffect].} =
   ## Copies a file from `source` to `dest`.
   ##
-  ## If this fails, `EOS` is raised. On the Windows platform this proc will
+  ## If this fails, `OSError` is raised. On the Windows platform this proc will
   ## copy the source file's attributes into dest. On other platforms you need
   ## to use `getFilePermissions() <#getFilePermissions>`_ and
   ## `setFilePermissions() <#setFilePermissions>`_ to copy them by hand (or use
@@ -1007,9 +1009,17 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
 
 proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
   tags: [ReadIOEffect, WriteIOEffect].} =
-  ## Moves a file from `source` to `dest`. If this fails, `EOS` is raised.
-  if c_rename(source, dest) != 0'i32:
-    raise newException(OSError, $strerror(errno))
+  ## Moves a file from `source` to `dest`. If this fails, `OSError` is raised.
+  when defined(Windows):
+    when useWinUnicode:
+      let s = newWideCString(source)
+      let d = newWideCString(dest)
+      if moveFileW(s, d, 0'i32) == 0'i32: raiseOSError(osLastError())
+    else:
+      if moveFileA(source, dest, 0'i32) == 0'i32: raiseOSError(osLastError())
+  else:
+    if c_rename(source, dest) != 0'i32:
+      raise newException(OSError, $strerror(errno))
 
 when not declared(ENOENT) and not defined(Windows):
   when NoFakeVars:
@@ -1028,7 +1038,7 @@ when defined(Windows):
       setFileAttributesA(file, attrs)
 
 proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
-  ## Removes the `file`. If this fails, `EOS` is raised. This does not fail
+  ## Removes the `file`. If this fails, `OSError` is raised. This does not fail
   ## if the file never existed in the first place.
   ## On Windows, ignores the read-only attribute.
   when defined(Windows):
@@ -1072,8 +1082,12 @@ when defined(windows):
   # because we support Windows GUI applications, things get really
   # messy here...
   when useWinUnicode:
-    proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.
-      importc: "wcschr", header: "<string.h>".}
+    when defined(cpp):
+      proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.
+        importcpp: "(NI16*)wcschr((const wchar_t *)#, #)", header: "<string.h>".}
+    else:
+      proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.
+        importc: "wcschr", header: "<string.h>".}
   else:
     proc strEnd(cstr: cstring, c = 0'i32): cstring {.
       importc: "strchr", header: "<string.h>".}
@@ -1085,7 +1099,7 @@ when defined(windows):
         var
           env = getEnvironmentStringsW()
           e = env
-        if e == nil: return # an error occured
+        if e == nil: return # an error occurred
         while true:
           var eend = strEnd(e)
           add(environment, $e)
@@ -1096,7 +1110,7 @@ when defined(windows):
         var
           env = getEnvironmentStringsA()
           e = env
-        if e == nil: return # an error occured
+        if e == nil: return # an error occurred
         while true:
           var eend = strEnd(e)
           add(environment, $e)
@@ -1107,8 +1121,8 @@ when defined(windows):
 
 else:
   const
-    useNSGetEnviron = defined(macosx) and
-      (defined(createNimRtl) or defined(useNimRtl))
+    useNSGetEnviron = defined(macosx)
+
   when useNSGetEnviron:
     # From the manual:
     # Shared libraries and bundles don't have direct access to environ,
@@ -1168,7 +1182,7 @@ proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} =
   ## If an error occurs, `EInvalidEnvVar` is raised.
 
   # Note: by storing the string in the environment sequence,
-  # we gurantee that we don't free the memory before the program
+  # we guarantee that we don't free the memory before the program
   # 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)
@@ -1231,13 +1245,15 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} =
     globfree(addr(f))
 
 type
-  TPathComponent* = enum  ## Enumeration specifying a path component.
+  PathComponent* = enum   ## Enumeration specifying a path component.
     pcFile,               ## path refers to a file
     pcLinkToFile,         ## path refers to a symbolic link to a file
     pcDir,                ## path refers to a directory
     pcLinkToDir           ## path refers to a symbolic link to a directory
 
-iterator walkDir*(dir: string): tuple[kind: TPathComponent, path: string] {.
+{.deprecated: [TPathComponent: PathComponent].}
+
+iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {.
   tags: [ReadDirEffect].} =
   ## walks over the directory `dir` and yields for each directory or file in
   ## `dir`. The component type and full path for each item is returned.
@@ -1283,8 +1299,16 @@ iterator walkDir*(dir: string): tuple[kind: TPathComponent, path: string] {.
         if y != "." and y != "..":
           var s: TStat
           y = dir / y
-          if lstat(y, s) < 0'i32: break
           var k = pcFile
+
+          when defined(linux) or defined(macosx) or defined(bsd):
+            if x.d_type != DT_UNKNOWN:
+              if x.d_type == DT_DIR: k = pcDir
+              if x.d_type == DT_LNK: k = succ(k)
+              yield (k, y)
+              continue
+
+          if lstat(y, s) < 0'i32: break
           if S_ISDIR(s.st_mode): k = pcDir
           if S_ISLNK(s.st_mode): k = succ(k)
           yield (k, y)
@@ -1331,11 +1355,11 @@ proc rawRemoveDir(dir: string) =
     if rmdir(dir) != 0'i32 and errno != ENOENT: raiseOSError(osLastError())
 
 proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
-  WriteDirEffect, ReadDirEffect].} =
+  WriteDirEffect, ReadDirEffect], benign.} =
   ## Removes the directory `dir` including all subdirectories and files
   ## in `dir` (recursively).
   ##
-  ## If this fails, `EOS` is raised. This does not fail if the directory never
+  ## If this fails, `OSError` is raised. This does not fail if the directory never
   ## existed in the first place.
   for kind, path in walkDir(dir):
     case kind
@@ -1362,11 +1386,11 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
   ## Creates the `directory`:idx: `dir`.
   ##
   ## The directory may contain several subdirectories that do not exist yet.
-  ## The full path is created. If this fails, `EOS` is raised. It does **not**
+  ## The full path is created. If this fails, `OSError` is raised. It does **not**
   ## fail if the path already exists because for most usages this does not
   ## indicate an error.
   var omitNext = false
-  when defined(doslike):
+  when doslike:
     omitNext = isAbsolute(dir)
   for i in 1.. dir.len-1:
     if dir[i] in {DirSep, AltSep}:
@@ -1377,10 +1401,10 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
   rawCreateDir(dir)
 
 proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
-  tags: [WriteIOEffect, ReadIOEffect].} =
+  tags: [WriteIOEffect, ReadIOEffect], benign.} =
   ## Copies a directory from `source` to `dest`.
   ##
-  ## If this fails, `EOS` is raised. On the Windows platform this proc will
+  ## If this fails, `OSError` is raised. On the Windows platform this proc will
   ## copy the attributes from `source` into `dest`. On other platforms created
   ## files and directories will inherit the default permissions of a newly
   ## created file/directory for the user. To preserve attributes recursively on
@@ -1438,7 +1462,7 @@ proc createHardlink*(src, dest: string) =
 proc parseCmdLine*(c: string): seq[string] {.
   noSideEffect, rtl, extern: "nos$1".} =
   ## Splits a command line into several components;
-  ## This proc is only occassionally useful, better use the `parseopt` module.
+  ## This proc is only occasionally useful, better use the `parseopt` module.
   ##
   ## On Windows, it uses the following parsing rules
   ## (see http://msdn.microsoft.com/en-us/library/17w5ykft.aspx ):
@@ -1550,10 +1574,10 @@ proc copyFileWithPermissions*(source, dest: string,
 
 proc copyDirWithPermissions*(source, dest: string,
     ignorePermissionErrors = true) {.rtl, extern: "nos$1",
-    tags: [WriteIOEffect, ReadIOEffect].} =
+    tags: [WriteIOEffect, ReadIOEffect], benign.} =
   ## Copies a directory from `source` to `dest` preserving file permissions.
   ##
-  ## If this fails, `EOS` is raised. This is a wrapper proc around `copyDir()
+  ## If this fails, `OSError` is raised. This is a wrapper proc around `copyDir()
   ## <#copyDir>`_ and `copyFileWithPermissions() <#copyFileWithPermissions>`_
   ## on non Windows platforms. On Windows this proc is just a wrapper for
   ## `copyDir() <#copyDir>`_ since that proc already copies attributes.
@@ -1580,7 +1604,7 @@ proc copyDirWithPermissions*(source, dest: string,
     else: discard
 
 proc inclFilePermissions*(filename: string,
-                          permissions: set[TFilePermission]) {.
+                          permissions: set[FilePermission]) {.
   rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect].} =
   ## a convenience procedure for:
   ##
@@ -1589,7 +1613,7 @@ proc inclFilePermissions*(filename: string,
   setFilePermissions(filename, getFilePermissions(filename)+permissions)
 
 proc exclFilePermissions*(filename: string,
-                          permissions: set[TFilePermission]) {.
+                          permissions: set[FilePermission]) {.
   rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect].} =
   ## a convenience procedure for:
   ##
@@ -1825,7 +1849,7 @@ proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect].} =
 
 proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1",
   tags: [ReadIOEffect].} =
-  ## returns the file size of `file`. Can raise ``EOS``.
+  ## returns the file size of `file`. Can raise ``OSError``.
   when defined(windows):
     var a: TWIN32_FIND_DATA
     var resA = findFirstFile(file, a)
@@ -1839,16 +1863,21 @@ proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1",
       close(f)
     else: raiseOSError(osLastError())
 
+proc expandTilde*(path: string): string {.tags: [ReadEnvEffect].}
+
 proc findExe*(exe: string): string {.tags: [ReadDirEffect, ReadEnvEffect].} =
   ## Searches for `exe` in the current working directory and then
   ## in directories listed in the ``PATH`` environment variable.
   ## Returns "" if the `exe` cannot be found. On DOS-like platforms, `exe`
-  ## is added an ``.exe`` file extension if it has no extension.
+  ## is added the `ExeExt <#ExeExt>`_ file extension if it has none.
   result = addFileExt(exe, os.ExeExt)
   if existsFile(result): return
   var path = string(os.getEnv("PATH"))
   for candidate in split(path, PathSep):
-    var x = candidate / result
+    when defined(windows):
+      var x = candidate / result
+    else:
+      var x = expandTilde(candidate) / result
     if existsFile(x): return x
   result = ""
 
@@ -1885,9 +1914,9 @@ type
   FileInfo* = object
     ## Contains information associated with a file object.
     id*: tuple[device: DeviceId, file: FileId] # Device and file id.
-    kind*: TPathComponent # Kind of file object - directory, symlink, etc.
+    kind*: PathComponent # Kind of file object - directory, symlink, etc.
     size*: BiggestInt # Size of file.
-    permissions*: set[TFilePermission] # File permissions
+    permissions*: set[FilePermission] # File permissions
     linkCount*: BiggestInt # Number of hard links the file object has.
     lastAccessTime*: Time # Time file was last accessed.
     lastWriteTime*: Time # Time file was last modified/written to.
@@ -1973,6 +2002,8 @@ proc getFileInfo*(handle: FileHandle): FileInfo =
     rawToFormalFileInfo(rawInfo, result)
 
 proc getFileInfo*(file: File): FileInfo =
+  if file.isNil:
+    raise newException(IOError, "File is nil")
   result = getFileInfo(file.getFileHandle())
 
 proc getFileInfo*(path: string, followSymlink = true): FileInfo =
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index bfdb0efed..dce0673ba 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -137,7 +137,7 @@ proc startProcess*(command: string,
   ## `env` is the environment that will be passed to the process.
   ## If ``env == nil`` the environment is inherited of
   ## the parent process. `options` are additional flags that may be passed
-  ## to `startProcess`. See the documentation of ``TProcessOption`` for the
+  ## to `startProcess`. See the documentation of ``ProcessOption`` for the
   ## meaning of these flags. You need to `close` the process when done.
   ##
   ## Note that you can't pass any `args` if you use the option
@@ -146,7 +146,7 @@ proc startProcess*(command: string,
   ## of `args` to `command` carefully escaping/quoting any special characters,
   ## since it will be passed *as is* to the system shell. Each system/shell may
   ## feature different escaping rules, so try to avoid this kind of shell
-  ## invokation if possible as it leads to non portable software.
+  ## invocation if possible as it leads to non portable software.
   ##
   ## Return value: The newly created process object. Nil is never returned,
   ## but ``EOS`` is raised in case of an error.
@@ -174,7 +174,7 @@ proc terminate*(p: Process) {.rtl, extern: "nosp$1", tags: [].}
 proc kill*(p: Process) {.rtl, extern: "nosp$1", tags: [].}
   ## Kill the process `p`. On Posix OSes the procedure sends ``SIGKILL`` to
   ## the process. On Windows ``kill()`` is simply an alias for ``terminate()``.
-  
+
 proc running*(p: Process): bool {.rtl, extern: "nosp$1", tags: [].}
   ## Returns true iff the process `p` is still running. Returns immediately.
 
@@ -260,7 +260,7 @@ proc execProcesses*(cmds: openArray[string],
     for i in 0..m-1:
       if beforeRunEvent != nil:
         beforeRunEvent(i)
-      q[i] = startCmd(cmds[i], options=options)
+      q[i] = startProcess(cmds[i], options=options + {poEvalCommand})
     when defined(noBusyWaiting):
       var r = 0
       for i in m..high(cmds):
@@ -275,7 +275,7 @@ proc execProcesses*(cmds: openArray[string],
         if q[r] != nil: close(q[r])
         if beforeRunEvent != nil:
           beforeRunEvent(i)
-        q[r] = startCmd(cmds[i], options=options)
+        q[r] = startProcess(cmds[i], options=options + {poEvalCommand})
         r = (r + 1) mod n
     else:
       var i = m
@@ -288,7 +288,7 @@ proc execProcesses*(cmds: openArray[string],
             if q[r] != nil: close(q[r])
             if beforeRunEvent != nil:
               beforeRunEvent(i)
-            q[r] = startCmd(cmds[i], options=options)
+            q[r] = startProcess(cmds[i], options=options + {poEvalCommand})
             inc(i)
             if i > high(cmds): break
     for j in 0..m-1:
@@ -298,7 +298,7 @@ proc execProcesses*(cmds: openArray[string],
     for i in 0..high(cmds):
       if beforeRunEvent != nil:
         beforeRunEvent(i)
-      var p = startCmd(cmds[i], options=options)
+      var p = startProcess(cmds[i], options=options + {poEvalCommand})
       result = max(waitForExit(p), result)
       close(p)
 
@@ -644,14 +644,14 @@ elif not defined(useNimRtl):
     var pid: TPid
 
     var sysArgs = allocCStringArray(sysArgsRaw)
-    finally: deallocCStringArray(sysArgs)
+    defer: deallocCStringArray(sysArgs)
 
     var sysEnv = if env == nil:
         envToCStringArray()
       else:
         envToCStringArray(env)
 
-    finally: deallocCStringArray(sysEnv)
+    defer: deallocCStringArray(sysEnv)
 
     var data: TStartProcessData
     data.sysCommand = sysCommand
@@ -666,7 +666,7 @@ elif not defined(useNimRtl):
     data.workingDir = workingDir
 
 
-    when declared(posix_spawn) and not defined(useFork) and 
+    when declared(posix_spawn) and not defined(useFork) and
         not defined(useClone) and not defined(linux):
       pid = startProcessAuxSpawn(data)
     else:
@@ -748,7 +748,7 @@ elif not defined(useNimRtl):
     if pipe(data.pErrorPipe) != 0:
       raiseOSError(osLastError())
 
-    finally:
+    defer:
       discard close(data.pErrorPipe[readIdx])
 
     var pid: TPid
@@ -823,7 +823,7 @@ elif not defined(useNimRtl):
         discard execvp(data.sysCommand, data.sysArgs)
       else:
         when defined(uClibc):
-          # uClibc environment (OpenWrt included) doesn't have the full execvpe 
+          # uClibc environment (OpenWrt included) doesn't have the full execvpe
           discard execve(data.sysCommand, data.sysArgs, data.sysEnv)
         else:
           discard execvpe(data.sysCommand, data.sysArgs, data.sysEnv)
@@ -848,7 +848,14 @@ elif not defined(useNimRtl):
     if kill(p.id, SIGCONT) != 0'i32: raiseOsError(osLastError())
 
   proc running(p: Process): bool =
-    var ret = waitpid(p.id, p.exitCode, WNOHANG)
+    var ret : int
+    when not defined(freebsd):
+      ret = waitpid(p.id, p.exitCode, WNOHANG)
+    else:
+      var status : cint = 1
+      ret = waitpid(p.id, status, WNOHANG)
+      if WIFEXITED(status):
+        p.exitCode = status
     if ret == 0: return true # Can't establish status. Assume running.
     result = ret == int(p.id)
 
@@ -857,9 +864,9 @@ elif not defined(useNimRtl):
       raiseOsError(osLastError())
 
   proc kill(p: Process) =
-    if kill(p.id, SIGKILL) != 0'i32: 
+    if kill(p.id, SIGKILL) != 0'i32:
       raiseOsError(osLastError())
-    
+
   proc waitForExit(p: Process, timeout: int = -1): int =
     #if waitPid(p.id, p.exitCode, 0) == int(p.id):
     # ``waitPid`` fails if the process is not running anymore. But then
@@ -876,7 +883,7 @@ elif not defined(useNimRtl):
     var ret = waitpid(p.id, p.exitCode, WNOHANG)
     var b = ret == int(p.id)
     if b: result = -1
-    if p.exitCode == -3: result = -1
+    if not WIFEXITED(p.exitCode): result = -1
     else: result = p.exitCode.int shr 8
 
   proc createStream(stream: var Stream, handle: var FileHandle,
@@ -900,7 +907,7 @@ elif not defined(useNimRtl):
       createStream(p.errStream, p.errHandle, fmRead)
     return p.errStream
 
-  proc csystem(cmd: cstring): cint {.nodecl, importc: "system", 
+  proc csystem(cmd: cstring): cint {.nodecl, importc: "system",
                                      header: "<stdlib.h>".}
 
   proc execCmd(command: string): int =
@@ -949,7 +956,7 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = {
                 exitCode: int] {.tags: [ExecIOEffect, ReadIOEffect], gcsafe.} =
   ## a convenience proc that runs the `command`, grabs all its output and
   ## exit code and returns both.
-  var p = startCmd(command, options)
+  var p = startProcess(command, options=options + {poEvalCommand})
   var outp = outputStream(p)
   result = (TaintedString"", -1)
   var line = newStringOfCap(120).TaintedString
diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim
index bb9d2aed2..bb64c8134 100644
--- a/lib/pure/parsecfg.nim
+++ b/lib/pure/parsecfg.nim
@@ -35,7 +35,7 @@ type
     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
+    cfgError            ## an error occurred during parsing
     
   CfgEvent* = object of RootObj ## describes a parsing event
     case kind*: CfgEventKind    ## the kind of the event
diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim
index f4943ed89..117d75cfa 100644
--- a/lib/pure/parsecsv.nim
+++ b/lib/pure/parsecsv.nim
@@ -166,7 +166,7 @@ proc close*(my: var CsvParser) {.inline.} =
   ## closes the parser `my` and its associated input stream.
   lexbase.close(my)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   import os
   var s = newFileStream(paramStr(1), fmRead)
   if s == nil: quit("cannot open the file" & paramStr(1))
diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim
index 8af6920c1..4c92a7cdf 100644
--- a/lib/pure/parseopt.nim
+++ b/lib/pure/parseopt.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -11,9 +11,12 @@
 ## It supports one convenience iterator over all command line options and some
 ## lower-level features.
 ##
-## **Deprecated since version 0.9.3:** Use the `parseopt2 <parseopt2.html>`_
-## module instead as this version has issues with spaces in arguments.
-{.deprecated.}
+## Supported syntax:
+##
+## 1. short options - ``-abcd``, where a, b, c, d are names
+## 2. long option - ``--foo:bar``, ``--foo=bar`` or ``--foo``
+## 3. argument - everything else
+
 {.push debugger: off.}
 
 include "system/inclrtl"
diff --git a/lib/pure/parseopt2.nim b/lib/pure/parseopt2.nim
index 5b1f50958..73b498fe0 100644
--- a/lib/pure/parseopt2.nim
+++ b/lib/pure/parseopt2.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -60,7 +60,7 @@ proc initOptParser*(cmdline: string): OptParser {.rtl, deprecated.} =
   ## Initalizes option parses with cmdline. Splits cmdline in on spaces
   ## and calls initOptParser(openarray[string])
   ## Do not use.
-  if cmdline == "": # backward compatibilty
+  if cmdline == "": # backward compatibility
     return initOptParser(seq[string](nil))
   else:
     return initOptParser(cmdline.split)
diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim
index bb4ede779..91917b1c5 100644
--- a/lib/pure/parsesql.nim
+++ b/lib/pure/parsesql.nim
@@ -1330,7 +1330,7 @@ proc renderSQL*(n: SqlNode): string =
   result = ""
   ra(n, result, 0)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   echo(renderSQL(parseSQL(newStringStream("""
       CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic');
       CREATE TABLE holidays (
diff --git a/lib/pure/parseurl.nim b/lib/pure/parseurl.nim
index 32e69b89a..56bf10768 100644
--- a/lib/pure/parseurl.nim
+++ b/lib/pure/parseurl.nim
@@ -1,16 +1,18 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Dominik Picheta
+#        (c) Copyright 2015 Dominik Picheta
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
-## Parses & constructs URLs.
+## **Warnings:** This module is deprecated since version 0.10.2.
+## Use the `uri <uri.html>`_ module instead.
 ##
-## **Note**: This module will be deprecated in the future and merged into a
-## new ``url`` module.
+## Parses & constructs URLs.
+
+{.deprecated.}
 
 import strutils
 
diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim
index 1efb141fc..c07b713de 100644
--- a/lib/pure/parseutils.nim
+++ b/lib/pure/parseutils.nim
@@ -181,7 +181,7 @@ proc parseWhile*(s: string, token: var string, validChars: set[char],
   token = substr(s, start, i-1)
 
 proc captureBetween*(s: string, first: char, second = '\0', start = 0): string =
-  ## Finds the first occurence of ``first``, then returns everything from there
+  ## Finds the first occurrence of ``first``, then returns everything from there
   ## up to ``second``(if ``second`` is '\0', then ``first`` is used).
   var i = skipUntil(s, first, start)+1+start
   result = ""
@@ -228,7 +228,7 @@ proc parseInt*(s: string, number: var int, start = 0): int {.
   if (sizeof(int) <= 4) and
       ((res < low(int)) or (res > high(int))):
     raise newException(OverflowError, "overflow")
-  else:
+  elif result != 0:
     number = int(res)
 
 proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {.
@@ -240,11 +240,12 @@ proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {.
 proc parseFloat*(s: string, number: var float, start = 0): int {.
   rtl, extern: "npuParseFloat", noSideEffect.} =
   ## parses a float starting at `start` and stores the value into `number`.
-  ## Result is the number of processed chars or 0 if there occured a parsing
+  ## Result is the number of processed chars or 0 if there occurred a parsing
   ## error.
   var bf: BiggestFloat
   result = parseBiggestFloat(s, bf, start)
-  number = bf
+  if result != 0:
+    number = bf
   
 type
   InterpolatedKind* = enum   ## describes for `interpolatedFragments`
@@ -294,7 +295,7 @@ iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
             dec nesting
           of '\0':
             raise newException(ValueError, 
-              "Expected closing '}': " & s[i..s.len])
+              "Expected closing '}': " & substr(s, i, s.high))
           else: discard
           inc j
         inc i, 2 # skip ${
@@ -310,7 +311,7 @@ iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
         kind = ikDollar
       else:
         raise newException(ValueError, 
-          "Unable to parse a varible name at " & s[i..s.len])
+          "Unable to parse a varible name at " & substr(s, i, s.high))
     else:
       while j < s.len and s[j] != '$': inc j
       kind = ikStr
@@ -322,8 +323,12 @@ iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
     i = j
 
 when isMainModule:
-  for k, v in interpolatedFragments("$test{}  $this is ${an{  example}}  "):
-    echo "(", k, ", \"", v, "\")"
+  import sequtils
+  let input = "$test{}  $this is ${an{  example}}  "
+  let expected = @[(ikVar, "test"), (ikStr, "{}  "), (ikVar, "this"),
+                   (ikStr, " is "), (ikExpr, "an{  example}"), (ikStr, "  ")]
+  assert toSeq(interpolatedFragments(input)) == expected
+
   var value = 0
   discard parseHex("0x38", value)
   assert value == 56
diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim
index 39dead3c0..eb792f086 100644
--- a/lib/pure/parsexml.nim
+++ b/lib/pure/parsexml.nim
@@ -57,7 +57,7 @@ import
 
 type 
   XmlEventKind* = enum ## enumation of all events that may occur when parsing
-    xmlError,           ## an error ocurred during parsing
+    xmlError,           ## an error occurred during parsing
     xmlEof,             ## end of file reached
     xmlCharData,        ## character data
     xmlWhitespace,      ## whitespace has been parsed
@@ -128,6 +128,7 @@ proc open*(my: var XmlParser, input: Stream, filename: string,
   my.kind = xmlError
   my.a = ""
   my.b = ""
+  my.c = nil
   my.options = options
   
 proc close*(my: var XmlParser) {.inline.} = 
@@ -138,43 +139,43 @@ proc kind*(my: XmlParser): XmlEventKind {.inline.} =
   ## returns the current event type for the XML parser
   return my.kind
 
-proc charData*(my: XmlParser): string {.inline.} = 
+template charData*(my: XmlParser): string =
   ## returns the character data for the events: ``xmlCharData``, 
   ## ``xmlWhitespace``, ``xmlComment``, ``xmlCData``, ``xmlSpecial``
   assert(my.kind in {xmlCharData, xmlWhitespace, xmlComment, xmlCData, 
                      xmlSpecial})
-  return my.a
+  my.a
 
-proc elementName*(my: XmlParser): string {.inline.} = 
+template elementName*(my: XmlParser): string =
   ## returns the element name for the events: ``xmlElementStart``, 
   ## ``xmlElementEnd``, ``xmlElementOpen``
   assert(my.kind in {xmlElementStart, xmlElementEnd, xmlElementOpen})
-  return my.a
+  my.a
 
-proc entityName*(my: XmlParser): string {.inline.} = 
+template entityName*(my: XmlParser): string =
   ## returns the entity name for the event: ``xmlEntity``
   assert(my.kind == xmlEntity)
-  return my.a
+  my.a
   
-proc attrKey*(my: XmlParser): string {.inline.} = 
+template attrKey*(my: XmlParser): string =
   ## returns the attribute key for the event ``xmlAttribute``
   assert(my.kind == xmlAttribute)
-  return my.a
+  my.a
   
-proc attrValue*(my: XmlParser): string {.inline.} = 
+template attrValue*(my: XmlParser): string =
   ## returns the attribute value for the event ``xmlAttribute``
   assert(my.kind == xmlAttribute)
-  return my.b
+  my.b
 
-proc piName*(my: XmlParser): string {.inline.} = 
+template piName*(my: XmlParser): string =
   ## returns the processing instruction name for the event ``xmlPI``
   assert(my.kind == xmlPI)
-  return my.a
+  my.a
 
-proc piRest*(my: XmlParser): string {.inline.} = 
+template piRest*(my: XmlParser): string =
   ## returns the rest of the processing instruction for the event ``xmlPI``
   assert(my.kind == xmlPI)
-  return my.b
+  my.b
 
 proc rawData*(my: XmlParser): string {.inline.} =
   ## returns the underlying 'data' string by reference.
@@ -621,13 +622,13 @@ proc next*(my: var XmlParser) =
   of stateEmptyElementTag:
     my.state = stateNormal
     my.kind = xmlElementEnd
-    if not isNil(my.c):
+    if not my.c.isNil:
       my.a = my.c
   of stateError: 
     my.kind = xmlError
     my.state = stateNormal
   
-when isMainModule:
+when not defined(testing) and isMainModule:
   import os
   var s = newFileStream(paramStr(1), fmRead)
   if s == nil: quit("cannot open the file" & paramStr(1))
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index 6eb7dee78..39f0bfa95 100644
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -28,8 +28,8 @@ when useUnicode:
 
 const
   InlineThreshold = 5  ## number of leaves; -1 to disable inlining
-  MaxSubpatterns* = 10 ## defines the maximum number of subpatterns that
-                       ## can be captured. More subpatterns cannot be captured! 
+  MaxSubpatterns* = 20 ## defines the maximum number of subpatterns that
+                       ## can be captured. More subpatterns cannot be captured!
 
 type
   PegKind = enum
@@ -85,14 +85,14 @@ type
     of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns]
     else: sons: seq[TNode]
   NonTerminal* = ref NonTerminalObj
-  
+
   Peg* = TNode ## type that represents a PEG
 
 {.deprecated: [TPeg: Peg].}
 
 proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} =
   ## constructs a PEG from a terminal string
-  if t.len != 1:  
+  if t.len != 1:
     result.kind = pkTerminal
     result.term = t
   else:
@@ -116,7 +116,7 @@ proc term*(t: char): Peg {.nosideEffect, rtl, extern: "npegs$1Char".} =
   assert t != '\0'
   result.kind = pkChar
   result.ch = t
-  
+
 proc charSet*(s: set[char]): Peg {.nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a PEG from a character set `s`
   assert '\0' notin s
@@ -129,12 +129,12 @@ proc add(d: var Peg, s: Peg) {.inline.} = add(d.sons, s)
 
 proc addChoice(dest: var Peg, elem: Peg) =
   var L = dest.len-1
-  if L >= 0 and dest.sons[L].kind == pkCharChoice: 
+  if L >= 0 and dest.sons[L].kind == pkCharChoice:
     # caution! Do not introduce false aliasing here!
     case elem.kind
     of pkCharChoice:
       dest.sons[L] = charSet(dest.sons[L].charChoice[] + elem.charChoice[])
-    of pkChar: 
+    of pkChar:
       dest.sons[L] = charSet(dest.sons[L].charChoice[] + {elem.ch})
     else: add(dest, elem)
   else: add(dest, elem)
@@ -158,12 +158,12 @@ proc `/`*(a: varargs[Peg]): Peg {.
 
 proc addSequence(dest: var Peg, elem: Peg) =
   var L = dest.len-1
-  if L >= 0 and dest.sons[L].kind == pkTerminal: 
+  if L >= 0 and dest.sons[L].kind == pkTerminal:
     # caution! Do not introduce false aliasing here!
     case elem.kind
-    of pkTerminal: 
+    of pkTerminal:
       dest.sons[L] = term(dest.sons[L].term & elem.term)
-    of pkChar: 
+    of pkChar:
       dest.sons[L] = term(dest.sons[L].term & elem.ch)
     else: add(dest, elem)
   else: add(dest, elem)
@@ -172,7 +172,7 @@ proc sequence*(a: varargs[Peg]): Peg {.
   nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a sequence with all the PEGs from `a`
   multipleOp(pkSequence, addSequence)
- 
+
 proc `?`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsOptional".} =
   ## constructs an optional for the PEG `a`
   if a.kind in {pkOption, pkGreedyRep, pkGreedyAny, pkGreedyRepChar,
@@ -207,7 +207,7 @@ proc `!*`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsSearch".} =
   result.kind = pkSearch
   result.sons = @[a]
 
-proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl, 
+proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl,
                              extern: "npgegsCapturedSearch".} =
   ## constructs a "captured search" for the PEG `a`
   result.kind = pkCapturedSearch
@@ -216,7 +216,7 @@ proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl,
 proc `+`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsGreedyPosRep".} =
   ## constructs a "greedy positive repetition" with the PEG `a`
   return sequence(a, *a)
-  
+
 proc `&`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsAndPredicate".} =
   ## constructs an "and predicate" with the PEG `a`
   result.kind = pkAndPredicate
@@ -239,33 +239,33 @@ proc newLine*: Peg {.inline.} =
   ## constructs the PEG `newline`:idx: (``\n``)
   result.kind = pkNewLine
 
-proc unicodeLetter*: Peg {.inline.} = 
+proc unicodeLetter*: Peg {.inline.} =
   ## constructs the PEG ``\letter`` which matches any Unicode letter.
   result.kind = pkLetter
-  
-proc unicodeLower*: Peg {.inline.} = 
+
+proc unicodeLower*: Peg {.inline.} =
   ## constructs the PEG ``\lower`` which matches any Unicode lowercase letter.
-  result.kind = pkLower 
+  result.kind = pkLower
 
-proc unicodeUpper*: Peg {.inline.} = 
+proc unicodeUpper*: Peg {.inline.} =
   ## constructs the PEG ``\upper`` which matches any Unicode uppercase letter.
   result.kind = pkUpper
-  
-proc unicodeTitle*: Peg {.inline.} = 
+
+proc unicodeTitle*: Peg {.inline.} =
   ## constructs the PEG ``\title`` which matches any Unicode title letter.
   result.kind = pkTitle
 
-proc unicodeWhitespace*: Peg {.inline.} = 
-  ## constructs the PEG ``\white`` which matches any Unicode 
+proc unicodeWhitespace*: Peg {.inline.} =
+  ## constructs the PEG ``\white`` which matches any Unicode
   ## whitespace character.
   result.kind = pkWhitespace
 
-proc startAnchor*: Peg {.inline.} = 
-  ## constructs the PEG ``^`` which matches the start of the input.  
+proc startAnchor*: Peg {.inline.} =
+  ## constructs the PEG ``^`` which matches the start of the input.
   result.kind = pkStartAnchor
 
-proc endAnchor*: Peg {.inline.} = 
-  ## constructs the PEG ``$`` which matches the end of the input.  
+proc endAnchor*: Peg {.inline.} =
+  ## constructs the PEG ``$`` which matches the end of the input.
   result = !any()
 
 proc capture*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsCapture".} =
@@ -274,21 +274,21 @@ proc capture*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsCapture".} =
   result.sons = @[a]
 
 proc backref*(index: range[1..MaxSubpatterns]): Peg {.
-  nosideEffect, rtl, extern: "npegs$1".} = 
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a back reference of the given `index`. `index` starts counting
   ## from 1.
   result.kind = pkBackRef
   result.index = index-1
 
 proc backrefIgnoreCase*(index: range[1..MaxSubpatterns]): Peg {.
-  nosideEffect, rtl, extern: "npegs$1".} = 
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a back reference of the given `index`. `index` starts counting
   ## from 1. Ignores case for matching.
   result.kind = pkBackRefIgnoreCase
   result.index = index-1
 
 proc backrefIgnoreStyle*(index: range[1..MaxSubpatterns]): Peg {.
-  nosideEffect, rtl, extern: "npegs$1".}= 
+  nosideEffect, rtl, extern: "npegs$1".}=
   ## constructs a back reference of the given `index`. `index` starts counting
   ## from 1. Ignores style for matching.
   result.kind = pkBackRefIgnoreStyle
@@ -298,7 +298,7 @@ proc spaceCost(n: Peg): int =
   case n.kind
   of pkEmpty: discard
   of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar,
-     pkGreedyRepChar, pkCharChoice, pkGreedyRepSet, 
+     pkGreedyRepChar, pkCharChoice, pkGreedyRepSet,
      pkAny..pkWhitespace, pkGreedyAny:
     result = 1
   of pkNonTerminal:
@@ -310,7 +310,7 @@ proc spaceCost(n: Peg): int =
       if result >= InlineThreshold: break
 
 proc nonterminal*(n: NonTerminal): Peg {.
-  nosideEffect, rtl, extern: "npegs$1".} = 
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## constructs a PEG that consists of the nonterminal symbol
   assert n != nil
   if ntDeclared in n.flags and spaceCost(n.rule) < InlineThreshold:
@@ -331,7 +331,7 @@ proc newNonTerminal*(name: string, line, column: int): NonTerminal {.
 template letters*: expr =
   ## expands to ``charset({'A'..'Z', 'a'..'z'})``
   charSet({'A'..'Z', 'a'..'z'})
-  
+
 template digits*: expr =
   ## expands to ``charset({'0'..'9'})``
   charSet({'0'..'9'})
@@ -339,11 +339,11 @@ template digits*: expr =
 template whitespace*: expr =
   ## expands to ``charset({' ', '\9'..'\13'})``
   charSet({' ', '\9'..'\13'})
-  
+
 template identChars*: expr =
   ## expands to ``charset({'a'..'z', 'A'..'Z', '0'..'9', '_'})``
   charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'})
-  
+
 template identStartChars*: expr =
   ## expands to ``charset({'A'..'Z', 'a'..'z', '_'})``
   charSet({'a'..'z', 'A'..'Z', '_'})
@@ -352,14 +352,14 @@ template ident*: expr =
   ## same as ``[a-zA-Z_][a-zA-z_0-9]*``; standard identifier
   sequence(charSet({'a'..'z', 'A'..'Z', '_'}),
            *charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'}))
-  
+
 template natural*: expr =
   ## same as ``\d+``
   +digits
 
 # ------------------------- debugging -----------------------------------------
 
-proc esc(c: char, reserved = {'\0'..'\255'}): string = 
+proc esc(c: char, reserved = {'\0'..'\255'}): string =
   case c
   of '\b': result = "\\b"
   of '\t': result = "\\t"
@@ -374,38 +374,38 @@ proc esc(c: char, reserved = {'\0'..'\255'}): string =
   elif c < ' ' or c >= '\128': result = '\\' & $ord(c)
   elif c in reserved: result = '\\' & c
   else: result = $c
-  
+
 proc singleQuoteEsc(c: char): string = return "'" & esc(c, {'\''}) & "'"
 
-proc singleQuoteEsc(str: string): string = 
+proc singleQuoteEsc(str: string): string =
   result = "'"
   for c in items(str): add result, esc(c, {'\''})
   add result, '\''
-  
-proc charSetEscAux(cc: set[char]): string = 
+
+proc charSetEscAux(cc: set[char]): string =
   const reserved = {'^', '-', ']'}
   result = ""
   var c1 = 0
-  while c1 <= 0xff: 
-    if chr(c1) in cc: 
+  while c1 <= 0xff:
+    if chr(c1) in cc:
       var c2 = c1
       while c2 < 0xff and chr(succ(c2)) in cc: inc(c2)
-      if c1 == c2: 
+      if c1 == c2:
         add result, esc(chr(c1), reserved)
-      elif c2 == succ(c1): 
+      elif c2 == succ(c1):
         add result, esc(chr(c1), reserved) & esc(chr(c2), reserved)
-      else: 
+      else:
         add result, esc(chr(c1), reserved) & '-' & esc(chr(c2), reserved)
       c1 = c2
     inc(c1)
-  
+
 proc charSetEsc(cc: set[char]): string =
-  if card(cc) >= 128+64: 
+  if card(cc) >= 128+64:
     result = "[^" & charSetEscAux({'\1'..'\xFF'} - cc) & ']'
-  else: 
+  else:
     result = '[' & charSetEscAux(cc) & ']'
-  
-proc toStrAux(r: Peg, res: var string) = 
+
+proc toStrAux(r: Peg, res: var string) =
   case r.kind
   of pkEmpty: add(res, "()")
   of pkAny: add(res, '.')
@@ -469,25 +469,25 @@ proc toStrAux(r: Peg, res: var string) =
     toStrAux(r.sons[0], res)
   of pkCapture:
     add(res, '{')
-    toStrAux(r.sons[0], res)    
+    toStrAux(r.sons[0], res)
     add(res, '}')
-  of pkBackRef: 
+  of pkBackRef:
     add(res, '$')
     add(res, $r.index)
-  of pkBackRefIgnoreCase: 
+  of pkBackRefIgnoreCase:
     add(res, "i$")
     add(res, $r.index)
-  of pkBackRefIgnoreStyle: 
+  of pkBackRefIgnoreStyle:
     add(res, "y$")
     add(res, $r.index)
   of pkRule:
-    toStrAux(r.sons[0], res)    
+    toStrAux(r.sons[0], res)
     add(res, " <- ")
     toStrAux(r.sons[1], res)
   of pkList:
     for i in 0 .. high(r.sons):
       toStrAux(r.sons[i], res)
-      add(res, "\n")  
+      add(res, "\n")
   of pkStartAnchor:
     add(res, '^')
 
@@ -506,14 +506,14 @@ type
 
 {.deprecated: [TCaptures: Captures].}
 
-proc bounds*(c: Captures, 
-             i: range[0..MaxSubpatterns-1]): tuple[first, last: int] = 
+proc bounds*(c: Captures,
+             i: range[0..MaxSubpatterns-1]): tuple[first, last: int] =
   ## returns the bounds ``[first..last]`` of the `i`'th capture.
   result = c.matches[i]
 
 when not useUnicode:
   type
-    TRune = char
+    Rune = char
   template fastRuneAt(s, i, ch: expr) =
     ch = s[i]
     inc(i)
@@ -527,7 +527,7 @@ when not useUnicode:
 
 proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
                nosideEffect, rtl, extern: "npegs$1".} =
-  ## low-level matching proc that implements the PEG interpreter. Use this 
+  ## low-level matching proc that implements the PEG interpreter. Use this
   ## for maximum efficiency (every other PEG operation ends up calling this
   ## proc).
   ## Returns -1 if it does not match, else the length of the match
@@ -541,7 +541,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
       result = runeLenAt(s, start)
     else:
       result = -1
-  of pkLetter: 
+  of pkLetter:
     if s[start] != '\0':
       var a: Rune
       result = start
@@ -550,7 +550,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
       else: result = -1
     else:
       result = -1
-  of pkLower: 
+  of pkLower:
     if s[start] != '\0':
       var a: Rune
       result = start
@@ -559,7 +559,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
       else: result = -1
     else:
       result = -1
-  of pkUpper: 
+  of pkUpper:
     if s[start] != '\0':
       var a: Rune
       result = start
@@ -568,16 +568,16 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
       else: result = -1
     else:
       result = -1
-  of pkTitle: 
+  of pkTitle:
     if s[start] != '\0':
       var a: Rune
       result = start
       fastRuneAt(s, result, a)
-      if isTitle(a): dec(result, start) 
+      if isTitle(a): dec(result, start)
       else: result = -1
     else:
       result = -1
-  of pkWhitespace: 
+  of pkWhitespace:
     if s[start] != '\0':
       var a: Rune
       result = start
@@ -641,7 +641,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
     when false: echo "leave: ", p.nt.name
     if result < 0: c.ml = oldMl
   of pkSequence:
-    var oldMl = c.ml  
+    var oldMl = c.ml
     result = 0
     for i in 0..high(p.sons):
       var x = rawMatch(s, p.sons[i], start+result, c)
@@ -723,11 +723,11 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
       #else: silently ignore the capture
     else:
       c.ml = idx
-  of pkBackRef..pkBackRefIgnoreStyle: 
+  of pkBackRef..pkBackRefIgnoreStyle:
     if p.index >= c.ml: return -1
     var (a, b) = c.matches[p.index]
     var n: Peg
-    n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef)) 
+    n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef))
     n.term = s.substr(a, b)
     result = rawMatch(s, n, start, c)
   of pkStartAnchor:
@@ -744,24 +744,6 @@ template fillMatches(s, caps, c: expr) =
     else:
       caps[k] = nil
 
-proc match*(s: string, pattern: Peg, matches: var openArray[string],
-            start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} =
-  ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and
-  ## the captured substrings in the array ``matches``. If it does not
-  ## match, nothing is written into ``matches`` and ``false`` is
-  ## returned.
-  var c: Captures
-  c.origStart = start
-  result = rawMatch(s, pattern, start, c) == len(s) - start
-  if result: fillMatches(s, matches, c)
-
-proc match*(s: string, pattern: Peg, 
-            start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} =
-  ## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``.
-  var c: Captures
-  c.origStart = start
-  result = rawMatch(s, pattern, start, c) == len(s)-start
-
 proc matchLen*(s: string, pattern: Peg, matches: var openArray[string],
                start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
   ## the same as ``match``, but it returns the length of the match,
@@ -773,7 +755,7 @@ proc matchLen*(s: string, pattern: Peg, matches: var openArray[string],
   result = rawMatch(s, pattern, start, c)
   if result >= 0: fillMatches(s, matches, c)
 
-proc matchLen*(s: string, pattern: Peg, 
+proc matchLen*(s: string, pattern: Peg,
                start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
   ## the same as ``match``, but it returns the length of the match,
   ## if there is no match, -1 is returned. Note that a match length
@@ -783,6 +765,20 @@ proc matchLen*(s: string, pattern: Peg,
   c.origStart = start
   result = rawMatch(s, pattern, start, c)
 
+proc match*(s: string, pattern: Peg, matches: var openArray[string],
+            start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} =
+  ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and
+  ## the captured substrings in the array ``matches``. If it does not
+  ## match, nothing is written into ``matches`` and ``false`` is
+  ## returned.
+  result = matchLen(s, pattern, matches, start) != -1
+
+proc match*(s: string, pattern: Peg,
+            start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} =
+  ## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``.
+  result = matchLen(s, pattern, start) != -1
+
+
 proc find*(s: string, pattern: Peg, matches: var openArray[string],
            start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
   ## returns the starting position of ``pattern`` in ``s`` and the captured
@@ -797,11 +793,11 @@ proc find*(s: string, pattern: Peg, matches: var openArray[string],
       return i
   return -1
   # could also use the pattern here: (!P .)* P
-  
+
 proc findBounds*(s: string, pattern: Peg, matches: var openArray[string],
                  start = 0): tuple[first, last: int] {.
                  nosideEffect, rtl, extern: "npegs$1Capture".} =
-  ## returns the starting position and end position of ``pattern`` in ``s`` 
+  ## returns the starting position and end position of ``pattern`` in ``s``
   ## and the captured
   ## substrings in the array ``matches``. If it does not match, nothing
   ## is written into ``matches`` and (-1,0) is returned.
@@ -814,8 +810,8 @@ proc findBounds*(s: string, pattern: Peg, matches: var openArray[string],
       fillMatches(s, matches, c)
       return (i, i+L-1)
   return (-1, 0)
-  
-proc find*(s: string, pattern: Peg, 
+
+proc find*(s: string, pattern: Peg,
            start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
   ## returns the starting position of ``pattern`` in ``s``. If it does not
   ## match, -1 is returned.
@@ -824,8 +820,8 @@ proc find*(s: string, pattern: Peg,
   for i in start .. s.len-1:
     if rawMatch(s, pattern, i, c) >= 0: return i
   return -1
-  
-iterator findAll*(s: string, pattern: Peg, start = 0): string = 
+
+iterator findAll*(s: string, pattern: Peg, start = 0): string =
   ## yields all matching *substrings* of `s` that match `pattern`.
   var c: Captures
   c.origStart = start
@@ -838,23 +834,23 @@ iterator findAll*(s: string, pattern: Peg, start = 0): string =
     else:
       yield substr(s, i, i+L-1)
       inc(i, L)
-    
+
 proc findAll*(s: string, pattern: Peg, start = 0): seq[string] {.
-  nosideEffect, rtl, extern: "npegs$1".} = 
+  nosideEffect, rtl, extern: "npegs$1".} =
   ## returns all matching *substrings* of `s` that match `pattern`.
   ## If it does not match, @[] is returned.
   accumulateResult(findAll(s, pattern, start))
 
 when not defined(nimhygiene):
   {.pragma: inject.}
-  
+
 template `=~`*(s: string, pattern: Peg): bool =
-  ## This calls ``match`` with an implicit declared ``matches`` array that 
-  ## can be used in the scope of the ``=~`` call: 
-  ## 
+  ## This calls ``match`` with an implicit declared ``matches`` array that
+  ## can be used in the scope of the ``=~`` call:
+  ##
   ## .. code-block:: nim
   ##
-  ##   if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}": 
+  ##   if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}":
   ##     # matches a key=value pair:
   ##     echo("Key: ", matches[0])
   ##     echo("Value: ", matches[1])
@@ -865,7 +861,7 @@ template `=~`*(s: string, pattern: Peg): bool =
   ##     echo("comment: ", matches[0])
   ##   else:
   ##     echo("syntax error")
-  ##  
+  ##
   bind MaxSubpatterns
   when not declaredInScope(matches):
     var matches {.inject.}: array[0..MaxSubpatterns-1, string]
@@ -902,7 +898,7 @@ proc replacef*(s: string, sub: Peg, by: string): string {.
   ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
   ##
   ## .. code-block:: nim
-  ##   "var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2")
+  ##   "var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2")
   ##
   ## Results in:
   ##
@@ -941,10 +937,10 @@ proc replace*(s: string, sub: Peg, by = ""): string {.
       add(result, by)
       inc(i, x)
   add(result, substr(s, i))
-  
+
 proc parallelReplace*(s: string, subs: varargs[
                       tuple[pattern: Peg, repl: string]]): string {.
-                      nosideEffect, rtl, extern: "npegs$1".} = 
+                      nosideEffect, rtl, extern: "npegs$1".} =
   ## Returns a modified copy of `s` with the substitutions in `subs`
   ## applied in parallel.
   result = ""
@@ -964,8 +960,8 @@ proc parallelReplace*(s: string, subs: varargs[
       add(result, s[i])
       inc(i)
   # copy the rest:
-  add(result, substr(s, i))  
-  
+  add(result, substr(s, i))
+
 proc transformFile*(infile, outfile: string,
                     subs: varargs[tuple[pattern: Peg, repl: string]]) {.
                     rtl, extern: "npegs$1".} =
@@ -974,7 +970,7 @@ proc transformFile*(infile, outfile: string,
   ## error occurs. This is supposed to be used for quick scripting.
   var x = readFile(infile).string
   writeFile(outfile, x.parallelReplace(subs))
-  
+
 iterator split*(s: string, sep: Peg): string =
   ## Splits the string `s` into substrings.
   ##
@@ -1049,14 +1045,14 @@ type
     tkBackref,          ## '$'
     tkDollar,           ## '$'
     tkHat               ## '^'
-  
+
   TToken {.final.} = object  ## a token
     kind: TTokKind           ## the type of the token
     modifier: TModifier
     literal: string          ## the parsed (string) literal
     charset: set[char]       ## if kind == tkCharSet
     index: int               ## if kind == tkBackref
-  
+
   PegLexer {.inheritable.} = object          ## the lexer object.
     bufpos: int               ## the current position within the buffer
     buf: cstring              ## the buffer itself
@@ -1086,7 +1082,7 @@ proc handleLF(L: var PegLexer, pos: int): int =
   result = pos+1
   L.lineStart = result
 
-proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) = 
+proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) =
   L.buf = input
   L.bufpos = 0
   L.lineNumber = line
@@ -1094,69 +1090,69 @@ proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) =
   L.lineStart = 0
   L.filename = filename
 
-proc getColumn(L: PegLexer): int {.inline.} = 
+proc getColumn(L: PegLexer): int {.inline.} =
   result = abs(L.bufpos - L.lineStart) + L.colOffset
 
-proc getLine(L: PegLexer): int {.inline.} = 
+proc getLine(L: PegLexer): int {.inline.} =
   result = L.lineNumber
-  
+
 proc errorStr(L: PegLexer, msg: string, line = -1, col = -1): string =
   var line = if line < 0: getLine(L) else: line
   var col = if col < 0: getColumn(L) else: col
   result = "$1($2, $3) Error: $4" % [L.filename, $line, $col, msg]
 
-proc handleHexChar(c: var PegLexer, xi: var int) = 
+proc handleHexChar(c: var PegLexer, xi: var int) =
   case c.buf[c.bufpos]
-  of '0'..'9': 
+  of '0'..'9':
     xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'))
     inc(c.bufpos)
-  of 'a'..'f': 
+  of 'a'..'f':
     xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10)
     inc(c.bufpos)
-  of 'A'..'F': 
+  of 'A'..'F':
     xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
     inc(c.bufpos)
   else: discard
 
-proc getEscapedChar(c: var PegLexer, tok: var TToken) = 
+proc getEscapedChar(c: var PegLexer, tok: var TToken) =
   inc(c.bufpos)
   case c.buf[c.bufpos]
-  of 'r', 'R', 'c', 'C': 
+  of 'r', 'R', 'c', 'C':
     add(tok.literal, '\c')
     inc(c.bufpos)
-  of 'l', 'L': 
+  of 'l', 'L':
     add(tok.literal, '\L')
     inc(c.bufpos)
-  of 'f', 'F': 
+  of 'f', 'F':
     add(tok.literal, '\f')
     inc(c.bufpos)
-  of 'e', 'E': 
+  of 'e', 'E':
     add(tok.literal, '\e')
     inc(c.bufpos)
-  of 'a', 'A': 
+  of 'a', 'A':
     add(tok.literal, '\a')
     inc(c.bufpos)
-  of 'b', 'B': 
+  of 'b', 'B':
     add(tok.literal, '\b')
     inc(c.bufpos)
-  of 'v', 'V': 
+  of 'v', 'V':
     add(tok.literal, '\v')
     inc(c.bufpos)
-  of 't', 'T': 
+  of 't', 'T':
     add(tok.literal, '\t')
     inc(c.bufpos)
-  of 'x', 'X': 
+  of 'x', 'X':
     inc(c.bufpos)
     var xi = 0
     handleHexChar(c, xi)
     handleHexChar(c, xi)
     if xi == 0: tok.kind = tkInvalid
     else: add(tok.literal, chr(xi))
-  of '0'..'9': 
+  of '0'..'9':
     var val = ord(c.buf[c.bufpos]) - ord('0')
     inc(c.bufpos)
     var i = 1
-    while (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}): 
+    while (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}):
       val = val * 10 + ord(c.buf[c.bufpos]) - ord('0')
       inc(c.bufpos)
       inc(i)
@@ -1169,32 +1165,32 @@ proc getEscapedChar(c: var PegLexer, tok: var TToken) =
   else:
     add(tok.literal, c.buf[c.bufpos])
     inc(c.bufpos)
-  
-proc skip(c: var PegLexer) = 
+
+proc skip(c: var PegLexer) =
   var pos = c.bufpos
   var buf = c.buf
-  while true: 
+  while true:
     case buf[pos]
-    of ' ', '\t': 
+    of ' ', '\t':
       inc(pos)
     of '#':
       while not (buf[pos] in {'\c', '\L', '\0'}): inc(pos)
     of '\c':
       pos = handleCR(c, pos)
       buf = c.buf
-    of '\L': 
+    of '\L':
       pos = handleLF(c, pos)
       buf = c.buf
-    else: 
+    else:
       break                   # EndOfFile also leaves the loop
   c.bufpos = pos
-  
-proc getString(c: var PegLexer, tok: var TToken) = 
+
+proc getString(c: var PegLexer, tok: var TToken) =
   tok.kind = tkStringLit
   var pos = c.bufpos + 1
   var buf = c.buf
   var quote = buf[pos-1]
-  while true: 
+  while true:
     case buf[pos]
     of '\\':
       c.bufpos = pos
@@ -1205,13 +1201,13 @@ proc getString(c: var PegLexer, tok: var TToken) =
       break
     elif buf[pos] == quote:
       inc(pos)
-      break      
+      break
     else:
       add(tok.literal, buf[pos])
       inc(pos)
   c.bufpos = pos
-  
-proc getDollar(c: var PegLexer, tok: var TToken) = 
+
+proc getDollar(c: var PegLexer, tok: var TToken) =
   var pos = c.bufpos + 1
   var buf = c.buf
   if buf[pos] in {'0'..'9'}:
@@ -1223,8 +1219,8 @@ proc getDollar(c: var PegLexer, tok: var TToken) =
   else:
     tok.kind = tkDollar
   c.bufpos = pos
-  
-proc getCharSet(c: var PegLexer, tok: var TToken) = 
+
+proc getCharSet(c: var PegLexer, tok: var TToken) =
   tok.kind = tkCharSet
   tok.charset = {}
   var pos = c.bufpos + 1
@@ -1247,7 +1243,7 @@ proc getCharSet(c: var PegLexer, tok: var TToken) =
     of '\C', '\L', '\0':
       tok.kind = tkInvalid
       break
-    else: 
+    else:
       ch = buf[pos]
       inc(pos)
     incl(tok.charset, ch)
@@ -1267,18 +1263,18 @@ proc getCharSet(c: var PegLexer, tok: var TToken) =
         of '\C', '\L', '\0':
           tok.kind = tkInvalid
           break
-        else: 
+        else:
           ch2 = buf[pos]
           inc(pos)
         for i in ord(ch)+1 .. ord(ch2):
           incl(tok.charset, chr(i))
   c.bufpos = pos
   if caret: tok.charset = {'\1'..'\xFF'} - tok.charset
-  
-proc getSymbol(c: var PegLexer, tok: var TToken) = 
+
+proc getSymbol(c: var PegLexer, tok: var TToken) =
   var pos = c.bufpos
   var buf = c.buf
-  while true: 
+  while true:
     add(tok.literal, buf[pos])
     inc(pos)
     if buf[pos] notin strutils.IdentChars: break
@@ -1294,7 +1290,7 @@ proc getBuiltin(c: var PegLexer, tok: var TToken) =
     tok.kind = tkEscaped
     getEscapedChar(c, tok) # may set tok.kind to tkInvalid
 
-proc getTok(c: var PegLexer, tok: var TToken) = 
+proc getTok(c: var PegLexer, tok: var TToken) =
   tok.kind = tkInvalid
   tok.modifier = modNone
   setLen(tok.literal, 0)
@@ -1309,11 +1305,11 @@ proc getTok(c: var PegLexer, tok: var TToken) =
     else:
       tok.kind = tkCurlyLe
       add(tok.literal, '{')
-  of '}': 
+  of '}':
     tok.kind = tkCurlyRi
     inc(c.bufpos)
     add(tok.literal, '}')
-  of '[': 
+  of '[':
     getCharSet(c, tok)
   of '(':
     tok.kind = tkParLe
@@ -1323,7 +1319,7 @@ proc getTok(c: var PegLexer, tok: var TToken) =
     tok.kind = tkParRi
     inc(c.bufpos)
     add(tok.literal, ')')
-  of '.': 
+  of '.':
     tok.kind = tkAny
     inc(c.bufpos)
     add(tok.literal, '.')
@@ -1331,16 +1327,16 @@ proc getTok(c: var PegLexer, tok: var TToken) =
     tok.kind = tkAnyRune
     inc(c.bufpos)
     add(tok.literal, '_')
-  of '\\': 
+  of '\\':
     getBuiltin(c, tok)
   of '\'', '"': getString(c, tok)
   of '$': getDollar(c, tok)
-  of '\0': 
+  of '\0':
     tok.kind = tkEof
     tok.literal = "[EOF]"
   of 'a'..'z', 'A'..'Z', '\128'..'\255':
     getSymbol(c, tok)
-    if c.buf[c.bufpos] in {'\'', '"'} or 
+    if c.buf[c.bufpos] in {'\'', '"'} or
         c.buf[c.bufpos] == '$' and c.buf[c.bufpos+1] in {'0'..'9'}:
       case tok.literal
       of "i": tok.modifier = modIgnoreCase
@@ -1388,7 +1384,7 @@ proc getTok(c: var PegLexer, tok: var TToken) =
     tok.kind = tkAt
     inc(c.bufpos)
     add(tok.literal, '@')
-    if c.buf[c.bufpos] == '@': 
+    if c.buf[c.bufpos] == '@':
       tok.kind = tkCurlyAt
       inc(c.bufpos)
       add(tok.literal, '@')
@@ -1407,7 +1403,7 @@ proc arrowIsNextTok(c: PegLexer): bool =
   result = c.buf[pos] == '<' and c.buf[pos+1] == '-'
 
 # ----------------------------- parser ----------------------------------------
-    
+
 type
   EInvalidPeg* = object of ValueError ## raised if an invalid
                                          ## PEG has been detected
@@ -1425,7 +1421,7 @@ proc pegError(p: PegParser, msg: string, line = -1, col = -1) =
   e.msg = errorStr(p, msg, line, col)
   raise e
 
-proc getTok(p: var PegParser) = 
+proc getTok(p: var PegParser) =
   getTok(p, p.tok)
   if p.tok.kind == tkInvalid: pegError(p, "invalid token")
 
@@ -1433,7 +1429,7 @@ proc eat(p: var PegParser, kind: TTokKind) =
   if p.tok.kind == kind: getTok(p)
   else: pegError(p, tokKindToStr[kind] & " expected")
 
-proc parseExpr(p: var PegParser): Peg
+proc parseExpr(p: var PegParser): Peg {.gcsafe.}
 
 proc getNonTerminal(p: var PegParser, name: string): NonTerminal =
   for i in 0..high(p.nonterms):
@@ -1475,7 +1471,7 @@ proc builtin(p: var PegParser): Peg =
   of "white": result = unicodeWhitespace()
   else: pegError(p, "unknown built-in: " & p.tok.literal)
 
-proc token(terminal: Peg, p: PegParser): Peg = 
+proc token(terminal: Peg, p: PegParser): Peg =
   if p.skip.kind == pkEmpty: result = terminal
   else: result = sequence(p.skip, terminal)
 
@@ -1496,7 +1492,7 @@ proc primary(p: var PegParser): Peg =
   else: discard
   case p.tok.kind
   of tkIdentifier:
-    if p.identIsVerbatim: 
+    if p.identIsVerbatim:
       var m = p.tok.modifier
       if m == modNone: m = p.modifier
       result = modifiedTerm(p.tok.literal, m).token(p)
@@ -1539,17 +1535,17 @@ proc primary(p: var PegParser): Peg =
   of tkEscaped:
     result = term(p.tok.literal[0]).token(p)
     getTok(p)
-  of tkDollar: 
+  of tkDollar:
     result = endAnchor()
     getTok(p)
-  of tkHat: 
+  of tkHat:
     result = startAnchor()
     getTok(p)
   of tkBackref:
     var m = p.tok.modifier
     if m == modNone: m = p.modifier
     result = modifiedBackref(p.tok.index, m).token(p)
-    if p.tok.index < 0 or p.tok.index > p.captures: 
+    if p.tok.index < 0 or p.tok.index > p.captures:
       pegError(p, "invalid back reference index: " & $p.tok.index)
     getTok(p)
   else:
@@ -1573,7 +1569,7 @@ proc seqExpr(p: var PegParser): Peg =
   while true:
     case p.tok.kind
     of tkAmp, tkNot, tkAt, tkStringLit, tkCharSet, tkParLe, tkCurlyLe,
-       tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref, 
+       tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref,
        tkHat, tkCurlyAt:
       result = sequence(result, primary(p))
     of tkIdentifier:
@@ -1587,7 +1583,7 @@ proc parseExpr(p: var PegParser): Peg =
   while p.tok.kind == tkBar:
     getTok(p)
     result = result / seqExpr(p)
-  
+
 proc parseRule(p: var PegParser): NonTerminal =
   if p.tok.kind == tkIdentifier and arrowIsNextTok(p):
     result = getNonTerminal(p, p.tok.literal)
@@ -1601,7 +1597,7 @@ proc parseRule(p: var PegParser): NonTerminal =
     incl(result.flags, ntDeclared) # NOW inlining may be attempted
   else:
     pegError(p, "rule expected, but found: " & p.tok.literal)
-  
+
 proc rawParse(p: var PegParser): Peg =
   ## parses a rule or a PEG expression
   while p.tok.kind == tkBuiltin:
@@ -1680,27 +1676,29 @@ when isMainModule:
   assert(not match("W_HI_L", peg"\y 'while'"))
   assert(not match("W_HI_Le", peg"\y v'while'"))
   assert match("W_HI_Le", peg"y'while'")
-  
+
   assert($ +digits == $peg"\d+")
   assert "0158787".match(peg"\d+")
   assert "ABC 0232".match(peg"\w+\s+\d+")
   assert "ABC".match(peg"\d+ / \w+")
 
+  var accum: seq[string] = @[]
   for word in split("00232this02939is39an22example111", peg"\d+"):
-    writeln(stdout, word)
+    accum.add(word)
+  assert(accum == @["this", "is", "an", "example"])
 
   assert matchLen("key", ident) == 3
 
   var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident)
   assert matchLen("key1=  cal9", pattern) == 11
-  
+
   var ws = newNonTerminal("ws", 1, 1)
   ws.rule = *whitespace
-  
+
   var expr = newNonTerminal("expr", 1, 1)
   expr.rule = sequence(capture(ident), *sequence(
                 nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr)))
-  
+
   var c: Captures
   var s = "a+b +  c +d+e+f"
   assert rawMatch(s, expr.rule, 0, c) == len(s)
@@ -1722,7 +1720,7 @@ when isMainModule:
     assert matches[0] == "abc"
   else:
     assert false
-  
+
   var g2 = peg"""S <- A B / C D
                  A <- 'a'+
                  B <- 'b'+
@@ -1748,18 +1746,20 @@ when isMainModule:
   else:
     assert false
 
+  accum = @[]
   for x in findAll("abcdef", peg".", 3):
-    echo x
+    accum.add(x)
+  assert(accum == @["d", "e", "f"])
 
   for x in findAll("abcdef", peg"^{.}", 3):
     assert x == "d"
-    
+
   if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')":
     assert matches[0] == "f"
     assert matches[1] == "a, b"
   else:
     assert false
-  
+
   assert match("eine übersicht und außerdem", peg"(\letter \white*)+")
   # ß is not a lower cased letter?!
   assert match("eine übersicht und auerdem", peg"(\lower \white*)+")
@@ -1783,3 +1783,9 @@ when isMainModule:
   if "foo" =~ peg"{'foo'}":
     assert matches[0] == "foo"
   else: assert false
+
+  let empty_test = peg"^\d*"
+  let str = "XYZ"
+
+  assert(str.find(empty_test) == 0)
+  assert(str.match(empty_test))
diff --git a/lib/pure/pegs.nimfix b/lib/pure/pegs.nimfix
index 8dd172a48..15bc95351 100644
--- a/lib/pure/pegs.nimfix
+++ b/lib/pure/pegs.nimfix
@@ -514,7 +514,7 @@ proc bounds*(c: Captures,
 
 when not useUnicode:
   type
-    TRune = char
+    Rune = char
   template fastRuneAt(s, i, ch: expr) =
     ch = s[i]
     inc(i)
diff --git a/lib/pure/poly.nim b/lib/pure/poly.nim
index 286e5a8fd..58dcdc1ad 100644
--- a/lib/pure/poly.nim
+++ b/lib/pure/poly.nim
@@ -58,7 +58,7 @@ proc `[]=` *(p:var Poly;idx:int,v:float)=
     
       
 iterator items*(p:Poly):float=
-  ## Iterates through the corfficients of the polynomial.
+  ## Iterates through the coefficients of the polynomial.
   var i=p.degree
   while i>=0:
     yield p[i]
diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim
new file mode 100644
index 000000000..3b68a2381
--- /dev/null
+++ b/lib/pure/rationals.nim
@@ -0,0 +1,289 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dennis Felsing
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+## This module implements rational numbers, consisting of a numerator `num` and
+## a denominator `den`, both of type int. The denominator can not be 0.
+
+import math
+import hashes
+
+type Rational*[T] = object
+  ## a rational number, consisting of a numerator and denominator
+  num*, den*: T
+
+proc initRational*[T](num, den: T): Rational[T] =
+  ## Create a new rational number.
+  result.num = num
+  result.den = den
+
+proc `//`*[T](num, den: T): Rational[T] = initRational[T](num, den)
+  ## A friendlier version of `initRational`. Example usage:
+  ##
+  ## .. code-block:: nim
+  ##   var x = 1//3 + 1//5
+
+proc `$`*[T](x: Rational[T]): string =
+  ## Turn a rational number into a string.
+  result = $x.num & "/" & $x.den
+
+proc toRational*[T](x: T): Rational[T] =
+  ## Convert some integer `x` to a rational number.
+  result.num = x
+  result.den = 1
+
+proc toFloat*[T](x: Rational[T]): float =
+  ## Convert a rational number `x` to a float.
+  x.num / x.den
+
+proc toInt*[T](x: Rational[T]): int =
+  ## Convert a rational number `x` to an int. Conversion rounds towards 0 if
+  ## `x` does not contain an integer value.
+  x.num div x.den
+
+proc reduce*[T](x: var Rational[T]) =
+  ## Reduce rational `x`.
+  let common = gcd(x.num, x.den)
+  if x.den > 0:
+    x.num = x.num div common
+    x.den = x.den div common
+  elif x.den < 0:
+    x.num = -x.num div common
+    x.den = -x.den div common
+  else:
+    raise newException(DivByZeroError, "division by zero")
+
+proc `+` *[T](x, y: Rational[T]): Rational[T] =
+  ## Add two rational numbers.
+  let common = lcm(x.den, y.den)
+  result.num = common div x.den * x.num + common div y.den * y.num
+  result.den = common
+  reduce(result)
+
+proc `+` *[T](x: Rational[T], y: T): Rational[T] =
+  ## Add rational `x` to int `y`.
+  result.num = x.num + y * x.den
+  result.den = x.den
+
+proc `+` *[T](x: T, y: Rational[T]): Rational[T] =
+  ## Add int `x` to rational `y`.
+  result.num = x * y.den + y.num
+  result.den = y.den
+
+proc `+=` *[T](x: var Rational[T], y: Rational[T]) =
+  ## Add rational `y` to rational `x`.
+  let common = lcm(x.den, y.den)
+  x.num = common div x.den * x.num + common div y.den * y.num
+  x.den = common
+  reduce(x)
+
+proc `+=` *[T](x: var Rational[T], y: T) =
+  ## Add int `y` to rational `x`.
+  x.num += y * x.den
+
+proc `-` *[T](x: Rational[T]): Rational[T] =
+  ## Unary minus for rational numbers.
+  result.num = -x.num
+  result.den = x.den
+
+proc `-` *[T](x, y: Rational[T]): Rational[T] =
+  ## Subtract two rational numbers.
+  let common = lcm(x.den, y.den)
+  result.num = common div x.den * x.num - common div y.den * y.num
+  result.den = common
+  reduce(result)
+
+proc `-` *[T](x: Rational[T], y: T): Rational[T] =
+  ## Subtract int `y` from rational `x`.
+  result.num = x.num - y * x.den
+  result.den = x.den
+
+proc `-` *[T](x: T, y: Rational[T]): Rational[T] =
+  ## Subtract rational `y` from int `x`.
+  result.num = - x * y.den + y.num
+  result.den = y.den
+
+proc `-=` *[T](x: var Rational[T], y: Rational[T]) =
+  ## Subtract rational `y` from rational `x`.
+  let common = lcm(x.den, y.den)
+  x.num = common div x.den * x.num - common div y.den * y.num
+  x.den = common
+  reduce(x)
+
+proc `-=` *[T](x: var Rational[T], y: T) =
+  ## Subtract int `y` from rational `x`.
+  x.num -= y * x.den
+
+proc `*` *[T](x, y: Rational[T]): Rational[T] =
+  ## Multiply two rational numbers.
+  result.num = x.num * y.num
+  result.den = x.den * y.den
+  reduce(result)
+
+proc `*` *[T](x: Rational[T], y: T): Rational[T] =
+  ## Multiply rational `x` with int `y`.
+  result.num = x.num * y
+  result.den = x.den
+  reduce(result)
+
+proc `*` *[T](x: T, y: Rational[T]): Rational[T] =
+  ## Multiply int `x` with rational `y`.
+  result.num = x * y.num
+  result.den = y.den
+  reduce(result)
+
+proc `*=` *[T](x: var Rational[T], y: Rational[T]) =
+  ## Multiply rationals `y` to `x`.
+  x.num *= y.num
+  x.den *= y.den
+  reduce(x)
+
+proc `*=` *[T](x: var Rational[T], y: T) =
+  ## Multiply int `y` to rational `x`.
+  x.num *= y
+  reduce(x)
+
+proc reciprocal*[T](x: Rational[T]): Rational[T] =
+  ## Calculate the reciprocal of `x`. (1/x)
+  if x.num > 0:
+    result.num = x.den
+    result.den = x.num
+  elif x.num < 0:
+    result.num = -x.den
+    result.den = -x.num
+  else:
+    raise newException(DivByZeroError, "division by zero")
+
+proc `/`*[T](x, y: Rational[T]): Rational[T] =
+  ## Divide rationals `x` by `y`.
+  result.num = x.num * y.den
+  result.den = x.den * y.num
+  reduce(result)
+
+proc `/`*[T](x: Rational[T], y: T): Rational[T] =
+  ## Divide rational `x` by int `y`.
+  result.num = x.num
+  result.den = x.den * y
+  reduce(result)
+
+proc `/`*[T](x: T, y: Rational[T]): Rational[T] =
+  ## Divide int `x` by Rational `y`.
+  result.num = x * y.den
+  result.den = y.num
+  reduce(result)
+
+proc `/=`*[T](x: var Rational[T], y: Rational[T]) =
+  ## Divide rationals `x` by `y` in place.
+  x.num *= y.den
+  x.den *= y.num
+  reduce(x)
+
+proc `/=`*[T](x: var Rational[T], y: T) =
+  ## Divide rational `x` by int `y` in place.
+  x.den *= y
+  reduce(x)
+
+proc cmp*(x, y: Rational): int {.procvar.} =
+  ## Compares two rationals.
+  (x - y).num
+
+proc `<` *(x, y: Rational): bool =
+  (x - y).num < 0
+
+proc `<=` *(x, y: Rational): bool =
+  (x - y).num <= 0
+
+proc `==` *(x, y: Rational): bool =
+  (x - y).num == 0
+
+proc abs*[T](x: Rational[T]): Rational[T] =
+  result.num = abs x.num
+  result.den = abs x.den
+
+proc hash*[T](x: Rational[T]): THash =
+  ## Computes hash for rational `x`
+  # reduce first so that hash(x) == hash(y) for x == y
+  var copy = x
+  reduce(copy)
+
+  var h: THash = 0
+  h = h !& hash(copy.num)
+  h = h !& hash(copy.den)
+  result = !$h
+  
+when isMainModule:
+  var
+    z = Rational[int](num: 0, den: 1)
+    o = initRational(num=1, den=1)
+    a = initRational(1, 2)
+    b = -1 // -2
+    m1 = -1 // 1
+    tt = 10 // 2
+
+  assert( a     == a )
+  assert( (a-a) == z )
+  assert( (a+b) == o )
+  assert( (a/b) == o )
+  assert( (a*b) == 1 // 4 )
+  assert( (3/a) == 6 // 1 )
+  assert( (a/3) == 1 // 6 )
+  assert( a*b   == 1 // 4 )
+  assert( tt*z  == z )
+  assert( 10*a  == tt )
+  assert( a*10  == tt )
+  assert( tt/10 == a  )
+  assert( a-m1  == 3 // 2 )
+  assert( a+m1  == -1 // 2 )
+  assert( m1+tt == 16 // 4 )
+  assert( m1-tt == 6 // -1 )
+
+  assert( z < o )
+  assert( z <= o )
+  assert( z == z )
+  assert( cmp(z, o) < 0 )
+  assert( cmp(o, z) > 0 )
+
+  assert( o == o )
+  assert( o >= o )
+  assert( not(o > o) )
+  assert( cmp(o, o) == 0 )
+  assert( cmp(z, z) == 0 )
+  assert( hash(o) == hash(o) )
+
+  assert( a == b )
+  assert( a >= b )
+  assert( not(b > a) )
+  assert( cmp(a, b) == 0 )
+  assert( hash(a) == hash(b) )
+
+  var x = 1//3
+
+  x *= 5//1
+  assert( x == 5//3 )
+  x += 2 // 9
+  assert( x == 17//9 )
+  x -= 9//18
+  assert( x == 25//18 )
+  x /= 1//2
+  assert( x == 50//18 )
+
+  var y = 1//3
+
+  y *= 4
+  assert( y == 4//3 )
+  y += 5
+  assert( y == 19//3 )
+  y -= 2
+  assert( y == 13//3 )
+  y /= 9
+  assert( y == 13//27 )
+
+  assert toRational(5) == 5//1
+  assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7
+  assert toInt(z) == 0
diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim
index 62a011999..a30c23ada 100644
--- a/lib/pure/rawsockets.nim
+++ b/lib/pure/rawsockets.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Dominik Picheta
+#        (c) Copyright 2015 Dominik Picheta
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -39,6 +39,9 @@ export
   SO_KEEPALIVE, SO_OOBINLINE, SO_REUSEADDR,
   MSG_PEEK
 
+when defined(macosx):
+    export SO_NOSIGPIPE
+
 type
   Port* = distinct uint16  ## port type
   
diff --git a/lib/pure/redis.nim b/lib/pure/redis.nim
index 52d81b3a4..aa2e0f9bd 100644
--- a/lib/pure/redis.nim
+++ b/lib/pure/redis.nim
@@ -285,6 +285,30 @@ proc keys*(r: Redis, pattern: string): RedisList =
   r.sendCommand("KEYS", pattern)
   return r.readArray()
 
+proc scan*(r: Redis, cursor: var BiggestInt): RedisList =
+  ## Find all keys matching the given pattern and yield it to client in portions
+  ## using default Redis values for MATCH and COUNT parameters
+  r.sendCommand("SCAN", $cursor)
+  let reply = r.readArray()
+  cursor = strutils.parseBiggestInt(reply[0])
+  return reply[1..high(reply)]
+
+proc scan*(r: Redis, cursor: var BiggestInt, pattern: string): RedisList =
+  ## Find all keys matching the given pattern and yield it to client in portions
+  ## using cursor as a client query identifier. Using default Redis value for COUNT argument
+  r.sendCommand("SCAN", $cursor, ["MATCH", pattern])
+  let reply = r.readArray()
+  cursor = strutils.parseBiggestInt(reply[0])
+  return reply[1..high(reply)]
+
+proc scan*(r: Redis, cursor: var BiggestInt, pattern: string, count: int): RedisList = 
+  ## Find all keys matching the given pattern and yield it to client in portions
+  ## using cursor as a client query identifier.
+  r.sendCommand("SCAN", $cursor, ["MATCH", pattern, "COUNT", $count])
+  let reply = r.readArray()
+  cursor = strutils.parseBiggestInt(reply[0])
+  return reply[1..high(reply)]
+
 proc move*(r: Redis, key: string, db: int): bool =
   ## Move a key to another database. Returns `true` on a successful move.
   r.sendCommand("MOVE", key, $db)
@@ -798,6 +822,22 @@ proc zunionstore*(r: Redis, destination: string, numkeys: string,
   
   return r.readInteger()
 
+# HyperLogLog
+
+proc pfadd*(r: Redis, key: string, elements: varargs[string]): RedisInteger = 
+  ## Add variable number of elements into special 'HyperLogLog' set type
+  r.sendCommand("PFADD", key, elements)
+  return r.readInteger()
+
+proc pfcount*(r: Redis, key: string): RedisInteger =
+  ## Count approximate number of elements in 'HyperLogLog'
+  r.sendCommand("PFCOUNT", key)
+  return r.readInteger()
+
+proc pfmerge*(r: Redis, destination: string, sources: varargs[string]) =
+  ## Merge several source HyperLogLog's into one specified by destKey
+  r.sendCommand("PFMERGE", destination, sources)
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
 
 # Pub/Sub
 
@@ -1040,7 +1080,7 @@ proc assertListsIdentical(listA, listB: seq[string]) =
     assert(item == listB[i])
     i = i + 1
   
-when isMainModule:
+when not defined(testing) and isMainModule:
   when false:
     var r = open()
 
diff --git a/lib/pure/romans.nim b/lib/pure/romans.nim
index 79fb75526..0c182843a 100644
--- a/lib/pure/romans.nim
+++ b/lib/pure/romans.nim
@@ -44,16 +44,13 @@ proc decimalToRoman*(number: range[1..3_999]): string =
     ("XC", 90), ("L", 50), ("XL", 40), ("X", 10), ("IX", 9),
     ("V", 5), ("IV", 4), ("I", 1)]
   result = ""
-  var decVal = number
+  var decVal: int = number
   for key, val in items(romanComposites):
     while decVal >= val:
       dec(decVal, val)
       result.add(key)
 
 when isMainModule:
-  import math
-  randomize()
-  for i in 1 .. 100:
-    var rnd = 1 + random(3990)
-    assert rnd == rnd.decimalToRoman.romanToDecimal
+  for i in 1 .. 3_999:
+    assert i == i.decimalToRoman.romanToDecimal
 
diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim
index 995dff2aa..5c7fedfe3 100644
--- a/lib/pure/ropes.nim
+++ b/lib/pure/ropes.nim
@@ -43,7 +43,7 @@ proc isConc(r: Rope): bool {.inline.} = return isNil(r.data)
 # Note that the left and right pointers are not needed for leafs.
 # Leaves have relatively high memory overhead (~30 bytes on a 32
 # bit machine) and we produce many of them. This is why we cache and
-# share leafs accross different rope trees.
+# share leafs across different rope trees.
 # To cache them they are inserted in another tree, a splay tree for best
 # performance. But for the caching tree we use the leaf's left and right
 # pointers.
@@ -52,9 +52,9 @@ proc len*(a: Rope): int {.rtl, extern: "nro$1".} =
   ## the rope's length
   if a == nil: result = 0
   else: result = a.length
-  
+
 proc newRope(): Rope = new(result)
-proc newRope(data: string): Rope = 
+proc newRope(data: string): Rope =
   new(result)
   result.length = len(data)
   result.data = data
@@ -65,18 +65,18 @@ var
 
 when countCacheMisses:
   var misses, hits: int
-  
-proc splay(s: string, tree: Rope, cmpres: var int): Rope = 
+
+proc splay(s: string, tree: Rope, cmpres: var int): Rope =
   var c: int
   var t = tree
   N.left = nil
   N.right = nil               # reset to nil
   var le = N
   var r = N
-  while true: 
+  while true:
     c = cmp(s, t.data)
-    if c < 0: 
-      if (t.left != nil) and (s < t.left.data): 
+    if c < 0:
+      if (t.left != nil) and (s < t.left.data):
         var y = t.left
         t.left = y.right
         y.right = t
@@ -85,8 +85,8 @@ proc splay(s: string, tree: Rope, cmpres: var int): Rope =
       r.left = t
       r = t
       t = t.left
-    elif c > 0: 
-      if (t.right != nil) and (s > t.right.data): 
+    elif c > 0:
+      if (t.right != nil) and (s > t.right.data):
         var y = t.right
         t.right = y.left
         y.left = t
@@ -95,8 +95,8 @@ proc splay(s: string, tree: Rope, cmpres: var int): Rope =
       le.right = t
       le = t
       t = t.right
-    else: 
-      break 
+    else:
+      break
   cmpres = c
   le.right = t.left
   r.left = t.right
@@ -104,50 +104,50 @@ proc splay(s: string, tree: Rope, cmpres: var int): Rope =
   t.right = N.left
   result = t
 
-proc insertInCache(s: string, tree: Rope): Rope = 
+proc insertInCache(s: string, tree: Rope): Rope =
   var t = tree
-  if t == nil: 
+  if t == nil:
     result = newRope(s)
     when countCacheMisses: inc(misses)
     return 
   var cmp: int
   t = splay(s, t, cmp)
-  if cmp == 0: 
+  if cmp == 0:
     # We get here if it's already in the Tree
     # Don't add it again
     result = t
     when countCacheMisses: inc(hits)
-  else: 
+  else:
     when countCacheMisses: inc(misses)
     result = newRope(s)
-    if cmp < 0: 
+    if cmp < 0:
       result.left = t.left
       result.right = t
       t.left = nil
-    else: 
+    else:
       # i > t.item:
       result.right = t.right
       result.left = t
       t.right = nil
 
 proc rope*(s: string): Rope {.rtl, extern: "nro$1Str".} =
-  ## Converts a string to a rope. 
-  if s.len == 0: 
+  ## Converts a string to a rope.
+  if s.len == 0:
     result = nil
-  elif cacheEnabled: 
+  elif cacheEnabled:
     result = insertInCache(s, cache)
     cache = result
-  else: 
+  else:
     result = newRope(s)
-  
-proc rope*(i: BiggestInt): Rope {.rtl, extern: "nro$1BiggestInt".} = 
-  ## Converts an int to a rope. 
+
+proc rope*(i: BiggestInt): Rope {.rtl, extern: "nro$1BiggestInt".} =
+  ## Converts an int to a rope.
   result = rope($i)
 
 proc rope*(f: BiggestFloat): Rope {.rtl, extern: "nro$1BiggestFloat".} =
-  ## Converts a float to a rope. 
+  ## Converts a float to a rope.
   result = rope($f)
-  
+
 proc enableCache*() {.rtl, extern: "nro$1".} =
   ## Enables the caching of leaves. This reduces the memory footprint at
   ## the cost of runtime efficiency.
@@ -160,9 +160,9 @@ proc disableCache*() {.rtl, extern: "nro$1".} =
 
 proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} =
   ## the concatenation operator for ropes.
-  if a == nil: 
+  if a == nil:
     result = b
-  elif b == nil: 
+  elif b == nil:
     result = a
   else:
     result = newRope()
@@ -177,16 +177,16 @@ proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} =
     else:
       result.left = a
       result.right = b
-  
-proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} = 
+
+proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} =
   ## the concatenation operator for ropes.
   result = a & rope(b)
-  
-proc `&`*(a: string, b: Rope): Rope {.rtl, extern: "nroConcStrRope".} = 
+
+proc `&`*(a: string, b: Rope): Rope {.rtl, extern: "nroConcStrRope".} =
   ## the concatenation operator for ropes.
   result = rope(a) & b
-  
-proc `&`*(a: openArray[Rope]): Rope {.rtl, extern: "nroConcOpenArray".} = 
+
+proc `&`*(a: openArray[Rope]): Rope {.rtl, extern: "nroConcOpenArray".} =
   ## the concatenation operator for an openarray of ropes.
   for i in countup(0, high(a)): result = result & a[i]
 
@@ -219,7 +219,7 @@ iterator leaves*(r: Rope): string =
   ## iterates over any leaf string in the rope `r`.
   if r != nil:
     var stack = @[r]
-    while stack.len > 0: 
+    while stack.len > 0:
       var it = stack.pop
       while isConc(it):
         stack.add(it.right)
@@ -227,7 +227,7 @@ iterator leaves*(r: Rope): string =
         assert(it != nil)
       assert(it.data != nil)
       yield it.data
-  
+
 iterator items*(r: Rope): char =
   ## iterates over any character in the rope `r`.
   for s in leaves(r):
@@ -237,7 +237,7 @@ proc write*(f: File, r: Rope) {.rtl, extern: "nro$1".} =
   ## writes a rope to a file.
   for s in leaves(r): write(f, s)
 
-proc `$`*(r: Rope): string  {.rtl, extern: "nroToString".}= 
+proc `$`*(r: Rope): string  {.rtl, extern: "nroToString".}=
   ## converts a rope back to a string.
   result = newString(r.len)
   setLen(result, 0)
@@ -251,25 +251,25 @@ when false:
     new(result)
     result.length = -idx
   
-  proc compileFrmt(frmt: string): Rope = 
+  proc compileFrmt(frmt: string): Rope =
     var i = 0
     var length = len(frmt)
     result = nil
     var num = 0
-    while i < length: 
-      if frmt[i] == '$': 
+    while i < length:
+      if frmt[i] == '$':
         inc(i)
         case frmt[i]
-        of '$': 
+        of '$':
           add(result, "$")
           inc(i)
-        of '#': 
+        of '#':
           inc(i)
           add(result, compiledArg(num+1))
           inc(num)
-        of '0'..'9': 
+        of '0'..'9':
           var j = 0
-          while true: 
+          while true:
             j = j * 10 + ord(frmt[i]) - ord('0')
             inc(i)
             if frmt[i] notin {'0'..'9'}: break 
@@ -285,13 +285,13 @@ when false:
           add(s, compiledArg(j))
         else: raise newException(EInvalidValue, "invalid format string")
       var start = i
-      while i < length: 
+      while i < length:
         if frmt[i] != '$': inc(i)
-        else: break 
-      if i - 1 >= start: 
+        else: break
+      if i - 1 >= start:
         add(result, substr(frmt, start, i-1))
-  
-proc `%`*(frmt: string, args: openArray[Rope]): Rope {. 
+
+proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
   rtl, extern: "nroFormat".} =
   ## `%` substitution operator for ropes. Does not support the ``$identifier``
   ## nor ``${identifier}`` notations.
@@ -299,23 +299,23 @@ proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
   var length = len(frmt)
   result = nil
   var num = 0
-  while i < length: 
-    if frmt[i] == '$': 
+  while i < length:
+    if frmt[i] == '$':
       inc(i)
       case frmt[i]
-      of '$': 
+      of '$':
         add(result, "$")
         inc(i)
-      of '#': 
+      of '#':
         inc(i)
         add(result, args[num])
         inc(num)
-      of '0'..'9': 
+      of '0'..'9':
         var j = 0
-        while true: 
+        while true:
           j = j * 10 + ord(frmt[i]) - ord('0')
           inc(i)
-          if frmt[i] notin {'0'..'9'}: break 
+          if frmt[i] notin {'0'..'9'}: break
         add(result, args[j-1])
       of '{':
         inc(i)
@@ -325,13 +325,14 @@ proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
           inc(i)
         if frmt[i] == '}': inc(i)
         else: raise newException(ValueError, "invalid format string")
+
         add(result, args[j-1])
       else: raise newException(ValueError, "invalid format string")
     var start = i
-    while i < length: 
+    while i < length:
       if frmt[i] != '$': inc(i)
-      else: break 
-    if i - 1 >= start: 
+      else: break
+    if i - 1 >= start:
       add(result, substr(frmt, start, i - 1))
 
 proc addf*(c: var Rope, frmt: string, args: openArray[Rope]) {.
@@ -339,29 +340,46 @@ proc addf*(c: var Rope, frmt: string, args: openArray[Rope]) {.
   ## shortcut for ``add(c, frmt % args)``.
   add(c, frmt % args)
 
+const
+  bufSize = 1024              # 1 KB is reasonable
+
 proc equalsFile*(r: Rope, f: File): bool {.rtl, extern: "nro$1File".} =
   ## returns true if the contents of the file `f` equal `r`.
-  var bufSize = 1024 # reasonable start value
-  var buf = alloc(bufSize)
+  var 
+    buf: array[bufSize, char]
+    bpos = buf.len
+    blen = buf.len
+
   for s in leaves(r):
-    if s.len > bufSize:
-      bufSize = max(bufSize * 2, s.len)
-      buf = realloc(buf, bufSize)
-    var readBytes = readBuffer(f, buf, s.len)
-    result = readBytes == s.len and equalMem(buf, cstring(s), s.len)
-    if not result: break
-  if result:
-    result = readBuffer(f, buf, 1) == 0 # really at the end of file?
-  dealloc(buf)
+    var spos = 0
+    let slen = s.len
+    while spos < slen:
+      if bpos == blen:
+        # Read more data
+        bpos = 0
+        blen = readBuffer(f, addr(buf[0]), buf.len)
+        if blen == 0:  # no more data in file
+          result = false
+          return
+      let n = min(blen - bpos, slen - spos)
+      # TODO There's gotta be a better way of comparing here...
+      if not equalMem(addr(buf[bpos]), 
+                      cast[pointer](cast[int](cstring(s))+spos), n):
+        result = false
+        return
+      spos += n
+      bpos += n
+
+  result = readBuffer(f, addr(buf[0]), 1) == 0  # check that we've read all
 
-proc equalsFile*(r: Rope, f: string): bool {.rtl, extern: "nro$1Str".} =
+proc equalsFile*(r: Rope, filename: string): bool {.rtl, extern: "nro$1Str".} =
   ## returns true if the contents of the file `f` equal `r`. If `f` does not
   ## exist, false is returned.
-  var bin: File
-  result = open(bin, f)
+  var f: File
+  result = open(f, filename)
   if result:
-    result = equalsFile(r, bin)
-    close(bin)
+    result = equalsFile(r, f)
+    close(f)
 
 new(N) # init dummy node for splay algorithm
 
diff --git a/lib/pure/scgi.nim b/lib/pure/scgi.nim
index 58b37833a..f3e2b583c 100644
--- a/lib/pure/scgi.nim
+++ b/lib/pure/scgi.nim
@@ -25,6 +25,10 @@
 ##
 ## **Warning:** The API of this module is unstable, and therefore is subject
 ## to change.
+##
+## **Warning:** This module only supports the old asynchronous interface.
+## You may wish to use the `asynchttpserver <asynchttpserver.html>`_
+## instead for web applications.
 
 include "system/inclrtl"
 
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
index 1c988c609..6901ecf58 100644
--- a/lib/pure/selectors.nim
+++ b/lib/pure/selectors.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Dominik Picheta
+#        (c) Copyright 2015 Dominik Picheta
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -23,7 +23,7 @@ proc `$`*(x: SocketHandle): string {.borrow.}
 
 type
   Event* = enum
-    EvRead, EvWrite
+    EvRead, EvWrite, EvError
 
   SelectorKey* = ref object
     fd*: SocketHandle
@@ -35,7 +35,7 @@ type
 when defined(nimdoc):
   type
     Selector* = ref object
-      ## An object which holds file descripters to be checked for read/write
+      ## An object which holds file descriptors to be checked for read/write
       ## status.
       fds: Table[SocketHandle, SelectorKey]
 
@@ -48,12 +48,21 @@ when defined(nimdoc):
                events: set[Event]): SelectorKey {.discardable.} =
     ## Updates the events which ``fd`` wants notifications for.
 
+  proc unregister*(s: Selector, fd: SocketHandle): SelectorKey {.discardable.} =
+    ## Unregisters file descriptor ``fd`` from selector ``s``.
+
+  proc close*(s: Selector) =
+    ## Closes the selector
+
   proc select*(s: Selector, timeout: int): seq[ReadyInfo] =
     ## The ``events`` field of the returned ``key`` contains the original events
     ## for which the ``fd`` was bound. This is contrary to the ``events`` field
     ## of the ``TReadyInfo`` tuple which determines which events are ready
     ## on the ``fd``.
 
+  proc newSelector*(): Selector =
+    ## Creates a new selector
+
   proc contains*(s: Selector, fd: SocketHandle): bool =
     ## Determines whether selector contains a file descriptor.
 
@@ -78,8 +87,6 @@ elif defined(linux):
   
   proc register*(s: Selector, fd: SocketHandle, events: set[Event],
       data: RootRef): SelectorKey {.discardable.} =
-    ## Registers file descriptor ``fd`` to selector ``s`` with a set of TEvent
-    ## ``events``.
     var event = createEventStruct(events, fd)
     if events != {}:
       if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0:
@@ -92,7 +99,6 @@ elif defined(linux):
   
   proc update*(s: Selector, fd: SocketHandle,
       events: set[Event]): SelectorKey {.discardable.} =
-    ## Updates the events which ``fd`` wants notifications for.
     if s.fds[fd].events != events:
       if events == {}:
         # This fd is idle -- it should not be registered to epoll.
@@ -146,12 +152,17 @@ elif defined(linux):
     ## on the ``fd``.
     result = @[]
     let evNum = epoll_wait(s.epollFD, addr s.events[0], 64.cint, timeout.cint)
-    if evNum < 0: raiseOSError(osLastError())
+    if evNum < 0:
+      let err = osLastError()
+      if err.cint == EINTR:
+        return @[]
+      raiseOSError(osLastError())
     if evNum == 0: return @[]
     for i in 0 .. <evNum:
       let fd = s.events[i].data.fd.SocketHandle
     
       var evSet: set[Event] = {}
+      if (s.events[i].events and EPOLLERR) != 0 or (s.events[i].events and EPOLLHUP) != 0: evSet = evSet + {EvError}
       if (s.events[i].events and EPOLLIN) != 0: evSet = evSet + {EvRead}
       if (s.events[i].events and EPOLLOUT) != 0: evSet = evSet + {EvWrite}
       let selectorKey = s.fds[fd]
@@ -199,7 +210,6 @@ elif not defined(nimdoc):
 
   proc update*(s: Selector, fd: SocketHandle,
       events: set[Event]): SelectorKey {.discardable.} =
-    ## Updates the events which ``fd`` wants notifications for.
     if not s.fds.hasKey(fd):
       raise newException(ValueError, "File descriptor not found.")
 
@@ -286,7 +296,7 @@ proc contains*(s: Selector, key: SelectorKey): bool =
    TReadyInfo: ReadyInfo, PSelector: Selector].}
 
 
-when isMainModule and not defined(nimdoc):
+when not defined(testing) and isMainModule and not defined(nimdoc):
   # Select()
   import sockets
   type
@@ -294,7 +304,7 @@ when isMainModule and not defined(nimdoc):
       sock: Socket
   
   var sock = socket()
-  if sock == sockets.InvalidSocket: raiseOSError(osLastError())
+  if sock == sockets.invalidSocket: raiseOSError(osLastError())
   #sock.setBlocking(false)
   sock.connect("irc.freenode.net", Port(6667))
   
diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim
index 26f0c9591..c1bc259a5 100644
--- a/lib/pure/smtp.nim
+++ b/lib/pure/smtp.nim
@@ -238,7 +238,7 @@ proc sendMail*(smtp: AsyncSmtp, fromAddr: string,
   await smtp.sock.send("MAIL FROM:<" & fromAddr & ">\c\L")
   await smtp.checkReply("250")
   for address in items(toAddrs):
-    await smtp.sock.send("RCPT TO:<" & smtp.address & ">\c\L")
+    await smtp.sock.send("RCPT TO:<" & address & ">\c\L")
     await smtp.checkReply("250")
   
   # Send the message
@@ -253,7 +253,7 @@ proc close*(smtp: AsyncSmtp) {.async.} =
   await smtp.sock.send("QUIT\c\L")
   smtp.sock.close()
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   #var msg = createMessage("Test subject!", 
   #     "Hello, my name is dom96.\n What\'s yours?", @["dominik@localhost"])
   #echo(msg)
diff --git a/lib/pure/smtp.nimrod.cfg b/lib/pure/smtp.nim.cfg
index 521e21de4..521e21de4 100644
--- a/lib/pure/smtp.nimrod.cfg
+++ b/lib/pure/smtp.nim.cfg
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
index e3c32e806..3afb545c8 100644
--- a/lib/pure/sockets.nim
+++ b/lib/pure/sockets.nim
@@ -7,6 +7,10 @@
 #    distribution, for details about the copyright.
 #
 
+## **Warning:** Since version 0.10.2 this module is deprecated.
+## Use the `net <net.html>`_ or the
+## `rawsockets <rawsockets.html>`_ module instead.
+##
 ## This module implements portable sockets, it supports a mix of different types
 ## of sockets. Sockets are buffered by default meaning that data will be
 ## received in ``BufferSize`` (4000) sized chunks, buffering
@@ -24,6 +28,8 @@
 ## Asynchronous sockets are supported, however a better alternative is to use
 ## the `asyncio <asyncio.html>`_ module.
 
+{.deprecated.}
+
 include "system/inclrtl"
 
 {.deadCodeElim: on.}
@@ -651,6 +657,8 @@ proc close*(socket: Socket) =
   when defined(ssl):
     if socket.isSSL:
       discard SSLShutdown(socket.sslHandle)
+      SSLFree(socket.sslHandle)
+      socket.sslHandle = nil
 
 proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} =
   ## Searches the database from the beginning and finds the first entry for 
@@ -845,7 +853,7 @@ proc connectAsync*(socket: Socket, name: string, port = Port(0),
                      af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
   ## A variant of ``connect`` for non-blocking sockets.
   ##
-  ## This procedure will immediatelly return, it will not block until a connection
+  ## This procedure will immediately return, it will not block until a connection
   ## is made. It is up to the caller to make sure the connection has been established
   ## by checking (using ``select``) whether the socket is writeable.
   ##
@@ -1461,7 +1469,7 @@ proc recvAsync*(socket: Socket, s: var TaintedString): bool {.
           of SSL_ERROR_ZERO_RETURN:
             raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
           of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
-            raiseSslError("Unexpected error occured.") # This should just not happen.
+            raiseSslError("Unexpected error occurred.") # This should just not happen.
           of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
             return false
           of SSL_ERROR_WANT_X509_LOOKUP:
@@ -1604,7 +1612,7 @@ proc sendAsync*(socket: Socket, data: string): int {.tags: [WriteIOEffect].} =
           of SSL_ERROR_ZERO_RETURN:
             raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
           of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
-            raiseSslError("Unexpected error occured.") # This should just not happen.
+            raiseSslError("Unexpected error occurred.") # This should just not happen.
           of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
             return 0
           of SSL_ERROR_WANT_X509_LOOKUP:
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index 31aa7497d..e706f2016 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -122,41 +122,41 @@ proc read[T](s: Stream, result: var T) =
     raise newEIO("cannot read from stream")
 
 proc readChar*(s: Stream): char =
-  ## reads a char from the stream `s`. Raises `EIO` if an error occured.
+  ## reads a char from the stream `s`. Raises `EIO` if an error occurred.
   ## Returns '\0' as an EOF marker.
   if readData(s, addr(result), sizeof(result)) != 1: result = '\0'
 
 proc readBool*(s: Stream): bool = 
-  ## reads a bool from the stream `s`. Raises `EIO` if an error occured.
+  ## reads a bool from the stream `s`. Raises `EIO` if an error occurred.
   read(s, result)
 
 proc readInt8*(s: Stream): int8 = 
-  ## reads an int8 from the stream `s`. Raises `EIO` if an error occured.
+  ## reads an int8 from the stream `s`. Raises `EIO` if an error occurred.
   read(s, result)
 
 proc readInt16*(s: Stream): int16 = 
-  ## reads an int16 from the stream `s`. Raises `EIO` if an error occured.
+  ## reads an int16 from the stream `s`. Raises `EIO` if an error occurred.
   read(s, result)
 
 proc readInt32*(s: Stream): int32 = 
-  ## reads an int32 from the stream `s`. Raises `EIO` if an error occured.
+  ## reads an int32 from the stream `s`. Raises `EIO` if an error occurred.
   read(s, result)
 
 proc readInt64*(s: Stream): int64 = 
-  ## reads an int64 from the stream `s`. Raises `EIO` if an error occured.
+  ## reads an int64 from the stream `s`. Raises `EIO` if an error occurred.
   read(s, result)
 
 proc readFloat32*(s: Stream): float32 = 
-  ## reads a float32 from the stream `s`. Raises `EIO` if an error occured.
+  ## reads a float32 from the stream `s`. Raises `EIO` if an error occurred.
   read(s, result)
 
 proc readFloat64*(s: Stream): float64 = 
-  ## reads a float64 from the stream `s`. Raises `EIO` if an error occured.
+  ## reads a float64 from the stream `s`. Raises `EIO` if an error occurred.
   read(s, result)
 
 proc readStr*(s: Stream, length: int): TaintedString = 
   ## reads a string of length `length` from the stream `s`. Raises `EIO` if 
-  ## an error occured.
+  ## an error occurred.
   result = newString(length).TaintedString
   var L = readData(s, addr(string(result)[0]), length)
   if L != length: setLen(result.string, L)
@@ -183,7 +183,7 @@ proc readLine*(s: Stream, line: var TaintedString): bool =
 
 proc readLine*(s: Stream): TaintedString =
   ## Reads a line from a stream `s`. Note: This is not very efficient. Raises 
-  ## `EIO` if an error occured.
+  ## `EIO` if an error occurred.
   result = TaintedString""
   while true:
     var c = readChar(s)
@@ -224,10 +224,12 @@ proc ssReadData(s: Stream, buffer: pointer, bufLen: int): int =
 
 proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) = 
   var s = StringStream(s)
-  if bufLen > 0: 
-    setLen(s.data, s.data.len + bufLen)
-    copyMem(addr(s.data[s.pos]), buffer, bufLen)
-    inc(s.pos, bufLen)
+  if bufLen <= 0:
+    return
+  if s.pos + bufLen > s.data.len:
+    setLen(s.data, s.pos + bufLen)
+  copyMem(addr(s.data[s.pos]), buffer, bufLen)
+  inc(s.pos, bufLen)
 
 proc ssClose(s: Stream) =
   var s = StringStream(s)
@@ -284,7 +286,7 @@ when not defined(js):
   proc newFileStream*(filename: string, mode: FileMode): FileStream =
     ## creates a new stream from the file named `filename` with the mode `mode`.
     ## If the file cannot be opened, nil is returned. See the `system
-    ## <system.html>`_ module for a list of available TFileMode enums.
+    ## <system.html>`_ module for a list of available FileMode enums.
     var f: File
     if open(f, filename, mode): result = newFileStream(f)
 
diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim
index 5b7149d8e..727d5a386 100644
--- a/lib/pure/strtabs.nim
+++ b/lib/pure/strtabs.nim
@@ -112,7 +112,7 @@ proc `[]`*(t: StringTableRef, key: string): string {.rtl, extern: "nstGet".} =
 proc mget*(t: StringTableRef, key: string): var string {.
              rtl, extern: "nstTake".} =
   ## retrieves the location at ``t[key]``. If `key` is not in `t`, the
-  ## ``EInvalidKey`` exception is raised.
+  ## ``KeyError`` exception is raised.
   var index = rawGet(t, key)
   if index >= 0: result = t.data[index].val
   else: raise newException(KeyError, "key does not exist: " & key)
@@ -158,7 +158,7 @@ proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string =
   else: result = ""
   if result.len == 0:
     if useKey in flags: result = '$' & key
-    elif not (useEmpty in flags): raiseFormatException(key)
+    elif useEmpty notin flags: raiseFormatException(key)
 
 proc newStringTable*(mode: StringTableMode): StringTableRef {.
   rtl, extern: "nst$1".} =
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 55a204b4c..1b248126b 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -386,7 +386,7 @@ proc split*(s: string, sep: string): seq[string] {.noSideEffect,
   ## `split iterator <#split.i,string,string>`_.
   accumulateResult(split(s, sep))
 
-proc toHex*(x: BiggestInt, len: int): string {.noSideEffect,
+proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect,
   rtl, extern: "nsuToHex".} =
   ## Converts `x` to its hexadecimal representation.
   ##
@@ -395,13 +395,15 @@ proc toHex*(x: BiggestInt, len: int): string {.noSideEffect,
   const
     HexChars = "0123456789ABCDEF"
   var
-    shift: BiggestInt
+    n = x
   result = newString(len)
   for j in countdown(len-1, 0):
-    result[j] = HexChars[toU32(x shr shift) and 0xF'i32]
-    shift = shift + 4
+    result[j] = HexChars[n and 0xF]
+    n = n shr 4
+    # handle negative overflow
+    if n == 0 and x < 0: n = -1
 
-proc intToStr*(x: int, minchars: int = 1): string {.noSideEffect,
+proc intToStr*(x: int, minchars: Positive = 1): string {.noSideEffect,
   rtl, extern: "nsuIntToStr".} =
   ## Converts `x` to its decimal representation.
   ##
@@ -497,30 +499,51 @@ proc parseEnum*[T: enum](s: string, default: T): T =
       return e
   result = default
 
-proc repeatChar*(count: int, c: char = ' '): string {.noSideEffect,
+proc repeat*(c: char, count: Natural): string {.noSideEffect,
   rtl, extern: "nsuRepeatChar".} =
   ## Returns a string of length `count` consisting only of
   ## the character `c`. You can use this proc to left align strings. Example:
   ##
   ## .. code-block:: nim
+  ##   proc tabexpand(indent: int, text: string, tabsize: int = 4) =
+  ##     echo '\t'.repeat(indent div tabsize), ' '.repeat(indent mod tabsize), text
+  ##
+  ##   tabexpand(4, "At four")
+  ##   tabexpand(5, "At five")
+  ##   tabexpand(6, "At six")
+  result = newString(count)
+  for i in 0..count-1: result[i] = c
+
+proc repeat*(s: string, n: Natural): string {.noSideEffect,
+  rtl, extern: "nsuRepeatStr".} =
+  ## Returns String `s` concatenated `n` times.  Example:
+  ##
+  ## .. code-block:: nim
+  ##   echo "+++ STOP ".repeat(4), "+++"
+  result = newStringOfCap(n * s.len)
+  for i in 1..n: result.add(s)
+
+template spaces*(n: Natural): string =  repeat(' ',n)
+  ## Returns a String with `n` space characters. You can use this proc
+  ## to left align strings. Example:
+  ##
+  ## .. code-block:: nim
   ##   let
   ##     width = 15
   ##     text1 = "Hello user!"
   ##     text2 = "This is a very long string"
-  ##   echo text1 & repeatChar(max(0, width - text1.len)) & "|"
-  ##   echo text2 & repeatChar(max(0, width - text2.len)) & "|"
-  result = newString(count)
-  for i in 0..count-1: result[i] = c
+  ##   echo text1 & spaces(max(0, width - text1.len)) & "|"
+  ##   echo text2 & spaces(max(0, width - text2.len)) & "|"
 
-proc repeatStr*(count: int, s: string): string {.noSideEffect,
-  rtl, extern: "nsuRepeatStr".} =
-  ## Returns `s` concatenated `count` times.
-  result = newStringOfCap(count*s.len)
-  for i in 0..count-1: result.add(s)
+proc repeatChar*(count: Natural, c: char = ' '): string {.deprecated.} = repeat(c, count)
+  ## deprecated: use repeat() or spaces()
+
+proc repeatStr*(count: Natural, s: string): string {.deprecated.} = repeat(s, count)
+  ## deprecated: use repeat(string, count) or string.repeat(count)
 
-proc align*(s: string, count: int, padding = ' '): string {.
+proc align*(s: string, count: Natural, padding = ' '): string {.
   noSideEffect, rtl, extern: "nsuAlignString".} =
-  ## Aligns a string `s` with `padding`, so that is of length `count`.
+  ## Aligns a string `s` with `padding`, so that it is of length `count`.
   ##
   ## `padding` characters (by default spaces) are added before `s` resulting in
   ## right alignment. If ``s.len >= count``, no spaces are added and `s` is
@@ -659,7 +682,7 @@ proc endsWith*(s, suffix: string): bool {.noSideEffect,
     inc(i)
   if suffix[i] == '\0': return true
 
-proc continuesWith*(s, substr: string, start: int): bool {.noSideEffect,
+proc continuesWith*(s, substr: string, start: Natural): bool {.noSideEffect,
   rtl, extern: "nsuContinuesWith".} =
   ## Returns true iff ``s`` continues with ``substr`` at position ``start``.
   ##
@@ -670,8 +693,8 @@ proc continuesWith*(s, substr: string, start: int): bool {.noSideEffect,
     if s[i+start] != substr[i]: return false
     inc(i)
 
-proc addSep*(dest: var string, sep = ", ", startLen = 0) {.noSideEffect,
-                                                           inline.} =
+proc addSep*(dest: var string, sep = ", ", startLen: Natural = 0)
+  {.noSideEffect, inline.} =
   ## Adds a separator to `dest` only if its length is bigger than `startLen`.
   ##
   ## A shorthand for:
@@ -761,7 +784,7 @@ proc findAux(s, sub: string, start: int, a: SkipTable): int =
     inc(j, a[s[j+m]])
   return -1
 
-proc find*(s, sub: string, start: int = 0): int {.noSideEffect,
+proc find*(s, sub: string, start: Natural = 0): int {.noSideEffect,
   rtl, extern: "nsuFindStr".} =
   ## Searches for `sub` in `s` starting at position `start`.
   ##
@@ -770,7 +793,7 @@ proc find*(s, sub: string, start: int = 0): int {.noSideEffect,
   preprocessSub(sub, a)
   result = findAux(s, sub, start, a)
 
-proc find*(s: string, sub: char, start: int = 0): int {.noSideEffect,
+proc find*(s: string, sub: char, start: Natural = 0): int {.noSideEffect,
   rtl, extern: "nsuFindChar".} =
   ## Searches for `sub` in `s` starting at position `start`.
   ##
@@ -779,7 +802,7 @@ proc find*(s: string, sub: char, start: int = 0): int {.noSideEffect,
     if sub == s[i]: return i
   return -1
 
-proc find*(s: string, chars: set[char], start: int = 0): int {.noSideEffect,
+proc find*(s: string, chars: set[char], start: Natural = 0): int {.noSideEffect,
   rtl, extern: "nsuFindCharSet".} =
   ## Searches for `chars` in `s` starting at position `start`.
   ##
@@ -803,10 +826,20 @@ proc rfind*(s, sub: string, start: int = -1): int {.noSideEffect.} =
     if result != -1: return
   return -1
 
+proc rfind*(s: string, sub: char, start: int = -1): int {.noSideEffect,
+  rtl.} =
+  ## Searches for `sub` in `s` in reverse starting at position `start`.
+  ##
+  ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
+  let realStart = if start == -1: s.len-1 else: start
+  for i in countdown(realStart, 0):
+    if sub == s[i]: return i
+  return -1
+
 proc count*(s: string, sub: string, overlapping: bool = false): int {.noSideEffect,
   rtl, extern: "nsuCountString".} =
-  ## Count the occurences of a substring `sub` in the string `s`.
-  ## Overlapping occurences of `sub` only count when `overlapping`
+  ## Count the occurrences of a substring `sub` in the string `s`.
+  ## Overlapping occurrences of `sub` only count when `overlapping`
   ## is set to true.
   var i = 0
   while true:
@@ -821,14 +854,14 @@ proc count*(s: string, sub: string, overlapping: bool = false): int {.noSideEffe
 
 proc count*(s: string, sub: char): int {.noSideEffect,
   rtl, extern: "nsuCountChar".} =
-  ## Count the occurences of the character `sub` in the string `s`.
+  ## Count the occurrences of the character `sub` in the string `s`.
   for c in s:
     if c == sub:
       inc result
 
 proc count*(s: string, subs: set[char]): int {.noSideEffect,
   rtl, extern: "nsuCountCharSet".} =
-  ## Count the occurences of the group of character `subs` in the string `s`.
+  ## Count the occurrences of the group of character `subs` in the string `s`.
   for c in s:
     if c in subs:
       inc result
@@ -888,7 +921,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
   rtl, extern: "nsuReplaceWord".} =
   ## Replaces `sub` in `s` by the string `by`.
   ##
-  ## Each occurance of `sub` has to be surrounded by word boundaries
+  ## Each occurrence of `sub` has to be surrounded by word boundaries
   ## (comparable to ``\\w`` in regular expressions), otherwise it is not
   ## replaced.
   const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'}
@@ -900,7 +933,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
     var j = findAux(s, sub, i, a)
     if j < 0: break
     # word boundary?
-    if (j == 0 or s[j-1] notin wordChars) and 
+    if (j == 0 or s[j-1] notin wordChars) and
         (j+sub.len >= s.len or s[j+sub.len] notin wordChars):
       add result, substr(s, i, j - 1)
       add result, by
@@ -943,7 +976,7 @@ proc parseOctInt*(s: string): int {.noSideEffect,
     of '\0': break
     else: raise newException(ValueError, "invalid integer: " & s)
 
-proc toOct*(x: BiggestInt, len: int): string {.noSideEffect,
+proc toOct*(x: BiggestInt, len: Positive): string {.noSideEffect,
   rtl, extern: "nsuToOct".} =
   ## Converts `x` into its octal representation.
   ##
@@ -959,7 +992,7 @@ proc toOct*(x: BiggestInt, len: int): string {.noSideEffect,
     shift = shift + 3
     mask = mask shl 3
 
-proc toBin*(x: BiggestInt, len: int): string {.noSideEffect,
+proc toBin*(x: BiggestInt, len: Positive): string {.noSideEffect,
   rtl, extern: "nsuToBin".} =
   ## Converts `x` into its binary representation.
   ##
@@ -1032,18 +1065,20 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
   ## ValueError exception will be raised.
   result = newStringOfCap(s.len)
   var i = 0
-  if s[0 .. prefix.len-1] != prefix:
+  if not s.startsWith(prefix):
     raise newException(ValueError,
                        "String does not start with a prefix of: " & prefix)
-  i.inc()
+  inc(i)
   while true:
     if i == s.len-suffix.len: break
     case s[i]
     of '\\':
       case s[i+1]:
       of 'x':
-        let j = parseHexInt(s[i+2 .. i+3])
-        result.add(chr(j))
+        inc i
+        var c: int
+        i += parseutils.parseHex(s, c, i)
+        result.add(chr(c))
         inc(i, 2)
       of '\\':
         result.add('\\')
@@ -1056,8 +1091,8 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
     of '\0': break
     else:
       result.add(s[i])
-    i.inc()
-  if s[i .. -1] != suffix:
+    inc(i)
+  if not s.endsWith(suffix):
     raise newException(ValueError,
                        "String does not end with a suffix of: " & suffix)
 
@@ -1186,7 +1221,7 @@ proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault,
   ## of significant digits to be printed.
   ## `precision`'s default value is the maximum number of meaningful digits
   ## after the decimal point for Nim's ``biggestFloat`` type.
-  ## 
+  ##
   ## If ``precision == 0``, it tries to format it nicely.
   const floatFormatToChar: array[FloatFormatMode, char] = ['g', 'f', 'e']
   var
@@ -1251,7 +1286,7 @@ proc findNormalized(x: string, inArray: openArray[string]): int =
   return -1
 
 proc invalidFormatString() {.noinline.} =
-  raise newException(ValueError, "invalid format string")  
+  raise newException(ValueError, "invalid format string")
 
 proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.
   noSideEffect, rtl, extern: "nsuAddf".} =
@@ -1367,21 +1402,27 @@ when isMainModule:
   doAssert align("a", 0) == "a"
   doAssert align("1232", 6) == "  1232"
   doAssert align("1232", 6, '#') == "##1232"
-  echo wordWrap(""" this is a long text --  muchlongerthan10chars and here
-                   it goes""", 10, false)
+
+  let
+    inp = """ this is a long text --  muchlongerthan10chars and here
+               it goes"""
+    outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes"
+  doAssert wordWrap(inp, 10, false) == outp
+
   doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001"
   doAssert formatBiggestFloat(0.00000000001, ffScientific, 1) == "1.0e-11"
 
   doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
-  echo formatSize(1'i64 shl 31 + 300'i64) # == "4,GB"
-  echo formatSize(1'i64 shl 31)
+  when not defined(testing):
+    echo formatSize(1'i64 shl 31 + 300'i64) # == "4,GB"
+    echo formatSize(1'i64 shl 31)
 
   doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
            "The cat eats fish."
 
   doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
   doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz  abc"
-  
+
   type MyEnum = enum enA, enB, enC, enuD, enE
   doAssert parseEnum[MyEnum]("enu_D") == enuD
 
diff --git a/lib/pure/subexes.nim b/lib/pure/subexes.nim
index c87823926..d213c99e6 100644
--- a/lib/pure/subexes.nim
+++ b/lib/pure/subexes.nim
@@ -38,7 +38,11 @@ proc raiseInvalidFormat(msg: string) {.noinline.} =
 
 type
   TFormatParser = object {.pure, final.}
-    f: cstring
+    when defined(js):
+      f: string # we rely on the '\0' terminator
+                # which JS's native string doesn't have
+    else:
+      f: cstring
     num, i, lineLen: int
 
 template call(x: stmt) {.immediate.} =
@@ -349,11 +353,11 @@ when isMainModule:
 
   proc `%`(formatstr: string, a: openarray[string]): string =
     result = newStringOfCap(formatstr.len + a.len shl 4)
-    addf(result, formatstr.TSubex, a)
+    addf(result, formatstr.Subex, a)
 
   proc `%`(formatstr: string, a: string): string =
     result = newStringOfCap(formatstr.len + a.len)
-    addf(result, formatstr.TSubex, [a])
+    addf(result, formatstr.Subex, [a])
 
 
   doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
@@ -382,8 +386,13 @@ when isMainModule:
     longishA, 
     longish)"""
   
-  echo "type TMyEnum* = enum\n  $', '2i'\n  '{..}" % ["fieldA", 
-    "fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"]
+  assert "type TMyEnum* = enum\n  $', '2i'\n  '{..}" % ["fieldA",
+    "fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"] ==
+    strutils.unindent """
+      type TMyEnum* = enum
+        fieldA, fieldB, 
+        FiledClkad, fieldD, 
+        fieldE, longishFieldName"""
   
   doAssert subex"$1($', '{2..})" % ["f", "a", "b", "c"] == "f(a, b, c)"
   
@@ -391,7 +400,12 @@ when isMainModule:
   
   doAssert subex"$['''|'|''''|']']#" % "0" == "'|"
   
-  echo subex("type\n  TEnum = enum\n    $', '40c'\n    '{..}") % [
-    "fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"]
+  assert subex("type\n  TEnum = enum\n    $', '40c'\n    '{..}") % [
+    "fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"] ==
+    strutils.unindent """
+      type
+        TEnum = enum
+          fieldNameA, fieldNameB, fieldNameC, 
+          fieldNameD"""
   
   
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
index 1c1d973ee..29f700db5 100644
--- a/lib/pure/terminal.nim
+++ b/lib/pure/terminal.nim
@@ -45,6 +45,21 @@ when defined(windows):
   var
     oldAttr = getAttributes()
 
+else:
+  import termios, unsigned
+
+  proc setRaw(fd: FileHandle, time: cint = TCSAFLUSH) =
+    var mode: Termios
+    discard fd.tcgetattr(addr mode)
+    mode.c_iflag = mode.c_iflag and not Tcflag(BRKINT or ICRNL or INPCK or
+      ISTRIP or IXON)
+    mode.c_oflag = mode.c_oflag and not Tcflag(OPOST)
+    mode.c_cflag = (mode.c_cflag and not Tcflag(CSIZE or PARENB)) or CS8
+    mode.c_lflag = mode.c_lflag and not Tcflag(ECHO or ICANON or IEXTEN or ISIG)
+    mode.c_cc[VMIN] = 1.cuchar
+    mode.c_cc[VTIME] = 0.cuchar
+    discard fd.tcsetattr(time, addr mode)
+
 proc setCursorPos*(x, y: int) =
   ## sets the terminal's cursor to the (x,y) position. (0,0) is the
   ## upper left of the screen.
@@ -185,13 +200,15 @@ proc eraseScreen* =
     var numwrote: DWORD
     var origin: TCOORD # is inititalized to 0, 0
     var hStdout = conHandle
+
     if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0:
       raiseOSError(osLastError())
-    if FillConsoleOutputCharacter(hStdout, ' ', scrbuf.dwSize.X*scrbuf.dwSize.Y,
+    let numChars = int32(scrbuf.dwSize.X)*int32(scrbuf.dwSize.Y)
+
+    if FillConsoleOutputCharacter(hStdout, ' ', numChars,
                                   origin, addr(numwrote)) == 0:
       raiseOSError(osLastError())
-    if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes,
-                                  scrbuf.dwSize.X * scrbuf.dwSize.Y,
+    if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, numChars,
                                   origin, addr(numwrote)) == 0:
       raiseOSError(osLastError())
     setCursorXPos(0)
@@ -327,7 +344,7 @@ proc isatty*(f: File): bool =
   else:
     proc isatty(fildes: FileHandle): cint {.
       importc: "_isatty", header: "<io.h>".}
-  
+
   result = isatty(getFileHandle(f)) != 0'i32
 
 proc styledEchoProcessArg(s: string) = write stdout, s
@@ -347,7 +364,19 @@ macro styledEcho*(m: varargs[expr]): stmt =
   result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n")))
   result.add(newCall(bindSym"resetAttributes"))
 
-when isMainModule:
+when not defined(windows):
+  proc getch*(): char =
+    ## Read a single character from the terminal, blocking until it is entered.
+    ## The character is not printed to the terminal. This is not available for
+    ## Windows.
+    let fd = getFileHandle(stdin)
+    var oldMode: Termios
+    discard fd.tcgetattr(addr oldMode)
+    fd.setRaw()
+    result = stdin.readChar()
+    discard fd.tcsetattr(TCSADRAIN, addr oldMode)
+
+when not defined(testing) and isMainModule:
   system.addQuitProc(resetAttributes)
   write(stdout, "never mind")
   eraseLine()
@@ -357,5 +386,5 @@ when isMainModule:
   setForeGroundColor(fgBlue)
   writeln(stdout, "ordinary text")
 
-  styledEcho("styled text ", {styleBright, styleBlink, styleUnderscore}) 
-  
+  styledEcho("styled text ", {styleBright, styleBlink, styleUnderscore})
+
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 1cabd381b..c275ede69 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -16,7 +16,7 @@
                       # of the standard library!
 
 import
-  strutils
+  strutils, parseutils
 
 include "system/inclrtl"
 
@@ -26,81 +26,87 @@ type
   WeekDay* = enum ## represents a weekday
     dMon, dTue, dWed, dThu, dFri, dSat, dSun
 
-var
-  timezone {.importc, header: "<time.h>".}: int
-  tzname {.importc, header: "<time.h>" .}: array[0..1, cstring]
+when not defined(JS):
+  var
+    timezone {.importc, header: "<time.h>".}: int
+    tzname {.importc, header: "<time.h>" .}: array[0..1, cstring]
 
 when defined(posix) and not defined(JS):
   type
-    TimeImpl {.importc: "time_t", header: "<sys/time.h>".} = int
+    TimeImpl {.importc: "time_t", header: "<time.h>".} = int
     Time* = distinct TimeImpl ## distinct type that represents a time
                               ## measured as number of seconds since the epoch
-    
-    Timeval {.importc: "struct timeval", 
+
+    Timeval {.importc: "struct timeval",
               header: "<sys/select.h>".} = object ## struct timeval
-      tv_sec: int  ## Seconds. 
-      tv_usec: int ## Microseconds. 
-      
+      tv_sec: int  ## Seconds.
+      tv_usec: int ## Microseconds.
+
   # we cannot import posix.nim here, because posix.nim depends on times.nim.
-  # Ok, we could, but I don't want circular dependencies. 
+  # Ok, we could, but I don't want circular dependencies.
   # And gettimeofday() is not defined in the posix module anyway. Sigh.
-  
+
   proc posix_gettimeofday(tp: var Timeval, unused: pointer = nil) {.
     importc: "gettimeofday", header: "<sys/time.h>".}
 
+  # we also need tzset() to make sure that tzname is initialized
+  proc tzset() {.importc, header: "<time.h>".}
+  # calling tzset() implicitly to initialize tzname data.
+  tzset()
+
 elif defined(windows):
   import winlean
-  
+
   when defined(vcc):
     # newest version of Visual C++ defines time_t to be of 64 bits
     type TimeImpl {.importc: "time_t", header: "<time.h>".} = int64
   else:
     type TimeImpl {.importc: "time_t", header: "<time.h>".} = int32
-  
+
   type
     Time* = distinct TimeImpl
 
 elif defined(JS):
   type
     Time* {.importc.} = object
-      getDay: proc (): int {.tags: [], raises: [], gcsafe.}
-      getFullYear: proc (): int {.tags: [], raises: [], gcsafe.}
-      getHours: proc (): int {.tags: [], raises: [], gcsafe.}
-      getMilliseconds: proc (): int {.tags: [], raises: [], gcsafe.}
-      getMinutes: proc (): int {.tags: [], raises: [], gcsafe.}
-      getMonth: proc (): int {.tags: [], raises: [], gcsafe.}
-      getSeconds: proc (): int {.tags: [], raises: [], gcsafe.}
-      getTime: proc (): int {.tags: [], raises: [], gcsafe.}
-      getTimezoneOffset: proc (): int {.tags: [], raises: [], gcsafe.}
-      getDate: proc (): int {.tags: [], raises: [], gcsafe.}
-      getUTCDate: proc (): int {.tags: [], raises: [], gcsafe.}
-      getUTCFullYear: proc (): int {.tags: [], raises: [], gcsafe.}
-      getUTCHours: proc (): int {.tags: [], raises: [], gcsafe.}
-      getUTCMilliseconds: proc (): int {.tags: [], raises: [], gcsafe.}
-      getUTCMinutes: proc (): int {.tags: [], raises: [], gcsafe.}
-      getUTCMonth: proc (): int {.tags: [], raises: [], gcsafe.}
-      getUTCSeconds: proc (): int {.tags: [], raises: [], gcsafe.}
-      getUTCDay: proc (): int {.tags: [], raises: [], gcsafe.}
-      getYear: proc (): int {.tags: [], raises: [], gcsafe.}
-      parse: proc (s: cstring): Time {.tags: [], raises: [], gcsafe.}
-      setDate: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setFullYear: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setHours: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setMilliseconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setMinutes: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setMonth: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setSeconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setTime: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setUTCDate: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setUTCFullYear: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setUTCHours: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setUTCMilliseconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setUTCMinutes: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setUTCMonth: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setUTCSeconds: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      setYear: proc (x: int) {.tags: [], raises: [], gcsafe.}
-      toGMTString: proc (): cstring {.tags: [], raises: [], gcsafe.}
-      toLocaleString: proc (): cstring {.tags: [], raises: [], gcsafe.}
+      getDay: proc (): int {.tags: [], raises: [], benign.}
+      getFullYear: proc (): int {.tags: [], raises: [], benign.}
+      getHours: proc (): int {.tags: [], raises: [], benign.}
+      getMilliseconds: proc (): int {.tags: [], raises: [], benign.}
+      getMinutes: proc (): int {.tags: [], raises: [], benign.}
+      getMonth: proc (): int {.tags: [], raises: [], benign.}
+      getSeconds: proc (): int {.tags: [], raises: [], benign.}
+      getTime: proc (): int {.tags: [], raises: [], benign.}
+      getTimezoneOffset: proc (): int {.tags: [], raises: [], benign.}
+      getDate: proc (): int {.tags: [], raises: [], benign.}
+      getUTCDate: proc (): int {.tags: [], raises: [], benign.}
+      getUTCFullYear: proc (): int {.tags: [], raises: [], benign.}
+      getUTCHours: proc (): int {.tags: [], raises: [], benign.}
+      getUTCMilliseconds: proc (): int {.tags: [], raises: [], benign.}
+      getUTCMinutes: proc (): int {.tags: [], raises: [], benign.}
+      getUTCMonth: proc (): int {.tags: [], raises: [], benign.}
+      getUTCSeconds: proc (): int {.tags: [], raises: [], benign.}
+      getUTCDay: proc (): int {.tags: [], raises: [], benign.}
+      getYear: proc (): int {.tags: [], raises: [], benign.}
+      parse: proc (s: cstring): Time {.tags: [], raises: [], benign.}
+      setDate: proc (x: int) {.tags: [], raises: [], benign.}
+      setFullYear: proc (x: int) {.tags: [], raises: [], benign.}
+      setHours: proc (x: int) {.tags: [], raises: [], benign.}
+      setMilliseconds: proc (x: int) {.tags: [], raises: [], benign.}
+      setMinutes: proc (x: int) {.tags: [], raises: [], benign.}
+      setMonth: proc (x: int) {.tags: [], raises: [], benign.}
+      setSeconds: proc (x: int) {.tags: [], raises: [], benign.}
+      setTime: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCDate: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCFullYear: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCHours: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCMilliseconds: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCMinutes: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCMonth: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCSeconds: proc (x: int) {.tags: [], raises: [], benign.}
+      setYear: proc (x: int) {.tags: [], raises: [], benign.}
+      toGMTString: proc (): cstring {.tags: [], raises: [], benign.}
+      toLocaleString: proc (): cstring {.tags: [], raises: [], benign.}
 
 type
   TimeInfo* = object of RootObj ## represents a time in different parts
@@ -139,51 +145,51 @@ type
 {.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time,
     TTimeInterval: TimeInterval, TTimeInfo: TimeInfo].}
 
-proc getTime*(): Time {.tags: [TimeEffect], gcsafe.}
+proc getTime*(): Time {.tags: [TimeEffect], benign.}
   ## gets the current calendar time as a UNIX epoch value (number of seconds
   ## elapsed since 1970) with integer precission. Use epochTime for higher
   ## resolution.
-proc getLocalTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], gcsafe.}
+proc getLocalTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], benign.}
   ## converts the calendar time `t` to broken-time representation,
   ## expressed relative to the user's specified time zone.
-proc getGMTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], gcsafe.}
+proc getGMTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], benign.}
   ## converts the calendar time `t` to broken-down time representation,
   ## expressed in Coordinated Universal Time (UTC).
 
-proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], gcsafe.}
+proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], benign.}
   ## converts a broken-down time structure to
   ## calendar time representation. The function ignores the specified
   ## contents of the structure members `weekday` and `yearday` and recomputes
   ## them from the other information in the broken-down time structure.
 
-proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], gcsafe.}
+proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], benign.}
   ## Takes a float which contains the number of seconds since the unix epoch and
   ## returns a time object.
 
-proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], gcsafe.} = 
+proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], benign.} =
   ## Takes an int which contains the number of seconds since the unix epoch and
   ## returns a time object.
   fromSeconds(float(since1970))
 
-proc toSeconds*(time: Time): float {.tags: [], raises: [], gcsafe.}
+proc toSeconds*(time: Time): float {.tags: [], raises: [], benign.}
   ## Returns the time in seconds since the unix epoch.
 
-proc `$` *(timeInfo: TimeInfo): string {.tags: [], raises: [], gcsafe.}
+proc `$` *(timeInfo: TimeInfo): string {.tags: [], raises: [], benign.}
   ## converts a `TimeInfo` object to a string representation.
-proc `$` *(time: Time): string {.tags: [], raises: [], gcsafe.}
+proc `$` *(time: Time): string {.tags: [], raises: [], benign.}
   ## converts a calendar time to a string representation.
 
 proc `-`*(a, b: Time): int64 {.
-  rtl, extern: "ntDiffTime", tags: [], raises: [].}
+  rtl, extern: "ntDiffTime", tags: [], raises: [], benign.}
   ## computes the difference of two calendar times. Result is in seconds.
 
 proc `<`*(a, b: Time): bool {.
-  rtl, extern: "ntLtTime", tags: [], raises: [].} = 
+  rtl, extern: "ntLtTime", tags: [], raises: [].} =
   ## returns true iff ``a < b``, that is iff a happened before b.
   result = a - b < 0
-  
+
 proc `<=` * (a, b: Time): bool {.
-  rtl, extern: "ntLeTime", tags: [], raises: [].}= 
+  rtl, extern: "ntLeTime", tags: [], raises: [].}=
   ## returns true iff ``a <= b``.
   result = a - b <= 0
 
@@ -194,18 +200,18 @@ proc `==`*(a, b: Time): bool {.
 
 when not defined(JS):
   proc getTzname*(): tuple[nonDST, DST: string] {.tags: [TimeEffect], raises: [],
-    gcsafe.}
+    benign.}
     ## returns the local timezone; ``nonDST`` is the name of the local non-DST
     ## timezone, ``DST`` is the name of the local DST timezone.
 
-proc getTimezone*(): int {.tags: [TimeEffect], raises: [], gcsafe.}
+proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign.}
   ## returns the offset of the local (non-DST) timezone in seconds west of UTC.
 
-proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], gcsafe.}
+proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], benign.}
   ## get the miliseconds from the start of the program. **Deprecated since
   ## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead.
 
-proc initInterval*(miliseconds, seconds, minutes, hours, days, months, 
+proc initInterval*(miliseconds, seconds, minutes, hours, days, months,
                    years: int = 0): TimeInterval =
   ## creates a new ``TimeInterval``.
   result.miliseconds = miliseconds
@@ -221,9 +227,9 @@ proc isLeapYear*(year: int): bool =
 
   if year mod 400 == 0:
     return true
-  elif year mod 100 == 0: 
+  elif year mod 100 == 0:
     return false
-  elif year mod 4 == 0: 
+  elif year mod 4 == 0:
     return true
   else:
     return false
@@ -232,7 +238,7 @@ proc getDaysInMonth*(month: Month, year: int): int =
   ## gets the amount of days in a ``month`` of a ``year``
 
   # http://www.dispersiondesign.com/articles/time/number_of_days_in_a_month
-  case month 
+  case month
   of mFeb: result = if isLeapYear(year): 29 else: 28
   of mApr, mJun, mSep, mNov: result = 30
   else: result = 31
@@ -244,7 +250,7 @@ proc toSeconds(a: TimeInfo, interval: TimeInterval): float =
   var anew = a
   var newinterv = interval
   result = 0
-  
+
   newinterv.months += interval.years * 12
   var curMonth = anew.month
   for mth in 1 .. newinterv.months:
@@ -284,18 +290,18 @@ proc `-`*(a: TimeInfo, interval: TimeInterval): TimeInfo =
   else:
     result = getLocalTime(fromSeconds(t - secs))
 
-when not defined(JS):  
+when not defined(JS):
   proc epochTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].}
     ## gets time after the UNIX epoch (1970) in seconds. It is a float
-    ## because sub-second resolution is likely to be supported (depending 
+    ## because sub-second resolution is likely to be supported (depending
     ## on the hardware/OS).
 
   proc cpuTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].}
     ## gets time spent that the CPU spent to run the current process in
     ## seconds. This may be more useful for benchmarking than ``epochTime``.
     ## However, it may measure the real time instead (depending on the OS).
-    ## The value of the result has no meaning. 
-    ## To generate useful timing values, take the difference between 
+    ## The value of the result has no meaning.
+    ## To generate useful timing values, take the difference between
     ## the results of two ``cpuTime`` calls:
     ##
     ## .. code-block:: nim
@@ -316,10 +322,10 @@ when not defined(JS):
         weekday {.importc: "tm_wday".},
         yearday {.importc: "tm_yday".},
         isdst {.importc: "tm_isdst".}: cint
-  
+
     TimeInfoPtr = ptr StructTM
     Clock {.importc: "clock_t".} = distinct int
-  
+
   proc localtime(timer: ptr Time): TimeInfoPtr {.
     importc: "localtime", header: "<time.h>", tags: [].}
   proc gmtime(timer: ptr Time): TimeInfoPtr {.
@@ -335,12 +341,12 @@ when not defined(JS):
   #  strftime(s: CString, maxsize: int, fmt: CString, t: tm): int {.
   #    importc: "strftime", header: "<time.h>".}
   proc getClock(): Clock {.importc: "clock", header: "<time.h>", tags: [TimeEffect].}
-  proc difftime(a, b: Time): float {.importc: "difftime", header: "<time.h>", 
+  proc difftime(a, b: Time): float {.importc: "difftime", header: "<time.h>",
     tags: [].}
-  
+
   var
     clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
-    
+
   # our own procs on top of that:
   proc tmToTimeInfo(tm: StructTM, local: bool): TimeInfo =
     const
@@ -364,7 +370,7 @@ when not defined(JS):
           "UTC",
       timezone: if local: getTimezone() else: 0
     )
-  
+
   proc timeInfoToTM(t: TimeInfo): StructTM =
     const
       weekDays: array [WeekDay, int8] = [1'i8,2'i8,3'i8,4'i8,5'i8,6'i8,0'i8]
@@ -377,11 +383,11 @@ when not defined(JS):
     result.weekday = weekDays[t.weekday]
     result.yearday = t.yearday
     result.isdst = if t.isDST: 1 else: 0
-  
+
   when not defined(useNimRtl):
     proc `-` (a, b: Time): int64 =
       return toBiggestInt(difftime(a, b))
-  
+
   proc getStartMilsecs(): int =
     #echo "clocks per sec: ", clocksPerSec, "clock: ", int(getClock())
     #return getClock() div (clocksPerSec div 1000)
@@ -394,37 +400,37 @@ when not defined(JS):
       posix_gettimeofday(a)
       result = a.tv_sec * 1000'i64 + a.tv_usec div 1000'i64
       #echo "result: ", result
-    
+
   proc getTime(): Time = return timec(nil)
   proc getLocalTime(t: Time): TimeInfo =
     var a = t
     result = tmToTimeInfo(localtime(addr(a))[], true)
     # copying is needed anyway to provide reentrancity; thus
     # the conversion is not expensive
-  
+
   proc getGMTime(t: Time): TimeInfo =
     var a = t
     result = tmToTimeInfo(gmtime(addr(a))[], false)
     # copying is needed anyway to provide reentrancity; thus
     # the conversion is not expensive
-  
+
   proc timeInfoToTime(timeInfo: TimeInfo): Time =
     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 toStringTillNL(p: cstring): string = 
+  proc toStringTillNL(p: cstring): string =
     result = ""
     var i = 0
-    while p[i] != '\0' and p[i] != '\10' and p[i] != '\13': 
+    while p[i] != '\0' and p[i] != '\10' and p[i] != '\13':
       add(result, p[i])
       inc(i)
-    
+
   proc `$`(timeInfo: TimeInfo): string =
     # BUGFIX: asctime returns a newline at the end!
     var p = asctime(timeInfoToTM(timeInfo))
     result = toStringTillNL(p)
-  
+
   proc `$`(time: Time): string =
     # BUGFIX: ctime returns a newline at the end!
     var a = time
@@ -434,17 +440,17 @@ when not defined(JS):
     epochDiff = 116444736000000000'i64
     rateDiff = 10000000'i64 # 100 nsecs
 
-  proc unixTimeToWinTime*(t: Time): int64 = 
+  proc unixTimeToWinTime*(t: Time): int64 =
     ## converts a UNIX `Time` (``time_t``) to a Windows file time
     result = int64(t) * rateDiff + epochDiff
-    
-  proc winTimeToUnixTime*(t: int64): Time = 
+
+  proc winTimeToUnixTime*(t: int64): Time =
     ## converts a Windows time to a UNIX `Time` (``time_t``)
     result = Time((t - epochDiff) div rateDiff)
- 
+
   proc getTzname(): tuple[nonDST, DST: string] =
     return ($tzname[0], $tzname[1])
-  
+
   proc getTimezone(): int =
     return timezone
 
@@ -453,7 +459,7 @@ when not defined(JS):
   proc toSeconds(time: Time): float = float(time)
 
   when not defined(useNimRtl):
-    proc epochTime(): float = 
+    proc epochTime(): float =
       when defined(posix):
         var a: Timeval
         posix_gettimeofday(a)
@@ -467,14 +473,14 @@ when not defined(JS):
         result = toFloat(int(secs)) + toFloat(int(subsecs)) * 0.0000001
       else:
         {.error: "unknown OS".}
-      
-    proc cpuTime(): float = 
+
+    proc cpuTime(): float =
       result = toFloat(int(getClock())) / toFloat(clocksPerSec)
-    
+
 elif defined(JS):
   proc newDate(): Time {.importc: "new Date".}
   proc internGetTime(): Time {.importc: "new Date", tags: [].}
-  
+
   proc newDate(value: float): Time {.importc: "new Date".}
   proc newDate(value: string): Time {.importc: "new Date".}
   proc getTime(): Time =
@@ -482,15 +488,15 @@ elif defined(JS):
     return newDate()
 
   const
-    weekDays: array [0..6, TWeekDay] = [
+    weekDays: array [0..6, WeekDay] = [
       dSun, dMon, dTue, dWed, dThu, dFri, dSat]
-  
+
   proc getLocalTime(t: Time): TimeInfo =
     result.second = t.getSeconds()
     result.minute = t.getMinutes()
     result.hour = t.getHours()
     result.monthday = t.getDate()
-    result.month = TMonth(t.getMonth())
+    result.month = Month(t.getMonth())
     result.year = t.getFullYear()
     result.weekday = weekDays[t.getDay()]
     result.yearday = 0
@@ -500,11 +506,11 @@ elif defined(JS):
     result.minute = t.getUTCMinutes()
     result.hour = t.getUTCHours()
     result.monthday = t.getUTCDate()
-    result.month = TMonth(t.getUTCMonth())
+    result.month = Month(t.getUTCMonth())
     result.year = t.getUTCFullYear()
     result.weekday = weekDays[t.getUTCDay()]
     result.yearday = 0
-  
+
   proc timeInfoToTime*(timeInfo: TimeInfo): Time =
     result = internGetTime()
     result.setSeconds(timeInfo.second)
@@ -513,16 +519,16 @@ elif defined(JS):
     result.setMonth(ord(timeInfo.month))
     result.setFullYear(timeInfo.year)
     result.setDate(timeInfo.monthday)
-  
+
   proc `$`(timeInfo: TimeInfo): string = return $(timeInfoToTime(timeInfo))
   proc `$`(time: Time): string = return $time.toLocaleString()
-    
-  proc `-` (a, b: Time): int64 = 
+
+  proc `-` (a, b: Time): 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)
@@ -535,6 +541,8 @@ elif defined(JS):
 
   proc getTimezone(): int = result = newDate().getTimezoneOffset()
 
+  proc epochTime*(): float {.tags: [TimeEffect].} = newDate().toSeconds()
+
 proc getDateStr*(): string {.rtl, extern: "nt$1", tags: [TimeEffect].} =
   ## gets the current date as a string of the format ``YYYY-MM-DD``.
   var ti = getLocalTime(getTime())
@@ -554,8 +562,8 @@ proc `$`*(day: WeekDay): string =
   return lookup[day]
 
 proc `$`*(m: Month): string =
-  ## stingify operator for ``TMonth``.
-  const lookup: array[Month, string] = ["January", "February", "March", 
+  ## stingify operator for ``Month``.
+  const lookup: array[Month, string] = ["January", "February", "March",
       "April", "May", "June", "July", "August", "September", "October",
       "November", "December"]
   return lookup[m]
@@ -628,25 +636,25 @@ proc formatToken(info: TimeInfo, token: string, buf: var string) =
     var fr = ($info.year).len()-2
     if fr < 0: fr = 0
     var fyear = ($info.year)[fr .. ($info.year).len()-1]
-    if fyear.len != 2: fyear = repeatChar(2-fyear.len(), '0') & fyear
+    if fyear.len != 2: fyear = repeat('0', 2-fyear.len()) & fyear
     buf.add(fyear)
   of "yyy":
     var fr = ($info.year).len()-3
     if fr < 0: fr = 0
     var fyear = ($info.year)[fr .. ($info.year).len()-1]
-    if fyear.len != 3: fyear = repeatChar(3-fyear.len(), '0') & fyear
+    if fyear.len != 3: fyear = repeat('0', 3-fyear.len()) & fyear
     buf.add(fyear)
   of "yyyy":
     var fr = ($info.year).len()-4
     if fr < 0: fr = 0
     var fyear = ($info.year)[fr .. ($info.year).len()-1]
-    if fyear.len != 4: fyear = repeatChar(4-fyear.len(), '0') & fyear
+    if fyear.len != 4: fyear = repeat('0', 4-fyear.len()) & fyear
     buf.add(fyear)
   of "yyyyy":
     var fr = ($info.year).len()-5
     if fr < 0: fr = 0
     var fyear = ($info.year)[fr .. ($info.year).len()-1]
-    if fyear.len != 5: fyear = repeatChar(5-fyear.len(), '0') & fyear
+    if fyear.len != 5: fyear = repeat('0', 5-fyear.len()) & fyear
     buf.add(fyear)
   of "z":
     let hrs = (info.timezone div 60) div 60
@@ -676,7 +684,7 @@ proc formatToken(info: TimeInfo, token: string, buf: var string) =
 proc format*(info: TimeInfo, f: string): string =
   ## This function formats `info` as specified by `f`. The following format
   ## specifiers are available:
-  ## 
+  ##
   ## ==========  =================================================================================  ================================================
   ## Specifier   Description                                                                        Example
   ## ==========  =================================================================================  ================================================
@@ -723,14 +731,14 @@ proc format*(info: TimeInfo, f: string): string =
 
       currentF = ""
       if f[i] == '\0': break
-      
+
       if f[i] == '\'':
         inc(i) # Skip '
         while f[i] != '\'' and f.len-1 > i:
           result.add(f[i])
           inc(i)
       else: result.add(f[i])
-      
+
     else:
       # Check if the letter being added matches previous accumulated buffer.
       if currentF.len < 1 or currentF[high(currentF)] == f[i]:
@@ -744,37 +752,364 @@ proc format*(info: TimeInfo, f: string): string =
 
 {.pop.}
 
+proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
+  ## Helper of the parse proc to parse individual tokens.
+  var sv: int
+  case token
+  of "d":
+    var pd = parseInt(value[j..j+1], sv)
+    info.monthday = sv
+    j += pd
+  of "dd":
+    info.monthday = value[j..j+1].parseInt()
+    j += 2
+  of "ddd":
+    case value[j..j+2].toLower():
+    of "sun":
+      info.weekday = dSun
+    of "mon":
+      info.weekday = dMon
+    of "tue":
+      info.weekday = dTue
+    of "wed":
+      info.weekday = dWed
+    of "thu":
+      info.weekday = dThu
+    of "fri":
+      info.weekday = dFri
+    of "sat":
+      info.weekday = dSat
+    else:
+      raise newException(ValueError, "invalid day of week ")
+    j += 3
+  of "dddd":
+    if value.len >= j+6 and value[j..j+5].cmpIgnoreCase("sunday") == 0:
+      info.weekday = dSun
+      j += 6
+    elif value.len >= j+6 and value[j..j+5].cmpIgnoreCase("monday") == 0:
+      info.weekday = dMon
+      j += 6
+    elif value.len >= j+7 and value[j..j+6].cmpIgnoreCase("tuesday") == 0:
+      info.weekday = dTue
+      j += 7
+    elif value.len >= j+9 and value[j..j+8].cmpIgnoreCase("wednesday") == 0:
+      info.weekday = dWed
+      j += 9
+    elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("thursday") == 0:
+      info.weekday = dThu
+      j += 8
+    elif value.len >= j+6 and value[j..j+5].cmpIgnoreCase("friday") == 0:
+      info.weekday = dFri
+      j += 6
+    elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("saturday") == 0:
+      info.weekday = dSat
+      j += 8
+    else:
+      raise newException(ValueError, "invalid day of week ")
+  of "h", "H":
+    var pd = parseInt(value[j..j+1], sv)
+    info.hour = sv
+    j += pd
+  of "hh", "HH":
+    info.hour = value[j..j+1].parseInt()
+    j += 2
+  of "m":
+    var pd = parseInt(value[j..j+1], sv)
+    info.minute = sv
+    j += pd
+  of "mm":
+    info.minute = value[j..j+1].parseInt()
+    j += 2
+  of "M":
+    var pd = parseInt(value[j..j+1], sv)
+    info.month = Month(sv-1)
+    info.monthday = sv
+    j += pd
+  of "MM":
+    var month = value[j..j+1].parseInt()
+    j += 2
+    info.month = Month(month-1)
+  of "MMM":
+    case value[j..j+2].toLower():
+    of "jan":
+      info.month =  mJan
+    of "feb":
+      info.month =  mFeb
+    of "mar":
+      info.month =  mMar
+    of "apr":
+      info.month =  mApr
+    of "may":
+      info.month =  mMay
+    of "jun":
+      info.month =  mJun
+    of "jul":
+      info.month =  mJul
+    of "aug":
+      info.month =  mAug
+    of "sep":
+      info.month =  mSep
+    of "oct":
+      info.month =  mOct
+    of "nov":
+      info.month =  mNov
+    of "dec":
+      info.month =  mDec
+    else:
+      raise newException(ValueError, "invalid month")
+    j += 3
+  of "MMMM":
+    if value.len >= j+7 and value[j..j+6].cmpIgnoreCase("january") == 0:
+      info.month =  mJan
+      j += 7
+    elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("february") == 0:
+      info.month =  mFeb
+      j += 8
+    elif value.len >= j+5 and value[j..j+4].cmpIgnoreCase("march") == 0:
+      info.month =  mMar
+      j += 5
+    elif value.len >= j+5 and value[j..j+4].cmpIgnoreCase("april") == 0:
+      info.month =  mApr
+      j += 5
+    elif value.len >= j+3 and value[j..j+2].cmpIgnoreCase("may") == 0:
+      info.month =  mMay
+      j += 3
+    elif value.len >= j+4 and value[j..j+3].cmpIgnoreCase("june") == 0:
+      info.month =  mJun
+      j += 4
+    elif value.len >= j+4 and value[j..j+3].cmpIgnoreCase("july") == 0:
+      info.month =  mJul
+      j += 4
+    elif value.len >= j+6 and value[j..j+5].cmpIgnoreCase("august") == 0:
+      info.month =  mAug
+      j += 6
+    elif value.len >= j+9 and value[j..j+8].cmpIgnoreCase("september") == 0:
+      info.month =  mSep
+      j += 9
+    elif value.len >= j+7 and value[j..j+6].cmpIgnoreCase("october") == 0:
+      info.month =  mOct
+      j += 7
+    elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("november") == 0:
+      info.month =  mNov
+      j += 8
+    elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("december") == 0:
+      info.month =  mDec
+      j += 8
+    else:
+      raise newException(ValueError, "invalid month")
+  of "s":
+    var pd = parseInt(value[j..j+1], sv)
+    info.second = sv
+    j += pd
+  of "ss":
+    info.second = value[j..j+1].parseInt()
+    j += 2
+  of "t":
+    if value[j] == 'P' and info.hour > 0 and info.hour < 12:
+      info.hour += 12
+    j += 1
+  of "tt":
+    if value[j..j+1] == "PM" and info.hour > 0 and info.hour < 12:
+      info.hour += 12
+    j += 2
+  of "yy":
+    # Assumes current century
+    var year = value[j..j+1].parseInt()
+    var thisCen = getLocalTime(getTime()).year div 100
+    info.year = thisCen*100 + year
+    j += 2
+  of "yyyy":
+    info.year = value[j..j+3].parseInt()
+    j += 4
+  of "z":
+    if value[j] == '+':
+      info.timezone = parseInt($value[j+1])
+    elif value[j] == '-':
+      info.timezone = 0-parseInt($value[j+1])
+    else:
+      raise newException(ValueError, "Sign for timezone " & value[j])
+    j += 2
+  of "zz":
+    if value[j] == '+':
+      info.timezone = value[j+1..j+2].parseInt()
+    elif value[j] == '-':
+      info.timezone = 0-value[j+1..j+2].parseInt()
+    else:
+      raise newException(ValueError, "Sign for timezone " & value[j])
+    j += 3
+  of "zzz":
+    if value[j] == '+':
+      info.timezone = value[j+1..j+2].parseInt()
+    elif value[j] == '-':
+      info.timezone = 0-value[j+1..j+2].parseInt()
+    else:
+      raise newException(ValueError, "Sign for timezone " & value[j])
+    j += 6
+  of "ZZZ":
+    info.tzname = value[j..j+2].toUpper()
+    j += 3
+  else:
+    # Ignore the token and move forward in the value string by the same length
+    j += token.len
+
+proc parse*(value, layout: string): TimeInfo =
+  ## This function parses a date/time string using the standard format identifiers (below)
+  ## The function defaults information not provided in the format string from the running program (timezone, month, year, etc)
+  ##
+  ## ==========  =================================================================================  ================================================
+  ## Specifier   Description                                                                        Example
+  ## ==========  =================================================================================  ================================================
+  ##    d        Numeric value of the day of the month, it will be one or two digits long.          ``1/04/2012 -> 1``, ``21/04/2012 -> 21``
+  ##    dd       Same as above, but always two digits.                                              ``1/04/2012 -> 01``, ``21/04/2012 -> 21``
+  ##    ddd      Three letter string which indicates the day of the week.                           ``Saturday -> Sat``, ``Monday -> Mon``
+  ##    dddd     Full string for the day of the week.                                               ``Saturday -> Saturday``, ``Monday -> Monday``
+  ##    h        The hours in one digit if possible. Ranging from 0-12.                             ``5pm -> 5``, ``2am -> 2``
+  ##    hh       The hours in two digits always. If the hour is one digit 0 is prepended.           ``5pm -> 05``, ``11am -> 11``
+  ##    H        The hours in one digit if possible, randing from 0-24.                             ``5pm -> 17``, ``2am -> 2``
+  ##    HH       The hours in two digits always. 0 is prepended if the hour is one digit.           ``5pm -> 17``, ``2am -> 02``
+  ##    m        The minutes in 1 digit if possible.                                                ``5:30 -> 30``, ``2:01 -> 1``
+  ##    mm       Same as above but always 2 digits, 0 is prepended if the minute is one digit.      ``5:30 -> 30``, ``2:01 -> 01``
+  ##    M        The month in one digit if possible.                                                ``September -> 9``, ``December -> 12``
+  ##    MM       The month in two digits always. 0 is prepended.                                    ``September -> 09``, ``December -> 12``
+  ##    MMM      Abbreviated three-letter form of the month.                                        ``September -> Sep``, ``December -> Dec``
+  ##    MMMM     Full month string, properly capitalized.                                           ``September -> September``
+  ##    s        Seconds as one digit if possible.                                                  ``00:00:06 -> 6``
+  ##    ss       Same as above but always two digits. 0 is prepended.                               ``00:00:06 -> 06``
+  ##    t        ``A`` when time is in the AM. ``P`` when time is in the PM.
+  ##    tt       Same as above, but ``AM`` and ``PM`` instead of ``A`` and ``P`` respectively.
+  ##    yy       Displays the year to two digits.                                                   ``2012 -> 12``
+  ##    yyyy     Displays the year to four digits.                                                  ``2012 -> 2012``
+  ##    z        Displays the timezone offset from UTC.                                             ``GMT+7 -> +7``, ``GMT-5 -> -5``
+  ##    zz       Same as above but with leading 0.                                                  ``GMT+7 -> +07``, ``GMT-5 -> -05``
+  ##    zzz      Same as above but with ``:00``.                                                    ``GMT+7 -> +07:00``, ``GMT-5 -> -05:00``
+  ##    ZZZ      Displays the name of the timezone.                                                 ``GMT -> GMT``, ``EST -> EST``
+  ## ==========  =================================================================================  ================================================
+  ##
+  ## Other strings can be inserted by putting them in ``''``. For example
+  ## ``hh'->'mm`` will give ``01->56``.  The following characters can be
+  ## inserted without quoting them: ``:`` ``-`` ``(`` ``)`` ``/`` ``[`` ``]``
+  ## ``,``. However you don't need to necessarily separate format specifiers, a
+  ## unambiguous format string like ``yyyyMMddhhmmss`` is valid too.
+  var i = 0 # pointer for format string
+  var j = 0 # pointer for value string
+  var token = ""
+  # Assumes current day of month, month and year, but time is reset to 00:00:00. Weekday will be reset after parsing.
+  var info = getLocalTime(getTime())
+  info.hour = 0
+  info.minute = 0
+  info.second = 0
+  while true:
+    case layout[i]
+    of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',':
+      if token.len > 0:
+        parseToken(info, token, value, j)
+      # Reset token
+      token = ""
+      # Break if at end of line
+      if layout[i] == '\0': break
+      # Skip separator and everything between single quotes
+      # These are literals in both the layout and the value string
+      if layout[i] == '\'':
+        inc(i)
+        inc(j)
+        while layout[i] != '\'' and layout.len-1 > i:
+          inc(i)
+          inc(j)
+      else:
+        inc(i)
+        inc(j)
+    else:
+      # Check if the letter being added matches previous accumulated buffer.
+      if token.len < 1 or token[high(token)] == layout[i]:
+        token.add(layout[i])
+        inc(i)
+      else:
+        parseToken(info, token, value, j)
+        token = ""
+  # Reset weekday as it might not have been provided and the default may be wrong
+  info.weekday = getLocalTime(timeInfoToTime(info)).weekday
+  return info
+
+
 when isMainModule:
   # $ date --date='@2147483647'
   # Tue 19 Jan 03:14:07 GMT 2038
 
   var t = getGMTime(fromSeconds(2147483647))
-  echo t.format("ddd dd MMM hh:mm:ss ZZZ yyyy")
-  echo t.format("ddd ddMMMhhmmssZZZyyyy")
   assert t.format("ddd dd MMM hh:mm:ss ZZZ yyyy") == "Tue 19 Jan 03:14:07 UTC 2038"
   assert t.format("ddd ddMMMhh:mm:ssZZZyyyy") == "Tue 19Jan03:14:07UTC2038"
-  
+
   assert t.format("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" &
-    " ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") == 
+    " ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") ==
     "19 19 Tue Tuesday 3 03 3 03 14 14 1 01 Jan January 7 07 A AM 8 38 038 2038 02038 0 00 00:00 UTC"
 
   assert t.format("yyyyMMddhhmmss") == "20380119031407"
-  
+
   var t2 = getGMTime(fromSeconds(160070789)) # Mon 27 Jan 16:06:29 GMT 1975
   assert t2.format("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" &
     " ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") ==
     "27 27 Mon Monday 4 04 16 16 6 06 1 01 Jan January 29 29 P PM 5 75 975 1975 01975 0 00 00:00 UTC"
-  
+
   when not defined(JS) and sizeof(Time) == 8:
     var t3 = getGMTime(fromSeconds(889067643645)) # Fri  7 Jun 19:20:45 BST 30143
     assert t3.format("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" &
-      " ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") == 
+      " ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") ==
       "7 07 Fri Friday 6 06 18 18 20 20 6 06 Jun June 45 45 P PM 3 43 143 0143 30143 0 00 00:00 UTC"
-    assert t3.format(":,[]()-/") == ":,[]()-/" 
-  
+    assert t3.format(":,[]()-/") == ":,[]()-/"
+
   var t4 = getGMTime(fromSeconds(876124714)) # Mon  6 Oct 08:58:34 BST 1997
   assert t4.format("M MM MMM MMMM") == "10 10 Oct October"
-  
+
   # Interval tests
   assert((t4 - initInterval(years = 2)).format("yyyy") == "1995")
   assert((t4 - initInterval(years = 7, minutes = 34, seconds = 24)).format("yyyy mm ss") == "1990 24 10")
+
+  var s = "Tuesday at 09:04am on Dec 15, 2015"
+  var f = "dddd at hh:mmtt on MMM d, yyyy"
+  assert($s.parse(f) == "Tue Dec 15 09:04:00 2015")
+  # ANSIC       = "Mon Jan _2 15:04:05 2006"
+  s = "Mon Jan 2 15:04:05 2006"
+  f = "ddd MMM d HH:mm:ss yyyy"
+  assert($s.parse(f) == "Mon Jan  2 15:04:05 2006")
+  # UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
+  s = "Mon Jan 2 15:04:05 MST 2006"
+  f = "ddd MMM d HH:mm:ss ZZZ yyyy"
+  assert($s.parse(f) == "Mon Jan  2 15:04:05 2006")
+  # RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
+  s = "Mon Jan 02 15:04:05 -07:00 2006"
+  f = "ddd MMM dd HH:mm:ss zzz yyyy"
+  assert($s.parse(f) == "Mon Jan  2 15:04:05 2006")
+  # RFC822      = "02 Jan 06 15:04 MST"
+  s = "02 Jan 06 15:04 MST"
+  f = "dd MMM yy HH:mm ZZZ"
+  assert($s.parse(f) == "Mon Jan  2 15:04:00 2006")
+  # RFC822Z     = "02 Jan 06 15:04 -0700" # RFC822 with numeric zone
+  s = "02 Jan 06 15:04 -07:00"
+  f = "dd MMM yy HH:mm zzz"
+  assert($s.parse(f) == "Mon Jan  2 15:04:00 2006")
+  # RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
+  s = "Monday, 02-Jan-06 15:04:05 MST"
+  f = "dddd, dd-MMM-yy HH:mm:ss ZZZ"
+  assert($s.parse(f) == "Mon Jan  2 15:04:05 2006")
+  # RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
+  s = "Mon, 02 Jan 2006 15:04:05 MST"
+  f = "ddd, dd MMM yyyy HH:mm:ss ZZZ"
+  assert($s.parse(f) == "Mon Jan  2 15:04:05 2006")
+  # RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" # RFC1123 with numeric zone
+  s = "Mon, 02 Jan 2006 15:04:05 -07:00"
+  f = "ddd, dd MMM yyyy HH:mm:ss zzz"
+  assert($s.parse(f) == "Mon Jan  2 15:04:05 2006")
+  # RFC3339     = "2006-01-02T15:04:05Z07:00"
+  s = "2006-01-02T15:04:05Z-07:00"
+  f = "yyyy-MM-ddTHH:mm:ssZzzz"
+  assert($s.parse(f) == "Mon Jan  2 15:04:05 2006")
+  # RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
+  s = "2006-01-02T15:04:05.999999999Z-07:00"
+  f = "yyyy-MM-ddTHH:mm:ss.999999999Zzzz"
+  assert($s.parse(f) == "Mon Jan  2 15:04:05 2006")
+  # Kitchen     = "3:04PM"
+  s = "3:04PM"
+  f = "h:mmtt"
+  assert "15:04:00" in $s.parse(f)
+  when not defined(testing):
+    echo "Kitchen: " & $s.parse(f)
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim
index c2eb001f6..4a9f4631d 100644
--- a/lib/pure/unicode.nim
+++ b/lib/pure/unicode.nim
@@ -19,7 +19,7 @@ type
   Rune16* = distinct int16 ## 16 bit Unicode character
 
 {.deprecated: [TRune: Rune, TRune16: Rune16].}
-  
+
 proc `<=%`*(a, b: Rune): bool = return int(a) <=% int(b)
 proc `<%`*(a, b: Rune): bool = return int(a) <% int(b)
 proc `==`*(a, b: Rune): bool = return int(a) == int(b)
@@ -39,7 +39,7 @@ proc runeLen*(s: string): int {.rtl, extern: "nuc$1".} =
     else: inc i
     inc(result)
 
-proc runeLenAt*(s: string, i: int): int =
+proc runeLenAt*(s: string, i: Natural): int =
   ## returns the number of bytes the rune starting at ``s[i]`` takes.
   if ord(s[i]) <=% 127: result = 1
   elif ord(s[i]) shr 5 == 0b110: result = 2
@@ -58,7 +58,7 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
     when doInc: inc(i)
   elif ord(s[i]) shr 5 == 0b110:
     # assert(ord(s[i+1]) shr 6 == 0b10)
-    result = Rune((ord(s[i]) and (ones(5))) shl 6 or 
+    result = Rune((ord(s[i]) and (ones(5))) shl 6 or
                   (ord(s[i+1]) and ones(6)))
     when doInc: inc(i, 2)
   elif ord(s[i]) shr 4 == 0b1110:
@@ -77,7 +77,7 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
              (ord(s[i+2]) and ones(6)) shl 6 or
              (ord(s[i+3]) and ones(6)))
     when doInc: inc(i, 4)
-  elif ord(s[i]) shr 2 == 0b111110: 
+  elif ord(s[i]) shr 2 == 0b111110:
     # assert(ord(s[i+1]) shr 6 == 0b10)
     # assert(ord(s[i+2]) shr 6 == 0b10)
     # assert(ord(s[i+3]) shr 6 == 0b10)
@@ -88,7 +88,7 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
              (ord(s[i+3]) and ones(6)) shl 6 or
              (ord(s[i+4]) and ones(6)))
     when doInc: inc(i, 5)
-  elif ord(s[i]) shr 1 == 0b1111110: 
+  elif ord(s[i]) shr 1 == 0b1111110:
     # assert(ord(s[i+1]) shr 6 == 0b10)
     # assert(ord(s[i+2]) shr 6 == 0b10)
     # assert(ord(s[i+3]) shr 6 == 0b10)
@@ -105,11 +105,11 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
     result = Rune(ord(s[i]))
     when doInc: inc(i)
 
-proc runeAt*(s: string, i: int): Rune =
+proc runeAt*(s: string, i: Natural): Rune =
   ## returns the unicode character in `s` at byte index `i`
   fastRuneAt(s, i, result, false)
 
-proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} = 
+proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} =
   ## converts a rune into its UTF8 representation
   var i = RuneImpl(c)
   if i <=% 127:
@@ -118,21 +118,35 @@ proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} =
   elif i <=% 0x07FF:
     result = newString(2)
     result[0] = chr((i shr 6) or 0b110_00000)
-    result[1] = chr((i and ones(6)) or 0b10_000000)
+    result[1] = chr((i and ones(6)) or 0b10_0000_00)
   elif i <=% 0xFFFF:
     result = newString(3)
     result[0] = chr(i shr 12 or 0b1110_0000)
     result[1] = chr(i shr 6 and ones(6) or 0b10_0000_00)
     result[2] = chr(i and ones(6) or 0b10_0000_00)
-  elif i <=% 0x0010FFFF:
+  elif i <=% 0x001FFFFF:
     result = newString(4)
     result[0] = chr(i shr 18 or 0b1111_0000)
     result[1] = chr(i shr 12 and ones(6) or 0b10_0000_00)
     result[2] = chr(i shr 6 and ones(6) or 0b10_0000_00)
     result[3] = chr(i and ones(6) or 0b10_0000_00)
+  elif i <=% 0x03FFFFFF:
+    result = newString(5)
+    result[0] = chr(i shr 24 or 0b111110_00)
+    result[1] = chr(i shr 18 and ones(6) or 0b10_0000_00)
+    result[2] = chr(i shr 12 and ones(6) or 0b10_0000_00)
+    result[3] = chr(i shr 6 and ones(6) or 0b10_0000_00)
+    result[4] = chr(i and ones(6) or 0b10_0000_00)
+  elif i <=% 0x7FFFFFFF:
+    result = newString(6)
+    result[0] = chr(i shr 30 or 0b1111110_0)
+    result[1] = chr(i shr 24 and ones(6) or 0b10_0000_00)
+    result[2] = chr(i shr 18 and ones(6) or 0b10_0000_00)
+    result[3] = chr(i shr 12 and ones(6) or 0b10_0000_00)
+    result[4] = chr(i shr 6 and ones(6) or 0b10_0000_00)
+    result[5] = chr(i and ones(6) or 0b10_0000_00)
   else:
-    result = newString(1)
-    result[0] = chr(i)
+    discard # error, exception?
 
 proc `$`*(rune: Rune): string =
   ## converts a rune to a string
@@ -145,967 +159,967 @@ proc `$`*(runes: seq[Rune]): string =
 
 const
   alphaRanges = [
-    0x00d8,  0x00f6,  #  - 
-    0x00f8,  0x01f5,  #  -    
-    0x0250,  0x02a8,  #  -    
-    0x038e,  0x03a1,  #  -    
-    0x03a3,  0x03ce,  #  -    
-    0x03d0,  0x03d6,  #  -    
-    0x03e2,  0x03f3,  #  -    
-    0x0490,  0x04c4,  #  -    
-    0x0561,  0x0587,  #  -    
-    0x05d0,  0x05ea,  #  -    
-    0x05f0,  0x05f2,  #  -    
-    0x0621,  0x063a,  #  -    
-    0x0640,  0x064a,  #  -    
-    0x0671,  0x06b7,  #  -    
-    0x06ba,  0x06be,  #  -    
-    0x06c0,  0x06ce,  #  -    
-    0x06d0,  0x06d3,  #  -    
-    0x0905,  0x0939,  #  -    
-    0x0958,  0x0961,  #  -    
-    0x0985,  0x098c,  #  -    
-    0x098f,  0x0990,  #  -    
-    0x0993,  0x09a8,  #  -    
-    0x09aa,  0x09b0,  #  -    
-    0x09b6,  0x09b9,  #  -    
-    0x09dc,  0x09dd,  #  -    
-    0x09df,  0x09e1,  #  -    
-    0x09f0,  0x09f1,  #  -    
-    0x0a05,  0x0a0a,  #  -    
-    0x0a0f,  0x0a10,  #  -    
-    0x0a13,  0x0a28,  #  -    
-    0x0a2a,  0x0a30,  #  -    
-    0x0a32,  0x0a33,  #  -    
-    0x0a35,  0x0a36,  #  -    
-    0x0a38,  0x0a39,  #  -    
-    0x0a59,  0x0a5c,  #  -    
-    0x0a85,  0x0a8b,  #  -    
-    0x0a8f,  0x0a91,  #  -    
-    0x0a93,  0x0aa8,  #  -    
-    0x0aaa,  0x0ab0,  #  -    
-    0x0ab2,  0x0ab3,  #  -    
-    0x0ab5,  0x0ab9,  #  -    
-    0x0b05,  0x0b0c,  #  -    
-    0x0b0f,  0x0b10,  #  -    
-    0x0b13,  0x0b28,  #  -    
-    0x0b2a,  0x0b30,  #  -    
-    0x0b32,  0x0b33,  #  -    
-    0x0b36,  0x0b39,  #  -    
-    0x0b5c,  0x0b5d,  #  -    
-    0x0b5f,  0x0b61,  #  -    
-    0x0b85,  0x0b8a,  #  -    
-    0x0b8e,  0x0b90,  #  -    
-    0x0b92,  0x0b95,  #  -    
-    0x0b99,  0x0b9a,  #  -    
-    0x0b9e,  0x0b9f,  #  -    
-    0x0ba3,  0x0ba4,  #  -    
-    0x0ba8,  0x0baa,  #  -    
-    0x0bae,  0x0bb5,  #  -    
-    0x0bb7,  0x0bb9,  #  -    
-    0x0c05,  0x0c0c,  #  -    
-    0x0c0e,  0x0c10,  #  -    
-    0x0c12,  0x0c28,  #  -    
-    0x0c2a,  0x0c33,  #  -    
-    0x0c35,  0x0c39,  #  -    
-    0x0c60,  0x0c61,  #  -    
-    0x0c85,  0x0c8c,  #  -    
-    0x0c8e,  0x0c90,  #  -    
-    0x0c92,  0x0ca8,  #  -    
-    0x0caa,  0x0cb3,  #  -    
-    0x0cb5,  0x0cb9,  #  -    
-    0x0ce0,  0x0ce1,  #  -    
-    0x0d05,  0x0d0c,  #  -    
-    0x0d0e,  0x0d10,  #  -    
-    0x0d12,  0x0d28,  #  -    
-    0x0d2a,  0x0d39,  #  -    
-    0x0d60,  0x0d61,  #  -    
-    0x0e01,  0x0e30,  #  -    
-    0x0e32,  0x0e33,  #  -    
-    0x0e40,  0x0e46,  #  -    
-    0x0e5a,  0x0e5b,  #  -    
-    0x0e81,  0x0e82,  #  -    
-    0x0e87,  0x0e88,  #  -    
-    0x0e94,  0x0e97,  #  -    
-    0x0e99,  0x0e9f,  #  -    
-    0x0ea1,  0x0ea3,  #  -    
-    0x0eaa,  0x0eab,  #  -    
-    0x0ead,  0x0eae,  #  -    
-    0x0eb2,  0x0eb3,  #  -    
-    0x0ec0,  0x0ec4,  #  -    
-    0x0edc,  0x0edd,  #  -    
-    0x0f18,  0x0f19,  #  -    
-    0x0f40,  0x0f47,  #  -    
-    0x0f49,  0x0f69,  #  -    
-    0x10d0,  0x10f6,  #  -    
-    0x1100,  0x1159,  #  -    
-    0x115f,  0x11a2,  #  -    
-    0x11a8,  0x11f9,  #  -    
-    0x1e00,  0x1e9b,  #  -    
-    0x1f50,  0x1f57,  #  -    
-    0x1f80,  0x1fb4,  #  -    
-    0x1fb6,  0x1fbc,  #  -    
-    0x1fc2,  0x1fc4,  #  -    
-    0x1fc6,  0x1fcc,  #  -    
-    0x1fd0,  0x1fd3,  #  -    
-    0x1fd6,  0x1fdb,  #  -    
-    0x1fe0,  0x1fec,  #  -    
-    0x1ff2,  0x1ff4,  #  -    
-    0x1ff6,  0x1ffc,  #  -    
-    0x210a,  0x2113,  #  -    
-    0x2115,  0x211d,  #  -    
-    0x2120,  0x2122,  #  -    
-    0x212a,  0x2131,  #  -    
-    0x2133,  0x2138,  #  -    
-    0x3041,  0x3094,  #  -    
-    0x30a1,  0x30fa,  #  -    
-    0x3105,  0x312c,  #  -    
-    0x3131,  0x318e,  #  -    
-    0x3192,  0x319f,  #  -    
-    0x3260,  0x327b,  #  -    
-    0x328a,  0x32b0,  #  -    
-    0x32d0,  0x32fe,  #  -    
-    0x3300,  0x3357,  #  -    
-    0x3371,  0x3376,  #  -    
-    0x337b,  0x3394,  #  -    
-    0x3399,  0x339e,  #  -    
-    0x33a9,  0x33ad,  #  -    
-    0x33b0,  0x33c1,  #  -    
-    0x33c3,  0x33c5,  #  -    
-    0x33c7,  0x33d7,  #  -    
-    0x33d9,  0x33dd,  #  -    
-    0x4e00,  0x9fff,  #  -    
-    0xac00,  0xd7a3,  #  -    
-    0xf900,  0xfb06,  #  -    
-    0xfb13,  0xfb17,  #  -    
-    0xfb1f,  0xfb28,  #  -    
-    0xfb2a,  0xfb36,  #  -    
-    0xfb38,  0xfb3c,  #  -    
-    0xfb40,  0xfb41,  #  -    
-    0xfb43,  0xfb44,  #  -    
-    0xfb46,  0xfbb1,  #  -    
-    0xfbd3,  0xfd3d,  #  -    
-    0xfd50,  0xfd8f,  #  -    
-    0xfd92,  0xfdc7,  #  -    
-    0xfdf0,  0xfdf9,  #  -    
-    0xfe70,  0xfe72,  #  -    
-    0xfe76,  0xfefc,  #  -    
-    0xff66,  0xff6f,  #  -    
-    0xff71,  0xff9d,  #  -    
-    0xffa0,  0xffbe,  #  -    
-    0xffc2,  0xffc7,  #  -    
-    0xffca,  0xffcf,  #  -    
-    0xffd2,  0xffd7,  #  -    
-    0xffda,  0xffdc]  #  -    
+    0x00d8,  0x00f6,  #  -
+    0x00f8,  0x01f5,  #  -
+    0x0250,  0x02a8,  #  -
+    0x038e,  0x03a1,  #  -
+    0x03a3,  0x03ce,  #  -
+    0x03d0,  0x03d6,  #  -
+    0x03e2,  0x03f3,  #  -
+    0x0490,  0x04c4,  #  -
+    0x0561,  0x0587,  #  -
+    0x05d0,  0x05ea,  #  -
+    0x05f0,  0x05f2,  #  -
+    0x0621,  0x063a,  #  -
+    0x0640,  0x064a,  #  -
+    0x0671,  0x06b7,  #  -
+    0x06ba,  0x06be,  #  -
+    0x06c0,  0x06ce,  #  -
+    0x06d0,  0x06d3,  #  -
+    0x0905,  0x0939,  #  -
+    0x0958,  0x0961,  #  -
+    0x0985,  0x098c,  #  -
+    0x098f,  0x0990,  #  -
+    0x0993,  0x09a8,  #  -
+    0x09aa,  0x09b0,  #  -
+    0x09b6,  0x09b9,  #  -
+    0x09dc,  0x09dd,  #  -
+    0x09df,  0x09e1,  #  -
+    0x09f0,  0x09f1,  #  -
+    0x0a05,  0x0a0a,  #  -
+    0x0a0f,  0x0a10,  #  -
+    0x0a13,  0x0a28,  #  -
+    0x0a2a,  0x0a30,  #  -
+    0x0a32,  0x0a33,  #  -
+    0x0a35,  0x0a36,  #  -
+    0x0a38,  0x0a39,  #  -
+    0x0a59,  0x0a5c,  #  -
+    0x0a85,  0x0a8b,  #  -
+    0x0a8f,  0x0a91,  #  -
+    0x0a93,  0x0aa8,  #  -
+    0x0aaa,  0x0ab0,  #  -
+    0x0ab2,  0x0ab3,  #  -
+    0x0ab5,  0x0ab9,  #  -
+    0x0b05,  0x0b0c,  #  -
+    0x0b0f,  0x0b10,  #  -
+    0x0b13,  0x0b28,  #  -
+    0x0b2a,  0x0b30,  #  -
+    0x0b32,  0x0b33,  #  -
+    0x0b36,  0x0b39,  #  -
+    0x0b5c,  0x0b5d,  #  -
+    0x0b5f,  0x0b61,  #  -
+    0x0b85,  0x0b8a,  #  -
+    0x0b8e,  0x0b90,  #  -
+    0x0b92,  0x0b95,  #  -
+    0x0b99,  0x0b9a,  #  -
+    0x0b9e,  0x0b9f,  #  -
+    0x0ba3,  0x0ba4,  #  -
+    0x0ba8,  0x0baa,  #  -
+    0x0bae,  0x0bb5,  #  -
+    0x0bb7,  0x0bb9,  #  -
+    0x0c05,  0x0c0c,  #  -
+    0x0c0e,  0x0c10,  #  -
+    0x0c12,  0x0c28,  #  -
+    0x0c2a,  0x0c33,  #  -
+    0x0c35,  0x0c39,  #  -
+    0x0c60,  0x0c61,  #  -
+    0x0c85,  0x0c8c,  #  -
+    0x0c8e,  0x0c90,  #  -
+    0x0c92,  0x0ca8,  #  -
+    0x0caa,  0x0cb3,  #  -
+    0x0cb5,  0x0cb9,  #  -
+    0x0ce0,  0x0ce1,  #  -
+    0x0d05,  0x0d0c,  #  -
+    0x0d0e,  0x0d10,  #  -
+    0x0d12,  0x0d28,  #  -
+    0x0d2a,  0x0d39,  #  -
+    0x0d60,  0x0d61,  #  -
+    0x0e01,  0x0e30,  #  -
+    0x0e32,  0x0e33,  #  -
+    0x0e40,  0x0e46,  #  -
+    0x0e5a,  0x0e5b,  #  -
+    0x0e81,  0x0e82,  #  -
+    0x0e87,  0x0e88,  #  -
+    0x0e94,  0x0e97,  #  -
+    0x0e99,  0x0e9f,  #  -
+    0x0ea1,  0x0ea3,  #  -
+    0x0eaa,  0x0eab,  #  -
+    0x0ead,  0x0eae,  #  -
+    0x0eb2,  0x0eb3,  #  -
+    0x0ec0,  0x0ec4,  #  -
+    0x0edc,  0x0edd,  #  -
+    0x0f18,  0x0f19,  #  -
+    0x0f40,  0x0f47,  #  -
+    0x0f49,  0x0f69,  #  -
+    0x10d0,  0x10f6,  #  -
+    0x1100,  0x1159,  #  -
+    0x115f,  0x11a2,  #  -
+    0x11a8,  0x11f9,  #  -
+    0x1e00,  0x1e9b,  #  -
+    0x1f50,  0x1f57,  #  -
+    0x1f80,  0x1fb4,  #  -
+    0x1fb6,  0x1fbc,  #  -
+    0x1fc2,  0x1fc4,  #  -
+    0x1fc6,  0x1fcc,  #  -
+    0x1fd0,  0x1fd3,  #  -
+    0x1fd6,  0x1fdb,  #  -
+    0x1fe0,  0x1fec,  #  -
+    0x1ff2,  0x1ff4,  #  -
+    0x1ff6,  0x1ffc,  #  -
+    0x210a,  0x2113,  #  -
+    0x2115,  0x211d,  #  -
+    0x2120,  0x2122,  #  -
+    0x212a,  0x2131,  #  -
+    0x2133,  0x2138,  #  -
+    0x3041,  0x3094,  #  -
+    0x30a1,  0x30fa,  #  -
+    0x3105,  0x312c,  #  -
+    0x3131,  0x318e,  #  -
+    0x3192,  0x319f,  #  -
+    0x3260,  0x327b,  #  -
+    0x328a,  0x32b0,  #  -
+    0x32d0,  0x32fe,  #  -
+    0x3300,  0x3357,  #  -
+    0x3371,  0x3376,  #  -
+    0x337b,  0x3394,  #  -
+    0x3399,  0x339e,  #  -
+    0x33a9,  0x33ad,  #  -
+    0x33b0,  0x33c1,  #  -
+    0x33c3,  0x33c5,  #  -
+    0x33c7,  0x33d7,  #  -
+    0x33d9,  0x33dd,  #  -
+    0x4e00,  0x9fff,  #  -
+    0xac00,  0xd7a3,  #  -
+    0xf900,  0xfb06,  #  -
+    0xfb13,  0xfb17,  #  -
+    0xfb1f,  0xfb28,  #  -
+    0xfb2a,  0xfb36,  #  -
+    0xfb38,  0xfb3c,  #  -
+    0xfb40,  0xfb41,  #  -
+    0xfb43,  0xfb44,  #  -
+    0xfb46,  0xfbb1,  #  -
+    0xfbd3,  0xfd3d,  #  -
+    0xfd50,  0xfd8f,  #  -
+    0xfd92,  0xfdc7,  #  -
+    0xfdf0,  0xfdf9,  #  -
+    0xfe70,  0xfe72,  #  -
+    0xfe76,  0xfefc,  #  -
+    0xff66,  0xff6f,  #  -
+    0xff71,  0xff9d,  #  -
+    0xffa0,  0xffbe,  #  -
+    0xffc2,  0xffc7,  #  -
+    0xffca,  0xffcf,  #  -
+    0xffd2,  0xffd7,  #  -
+    0xffda,  0xffdc]  #  -
 
   alphaSinglets = [
-    0x00aa,  #    
-    0x00b5,  #    
-    0x00ba,  #    
-    0x03da,  #    
-    0x03dc,  #    
-    0x03de,  #    
-    0x03e0,  #    
-    0x06d5,  #    
-    0x09b2,  #    
-    0x0a5e,  #    
-    0x0a8d,  #    
-    0x0ae0,  #    
-    0x0b9c,  #    
-    0x0cde,  #    
-    0x0e4f,  #    
-    0x0e84,  #    
-    0x0e8a,  #    
-    0x0e8d,  #    
-    0x0ea5,  #    
-    0x0ea7,  #    
-    0x0eb0,  #    
-    0x0ebd,  #    
-    0x1fbe,  #    
-    0x207f,  #    
-    0x20a8,  #    
-    0x2102,  #    
-    0x2107,  #    
-    0x2124,  #    
-    0x2126,  #    
-    0x2128,  #    
-    0xfb3e,  #    
-    0xfe74]  #    
+    0x00aa,  #
+    0x00b5,  #
+    0x00ba,  #
+    0x03da,  #
+    0x03dc,  #
+    0x03de,  #
+    0x03e0,  #
+    0x06d5,  #
+    0x09b2,  #
+    0x0a5e,  #
+    0x0a8d,  #
+    0x0ae0,  #
+    0x0b9c,  #
+    0x0cde,  #
+    0x0e4f,  #
+    0x0e84,  #
+    0x0e8a,  #
+    0x0e8d,  #
+    0x0ea5,  #
+    0x0ea7,  #
+    0x0eb0,  #
+    0x0ebd,  #
+    0x1fbe,  #
+    0x207f,  #
+    0x20a8,  #
+    0x2102,  #
+    0x2107,  #
+    0x2124,  #
+    0x2126,  #
+    0x2128,  #
+    0xfb3e,  #
+    0xfe74]  #
 
   spaceRanges = [
-    0x0009,  0x000a,  # tab and newline   
-    0x0020,  0x0020,  # space   
-    0x00a0,  0x00a0,  #    
-    0x2000,  0x200b,  #  -    
-    0x2028,  0x2029,  #  -     0x3000,  0x3000,  #    
-    0xfeff,  0xfeff]  #    
+    0x0009,  0x000a,  # tab and newline
+    0x0020,  0x0020,  # space
+    0x00a0,  0x00a0,  #
+    0x2000,  0x200b,  #  -
+    0x2028,  0x2029,  #  -     0x3000,  0x3000,  #
+    0xfeff,  0xfeff]  #
 
   toupperRanges = [
-    0x0061,  0x007a, 468,  # a-z A-Z   
-    0x00e0,  0x00f6, 468,  # - -   
-    0x00f8,  0x00fe, 468,  # - -   
-    0x0256,  0x0257, 295,  # - -   
-    0x0258,  0x0259, 298,  # - -   
-    0x028a,  0x028b, 283,  # - -   
-    0x03ad,  0x03af, 463,  # - -   
-    0x03b1,  0x03c1, 468,  # - -   
-    0x03c3,  0x03cb, 468,  # - -   
-    0x03cd,  0x03ce, 437,  # - -   
-    0x0430,  0x044f, 468,  # - -   
-    0x0451,  0x045c, 420,  # - -   
-    0x045e,  0x045f, 420,  # - -   
-    0x0561,  0x0586, 452,  # - -   
-    0x1f00,  0x1f07, 508,  # - -   
-    0x1f10,  0x1f15, 508,  # - -   
-    0x1f20,  0x1f27, 508,  # - -   
-    0x1f30,  0x1f37, 508,  # - -   
-    0x1f40,  0x1f45, 508,  # - -   
-    0x1f60,  0x1f67, 508,  # - -   
-    0x1f70,  0x1f71, 574,  # - -   
-    0x1f72,  0x1f75, 586,  # - -   
-    0x1f76,  0x1f77, 600,  # - -   
-    0x1f78,  0x1f79, 628,  # - -   
-    0x1f7a,  0x1f7b, 612,  # - -   
-    0x1f7c,  0x1f7d, 626,  # - -   
-    0x1f80,  0x1f87, 508,  # - -   
-    0x1f90,  0x1f97, 508,  # - -   
-    0x1fa0,  0x1fa7, 508,  # - -   
-    0x1fb0,  0x1fb1, 508,  # - -   
-    0x1fd0,  0x1fd1, 508,  # - -   
-    0x1fe0,  0x1fe1, 508,  # - -   
-    0x2170,  0x217f, 484,  # - -   
-    0x24d0,  0x24e9, 474,  # - -   
-    0xff41,  0xff5a, 468]  # - -   
+    0x0061,  0x007a, 468,  # a-z A-Z
+    0x00e0,  0x00f6, 468,  # - -
+    0x00f8,  0x00fe, 468,  # - -
+    0x0256,  0x0257, 295,  # - -
+    0x0258,  0x0259, 298,  # - -
+    0x028a,  0x028b, 283,  # - -
+    0x03ad,  0x03af, 463,  # - -
+    0x03b1,  0x03c1, 468,  # - -
+    0x03c3,  0x03cb, 468,  # - -
+    0x03cd,  0x03ce, 437,  # - -
+    0x0430,  0x044f, 468,  # - -
+    0x0451,  0x045c, 420,  # - -
+    0x045e,  0x045f, 420,  # - -
+    0x0561,  0x0586, 452,  # - -
+    0x1f00,  0x1f07, 508,  # - -
+    0x1f10,  0x1f15, 508,  # - -
+    0x1f20,  0x1f27, 508,  # - -
+    0x1f30,  0x1f37, 508,  # - -
+    0x1f40,  0x1f45, 508,  # - -
+    0x1f60,  0x1f67, 508,  # - -
+    0x1f70,  0x1f71, 574,  # - -
+    0x1f72,  0x1f75, 586,  # - -
+    0x1f76,  0x1f77, 600,  # - -
+    0x1f78,  0x1f79, 628,  # - -
+    0x1f7a,  0x1f7b, 612,  # - -
+    0x1f7c,  0x1f7d, 626,  # - -
+    0x1f80,  0x1f87, 508,  # - -
+    0x1f90,  0x1f97, 508,  # - -
+    0x1fa0,  0x1fa7, 508,  # - -
+    0x1fb0,  0x1fb1, 508,  # - -
+    0x1fd0,  0x1fd1, 508,  # - -
+    0x1fe0,  0x1fe1, 508,  # - -
+    0x2170,  0x217f, 484,  # - -
+    0x24d0,  0x24e9, 474,  # - -
+    0xff41,  0xff5a, 468]  # - -
 
   toupperSinglets = [
-    0x00ff, 621,  #     
-    0x0101, 499,  #     
-    0x0103, 499,  #     
-    0x0105, 499,  #     
-    0x0107, 499,  #     
-    0x0109, 499,  #     
-    0x010b, 499,  #     
-    0x010d, 499,  #     
-    0x010f, 499,  #     
-    0x0111, 499,  #     
-    0x0113, 499,  #     
-    0x0115, 499,  #     
-    0x0117, 499,  #     
-    0x0119, 499,  #     
-    0x011b, 499,  #     
-    0x011d, 499,  #     
-    0x011f, 499,  #     
-    0x0121, 499,  #     
-    0x0123, 499,  #     
-    0x0125, 499,  #     
-    0x0127, 499,  #     
-    0x0129, 499,  #     
-    0x012b, 499,  #     
-    0x012d, 499,  #     
-    0x012f, 499,  #     
-    0x0131, 268,  #  I   
-    0x0133, 499,  #     
-    0x0135, 499,  #     
-    0x0137, 499,  #     
-    0x013a, 499,  #     
-    0x013c, 499,  #     
-    0x013e, 499,  #     
-    0x0140, 499,  #     
-    0x0142, 499,  #     
-    0x0144, 499,  #     
-    0x0146, 499,  #     
-    0x0148, 499,  #     
-    0x014b, 499,  #     
-    0x014d, 499,  #     
-    0x014f, 499,  #     
-    0x0151, 499,  #     
-    0x0153, 499,  #     
-    0x0155, 499,  #     
-    0x0157, 499,  #     
-    0x0159, 499,  #     
-    0x015b, 499,  #     
-    0x015d, 499,  #     
-    0x015f, 499,  #     
-    0x0161, 499,  #     
-    0x0163, 499,  #     
-    0x0165, 499,  #     
-    0x0167, 499,  #     
-    0x0169, 499,  #     
-    0x016b, 499,  #     
-    0x016d, 499,  #     
-    0x016f, 499,  #     
-    0x0171, 499,  #     
-    0x0173, 499,  #     
-    0x0175, 499,  #     
-    0x0177, 499,  #     
-    0x017a, 499,  #     
-    0x017c, 499,  #     
-    0x017e, 499,  #     
-    0x017f, 200,  #  S   
-    0x0183, 499,  #     
-    0x0185, 499,  #     
-    0x0188, 499,  #     
-    0x018c, 499,  #     
-    0x0192, 499,  #     
-    0x0199, 499,  #     
-    0x01a1, 499,  #     
-    0x01a3, 499,  #     
-    0x01a5, 499,  #     
-    0x01a8, 499,  #     
-    0x01ad, 499,  #     
-    0x01b0, 499,  #     
-    0x01b4, 499,  #     
-    0x01b6, 499,  #     
-    0x01b9, 499,  #     
-    0x01bd, 499,  #     
-    0x01c5, 499,  #     
-    0x01c6, 498,  #     
-    0x01c8, 499,  #     
-    0x01c9, 498,  #     
-    0x01cb, 499,  #     
-    0x01cc, 498,  #     
-    0x01ce, 499,  #     
-    0x01d0, 499,  #     
-    0x01d2, 499,  #     
-    0x01d4, 499,  #     
-    0x01d6, 499,  #     
-    0x01d8, 499,  #     
-    0x01da, 499,  #     
-    0x01dc, 499,  #     
-    0x01df, 499,  #     
-    0x01e1, 499,  #     
-    0x01e3, 499,  #     
-    0x01e5, 499,  #     
-    0x01e7, 499,  #     
-    0x01e9, 499,  #     
-    0x01eb, 499,  #     
-    0x01ed, 499,  #     
-    0x01ef, 499,  #     
-    0x01f2, 499,  #     
-    0x01f3, 498,  #     
-    0x01f5, 499,  #     
-    0x01fb, 499,  #     
-    0x01fd, 499,  #     
-    0x01ff, 499,  #     
-    0x0201, 499,  #     
-    0x0203, 499,  #     
-    0x0205, 499,  #     
-    0x0207, 499,  #     
-    0x0209, 499,  #     
-    0x020b, 499,  #     
-    0x020d, 499,  #     
-    0x020f, 499,  #     
-    0x0211, 499,  #     
-    0x0213, 499,  #     
-    0x0215, 499,  #     
-    0x0217, 499,  #     
-    0x0253, 290,  #     
-    0x0254, 294,  #     
-    0x025b, 297,  #     
-    0x0260, 295,  #     
-    0x0263, 293,  #     
-    0x0268, 291,  #     
-    0x0269, 289,  #     
-    0x026f, 289,  #     
-    0x0272, 287,  #     
-    0x0283, 282,  #     
-    0x0288, 282,  #     
-    0x0292, 281,  #     
-    0x03ac, 462,  #     
-    0x03cc, 436,  #     
-    0x03d0, 438,  #     
-    0x03d1, 443,  #     
-    0x03d5, 453,  #     
-    0x03d6, 446,  #     
-    0x03e3, 499,  #     
-    0x03e5, 499,  #     
-    0x03e7, 499,  #     
-    0x03e9, 499,  #     
-    0x03eb, 499,  #     
-    0x03ed, 499,  #     
-    0x03ef, 499,  #     
-    0x03f0, 414,  #     
-    0x03f1, 420,  #     
-    0x0461, 499,  #     
-    0x0463, 499,  #     
-    0x0465, 499,  #     
-    0x0467, 499,  #     
-    0x0469, 499,  #     
-    0x046b, 499,  #     
-    0x046d, 499,  #     
-    0x046f, 499,  #     
-    0x0471, 499,  #     
-    0x0473, 499,  #     
-    0x0475, 499,  #     
-    0x0477, 499,  #     
-    0x0479, 499,  #     
-    0x047b, 499,  #     
-    0x047d, 499,  #     
-    0x047f, 499,  #     
-    0x0481, 499,  #     
-    0x0491, 499,  #     
-    0x0493, 499,  #     
-    0x0495, 499,  #     
-    0x0497, 499,  #     
-    0x0499, 499,  #     
-    0x049b, 499,  #     
-    0x049d, 499,  #     
-    0x049f, 499,  #     
-    0x04a1, 499,  #     
-    0x04a3, 499,  #     
-    0x04a5, 499,  #     
-    0x04a7, 499,  #     
-    0x04a9, 499,  #     
-    0x04ab, 499,  #     
-    0x04ad, 499,  #     
-    0x04af, 499,  #     
-    0x04b1, 499,  #     
-    0x04b3, 499,  #     
-    0x04b5, 499,  #     
-    0x04b7, 499,  #     
-    0x04b9, 499,  #     
-    0x04bb, 499,  #     
-    0x04bd, 499,  #     
-    0x04bf, 499,  #     
-    0x04c2, 499,  #     
-    0x04c4, 499,  #     
-    0x04c8, 499,  #     
-    0x04cc, 499,  #     
-    0x04d1, 499,  #     
-    0x04d3, 499,  #     
-    0x04d5, 499,  #     
-    0x04d7, 499,  #     
-    0x04d9, 499,  #     
-    0x04db, 499,  #     
-    0x04dd, 499,  #     
-    0x04df, 499,  #     
-    0x04e1, 499,  #     
-    0x04e3, 499,  #     
-    0x04e5, 499,  #     
-    0x04e7, 499,  #     
-    0x04e9, 499,  #     
-    0x04eb, 499,  #     
-    0x04ef, 499,  #     
-    0x04f1, 499,  #     
-    0x04f3, 499,  #     
-    0x04f5, 499,  #     
-    0x04f9, 499,  #     
-    0x1e01, 499,  #     
-    0x1e03, 499,  #     
-    0x1e05, 499,  #     
-    0x1e07, 499,  #     
-    0x1e09, 499,  #     
-    0x1e0b, 499,  #     
-    0x1e0d, 499,  #     
-    0x1e0f, 499,  #     
-    0x1e11, 499,  #     
-    0x1e13, 499,  #     
-    0x1e15, 499,  #     
-    0x1e17, 499,  #     
-    0x1e19, 499,  #     
-    0x1e1b, 499,  #     
-    0x1e1d, 499,  #     
-    0x1e1f, 499,  #     
-    0x1e21, 499,  #     
-    0x1e23, 499,  #     
-    0x1e25, 499,  #     
-    0x1e27, 499,  #     
-    0x1e29, 499,  #     
-    0x1e2b, 499,  #     
-    0x1e2d, 499,  #     
-    0x1e2f, 499,  #     
-    0x1e31, 499,  #     
-    0x1e33, 499,  #     
-    0x1e35, 499,  #     
-    0x1e37, 499,  #     
-    0x1e39, 499,  #     
-    0x1e3b, 499,  #     
-    0x1e3d, 499,  #     
-    0x1e3f, 499,  #     
-    0x1e41, 499,  #     
-    0x1e43, 499,  #     
-    0x1e45, 499,  #     
-    0x1e47, 499,  #     
-    0x1e49, 499,  #     
-    0x1e4b, 499,  #     
-    0x1e4d, 499,  #     
-    0x1e4f, 499,  #     
-    0x1e51, 499,  #     
-    0x1e53, 499,  #     
-    0x1e55, 499,  #     
-    0x1e57, 499,  #     
-    0x1e59, 499,  #     
-    0x1e5b, 499,  #     
-    0x1e5d, 499,  #     
-    0x1e5f, 499,  #     
-    0x1e61, 499,  #     
-    0x1e63, 499,  #     
-    0x1e65, 499,  #     
-    0x1e67, 499,  #     
-    0x1e69, 499,  #     
-    0x1e6b, 499,  #     
-    0x1e6d, 499,  #     
-    0x1e6f, 499,  #     
-    0x1e71, 499,  #     
-    0x1e73, 499,  #     
-    0x1e75, 499,  #     
-    0x1e77, 499,  #     
-    0x1e79, 499,  #     
-    0x1e7b, 499,  #     
-    0x1e7d, 499,  #     
-    0x1e7f, 499,  #     
-    0x1e81, 499,  #     
-    0x1e83, 499,  #     
-    0x1e85, 499,  #     
-    0x1e87, 499,  #     
-    0x1e89, 499,  #     
-    0x1e8b, 499,  #     
-    0x1e8d, 499,  #     
-    0x1e8f, 499,  #     
-    0x1e91, 499,  #     
-    0x1e93, 499,  #     
-    0x1e95, 499,  #     
-    0x1ea1, 499,  #     
-    0x1ea3, 499,  #     
-    0x1ea5, 499,  #     
-    0x1ea7, 499,  #     
-    0x1ea9, 499,  #     
-    0x1eab, 499,  #     
-    0x1ead, 499,  #     
-    0x1eaf, 499,  #     
-    0x1eb1, 499,  #     
-    0x1eb3, 499,  #     
-    0x1eb5, 499,  #     
-    0x1eb7, 499,  #     
-    0x1eb9, 499,  #     
-    0x1ebb, 499,  #     
-    0x1ebd, 499,  #     
-    0x1ebf, 499,  #     
-    0x1ec1, 499,  #     
-    0x1ec3, 499,  #     
-    0x1ec5, 499,  #     
-    0x1ec7, 499,  #     
-    0x1ec9, 499,  #     
-    0x1ecb, 499,  #     
-    0x1ecd, 499,  #     
-    0x1ecf, 499,  #     
-    0x1ed1, 499,  #     
-    0x1ed3, 499,  #     
-    0x1ed5, 499,  #     
-    0x1ed7, 499,  #     
-    0x1ed9, 499,  #     
-    0x1edb, 499,  #     
-    0x1edd, 499,  #     
-    0x1edf, 499,  #     
-    0x1ee1, 499,  #     
-    0x1ee3, 499,  #     
-    0x1ee5, 499,  #     
-    0x1ee7, 499,  #     
-    0x1ee9, 499,  #     
-    0x1eeb, 499,  #     
-    0x1eed, 499,  #     
-    0x1eef, 499,  #     
-    0x1ef1, 499,  #     
-    0x1ef3, 499,  #     
-    0x1ef5, 499,  #     
-    0x1ef7, 499,  #     
-    0x1ef9, 499,  #     
-    0x1f51, 508,  #     
-    0x1f53, 508,  #     
-    0x1f55, 508,  #     
-    0x1f57, 508,  #     
-    0x1fb3, 509,  #     
-    0x1fc3, 509,  #     
-    0x1fe5, 507,  #     
-    0x1ff3, 509]  #     
+    0x00ff, 621,  #
+    0x0101, 499,  #
+    0x0103, 499,  #
+    0x0105, 499,  #
+    0x0107, 499,  #
+    0x0109, 499,  #
+    0x010b, 499,  #
+    0x010d, 499,  #
+    0x010f, 499,  #
+    0x0111, 499,  #
+    0x0113, 499,  #
+    0x0115, 499,  #
+    0x0117, 499,  #
+    0x0119, 499,  #
+    0x011b, 499,  #
+    0x011d, 499,  #
+    0x011f, 499,  #
+    0x0121, 499,  #
+    0x0123, 499,  #
+    0x0125, 499,  #
+    0x0127, 499,  #
+    0x0129, 499,  #
+    0x012b, 499,  #
+    0x012d, 499,  #
+    0x012f, 499,  #
+    0x0131, 268,  #  I
+    0x0133, 499,  #
+    0x0135, 499,  #
+    0x0137, 499,  #
+    0x013a, 499,  #
+    0x013c, 499,  #
+    0x013e, 499,  #
+    0x0140, 499,  #
+    0x0142, 499,  #
+    0x0144, 499,  #
+    0x0146, 499,  #
+    0x0148, 499,  #
+    0x014b, 499,  #
+    0x014d, 499,  #
+    0x014f, 499,  #
+    0x0151, 499,  #
+    0x0153, 499,  #
+    0x0155, 499,  #
+    0x0157, 499,  #
+    0x0159, 499,  #
+    0x015b, 499,  #
+    0x015d, 499,  #
+    0x015f, 499,  #
+    0x0161, 499,  #
+    0x0163, 499,  #
+    0x0165, 499,  #
+    0x0167, 499,  #
+    0x0169, 499,  #
+    0x016b, 499,  #
+    0x016d, 499,  #
+    0x016f, 499,  #
+    0x0171, 499,  #
+    0x0173, 499,  #
+    0x0175, 499,  #
+    0x0177, 499,  #
+    0x017a, 499,  #
+    0x017c, 499,  #
+    0x017e, 499,  #
+    0x017f, 200,  #  S
+    0x0183, 499,  #
+    0x0185, 499,  #
+    0x0188, 499,  #
+    0x018c, 499,  #
+    0x0192, 499,  #
+    0x0199, 499,  #
+    0x01a1, 499,  #
+    0x01a3, 499,  #
+    0x01a5, 499,  #
+    0x01a8, 499,  #
+    0x01ad, 499,  #
+    0x01b0, 499,  #
+    0x01b4, 499,  #
+    0x01b6, 499,  #
+    0x01b9, 499,  #
+    0x01bd, 499,  #
+    0x01c5, 499,  #
+    0x01c6, 498,  #
+    0x01c8, 499,  #
+    0x01c9, 498,  #
+    0x01cb, 499,  #
+    0x01cc, 498,  #
+    0x01ce, 499,  #
+    0x01d0, 499,  #
+    0x01d2, 499,  #
+    0x01d4, 499,  #
+    0x01d6, 499,  #
+    0x01d8, 499,  #
+    0x01da, 499,  #
+    0x01dc, 499,  #
+    0x01df, 499,  #
+    0x01e1, 499,  #
+    0x01e3, 499,  #
+    0x01e5, 499,  #
+    0x01e7, 499,  #
+    0x01e9, 499,  #
+    0x01eb, 499,  #
+    0x01ed, 499,  #
+    0x01ef, 499,  #
+    0x01f2, 499,  #
+    0x01f3, 498,  #
+    0x01f5, 499,  #
+    0x01fb, 499,  #
+    0x01fd, 499,  #
+    0x01ff, 499,  #
+    0x0201, 499,  #
+    0x0203, 499,  #
+    0x0205, 499,  #
+    0x0207, 499,  #
+    0x0209, 499,  #
+    0x020b, 499,  #
+    0x020d, 499,  #
+    0x020f, 499,  #
+    0x0211, 499,  #
+    0x0213, 499,  #
+    0x0215, 499,  #
+    0x0217, 499,  #
+    0x0253, 290,  #
+    0x0254, 294,  #
+    0x025b, 297,  #
+    0x0260, 295,  #
+    0x0263, 293,  #
+    0x0268, 291,  #
+    0x0269, 289,  #
+    0x026f, 289,  #
+    0x0272, 287,  #
+    0x0283, 282,  #
+    0x0288, 282,  #
+    0x0292, 281,  #
+    0x03ac, 462,  #
+    0x03cc, 436,  #
+    0x03d0, 438,  #
+    0x03d1, 443,  #
+    0x03d5, 453,  #
+    0x03d6, 446,  #
+    0x03e3, 499,  #
+    0x03e5, 499,  #
+    0x03e7, 499,  #
+    0x03e9, 499,  #
+    0x03eb, 499,  #
+    0x03ed, 499,  #
+    0x03ef, 499,  #
+    0x03f0, 414,  #
+    0x03f1, 420,  #
+    0x0461, 499,  #
+    0x0463, 499,  #
+    0x0465, 499,  #
+    0x0467, 499,  #
+    0x0469, 499,  #
+    0x046b, 499,  #
+    0x046d, 499,  #
+    0x046f, 499,  #
+    0x0471, 499,  #
+    0x0473, 499,  #
+    0x0475, 499,  #
+    0x0477, 499,  #
+    0x0479, 499,  #
+    0x047b, 499,  #
+    0x047d, 499,  #
+    0x047f, 499,  #
+    0x0481, 499,  #
+    0x0491, 499,  #
+    0x0493, 499,  #
+    0x0495, 499,  #
+    0x0497, 499,  #
+    0x0499, 499,  #
+    0x049b, 499,  #
+    0x049d, 499,  #
+    0x049f, 499,  #
+    0x04a1, 499,  #
+    0x04a3, 499,  #
+    0x04a5, 499,  #
+    0x04a7, 499,  #
+    0x04a9, 499,  #
+    0x04ab, 499,  #
+    0x04ad, 499,  #
+    0x04af, 499,  #
+    0x04b1, 499,  #
+    0x04b3, 499,  #
+    0x04b5, 499,  #
+    0x04b7, 499,  #
+    0x04b9, 499,  #
+    0x04bb, 499,  #
+    0x04bd, 499,  #
+    0x04bf, 499,  #
+    0x04c2, 499,  #
+    0x04c4, 499,  #
+    0x04c8, 499,  #
+    0x04cc, 499,  #
+    0x04d1, 499,  #
+    0x04d3, 499,  #
+    0x04d5, 499,  #
+    0x04d7, 499,  #
+    0x04d9, 499,  #
+    0x04db, 499,  #
+    0x04dd, 499,  #
+    0x04df, 499,  #
+    0x04e1, 499,  #
+    0x04e3, 499,  #
+    0x04e5, 499,  #
+    0x04e7, 499,  #
+    0x04e9, 499,  #
+    0x04eb, 499,  #
+    0x04ef, 499,  #
+    0x04f1, 499,  #
+    0x04f3, 499,  #
+    0x04f5, 499,  #
+    0x04f9, 499,  #
+    0x1e01, 499,  #
+    0x1e03, 499,  #
+    0x1e05, 499,  #
+    0x1e07, 499,  #
+    0x1e09, 499,  #
+    0x1e0b, 499,  #
+    0x1e0d, 499,  #
+    0x1e0f, 499,  #
+    0x1e11, 499,  #
+    0x1e13, 499,  #
+    0x1e15, 499,  #
+    0x1e17, 499,  #
+    0x1e19, 499,  #
+    0x1e1b, 499,  #
+    0x1e1d, 499,  #
+    0x1e1f, 499,  #
+    0x1e21, 499,  #
+    0x1e23, 499,  #
+    0x1e25, 499,  #
+    0x1e27, 499,  #
+    0x1e29, 499,  #
+    0x1e2b, 499,  #
+    0x1e2d, 499,  #
+    0x1e2f, 499,  #
+    0x1e31, 499,  #
+    0x1e33, 499,  #
+    0x1e35, 499,  #
+    0x1e37, 499,  #
+    0x1e39, 499,  #
+    0x1e3b, 499,  #
+    0x1e3d, 499,  #
+    0x1e3f, 499,  #
+    0x1e41, 499,  #
+    0x1e43, 499,  #
+    0x1e45, 499,  #
+    0x1e47, 499,  #
+    0x1e49, 499,  #
+    0x1e4b, 499,  #
+    0x1e4d, 499,  #
+    0x1e4f, 499,  #
+    0x1e51, 499,  #
+    0x1e53, 499,  #
+    0x1e55, 499,  #
+    0x1e57, 499,  #
+    0x1e59, 499,  #
+    0x1e5b, 499,  #
+    0x1e5d, 499,  #
+    0x1e5f, 499,  #
+    0x1e61, 499,  #
+    0x1e63, 499,  #
+    0x1e65, 499,  #
+    0x1e67, 499,  #
+    0x1e69, 499,  #
+    0x1e6b, 499,  #
+    0x1e6d, 499,  #
+    0x1e6f, 499,  #
+    0x1e71, 499,  #
+    0x1e73, 499,  #
+    0x1e75, 499,  #
+    0x1e77, 499,  #
+    0x1e79, 499,  #
+    0x1e7b, 499,  #
+    0x1e7d, 499,  #
+    0x1e7f, 499,  #
+    0x1e81, 499,  #
+    0x1e83, 499,  #
+    0x1e85, 499,  #
+    0x1e87, 499,  #
+    0x1e89, 499,  #
+    0x1e8b, 499,  #
+    0x1e8d, 499,  #
+    0x1e8f, 499,  #
+    0x1e91, 499,  #
+    0x1e93, 499,  #
+    0x1e95, 499,  #
+    0x1ea1, 499,  #
+    0x1ea3, 499,  #
+    0x1ea5, 499,  #
+    0x1ea7, 499,  #
+    0x1ea9, 499,  #
+    0x1eab, 499,  #
+    0x1ead, 499,  #
+    0x1eaf, 499,  #
+    0x1eb1, 499,  #
+    0x1eb3, 499,  #
+    0x1eb5, 499,  #
+    0x1eb7, 499,  #
+    0x1eb9, 499,  #
+    0x1ebb, 499,  #
+    0x1ebd, 499,  #
+    0x1ebf, 499,  #
+    0x1ec1, 499,  #
+    0x1ec3, 499,  #
+    0x1ec5, 499,  #
+    0x1ec7, 499,  #
+    0x1ec9, 499,  #
+    0x1ecb, 499,  #
+    0x1ecd, 499,  #
+    0x1ecf, 499,  #
+    0x1ed1, 499,  #
+    0x1ed3, 499,  #
+    0x1ed5, 499,  #
+    0x1ed7, 499,  #
+    0x1ed9, 499,  #
+    0x1edb, 499,  #
+    0x1edd, 499,  #
+    0x1edf, 499,  #
+    0x1ee1, 499,  #
+    0x1ee3, 499,  #
+    0x1ee5, 499,  #
+    0x1ee7, 499,  #
+    0x1ee9, 499,  #
+    0x1eeb, 499,  #
+    0x1eed, 499,  #
+    0x1eef, 499,  #
+    0x1ef1, 499,  #
+    0x1ef3, 499,  #
+    0x1ef5, 499,  #
+    0x1ef7, 499,  #
+    0x1ef9, 499,  #
+    0x1f51, 508,  #
+    0x1f53, 508,  #
+    0x1f55, 508,  #
+    0x1f57, 508,  #
+    0x1fb3, 509,  #
+    0x1fc3, 509,  #
+    0x1fe5, 507,  #
+    0x1ff3, 509]  #
 
   tolowerRanges = [
     0x0041,  0x005a, 532,  # A-Z a-z
-    0x00c0,  0x00d6, 532,  # - -   
-    0x00d8,  0x00de, 532,  # - -   
-    0x0189,  0x018a, 705,  # - -   
-    0x018e,  0x018f, 702,  # - -   
-    0x01b1,  0x01b2, 717,  # - -   
-    0x0388,  0x038a, 537,  # - -   
-    0x038e,  0x038f, 563,  # - -   
-    0x0391,  0x03a1, 532,  # - -   
-    0x03a3,  0x03ab, 532,  # - -   
-    0x0401,  0x040c, 580,  # - -   
-    0x040e,  0x040f, 580,  # - -   
-    0x0410,  0x042f, 532,  # - -   
-    0x0531,  0x0556, 548,  # - -   
-    0x10a0,  0x10c5, 548,  # - -   
-    0x1f08,  0x1f0f, 492,  # - -   
-    0x1f18,  0x1f1d, 492,  # - -   
-    0x1f28,  0x1f2f, 492,  # - -   
-    0x1f38,  0x1f3f, 492,  # - -   
-    0x1f48,  0x1f4d, 492,  # - -   
-    0x1f68,  0x1f6f, 492,  # - -   
-    0x1f88,  0x1f8f, 492,  # - -   
-    0x1f98,  0x1f9f, 492,  # - -   
-    0x1fa8,  0x1faf, 492,  # - -   
-    0x1fb8,  0x1fb9, 492,  # - -   
-    0x1fba,  0x1fbb, 426,  # - -   
-    0x1fc8,  0x1fcb, 414,  # - -   
-    0x1fd8,  0x1fd9, 492,  # - -   
-    0x1fda,  0x1fdb, 400,  # - -   
-    0x1fe8,  0x1fe9, 492,  # - -   
-    0x1fea,  0x1feb, 388,  # - -   
-    0x1ff8,  0x1ff9, 372,  # - -   
-    0x1ffa,  0x1ffb, 374,  # - -   
-    0x2160,  0x216f, 516,  # - -   
-    0x24b6,  0x24cf, 526,  # - -   
-    0xff21,  0xff3a, 532]  # - -   
+    0x00c0,  0x00d6, 532,  # - -
+    0x00d8,  0x00de, 532,  # - -
+    0x0189,  0x018a, 705,  # - -
+    0x018e,  0x018f, 702,  # - -
+    0x01b1,  0x01b2, 717,  # - -
+    0x0388,  0x038a, 537,  # - -
+    0x038e,  0x038f, 563,  # - -
+    0x0391,  0x03a1, 532,  # - -
+    0x03a3,  0x03ab, 532,  # - -
+    0x0401,  0x040c, 580,  # - -
+    0x040e,  0x040f, 580,  # - -
+    0x0410,  0x042f, 532,  # - -
+    0x0531,  0x0556, 548,  # - -
+    0x10a0,  0x10c5, 548,  # - -
+    0x1f08,  0x1f0f, 492,  # - -
+    0x1f18,  0x1f1d, 492,  # - -
+    0x1f28,  0x1f2f, 492,  # - -
+    0x1f38,  0x1f3f, 492,  # - -
+    0x1f48,  0x1f4d, 492,  # - -
+    0x1f68,  0x1f6f, 492,  # - -
+    0x1f88,  0x1f8f, 492,  # - -
+    0x1f98,  0x1f9f, 492,  # - -
+    0x1fa8,  0x1faf, 492,  # - -
+    0x1fb8,  0x1fb9, 492,  # - -
+    0x1fba,  0x1fbb, 426,  # - -
+    0x1fc8,  0x1fcb, 414,  # - -
+    0x1fd8,  0x1fd9, 492,  # - -
+    0x1fda,  0x1fdb, 400,  # - -
+    0x1fe8,  0x1fe9, 492,  # - -
+    0x1fea,  0x1feb, 388,  # - -
+    0x1ff8,  0x1ff9, 372,  # - -
+    0x1ffa,  0x1ffb, 374,  # - -
+    0x2160,  0x216f, 516,  # - -
+    0x24b6,  0x24cf, 526,  # - -
+    0xff21,  0xff3a, 532]  # - -
 
   tolowerSinglets = [
-    0x0100, 501,  #     
-    0x0102, 501,  #     
-    0x0104, 501,  #     
-    0x0106, 501,  #     
-    0x0108, 501,  #     
-    0x010a, 501,  #     
-    0x010c, 501,  #     
-    0x010e, 501,  #     
-    0x0110, 501,  #     
-    0x0112, 501,  #     
-    0x0114, 501,  #     
-    0x0116, 501,  #     
-    0x0118, 501,  #     
-    0x011a, 501,  #     
-    0x011c, 501,  #     
-    0x011e, 501,  #     
-    0x0120, 501,  #     
-    0x0122, 501,  #     
-    0x0124, 501,  #     
-    0x0126, 501,  #     
-    0x0128, 501,  #     
-    0x012a, 501,  #     
-    0x012c, 501,  #     
-    0x012e, 501,  #     
-    0x0130, 301,  #  i   
-    0x0132, 501,  #     
-    0x0134, 501,  #     
-    0x0136, 501,  #     
-    0x0139, 501,  #     
-    0x013b, 501,  #     
-    0x013d, 501,  #     
-    0x013f, 501,  #     
-    0x0141, 501,  #     
-    0x0143, 501,  #     
-    0x0145, 501,  #     
-    0x0147, 501,  #     
-    0x014a, 501,  #     
-    0x014c, 501,  #     
-    0x014e, 501,  #     
-    0x0150, 501,  #     
-    0x0152, 501,  #     
-    0x0154, 501,  #     
-    0x0156, 501,  #     
-    0x0158, 501,  #     
-    0x015a, 501,  #     
-    0x015c, 501,  #     
-    0x015e, 501,  #     
-    0x0160, 501,  #     
-    0x0162, 501,  #     
-    0x0164, 501,  #     
-    0x0166, 501,  #     
-    0x0168, 501,  #     
-    0x016a, 501,  #     
-    0x016c, 501,  #     
-    0x016e, 501,  #     
-    0x0170, 501,  #     
-    0x0172, 501,  #     
-    0x0174, 501,  #     
-    0x0176, 501,  #     
-    0x0178, 379,  #     
-    0x0179, 501,  #     
-    0x017b, 501,  #     
-    0x017d, 501,  #     
-    0x0181, 710,  #     
-    0x0182, 501,  #     
-    0x0184, 501,  #     
-    0x0186, 706,  #     
-    0x0187, 501,  #     
-    0x018b, 501,  #     
-    0x0190, 703,  #     
-    0x0191, 501,  #     
-    0x0193, 705,  #     
-    0x0194, 707,  #     
-    0x0196, 711,  #     
-    0x0197, 709,  #     
-    0x0198, 501,  #     
-    0x019c, 711,  #     
-    0x019d, 713,  #     
-    0x01a0, 501,  #     
-    0x01a2, 501,  #     
-    0x01a4, 501,  #     
-    0x01a7, 501,  #     
-    0x01a9, 718,  #     
-    0x01ac, 501,  #     
-    0x01ae, 718,  #     
-    0x01af, 501,  #     
-    0x01b3, 501,  #     
-    0x01b5, 501,  #     
-    0x01b7, 719,  #     
-    0x01b8, 501,  #     
-    0x01bc, 501,  #     
-    0x01c4, 502,  #     
-    0x01c5, 501,  #     
-    0x01c7, 502,  #     
-    0x01c8, 501,  #     
-    0x01ca, 502,  #     
-    0x01cb, 501,  #     
-    0x01cd, 501,  #     
-    0x01cf, 501,  #     
-    0x01d1, 501,  #     
-    0x01d3, 501,  #     
-    0x01d5, 501,  #     
-    0x01d7, 501,  #     
-    0x01d9, 501,  #     
-    0x01db, 501,  #     
-    0x01de, 501,  #     
-    0x01e0, 501,  #     
-    0x01e2, 501,  #     
-    0x01e4, 501,  #     
-    0x01e6, 501,  #     
-    0x01e8, 501,  #     
-    0x01ea, 501,  #     
-    0x01ec, 501,  #     
-    0x01ee, 501,  #     
-    0x01f1, 502,  #     
-    0x01f2, 501,  #     
-    0x01f4, 501,  #     
-    0x01fa, 501,  #     
-    0x01fc, 501,  #     
-    0x01fe, 501,  #     
-    0x0200, 501,  #     
-    0x0202, 501,  #     
-    0x0204, 501,  #     
-    0x0206, 501,  #     
-    0x0208, 501,  #     
-    0x020a, 501,  #     
-    0x020c, 501,  #     
-    0x020e, 501,  #     
-    0x0210, 501,  #     
-    0x0212, 501,  #     
-    0x0214, 501,  #     
-    0x0216, 501,  #     
-    0x0386, 538,  #     
-    0x038c, 564,  #     
-    0x03e2, 501,  #     
-    0x03e4, 501,  #     
-    0x03e6, 501,  #     
-    0x03e8, 501,  #     
-    0x03ea, 501,  #     
-    0x03ec, 501,  #     
-    0x03ee, 501,  #     
-    0x0460, 501,  #     
-    0x0462, 501,  #     
-    0x0464, 501,  #     
-    0x0466, 501,  #     
-    0x0468, 501,  #     
-    0x046a, 501,  #     
-    0x046c, 501,  #     
-    0x046e, 501,  #     
-    0x0470, 501,  #     
-    0x0472, 501,  #     
-    0x0474, 501,  #     
-    0x0476, 501,  #     
-    0x0478, 501,  #     
-    0x047a, 501,  #     
-    0x047c, 501,  #     
-    0x047e, 501,  #     
-    0x0480, 501,  #     
-    0x0490, 501,  #     
-    0x0492, 501,  #     
-    0x0494, 501,  #     
-    0x0496, 501,  #     
-    0x0498, 501,  #     
-    0x049a, 501,  #     
-    0x049c, 501,  #     
-    0x049e, 501,  #     
-    0x04a0, 501,  #     
-    0x04a2, 501,  #     
-    0x04a4, 501,  #     
-    0x04a6, 501,  #     
-    0x04a8, 501,  #     
-    0x04aa, 501,  #     
-    0x04ac, 501,  #     
-    0x04ae, 501,  #     
-    0x04b0, 501,  #     
-    0x04b2, 501,  #     
-    0x04b4, 501,  #     
-    0x04b6, 501,  #     
-    0x04b8, 501,  #     
-    0x04ba, 501,  #     
-    0x04bc, 501,  #     
-    0x04be, 501,  #     
-    0x04c1, 501,  #     
-    0x04c3, 501,  #     
-    0x04c7, 501,  #     
-    0x04cb, 501,  #     
-    0x04d0, 501,  #     
-    0x04d2, 501,  #     
-    0x04d4, 501,  #     
-    0x04d6, 501,  #     
-    0x04d8, 501,  #     
-    0x04da, 501,  #     
-    0x04dc, 501,  #     
-    0x04de, 501,  #     
-    0x04e0, 501,  #     
-    0x04e2, 501,  #     
-    0x04e4, 501,  #     
-    0x04e6, 501,  #     
-    0x04e8, 501,  #     
-    0x04ea, 501,  #     
-    0x04ee, 501,  #     
-    0x04f0, 501,  #     
-    0x04f2, 501,  #     
-    0x04f4, 501,  #     
-    0x04f8, 501,  #     
-    0x1e00, 501,  #     
-    0x1e02, 501,  #     
-    0x1e04, 501,  #     
-    0x1e06, 501,  #     
-    0x1e08, 501,  #     
-    0x1e0a, 501,  #     
-    0x1e0c, 501,  #     
-    0x1e0e, 501,  #     
-    0x1e10, 501,  #     
-    0x1e12, 501,  #     
-    0x1e14, 501,  #     
-    0x1e16, 501,  #     
-    0x1e18, 501,  #     
-    0x1e1a, 501,  #     
-    0x1e1c, 501,  #     
-    0x1e1e, 501,  #     
-    0x1e20, 501,  #     
-    0x1e22, 501,  #     
-    0x1e24, 501,  #     
-    0x1e26, 501,  #     
-    0x1e28, 501,  #     
-    0x1e2a, 501,  #     
-    0x1e2c, 501,  #     
-    0x1e2e, 501,  #     
-    0x1e30, 501,  #     
-    0x1e32, 501,  #     
-    0x1e34, 501,  #     
-    0x1e36, 501,  #     
-    0x1e38, 501,  #     
-    0x1e3a, 501,  #     
-    0x1e3c, 501,  #     
-    0x1e3e, 501,  #     
-    0x1e40, 501,  #     
-    0x1e42, 501,  #     
-    0x1e44, 501,  #     
-    0x1e46, 501,  #     
-    0x1e48, 501,  #     
-    0x1e4a, 501,  #     
-    0x1e4c, 501,  #     
-    0x1e4e, 501,  #     
-    0x1e50, 501,  #     
-    0x1e52, 501,  #     
-    0x1e54, 501,  #     
-    0x1e56, 501,  #     
-    0x1e58, 501,  #     
-    0x1e5a, 501,  #     
-    0x1e5c, 501,  #     
-    0x1e5e, 501,  #     
-    0x1e60, 501,  #     
-    0x1e62, 501,  #     
-    0x1e64, 501,  #     
-    0x1e66, 501,  #     
-    0x1e68, 501,  #     
-    0x1e6a, 501,  #     
-    0x1e6c, 501,  #     
-    0x1e6e, 501,  #     
-    0x1e70, 501,  #     
-    0x1e72, 501,  #     
-    0x1e74, 501,  #     
-    0x1e76, 501,  #     
-    0x1e78, 501,  #     
-    0x1e7a, 501,  #     
-    0x1e7c, 501,  #     
-    0x1e7e, 501,  #     
-    0x1e80, 501,  #     
-    0x1e82, 501,  #     
-    0x1e84, 501,  #     
-    0x1e86, 501,  #     
-    0x1e88, 501,  #     
-    0x1e8a, 501,  #     
-    0x1e8c, 501,  #     
-    0x1e8e, 501,  #     
-    0x1e90, 501,  #     
-    0x1e92, 501,  #     
-    0x1e94, 501,  #     
-    0x1ea0, 501,  #     
-    0x1ea2, 501,  #     
-    0x1ea4, 501,  #     
-    0x1ea6, 501,  #     
-    0x1ea8, 501,  #     
-    0x1eaa, 501,  #     
-    0x1eac, 501,  #     
-    0x1eae, 501,  #     
-    0x1eb0, 501,  #     
-    0x1eb2, 501,  #     
-    0x1eb4, 501,  #     
-    0x1eb6, 501,  #     
-    0x1eb8, 501,  #     
-    0x1eba, 501,  #     
-    0x1ebc, 501,  #     
-    0x1ebe, 501,  #     
-    0x1ec0, 501,  #     
-    0x1ec2, 501,  #     
-    0x1ec4, 501,  #     
-    0x1ec6, 501,  #     
-    0x1ec8, 501,  #     
-    0x1eca, 501,  #     
-    0x1ecc, 501,  #     
-    0x1ece, 501,  #     
-    0x1ed0, 501,  #     
-    0x1ed2, 501,  #     
-    0x1ed4, 501,  #     
-    0x1ed6, 501,  #     
-    0x1ed8, 501,  #     
-    0x1eda, 501,  #     
-    0x1edc, 501,  #     
-    0x1ede, 501,  #     
-    0x1ee0, 501,  #     
-    0x1ee2, 501,  #     
-    0x1ee4, 501,  #     
-    0x1ee6, 501,  #     
-    0x1ee8, 501,  #     
-    0x1eea, 501,  #     
-    0x1eec, 501,  #     
-    0x1eee, 501,  #     
-    0x1ef0, 501,  #     
-    0x1ef2, 501,  #     
-    0x1ef4, 501,  #     
-    0x1ef6, 501,  #     
-    0x1ef8, 501,  #     
-    0x1f59, 492,  #     
-    0x1f5b, 492,  #     
-    0x1f5d, 492,  #     
-    0x1f5f, 492,  #     
-    0x1fbc, 491,  #     
-    0x1fcc, 491,  #     
-    0x1fec, 493,  #     
-    0x1ffc, 491]  #     
+    0x0100, 501,  #
+    0x0102, 501,  #
+    0x0104, 501,  #
+    0x0106, 501,  #
+    0x0108, 501,  #
+    0x010a, 501,  #
+    0x010c, 501,  #
+    0x010e, 501,  #
+    0x0110, 501,  #
+    0x0112, 501,  #
+    0x0114, 501,  #
+    0x0116, 501,  #
+    0x0118, 501,  #
+    0x011a, 501,  #
+    0x011c, 501,  #
+    0x011e, 501,  #
+    0x0120, 501,  #
+    0x0122, 501,  #
+    0x0124, 501,  #
+    0x0126, 501,  #
+    0x0128, 501,  #
+    0x012a, 501,  #
+    0x012c, 501,  #
+    0x012e, 501,  #
+    0x0130, 301,  #  i
+    0x0132, 501,  #
+    0x0134, 501,  #
+    0x0136, 501,  #
+    0x0139, 501,  #
+    0x013b, 501,  #
+    0x013d, 501,  #
+    0x013f, 501,  #
+    0x0141, 501,  #
+    0x0143, 501,  #
+    0x0145, 501,  #
+    0x0147, 501,  #
+    0x014a, 501,  #
+    0x014c, 501,  #
+    0x014e, 501,  #
+    0x0150, 501,  #
+    0x0152, 501,  #
+    0x0154, 501,  #
+    0x0156, 501,  #
+    0x0158, 501,  #
+    0x015a, 501,  #
+    0x015c, 501,  #
+    0x015e, 501,  #
+    0x0160, 501,  #
+    0x0162, 501,  #
+    0x0164, 501,  #
+    0x0166, 501,  #
+    0x0168, 501,  #
+    0x016a, 501,  #
+    0x016c, 501,  #
+    0x016e, 501,  #
+    0x0170, 501,  #
+    0x0172, 501,  #
+    0x0174, 501,  #
+    0x0176, 501,  #
+    0x0178, 379,  #
+    0x0179, 501,  #
+    0x017b, 501,  #
+    0x017d, 501,  #
+    0x0181, 710,  #
+    0x0182, 501,  #
+    0x0184, 501,  #
+    0x0186, 706,  #
+    0x0187, 501,  #
+    0x018b, 501,  #
+    0x0190, 703,  #
+    0x0191, 501,  #
+    0x0193, 705,  #
+    0x0194, 707,  #
+    0x0196, 711,  #
+    0x0197, 709,  #
+    0x0198, 501,  #
+    0x019c, 711,  #
+    0x019d, 713,  #
+    0x01a0, 501,  #
+    0x01a2, 501,  #
+    0x01a4, 501,  #
+    0x01a7, 501,  #
+    0x01a9, 718,  #
+    0x01ac, 501,  #
+    0x01ae, 718,  #
+    0x01af, 501,  #
+    0x01b3, 501,  #
+    0x01b5, 501,  #
+    0x01b7, 719,  #
+    0x01b8, 501,  #
+    0x01bc, 501,  #
+    0x01c4, 502,  #
+    0x01c5, 501,  #
+    0x01c7, 502,  #
+    0x01c8, 501,  #
+    0x01ca, 502,  #
+    0x01cb, 501,  #
+    0x01cd, 501,  #
+    0x01cf, 501,  #
+    0x01d1, 501,  #
+    0x01d3, 501,  #
+    0x01d5, 501,  #
+    0x01d7, 501,  #
+    0x01d9, 501,  #
+    0x01db, 501,  #
+    0x01de, 501,  #
+    0x01e0, 501,  #
+    0x01e2, 501,  #
+    0x01e4, 501,  #
+    0x01e6, 501,  #
+    0x01e8, 501,  #
+    0x01ea, 501,  #
+    0x01ec, 501,  #
+    0x01ee, 501,  #
+    0x01f1, 502,  #
+    0x01f2, 501,  #
+    0x01f4, 501,  #
+    0x01fa, 501,  #
+    0x01fc, 501,  #
+    0x01fe, 501,  #
+    0x0200, 501,  #
+    0x0202, 501,  #
+    0x0204, 501,  #
+    0x0206, 501,  #
+    0x0208, 501,  #
+    0x020a, 501,  #
+    0x020c, 501,  #
+    0x020e, 501,  #
+    0x0210, 501,  #
+    0x0212, 501,  #
+    0x0214, 501,  #
+    0x0216, 501,  #
+    0x0386, 538,  #
+    0x038c, 564,  #
+    0x03e2, 501,  #
+    0x03e4, 501,  #
+    0x03e6, 501,  #
+    0x03e8, 501,  #
+    0x03ea, 501,  #
+    0x03ec, 501,  #
+    0x03ee, 501,  #
+    0x0460, 501,  #
+    0x0462, 501,  #
+    0x0464, 501,  #
+    0x0466, 501,  #
+    0x0468, 501,  #
+    0x046a, 501,  #
+    0x046c, 501,  #
+    0x046e, 501,  #
+    0x0470, 501,  #
+    0x0472, 501,  #
+    0x0474, 501,  #
+    0x0476, 501,  #
+    0x0478, 501,  #
+    0x047a, 501,  #
+    0x047c, 501,  #
+    0x047e, 501,  #
+    0x0480, 501,  #
+    0x0490, 501,  #
+    0x0492, 501,  #
+    0x0494, 501,  #
+    0x0496, 501,  #
+    0x0498, 501,  #
+    0x049a, 501,  #
+    0x049c, 501,  #
+    0x049e, 501,  #
+    0x04a0, 501,  #
+    0x04a2, 501,  #
+    0x04a4, 501,  #
+    0x04a6, 501,  #
+    0x04a8, 501,  #
+    0x04aa, 501,  #
+    0x04ac, 501,  #
+    0x04ae, 501,  #
+    0x04b0, 501,  #
+    0x04b2, 501,  #
+    0x04b4, 501,  #
+    0x04b6, 501,  #
+    0x04b8, 501,  #
+    0x04ba, 501,  #
+    0x04bc, 501,  #
+    0x04be, 501,  #
+    0x04c1, 501,  #
+    0x04c3, 501,  #
+    0x04c7, 501,  #
+    0x04cb, 501,  #
+    0x04d0, 501,  #
+    0x04d2, 501,  #
+    0x04d4, 501,  #
+    0x04d6, 501,  #
+    0x04d8, 501,  #
+    0x04da, 501,  #
+    0x04dc, 501,  #
+    0x04de, 501,  #
+    0x04e0, 501,  #
+    0x04e2, 501,  #
+    0x04e4, 501,  #
+    0x04e6, 501,  #
+    0x04e8, 501,  #
+    0x04ea, 501,  #
+    0x04ee, 501,  #
+    0x04f0, 501,  #
+    0x04f2, 501,  #
+    0x04f4, 501,  #
+    0x04f8, 501,  #
+    0x1e00, 501,  #
+    0x1e02, 501,  #
+    0x1e04, 501,  #
+    0x1e06, 501,  #
+    0x1e08, 501,  #
+    0x1e0a, 501,  #
+    0x1e0c, 501,  #
+    0x1e0e, 501,  #
+    0x1e10, 501,  #
+    0x1e12, 501,  #
+    0x1e14, 501,  #
+    0x1e16, 501,  #
+    0x1e18, 501,  #
+    0x1e1a, 501,  #
+    0x1e1c, 501,  #
+    0x1e1e, 501,  #
+    0x1e20, 501,  #
+    0x1e22, 501,  #
+    0x1e24, 501,  #
+    0x1e26, 501,  #
+    0x1e28, 501,  #
+    0x1e2a, 501,  #
+    0x1e2c, 501,  #
+    0x1e2e, 501,  #
+    0x1e30, 501,  #
+    0x1e32, 501,  #
+    0x1e34, 501,  #
+    0x1e36, 501,  #
+    0x1e38, 501,  #
+    0x1e3a, 501,  #
+    0x1e3c, 501,  #
+    0x1e3e, 501,  #
+    0x1e40, 501,  #
+    0x1e42, 501,  #
+    0x1e44, 501,  #
+    0x1e46, 501,  #
+    0x1e48, 501,  #
+    0x1e4a, 501,  #
+    0x1e4c, 501,  #
+    0x1e4e, 501,  #
+    0x1e50, 501,  #
+    0x1e52, 501,  #
+    0x1e54, 501,  #
+    0x1e56, 501,  #
+    0x1e58, 501,  #
+    0x1e5a, 501,  #
+    0x1e5c, 501,  #
+    0x1e5e, 501,  #
+    0x1e60, 501,  #
+    0x1e62, 501,  #
+    0x1e64, 501,  #
+    0x1e66, 501,  #
+    0x1e68, 501,  #
+    0x1e6a, 501,  #
+    0x1e6c, 501,  #
+    0x1e6e, 501,  #
+    0x1e70, 501,  #
+    0x1e72, 501,  #
+    0x1e74, 501,  #
+    0x1e76, 501,  #
+    0x1e78, 501,  #
+    0x1e7a, 501,  #
+    0x1e7c, 501,  #
+    0x1e7e, 501,  #
+    0x1e80, 501,  #
+    0x1e82, 501,  #
+    0x1e84, 501,  #
+    0x1e86, 501,  #
+    0x1e88, 501,  #
+    0x1e8a, 501,  #
+    0x1e8c, 501,  #
+    0x1e8e, 501,  #
+    0x1e90, 501,  #
+    0x1e92, 501,  #
+    0x1e94, 501,  #
+    0x1ea0, 501,  #
+    0x1ea2, 501,  #
+    0x1ea4, 501,  #
+    0x1ea6, 501,  #
+    0x1ea8, 501,  #
+    0x1eaa, 501,  #
+    0x1eac, 501,  #
+    0x1eae, 501,  #
+    0x1eb0, 501,  #
+    0x1eb2, 501,  #
+    0x1eb4, 501,  #
+    0x1eb6, 501,  #
+    0x1eb8, 501,  #
+    0x1eba, 501,  #
+    0x1ebc, 501,  #
+    0x1ebe, 501,  #
+    0x1ec0, 501,  #
+    0x1ec2, 501,  #
+    0x1ec4, 501,  #
+    0x1ec6, 501,  #
+    0x1ec8, 501,  #
+    0x1eca, 501,  #
+    0x1ecc, 501,  #
+    0x1ece, 501,  #
+    0x1ed0, 501,  #
+    0x1ed2, 501,  #
+    0x1ed4, 501,  #
+    0x1ed6, 501,  #
+    0x1ed8, 501,  #
+    0x1eda, 501,  #
+    0x1edc, 501,  #
+    0x1ede, 501,  #
+    0x1ee0, 501,  #
+    0x1ee2, 501,  #
+    0x1ee4, 501,  #
+    0x1ee6, 501,  #
+    0x1ee8, 501,  #
+    0x1eea, 501,  #
+    0x1eec, 501,  #
+    0x1eee, 501,  #
+    0x1ef0, 501,  #
+    0x1ef2, 501,  #
+    0x1ef4, 501,  #
+    0x1ef6, 501,  #
+    0x1ef8, 501,  #
+    0x1f59, 492,  #
+    0x1f5b, 492,  #
+    0x1f5d, 492,  #
+    0x1f5f, 492,  #
+    0x1fbc, 491,  #
+    0x1fcc, 491,  #
+    0x1fec, 493,  #
+    0x1ffc, 491]  #
 
   toTitleSinglets = [
-    0x01c4, 501,  #     
-    0x01c6, 499,  #     
-    0x01c7, 501,  #     
-    0x01c9, 499,  #     
-    0x01ca, 501,  #     
-    0x01cc, 499,  #     
-    0x01f1, 501,  #     
-    0x01f3, 499]  #     
+    0x01c4, 501,  #
+    0x01c6, 499,  #
+    0x01c7, 501,  #
+    0x01c9, 499,  #
+    0x01ca, 501,  #
+    0x01cc, 499,  #
+    0x01f1, 501,  #
+    0x01f3, 499]  #
 
-proc binarySearch(c: RuneImpl, tab: openArray[RuneImpl], len, stride: int): int = 
+proc binarySearch(c: RuneImpl, tab: openArray[RuneImpl], len, stride: int): int =
   var n = len
   var t = 0
-  while n > 1: 
+  while n > 1:
     var m = n div 2
     var p = t + m*stride
     if c >= tab[p]:
@@ -1117,9 +1131,9 @@ proc binarySearch(c: RuneImpl, tab: openArray[RuneImpl], len, stride: int): int
     return t
   return -1
 
-proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = 
+proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
   ## Converts `c` into lower case. This works for any Unicode character.
-  ## If possible, prefer `toLower` over `toUpper`. 
+  ## If possible, prefer `toLower` over `toUpper`.
   var c = RuneImpl(c)
   var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3)
   if p >= 0 and c >= tolowerRanges[p] and c <= tolowerRanges[p+1]:
@@ -1129,9 +1143,9 @@ proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
     return Rune(c + tolowerSinglets[p+1] - 500)
   return Rune(c)
 
-proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = 
+proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
   ## Converts `c` into upper case. This works for any Unicode character.
-  ## If possible, prefer `toLower` over `toUpper`. 
+  ## If possible, prefer `toLower` over `toUpper`.
   var c = RuneImpl(c)
   var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3)
   if p >= 0 and c >= toupperRanges[p] and c <= toupperRanges[p+1]:
@@ -1141,16 +1155,16 @@ proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
     return Rune(c + toupperSinglets[p+1] - 500)
   return Rune(c)
 
-proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = 
+proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
   var c = RuneImpl(c)
   var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2)
   if p >= 0 and c == toTitleSinglets[p]:
     return Rune(c + toTitleSinglets[p+1] - 500)
   return Rune(c)
 
-proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = 
+proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
   ## returns true iff `c` is a lower case Unicode character
-  ## If possible, prefer `isLower` over `isUpper`. 
+  ## If possible, prefer `isLower` over `isUpper`.
   var c = RuneImpl(c)
   # Note: toUpperRanges is correct here!
   var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3)
@@ -1160,9 +1174,9 @@ proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
   if p >= 0 and c == toupperSinglets[p]:
     return true
 
-proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = 
+proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
   ## returns true iff `c` is a upper case Unicode character
-  ## If possible, prefer `isLower` over `isUpper`. 
+  ## If possible, prefer `isLower` over `isUpper`.
   var c = RuneImpl(c)
   # Note: toLowerRanges is correct here!
   var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3)
@@ -1172,9 +1186,9 @@ proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
   if p >= 0 and c == tolowerSinglets[p]:
     return true
 
-proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = 
+proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
   ## returns true iff `c` is an *alpha* Unicode character (i.e. a letter)
-  if isUpper(c) or isLower(c): 
+  if isUpper(c) or isLower(c):
     return true
   var c = RuneImpl(c)
   var p = binarySearch(c, alphaRanges, len(alphaRanges) div 2, 2)
@@ -1183,17 +1197,28 @@ proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
   p = binarySearch(c, alphaSinglets, len(alphaSinglets), 1)
   if p >= 0 and c == alphaSinglets[p]:
     return true
-  
-proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = 
+
+proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
   return isUpper(c) and isLower(c)
 
-proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = 
+proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
   ## returns true iff `c` is a Unicode whitespace character
   var c = RuneImpl(c)
   var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2)
   if p >= 0 and c >= spaceRanges[p] and c <= spaceRanges[p+1]:
     return true
 
+proc isCombining*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
+  ## returns true iff `c` is a Unicode combining character
+  var c = RuneImpl(c)
+
+  # Optimized to return false immediately for ASCII
+  return c >= 0x0300 and (c <= 0x036f or
+    (c >= 0x1ab0 and c <= 0x1aff) or
+    (c >= 0x1dc0 and c <= 0x1dff) or
+    (c >= 0x20d0 and c <= 0x20ff) or
+    (c >= 0xfe20 and c <= 0xfe2f))
+
 iterator runes*(s: string): Rune =
   ## iterates over any unicode character of the string `s`.
   var
@@ -1203,7 +1228,7 @@ iterator runes*(s: string): Rune =
     fastRuneAt(s, i, result, true)
     yield result
 
-proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} = 
+proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} =
   ## compares two UTF8 strings and ignores the case. Returns:
   ##
   ## | 0 iff a == b
@@ -1220,9 +1245,49 @@ proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} =
     if result != 0: return
   result = a.len - b.len
 
+proc reversed*(s: string): string =
+  ## returns the reverse of `s`, interpreting it as unicode characters. Unicode
+  ## combining characters are correctly interpreted as well:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   assert reversed("Reverse this!") == "!siht esreveR"
+  ##   assert reversed("先秦兩漢") == "漢兩秦先"
+  ##   assert reversed("asâƒdfÌ…") == "fÌ…dsâƒa"
+  ##   assert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞"
+  var
+    i = 0
+    lastI = 0
+    newPos = len(s) - 1
+    blockPos = 0
+    r: Rune
+
+  template reverseUntil(pos): stmt =
+    var j = pos - 1
+    while j > blockPos:
+      result[newPos] = s[j]
+      dec j
+      dec newPos
+    blockPos = pos - 1
+
+  result = newString(len(s))
+
+  while i < len(s):
+    lastI = i
+    fastRuneAt(s, i, r, true)
+    if not isCombining(r):
+      reverseUntil(lastI)
+
+  reverseUntil(len(s))
+
 when isMainModule:
   let
     someString = "öÑ"
     someRunes = @[runeAt(someString, 0), runeAt(someString, 2)]
     compared = (someString == $someRunes)
   assert compared == true
+
+  assert reversed("Reverse this!") == "!siht esreveR"
+  assert reversed("先秦兩漢") == "漢兩秦先"
+  assert reversed("asâƒdfÌ…") == "fÌ…dsâƒa"
+  assert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞"
diff --git a/lib/pure/unidecode/unidecode.nim b/lib/pure/unidecode/unidecode.nim
index 798eef5d0..a83b9be0f 100644
--- a/lib/pure/unidecode/unidecode.nim
+++ b/lib/pure/unidecode/unidecode.nim
@@ -70,5 +70,5 @@ proc unidecode*(s: string): string =
 
 when isMainModule:
   loadUnidecodeTable("lib/pure/unidecode/unidecode.dat")
-  echo unidecode("Äußerst")
+  assert unidecode("Äußerst") == "Ausserst"
 
diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim
index fa2e30ef4..3bf4724b9 100644
--- a/lib/pure/unittest.nim
+++ b/lib/pure/unittest.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2012 Nim Contributors
+#        (c) Copyright 2015 Nim Contributors
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -9,12 +9,27 @@
 
 ## :Author: Zahary Karadjov
 ##
-## This module implements the standard unit testing facilities such as
-## suites, fixtures and test cases as well as facilities for combinatorial 
-## and randomzied test case generation (not yet available) 
-## and object mocking (not yet available)
+## This module implements boilerplate to make testing easy.
 ##
-## It is loosely based on C++'s boost.test and Haskell's QuickTest
+## Example:
+##
+## .. code:: nim
+##
+##   suite "description for this stuff":
+##     test "essential truths":
+##       # give up and stop if this fails
+##       require(true)
+##
+##     test "slightly less obvious stuff":
+##       # print a nasty message and move on, skipping
+##       # the remainder of this block
+##       check(1 != 1)
+##       check("asd"[2] == 'd')
+##
+##     test "out of bounds error is thrown on bad access":
+##       let v = @[1, 2, 3]  # you can do initialization here
+##       expect(IndexError):
+##         discard v[4]
 
 import
   macros
@@ -24,6 +39,7 @@ when declared(stdout):
 
 when not defined(ECMAScript):
   import terminal
+  system.addQuitProc(resetAttributes)
 
 type
   TestStatus* = enum OK, FAILED
@@ -31,11 +47,11 @@ type
 
 {.deprecated: [TTestStatus: TestStatus, TOutputLevel: OutputLevel]}
 
-var 
+var
   abortOnError* {.threadvar.}: bool
   outputLevel* {.threadvar.}: OutputLevel
   colorOutput* {.threadvar.}: bool
-  
+
   checkpoints {.threadvar.}: seq[string]
 
 checkpoints = @[]
@@ -61,29 +77,30 @@ proc testDone(name: string, s: TestStatus) =
     programResult += 1
 
   if outputLevel != PRINT_NONE and (outputLevel == PRINT_ALL or s == FAILED):
-    template rawPrint() = echo("[", $s, "] ", name, "\n")
+    template rawPrint() = echo("[", $s, "] ", name)
     when not defined(ECMAScript):
       if colorOutput and not defined(ECMAScript):
         var color = (if s == OK: fgGreen else: fgRed)
-        styledEcho styleBright, color, "[", $s, "] ", fgWhite, name, "\n"
+        styledEcho styleBright, color, "[", $s, "] ", fgWhite, name
       else:
         rawPrint()
     else:
       rawPrint()
-  
+
 template test*(name: expr, body: stmt): stmt {.immediate, dirty.} =
   bind shouldRun, checkpoints, testDone
 
   if shouldRun(name):
     checkpoints = @[]
     var testStatusIMPL {.inject.} = OK
-    
+
     try:
       testSetupIMPL()
       body
 
     except:
       checkpoint("Unhandled exception: " & getCurrentExceptionMsg())
+      echo getCurrentException().getStackTrace()
       fail()
 
     finally:
@@ -97,11 +114,13 @@ proc checkpoint*(msg: string) =
 template fail* =
   bind checkpoints
   for msg in items(checkpoints):
-    echo msg
+    # this used to be 'echo' which now breaks due to a bug. XXX will revisit
+    # this issue later.
+    stdout.writeln msg
 
   when not defined(ECMAScript):
     if abortOnError: quit(1)
- 
+
   when declared(testStatusIMPL):
     testStatusIMPL = FAILED
   else:
@@ -111,7 +130,7 @@ template fail* =
 
 macro check*(conditions: stmt): stmt {.immediate.} =
   let checked = callsite()[1]
-  
+
   var
     argsAsgns = newNimNode(nnkStmtList)
     argsPrintOuts = newNimNode(nnkStmtList)
@@ -120,21 +139,30 @@ macro check*(conditions: stmt): stmt {.immediate.} =
   template asgn(a, value: expr): stmt =
     var a = value # XXX: we need "var: var" here in order to
                   # preserve the semantics of var params
-  
+
   template print(name, value: expr): stmt =
     when compiles(string($value)):
       checkpoint(name & " was " & $value)
 
-  proc inspectArgs(exp: PNimrodNode) =
+  proc inspectArgs(exp: NimNode) =
     for i in 1 .. <exp.len:
       if exp[i].kind notin nnkLiterals:
         inc counter
         var arg = newIdentNode(":p" & $counter)
         var argStr = exp[i].toStrLit
+        var paramAst = exp[i]
         if exp[i].kind in nnkCallKinds: inspectArgs(exp[i])
-        argsAsgns.add getAst(asgn(arg, exp[i]))
+        if exp[i].kind == nnkExprEqExpr:
+          # ExprEqExpr
+          #   Ident !"v"
+          #   IntLit 2
+          paramAst = exp[i][1]
+        argsAsgns.add getAst(asgn(arg, paramAst))
         argsPrintOuts.add getAst(print(argStr, arg))
-        exp[i] = arg
+        if exp[i].kind != nnkExprEqExpr:
+          exp[i] = arg
+        else:
+          exp[i][1] = arg
 
   case checked.kind
   of nnkCallKinds:
@@ -146,7 +174,7 @@ macro check*(conditions: stmt): stmt {.immediate.} =
           checkpoint(lineInfoLit & ": Check failed: " & callLit)
           argPrintOuts
           fail()
-      
+
     var checkedStr = checked.toStrLit
     inspectArgs(checked)
     result = getAst(rewrite(checked, checked.lineinfo, checkedStr,
@@ -174,7 +202,7 @@ template require*(conditions: stmt): stmt {.immediate, dirty.} =
 macro expect*(exceptions: varargs[expr], body: stmt): stmt {.immediate.} =
   let exp = callsite()
   template expectBody(errorTypes, lineInfoLit: expr,
-                      body: stmt): PNimrodNode {.dirty.} =
+                      body: stmt): NimNode {.dirty.} =
     try:
       body
       checkpoint(lineInfoLit & ": Expect Failed, no exception was thrown.")
diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim
index 2c65d071e..b0afb75f9 100644
--- a/lib/pure/uri.nim
+++ b/lib/pure/uri.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Dominik Picheta
+#        (c) Copyright 2015 Dominik Picheta
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -16,17 +16,19 @@ type
   Uri* = object
     scheme*, username*, password*: string 
     hostname*, port*, path*, query*, anchor*: string
+    opaque*: bool
 
 {.deprecated: [TUrl: Url, TUri: Uri].}
 
-proc `$`*(url: TUrl): string {.deprecated.} =
-  ## **Deprecated since 0.9.6**: Use ``TUri`` instead.
+{.push warning[deprecated]: off.}
+proc `$`*(url: Url): string {.deprecated.} =
+  ## **Deprecated since 0.9.6**: Use ``Uri`` instead.
   return string(url)
 
-proc `/`*(a, b: TUrl): TUrl {.deprecated.} =
+proc `/`*(a, b: Url): Url {.deprecated.} =
   ## Joins two URLs together, separating them with / if needed.
   ##
-  ## **Deprecated since 0.9.6**: Use ``TUri`` instead.
+  ## **Deprecated since 0.9.6**: Use ``Uri`` instead.
   var urlS = $a
   var bS = $b
   if urlS == "": return b
@@ -36,15 +38,16 @@ proc `/`*(a, b: TUrl): TUrl {.deprecated.} =
     urlS.add(bS.substr(1))
   else:
     urlS.add(bs)
-  result = TUrl(urlS)
+  result = Url(urlS)
 
-proc add*(url: var TUrl, a: TUrl) {.deprecated.} =
+proc add*(url: var Url, a: Url) {.deprecated.} =
   ## Appends url to url.
   ##
-  ## **Deprecated since 0.9.6**: Use ``TUri`` instead.
+  ## **Deprecated since 0.9.6**: Use ``Uri`` instead.
   url = url / a
+{.pop.}
 
-proc parseAuthority(authority: string, result: var TUri) =
+proc parseAuthority(authority: string, result: var Uri) =
   var i = 0
   var inPort = false
   while true:
@@ -65,7 +68,7 @@ proc parseAuthority(authority: string, result: var TUri) =
         result.hostname.add(authority[i])
     i.inc
 
-proc parsePath(uri: string, i: var int, result: var TUri) =
+proc parsePath(uri: string, i: var int, result: var Uri) =
   
   i.inc parseUntil(uri, result.path, {'?', '#'}, i)
 
@@ -82,11 +85,11 @@ proc parsePath(uri: string, i: var int, result: var TUri) =
     i.inc # Skip '#'
     i.inc parseUntil(uri, result.anchor, {}, i)
 
-proc initUri(): TUri =
-  result = TUri(scheme: "", username: "", password: "", hostname: "", port: "",
+proc initUri(): Uri =
+  result = Uri(scheme: "", username: "", password: "", hostname: "", port: "",
                 path: "", query: "", anchor: "")
 
-proc parseUri*(uri: string): TUri =
+proc parseUri*(uri: string): Uri =
   ## Parses a URI.
   result = initUri()
 
@@ -113,8 +116,10 @@ proc parseUri*(uri: string): TUri =
     var authority = ""
     i.inc parseUntil(uri, authority, {'/', '?', '#'}, i)
     if authority == "":
-      raise newException(EInvalidValue, "Expected authority got nothing.")
+      raise newException(ValueError, "Expected authority got nothing.")
     parseAuthority(authority, result)
+  else:
+    result.opaque = true
 
   # Path
   parsePath(uri, i, result)
@@ -150,7 +155,7 @@ proc removeDotSegments(path: string): string =
   result = collection.join("/")
   if endsWithSlash: result.add '/'
 
-proc merge(base, reference: TUri): string =
+proc merge(base, reference: Uri): string =
   # http://tools.ietf.org/html/rfc3986#section-5.2.3
   if base.hostname != "" and base.path == "":
     '/' & reference.path
@@ -161,7 +166,7 @@ proc merge(base, reference: TUri): string =
     else:
       base.path[0 .. lastSegment] & reference.path
 
-proc combine*(base: TUri, reference: TUri): TUri =
+proc combine*(base: Uri, reference: Uri): Uri =
   ## Combines a base URI with a reference URI.
   ##
   ## This uses the algorithm specified in
@@ -179,10 +184,10 @@ proc combine*(base: TUri, reference: TUri): TUri =
   ##   assert foo.path == "/baz"
   ##
   ##   let bar = combine(parseUri("http://example.com/foo/bar"), parseUri("baz"))
-  ##   assert foo.path == "/foo/baz"
+  ##   assert bar.path == "/foo/baz"
   ##
   ##   let bar = combine(parseUri("http://example.com/foo/bar/"), parseUri("baz"))
-  ##   assert foo.path == "/foo/bar/baz"
+  ##   assert bar.path == "/foo/bar/baz"
   
   template setAuthority(dest, src: expr): stmt =
     dest.hostname = src.hostname
@@ -216,13 +221,13 @@ proc combine*(base: TUri, reference: TUri): TUri =
     result.scheme = base.scheme
   result.anchor = reference.anchor
 
-proc combine*(uris: varargs[TUri]): TUri =
+proc combine*(uris: varargs[Uri]): Uri =
   ## Combines multiple URIs together.
   result = uris[0]
   for i in 1 .. <uris.len:
     result = combine(result, uris[i])
 
-proc `/`*(x: TUri, path: string): TUri =
+proc `/`*(x: Uri, path: string): Uri =
   ## Concatenates the path specified to the specified URI's path.
   ##
   ## Contrary to the ``combine`` procedure you do not have to worry about
@@ -236,10 +241,10 @@ proc `/`*(x: TUri, path: string): TUri =
   ##   assert foo.path == "/foo/bar/baz"
   ##
   ##   let bar = parseUri("http://example.com/foo/bar") / parseUri("baz")
-  ##   assert foo.path == "/foo/bar/baz"
+  ##   assert bar.path == "/foo/bar/baz"
   ##
   ##   let bar = parseUri("http://example.com/foo/bar/") / parseUri("baz")
-  ##   assert foo.path == "/foo/bar/baz"
+  ##   assert bar.path == "/foo/bar/baz"
   result = x
   if result.path[result.path.len-1] == '/':
     if path[0] == '/':
@@ -251,12 +256,15 @@ proc `/`*(x: TUri, path: string): TUri =
       result.path.add '/'
     result.path.add(path)
 
-proc `$`*(u: TUri): string =
+proc `$`*(u: Uri): string =
   ## Returns the string representation of the specified URI object.
   result = ""
   if u.scheme.len > 0:
     result.add(u.scheme)
-    result.add("://")
+    if u.opaque:
+      result.add(":")
+    else:
+      result.add("://")
   if u.username.len > 0:
     result.add(u.username)
     if u.password.len > 0:
@@ -268,22 +276,38 @@ proc `$`*(u: TUri): string =
     result.add(":")
     result.add(u.port)
   if u.path.len > 0:
-    if u.path[0] != '/': result.add("/")
     result.add(u.path)
-  result.add(u.query)
-  result.add(u.anchor)
+  if u.query.len > 0:
+    result.add("?")
+    result.add(u.query)
+  if u.anchor.len > 0:
+    result.add("#")
+    result.add(u.anchor)
 
 when isMainModule:
   block:
-    let test = parseUri("http://localhost:8080/test")
+    let str = "http://localhost"
+    let test = parseUri(str)
+    doAssert test.path == ""
+
+  block:
+    let str = "http://localhost/"
+    let test = parseUri(str)
+    doAssert test.path == "/"
+
+  block:
+    let str = "http://localhost:8080/test"
+    let test = parseUri(str)
     doAssert test.scheme == "http"
     doAssert test.port == "8080"
     doAssert test.path == "/test"
     doAssert test.hostname == "localhost"
+    doAssert($test == str)
 
   block:
-    let test = parseUri("foo://username:password@example.com:8042/over/there" &
-                        "/index.dtb?type=animal&name=narwhal#nose")
+    let str = "foo://username:password@example.com:8042/over/there" &
+              "/index.dtb?type=animal&name=narwhal#nose"
+    let test = parseUri(str)
     doAssert test.scheme == "foo"
     doAssert test.username == "username"
     doAssert test.password == "password"
@@ -292,34 +316,45 @@ when isMainModule:
     doAssert test.path == "/over/there/index.dtb"
     doAssert test.query == "type=animal&name=narwhal"
     doAssert test.anchor == "nose"
+    doAssert($test == str)
 
   block:
-    let test = parseUri("urn:example:animal:ferret:nose")
+    let str = "urn:example:animal:ferret:nose"
+    let test = parseUri(str)
     doAssert test.scheme == "urn"
     doAssert test.path == "example:animal:ferret:nose"
+    doAssert($test == str)
 
   block:
-    let test = parseUri("mailto:username@example.com?subject=Topic")
+    let str = "mailto:username@example.com?subject=Topic"
+    let test = parseUri(str)
     doAssert test.scheme == "mailto"
     doAssert test.username == "username"
     doAssert test.hostname == "example.com"
     doAssert test.query == "subject=Topic"
+    doAssert($test == str)
 
   block:
-    let test = parseUri("magnet:?xt=urn:sha1:72hsga62ba515sbd62&dn=foobar")
+    let str = "magnet:?xt=urn:sha1:72hsga62ba515sbd62&dn=foobar"
+    let test = parseUri(str)
     doAssert test.scheme == "magnet"
     doAssert test.query == "xt=urn:sha1:72hsga62ba515sbd62&dn=foobar"
+    doAssert($test == str)
 
   block:
-    let test = parseUri("/test/foo/bar?q=2#asdf")
+    let str = "/test/foo/bar?q=2#asdf"
+    let test = parseUri(str)
     doAssert test.scheme == ""
     doAssert test.path == "/test/foo/bar"
     doAssert test.query == "q=2"
     doAssert test.anchor == "asdf"
+    doAssert($test == str)
 
   block:
-    let test = parseUri("test/no/slash")
+    let str = "test/no/slash"
+    let test = parseUri(str)
     doAssert test.path == "test/no/slash"
+    doAssert($test == str)
 
   # Remove dot segments tests
   block:
@@ -371,5 +406,3 @@ when isMainModule:
   block:
     let test = parseUri("http://example.com/foo/") / "/bar/asd"
     doAssert test.path == "/foo/bar/asd"
-
-  
diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim
index 660932d92..6cf837f25 100644
--- a/lib/pure/xmldom.nim
+++ b/lib/pure/xmldom.nim
@@ -365,23 +365,21 @@ discard """proc getElementById*(doc: PDocument, elementId: string): PElement =
 proc getElementsByTagName*(doc: PDocument, tagName: string): seq[PNode] =
   ## Returns a NodeList of all the Elements with a given tag name in
   ## the order in which they are encountered in a preorder traversal of the Document tree.
-  var result: seq[PNode] = @[]
+  result = @[]
   if doc.fDocumentElement.fNodeName == tagName or tagName == "*":
     result.add(doc.fDocumentElement)
 
   result.add(doc.fDocumentElement.findNodes(tagName))
-  return result
 
 proc getElementsByTagNameNS*(doc: PDocument, namespaceURI: string, localName: string): seq[PNode] =
   ## Returns a NodeList of all the Elements with a given localName and namespaceURI
   ## in the order in which they are encountered in a preorder traversal of the Document tree.
-  var result: seq[PNode] = @[]
+  result = @[]
   if doc.fDocumentElement.fLocalName == localName or localName == "*":
     if doc.fDocumentElement.fNamespaceURI == namespaceURI or namespaceURI == "*":
       result.add(doc.fDocumentElement)
 
   result.add(doc.fDocumentElement.findNodesNS(namespaceURI, localName))
-  return result
 
 proc importNode*(doc: PDocument, importedNode: PNode, deep: bool): PNode =
   ## Imports a node from another document to this document
@@ -642,7 +640,7 @@ proc isEmpty(s: string): bool =
   return true
 
 proc normalize*(n: PNode) =
-  ## Merges all seperated TextNodes together, and removes any empty TextNodes
+  ## Merges all separated TextNodes together, and removes any empty TextNodes
   var curTextNode: PNode = nil
   var i: int = 0
 
@@ -677,7 +675,7 @@ proc removeChild*(n: PNode, oldChild: PNode): PNode =
       if n.childNodes[i] == oldChild:
         result = n.childNodes[i]
         n.childNodes.delete(i)
-        return result
+        return
 
   raise newException(ENotFoundErr, "Node not found")
 
@@ -693,7 +691,7 @@ proc replaceChild*(n: PNode, newChild: PNode, oldChild: PNode): PNode =
       if n.childNodes[i] == oldChild:
         result = n.childNodes[i]
         n.childNodes[i] = newChild
-        return result
+        return
 
   raise newException(ENotFoundErr, "Node not found")
 
@@ -740,7 +738,7 @@ proc removeNamedItem*(nList: var seq[PNode], name: string): PNode =
     if nList[i].fNodeName == name:
       result = nList[i]
       nList.delete(i)
-      return result
+      return
 
   raise newException(ENotFoundErr, "Node not found")
 
@@ -750,7 +748,7 @@ proc removeNamedItemNS*(nList: var seq[PNode], namespaceURI: string, localName:
     if nList[i].fLocalName == localName and nList[i].fNamespaceURI == namespaceURI:
       result = nList[i]
       nList.delete(i)
-      return result
+      return
 
   raise newException(ENotFoundErr, "Node not found")
 
@@ -965,7 +963,7 @@ proc removeAttributeNode*(el: PElement, oldAttr: PAttr): PAttr =
       if el.attributes[i] == oldAttr:
         result = el.attributes[i]
         el.attributes.delete(i)
-        return result
+        return
 
   raise newException(ENotFoundErr, "oldAttr is not a member of el's Attributes")
 
@@ -1083,7 +1081,7 @@ proc addEscaped(s: string): string =
     else: result.add(c)
 
 proc nodeToXml(n: PNode, indent: int = 0): string =
-  result = repeatChar(indent, ' ') & "<" & n.nodeName
+  result = spaces(indent) & "<" & n.nodeName
   if not isNil(n.attributes):
     for i in items(n.attributes):
       result.add(" " & i.name & "=\"" & addEscaped(i.value) & "\"")
@@ -1098,23 +1096,23 @@ proc nodeToXml(n: PNode, indent: int = 0): string =
       of ElementNode:
         result.add(nodeToXml(i, indent + 2))
       of TextNode:
-        result.add(repeatChar(indent * 2, ' '))
+        result.add(spaces(indent * 2))
         result.add(addEscaped(i.nodeValue))
       of CDataSectionNode:
-        result.add(repeatChar(indent * 2, ' '))
+        result.add(spaces(indent * 2))
         result.add("<![CDATA[" & i.nodeValue & "]]>")
       of ProcessingInstructionNode:
-        result.add(repeatChar(indent * 2, ' '))
+        result.add(spaces(indent * 2))
         result.add("<?" & PProcessingInstruction(i).target & " " &
                           PProcessingInstruction(i).data & " ?>")
       of CommentNode:
-        result.add(repeatChar(indent * 2, ' '))
+        result.add(spaces(indent * 2))
         result.add("<!-- " & i.nodeValue & " -->")
       else:
         continue
       result.add("\n")
     # Add the ending tag - </tag>
-    result.add(repeatChar(indent, ' ') & "</" & n.nodeName & ">")
+    result.add(spaces(indent) & "</" & n.nodeName & ">")
 
 proc `$`*(doc: PDocument): string =
   ## Converts a PDocument object into a string representation of it's XML
diff --git a/lib/pure/xmldomparser.nim b/lib/pure/xmldomparser.nim
index 7f34d72a8..050362435 100644
--- a/lib/pure/xmldomparser.nim
+++ b/lib/pure/xmldomparser.nim
@@ -155,7 +155,7 @@ proc loadXMLFile*(path: string): PDocument =
   return loadXMLStream(s)
 
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   var xml = loadXMLFile("nim/xmldom/test.xml")
   #echo(xml.getElementsByTagName("m:test2")[0].namespaceURI)
   #echo(xml.getElementsByTagName("bla:test")[0].namespaceURI)
diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim
index 8591e894c..840cae734 100644
--- a/lib/pure/xmlparser.nim
+++ b/lib/pure/xmlparser.nim
@@ -103,7 +103,7 @@ proc parse(x: var XmlParser, errors: var seq[string]): XmlNode =
 proc parseXml*(s: Stream, filename: string, 
                errors: var seq[string]): XmlNode = 
   ## parses the XML from stream `s` and returns a ``PXmlNode``. Every
-  ## occured parsing error is added to the `errors` sequence.
+  ## occurred parsing error is added to the `errors` sequence.
   var x: XmlParser
   open(x, s, filename, {reportComments})
   while true:
@@ -129,7 +129,7 @@ proc parseXml*(s: Stream): XmlNode =
 
 proc loadXml*(path: string, errors: var seq[string]): XmlNode =
   ## Loads and parses XML from file specified by ``path``, and returns 
-  ## a ``PXmlNode``. Every occured parsing error is added to the `errors`
+  ## a ``PXmlNode``. Every occurred parsing error is added to the `errors`
   ## sequence.
   var s = newFileStream(path, fmRead)
   if s == nil: raise newException(IOError, "Unable to read file: " & path)
@@ -143,7 +143,7 @@ proc loadXml*(path: string): XmlNode =
   result = loadXml(path, errors)
   if errors.len > 0: raiseInvalidXml(errors)
 
-when isMainModule:
+when not defined(testing) and isMainModule:
   import os
 
   var errors: seq[string] = @[]  
diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim
index b84da9586..7526a989a 100644
--- a/lib/pure/xmltree.nim
+++ b/lib/pure/xmltree.nim
@@ -12,20 +12,20 @@
 import macros, strtabs
 
 type
-  XmlNode* = ref XmlNodeObj ## an XML tree consists of ``PXmlNode``'s. 
-  
+  XmlNode* = ref XmlNodeObj ## an XML tree consists of ``PXmlNode``'s.
+
   XmlNodeKind* = enum  ## different kinds of ``PXmlNode``'s
     xnText,             ## a text element
     xnElement,          ## an element with 0 or more children
     xnCData,            ## a CDATA node
     xnEntity,           ## an entity (like ``&thing;``)
     xnComment           ## an XML comment
-  
+
   XmlAttributes* = StringTableRef ## an alias for a string to string mapping
-  
-  XmlNodeObj {.acyclic.} = object 
+
+  XmlNodeObj {.acyclic.} = object
     case k: XmlNodeKind # private, use the kind() proc to read this field.
-    of xnText, xnComment, xnCData, xnEntity: 
+    of xnText, xnComment, xnCData, xnEntity:
       fText: string
     of xnElement:
       fTag: string
@@ -41,34 +41,34 @@ proc newXmlNode(kind: XmlNodeKind): XmlNode =
   new(result)
   result.k = kind
 
-proc newElement*(tag: string): XmlNode = 
+proc newElement*(tag: string): XmlNode =
   ## creates a new ``PXmlNode`` of kind ``xnText`` with the given `tag`.
   result = newXmlNode(xnElement)
   result.fTag = tag
   result.s = @[]
   # init attributes lazily to safe memory
 
-proc newText*(text: string): XmlNode = 
+proc newText*(text: string): XmlNode =
   ## creates a new ``PXmlNode`` of kind ``xnText`` with the text `text`.
   result = newXmlNode(xnText)
   result.fText = text
 
-proc newComment*(comment: string): XmlNode = 
+proc newComment*(comment: string): XmlNode =
   ## creates a new ``PXmlNode`` of kind ``xnComment`` with the text `comment`.
   result = newXmlNode(xnComment)
   result.fText = comment
 
-proc newCData*(cdata: string): XmlNode = 
+proc newCData*(cdata: string): XmlNode =
   ## creates a new ``PXmlNode`` of kind ``xnComment`` with the text `cdata`.
   result = newXmlNode(xnCData)
   result.fText = cdata
 
-proc newEntity*(entity: string): XmlNode = 
+proc newEntity*(entity: string): XmlNode =
   ## creates a new ``PXmlNode`` of kind ``xnEntity`` with the text `entity`.
   result = newXmlNode(xnCData)
   result.fText = entity
 
-proc text*(n: XmlNode): string {.inline.} = 
+proc text*(n: XmlNode): string {.inline.} =
   ## gets the associated text with the node `n`. `n` can be a CDATA, Text,
   ## comment, or entity node.
   assert n.k in {xnText, xnComment, xnCData, xnEntity}
@@ -93,16 +93,16 @@ proc innerText*(n: XmlNode): string =
   for i in 0 .. n.s.len-1:
     if n.s[i].k in {xnText, xnEntity}: result.add(n.s[i].fText)
 
-proc tag*(n: XmlNode): string {.inline.} = 
+proc tag*(n: XmlNode): string {.inline.} =
   ## gets the tag name of `n`. `n` has to be an ``xnElement`` node.
   assert n.k == xnElement
   result = n.fTag
-    
-proc add*(father, son: XmlNode) {.inline.} = 
+
+proc add*(father, son: XmlNode) {.inline.} =
   ## adds the child `son` to `father`.
   add(father.s, son)
-  
-proc len*(n: XmlNode): int {.inline.} = 
+
+proc len*(n: XmlNode): int {.inline.} =
   ## returns the number `n`'s children.
   if n.k == xnElement: result = len(n.s)
 
@@ -110,28 +110,38 @@ proc kind*(n: XmlNode): XmlNodeKind {.inline.} =
   ## returns `n`'s kind.
   result = n.k
 
-proc `[]`* (n: XmlNode, i: int): XmlNode {.inline.} = 
+proc `[]`* (n: XmlNode, i: int): XmlNode {.inline.} =
   ## returns the `i`'th child of `n`.
   assert n.k == xnElement
   result = n.s[i]
 
-iterator items*(n: XmlNode): XmlNode {.inline.} = 
+proc mget* (n: var XmlNode, i: int): var XmlNode {.inline.} =
+  ## returns the `i`'th child of `n` so that it can be modified
+  assert n.k == xnElement
+  result = n.s[i]
+
+iterator items*(n: XmlNode): XmlNode {.inline.} =
   ## iterates over any child of `n`.
   assert n.k == xnElement
   for i in 0 .. n.len-1: yield n[i]
 
-proc attrs*(n: XmlNode): XmlAttributes {.inline.} = 
+iterator mitems*(n: var XmlNode): var XmlNode {.inline.} =
+  ## iterates over any child of `n`.
+  assert n.k == xnElement
+  for i in 0 .. n.len-1: yield mget(n, i)
+
+proc attrs*(n: XmlNode): XmlAttributes {.inline.} =
   ## gets the attributes belonging to `n`.
   ## Returns `nil` if attributes have not been initialised for this node.
   assert n.k == xnElement
   result = n.fAttr
-  
-proc `attrs=`*(n: XmlNode, attr: XmlAttributes) {.inline.} = 
+
+proc `attrs=`*(n: XmlNode, attr: XmlAttributes) {.inline.} =
   ## sets the attributes belonging to `n`.
   assert n.k == xnElement
   n.fAttr = attr
 
-proc attrsLen*(n: XmlNode): int {.inline.} = 
+proc attrsLen*(n: XmlNode): int {.inline.} =
   ## returns the number of `n`'s attributes.
   assert n.k == xnElement
   if not isNil(n.fAttr): result = len(n.fAttr)
@@ -141,12 +151,12 @@ proc clientData*(n: XmlNode): int {.inline.} =
   ## parser and generator.
   result = n.fClientData
 
-proc `clientData=`*(n: XmlNode, data: int) {.inline.} = 
+proc `clientData=`*(n: XmlNode, data: int) {.inline.} =
   ## sets the client data of `n`. The client data field is used by the HTML
   ## parser and generator.
   n.fClientData = data
 
-proc addEscaped*(result: var string, s: string) = 
+proc addEscaped*(result: var string, s: string) =
   ## same as ``result.add(escape(s))``, but more efficient.
   for c in items(s):
     case c
@@ -158,8 +168,8 @@ proc addEscaped*(result: var string, s: string) =
     of '/': result.add("&#x2F;")
     else: result.add(c)
 
-proc escape*(s: string): string = 
-  ## escapes `s` for inclusion into an XML document. 
+proc escape*(s: string): string =
+  ## escapes `s` for inclusion into an XML document.
   ## Escapes these characters:
   ##
   ## ------------    -------------------
@@ -174,26 +184,26 @@ proc escape*(s: string): string =
   ## ------------    -------------------
   result = newStringOfCap(s.len)
   addEscaped(result, s)
-  
-proc addIndent(result: var string, indent: int) = 
+
+proc addIndent(result: var string, indent: int) =
   result.add("\n")
   for i in 1..indent: result.add(' ')
-  
+
 proc noWhitespace(n: XmlNode): bool =
   #for i in 1..n.len-1:
   #  if n[i].kind != n[0].kind: return true
   for i in 0..n.len-1:
     if n[i].kind in {xnText, xnEntity}: return true
-  
-proc add*(result: var string, n: XmlNode, indent = 0, indWidth = 2) = 
+
+proc add*(result: var string, n: XmlNode, indent = 0, indWidth = 2) =
   ## adds the textual representation of `n` to `result`.
   if n == nil: return
   case n.k
   of xnElement:
     result.add('<')
     result.add(n.fTag)
-    if not isNil(n.fAttr): 
-      for key, val in pairs(n.fAttr): 
+    if not isNil(n.fAttr):
+      for key, val in pairs(n.fAttr):
         result.add(' ')
         result.add(key)
         result.add("=\"")
@@ -207,7 +217,7 @@ proc add*(result: var string, n: XmlNode, indent = 0, indWidth = 2) =
           # because this would be wrong. For example: ``a<b>b</b>`` is
           # different from ``a <b>b</b>``.
           for i in 0..n.len-1: result.add(n[i], indent+indWidth, indWidth)
-        else: 
+        else:
           for i in 0..n.len-1:
             result.addIndent(indent+indWidth)
             result.add(n[i], indent+indWidth, indWidth)
@@ -217,7 +227,7 @@ proc add*(result: var string, n: XmlNode, indent = 0, indWidth = 2) =
       result.add("</")
       result.add(n.fTag)
       result.add(">")
-    else: 
+    else:
       result.add(" />")
   of xnText:
     result.addEscaped(n.fText)
@@ -235,7 +245,7 @@ proc add*(result: var string, n: XmlNode, indent = 0, indWidth = 2) =
     result.add(';')
 
 const
-  xmlHeader* = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" 
+  xmlHeader* = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
     ## header to use for complete XML output
 
 proc `$`*(n: XmlNode): string =
@@ -245,21 +255,21 @@ proc `$`*(n: XmlNode): string =
   result.add(n)
 
 proc newXmlTree*(tag: string, children: openArray[XmlNode],
-                 attributes: XmlAttributes = nil): XmlNode = 
+                 attributes: XmlAttributes = nil): XmlNode =
   ## creates a new XML tree with `tag`, `children` and `attributes`
   result = newXmlNode(xnElement)
   result.fTag = tag
   newSeq(result.s, children.len)
   for i in 0..children.len-1: result.s[i] = children[i]
   result.fAttr = attributes
-  
-proc xmlConstructor(e: PNimrodNode): PNimrodNode {.compileTime.} =
+
+proc xmlConstructor(e: NimNode): NimNode {.compileTime.} =
   expectLen(e, 2)
   var a = e[1]
   if a.kind == nnkCall:
     result = newCall("newXmlTree", toStrLit(a[0]))
     var attrs = newNimNode(nnkBracket, a)
-    var newStringTabCall = newCall("newStringTable", attrs, 
+    var newStringTabCall = newCall("newStringTable", attrs,
                                    newIdentNode("modeCaseSensitive"))
     var elements = newNimNode(nnkBracket, a)
     for i in 1..a.len-1:
@@ -270,21 +280,21 @@ proc xmlConstructor(e: PNimrodNode): PNimrodNode {.compileTime.} =
       else:
         elements.add(a[i])
     result.add(elements)
-    if attrs.len > 1: 
+    if attrs.len > 1:
       #echo repr(newStringTabCall)
       result.add(newStringTabCall)
   else:
     result = newCall("newXmlTree", toStrLit(a))
 
-macro `<>`*(x: expr): expr {.immediate.} = 
+macro `<>`*(x: expr): expr {.immediate.} =
   ## Constructor macro for XML. Example usage:
   ##
   ## .. code-block:: nim
-  ##   <>a(href="http://nim-code.org", newText("Nim rules."))
+  ##   <>a(href="http://nim-lang.org", newText("Nim rules."))
   ##
   ## Produces an XML tree for::
   ##
-  ##  <a href="http://nim-code.org">Nim rules.</a>
+  ##  <a href="http://nim-lang.org">Nim rules.</a>
   ##
   let x = callsite()
   result = xmlConstructor(x)
@@ -343,5 +353,6 @@ proc findAll*(n: XmlNode, tag: string): seq[XmlNode] =
   findAll(n, tag, result)
 
 when isMainModule:
-  assert """<a href="http://nim-code.org">Nim rules.</a>""" ==
-    $(<>a(href="http://nim-code.org", newText("Nim rules.")))
+  let link = "http://nim-lang.org"
+  assert """<a href="""" & escape(link) & """">Nim rules.</a>""" ==
+    $(<>a(href="http://nim-lang.org", newText("Nim rules.")))
diff --git a/lib/system.nim b/lib/system.nim
index 0cd4b84e2..85f1350d7 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -73,9 +73,13 @@ type
   expr* {.magic: Expr.} ## meta type to denote an expression (for templates)
   stmt* {.magic: Stmt.} ## meta type to denote a statement (for templates)
   typedesc* {.magic: TypeDesc.} ## meta type to denote a type description
-  void* {.magic: "VoidType".}   ## meta type to denote the absense of any type
+  void* {.magic: "VoidType".}   ## meta type to denote the absence of any type
   auto* = expr
   any* = distinct auto
+  untyped* {.magic: Expr.} ## meta type to denote an expression that
+                           ## is not resolved (for templates)
+  typed* {.magic: Stmt.}   ## meta type to denote an expression that
+                           ## is resolved (for templates)
 
   SomeSignedInt* = int|int8|int16|int32|int64
     ## type class matching all signed integer types
@@ -89,7 +93,7 @@ type
   SomeOrdinal* = int|int8|int16|int32|int64|bool|enum|uint8|uint16|uint32
     ## type class matching all ordinal types; however this includes enums with
     ## holes.
-  
+
   SomeReal* = float|float32|float64
     ## type class matching all floating point number types
 
@@ -124,7 +128,7 @@ proc declared*(x: expr): bool {.magic: "Defined", noSideEffect.}
   ## feature or not:
   ##
   ## .. code-block:: Nim
-  ##   when not defined(strutils.toUpper):
+  ##   when not declared(strutils.toUpper):
   ##     # provide our own toUpper proc here, because strutils is
   ##     # missing it.
 
@@ -140,6 +144,16 @@ proc declaredInScope*(x: expr): bool {.
   ## Special compile-time procedure that checks whether `x` is
   ## declared in the current scope. `x` has to be an identifier.
 
+proc `addr`*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} =
+  ## Builtin 'addr' operator for taking the address of a memory location.
+  ## Cannot be overloaded.
+  discard
+
+proc `type`*(x: expr): typeDesc {.magic: "TypeOf", noSideEffect.} =
+  ## Builtin 'type' operator for accessing the type of an expression.
+  ## Cannot be overloaded.
+  discard
+
 proc `not` *(x: bool): bool {.magic: "Not", noSideEffect.}
   ## Boolean not; returns true iff ``x == false``.
 
@@ -163,12 +177,6 @@ proc new*(T: typedesc): ref T =
   ## reference to it as result value
   new(result)
 
-proc unsafeNew*[T](a: var ref T, size: int) {.magic: "New", noSideEffect.}
-  ## creates a new object of type ``T`` and returns a safe (traced)
-  ## reference to it in ``a``. This is **unsafe** as it allocates an object
-  ## of the passed ``size``. This should only be used for optimization
-  ## purposes when you know what you're doing!
-
 proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.}
   ## leaked implementation detail. Do not use.
 
@@ -181,7 +189,7 @@ proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {.
   ## 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
   ## will be called!
-  
+
 proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.}
   ## resets an object `obj` to its initial (binary zero) value. This needs to
   ## be called before any possible `object branch transition`:idx:.
@@ -212,13 +220,13 @@ type
   set*{.magic: "Set".}[T]  ## Generic type to construct bit sets.
 
 type
-  Slice* {.final, pure.}[T] = object ## builtin slice type
-    a*, b*: T                        ## the bounds
+  Slice*[T] = object ## builtin slice type
+    a*, b*: T        ## the bounds
 
 when defined(nimalias):
   {.deprecated: [TSlice: Slice].}
 
-proc `..`*[T](a, b: T): Slice[T] {.noSideEffect, inline.} =
+proc `..`*[T](a, b: T): Slice[T] {.noSideEffect, inline, magic: "DotDot".} =
   ## `slice`:idx: operator that constructs an interval ``[a, b]``, both `a`
   ## and `b` are inclusive. Slices can also be used in the set constructor
   ## and in ordinal case statements, but then they are special-cased by the
@@ -226,7 +234,7 @@ proc `..`*[T](a, b: T): Slice[T] {.noSideEffect, inline.} =
   result.a = a
   result.b = b
 
-proc `..`*[T](b: T): Slice[T] {.noSideEffect, inline.} =
+proc `..`*[T](b: T): Slice[T] {.noSideEffect, inline, magic: "DotDot".} =
   ## `slice`:idx: operator that constructs an interval ``[default(T), b]``
   result.b = b
 
@@ -291,12 +299,14 @@ include "system/inclrtl"
 const NoFakeVars* = defined(NimrodVM) ## true if the backend doesn't support \
   ## "fake variables" like 'var EBADF {.importc.}: cint'.
 
+const ArrayDummySize = when defined(cpu16): 10_000 else: 100_000_000
+
 when not defined(JS):
   type
     TGenericSeq {.compilerproc, pure, inheritable.} = object
       len, reserved: int
     PGenericSeq {.exportc.} = ptr TGenericSeq
-    UncheckedCharArray {.unchecked.} = array[0..100_000_000, char]
+    UncheckedCharArray {.unchecked.} = array[0..ArrayDummySize, char]
     # len and space without counting the terminating zero:
     NimStringDesc {.compilerproc, final.} = object of TGenericSeq
       data: UncheckedCharArray
@@ -341,12 +351,12 @@ type
     ##
     ## Each exception has to inherit from `Exception`. See the full `exception
     ## hierarchy`_.
-    parent: ref Exception     ## parent exception (can be used as a stack)
-    name: cstring             ## The exception's name is its Nim identifier.
-                              ## This field is filled automatically in the
-                              ## ``raise`` statement.
+    parent*: ref Exception ## parent exception (can be used as a stack)
+    name: cstring ## The exception's name is its Nim identifier.
+                  ## This field is filled automatically in the
+                  ## ``raise`` statement.
     msg* {.exportc: "message".}: string ## the exception's message. Not
-                                        ## providing an exception message 
+                                        ## providing an exception message
                                         ## is bad style.
     trace: string
 
@@ -355,7 +365,7 @@ type
     ##
     ## See the full `exception hierarchy`_.
   IOError* = object of SystemError ## \
-    ## Raised if an IO error occured.
+    ## Raised if an IO error occurred.
     ##
     ## See the full `exception hierarchy`_.
   OSError* = object of SystemError ## \
@@ -368,11 +378,11 @@ type
     ##
     ## See the full `exception hierarchy`_.
   ResourceExhaustedError* = object of SystemError ## \
-    ## Raised if a resource request could not be fullfilled.
+    ## Raised if a resource request could not be fulfilled.
     ##
     ## See the full `exception hierarchy`_.
   ArithmeticError* = object of Exception ## \
-    ## Raised if any kind of arithmetic error occured.
+    ## Raised if any kind of arithmetic error occurred.
     ##
     ## See the full `exception hierarchy`_.
   DivByZeroError* = object of ArithmeticError ## \
@@ -481,7 +491,7 @@ type
 
   E_Base: Exception, ESystem: SystemError, EIO: IOError,
   EOS: OSError, EInvalidLibrary: LibraryError,
-  EResourceExhausted: ResourceExhaustedError, 
+  EResourceExhausted: ResourceExhaustedError,
   EArithmetic: ArithmeticError, EDivByZero: DivByZeroError,
   EOverflow: OverflowError, EAccessViolation: AccessViolationError,
   EAssertionFailed: AssertionError, EInvalidValue: ValueError,
@@ -492,7 +502,7 @@ type
   EInvalidObjectAssignment: ObjectAssignmentError,
   EInvalidObjectConversion: ObjectConversionError,
   EDeadThread: DeadThreadError,
-  EFloatInexact: FloatInexactError, 
+  EFloatInexact: FloatInexactError,
   EFloatUnderflow: FloatUnderflowError,
   EFloatingPoint: FloatingPointError,
   EFloatInvalidOp: FloatInvalidOpError,
@@ -501,7 +511,13 @@ type
   ESynch: Exception
 ].}
 
-proc sizeof*[T](x: T): Natural {.magic: "SizeOf", noSideEffect.}
+proc unsafeNew*[T](a: var ref T, size: Natural) {.magic: "New", noSideEffect.}
+  ## creates a new object of type ``T`` and returns a safe (traced)
+  ## reference to it in ``a``. This is **unsafe** as it allocates an object
+  ## of the passed ``size``. This should only be used for optimization
+  ## purposes when you know what you're doing!
+
+proc sizeof*[T](x: T): int {.magic: "SizeOf", noSideEffect.}
   ## returns the size of ``x`` in bytes. Since this is a low-level proc,
   ## its usage is discouraged - using ``new`` for the most cases suffices
   ## that one never needs to know ``x``'s size. As a special semantic rule,
@@ -509,11 +525,11 @@ proc sizeof*[T](x: T): Natural {.magic: "SizeOf", noSideEffect.}
 
 proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.}
   ## unary ``<`` that can be used for nice looking excluding ranges:
-  ## 
+  ##
   ## .. code-block:: nim
   ##   for i in 0 .. <10: echo i
   ##
-  ## Semantically this is the same as ``pred``. 
+  ## Semantically this is the same as ``pred``.
 
 proc succ*[T](x: Ordinal[T], y = 1): T {.magic: "Succ", noSideEffect.}
   ## returns the ``y``-th successor of the value ``x``. ``T`` has to be
@@ -534,8 +550,8 @@ proc dec*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Dec", noSideEffect.
   ## decrements the ordinal ``x`` by ``y``. If such a value does not
   ## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
   ## short notation for: ``x = pred(x, y)``.
-  
-proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
+
+proc newSeq*[T](s: var seq[T], len: Natural) {.magic: "NewSeq", noSideEffect.}
   ## creates a new sequence of type ``seq[T]`` with length ``len``.
   ## This is equivalent to ``s = @[]; setlen(s, len)``, but more
   ## efficient since no reallocation is needed.
@@ -553,7 +569,7 @@ proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
   ##   inputStrings[2] = "would crash"
   ##   #inputStrings[3] = "out of bounds"
 
-proc newSeq*[T](len = 0): seq[T] =
+proc newSeq*[T](len = 0.Natural): seq[T] =
   ## creates a new sequence of type ``seq[T]`` with length ``len``.
   ##
   ## Note that the sequence will be filled with zeroed entries, which can be a
@@ -576,7 +592,7 @@ proc len*(x: cstring): int {.magic: "LengthStr", noSideEffect.}
 proc len*[I, T](x: array[I, T]): int {.magic: "LengthArray", noSideEffect.}
 proc len*[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.}
   ## returns the length of an array, an openarray, a sequence or a string.
-  ## This is rougly the same as ``high(T)-low(T)+1``, but its resulting type is
+  ## This is roughly the same as ``high(T)-low(T)+1``, but its resulting type is
   ## always an int.
 
 # set routines:
@@ -634,7 +650,7 @@ when not defined(JS):
 
   proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.}
     ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits
-    ## from `x`.    
+    ## from `x`.
   proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect.}
     ## treats `x` as unsigned and converts it to an ``int16`` by taking the last
     ## 16 bits from `x`.
@@ -647,7 +663,7 @@ proc `+` *(x: int): int {.magic: "UnaryPlusI", noSideEffect.}
 proc `+` *(x: int8): int8 {.magic: "UnaryPlusI", noSideEffect.}
 proc `+` *(x: int16): int16 {.magic: "UnaryPlusI", noSideEffect.}
 proc `+` *(x: int32): int32 {.magic: "UnaryPlusI", noSideEffect.}
-proc `+` *(x: int64): int64 {.magic: "UnaryPlusI64", noSideEffect.}
+proc `+` *(x: int64): int64 {.magic: "UnaryPlusI", noSideEffect.}
   ## Unary `+` operator for an integer. Has no effect.
 
 proc `-` *(x: int): int {.magic: "UnaryMinusI", noSideEffect.}
@@ -692,6 +708,7 @@ proc `div` *(x, y: int32): int32 {.magic: "DivI", noSideEffect.}
 proc `div` *(x, y: int64): int64 {.magic: "DivI64", noSideEffect.}
   ## computes the integer division. This is roughly the same as
   ## ``floor(x/y)``.
+  ##
   ## .. code-block:: Nim
   ##   1 div 2 == 0
   ##   2 div 2 == 1
@@ -711,6 +728,7 @@ proc `shr` *(x, y: int16): int16 {.magic: "ShrI", noSideEffect.}
 proc `shr` *(x, y: int32): int32 {.magic: "ShrI", noSideEffect.}
 proc `shr` *(x, y: int64): int64 {.magic: "ShrI64", noSideEffect.}
   ## computes the `shift right` operation of `x` and `y`.
+  ##
   ## .. code-block:: Nim
   ##   0b0001_0000'i8 shr 2 == 0b0100_0000'i8
   ##   0b1000_0000'i8 shr 2 == 0b0000_0000'i8
@@ -798,7 +816,7 @@ proc `%%` *(x, y: int64): int64 {.magic: "ModU", noSideEffect.}
   ## The result is truncated to fit into the result.
   ## This implements modulo arithmetic.
   ## No overflow errors are possible.
-  
+
 proc `<=%` *(x, y: IntMax32): bool {.magic: "LeU", noSideEffect.}
 proc `<=%` *(x, y: int64): bool {.magic: "LeU64", noSideEffect.}
   ## treats `x` and `y` as unsigned and compares them.
@@ -863,7 +881,7 @@ proc contains*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.}
   ## passes its arguments in reverse order.
 
 proc contains*[T](s: Slice[T], value: T): bool {.noSideEffect, inline.} =
-  ## Checks if `value` is withing the range of `s`; returns true iff
+  ## Checks if `value` is within the range of `s`; returns true iff
   ## `value >= s.a and value <= s.b`
   ##
   ## .. code-block:: Nim
@@ -887,7 +905,7 @@ template `notin` * (x, y: expr): expr {.immediate, dirty.} = not contains(y, x)
 
 proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
   ## Checks if T is of the same type as S
-  ## 
+  ##
   ## .. code-block:: Nim
   ##   proc test[T](a: T): int =
   ##     when (T is int):
@@ -922,25 +940,25 @@ proc cmp*(x, y: string): int {.noSideEffect, procvar.}
 proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {.
   magic: "ArrToSeq", nosideeffect.}
   ## turns an array into a sequence. This most often useful for constructing
-  ## sequences with the array constructor: ``@[1, 2, 3]`` has the type 
+  ## sequences with the array constructor: ``@[1, 2, 3]`` has the type
   ## ``seq[int]``, while ``[1, 2, 3]`` has the type ``array[0..2, int]``.
 
-proc setLen*[T](s: var seq[T], newlen: int) {.
+proc setLen*[T](s: var seq[T], newlen: Natural) {.
   magic: "SetLengthSeq", noSideEffect.}
   ## sets the length of `s` to `newlen`.
   ## ``T`` may be any sequence type.
   ## If the current length is greater than the new length,
   ## ``s`` will be truncated. `s` cannot be nil! To initialize a sequence with
-  ## a size, use ``newSeq`` instead. 
+  ## a size, use ``newSeq`` instead.
 
-proc setLen*(s: var string, newlen: int) {.
+proc setLen*(s: var string, newlen: Natural) {.
   magic: "SetLengthStr", noSideEffect.}
   ## sets the length of `s` to `newlen`.
   ## If the current length is greater than the new length,
   ## ``s`` will be truncated. `s` cannot be nil! To initialize a string with
-  ## a size, use ``newString`` instead. 
+  ## a size, use ``newString`` instead.
 
-proc newString*(len: int): string {.
+proc newString*(len: Natural): string {.
   magic: "NewString", importc: "mnewString", noSideEffect.}
   ## returns a new string of length ``len`` but with uninitialized
   ## content. One needs to fill the string character after character
@@ -948,10 +966,10 @@ proc newString*(len: int): string {.
   ## optimization purposes; the same effect can be achieved with the
   ## ``&`` operator or with ``add``.
 
-proc newStringOfCap*(cap: int): string {.
+proc newStringOfCap*(cap: Natural): string {.
   magic: "NewStringOfCap", importc: "rawNewString", noSideEffect.}
   ## returns a new string of length ``0`` but with capacity `cap`.This
-  ## procedure exists only for optimization purposes; the same effect can 
+  ## procedure exists only for optimization purposes; the same effect can
   ## be achieved with the ``&`` operator or with ``add``.
 
 proc `&` * (x: string, y: char): string {.
@@ -980,7 +998,7 @@ proc `&` * (x: char, y: string): string {.
   ##   assert('a' & "bc" == "abc")
 
 # implementation note: These must all have the same magic value "ConStrStr" so
-# that the merge optimization works properly. 
+# that the merge optimization works properly.
 
 proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.}
   ## Appends `y` to `x` in place
@@ -1037,15 +1055,15 @@ proc compileOption*(option: string): bool {.
   ## can be used to determine an on|off compile-time option. Example:
   ##
   ## .. code-block:: nim
-  ##   when compileOption("floatchecks"): 
+  ##   when compileOption("floatchecks"):
   ##     echo "compiled with floating point NaN and Inf checks"
-  
+
 proc compileOption*(option, arg: string): bool {.
   magic: "CompileOptionArg", noSideEffect.}
   ## can be used to determine an enum compile-time option. Example:
   ##
   ## .. code-block:: nim
-  ##   when compileOption("opt", "size") and compileOption("gc", "boehm"): 
+  ##   when compileOption("opt", "size") and compileOption("gc", "boehm"):
   ##     echo "compiled with optimization for size and uses Boehm's GC"
 
 const
@@ -1054,16 +1072,16 @@ const
   taintMode = compileOption("taintmode")
 
 when taintMode:
-  type TaintedString* = distinct string ## a distinct string type that 
+  type TaintedString* = distinct string ## a distinct string type that
                                         ## is `tainted`:idx:. It is an alias for
                                         ## ``string`` if the taint mode is not
                                         ## turned on. Use the ``-d:taintMode``
                                         ## command line switch to turn the taint
                                         ## mode on.
-  
+
   proc len*(s: TaintedString): int {.borrow.}
 else:
-  type TaintedString* = string          ## a distinct string type that 
+  type TaintedString* = string          ## a distinct string type that
                                         ## is `tainted`:idx:. It is an alias for
                                         ## ``string`` if the taint mode is not
                                         ## turned on. Use the ``-d:taintMode``
@@ -1134,25 +1152,25 @@ proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
 proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".}
   ## use this instead of `=` for a `shallow copy`:idx:. The shallow copy
   ## only changes the semantics for sequences and strings (and types which
-  ## contain those). Be careful with the changed semantics though! There 
+  ## contain those). Be careful with the changed semantics though! There
   ## is a reason why the default assignment does a deep copy of sequences
   ## and strings.
 
-proc del*[T](x: var seq[T], i: int) {.noSideEffect.} = 
+proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
   ## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
   ## This is an O(1) operation.
   let xl = x.len
   shallowCopy(x[i], x[xl-1])
   setLen(x, xl-1)
-  
-proc delete*[T](x: var seq[T], i: int) {.noSideEffect.} = 
+
+proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
   ## deletes the item at index `i` by moving ``x[i+1..]`` by one position.
   ## This is an O(n) operation.
   let xl = x.len
-  for j in i..xl-2: shallowCopy(x[j], x[j+1]) 
+  for j in i..xl-2: shallowCopy(x[j], x[j+1])
   setLen(x, xl-1)
-  
-proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} = 
+
+proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} =
   ## inserts `item` into `x` at position `i`.
   let xl = x.len
   setLen(x, xl+1)
@@ -1222,16 +1240,16 @@ type # these work for most platforms:
     ## This is the same as the type ``unsigned char`` in *C*.
   cushort* {.importc: "unsigned short", nodecl.} = uint16
     ## This is the same as the type ``unsigned short`` in *C*.
-  cuint* {.importc: "int", nodecl.} = uint32
+  cuint* {.importc: "unsigned int", nodecl.} = uint32
     ## This is the same as the type ``unsigned int`` in *C*.
   culonglong* {.importc: "unsigned long long", nodecl.} = uint64
     ## This is the same as the type ``unsigned long long`` in *C*.
 
-  cstringArray* {.importc: "char**", nodecl.} = ptr array [0..50_000, cstring]
+  cstringArray* {.importc: "char**", nodecl.} = ptr array [0..ArrayDummySize, cstring]
     ## This is binary compatible to the type ``char**`` in *C*. The array's
     ## high value is large enough to disable bounds checking in practice.
     ## Use `cstringArrayToSeq` to convert it into a ``seq[string]``.
-  
+
   PFloat32* = ptr float32 ## an alias for ``ptr float32``
   PFloat64* = ptr float64 ## an alias for ``ptr float64``
   PInt64* = ptr int64 ## an alias for ``ptr int64``
@@ -1278,7 +1296,7 @@ proc addQuitProc*(QuitProc: proc() {.noconv.}) {.
 proc copy*(s: string, first = 0): string {.
   magic: "CopyStr", importc: "copyStr", noSideEffect, deprecated.}
 proc copy*(s: string, first, last: int): string {.
-  magic: "CopyStrLast", importc: "copyStrLast", noSideEffect, 
+  magic: "CopyStrLast", importc: "copyStrLast", noSideEffect,
   deprecated.}
   ## copies a slice of `s` into a new string and returns this new
   ## string. The bounds `first` and `last` denote the indices of
@@ -1298,19 +1316,19 @@ proc substr*(s: string, first, last: int): string {.
   ## or `limit`:idx: a string's length.
 
 when not defined(nimrodVM):
-  proc zeroMem*(p: pointer, size: int) {.importc, noDecl, benign.}
+  proc zeroMem*(p: pointer, size: Natural) {.importc, noDecl, benign.}
     ## overwrites the contents of the memory at ``p`` with the value 0.
     ## Exactly ``size`` bytes will be overwritten. Like any procedure
     ## dealing with raw memory this is *unsafe*.
 
-  proc copyMem*(dest, source: pointer, size: int) {.
+  proc copyMem*(dest, source: pointer, size: Natural) {.
     importc: "memcpy", header: "<string.h>", benign.}
     ## copies the contents from the memory at ``source`` to the memory
     ## at ``dest``. Exactly ``size`` bytes will be copied. The memory
     ## regions may not overlap. Like any procedure dealing with raw
     ## memory this is *unsafe*.
 
-  proc moveMem*(dest, source: pointer, size: int) {.
+  proc moveMem*(dest, source: pointer, size: Natural) {.
     importc: "memmove", header: "<string.h>", benign.}
     ## copies the contents from the memory at ``source`` to the memory
     ## at ``dest``. Exactly ``size`` bytes will be copied. The memory
@@ -1318,7 +1336,7 @@ when not defined(nimrodVM):
     ## and is thus somewhat more safe than ``copyMem``. Like any procedure
     ## dealing with raw memory this is still *unsafe*, though.
 
-  proc equalMem*(a, b: pointer, size: int): bool {.
+  proc equalMem*(a, b: pointer, size: Natural): bool {.
     importc: "equalMem", noDecl, noSideEffect.}
     ## compares the memory blocks ``a`` and ``b``. ``size`` bytes will
     ## be compared. If the blocks are equal, true is returned, false
@@ -1326,7 +1344,7 @@ when not defined(nimrodVM):
     ## *unsafe*.
 
   when hostOS != "standalone":
-    proc alloc*(size: int): pointer {.noconv, rtl, tags: [], benign.}
+    proc alloc*(size: Natural): pointer {.noconv, rtl, tags: [], benign.}
       ## allocates a new memory block with at least ``size`` bytes. The
       ## block has to be freed with ``realloc(block, 0)`` or
       ## ``dealloc(block)``. The block is not initialized, so reading
@@ -1341,7 +1359,7 @@ when not defined(nimrodVM):
       ## The allocated memory belongs to its allocating thread!
       ## Use `createSharedU` to allocate from a shared heap.
       cast[ptr T](alloc(T.sizeof * size))
-    proc alloc0*(size: int): pointer {.noconv, rtl, tags: [], benign.}
+    proc alloc0*(size: Natural): pointer {.noconv, rtl, tags: [], benign.}
       ## allocates a new memory block with at least ``size`` bytes. The
       ## block has to be freed with ``realloc(block, 0)`` or
       ## ``dealloc(block)``. The block is initialized with all bytes
@@ -1356,8 +1374,8 @@ when not defined(nimrodVM):
       ## The allocated memory belongs to its allocating thread!
       ## Use `createShared` to allocate from a shared heap.
       cast[ptr T](alloc0(T.sizeof * size))
-    proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [], 
-                                                       benign.}
+    proc realloc*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [],
+                                                           benign.}
       ## grows or shrinks a given memory block. If p is **nil** then a new
       ## memory block is returned. In either way the block has at least
       ## ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
@@ -1379,40 +1397,40 @@ when not defined(nimrodVM):
       ## ``realloc``. This procedure is dangerous! If one forgets to
       ## free the memory a leak occurs; if one tries to access freed
       ## memory (or just freeing it twice!) a core dump may happen
-      ## or other memory may be corrupted. 
+      ## or other memory may be corrupted.
       ## The freed memory must belong to its allocating thread!
       ## Use `deallocShared` to deallocate from a shared heap.
     proc free*[T](p: ptr T) {.inline, benign.} =
       dealloc(p)
-    proc allocShared*(size: int): pointer {.noconv, rtl, benign.}
+    proc allocShared*(size: Natural): pointer {.noconv, rtl, benign.}
       ## allocates a new memory block on the shared heap with at
       ## least ``size`` bytes. The block has to be freed with
       ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
-      ## is not initialized, so reading from it before writing to it is 
+      ## is not initialized, so reading from it before writing to it is
       ## undefined behaviour!
-    proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline, 
+    proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline,
                                                                  benign.} =
       ## allocates a new memory block on the shared heap with at
       ## least ``T.sizeof * size`` bytes. The block has to be freed with
       ## ``resizeShared(block, 0)`` or ``freeShared(block)``. The block
-      ## is not initialized, so reading from it before writing to it is 
+      ## is not initialized, so reading from it before writing to it is
       ## undefined behaviour!
       cast[ptr T](allocShared(T.sizeof * size))
-    proc allocShared0*(size: int): pointer {.noconv, rtl, benign.}
-      ## allocates a new memory block on the shared heap with at 
+    proc allocShared0*(size: Natural): pointer {.noconv, rtl, benign.}
+      ## allocates a new memory block on the shared heap with at
       ## least ``size`` bytes. The block has to be freed with
       ## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
       ## The block is initialized with all bytes
       ## containing zero, so it is somewhat safer than ``allocShared``.
     proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
-      ## allocates a new memory block on the shared heap with at 
+      ## allocates a new memory block on the shared heap with at
       ## least ``T.sizeof * size`` bytes. The block has to be freed with
       ## ``resizeShared(block, 0)`` or ``freeShared(block)``.
       ## The block is initialized with all bytes
       ## containing zero, so it is somewhat safer than ``createSharedU``.
       cast[ptr T](allocShared0(T.sizeof * size))
-    proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl, 
-                                                             benign.}
+    proc reallocShared*(p: pointer, newSize: Natural): pointer {.noconv, rtl,
+                                                                 benign.}
       ## grows or shrinks a given memory block on the heap. If p is **nil**
       ## then a new memory block is returned. In either way the block has at
       ## least ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
@@ -1453,7 +1471,8 @@ template `>%` *(x, y: expr): expr {.immediate.} = y <% x
 
 proc `$`*(x: int): string {.magic: "IntToStr", noSideEffect.}
   ## The stringify operator for an integer argument. Returns `x`
-  ## converted to a decimal string.
+  ## converted to a decimal string. ``$`` is Nim's general way of
+  ## spelling `toString`:idx:.
 
 proc `$`*(x: int64): string {.magic: "Int64ToStr", noSideEffect.}
   ## The stringify operator for an integer argument. Returns `x`
@@ -1516,13 +1535,13 @@ const
   NimMinor*: int = 10
     ## is the minor number of Nim's version.
 
-  NimPatch*: int = 1
+  NimPatch*: int = 3
     ## is the patch number of Nim's version.
 
   NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
     ## is the version of Nim as a string.
 
-{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion, 
+{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion,
     NimrodMajor: NimMajor, NimrodMinor: NimMinor, NimrodPatch: NimPatch].}
 
 # GC interface:
@@ -1553,30 +1572,51 @@ when not defined(nimrodVM) and hostOS != "standalone":
       ## returns the number of bytes on the shared heap that are owned by the
       ## process. This is only available when threads are enabled.
 
+when sizeof(int) <= 2:
+  type IntLikeForCount = int|int8|int16|char|bool|uint8|enum
+else:
+  type IntLikeForCount = int|int8|int16|int32|char|bool|uint8|uint16|enum
+
 iterator countdown*[T](a, b: T, step = 1): T {.inline.} =
   ## Counts from ordinal value `a` down to `b` with the given
   ## step count. `T` may be any ordinal type, `step` may only
-  ## be positive.
-  var res = a
-  while res >= b:
-    yield res
-    dec(res, step)
+  ## be positive. **Note**: This fails to count to ``low(int)`` if T = int for
+  ## efficiency reasons.
+  when T is IntLikeForCount:
+    var res = int(a)
+    while res >= int(b):
+      yield T(res)
+      dec(res, step)
+  else:
+    var res = a
+    while res >= b:
+      yield res
+      dec(res, step)
+
+template countupImpl(incr: stmt) {.immediate, dirty.} =
+  when T is IntLikeForCount:
+    var res = int(a)
+    while res <= int(b):
+      yield T(res)
+      incr
+  else:
+    var res: T = T(a)
+    while res <= b:
+      yield res
+      incr
 
 iterator countup*[S, T](a: S, b: T, step = 1): T {.inline.} =
   ## Counts from ordinal value `a` up to `b` with the given
   ## step count. `S`, `T` may be any ordinal type, `step` may only
-  ## be positive.
-  var res: T = T(a)
-  while res <= b:
-    yield res
+  ## be positive. **Note**: This fails to count to ``high(int)`` if T = int for
+  ## efficiency reasons.
+  countupImpl:
     inc(res, step)
 
 iterator `..`*[S, T](a: S, b: T): T {.inline.} =
   ## An alias for `countup`.
-  var res: T = T(a)
-  while res <= b:
-    yield res
-    inc res
+  countupImpl:
+    inc(res)
 
 iterator `||`*[S, T](a: S, b: T, annotation=""): T {.
   inline, magic: "OmpParFor", sideEffect.} =
@@ -1598,7 +1638,7 @@ proc min*(x, y: int16): int16 {.magic: "MinI", noSideEffect.} =
   if x <= y: x else: y
 proc min*(x, y: int32): int32 {.magic: "MinI", noSideEffect.} =
   if x <= y: x else: y
-proc min*(x, y: int64): int64 {.magic: "MinI64", noSideEffect.} =
+proc min*(x, y: int64): int64 {.magic: "MinI", noSideEffect.} =
   ## The minimum value of two integers.
   if x <= y: x else: y
 
@@ -1616,7 +1656,7 @@ proc max*(x, y: int16): int16 {.magic: "MaxI", noSideEffect.} =
   if y <= x: x else: y
 proc max*(x, y: int32): int32 {.magic: "MaxI", noSideEffect.} =
   if y <= x: x else: y
-proc max*(x, y: int64): int64 {.magic: "MaxI64", noSideEffect.} =
+proc max*(x, y: int64): int64 {.magic: "MaxI", noSideEffect.} =
   ## The maximum value of two integers.
   if y <= x: x else: y
 
@@ -1651,6 +1691,13 @@ iterator items*[T](a: openArray[T]): T {.inline.} =
     yield a[i]
     inc(i)
 
+iterator mitems*[T](a: var openArray[T]): var T {.inline.} =
+  ## iterates over each item of `a` so that you can modify the yielded value.
+  var i = 0
+  while i < len(a):
+    yield a[i]
+    inc(i)
+
 iterator items*[IX, T](a: array[IX, T]): T {.inline.} =
   ## iterates over each item of `a`.
   var i = low(IX)
@@ -1660,16 +1707,23 @@ iterator items*[IX, T](a: array[IX, T]): T {.inline.} =
       if i >= high(IX): break
       inc(i)
 
+iterator mitems*[IX, T](a: var array[IX, T]): var T {.inline.} =
+  ## iterates over each item of `a` so that you can modify the yielded value.
+  var i = low(IX)
+  if i <= high(IX):
+    while true:
+      yield a[i]
+      if i >= high(IX): break
+      inc(i)
+
 iterator items*[T](a: set[T]): T {.inline.} =
   ## iterates over each element of `a`. `items` iterates only over the
   ## elements that are really in the set (and not over the ones the set is
   ## able to hold).
-  var i = low(T)
-  if i <= high(T):
-    while true:
-      if i in a: yield i
-      if i >= high(T): break
-      inc(i)
+  var i = low(T).int
+  while i <= high(T).int:
+    if T(i) in a: yield T(i)
+    inc(i)
 
 iterator items*(a: cstring): char {.inline.} =
   ## iterates over each item of `a`.
@@ -1678,11 +1732,24 @@ iterator items*(a: cstring): char {.inline.} =
     yield a[i]
     inc(i)
 
+iterator mitems*(a: var cstring): var char {.inline.} =
+  ## iterates over each item of `a` so that you can modify the yielded value.
+  var i = 0
+  while a[i] != '\0':
+    yield a[i]
+    inc(i)
+
 iterator items*(E: typedesc[enum]): E =
   ## iterates over the values of the enum ``E``.
   for v in low(E)..high(E):
     yield v
 
+iterator items*[T](s: Slice[T]): T =
+  ## iterates over the slice `s`, yielding each value between `s.a` and `s.b`
+  ## (inclusively).
+  for x in s.a..s.b:
+    yield x
+
 iterator pairs*[T](a: openArray[T]): tuple[key: int, val: T] {.inline.} =
   ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
   var i = 0
@@ -1690,6 +1757,14 @@ iterator pairs*[T](a: openArray[T]): tuple[key: int, val: T] {.inline.} =
     yield (i, a[i])
     inc(i)
 
+iterator mpairs*[T](a: var openArray[T]): tuple[key: int, val: var T] {.inline.} =
+  ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
+  ## ``a[index]`` can be modified.
+  var i = 0
+  while i < len(a):
+    yield (i, a[i])
+    inc(i)
+
 iterator pairs*[IX, T](a: array[IX, T]): tuple[key: IX, val: T] {.inline.} =
   ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
   var i = low(IX)
@@ -1699,6 +1774,16 @@ iterator pairs*[IX, T](a: array[IX, T]): tuple[key: IX, val: T] {.inline.} =
       if i >= high(IX): break
       inc(i)
 
+iterator mpairs*[IX, T](a: var array[IX, T]): tuple[key: IX, val: var T] {.inline.} =
+  ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
+  ## ``a[index]`` can be modified.
+  var i = low(IX)
+  if i <= high(IX):
+    while true:
+      yield (i, a[i])
+      if i >= high(IX): break
+      inc(i)
+
 iterator pairs*[T](a: seq[T]): tuple[key: int, val: T] {.inline.} =
   ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
   var i = 0
@@ -1706,6 +1791,14 @@ iterator pairs*[T](a: seq[T]): tuple[key: int, val: T] {.inline.} =
     yield (i, a[i])
     inc(i)
 
+iterator mpairs*[T](a: var seq[T]): tuple[key: int, val: var T] {.inline.} =
+  ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
+  ## ``a[index]`` can be modified.
+  var i = 0
+  while i < len(a):
+    yield (i, a[i])
+    inc(i)
+
 iterator pairs*(a: string): tuple[key: int, val: char] {.inline.} =
   ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
   var i = 0
@@ -1713,6 +1806,29 @@ iterator pairs*(a: string): tuple[key: int, val: char] {.inline.} =
     yield (i, a[i])
     inc(i)
 
+iterator mpairs*(a: var string): tuple[key: int, val: var char] {.inline.} =
+  ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
+  ## ``a[index]`` can be modified.
+  var i = 0
+  while i < len(a):
+    yield (i, a[i])
+    inc(i)
+
+iterator pairs*(a: cstring): tuple[key: int, val: char] {.inline.} =
+  ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
+  var i = 0
+  while a[i] != '\0':
+    yield (i, a[i])
+    inc(i)
+
+iterator mpairs*(a: var cstring): tuple[key: int, val: var char] {.inline.} =
+  ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
+  ## ``a[index]`` can be modified.
+  var i = 0
+  while a[i] != '\0':
+    yield (i, a[i])
+    inc(i)
+
 
 proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil".}
 proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".}
@@ -1730,7 +1846,7 @@ proc `==` *[I, T](x, y: array[I, T]): bool =
       return
   result = true
 
-proc `@`*[T](a: openArray[T]): seq[T] = 
+proc `@`*[T](a: openArray[T]): seq[T] =
   ## turns an openarray into a sequence. This is not as efficient as turning
   ## a fixed length array into a sequence as it always copies every element
   ## of `a`.
@@ -1778,7 +1894,7 @@ when not defined(NimrodVM):
   else:
     proc seqToPtr[T](x: seq[T]): pointer {.asmNoStackFrame, 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`.
@@ -1804,7 +1920,7 @@ proc contains*[T](a: openArray[T], item: T): bool {.inline.}=
   ## for ``find(a, item) >= 0``.
   return find(a, item) >= 0
 
-proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} = 
+proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} =
   ## returns the last item of `s` and decreases ``s.len`` by one. This treats
   ## `s` as a stack and implements the common *pop* operation.
   var L = s.len-1
@@ -1866,7 +1982,7 @@ iterator fields*[T: tuple|object](x: T): RootObj {.
 iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[a,b: expr] {.
   magic: "Fields", noSideEffect.}
   ## iterates over every field of `x` and `y`.
-  ## Warning: This is really transforms the 'for' and unrolls the loop. 
+  ## Warning: This is really transforms the 'for' and unrolls the loop.
   ## The current implementation also has a bug that affects symbol binding
   ## in the loop body.
 iterator fieldPairs*[T: tuple|object](x: T): RootObj {.
@@ -1907,18 +2023,18 @@ iterator fieldPairs*[S: tuple|object, T: tuple|object](x: S, y: T): tuple[
   a, b: expr] {.
   magic: "FieldPairs", noSideEffect.}
   ## iterates over every field of `x` and `y`.
-  ## Warning: This really transforms the 'for' and unrolls the loop. 
+  ## Warning: This really transforms the 'for' and unrolls the loop.
   ## The current implementation also has a bug that affects symbol binding
   ## in the loop body.
 
-proc `==`*[T: tuple|object](x, y: T): bool = 
+proc `==`*[T: tuple|object](x, y: T): bool =
   ## generic ``==`` operator for tuples that is lifted from the components
   ## of `x` and `y`.
   for a, b in fields(x, y):
     if a != b: return false
   return true
 
-proc `<=`*[T: tuple](x, y: T): bool = 
+proc `<=`*[T: tuple](x, y: T): bool =
   ## generic ``<=`` operator for tuples that is lifted from the components
   ## of `x` and `y`. This implementation uses `cmp`.
   for a, b in fields(x, y):
@@ -1927,7 +2043,7 @@ proc `<=`*[T: tuple](x, y: T): bool =
     if c > 0: return false
   return true
 
-proc `<`*[T: tuple](x, y: T): bool = 
+proc `<`*[T: tuple](x, y: T): bool =
   ## generic ``<`` operator for tuples that is lifted from the components
   ## of `x` and `y`. This implementation uses `cmp`.
   for a, b in fields(x, y):
@@ -1936,7 +2052,7 @@ proc `<`*[T: tuple](x, y: T): bool =
     if c > 0: return false
   return false
 
-proc `$`*[T: tuple|object](x: T): string = 
+proc `$`*[T: tuple|object](x: T): string =
   ## generic ``$`` operator for tuples that is lifted from the components
   ## of `x`. Example:
   ##
@@ -1946,13 +2062,13 @@ proc `$`*[T: tuple|object](x: T): string =
   result = "("
   var firstElement = true
   for name, value in fieldPairs(x):
-    if not(firstElement): result.add(", ")
+    if not firstElement: result.add(", ")
     result.add(name)
     result.add(": ")
     result.add($value)
     firstElement = false
   result.add(")")
-  
+
 proc collectionToString[T](x: T, b, e: string): string =
   result = b
   var firstElement = true
@@ -1962,7 +2078,7 @@ proc collectionToString[T](x: T, b, e: string): string =
     firstElement = false
   result.add(e)
 
-proc `$`*[T](x: set[T]): string = 
+proc `$`*[T](x: set[T]): string =
   ## generic ``$`` operator for sets that is lifted from the components
   ## of `x`. Example:
   ##
@@ -1970,7 +2086,7 @@ proc `$`*[T](x: set[T]): string =
   ##   ${23, 45} == "{23, 45}"
   collectionToString(x, "{", "}")
 
-proc `$`*[T](x: seq[T]): string = 
+proc `$`*[T](x: seq[T]): string =
   ## generic ``$`` operator for seqs that is lifted from the components
   ## of `x`. Example:
   ##
@@ -1981,7 +2097,7 @@ proc `$`*[T](x: seq[T]): string =
 when false:
   # causes bootstrapping to fail as we use array of chars and cstring should
   # match better ...
-  proc `$`*[T, IDX](x: array[IDX, T]): string = 
+  proc `$`*[T, IDX](x: array[IDX, T]): string =
     collectionToString(x, "[", "]")
 
 # ----------------- GC interface ---------------------------------------------
@@ -2023,18 +2139,17 @@ when not defined(nimrodVM) and hostOS != "standalone":
   proc GC_getStatistics*(): string {.rtl, benign.}
     ## returns an informative string about the GC's activity. This may be useful
     ## for tweaking.
-    
-  # XXX mark these as 'locks: 0' once 0.10.0 has been released
-  proc GC_ref*[T](x: ref T) {.magic: "GCref", gcsafe.}
-  proc GC_ref*[T](x: seq[T]) {.magic: "GCref", gcsafe.}
-  proc GC_ref*(x: string) {.magic: "GCref", gcsafe.}
+
+  proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
+  proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
+  proc GC_ref*(x: string) {.magic: "GCref", benign.}
     ## marks the object `x` as referenced, so that it will not be freed until
     ## it is unmarked via `GC_unref`. If called n-times for the same object `x`,
-    ## n calls to `GC_unref` are needed to unmark `x`. 
-    
-  proc GC_unref*[T](x: ref T) {.magic: "GCunref", gcsafe.}
-  proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", gcsafe.}
-  proc GC_unref*(x: string) {.magic: "GCunref", gcsafe.}
+    ## n calls to `GC_unref` are needed to unmark `x`.
+
+  proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.}
+  proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
+  proc GC_unref*(x: string) {.magic: "GCunref", benign.}
     ## see the documentation of `GC_ref`.
 
 template accumulateResult*(iter: expr) =
@@ -2067,19 +2182,19 @@ var
     ## application code should never set this hook! You better know what you
     ## do when setting this. If ``localRaiseHook`` returns false, the exception
     ## is caught and does not propagate further through the call stack.
-    
+
   outOfMemHook*: proc () {.nimcall, tags: [], benign.}
-    ## set this variable to provide a procedure that should be called 
+    ## set this variable to provide a procedure that should be called
     ## in case of an `out of memory`:idx: event. The standard handler
     ## writes an error message and terminates the program. `outOfMemHook` can
     ## be used to raise an exception in case of OOM like so:
-    ## 
+    ##
     ## .. code-block:: nim
     ##
     ##   var gOutOfMem: ref EOutOfMemory
     ##   new(gOutOfMem) # need to be allocated *before* OOM really happened!
     ##   gOutOfMem.msg = "out of memory"
-    ## 
+    ##
     ##   proc handleOOM() =
     ##     raise gOutOfMem
     ##
@@ -2120,7 +2235,8 @@ elif hostOS != "standalone":
       inc(i)
   {.pop.}
 
-proc echo*(x: varargs[expr, `$`]) {.magic: "Echo", tags: [WriteIOEffect], benign.}
+proc echo*(x: varargs[expr, `$`]) {.magic: "Echo", tags: [WriteIOEffect],
+  benign, sideEffect.}
   ## Writes and flushes the parameters to the standard output.
   ##
   ## Special built-in that takes a variable number of arguments. Each argument
@@ -2135,7 +2251,7 @@ proc echo*(x: varargs[expr, `$`]) {.magic: "Echo", tags: [WriteIOEffect], benign
   ## <manual.html#nosideeffect-pragma>`_ you can use `debugEcho <#debugEcho>`_
   ## instead.
 
-proc debugEcho*(x: varargs[expr, `$`]) {.magic: "Echo", noSideEffect, 
+proc debugEcho*(x: varargs[expr, `$`]) {.magic: "Echo", noSideEffect,
                                            tags: [], raises: [].}
   ## Same as `echo <#echo>`_, but as a special semantic rule, ``debugEcho``
   ## pretends to be free of side effects, so that it can be used for debugging
@@ -2173,14 +2289,9 @@ when not declared(sysFatal):
       e.msg = message & arg
       raise e
 
-when defined(nimlocks):
-  proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", gcsafe, locks: 0.}
-    ## get type information for `x`. Ordinary code should not use this, but
-    ## the `typeinfo` module instead.
-else:
-  proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", gcsafe.}
-    ## get type information for `x`. Ordinary code should not use this, but
-    ## the `typeinfo` module instead.
+proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", benign.}
+  ## get type information for `x`. Ordinary code should not use this, but
+  ## the `typeinfo` module instead.
 
 {.push stackTrace: off.}
 proc abs*(x: int): int {.magic: "AbsI", noSideEffect.} =
@@ -2192,7 +2303,7 @@ proc abs*(x: int16): int16 {.magic: "AbsI", noSideEffect.} =
 proc abs*(x: int32): int32 {.magic: "AbsI", noSideEffect.} =
   if x < 0: -x else: x
 proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.} =
-  ## returns the absolute value of `x`. If `x` is ``low(x)`` (that 
+  ## returns the absolute value of `x`. If `x` is ``low(x)`` (that
   ## is -MININT for its type), an overflow exception is thrown (if overflow
   ## checking is turned on).
   if x < 0: -x else: x
@@ -2248,14 +2359,14 @@ when not defined(JS): #and not defined(NimrodVM):
       # 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 ------------------------------------------------
   when hostOS != "standalone":
     type
-      CFile {.importc: "FILE", header: "<stdio.h>", 
+      CFile {.importc: "FILE", header: "<stdio.h>",
               final, incompletestruct.} = object
       File* = ptr CFile ## The type representing a file handle.
 
@@ -2305,9 +2416,9 @@ when not defined(JS): #and not defined(NimrodVM):
       ## Creates a ``TFile`` from a `filehandle` with given `mode`.
       ##
       ## Default mode is readonly. Returns true iff the file could be opened.
-      
+
     proc open*(filename: string,
-               mode: FileMode = fmRead, bufSize: int = -1): File = 
+               mode: FileMode = fmRead, bufSize: int = -1): File =
       ## Opens a file named `filename` with given `mode`.
       ##
       ## Default mode is readonly. Raises an ``IO`` exception if the file
@@ -2317,7 +2428,7 @@ when not defined(JS): #and not defined(NimrodVM):
 
     proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {.
       tags: [], benign.}
-      ## reopens the file `f` with given `filename` and `mode`. This 
+      ## reopens the file `f` with given `filename` and `mode`. This
       ## is often used to redirect the `stdin`, `stdout` or `stderr`
       ## file variables.
       ##
@@ -2328,7 +2439,7 @@ when not defined(JS): #and not defined(NimrodVM):
 
     proc endOfFile*(f: File): bool {.tags: [], benign.}
       ## Returns true iff `f` is at the end.
-      
+
     proc readChar*(f: File): char {.
       importc: "fgetc", header: "<stdio.h>", tags: [ReadIOEffect].}
       ## Reads a single character from the stream `f`.
@@ -2341,7 +2452,7 @@ when not defined(JS): #and not defined(NimrodVM):
       ##
       ## Raises an IO exception in case of an error. It is an error if the
       ## current file position is not at the beginning of the file.
-    
+
     proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.}
       ## Opens a file named `filename` for reading.
       ##
@@ -2370,8 +2481,8 @@ when not defined(JS): #and not defined(NimrodVM):
       ## reads a line of text from the file `f`. May throw an IO exception.
       ## A line of text may be delimited by ``CR``, ``LF`` or
       ## ``CRLF``. The newline character(s) are not part of the returned string.
-    
-    proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], 
+
+    proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect],
                   benign.}
       ## reads a line of text from the file `f` into `line`. `line` must not be
       ## ``nil``! May throw an IO exception.
@@ -2380,49 +2491,45 @@ when not defined(JS): #and not defined(NimrodVM):
       ## Returns ``false`` if the end of the file has been reached, ``true``
       ## otherwise. If ``false`` is returned `line` contains no new data.
 
-    when not defined(booting):
-      proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, 
-                               tags: [WriteIOEffect], gcsafe, locks: 0.}
-        ## writes the values `x` to `f` and then writes "\n".
-        ## May throw an IO exception.
-    else:
-      proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, 
-                               tags: [WriteIOEffect].}
+    proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
+                             tags: [WriteIOEffect], benign.}
+      ## writes the values `x` to `f` and then writes "\n".
+      ## May throw an IO exception.
 
     proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.}
       ## retrieves the file size (in bytes) of `f`.
 
-    proc readBytes*(f: File, a: var openArray[int8], start, len: int): int {.
+    proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: Natural): int {.
       tags: [ReadIOEffect], benign.}
       ## 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: File, a: var openArray[char], start, len: int): int {.
+    proc readChars*(f: File, a: var openArray[char], start, len: Natural): int {.
       tags: [ReadIOEffect], benign.}
       ## 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: File, buffer: pointer, len: int): int {.
+    proc readBuffer*(f: File, buffer: pointer, len: Natural): int {.
       tags: [ReadIOEffect], benign.}
       ## 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: File, a: openArray[int8], start, len: int): int {.
+    proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: Natural): int {.
       tags: [WriteIOEffect], benign.}
       ## 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: File, a: openArray[char], start, len: int): int {.
+    proc writeChars*(f: File, a: openArray[char], start, len: Natural): int {.
       tags: [WriteIOEffect], benign.}
       ## 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: File, buffer: pointer, len: int): int {.
+    proc writeBuffer*(f: File, buffer: pointer, len: Natural): int {.
       tags: [WriteIOEffect], benign.}
       ## 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
@@ -2444,7 +2551,7 @@ when not defined(JS): #and not defined(NimrodVM):
     when not defined(nimfix):
       {.deprecated: [fileHandle: getFileHandle].}
 
-    proc cstringArrayToSeq*(a: cstringArray, len: int): seq[string] =
+    proc cstringArrayToSeq*(a: cstringArray, len: Natural): seq[string] =
       ## converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be
       ## of length ``len``.
       newSeq(result, len)
@@ -2478,11 +2585,11 @@ when not defined(JS): #and not defined(NimrodVM):
       dealloc(a)
 
   when not defined(NimrodVM):
-    proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, 
+    proc atomicInc*(memLoc: var int, x: int = 1): int {.inline,
       discardable, benign.}
       ## atomic increment of `memLoc`. Returns the value after the operation.
-    
-    proc atomicDec*(memLoc: var int, x: int = 1): int {.inline, 
+
+    proc atomicDec*(memLoc: var int, x: int = 1): int {.inline,
       discardable, benign.}
       ## atomic decrement of `memLoc`. Returns the value after the operation.
 
@@ -2496,21 +2603,21 @@ when not defined(JS): #and not defined(NimrodVM):
       context: C_JmpBuf
       hasRaiseAction: bool
       raiseAction: proc (e: ref Exception): bool {.closure.}
-  
+
   when declared(initAllocator):
     initAllocator()
   when hasThreadSupport:
     include "system/syslocks"
-    include "system/threads"
+    when hostOS != "standalone": include "system/threads"
   elif not defined(nogc) and not defined(NimrodVM) and hostOS != "standalone":
     when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom()
     initGC()
 
   when not defined(NimrodVM):
-    proc setControlCHook*(hook: proc () {.noconv.})
+    proc setControlCHook*(hook: proc () {.noconv.} not nil)
       ## allows you to override the behaviour of your application when CTRL+C
       ## is pressed. Only one such hook is supported.
-      
+
     proc writeStackTrace*() {.tags: [WriteIOEffect].}
       ## writes the current stack trace to ``stderr``. This is only works
       ## for debug builds.
@@ -2521,20 +2628,20 @@ when not defined(JS): #and not defined(NimrodVM):
       proc getStackTrace*(e: ref Exception): string
         ## gets the stack trace associated with `e`, which is the stack that
         ## lead to the ``raise`` statement. This only works for debug builds.
-        
+
     {.push stack_trace: off, profiler:off.}
     when hostOS == "standalone":
       include "system/embedded"
     else:
       include "system/excpt"
     include "system/chcks"
-      
+
     # we cannot compile this with stack tracing on
     # as it would recurse endlessly!
     include "system/arithm"
     {.pop.} # stack trace
   {.pop.} # stack trace
-      
+
   when hostOS != "standalone" and not defined(NimrodVM):
     include "system/dyncalls"
   when not defined(NimrodVM):
@@ -2542,7 +2649,7 @@ when not defined(JS): #and not defined(NimrodVM):
 
     const
       GenericSeqSize = (2 * sizeof(int))
-      
+
     proc getDiscriminant(aa: pointer, n: ptr TNimNode): int =
       sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
       var d: int
@@ -2662,7 +2769,7 @@ when not defined(JS): #and not defined(NimrodVM):
       ##       process(value)
       ##     else:
       ##       echo "Value too big!"
-    
+
     proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
       ## Hints the optimizer that `val` is likely going to be false.
       ##
@@ -2676,7 +2783,7 @@ when not defined(JS): #and not defined(NimrodVM):
       ##       echo "Value too big!"
       ##     else:
       ##       process(value)
-      
+
     proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} =
       ## retrieves the raw proc pointer of the closure `x`. This is
       ## useful for interfacing closures with C.
@@ -2708,20 +2815,20 @@ elif defined(JS):
   proc GC_enableMarkAndSweep() = discard
   proc GC_disableMarkAndSweep() = discard
   proc GC_getStatistics(): string = return ""
-  
+
   proc getOccupiedMem(): int = return -1
   proc getFreeMem(): int = return -1
   proc getTotalMem(): int = return -1
 
   proc dealloc(p: pointer) = discard
-  proc alloc(size: int): pointer = discard
-  proc alloc0(size: int): pointer = discard
-  proc realloc(p: pointer, newsize: int): pointer = discard
+  proc alloc(size: Natural): pointer = discard
+  proc alloc0(size: Natural): pointer = discard
+  proc realloc(p: pointer, newsize: Natural): pointer = discard
 
-  proc allocShared(size: int): pointer = discard
-  proc allocShared0(size: int): pointer = discard
+  proc allocShared(size: Natural): pointer = discard
+  proc allocShared0(size: Natural): pointer = discard
   proc deallocShared(p: pointer) = discard
-  proc reallocShared(p: pointer, newsize: int): pointer = discard
+  proc reallocShared(p: pointer, newsize: Natural): pointer = discard
 
   when defined(JS):
     include "system/jssys"
@@ -2731,7 +2838,7 @@ elif defined(JS):
       if x == y: return 0
       if x < y: return -1
       return 1
-  
+
   when defined(nimffi):
     include "system/sysio"
 
@@ -2765,32 +2872,31 @@ template spliceImpl(s, a, L, b: expr): stmt {.immediate.} =
     # cut down:
     setLen(s, newLen)
   # fill the hole:
-  for i in 0 .. <b.len: s[i+a] = b[i]  
+  for i in 0 .. <b.len: s[i+a] = b[i]
 
 when hostOS != "standalone":
   proc `[]`*(s: string, x: Slice[int]): string {.inline.} =
-    ## slice operation for strings. Negative indexes are supported.
-    result = s.substr(x.a-|s, x.b-|s)
+    ## slice operation for strings.
+    result = s.substr(x.a, x.b)
 
-  proc `[]=`*(s: var string, x: Slice[int], b: string) = 
-    ## slice assignment for strings. Negative indexes are supported. If
+  proc `[]=`*(s: var string, x: Slice[int], b: string) =
+    ## slice assignment for strings. If
     ## ``b.len`` is not exactly the number of elements that are referred to
     ## by `x`, a `splice`:idx: is performed:
     ##
     ## .. code-block:: nim
     ##   var s = "abcdef"
-    ##   s[1 .. -2] = "xyz"
+    ##   s[1 .. ^2] = "xyz"
     ##   assert s == "axyzf"
-    var a = x.a-|s
-    var L = x.b-|s - a + 1
+    var a = x.a
+    var L = x.b - a + 1
     if L == b.len:
       for i in 0 .. <L: s[i+a] = b[i]
     else:
       spliceImpl(s, a, L, b)
 
 proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[int]): seq[T] =
-  ## slice operation for arrays. Negative indexes are **not** supported
-  ## because the array might have negative bounds.
+  ## slice operation for arrays.
   when low(a) < 0:
     {.error: "Slicing for arrays with negative indices is unsupported.".}
   var L = x.b - x.a + 1
@@ -2798,8 +2904,7 @@ proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[int]): seq[T] =
   for i in 0.. <L: result[i] = a[i + x.a]
 
 proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[int], b: openArray[T]) =
-  ## slice assignment for arrays. Negative indexes are **not** supported
-  ## because the array might have negative bounds.
+  ## slice assignment for arrays.
   when low(a) < 0:
     {.error: "Slicing for arrays with negative indices is unsupported.".}
   var L = x.b - x.a + 1
@@ -2809,40 +2914,34 @@ proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[int], b: openArray[T]) =
     sysFatal(RangeError, "different lengths for slice assignment")
 
 proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[Idx]): seq[T] =
-  ## slice operation for arrays. Negative indexes are **not** supported
-  ## because the array might have negative bounds.
+  ## slice operation for arrays.
   var L = ord(x.b) - ord(x.a) + 1
   newSeq(result, L)
-  var j = x.a
-  for i in 0.. <L: 
-    result[i] = a[j]
-    inc(j)
+  for i in 0.. <L:
+    result[i] = a[Idx(ord(x.a) + i)]
 
 proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[Idx], b: openArray[T]) =
-  ## slice assignment for arrays. Negative indexes are **not** supported
-  ## because the array might have negative bounds.
+  ## slice assignment for arrays.
   var L = ord(x.b) - ord(x.a) + 1
   if L == b.len:
-    var j = x.a
-    for i in 0 .. <L: 
-      a[j] = b[i]
-      inc(j)
+    for i in 0 .. <L:
+      a[Idx(ord(x.a) + i)] = b[i]
   else:
     sysFatal(RangeError, "different lengths for slice assignment")
 
-proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] = 
-  ## slice operation for sequences. Negative indexes are supported.
-  var a = x.a-|s
-  var L = x.b-|s - a + 1
+proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] =
+  ## slice operation for sequences.
+  var a = x.a
+  var L = x.b - a + 1
   newSeq(result, L)
   for i in 0.. <L: result[i] = s[i + a]
 
-proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) = 
-  ## slice assignment for sequences. Negative indexes are supported. If
+proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) =
+  ## slice assignment for sequences. If
   ## ``b.len`` is not exactly the number of elements that are referred to
-  ## by `x`, a `splice`:idx: is performed. 
-  var a = x.a-|s
-  var L = x.b-|s - a + 1
+  ## by `x`, a `splice`:idx: is performed.
+  var a = x.a
+  var L = x.b - a + 1
   if L == b.len:
     for i in 0 .. <L: s[i+a] = b[i]
   else:
@@ -2871,7 +2970,7 @@ proc staticExec*(command: string, input = ""): string {.
   ## to the executed program.
   ##
   ## .. code-block:: nim
-  ##     const buildInfo = "Revision " & staticExec("git rev-parse HEAD") & 
+  ##     const buildInfo = "Revision " & staticExec("git rev-parse HEAD") &
   ##                       "\nCompiled on " & staticExec("uname -v")
   ##
   ## `gorge <#gorge>`_ is an alias for ``staticExec``. Note that you can use
@@ -2913,7 +3012,7 @@ proc `&=`* (x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.}
 proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.}
   ## converts the AST of `x` into a string representation. This is very useful
   ## for debugging.
-  
+
 proc instantiationInfo*(index = -1, fullPaths = false): tuple[
   filename: string, line: int] {. magic: "InstantiationInfo", noSideEffect.}
   ## provides access to the compiler's instantiation stack line information.
@@ -2941,8 +3040,8 @@ proc instantiationInfo*(index = -1, fullPaths = false): tuple[
   ##     result = a[pos]
   ##
   ##   when isMainModule:
-  ##     testException(EInvalidIndex, tester(30))
-  ##     testException(EInvalidIndex, tester(1))
+  ##     testException(IndexError, tester(30))
+  ##     testException(IndexError, tester(1))
   ##     # --> Test failure at example.nim:20 with 'tester(1)'
 
 template currentSourcePath*: string = instantiationInfo(-1, true).filename
@@ -2951,13 +3050,12 @@ template currentSourcePath*: string = instantiationInfo(-1, true).filename
 proc raiseAssert*(msg: string) {.noinline.} =
   sysFatal(AssertionError, msg)
 
-when true:
-  proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
-    # trick the compiler to not list ``EAssertionFailed`` when called
-    # by ``assert``.
-    type THide = proc (msg: string) {.noinline, raises: [], noSideEffect,
-                                      tags: [].}
-    THide(raiseAssert)(msg)
+proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
+  # trick the compiler to not list ``AssertionError`` when called
+  # by ``assert``.
+  type THide = proc (msg: string) {.noinline, raises: [], noSideEffect,
+                                    tags: [].}
+  THide(raiseAssert)(msg)
 
 template assert*(cond: bool, msg = "") =
   ## Raises ``AssertionError`` with `msg` if `cond` is false. Note
@@ -2990,6 +3088,15 @@ iterator items*[T](a: seq[T]): T {.inline.} =
     inc(i)
     assert(len(a) == L, "seq modified while iterating over it")
 
+iterator mitems*[T](a: var seq[T]): var T {.inline.} =
+  ## iterates over each item of `a` so that you can modify the yielded value.
+  var i = 0
+  let L = len(a)
+  while i < L:
+    yield a[i]
+    inc(i)
+    assert(len(a) == L, "seq modified while iterating over it")
+
 iterator items*(a: string): char {.inline.} =
   ## iterates over each item of `a`.
   var i = 0
@@ -2999,35 +3106,38 @@ iterator items*(a: string): char {.inline.} =
     inc(i)
     assert(len(a) == L, "string modified while iterating over it")
 
+iterator mitems*(a: var string): var char {.inline.} =
+  ## iterates over each item of `a` so that you can modify the yielded value.
+  var i = 0
+  let L = len(a)
+  while i < L:
+    yield a[i]
+    inc(i)
+    assert(len(a) == L, "string modified while iterating over it")
+
 when not defined(nimhygiene):
   {.pragma: inject.}
 
 template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} =
   ## Sets an assertion failure handler that will intercept any assert
-  ## statements following `onFailedAssert` in the current lexical scope.
-  ## Can be defined multiple times in a single function.
-  ##  
-  ## .. code-block:: nim
+  ## statements following `onFailedAssert` in the current module scope.
   ##
-  ##   proc example(x: int): TErrorCode =
-  ##     onFailedAssert(msg):
-  ##       log msg
-  ##       return E_FAIL
-  ## 
-  ##     assert(...)
-  ##     
-  ##     onFailedAssert(msg):
-  ##       raise newException(EMyException, msg)
-  ##
-  ##     assert(...)
+  ## .. code-block:: nim
+  ##  # module-wide policy to change the failed assert
+  ##  # exception type in order to include a lineinfo
+  ##  onFailedAssert(msg):
+  ##    var e = new(TMyError)
+  ##    e.msg = msg
+  ##    e.lineinfo = instantiationInfo(-2)
+  ##    raise e
   ##
-  template failedAssertImpl(msgIMPL: string): stmt {.dirty, immediate.} =
+  template failedAssertImpl(msgIMPL: string): stmt {.dirty.} =
     let msg = msgIMPL
     code
 
 proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
   ## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not
-  ## perform deep copies of `s`. This is only useful for optimization 
+  ## perform deep copies of `s`. This is only useful for optimization
   ## purposes.
   when not defined(JS) and not defined(NimrodVM):
     var s = cast[PGenericSeq](s)
@@ -3035,27 +3145,29 @@ proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
 
 proc shallow*(s: var string) {.noSideEffect, inline.} =
   ## marks a string `s` as `shallow`:idx:. Subsequent assignments will not
-  ## perform deep copies of `s`. This is only useful for optimization 
+  ## perform deep copies of `s`. This is only useful for optimization
   ## purposes.
   when not defined(JS) and not defined(NimrodVM):
     var s = cast[PGenericSeq](s)
     s.reserved = s.reserved or seqShallowFlag
 
 type
-  TNimrodNode {.final.} = object
-  PNimrodNode* {.magic: "PNimrodNode".} = ref TNimrodNode
+  NimNodeObj = object
+
+  NimNode* {.magic: "PNimrodNode".} = ref NimNodeObj
     ## represents a Nim AST node. Macros operate on this type.
+{.deprecated: [PNimrodNode: NimNode].}
 
 when false:
   template eval*(blk: stmt): stmt =
     ## executes a block of code at compile time just as if it was a macro
-    ## optionally, the block can return an AST tree that will replace the 
+    ## optionally, the block can return an AST tree that will replace the
     ## eval expression
     macro payload: stmt {.gensym.} = blk
     payload()
 
 when hostOS != "standalone":
-  proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} = 
+  proc insert*(x: var string, item: string, i = 0.Natural) {.noSideEffect.} =
     ## inserts `item` into `x` at position `i`.
     var xl = x.len
     setLen(x, xl+item.len)
@@ -3068,7 +3180,7 @@ when hostOS != "standalone":
       x[j+i] = item[j]
       inc(j)
 
-proc compiles*(x): bool {.magic: "Compiles", noSideEffect.} =
+proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect.} =
   ## Special compile-time procedure that checks whether `x` can be compiled
   ## without any semantic error.
   ## This can be used to check whether a type supports some operation:
@@ -3095,7 +3207,7 @@ when hostOS != "standalone":
     if x == nil: x = y
     else: x.add(y)
 
-proc locals*(): RootObj {.magic: "Locals", noSideEffect.} =
+proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} =
   ## generates a tuple constructor expression listing all the local variables
   ## in the current scope. This is quite fast as it does not rely
   ## on any debug or runtime information. Note that in constrast to what
@@ -3136,4 +3248,28 @@ proc procCall*(x: expr) {.magic: "ProcCall".} =
   ##   procCall someMethod(a, b)
   discard
 
+proc `^`*(x: int): int {.noSideEffect, magic: "Roof".} =
+  ## builtin `roof`:idx: operator that can be used for convenient array access.
+  ## ``a[^x]`` is rewritten to ``a[a.len-x]``. However currently the ``a``
+  ## expression must not have side effects for this to compile. Note that since
+  ## this is a builtin, it automatically works for all kinds of
+  ## overloaded ``[]`` or ``[]=`` accessors.
+  discard
+
+template `..^`*(a, b: expr): expr =
+  ## a shortcut for '.. ^' to avoid the common gotcha that a space between
+  ## '..' and '^' is required.
+  a .. ^b
+
+template `..<`*(a, b: expr): expr =
+  ## a shortcut for '.. <' to avoid the common gotcha that a space between
+  ## '..' and '<' is required.
+  a .. <b
+
+proc xlen*(x: string): int {.magic: "XLenStr", noSideEffect.} = discard
+proc xlen*[T](x: seq[T]): int {.magic: "XLenSeq", noSideEffect.} =
+  ## returns the length of a sequence or a string without testing for 'nil'.
+  ## This is an optimization that rarely makes sense.
+  discard
+
 {.pop.} #{.push warning[GcMem]: off.}
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index fd3ced832..ad3419808 100644
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -8,7 +8,7 @@
 #
 
 # Low level allocator for Nim. Has been designed to support the GC.
-# TODO: 
+# TODO:
 # - eliminate "used" field
 # - make searching for block O(1)
 {.push profiler:off.}
@@ -21,37 +21,37 @@
 # used with a size of 0:
 const weirdUnmap = not (defined(amd64) or defined(i386)) or defined(windows)
 
-when defined(posix): 
+when defined(posix):
   const
-    PROT_READ  = 1             # page can be read 
-    PROT_WRITE = 2             # page can be written 
-    MAP_PRIVATE = 2'i32        # Changes are private 
-  
+    PROT_READ  = 1             # page can be read
+    PROT_WRITE = 2             # page can be written
+    MAP_PRIVATE = 2'i32        # Changes are private
+
   when defined(macosx) or defined(bsd):
     const MAP_ANONYMOUS = 0x1000
-  elif defined(solaris): 
+  elif defined(solaris):
     const MAP_ANONYMOUS = 0x100
   else:
     var
       MAP_ANONYMOUS {.importc: "MAP_ANONYMOUS", header: "<sys/mman.h>".}: cint
-    
+
   proc mmap(adr: pointer, len: int, prot, flags, fildes: cint,
             off: int): pointer {.header: "<sys/mman.h>".}
 
   proc munmap(adr: pointer, len: int) {.header: "<sys/mman.h>".}
-  
-  proc osAllocPages(size: int): pointer {.inline.} = 
-    result = mmap(nil, size, PROT_READ or PROT_WRITE, 
+
+  proc osAllocPages(size: int): pointer {.inline.} =
+    result = mmap(nil, size, PROT_READ or PROT_WRITE,
                              MAP_PRIVATE or MAP_ANONYMOUS, -1, 0)
     if result == nil or result == cast[pointer](-1):
       raiseOutOfMem()
-      
+
   proc osDeallocPages(p: pointer, size: int) {.inline} =
     when reallyOsDealloc: munmap(p, size)
-  
-elif defined(windows): 
+
+elif defined(windows):
   const
-    MEM_RESERVE = 0x2000 
+    MEM_RESERVE = 0x2000
     MEM_COMMIT = 0x1000
     MEM_TOP_DOWN = 0x100000
     PAGE_READWRITE = 0x04
@@ -62,12 +62,12 @@ elif defined(windows):
   proc virtualAlloc(lpAddress: pointer, dwSize: int, flAllocationType,
                     flProtect: int32): pointer {.
                     header: "<windows.h>", stdcall, importc: "VirtualAlloc".}
-  
-  proc virtualFree(lpAddress: pointer, dwSize: int, 
+
+  proc virtualFree(lpAddress: pointer, dwSize: int,
                    dwFreeType: int32) {.header: "<windows.h>", stdcall,
                    importc: "VirtualFree".}
-  
-  proc osAllocPages(size: int): pointer {.inline.} = 
+
+  proc osAllocPages(size: int): pointer {.inline.} =
     result = virtualAlloc(nil, size, MEM_RESERVE or MEM_COMMIT,
                           PAGE_READWRITE)
     if result == nil: raiseOutOfMem()
@@ -82,7 +82,7 @@ elif defined(windows):
     when reallyOsDealloc: virtualFree(p, 0, MEM_RELEASE)
     #VirtualFree(p, size, MEM_DECOMMIT)
 
-else: 
+else:
   {.error: "Port memory manager to your platform".}
 
 # --------------------- end of non-portable code -----------------------------
@@ -97,17 +97,17 @@ const
   InitialMemoryRequest = ChunkOsReturn div 2 # < ChunkOsReturn!
   SmallChunkSize = PageSize
 
-type 
+type
   PTrunk = ptr TTrunk
-  TTrunk {.final.} = object 
+  TTrunk {.final.} = object
     next: PTrunk         # all nodes are connected with this pointer
     key: int             # start address at bit 0
     bits: array[0..IntsPerTrunk-1, int] # a bit vector
-  
+
   TTrunkBuckets = array[0..255, PTrunk]
-  TIntSet {.final.} = object 
+  TIntSet {.final.} = object
     data: TTrunkBuckets
-  
+
 type
   TAlignType = BiggestFloat
   TFreeCell {.final, pure.} = object
@@ -123,14 +123,14 @@ type
     prevSize: int        # size of previous chunk; for coalescing
     size: int            # if < PageSize it is a small chunk
     used: bool           # later will be optimized into prevSize...
-  
+
   TSmallChunk = object of TBaseChunk
     next, prev: PSmallChunk  # chunks of the same size
     freeList: ptr TFreeCell
-    free: int            # how many bytes remain    
+    free: int            # how many bytes remain
     acc: int             # accumulator for small object allocation
     data: TAlignType     # start of usable memory
-  
+
   TBigChunk = object of TBaseChunk # not necessarily > PageSize!
     next, prev: PBigChunk    # chunks of the same (or bigger) size
     align: int
@@ -139,7 +139,7 @@ type
 template smallChunkOverhead(): expr = sizeof(TSmallChunk)-sizeof(TAlignType)
 template bigChunkOverhead(): expr = sizeof(TBigChunk)-sizeof(TAlignType)
 
-proc roundup(x, v: int): int {.inline.} = 
+proc roundup(x, v: int): int {.inline.} =
   result = (x + (v-1)) and not (v-1)
   sysAssert(result >= x, "roundup: result < x")
   #return ((-x) and (v-1)) +% x
@@ -153,7 +153,7 @@ sysAssert(roundup(65, 8) == 72, "roundup broken 2")
 # endings of big chunks. This is needed by the merging operation. The only
 # remaining operation is best-fit for big chunks. Since there is a size-limit
 # for big chunks (because greater than the limit means they are returned back
-# to the OS), a fixed size array can be used. 
+# to the OS), a fixed size array can be used.
 
 type
   PLLChunk = ptr TLLChunk
@@ -163,21 +163,21 @@ type
     next: PLLChunk           # next low-level chunk; only needed for dealloc
 
   PAvlNode = ptr TAvlNode
-  TAvlNode {.pure, final.} = object 
-    link: array[0..1, PAvlNode] # Left (0) and right (1) links 
+  TAvlNode {.pure, final.} = object
+    link: array[0..1, PAvlNode] # Left (0) and right (1) links
     key, upperBound: int
     level: int
-    
+
   TMemRegion {.final, pure.} = object
     minLargeObj, maxLargeObj: int
     freeSmallChunks: array[0..SmallChunkSize div MemAlign-1, PSmallChunk]
     llmem: PLLChunk
     currMem, maxMem, freeMem: int # memory sizes (allocated from OS)
-    lastSize: int # needed for the case that OS gives us pages linearly 
+    lastSize: int # needed for the case that OS gives us pages linearly
     freeChunksList: PBigChunk # XXX make this a datastructure with O(1) access
     chunkStarts: TIntSet
     root, deleted, last, freeAvlNodes: PAvlNode
-  
+
 # shared:
 var
   bottomData: TAvlNode
@@ -191,7 +191,7 @@ proc initAllocator() =
     bottom.link[1] = bottom
 {.pop.}
 
-proc incCurrMem(a: var TMemRegion, bytes: int) {.inline.} = 
+proc incCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
   inc(a.currMem, bytes)
 
 proc decCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
@@ -199,11 +199,11 @@ proc decCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
   dec(a.currMem, bytes)
 
 proc getMaxMem(a: var TMemRegion): int =
-  # Since we update maxPagesCount only when freeing pages, 
+  # Since we update maxPagesCount only when freeing pages,
   # maxPagesCount may not be up to date. Thus we use the
   # maximum of these both values here:
   result = max(a.currMem, a.maxMem)
-  
+
 proc llAlloc(a: var TMemRegion, size: int): pointer =
   # *low-level* alloc for the memory managers data structures. Deallocation
   # is done at he end of the allocator's life time.
@@ -251,15 +251,15 @@ proc llDeallocAll(a: var TMemRegion) =
     var next = it.next
     osDeallocPages(it, PageSize)
     it = next
-  
-proc intSetGet(t: TIntSet, key: int): PTrunk = 
+
+proc intSetGet(t: TIntSet, key: int): PTrunk =
   var it = t.data[key and high(t.data)]
-  while it != nil: 
+  while it != nil:
     if it.key == key: return it
     it = it.next
   result = nil
 
-proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk = 
+proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk =
   result = intSetGet(t, key)
   if result == nil:
     result = cast[PTrunk](llAlloc(a, sizeof(result[])))
@@ -267,20 +267,20 @@ proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk =
     t.data[key and high(t.data)] = result
     result.key = key
 
-proc contains(s: TIntSet, key: int): bool = 
+proc contains(s: TIntSet, key: int): bool =
   var t = intSetGet(s, key shr TrunkShift)
-  if t != nil: 
+  if t != nil:
     var u = key and TrunkMask
     result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
-  else: 
+  else:
     result = false
-  
-proc incl(a: var TMemRegion, s: var TIntSet, key: int) = 
+
+proc incl(a: var TMemRegion, s: var TIntSet, key: int) =
   var t = intSetPut(a, s, key shr TrunkShift)
   var u = key and TrunkMask
   t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask))
 
-proc excl(s: var TIntSet, key: int) = 
+proc excl(s: var TIntSet, key: int) =
   var t = intSetGet(s, key shr TrunkShift)
   if t != nil:
     var u = key and TrunkMask
@@ -304,11 +304,11 @@ iterator elements(t: TIntSet): int {.inline.} =
           w = w shr 1
         inc(i)
       r = r.next
-  
-proc isSmallChunk(c: PChunk): bool {.inline.} = 
+
+proc isSmallChunk(c: PChunk): bool {.inline.} =
   return c.size <= SmallChunkSize-smallChunkOverhead()
-  
-proc chunkUnused(c: PChunk): bool {.inline.} = 
+
+proc chunkUnused(c: PChunk): bool {.inline.} =
   result = not c.used
 
 iterator allObjects(m: TMemRegion): pointer {.inline.} =
@@ -319,7 +319,7 @@ iterator allObjects(m: TMemRegion): pointer {.inline.} =
       if not chunkUnused(c):
         if isSmallChunk(c):
           var c = cast[PSmallChunk](c)
-          
+
           let size = c.size
           var a = cast[ByteAddress](addr(c.data))
           let limit = a + c.acc
@@ -334,17 +334,17 @@ proc isCell(p: pointer): bool {.inline.} =
   result = cast[ptr TFreeCell](p).zeroField >% 1
 
 # ------------- chunk management ----------------------------------------------
-proc pageIndex(c: PChunk): int {.inline.} = 
+proc pageIndex(c: PChunk): int {.inline.} =
   result = cast[ByteAddress](c) shr PageShift
 
-proc pageIndex(p: pointer): int {.inline.} = 
+proc pageIndex(p: pointer): int {.inline.} =
   result = cast[ByteAddress](p) shr PageShift
 
-proc pageAddr(p: pointer): PChunk {.inline.} = 
+proc pageAddr(p: pointer): PChunk {.inline.} =
   result = cast[PChunk](cast[ByteAddress](p) and not PageMask)
   #sysAssert(Contains(allocator.chunkStarts, pageIndex(result)))
 
-proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk = 
+proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk =
   incCurrMem(a, size)
   inc(a.freeMem, size)
   result = cast[PBigChunk](osAllocPages(size))
@@ -373,7 +373,7 @@ proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk =
     result.prevSize = 0 # unknown
   a.lastSize = size # for next request
 
-proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) = 
+proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) =
   # update next.prevSize:
   var c = cast[PChunk](p)
   var nxt = cast[ByteAddress](p) +% c.size
@@ -387,36 +387,36 @@ proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) =
   dec(a.freeMem, size)
   #c_fprintf(c_stdout, "[Alloc] back to OS: %ld\n", size)
 
-proc isAccessible(a: TMemRegion, p: pointer): bool {.inline.} = 
+proc isAccessible(a: TMemRegion, p: pointer): bool {.inline.} =
   result = contains(a.chunkStarts, pageIndex(p))
 
-proc contains[T](list, x: T): bool = 
+proc contains[T](list, x: T): bool =
   var it = list
   while it != nil:
     if it == x: return true
     it = it.next
-    
+
 proc writeFreeList(a: TMemRegion) =
   var it = a.freeChunksList
   c_fprintf(c_stdout, "freeChunksList: %p\n", it)
-  while it != nil: 
-    c_fprintf(c_stdout, "it: %p, next: %p, prev: %p\n", 
+  while it != nil:
+    c_fprintf(c_stdout, "it: %p, next: %p, prev: %p\n",
               it, it.next, it.prev)
     it = it.next
 
-proc listAdd[T](head: var T, c: T) {.inline.} = 
+proc listAdd[T](head: var T, c: T) {.inline.} =
   sysAssert(c notin head, "listAdd 1")
   sysAssert c.prev == nil, "listAdd 2"
   sysAssert c.next == nil, "listAdd 3"
   c.next = head
-  if head != nil: 
+  if head != nil:
     sysAssert head.prev == nil, "listAdd 4"
     head.prev = c
   head = c
 
 proc listRemove[T](head: var T, c: T) {.inline.} =
   sysAssert(c in head, "listRemove")
-  if c == head: 
+  if c == head:
     head = c.next
     sysAssert c.prev == nil, "listRemove 2"
     if head != nil: head.prev = nil
@@ -426,15 +426,15 @@ proc listRemove[T](head: var T, c: T) {.inline.} =
     if c.next != nil: c.next.prev = c.prev
   c.next = nil
   c.prev = nil
-  
-proc updatePrevSize(a: var TMemRegion, c: PBigChunk, 
-                    prevSize: int) {.inline.} = 
+
+proc updatePrevSize(a: var TMemRegion, c: PBigChunk,
+                    prevSize: int) {.inline.} =
   var ri = cast[PChunk](cast[ByteAddress](c) +% c.size)
   sysAssert((cast[ByteAddress](ri) and PageMask) == 0, "updatePrevSize")
   if isAccessible(a, ri):
     ri.prevSize = prevSize
-  
-proc freeBigChunk(a: var TMemRegion, c: PBigChunk) = 
+
+proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
   var c = c
   sysAssert(c.size >= PageSize, "freeBigChunk")
   inc(a.freeMem, c.size)
@@ -448,7 +448,7 @@ proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
         inc(c.size, ri.size)
         excl(a.chunkStarts, pageIndex(ri))
   when coalescLeft:
-    if c.prevSize != 0: 
+    if c.prevSize != 0:
       var le = cast[PChunk](cast[ByteAddress](c) -% c.prevSize)
       sysAssert((cast[ByteAddress](le) and PageMask) == 0, "freeBigChunk 4")
       if isAccessible(a, le) and chunkUnused(le):
@@ -467,7 +467,7 @@ proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
   else:
     freeOsChunks(a, c, c.size)
 
-proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) = 
+proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) =
   var rest = cast[PBigChunk](cast[ByteAddress](c) +% size)
   sysAssert(rest notin a.freeChunksList, "splitChunk")
   rest.size = c.size - size
@@ -480,7 +480,7 @@ proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) =
   incl(a, a.chunkStarts, pageIndex(rest))
   listAdd(a.freeChunksList, rest)
 
-proc getBigChunk(a: var TMemRegion, size: int): PBigChunk = 
+proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
   # use first fit for now:
   sysAssert((size and PageMask) == 0, "getBigChunk 1")
   sysAssert(size > 0, "getBigChunk 2")
@@ -488,7 +488,7 @@ proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
   block search:
     while result != nil:
       sysAssert chunkUnused(result), "getBigChunk 3"
-      if result.size == size: 
+      if result.size == size:
         listRemove(a.freeChunksList, result)
         break search
       elif result.size > size:
@@ -497,7 +497,7 @@ proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
         break search
       result = result.next
       sysAssert result != a.freeChunksList, "getBigChunk 4"
-    if size < InitialMemoryRequest: 
+    if size < InitialMemoryRequest:
       result = requestOsChunks(a, InitialMemoryRequest)
       splitChunk(a, result, size)
     else:
@@ -507,7 +507,7 @@ proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
   incl(a, a.chunkStarts, pageIndex(result))
   dec(a.freeMem, size)
 
-proc getSmallChunk(a: var TMemRegion): PSmallChunk = 
+proc getSmallChunk(a: var TMemRegion): PSmallChunk =
   var res = getBigChunk(a, PageSize)
   sysAssert res.prev == nil, "getSmallChunk 1"
   sysAssert res.next == nil, "getSmallChunk 2"
@@ -521,15 +521,15 @@ proc allocInv(a: TMemRegion): bool =
   for s in low(a.freeSmallChunks)..high(a.freeSmallChunks):
     var c = a.freeSmallChunks[s]
     while c != nil:
-      if c.next == c: 
+      if c.next == c:
         echo "[SYSASSERT] c.next == c"
         return false
-      if c.size != s * MemAlign: 
+      if c.size != s * MemAlign:
         echo "[SYSASSERT] c.size != s * MemAlign"
         return false
       var it = c.freeList
       while it != nil:
-        if it.zeroField != 0: 
+        if it.zeroField != 0:
           echo "[SYSASSERT] it.zeroField != 0"
           c_printf("%ld %p\n", it.zeroField, it)
           return false
@@ -539,16 +539,16 @@ proc allocInv(a: TMemRegion): bool =
 
 proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
   sysAssert(allocInv(a), "rawAlloc: begin")
-  sysAssert(roundup(65, 8) == 72, "rawAlloc 1")
-  sysAssert requestedSize >= sizeof(TFreeCell), "rawAlloc 2"
+  sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken")
+  sysAssert(requestedSize >= sizeof(TFreeCell), "rawAlloc: requested size too small")
   var size = roundup(requestedSize, MemAlign)
   sysAssert(size >= requestedSize, "insufficient allocated size!")
   #c_fprintf(c_stdout, "alloc; size: %ld; %ld\n", requestedSize, size)
-  if size <= SmallChunkSize-smallChunkOverhead(): 
+  if size <= SmallChunkSize-smallChunkOverhead():
     # allocate a small block: for small chunks, we use only its next pointer
     var s = size div MemAlign
     var c = a.freeSmallChunks[s]
-    if c == nil: 
+    if c == nil:
       c = getSmallChunk(a)
       c.freeList = nil
       sysAssert c.size == PageSize, "rawAlloc 3"
@@ -567,7 +567,7 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
       #  c_fprintf(c_stdout, "csize: %lld; size %lld\n", c.size, size)
       sysAssert c.size == size, "rawAlloc 6"
       if c.freeList == nil:
-        sysAssert(c.acc + smallChunkOverhead() + size <= SmallChunkSize, 
+        sysAssert(c.acc + smallChunkOverhead() + size <= SmallChunkSize,
                   "rawAlloc 7")
         result = cast[pointer](cast[ByteAddress](addr(c.data)) +% c.acc)
         inc(c.acc, size)
@@ -621,9 +621,9 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
     f.zeroField = 0
     f.next = c.freeList
     c.freeList = f
-    when overwriteFree: 
+    when overwriteFree:
       # set to 0xff to check for usage after free bugs:
-      c_memset(cast[pointer](cast[int](p) +% sizeof(TFreeCell)), -1'i32, 
+      c_memset(cast[pointer](cast[int](p) +% sizeof(TFreeCell)), -1'i32,
                s -% sizeof(TFreeCell))
     # check if it is not in the freeSmallChunks[s] list:
     if c.free < s:
@@ -649,13 +649,13 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
   sysAssert(allocInv(a), "rawDealloc: end")
   when logAlloc: cprintf("rawDealloc: %p\n", p)
 
-proc isAllocatedPtr(a: TMemRegion, p: pointer): bool = 
+proc isAllocatedPtr(a: TMemRegion, p: pointer): bool =
   if isAccessible(a, p):
     var c = pageAddr(p)
     if not chunkUnused(c):
       if isSmallChunk(c):
         var c = cast[PSmallChunk](c)
-        var offset = (cast[ByteAddress](p) and (PageSize-1)) -% 
+        var offset = (cast[ByteAddress](p) and (PageSize-1)) -%
                      smallChunkOverhead()
         result = (c.acc >% offset) and (offset %% c.size == 0) and
           (cast[ptr TFreeCell](p).zeroField >% 1)
@@ -673,12 +673,12 @@ proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer =
     if not chunkUnused(c):
       if isSmallChunk(c):
         var c = cast[PSmallChunk](c)
-        var offset = (cast[ByteAddress](p) and (PageSize-1)) -% 
+        var offset = (cast[ByteAddress](p) and (PageSize-1)) -%
                      smallChunkOverhead()
         if c.acc >% offset:
           sysAssert(cast[ByteAddress](addr(c.data)) +% offset ==
                     cast[ByteAddress](p), "offset is not what you think it is")
-          var d = cast[ptr TFreeCell](cast[ByteAddress](addr(c.data)) +% 
+          var d = cast[ptr TFreeCell](cast[ByteAddress](addr(c.data)) +%
                     offset -% (offset %% c.size))
           if d.zeroField >% 1:
             result = d
@@ -711,13 +711,13 @@ proc ptrSize(p: pointer): int =
   if not isSmallChunk(c):
     dec result, bigChunkOverhead()
 
-proc alloc(allocator: var TMemRegion, size: int): pointer =
+proc alloc(allocator: var TMemRegion, size: Natural): pointer =
   result = rawAlloc(allocator, size+sizeof(TFreeCell))
   cast[ptr TFreeCell](result).zeroField = 1 # mark it as used
   sysAssert(not isAllocatedPtr(allocator, result), "alloc")
   result = cast[pointer](cast[ByteAddress](result) +% sizeof(TFreeCell))
 
-proc alloc0(allocator: var TMemRegion, size: int): pointer =
+proc alloc0(allocator: var TMemRegion, size: Natural): pointer =
   result = alloc(allocator, size)
   zeroMem(result, size)
 
@@ -730,7 +730,7 @@ proc dealloc(allocator: var TMemRegion, p: pointer) =
   rawDealloc(allocator, x)
   sysAssert(not isAllocatedPtr(allocator, x), "dealloc 3")
 
-proc realloc(allocator: var TMemRegion, p: pointer, newsize: int): pointer =
+proc realloc(allocator: var TMemRegion, p: pointer, newsize: Natural): pointer =
   if newsize > 0:
     result = alloc0(allocator, newsize)
     if p != nil:
@@ -758,7 +758,7 @@ proc deallocOsPages(a: var TMemRegion) =
 
 proc getFreeMem(a: TMemRegion): int {.inline.} = result = a.freeMem
 proc getTotalMem(a: TMemRegion): int {.inline.} = result = a.currMem
-proc getOccupiedMem(a: TMemRegion): int {.inline.} = 
+proc getOccupiedMem(a: TMemRegion): int {.inline.} =
   result = a.currMem - a.freeMem
 
 # ---------------------- thread memory region -------------------------------
@@ -774,16 +774,16 @@ template instantiateForRegion(allocator: expr) =
 
   proc deallocOsPages = deallocOsPages(allocator)
 
-  proc alloc(size: int): pointer =
+  proc alloc(size: Natural): pointer =
     result = alloc(allocator, size)
 
-  proc alloc0(size: int): pointer =
+  proc alloc0(size: Natural): pointer =
     result = alloc0(allocator, size)
 
   proc dealloc(p: pointer) =
     dealloc(allocator, p)
 
-  proc realloc(p: pointer, newsize: int): pointer =
+  proc realloc(p: pointer, newsize: Natural): pointer =
     result = realloc(allocator, p, newSize)
 
   when false:
@@ -794,7 +794,7 @@ template instantiateForRegion(allocator: expr) =
         inc(result, it.size)
         it = it.next
 
-  proc getFreeMem(): int = 
+  proc getFreeMem(): int =
     result = allocator.freeMem
     #sysAssert(result == countFreeMem())
 
@@ -807,7 +807,7 @@ template instantiateForRegion(allocator: expr) =
     var heapLock: TSysLock
     initSysLock(heapLock)
 
-  proc allocShared(size: int): pointer =
+  proc allocShared(size: Natural): pointer =
     when hasThreadSupport:
       acquireSys(heapLock)
       result = alloc(sharedHeap, size)
@@ -815,20 +815,20 @@ template instantiateForRegion(allocator: expr) =
     else:
       result = alloc(size)
 
-  proc allocShared0(size: int): pointer =
+  proc allocShared0(size: Natural): pointer =
     result = allocShared(size)
     zeroMem(result, size)
 
   proc deallocShared(p: pointer) =
-    when hasThreadSupport: 
+    when hasThreadSupport:
       acquireSys(heapLock)
       dealloc(sharedHeap, p)
       releaseSys(heapLock)
     else:
       dealloc(p)
 
-  proc reallocShared(p: pointer, newsize: int): pointer =
-    when hasThreadSupport: 
+  proc reallocShared(p: pointer, newsize: Natural): pointer =
+    when hasThreadSupport:
       acquireSys(heapLock)
       result = realloc(sharedHeap, p, newsize)
       releaseSys(heapLock)
diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim
index 6bc44719f..9406f26c9 100644
--- a/lib/system/ansi_c.nim
+++ b/lib/system/ansi_c.nim
@@ -33,10 +33,11 @@ type
 
   C_JmpBuf {.importc: "jmp_buf", header: "<setjmp.h>".} = object
 
-var
-  c_stdin {.importc: "stdin", nodecl.}: C_TextFileStar
-  c_stdout {.importc: "stdout", nodecl.}: C_TextFileStar
-  c_stderr {.importc: "stderr", nodecl.}: C_TextFileStar
+when not defined(vm):
+  var
+    c_stdin {.importc: "stdin", nodecl.}: C_TextFileStar
+    c_stdout {.importc: "stdout", nodecl.}: C_TextFileStar
+    c_stderr {.importc: "stderr", nodecl.}: C_TextFileStar
 
 # constants faked as variables:
 when not declared(SIGINT):
diff --git a/lib/system/arithm.nim b/lib/system/arithm.nim
index c4df287cf..f68e2dcd9 100644
--- a/lib/system/arithm.nim
+++ b/lib/system/arithm.nim
@@ -15,7 +15,7 @@ proc raiseOverflow {.compilerproc, noinline, noreturn.} =
   sysFatal(OverflowError, "over- or underflow")
 
 proc raiseDivByZero {.compilerproc, noinline, noreturn.} =
-  sysFatal(DivByZeroError, "divison by zero")
+  sysFatal(DivByZeroError, "division by zero")
 
 proc addInt64(a, b: int64): int64 {.compilerProc, inline.} =
   result = a +% b
diff --git a/lib/system/assign.nim b/lib/system/assign.nim
index 429a92d34..78995954f 100644
--- a/lib/system/assign.nim
+++ b/lib/system/assign.nim
@@ -27,7 +27,7 @@ proc genericAssignAux(dest, src: pointer, n: ptr TNimNode,
     var m = selectBranch(src, n)
     # reset if different branches are in use; note different branches also
     # imply that's not self-assignment (``x = x``)!
-    if m != dd and dd != nil: 
+    if m != dd and dd != nil:
       genericResetAux(dest, dd)
     copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
             n.typ.size)
@@ -205,9 +205,13 @@ proc genericReset(dest: pointer, mt: PNimType) =
   case mt.kind
   of tyString, tyRef, tySequence:
     unsureAsgnRef(cast[PPointer](dest), nil)
-  of tyObject, tyTuple:
-    # we don't need to reset m_type field for tyObject
+  of tyTuple:
+    genericResetAux(dest, mt.node)
+  of tyObject:
     genericResetAux(dest, mt.node)
+    # also reset the type field for tyObject, for correct branch switching!
+    var pint = cast[ptr PNimType](dest)
+    pint[] = nil
   of tyArray, tyArrayConstr:
     for i in 0..(mt.size div mt.base.size)-1:
       genericReset(cast[pointer](d +% i*% mt.base.size), mt.base)
diff --git a/lib/system/atomics.nim b/lib/system/atomics.nim
index f816c8201..c97d2fc7f 100644
--- a/lib/system/atomics.nim
+++ b/lib/system/atomics.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -21,19 +21,19 @@ when someGcc and hasThreadSupport:
     ## synchronization with another thread.
   var ATOMIC_ACQUIRE* {.importc: "__ATOMIC_ACQUIRE", nodecl.}: AtomMemModel
     ## Barrier to hoisting of code and synchronizes with
-    ## release (or stronger) 
+    ## release (or stronger)
     ## semantic stores from another thread.
   var ATOMIC_RELEASE* {.importc: "__ATOMIC_RELEASE", nodecl.}: AtomMemModel
     ## Barrier to sinking of code and synchronizes with
-    ## acquire (or stronger) 
-    ## semantic loads from another thread. 
+    ## acquire (or stronger)
+    ## semantic loads from another thread.
   var ATOMIC_ACQ_REL* {.importc: "__ATOMIC_ACQ_REL", nodecl.}: AtomMemModel
     ## Full barrier in both directions and synchronizes
-    ## with acquire loads 
+    ## with acquire loads
     ## and release stores in another thread.
   var ATOMIC_SEQ_CST* {.importc: "__ATOMIC_SEQ_CST", nodecl.}: AtomMemModel
     ## Full barrier in both directions and synchronizes
-    ## with acquire loads 
+    ## with acquire loads
     ## and release stores in all threads.
 
   type
@@ -46,11 +46,11 @@ when someGcc and hasThreadSupport:
     ## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_ACQUIRE, ATOMIC_CONSUME.
 
   proc atomicLoad*[T: TAtomType](p, ret: ptr T, mem: AtomMemModel) {.
-    importc: "__atomic_load", nodecl.}  
+    importc: "__atomic_load", nodecl.}
     ## This is the generic version of an atomic load. It returns the contents at p in ret.
 
   proc atomicStoreN*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel) {.
-    importc: "__atomic_store_n", nodecl.} 
+    importc: "__atomic_store_n", nodecl.}
     ## This proc implements an atomic store operation. It writes val at p.
     ## ATOMIC_RELAXED, ATOMIC_SEQ_CST, and ATOMIC_RELEASE.
 
@@ -60,39 +60,39 @@ when someGcc and hasThreadSupport:
 
   proc atomicExchangeN*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
     importc: "__atomic_exchange_n", nodecl.}
-    ## This proc implements an atomic exchange operation. It writes val at p, 
+    ## This proc implements an atomic exchange operation. It writes val at p,
     ## and returns the previous contents at p.
     ## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_ACQUIRE, ATOMIC_RELEASE, ATOMIC_ACQ_REL
 
   proc atomicExchange*[T: TAtomType](p, val, ret: ptr T, mem: AtomMemModel) {.
     importc: "__atomic_exchange", nodecl.}
-    ## This is the generic version of an atomic exchange. It stores the contents at val at p. 
+    ## This is the generic version of an atomic exchange. It stores the contents at val at p.
     ## The original value at p is copied into ret.
 
   proc atomicCompareExchangeN*[T: TAtomType](p, expected: ptr T, desired: T,
     weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
-    importc: "__atomic_compare_exchange_n ", nodecl.} 
+    importc: "__atomic_compare_exchange_n ", nodecl.}
     ## This proc implements an atomic compare and exchange operation. This compares the
-    ## contents at p with the contents at expected and if equal, writes desired at p. 
-    ## If they are not equal, the current contents at p is written into expected. 
-    ## Weak is true for weak compare_exchange, and false for the strong variation. 
-    ## Many targets only offer the strong variation and ignore the parameter. 
+    ## contents at p with the contents at expected and if equal, writes desired at p.
+    ## If they are not equal, the current contents at p is written into expected.
+    ## Weak is true for weak compare_exchange, and false for the strong variation.
+    ## Many targets only offer the strong variation and ignore the parameter.
     ## When in doubt, use the strong variation.
-    ## True is returned if desired is written at p and the execution is considered 
-    ## to conform to the memory model specified by success_memmodel. There are no 
-    ## restrictions on what memory model can be used here. False is returned otherwise, 
-    ## and the execution is considered to conform to failure_memmodel. This memory model 
-    ## cannot be __ATOMIC_RELEASE nor __ATOMIC_ACQ_REL. It also cannot be a stronger model 
+    ## True is returned if desired is written at p and the execution is considered
+    ## to conform to the memory model specified by success_memmodel. There are no
+    ## restrictions on what memory model can be used here. False is returned otherwise,
+    ## and the execution is considered to conform to failure_memmodel. This memory model
+    ## cannot be __ATOMIC_RELEASE nor __ATOMIC_ACQ_REL. It also cannot be a stronger model
     ## than that specified by success_memmodel.
 
   proc atomicCompareExchange*[T: TAtomType](p, expected, desired: ptr T,
     weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
-    importc: "__atomic_compare_exchange_n ", nodecl.}  
-    ## This proc implements the generic version of atomic_compare_exchange. 
-    ## The proc is virtually identical to atomic_compare_exchange_n, except the desired 
-    ## value is also a pointer. 
+    importc: "__atomic_compare_exchange", nodecl.}
+    ## This proc implements the generic version of atomic_compare_exchange.
+    ## The proc is virtually identical to atomic_compare_exchange_n, except the desired
+    ## value is also a pointer.
 
-  ## Perform the operation return the new value, all memory models are valid 
+  ## Perform the operation return the new value, all memory models are valid
   proc atomicAddFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
     importc: "__atomic_add_fetch", nodecl.}
   proc atomicSubFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
@@ -101,64 +101,64 @@ when someGcc and hasThreadSupport:
     importc: "__atomic_or_fetch ", nodecl.}
   proc atomicAndFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
     importc: "__atomic_and_fetch", nodecl.}
-  proc atomicXorFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.   
+  proc atomicXorFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
     importc: "__atomic_xor_fetch", nodecl.}
-  proc atomicNandFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.   
-    importc: "__atomic_nand_fetch ", nodecl.} 
+  proc atomicNandFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
+    importc: "__atomic_nand_fetch ", nodecl.}
 
-  ## Perform the operation return the old value, all memory models are valid 
+  ## Perform the operation return the old value, all memory models are valid
   proc atomicFetchAdd*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
     importc: "__atomic_fetch_add", nodecl.}
-  proc atomicFetchSub*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.  
+  proc atomicFetchSub*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
     importc: "__atomic_fetch_sub", nodecl.}
-  proc atomicFetchOr*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.  
+  proc atomicFetchOr*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
     importc: "__atomic_fetch_or", nodecl.}
-  proc atomicFetchAnd*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.   
+  proc atomicFetchAnd*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
     importc: "__atomic_fetch_and", nodecl.}
-  proc atomicFetchXor*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.  
+  proc atomicFetchXor*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
     importc: "__atomic_fetch_xor", nodecl.}
-  proc atomicFetchNand*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.  
-    importc: "__atomic_fetch_nand", nodecl.} 
+  proc atomicFetchNand*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
+    importc: "__atomic_fetch_nand", nodecl.}
 
-  proc atomicTestAndSet*(p: pointer, mem: AtomMemModel): bool {.  
-    importc: "__atomic_test_and_set", nodecl.} 
-    ## This built-in function performs an atomic test-and-set operation on the byte at p. 
+  proc atomicTestAndSet*(p: pointer, mem: AtomMemModel): bool {.
+    importc: "__atomic_test_and_set", nodecl.}
+    ## This built-in function performs an atomic test-and-set operation on the byte at p.
     ## The byte is set to some implementation defined nonzero “set†value and the return
     ## value is true if and only if the previous contents were “setâ€.
     ## All memory models are valid.
 
-  proc atomicClear*(p: pointer, mem: AtomMemModel) {.  
+  proc atomicClear*(p: pointer, mem: AtomMemModel) {.
     importc: "__atomic_clear", nodecl.}
-    ## This built-in function performs an atomic clear operation at p. 
+    ## This built-in function performs an atomic clear operation at p.
     ## After the operation, at p contains 0.
     ## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_RELEASE
 
-  proc atomicThreadFence*(mem: AtomMemModel) {.  
+  proc atomicThreadFence*(mem: AtomMemModel) {.
     importc: "__atomic_thread_fence", nodecl.}
-    ## This built-in function acts as a synchronization fence between threads based 
+    ## This built-in function acts as a synchronization fence between threads based
     ## on the specified memory model. All memory orders are valid.
 
-  proc atomicSignalFence*(mem: AtomMemModel) {.  
+  proc atomicSignalFence*(mem: AtomMemModel) {.
     importc: "__atomic_signal_fence", nodecl.}
-    ## This built-in function acts as a synchronization fence between a thread and 
+    ## This built-in function acts as a synchronization fence between a thread and
     ## signal handlers based in the same thread. All memory orders are valid.
 
-  proc atomicAlwaysLockFree*(size: int, p: pointer): bool {.  
+  proc atomicAlwaysLockFree*(size: int, p: pointer): bool {.
     importc: "__atomic_always_lock_free", nodecl.}
-    ## This built-in function returns true if objects of size bytes always generate 
-    ## lock free atomic instructions for the target architecture. size must resolve 
+    ## This built-in function returns true if objects of size bytes always generate
+    ## lock free atomic instructions for the target architecture. size must resolve
     ## to a compile-time constant and the result also resolves to a compile-time constant.
-    ## ptr is an optional pointer to the object that may be used to determine alignment. 
-    ## A value of 0 indicates typical alignment should be used. The compiler may also 
+    ## ptr is an optional pointer to the object that may be used to determine alignment.
+    ## A value of 0 indicates typical alignment should be used. The compiler may also
     ## ignore this parameter.
 
-  proc atomicIsLockFree*(size: int, p: pointer): bool {.  
+  proc atomicIsLockFree*(size: int, p: pointer): bool {.
     importc: "__atomic_is_lock_free", nodecl.}
-    ## This built-in function returns true if objects of size bytes always generate 
-    ## lock free atomic instructions for the target architecture. If it is not known 
+    ## This built-in function returns true if objects of size bytes always generate
+    ## lock free atomic instructions for the target architecture. If it is not known
     ## to be lock free a call is made to a runtime routine named __atomic_is_lock_free.
-    ## ptr is an optional pointer to the object that may be used to determine alignment. 
-    ## A value of 0 indicates typical alignment should be used. The compiler may also 
+    ## ptr is an optional pointer to the object that may be used to determine alignment.
+    ## A value of 0 indicates typical alignment should be used. The compiler may also
     ## ignore this parameter.
 
   template fence*() = atomicThreadFence(ATOMIC_SEQ_CST)
@@ -178,7 +178,7 @@ proc atomicInc*(memLoc: var int, x: int = 1): int =
   else:
     inc(memLoc, x)
     result = memLoc
-  
+
 proc atomicDec*(memLoc: var int, x: int = 1): int =
   when someGcc and hasThreadSupport:
     when declared(atomic_sub_fetch):
@@ -206,6 +206,9 @@ else:
 when (defined(x86) or defined(amd64)) and someGcc:
   proc cpuRelax* {.inline.} =
     {.emit: """asm volatile("pause" ::: "memory");""".}
+elif someGcc:
+  proc cpuRelax* {.inline.} =
+    {.emit: """asm volatile("" ::: "memory");""".}
 elif (defined(x86) or defined(amd64)) and defined(vcc):
   proc cpuRelax* {.importc: "YieldProcessor", header: "<windows.h>".}
 elif defined(icl):
diff --git a/lib/system/cgprocs.nim b/lib/system/cgprocs.nim
index 089846578..f3acc81f2 100644
--- a/lib/system/cgprocs.nim
+++ b/lib/system/cgprocs.nim
@@ -13,7 +13,7 @@ proc addChar(s: NimString, c: char): NimString {.compilerProc, benign.}
 
 type
   TLibHandle = pointer       # private type
-  TProcAddr = pointer        # libary loading and loading of procs:
+  TProcAddr = pointer        # library loading and loading of procs:
 
 proc nimLoadLibrary(path: string): TLibHandle {.compilerproc.}
 proc nimUnloadLibrary(lib: TLibHandle) {.compilerproc.}
diff --git a/lib/system/channels.nim b/lib/system/channels.nim
index 3e5ca0795..ebd30c353 100644
--- a/lib/system/channels.nim
+++ b/lib/system/channels.nim
@@ -1,7 +1,7 @@
 #

 #

 #            Nim's Runtime Library

-#        (c) Copyright 2014 Andreas Rumpf

+#        (c) Copyright 2015 Andreas Rumpf
 #

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

 #    distribution, for details about the copyright.

@@ -232,9 +232,10 @@ proc tryRecv*[TMsg](c: var TChannel[TMsg]): tuple[dataAvailable: bool,
   ## it returns ``(false, default(msg))``.

   var q = cast[PRawChannel](addr(c))

   if q.mask != ChannelDeadMask:

-    if tryAcquireSys(q.lock):

-      llRecv(q, addr(result.msg), cast[PNimType](getTypeInfo(result.msg)))

-      result.dataAvailable = true

+    if tryAcquireSys(q.lock):
+      if q.count > 0:

+        llRecv(q, addr(result.msg), cast[PNimType](getTypeInfo(result.msg)))

+        result.dataAvailable = true

       releaseSys(q.lock)

 

 proc peek*[TMsg](c: var TChannel[TMsg]): int =

diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim
index 5c32a307a..2f6d25a12 100644
--- a/lib/system/chcks.nim
+++ b/lib/system/chcks.nim
@@ -11,7 +11,7 @@
 
 proc raiseRangeError(val: BiggestInt) {.compilerproc, noreturn, noinline.} =
   when hostOS == "standalone":
-    sysFatal(EOutOfRange, "value out of range")
+    sysFatal(RangeError, "value out of range")
   else:
     sysFatal(RangeError, "value out of range: ", $val)
 
@@ -44,7 +44,7 @@ proc chckRangeF(x, a, b: float): float =
     return x
   else:
     when hostOS == "standalone":
-      sysFatal(EOutOfRange, "value out of range")
+      sysFatal(RangeError, "value out of range")
     else:
       sysFatal(RangeError, "value out of range: ", $x)
 
diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim
index fbebb17a8..093c0f3a7 100644
--- a/lib/system/deepcopy.nim
+++ b/lib/system/deepcopy.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -34,9 +34,9 @@ proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode) {.benign.} =
 
 proc copyDeepString(src: NimString): NimString {.inline.} =
   if src != nil:
-    result = rawNewString(src.space)
+    result = rawNewStringNoInit(src.len)
     result.len = src.len
-    c_memcpy(result.data, src.data, (src.len + 1) * sizeof(char))
+    c_memcpy(result.data, src.data, src.len + 1)
 
 proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
   var
diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim
index e0d99cf88..44f7b67c3 100644
--- a/lib/system/dyncalls.nim
+++ b/lib/system/dyncalls.nim
@@ -8,7 +8,7 @@
 #
 
 # This file implements the ability to call native procs from libraries.
-# It is not possible to do this in a platform independant way, unfortunately.
+# It is not possible to do this in a platform independent way, unfortunately.
 # However, the interface has been designed to take platform differences into
 # account and been ported to all major platforms.
 
@@ -80,15 +80,22 @@ elif defined(windows) or defined(dos):
   # Native Windows Implementation
   # =======================================================================
   #
-  type
-    THINSTANCE {.importc: "HINSTANCE".} = pointer
+  when defined(cpp):
+    type
+      THINSTANCE {.importc: "HINSTANCE".} = object
+        x: pointer
+    proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
+        importcpp: "(void*)GetProcAddress(@)", header: "<windows.h>", stdcall.}
+  else:
+    type
+      THINSTANCE {.importc: "HINSTANCE".} = pointer
+    proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
+        importc: "GetProcAddress", header: "<windows.h>", stdcall.}
 
   proc freeLibrary(lib: THINSTANCE) {.
       importc: "FreeLibrary", header: "<windows.h>", stdcall.}
   proc winLoadLibrary(path: cstring): THINSTANCE {.
       importc: "LoadLibraryA", header: "<windows.h>", stdcall.}
-  proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
-      importc: "GetProcAddress", header: "<windows.h>", stdcall.}
 
   proc nimUnloadLibrary(lib: TLibHandle) =
     freeLibrary(cast[THINSTANCE](lib))
diff --git a/lib/system/embedded.nim b/lib/system/embedded.nim
index 9bb25b8dd..a14f43e7e 100644
--- a/lib/system/embedded.nim
+++ b/lib/system/embedded.nim
@@ -33,11 +33,11 @@ proc quitOrDebug() {.inline.} =
   quit(1)
 
 proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =
-  sysFatal(ENoExceptionToReraise, "exception handling is not available")
+  sysFatal(ReraiseError, "exception handling is not available")
 
 proc reraiseException() {.compilerRtl.} =
-  sysFatal(ENoExceptionToReraise, "no exception to reraise")
+  sysFatal(ReraiseError, "no exception to reraise")
 
 proc writeStackTrace() = discard
 
-proc setControlCHook(hook: proc () {.noconv.}) = discard
+proc setControlCHook(hook: proc () {.noconv.} not nil) = discard
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index e21eeca6a..1b3471978 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -175,6 +175,8 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
       add(s, tempFrames[j].procname)
     add(s, "\n")
 
+proc stackTraceAvailable*(): bool
+
 when hasSomeStackTrace:
   proc rawWriteStackTrace(s: var string) =
     when NimStackTrace:
@@ -188,6 +190,18 @@ when hasSomeStackTrace:
       auxWriteStackTraceWithBacktrace(s)
     else:
       add(s, "No stack traceback available\n")
+  proc stackTraceAvailable(): bool =
+    when NimStackTrace:
+      if framePtr == nil:
+        result = false
+      else:
+        result = true
+    elif defined(nativeStackTrace) and nativeStackTraceSupported:
+      result = true
+    else:
+      result = false
+else:
+  proc stackTraceAvailable*(): bool = result = false
 
 proc quitOrDebug() {.inline.} =
   when not defined(endb):
@@ -303,7 +317,7 @@ when not defined(noSignalHandler):
         action("SIGABRT: Abnormal termination.\n")
       elif s == SIGFPE: action("SIGFPE: Arithmetic error.\n")
       elif s == SIGILL: action("SIGILL: Illegal operation.\n")
-      elif s == SIGBUS: 
+      elif s == SIGBUS:
         action("SIGBUS: Illegal storage access. (Attempt to read from nil?)\n")
       else:
         block platformSpecificSignal:
@@ -341,7 +355,7 @@ when not defined(noSignalHandler):
 
   registerSignalHandler() # call it in initialization section
 
-proc setControlCHook(hook: proc () {.noconv.}) =
+proc setControlCHook(hook: proc () {.noconv.} not nil) =
   # ugly cast, but should work on all architectures:
   type TSignalHandler = proc (sig: cint) {.noconv, benign.}
   c_signal(SIGINT, cast[TSignalHandler](hook))
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index fe4b40903..c4374d00c 100644
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2013 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -33,7 +33,7 @@ const
 when withRealTime and not declared(getTicks):
   include "system/timers"
 when defined(memProfiler):
-  proc nimProfile(requestedSize: int)
+  proc nimProfile(requestedSize: int) {.benign.}
 
 const
   rcIncrement = 0b1000 # so that lowest 3 bits are not touched
@@ -48,8 +48,8 @@ type
   TWalkOp = enum
     waMarkGlobal,    # part of the backup/debug mark&sweep
     waMarkPrecise,   # part of the backup/debug mark&sweep
-    waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack, 
-    waCollectWhite,
+    waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack,
+    waCollectWhite #, waDebug
 
   TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
     # A ref type can have a finalizer that is called before the object's
@@ -61,9 +61,9 @@ type
     maxThreshold: int        # max threshold that has been set
     maxStackSize: int        # max stack size
     maxStackCells: int       # max stack cells in ``decStack``
-    cycleTableSize: int      # max entries in cycle table  
+    cycleTableSize: int      # max entries in cycle table
     maxPause: int64          # max measured GC pause in nanoseconds
-  
+
   TGcHeap {.final, pure.} = object # this contains the zero count and
                                    # non-zero count table
     stackBottom: pointer
@@ -88,11 +88,11 @@ var
 when not defined(useNimRtl):
   instantiateForRegion(gch.region)
 
-template acquire(gch: TGcHeap) = 
+template acquire(gch: TGcHeap) =
   when hasThreadSupport and hasSharedHeap:
     acquireSys(HeapLock)
 
-template release(gch: TGcHeap) = 
+template release(gch: TGcHeap) =
   when hasThreadSupport and hasSharedHeap:
     releaseSys(HeapLock)
 
@@ -117,7 +117,7 @@ proc usrToCell(usr: pointer): PCell {.inline.} =
   # convert pointer to userdata to object (=pointer to refcount)
   result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
 
-proc canbeCycleRoot(c: PCell): bool {.inline.} =
+proc canBeCycleRoot(c: PCell): bool {.inline.} =
   result = ntfAcyclic notin c.typ.flags
 
 proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
@@ -163,7 +163,7 @@ when hasThreadSupport and hasSharedHeap:
   template `--`(x: expr): expr = atomicDec(x, rcIncrement) <% rcIncrement
   template `++`(x: expr): stmt = discard atomicInc(x, rcIncrement)
 else:
-  template `--`(x: expr): expr = 
+  template `--`(x: expr): expr =
     dec(x, rcIncrement)
     x <% rcIncrement
   template `++`(x: expr): stmt = inc(x, rcIncrement)
@@ -181,7 +181,7 @@ proc prepareDealloc(cell: PCell) =
     (cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
     dec(gch.recGcLock)
 
-proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} = 
+proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
   # we MUST access gch as a global here, because this crosses DLL boundaries!
   when hasThreadSupport and hasSharedHeap:
     acquireSys(HeapLock)
@@ -211,7 +211,7 @@ proc decRef(c: PCell) {.inline.} =
     rtlAddCycleRoot(c)
     #writeCell("decRef", c)
 
-proc incRef(c: PCell) {.inline.} = 
+proc incRef(c: PCell) {.inline.} =
   gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
   c.refcount = c.refcount +% rcIncrement
   # and not colorMask
@@ -246,12 +246,12 @@ proc asgnRef(dest: PPointer, src: pointer) {.compilerProc, inline.} =
   dest[] = src
 
 proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerProc, inline.} =
-  # the code generator calls this proc if it is known at compile time that no 
+  # the code generator calls this proc if it is known at compile time that no
   # cycle is possible.
   if src != nil:
     var c = usrToCell(src)
     ++c.refcount
-  if dest[] != nil: 
+  if dest[] != nil:
     var c = usrToCell(dest[])
     if --c.refcount:
       rtlAddZCT(c)
@@ -269,7 +269,7 @@ proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerProc.} =
     if cast[int](dest[]) >=% PageSize: decRef(usrToCell(dest[]))
   else:
     # can't be an interior pointer if it's a stack location!
-    gcAssert(interiorAllocatedPtr(gch.region, dest) == nil, 
+    gcAssert(interiorAllocatedPtr(gch.region, dest) == nil,
              "stack loc AND interior pointer")
   dest[] = src
 
@@ -292,6 +292,20 @@ proc initGC() =
     when useMarkForDebug or useBackupGc:
       init(gch.marked)
 
+var
+  localGcInitialized {.rtlThreadVar.}: bool
+
+proc setupForeignThreadGc*() =
+  ## call this if you registered a callback that will be run from a thread not
+  ## under your control. This has a cheap thread-local guard, so the GC for
+  ## this thread will only be initialized once per thread, no matter how often
+  ## it is called.
+  if not localGcInitialized:
+    localGcInitialized = true
+    var stackTop {.volatile.}: pointer
+    setStackBottom(addr(stackTop))
+    initGC()
+
 when useMarkForDebug or useBackupGc:
   type
     TGlobalMarkerProc = proc () {.nimcall, benign.}
@@ -307,7 +321,7 @@ when useMarkForDebug or useBackupGc:
       echo "[GC] cannot register global variable; too many global variables"
       quit 1
 
-proc cellsetReset(s: var TCellSet) = 
+proc cellsetReset(s: var TCellSet) =
   deinit(s)
   init(s)
 
@@ -322,7 +336,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
         if n.sons[i].typ.kind in {tyRef, tyString, tySequence}:
           doOperation(cast[PPointer](d +% n.sons[i].offset)[], op)
         else:
-          forAllChildrenAux(cast[pointer](d +% n.sons[i].offset), 
+          forAllChildrenAux(cast[pointer](d +% n.sons[i].offset),
                             n.sons[i].typ, op)
       else:
         forAllSlotsAux(dest, n.sons[i], op)
@@ -370,7 +384,7 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
   # we check the last 8 entries (cache line) for a slot that could be reused.
   # In 63% of all cases we succeed here! But we have to optimize the heck
   # out of this small linear search so that ``newObj`` is not slowed down.
-  # 
+  #
   # Slots to try          cache hit
   # 1                     32%
   # 4                     59%
@@ -447,6 +461,10 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
 
 {.pop.}
 
+proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
+  result = rawNewObj(typ, size, gch)
+  when defined(memProfiler): nimProfile(size)
+
 proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
   result = rawNewObj(typ, size, gch)
   zeroMem(result, size)
@@ -467,7 +485,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
   gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
   collectCT(gch)
   sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
-  
+
   var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
   sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc")
   sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
@@ -496,7 +514,7 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
   cast[PGenericSeq](result).len = len
   cast[PGenericSeq](result).reserved = len
   when defined(memProfiler): nimProfile(size)
-  
+
 proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
   acquire(gch)
   collectCT(gch)
@@ -508,34 +526,42 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
   var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
   var elemSize = 1
   if ol.typ.kind != tyString: elemSize = ol.typ.base.size
-  
+
   var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
   copyMem(res, ol, oldsize + sizeof(TCell))
   zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
           newsize-oldsize)
   sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
-  sysAssert(res.refcount shr rcShift <=% 1, "growObj: 4")
-  #if res.refcount <% rcIncrement:
-  #  add(gch.zct, res)
-  #else: # XXX: what to do here?
-  #  decRef(ol)
-  if (ol.refcount and ZctFlag) != 0:
-    var j = gch.zct.len-1
-    var d = gch.zct.d
-    while j >= 0: 
-      if d[j] == ol:
-        d[j] = res
-        break
-      dec(j)
-  if canbeCycleRoot(ol): excl(gch.cycleRoots, ol)
+  # This can be wrong for intermediate temps that are nevertheless on the
+  # heap because of lambda lifting:
+  #gcAssert(res.refcount shr rcShift <=% 1, "growObj: 4")
   when logGC:
     writeCell("growObj old cell", ol)
     writeCell("growObj new cell", res)
   gcTrace(ol, csZctFreed)
   gcTrace(res, csAllocated)
-  when reallyDealloc: 
+  when reallyDealloc:
     sysAssert(allocInv(gch.region), "growObj before dealloc")
-    rawDealloc(gch.region, ol)
+    if ol.refcount shr rcShift <=% 1:
+      # free immediately to save space:
+      if (ol.refcount and ZctFlag) != 0:
+        var j = gch.zct.len-1
+        var d = gch.zct.d
+        while j >= 0:
+          if d[j] == ol:
+            d[j] = res
+            break
+          dec(j)
+      if canbeCycleRoot(ol): excl(gch.cycleRoots, ol)
+      rawDealloc(gch.region, ol)
+    else:
+      # we split the old refcount in 2 parts. XXX This is still not entirely
+      # correct if the pointer that receives growObj's result is on the stack.
+      # A better fix would be to emit the location specific write barrier for
+      # 'growObj', but this is lost of more work and who knows what new problems
+      # this would create.
+      res.refcount = rcIncrement
+      decRef(ol)
   else:
     sysAssert(ol.typ != nil, "growObj: 5")
     zeroMem(ol, sizeof(TCell))
@@ -558,7 +584,7 @@ proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
   prepareDealloc(c)
   gcTrace(c, csCycFreed)
   when logGC: writeCell("cycle collector dealloc cell", c)
-  when reallyDealloc: 
+  when reallyDealloc:
     sysAssert(allocInv(gch.region), "free cyclic cell")
     rawDealloc(gch.region, c)
   else:
@@ -581,9 +607,15 @@ proc scan(s: PCell) =
     else:
       s.setColor(rcWhite)
       forAllChildren(s, waScan)
-  
+
 proc collectWhite(s: PCell) =
-  if s.color == rcWhite and s notin gch.cycleRoots:
+  # This is a hacky way to deal with the following problem (bug #1796)
+  # Consider this content in cycleRoots:
+  #   x -> a; y -> a  where 'a' is an acyclic object so not included in
+  # cycleRoots itself. Then 'collectWhite' used to free 'a' twice. The
+  # 'isAllocatedPtr' check prevents this. This also means we do not need
+  # to query 's notin gch.cycleRoots' at all.
+  if isAllocatedPtr(gch.region, s) and s.color == rcWhite:
     s.setColor(rcBlack)
     forAllChildren(s, waCollectWhite)
     freeCyclicCell(gch, s)
@@ -634,6 +666,28 @@ when useMarkForDebug or useBackupGc:
       if objStart != nil:
         markS(gch, objStart)
 
+when logGC:
+  var
+    cycleCheckA: array[100, PCell]
+    cycleCheckALen = 0
+
+  proc alreadySeen(c: PCell): bool =
+    for i in 0 .. <cycleCheckALen:
+      if cycleCheckA[i] == c: return true
+    if cycleCheckALen == len(cycleCheckA):
+      gcAssert(false, "cycle detection overflow")
+      quit 1
+    cycleCheckA[cycleCheckALen] = c
+    inc cycleCheckALen
+
+  proc debugGraph(s: PCell) =
+    if alreadySeen(s):
+      writeCell("child cell (already seen) ", s)
+    else:
+      writeCell("cell {", s)
+      forAllChildren(s, waDebug)
+      c_fprintf(c_stdout, "}\n")
+
 proc doOperation(p: pointer, op: TWalkOp) =
   if p == nil: return
   var c: PCell = usrToCell(p)
@@ -676,6 +730,7 @@ proc doOperation(p: pointer, op: TWalkOp) =
   of waMarkPrecise:
     when useMarkForDebug or useBackupGc:
       add(gch.tempStack, c)
+  #of waDebug: debugGraph(c)
 
 proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
   doOperation(d, TWalkOp(op))
@@ -688,7 +743,6 @@ when useMarkForDebug or useBackupGc:
 
 proc collectRoots(gch: var TGcHeap) =
   for s in elements(gch.cycleRoots):
-    excl(gch.cycleRoots, s)
     collectWhite(s)
 
 proc collectCycles(gch: var TGcHeap) =
@@ -717,7 +771,7 @@ proc collectCycles(gch: var TGcHeap) =
       gcAssert isAllocatedPtr(gch.region, c), "addBackStackRoots"
       gcAssert c.refcount >=% rcIncrement, "addBackStackRoots: dead cell"
       if canBeCycleRoot(c):
-        #if c notin gch.cycleRoots: 
+        #if c notin gch.cycleRoots:
         inc cycleRootsLen
         incl(gch.cycleRoots, c)
       gcAssert c.typ != nil, "addBackStackRoots 2"
@@ -744,12 +798,12 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
         add(gch.decStack, cell)
   sysAssert(allocInv(gch.region), "gcMark end")
 
-proc markThreadStacks(gch: var TGcHeap) = 
+proc markThreadStacks(gch: var TGcHeap) =
   when hasThreadSupport and hasSharedHeap:
     {.error: "not fully implemented".}
     var it = threadList
     while it != nil:
-      # mark registers: 
+      # mark registers:
       for i in 0 .. high(it.registers): gcMark(gch, it.registers[i])
       var sp = cast[TAddress](it.stackBottom)
       var max = cast[TAddress](it.stackTop)
@@ -834,7 +888,7 @@ elif stackIncreases:
   var
     jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
       # a little hack to get the size of a TJmpBuf in the generated C code
-      # in a platform independant way
+      # in a platform independent way
 
   template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} =
     var registers: C_JmpBuf
@@ -883,7 +937,7 @@ else:
       while sp <=% max:
         gcMark(gch, cast[PPointer](sp)[])
         sp = sp +% sizeof(pointer)
-    
+
 proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
   forEachStackSlot(gch, gcMark)
 
@@ -896,13 +950,13 @@ when useMarkForDebug or useBackupGc:
 # ----------------------------------------------------------------------------
 
 proc collectZCT(gch: var TGcHeap): bool =
-  # Note: Freeing may add child objects to the ZCT! So essentially we do 
-  # deep freeing, which is bad for incremental operation. In order to 
+  # Note: Freeing may add child objects to the ZCT! So essentially we do
+  # deep freeing, which is bad for incremental operation. In order to
   # avoid a deep stack, we move objects to keep the ZCT small.
   # This is performance critical!
   const workPackage = 100
   var L = addr(gch.zct.len)
-  
+
   when withRealTime:
     var steps = workPackage
     var t0: TTicks
@@ -912,15 +966,15 @@ proc collectZCT(gch: var TGcHeap): bool =
     sysAssert(isAllocatedPtr(gch.region, c), "CollectZCT: isAllocatedPtr")
     # remove from ZCT:
     gcAssert((c.refcount and ZctFlag) == ZctFlag, "collectZCT")
-    
+
     c.refcount = c.refcount and not ZctFlag
     gch.zct.d[0] = gch.zct.d[L[] - 1]
     dec(L[])
     when withRealTime: dec steps
-    if c.refcount <% rcIncrement: 
+    if c.refcount <% rcIncrement:
       # It may have a RC > 0, if it is in the hardware stack or
       # it has not been removed yet from the ZCT. This is because
-      # ``incref`` does not bother to remove the cell from the ZCT 
+      # ``incref`` does not bother to remove the cell from the ZCT
       # as this might be too slow.
       # In any case, it should be removed from the ZCT. But not
       # freed. **KEEP THIS IN MIND WHEN MAKING THIS INCREMENTAL!**
@@ -933,7 +987,7 @@ proc collectZCT(gch: var TGcHeap): bool =
       # access invalid memory. This is done by prepareDealloc():
       prepareDealloc(c)
       forAllChildren(c, waZctDecRef)
-      when reallyDealloc: 
+      when reallyDealloc:
         sysAssert(allocInv(gch.region), "collectZCT: rawDealloc")
         rawDealloc(gch.region, c)
       else:
@@ -944,7 +998,7 @@ proc collectZCT(gch: var TGcHeap): bool =
         steps = workPackage
         if gch.maxPause > 0:
           let duration = getticks() - t0
-          # the GC's measuring is not accurate and needs some cleanup actions 
+          # the GC's measuring is not accurate and needs some cleanup actions
           # (stack unmarking), so subtract some short amount of time in
           # order to miss deadlines less often:
           if duration >= gch.maxPause - 50_000:
@@ -967,7 +1021,7 @@ proc collectCTBody(gch: var TGcHeap) =
   when withRealTime:
     let t0 = getticks()
   sysAssert(allocInv(gch.region), "collectCT: begin")
-  
+
   gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
   sysAssert(gch.decStack.len == 0, "collectCT")
   prepareForInteriorPointerChecking(gch.region)
@@ -986,7 +1040,7 @@ proc collectCTBody(gch: var TGcHeap) =
         gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
   unmarkStackAndRegisters(gch)
   sysAssert(allocInv(gch.region), "collectCT: end")
-  
+
   when withRealTime:
     let duration = getticks() - t0
     gch.stat.maxPause = max(gch.stat.maxPause, duration)
@@ -1000,8 +1054,12 @@ when useMarkForDebug or useBackupGc:
     markGlobals(gch)
 
 proc collectCT(gch: var TGcHeap) =
-  if (gch.zct.len >= ZctThreshold or (cycleGC and
-      getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and 
+  # stackMarkCosts prevents some pathological behaviour: Stack marking
+  # becomes more expensive with large stacks and large stacks mean that
+  # cells with RC=0 are more likely to be kept alive by the stack.
+  let stackMarkCosts = max(stackSize() div (16*sizeof(int)), ZctThreshold)
+  if (gch.zct.len >= stackMarkCosts or (cycleGC and
+      getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
       gch.recGcLock == 0:
     when useMarkForDebug:
       prepareForInteriorPointerChecking(gch.region)
@@ -1020,7 +1078,7 @@ when withRealTime:
     acquire(gch)
     gch.maxPause = us.toNano
     if (gch.zct.len >= ZctThreshold or (cycleGC and
-        getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or 
+        getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or
         strongAdvice:
       collectCTBody(gch)
     release(gch)
@@ -1028,13 +1086,13 @@ when withRealTime:
   proc GC_step*(us: int, strongAdvice = false) = GC_step(gch, us, strongAdvice)
 
 when not defined(useNimRtl):
-  proc GC_disable() = 
+  proc GC_disable() =
     when hasThreadSupport and hasSharedHeap:
       discard atomicInc(gch.recGcLock, 1)
     else:
       inc(gch.recGcLock)
   proc GC_enable() =
-    if gch.recGcLock > 0: 
+    if gch.recGcLock > 0:
       when hasThreadSupport and hasSharedHeap:
         discard atomicDec(gch.recGcLock, 1)
       else:
diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim
index ee52b54f5..4e3dee51c 100644
--- a/lib/system/gc2.nim
+++ b/lib/system/gc2.nim
@@ -128,7 +128,7 @@ type
                              # cycle roots table that uses a cheap linear scan
                              # to find only possitively dead objects.
                              # One strategy is to perform it only for new objects
-                             # allocated between the invocations of CollectZCT.
+                             # allocated between the invocations of collectZCT.
                              # This index indicates the start of the range of
                              # such new objects within the table.
     when withRealTime:
@@ -140,7 +140,7 @@ var
   gch* {.rtlThreadVar.}: TGcHeap
 
 when not defined(useNimRtl):
-  InstantiateForRegion(gch.region)
+  instantiateForRegion(gch.region)
 
 template acquire(gch: TGcHeap) = 
   when hasThreadSupport and hasSharedHeap:
@@ -233,11 +233,11 @@ template addCycleRoot(cycleRoots: var TCellSeq, c: PCell) =
 
 proc cellToUsr(cell: PCell): pointer {.inline.} =
   # convert object (=pointer to refcount) to pointer to userdata
-  result = cast[pointer](cast[TAddress](cell)+%TAddress(sizeof(TCell)))
+  result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(TCell)))
 
 proc usrToCell*(usr: pointer): PCell {.inline.} =
   # convert pointer to userdata to object (=pointer to refcount)
-  result = cast[PCell](cast[TAddress](usr)-%TAddress(sizeof(TCell)))
+  result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
 
 proc canbeCycleRoot(c: PCell): bool {.inline.} =
   result = ntfAcyclic notin c.typ.flags
@@ -255,10 +255,10 @@ when BitsPerPage mod (sizeof(int)*8) != 0:
 
 # forward declarations:
 proc collectCT(gch: var TGcHeap)
-proc IsOnStack*(p: pointer): bool {.noinline.}
+proc isOnStack*(p: pointer): bool {.noinline.}
 proc forAllChildren(cell: PCell, op: TWalkOp)
 proc doOperation(p: pointer, op: TWalkOp)
-proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp)
+proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp)
 # we need the prototype here for debugging purposes
 
 proc prepareDealloc(cell: PCell) =
@@ -432,7 +432,7 @@ proc nimGCunrefNoCycle(p: pointer) {.compilerProc, inline.} =
     sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 2")
   sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 5")
 
-template doAsgnRef(dest: ppointer, src: pointer,
+template doAsgnRef(dest: PPointer, src: pointer,
                   heapType = LocalHeap, cycleFlag = MaybeCyclic): stmt =
   sysAssert(not isOnStack(dest), "asgnRef")
   # BUGFIX: first incRef then decRef!
@@ -440,20 +440,20 @@ template doAsgnRef(dest: ppointer, src: pointer,
   if dest[] != nil: doDecRef(usrToCell(dest[]), heapType, cycleFlag)
   dest[] = src
 
-proc asgnRef(dest: ppointer, src: pointer) {.compilerProc, inline.} =
+proc asgnRef(dest: PPointer, src: pointer) {.compilerProc, inline.} =
   # the code generator calls this proc!
   doAsgnRef(dest, src, LocalHeap, MaybeCyclic)
 
-proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerProc, inline.} =
+proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerProc, inline.} =
   # the code generator calls this proc if it is known at compile time that no 
   # cycle is possible.
   doAsgnRef(dest, src, LocalHeap, Acyclic)
 
-proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerProc.} =
+proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerProc.} =
   # unsureAsgnRef updates the reference counters only if dest is not on the
   # stack. It is used by the code generator if it cannot decide wether a
   # reference is in the stack or not (this can happen for var parameters).
-  if not IsOnStack(dest):
+  if not isOnStack(dest):
     if src != nil: doIncRef(usrToCell(src))
     # XXX we must detect a shared heap here
     # better idea may be to just eliminate the need for unsureAsgnRef
@@ -470,16 +470,16 @@ proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerProc.} =
 
 when hasThreadSupport and hasSharedHeap:
   # shared heap version of the above procs
-  proc asgnRefSh(dest: ppointer, src: pointer) {.compilerProc, inline.} =
+  proc asgnRefSh(dest: PPointer, src: pointer) {.compilerProc, inline.} =
     doAsgnRef(dest, src, SharedHeap, MaybeCyclic)
 
-  proc asgnRefNoCycleSh(dest: ppointer, src: pointer) {.compilerProc, inline.} =
+  proc asgnRefNoCycleSh(dest: PPointer, src: pointer) {.compilerProc, inline.} =
     doAsgnRef(dest, src, SharedHeap, Acyclic)
 
 proc initGC() =
   when not defined(useNimRtl):
     when traceGC:
-      for i in low(TCellState)..high(TCellState): Init(states[i])
+      for i in low(TCellState)..high(TCellState): init(states[i])
     gch.cycleThreshold = InitialCycleThreshold
     gch.stat.stackScans = 0
     gch.stat.cycleCollections = 0
@@ -491,11 +491,11 @@ proc initGC() =
     init(gch.zct)
     init(gch.tempStack)
     init(gch.freeStack)
-    Init(gch.cycleRoots)
-    Init(gch.decStack)
+    init(gch.cycleRoots)
+    init(gch.decStack)
 
 proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
-  var d = cast[TAddress](dest)
+  var d = cast[ByteAddress](dest)
   case n.kind
   of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
   of nkList:
@@ -503,7 +503,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
       # inlined for speed
       if n.sons[i].kind == nkSlot:
         if n.sons[i].typ.kind in {tyRef, tyString, tySequence}:
-          doOperation(cast[ppointer](d +% n.sons[i].offset)[], op)
+          doOperation(cast[PPointer](d +% n.sons[i].offset)[], op)
         else:
           forAllChildrenAux(cast[pointer](d +% n.sons[i].offset), 
                             n.sons[i].typ, op)
@@ -514,19 +514,19 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
     if m != nil: forAllSlotsAux(dest, m, op)
   of nkNone: sysAssert(false, "forAllSlotsAux")
 
-proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp) =
-  var d = cast[TAddress](dest)
+proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
+  var d = cast[ByteAddress](dest)
   if dest == nil: return # nothing to do
   if ntfNoRefs notin mt.flags:
-    case mt.Kind
+    case mt.kind
     of tyRef, tyString, tySequence: # leaf:
-      doOperation(cast[ppointer](d)[], op)
+      doOperation(cast[PPointer](d)[], op)
     of tyObject, tyTuple:
       forAllSlotsAux(dest, mt.node, op)
     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)
-    else: nil
+    else: discard
 
 proc forAllChildren(cell: PCell, op: TWalkOp) =
   sysAssert(cell != nil, "forAllChildren: 1")
@@ -536,18 +536,18 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
   if marker != nil:
     marker(cellToUsr(cell), op.int)
   else:
-    case cell.typ.Kind
+    case cell.typ.kind
     of tyRef: # common case
       forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
     of tySequence:
-      var d = cast[TAddress](cellToUsr(cell))
+      var d = cast[ByteAddress](cellToUsr(cell))
       var s = cast[PGenericSeq](d)
       if s != nil:
         let baseAddr = d +% GenericSeqSize
         for i in 0..s.len-1:
           forAllChildrenAux(cast[pointer](baseAddr +% i *% cell.typ.base.size),
                             cell.typ.base, op)
-    else: nil
+    else: discard
 
 proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
   # we check the last 8 entries (cache line) for a slot that could be reused.
@@ -593,7 +593,7 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
         return
     add(gch.zct, res)
 
-proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1: bool): pointer =
+proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1 = false): pointer =
   # generates a new object and sets its reference counter to 0
   acquire(gch)
   sysAssert(allocInv(gch.region), "rawNewObj begin")
@@ -605,7 +605,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1: bool): pointer =
   var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
   sysAssert(allocInv(gch.region), "rawNewObj after rawAlloc")
 
-  sysAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
+  sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
   
   res.typ = typ
   
@@ -634,8 +634,6 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1: bool): pointer =
   gcTrace(res, csAllocated)
   release(gch)
   result = cellToUsr(res)
-  zeroMem(result, size)
-  when defined(memProfiler): nimProfile(size)
   sysAssert(allocInv(gch.region), "rawNewObj end")
 
 {.pop.}
@@ -670,23 +668,31 @@ template trimAt(roots: var TCellSeq, at: int): stmt =
 proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
   setStackTop(gch)
   result = rawNewObj(typ, size, gch, false)
-  
+  zeroMem(result, size)
+  when defined(memProfiler): nimProfile(size)
+
+proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
+  setStackTop(gch)
+  result = rawNewObj(typ, size, gch, false)
+  when defined(memProfiler): nimProfile(size)
+
 proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
   setStackTop(gch)
-  # `rawNewObj` already uses locks, so no need for them here.
+  # `newObj` already uses locks, so no need for them here.
   let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
-  result = rawNewObj(typ, size, gch, false)
+  result = newObj(typ, size)
   cast[PGenericSeq](result).len = len
   cast[PGenericSeq](result).reserved = len
 
 proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
   setStackTop(gch)
   result = rawNewObj(typ, size, gch, true)
+  when defined(memProfiler): nimProfile(size)
 
 proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
   setStackTop(gch)
   let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
-  result = rawNewObj(typ, size, gch, true)
+  result = newObjRC1(typ, size)
   cast[PGenericSeq](result).len = len
   cast[PGenericSeq](result).reserved = len
 
@@ -708,10 +714,10 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
   # call user-defined move code
   # call user-defined default constructor
   copyMem(res, ol, oldsize + sizeof(TCell))
-  zeroMem(cast[pointer](cast[TAddress](res)+% oldsize +% sizeof(TCell)),
+  zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
           newsize-oldsize)
 
-  sysAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
+  sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
   sysAssert(res.refcount shr rcShift <=% 1, "growObj: 4")
   
   when false:
@@ -786,10 +792,10 @@ type
     FromChildren,
     FromRoot
 
-proc CollectZCT(gch: var TGcHeap): bool
+proc collectZCT(gch: var TGcHeap): bool
 
 template pseudoRecursion(typ: TRecursionType, body: stmt): stmt =
-  #
+  discard
 
 proc trimCycleRoots(gch: var TGcHeap, startIdx = gch.cycleRootsTrimIdx) =
   var i = startIdx
@@ -967,17 +973,17 @@ proc collectCycles(gch: var TGcHeap) =
       maybedeads,
       collected
 
-  Deinit(gch.cycleRoots)
-  Init(gch.cycleRoots)
+  deinit(gch.cycleRoots)
+  init(gch.cycleRoots)
 
-  Deinit(gch.freeStack)
-  Init(gch.freeStack)
+  deinit(gch.freeStack)
+  init(gch.freeStack)
 
   when MarkingSkipsAcyclicObjects:
     # Collect the acyclic objects that became unreachable due to collected
     # cyclic objects. 
-    discard CollectZCT(gch)
-    # CollectZCT may add new cycle candidates and we may decide to loop here
+    discard collectZCT(gch)
+    # collectZCT may add new cycle candidates and we may decide to loop here
     # if gch.cycleRoots.len > 0: repeat
 
 var gcDebugging* = false
@@ -988,7 +994,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
   # the addresses are not as cells on the stack, so turn them to cells:
   sysAssert(allocInv(gch.region), "gcMark begin")
   var cell = usrToCell(p)
-  var c = cast[TAddress](cell)
+  var c = cast[ByteAddress](cell)
   if c >% PageSize:
     # fast check: does it look like a cell?
     var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
@@ -997,6 +1003,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
       if objStart.color != rcReallyDead:
         if gcDebugging:
           # writeCell("marking ", objStart)
+          discard
         else:
           inc objStart.refcount, rcIncrement
           gch.decStack.add objStart
@@ -1009,6 +1016,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
         # coincidence due to the conservative stack marking.
         when debugGC:
           # writeCell("marking dead object", objStart)
+          discard
     when false:
       if isAllocatedPtr(gch.region, cell):
         sysAssert false, "allocated pointer but not interior?"
@@ -1024,12 +1032,12 @@ proc markThreadStacks(gch: var TGcHeap) =
     while it != nil:
       # mark registers: 
       for i in 0 .. high(it.registers): gcMark(gch, it.registers[i])
-      var sp = cast[TAddress](it.stackBottom)
-      var max = cast[TAddress](it.stackTop)
+      var sp = cast[ByteAddress](it.stackBottom)
+      var max = cast[ByteAddress](it.stackTop)
       # XXX stack direction?
       # XXX unroll this loop:
       while sp <=% max:
-        gcMark(gch, cast[ppointer](sp)[])
+        gcMark(gch, cast[PPointer](sp)[])
         sp = sp +% sizeof(pointer)
       it = it.next
 
@@ -1051,8 +1059,8 @@ when not defined(useNimRtl):
     # the first init must be the one that defines the stack bottom:
     if gch.stackBottom == nil: gch.stackBottom = theStackBottom
     else:
-      var a = cast[TAddress](theStackBottom) # and not PageMask - PageSize*2
-      var b = cast[TAddress](gch.stackBottom)
+      var a = cast[ByteAddress](theStackBottom) # and not PageMask - PageSize*2
+      var b = cast[ByteAddress](gch.stackBottom)
       #c_fprintf(c_stdout, "old: %p new: %p;\n",gch.stackBottom,theStackBottom)
       when stackIncreases:
         gch.stackBottom = cast[pointer](min(a, b))
@@ -1067,15 +1075,15 @@ proc stackSize(): int {.noinline.} =
 var
   jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
     # a little hack to get the size of a TJmpBuf in the generated C code
-    # in a platform independant way
+    # in a platform independent way
 
 when defined(sparc): # For SPARC architecture.
   proc isOnStack(p: pointer): bool =
     var stackTop {.volatile.}: pointer
     stackTop = addr(stackTop)
-    var b = cast[TAddress](gch.stackBottom)
-    var a = cast[TAddress](stackTop)
-    var x = cast[TAddress](p)
+    var b = cast[ByteAddress](gch.stackBottom)
+    var a = cast[ByteAddress](stackTop)
+    var x = cast[ByteAddress](p)
     result = a <=% x and x <=% b
 
   proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
@@ -1092,7 +1100,7 @@ when defined(sparc): # For SPARC architecture.
     # Addresses decrease as the stack grows.
     while sp <= max:
       gcMark(gch, sp[])
-      sp = cast[ppointer](cast[TAddress](sp) +% sizeof(pointer))
+      sp = cast[PPointer](cast[ByteAddress](sp) +% sizeof(pointer))
 
 elif defined(ELATE):
   {.error: "stack marking code is to be written for this architecture".}
@@ -1104,20 +1112,20 @@ elif stackIncreases:
   proc isOnStack(p: pointer): bool =
     var stackTop {.volatile.}: pointer
     stackTop = addr(stackTop)
-    var a = cast[TAddress](gch.stackBottom)
-    var b = cast[TAddress](stackTop)
-    var x = cast[TAddress](p)
+    var a = cast[ByteAddress](gch.stackBottom)
+    var b = cast[ByteAddress](stackTop)
+    var x = cast[ByteAddress](p)
     result = a <=% x and x <=% b
   
   proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
     var registers: C_JmpBuf
     if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
-      var max = cast[TAddress](gch.stackBottom)
-      var sp = cast[TAddress](addr(registers)) +% jmpbufSize -% sizeof(pointer)
+      var max = cast[ByteAddress](gch.stackBottom)
+      var sp = cast[ByteAddress](addr(registers)) +% jmpbufSize -% sizeof(pointer)
       # 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(gch, cast[ppointer](sp)[])
+        gcMark(gch, cast[PPointer](sp)[])
         sp = sp -% sizeof(pointer)
 
 else:
@@ -1127,9 +1135,9 @@ else:
   proc isOnStack(p: pointer): bool =
     var stackTop {.volatile.}: pointer
     stackTop = addr(stackTop)
-    var b = cast[TAddress](gch.stackBottom)
-    var a = cast[TAddress](stackTop)
-    var x = cast[TAddress](p)
+    var b = cast[ByteAddress](gch.stackBottom)
+    var a = cast[ByteAddress](stackTop)
+    var x = cast[ByteAddress](p)
     result = a <=% x and x <=% b
 
   proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
@@ -1141,18 +1149,18 @@ else:
     if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
       when MinimumStackMarking:
         # mark the registers
-        var jmpbufPtr = cast[TAddress](addr(registers))
+        var jmpbufPtr = cast[ByteAddress](addr(registers))
         var jmpbufEnd = jmpbufPtr +% jmpbufSize
       
         while jmpbufPtr <=% jmpbufEnd:
-          gcMark(gch, cast[ppointer](jmpbufPtr)[])
+          gcMark(gch, cast[PPointer](jmpbufPtr)[])
           jmpbufPtr = jmpbufPtr +% sizeof(pointer)
 
-        var sp = cast[TAddress](gch.stackTop)
+        var sp = cast[ByteAddress](gch.stackTop)
       else:
-        var sp = cast[TAddress](addr(registers))
+        var sp = cast[ByteAddress](addr(registers))
       # mark the user stack
-      var max = cast[TAddress](gch.stackBottom)
+      var max = cast[ByteAddress](gch.stackBottom)
       # loop unrolled:
       while sp <% max - 8*sizeof(pointer):
         gcMark(gch, cast[PStackSlice](sp)[0])
@@ -1166,7 +1174,7 @@ else:
         sp = sp +% sizeof(pointer)*8
       # last few entries:
       while sp <=% max:
-        gcMark(gch, cast[ppointer](sp)[])
+        gcMark(gch, cast[PPointer](sp)[])
         sp = sp +% sizeof(pointer)
 
 # ----------------------------------------------------------------------------
@@ -1202,7 +1210,7 @@ proc releaseCell(gch: var TGcHeap, cell: PCell) =
   #  recursion).
   # We can ignore it now as the ZCT cleaner will reach it soon.
 
-proc CollectZCT(gch: var TGcHeap): bool =
+proc collectZCT(gch: var TGcHeap): bool =
   const workPackage = 100
   var L = addr(gch.zct.len)
   
@@ -1213,8 +1221,8 @@ proc CollectZCT(gch: var TGcHeap): bool =
   
   while L[] > 0:
     var c = gch.zct.d[0]
-    sysAssert c.isBitUp(rcZct), "CollectZCT: rcZct missing!"
-    sysAssert(isAllocatedPtr(gch.region, c), "CollectZCT: isAllocatedPtr")
+    sysAssert c.isBitUp(rcZct), "collectZCT: rcZct missing!"
+    sysAssert(isAllocatedPtr(gch.region, c), "collectZCT: isAllocatedPtr")
     
     # remove from ZCT:    
     c.clearBit(rcZct)
@@ -1263,7 +1271,7 @@ proc unmarkStackAndRegisters(gch: var TGcHeap) =
     # XXX no need for an atomic dec here:
     if c.refcount--(LocalHeap):
       # the object survived only because of a stack reference
-      # it still doesn't have heap refernces
+      # it still doesn't have heap references
       addZCT(gch.zct, c)
     
     if canbeCycleRoot(c):
@@ -1295,7 +1303,7 @@ proc collectCTBody(gch: var TGcHeap) =
         sysAssert gch.zct.len == 0, "zct is not null after collect cycles"
         inc(gch.stat.cycleCollections)
         gch.cycleThreshold = max(InitialCycleThreshold, getOccupiedMem() *
-                                 cycleIncrease)
+                                 CycleIncrease)
         gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
   unmarkStackAndRegisters(gch)
   sysAssert(allocInv(gch.region), "collectCT: end")
@@ -1344,12 +1352,12 @@ when not defined(useNimRtl):
       else:
         dec(gch.recGcLock)
 
-  proc GC_setStrategy(strategy: TGC_Strategy) =
+  proc GC_setStrategy(strategy: GC_Strategy) =
     case strategy
-    of gcThroughput: nil
-    of gcResponsiveness: nil
-    of gcOptimizeSpace: nil
-    of gcOptimizeTime: nil
+    of gcThroughput: discard
+    of gcResponsiveness: discard
+    of gcOptimizeSpace: discard
+    of gcOptimizeTime: discard
 
   proc GC_enableMarkAndSweep() =
     gch.cycleThreshold = InitialCycleThreshold
diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim
index 242ca1608..e287bf5d9 100644
--- a/lib/system/gc_ms.nim
+++ b/lib/system/gc_ms.nim
@@ -1,19 +1,19 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
-# A simple mark&sweep garbage collector for Nim. Define the 
+# A simple mark&sweep garbage collector for Nim. Define the
 # symbol ``gcUseBitvectors`` to generate a variant of this GC.
 {.push profiler:off.}
 
 const
   InitialThreshold = 4*1024*1024 # X MB because marking&sweeping is slow
-  withBitvectors = defined(gcUseBitvectors) 
+  withBitvectors = defined(gcUseBitvectors)
   # bitvectors are significantly faster for GC-bench, but slower for
   # bootstrapping and use more memory
   rcWhite = 0
@@ -29,21 +29,21 @@ type
   TWalkOp = enum
     waMarkGlobal,  # we need to mark conservatively for global marker procs
                    # as these may refer to a global var and not to a thread
-                   # local 
+                   # local
     waMarkPrecise  # fast precise marking
 
   TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
     # A ref type can have a finalizer that is called before the object's
     # storage is freed.
-  
+
   TGlobalMarkerProc = proc () {.nimcall, benign.}
 
   TGcStat = object
     collections: int         # number of performed full collections
     maxThreshold: int        # max threshold that has been set
     maxStackSize: int        # max stack size
-    freedObjects: int        # max entries in cycle table  
-  
+    freedObjects: int        # max entries in cycle table
+
   TGcHeap = object           # this contains the zero count and
                              # non-zero count table
     stackBottom: pointer
@@ -64,11 +64,11 @@ var
 when not defined(useNimRtl):
   instantiateForRegion(gch.region)
 
-template acquire(gch: TGcHeap) = 
+template acquire(gch: TGcHeap) =
   when hasThreadSupport and hasSharedHeap:
     acquireSys(HeapLock)
 
-template release(gch: TGcHeap) = 
+template release(gch: TGcHeap) =
   when hasThreadSupport and hasSharedHeap:
     releaseSys(HeapLock)
 
@@ -134,7 +134,7 @@ proc prepareDealloc(cell: PCell) =
     (cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
     dec(gch.recGcLock)
 
-proc nimGCref(p: pointer) {.compilerProc.} = 
+proc nimGCref(p: pointer) {.compilerProc.} =
   # we keep it from being collected by pretending it's not even allocated:
   when false:
     when withBitvectors: excl(gch.allocated, usrToCell(p))
@@ -165,9 +165,23 @@ proc initGC() =
     init(gch.tempStack)
     init(gch.additionalRoots)
     when withBitvectors:
-      Init(gch.allocated)
+      init(gch.allocated)
       init(gch.marked)
 
+var
+  localGcInitialized {.rtlThreadVar.}: bool
+
+proc setupForeignThreadGc*() =
+  ## call this if you registered a callback that will be run from a thread not
+  ## under your control. This has a cheap thread-local guard, so the GC for
+  ## this thread will only be initialized once per thread, no matter how often
+  ## it is called.
+  if not localGcInitialized:
+    localGcInitialized = true
+    var stackTop {.volatile.}: pointer
+    setStackBottom(addr(stackTop))
+    initGC()
+
 proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
   var d = cast[ByteAddress](dest)
   case n.kind
@@ -247,6 +261,10 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
   zeroMem(result, size)
   when defined(memProfiler): nimProfile(size)
 
+proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
+  result = rawNewObj(typ, size, gch)
+  when defined(memProfiler): nimProfile(size)
+
 proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
   # `newObj` already uses locks, so no need for them here.
   let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
@@ -259,34 +277,36 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
   result = rawNewObj(typ, size, gch)
   zeroMem(result, size)
   when defined(memProfiler): nimProfile(size)
-  
+
 proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
   let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
   result = newObj(typ, size)
   cast[PGenericSeq](result).len = len
   cast[PGenericSeq](result).reserved = len
   when defined(memProfiler): nimProfile(size)
-  
+
 proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
   acquire(gch)
   collectCT(gch)
   var ol = usrToCell(old)
   sysAssert(ol.typ != nil, "growObj: 1")
   gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
-  
+
   var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
   var elemSize = 1
   if ol.typ.kind != tyString: elemSize = ol.typ.base.size
-  
+
   var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
   copyMem(res, ol, oldsize + sizeof(TCell))
   zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
           newsize-oldsize)
   sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
-  when withBitvectors: excl(gch.allocated, ol)
-  when reallyDealloc: rawDealloc(gch.region, ol)
-  else:
-    zeroMem(ol, sizeof(TCell))
+  when false:
+    # this is wrong since seqs can be shared via 'shallow':
+    when withBitvectors: excl(gch.allocated, ol)
+    when reallyDealloc: rawDealloc(gch.region, ol)
+    else:
+      zeroMem(ol, sizeof(TCell))
   when withBitvectors: incl(gch.allocated, res)
   when useCellIds:
     inc gch.idGenerator
@@ -385,7 +405,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
     var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
     if objStart != nil:
       mark(gch, objStart)
-  
+
 # ----------------- stack management --------------------------------------
 #  inspired from Smart Eiffel
 
@@ -460,7 +480,7 @@ elif stackIncreases:
   var
     jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
       # a little hack to get the size of a TJmpBuf in the generated C code
-      # in a platform independant way
+      # in a platform independent way
 
   proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
     var registers: C_JmpBuf
@@ -520,7 +540,7 @@ proc collectCTBody(gch: var TGcHeap) =
   markStackAndRegisters(gch)
   markGlobals(gch)
   sweep(gch)
-  
+
   inc(gch.stat.collections)
   when withBitvectors:
     deinit(gch.marked)
@@ -528,19 +548,19 @@ proc collectCTBody(gch: var TGcHeap) =
   gch.cycleThreshold = max(InitialThreshold, getOccupiedMem().mulThreshold)
   gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
   sysAssert(allocInv(gch.region), "collectCT: end")
-  
+
 proc collectCT(gch: var TGcHeap) =
   if getOccupiedMem(gch.region) >= gch.cycleThreshold and gch.recGcLock == 0:
     collectCTBody(gch)
 
 when not defined(useNimRtl):
-  proc GC_disable() = 
+  proc GC_disable() =
     when hasThreadSupport and hasSharedHeap:
       atomicInc(gch.recGcLock, 1)
     else:
       inc(gch.recGcLock)
   proc GC_enable() =
-    if gch.recGcLock > 0: 
+    if gch.recGcLock > 0:
       when hasThreadSupport and hasSharedHeap:
         atomicDec(gch.recGcLock, 1)
       else:
diff --git a/lib/system/hti.nim b/lib/system/hti.nim
index e599668a7..aff0c0e6f 100644
--- a/lib/system/hti.nim
+++ b/lib/system/hti.nim
@@ -11,7 +11,7 @@ when declared(NimString):
   # we are in system module:
   {.pragma: codegenType, compilerproc.}
 else:
-  {.pragma: codegenType.}
+  {.pragma: codegenType, importc.}
 
 type 
   # This should be he same as ast.TTypeKind
@@ -26,7 +26,7 @@ type
     tyExpr,
     tyStmt,
     tyTypeDesc,
-    tyGenericInvokation, # ``T[a, b]`` for types to invoke
+    tyGenericInvocation, # ``T[a, b]`` for types to invoke
     tyGenericBody,       # ``T[a, b, body]`` last parameter is the body
     tyGenericInst,       # ``T[a, b, realInstance]`` instantiated generic type
     tyGenericParam,      # ``a`` in the example
@@ -65,7 +65,7 @@ type
     tyBigNum,
 
   TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
-  TNimNode {.codegenType, final.} = object
+  TNimNode {.codegenType.} = object
     kind: TNimNodeKind
     offset: int
     typ: ptr TNimType
@@ -78,7 +78,7 @@ type
     ntfAcyclic = 1,    # type cannot form a cycle
     ntfEnumHole = 2    # enum has holes and thus `$` for them needs the slow
                        # version
-  TNimType {.codegenType, final.} = object
+  TNimType {.codegenType.} = object
     size: int
     kind: TNimKind
     flags: set[TNimTypeFlag]
diff --git a/lib/system/inclrtl.nim b/lib/system/inclrtl.nim
index aac802229..dbc961402 100644
--- a/lib/system/inclrtl.nim
+++ b/lib/system/inclrtl.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index 9b4a7d556..3b55f62ca 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -128,7 +128,7 @@ proc raiseOverflow {.exportc: "raiseOverflow", noreturn.} =
   raise newException(OverflowError, "over- or underflow")
 
 proc raiseDivByZero {.exportc: "raiseDivByZero", noreturn.} =
-  raise newException(DivByZeroError, "divison by zero")
+  raise newException(DivByZeroError, "division by zero")
 
 proc raiseRangeError() {.compilerproc, noreturn.} =
   raise newException(RangeError, "value out of range")
@@ -322,10 +322,10 @@ when defined(kwin):
       }
       print(buf);
     """
-    
+
 elif defined(nodejs):
   proc ewriteln(x: cstring) = log(x)
-  
+
   proc rawEcho {.compilerproc, asmNoStackFrame.} =
     asm """
       var buf = "";
@@ -339,12 +339,12 @@ else:
   var
     document {.importc, nodecl.}: ref TDocument
 
-  proc ewriteln(x: cstring) = 
+  proc ewriteln(x: cstring) =
     var node = document.getElementsByTagName("body")[0]
-    if node != nil: 
+    if node != nil:
       node.appendChild(document.createTextNode(x))
       node.appendChild(document.createElement("br"))
-    else: 
+    else:
       raise newException(ValueError, "<body> element does not exist yet!")
 
   proc rawEcho {.compilerproc.} =
@@ -563,7 +563,11 @@ proc nimCopy(x: pointer, ti: PNimType): pointer =
       }
     """
   of tyString:
-    asm "`result` = `x`.slice(0);"
+    asm """
+      if (`x` !== null) {
+        `result` = `x`.slice(0);
+      }
+    """
   else:
     result = x
 
@@ -679,7 +683,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start = 0): int {
   if s[i] == 'I' or s[i] == 'i':
     if s[i+1] == 'N' or s[i+1] == 'n':
       if s[i+2] == 'F' or s[i+2] == 'f':
-        if s[i+3] notin IdentChars: 
+        if s[i+3] notin IdentChars:
           number = Inf*sign
           return i+3 - start
     return 0
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index e091c0889..a378f86e7 100644
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2013 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -23,7 +23,7 @@ const
   leakDetector = false
   overwriteFree = false
   trackAllocationSource = leakDetector
-  
+
   cycleGC = true # (de)activate the cycle GC
   reallyDealloc = true # for debugging purposes this can be set to false
   reallyOsDealloc = true
@@ -71,13 +71,13 @@ when defined(boehmgc):
     const boehmLib = "libgc.dylib"
   else:
     const boehmLib = "/usr/lib/libgc.so.1"
-    
+
   proc boehmGCinit {.importc: "GC_init", dynlib: boehmLib.}
-  proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.} 
-  proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.} 
+  proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.}
+  proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.}
   proc boehmGCincremental {.
-    importc: "GC_enable_incremental", dynlib: boehmLib.} 
-  proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.}  
+    importc: "GC_enable_incremental", dynlib: boehmLib.}
+  proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.}
   proc boehmAlloc(size: int): pointer {.
     importc: "GC_malloc", dynlib: boehmLib.}
   proc boehmAllocAtomic(size: int): pointer {.
@@ -85,7 +85,7 @@ when defined(boehmgc):
   proc boehmRealloc(p: pointer, size: int): pointer {.
     importc: "GC_realloc", dynlib: boehmLib.}
   proc boehmDealloc(p: pointer) {.importc: "GC_free", dynlib: boehmLib.}
-  
+
   proc boehmGetHeapSize: int {.importc: "GC_get_heap_size", dynlib: boehmLib.}
     ## Return the number of bytes in the heap.  Excludes collector private
     ## data structures. Includes empty blocks and fragmentation loss.
@@ -108,25 +108,25 @@ when defined(boehmgc):
     zeroMem(result, size)
 
   when not defined(useNimRtl):
-    
-    proc alloc(size: int): pointer =
+
+    proc alloc(size: Natural): pointer =
       result = boehmAlloc(size)
       if result == nil: raiseOutOfMem()
-    proc alloc0(size: int): pointer =
+    proc alloc0(size: Natural): pointer =
       result = alloc(size)
       zeroMem(result, size)
-    proc realloc(p: pointer, newsize: int): pointer =
+    proc realloc(p: pointer, newsize: Natural): pointer =
       result = boehmRealloc(p, newsize)
       if result == nil: raiseOutOfMem()
     proc dealloc(p: pointer) = boehmDealloc(p)
-    
-    proc allocShared(size: int): pointer =
+
+    proc allocShared(size: Natural): pointer =
       result = boehmAlloc(size)
       if result == nil: raiseOutOfMem()
-    proc allocShared0(size: int): pointer =
+    proc allocShared0(size: Natural): pointer =
       result = alloc(size)
       zeroMem(result, size)
-    proc reallocShared(p: pointer, newsize: int): pointer =
+    proc reallocShared(p: pointer, newsize: Natural): pointer =
       result = boehmRealloc(p, newsize)
       if result == nil: raiseOutOfMem()
     proc deallocShared(p: pointer) = boehmDealloc(p)
@@ -144,18 +144,18 @@ when defined(boehmgc):
     proc GC_disable() = boehmGC_disable()
     proc GC_enable() = boehmGC_enable()
     proc GC_fullCollect() = boehmGCfullCollect()
-    proc GC_setStrategy(strategy: TGC_Strategy) = discard
+    proc GC_setStrategy(strategy: GC_Strategy) = discard
     proc GC_enableMarkAndSweep() = discard
     proc GC_disableMarkAndSweep() = discard
     proc GC_getStatistics(): string = return ""
-    
+
     proc getOccupiedMem(): int = return boehmGetHeapSize()-boehmGetFreeBytes()
     proc getFreeMem(): int = return boehmGetFreeBytes()
     proc getTotalMem(): int = return boehmGetHeapSize()
 
     proc setStackBottom(theStackBottom: pointer) = discard
 
-  proc initGC() = 
+  proc initGC() =
     when defined(macosx): boehmGCinit()
 
   proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
@@ -171,7 +171,7 @@ when defined(boehmgc):
 
   proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
   proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
-  
+
   proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
     dest[] = src
   proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
@@ -181,39 +181,39 @@ when defined(boehmgc):
 
   type
     TMemRegion = object {.final, pure.}
-  
+
   proc alloc(r: var TMemRegion, size: int): pointer =
     result = boehmAlloc(size)
     if result == nil: raiseOutOfMem()
   proc alloc0(r: var TMemRegion, size: int): pointer =
     result = alloc(size)
     zeroMem(result, size)
-  proc dealloc(r: var TMemRegion, p: pointer) = boehmDealloc(p)  
+  proc dealloc(r: var TMemRegion, p: pointer) = boehmDealloc(p)
   proc deallocOsPages(r: var TMemRegion) {.inline.} = discard
   proc deallocOsPages() {.inline.} = discard
 
   include "system/cellsets"
 elif defined(nogc) and defined(useMalloc):
-  
+
   when not defined(useNimRtl):
-    proc alloc(size: int): pointer =
+    proc alloc(size: Natural): pointer =
       result = cmalloc(size)
       if result == nil: raiseOutOfMem()
-    proc alloc0(size: int): pointer =
+    proc alloc0(size: Natural): pointer =
       result = alloc(size)
       zeroMem(result, size)
-    proc realloc(p: pointer, newsize: int): pointer =
+    proc realloc(p: pointer, newsize: Natural): pointer =
       result = crealloc(p, newsize)
       if result == nil: raiseOutOfMem()
     proc dealloc(p: pointer) = cfree(p)
-    
-    proc allocShared(size: int): pointer =
+
+    proc allocShared(size: Natural): pointer =
       result = cmalloc(size)
       if result == nil: raiseOutOfMem()
-    proc allocShared0(size: int): pointer =
+    proc allocShared0(size: Natural): pointer =
       result = alloc(size)
       zeroMem(result, size)
-    proc reallocShared(p: pointer, newsize: int): pointer =
+    proc reallocShared(p: pointer, newsize: Natural): pointer =
       result = crealloc(p, newsize)
       if result == nil: raiseOutOfMem()
     proc deallocShared(p: pointer) = cfree(p)
@@ -221,15 +221,15 @@ elif defined(nogc) and defined(useMalloc):
     proc GC_disable() = discard
     proc GC_enable() = discard
     proc GC_fullCollect() = discard
-    proc GC_setStrategy(strategy: TGC_Strategy) = discard
+    proc GC_setStrategy(strategy: GC_Strategy) = discard
     proc GC_enableMarkAndSweep() = discard
     proc GC_disableMarkAndSweep() = discard
     proc GC_getStatistics(): string = return ""
-    
+
     proc getOccupiedMem(): int = discard
     proc getFreeMem(): int = discard
     proc getTotalMem(): int = discard
-    
+
     proc setStackBottom(theStackBottom: pointer) = discard
 
   proc initGC() = discard
@@ -240,13 +240,15 @@ elif defined(nogc) and defined(useMalloc):
     result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
     cast[PGenericSeq](result).len = len
     cast[PGenericSeq](result).reserved = len
+  proc newObjNoInit(typ: PNimType, size: int): pointer =
+    result = alloc(size)
 
   proc growObj(old: pointer, newsize: int): pointer =
     result = realloc(old, newsize)
 
   proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
   proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
-  
+
   proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
     dest[] = src
   proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
@@ -256,7 +258,7 @@ elif defined(nogc) and defined(useMalloc):
 
   type
     TMemRegion = object {.final, pure.}
-  
+
   proc alloc(r: var TMemRegion, size: int): pointer =
     result = alloc(size)
   proc alloc0(r: var TMemRegion, size: int): pointer =
@@ -272,23 +274,27 @@ elif defined(nogc):
   # object, because C does not support this operation... Even though every
   # possible implementation has to have a way to determine the object's size.
   # C just sucks.
-  when appType == "lib": 
+  when appType == "lib":
     {.warning: "nogc in a library context may not work".}
-  
+
   include "system/alloc"
 
   proc initGC() = discard
   proc GC_disable() = discard
   proc GC_enable() = discard
   proc GC_fullCollect() = discard
-  proc GC_setStrategy(strategy: TGC_Strategy) = discard
+  proc GC_setStrategy(strategy: GC_Strategy) = discard
   proc GC_enableMarkAndSweep() = discard
   proc GC_disableMarkAndSweep() = discard
   proc GC_getStatistics(): string = return ""
-  
-  
+
+
   proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
     result = alloc0(size)
+
+  proc newObjNoInit(typ: PNimType, size: int): pointer =
+    result = alloc(size)
+
   proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
     result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
     cast[PGenericSeq](result).len = len
@@ -299,7 +305,7 @@ elif defined(nogc):
   proc setStackBottom(theStackBottom: pointer) = discard
   proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
   proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
-  
+
   proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
     dest[] = src
   proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
@@ -327,6 +333,6 @@ else:
     include "system/gc"
   else:
     include "system/gc"
-  
+
 {.pop.}
 
diff --git a/lib/system/platforms.nim b/lib/system/platforms.nim
index 3ec6a270e..47a01d5fe 100644
--- a/lib/system/platforms.nim
+++ b/lib/system/platforms.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
diff --git a/lib/system/profiler.nim b/lib/system/profiler.nim
index 96ab6abc7..6d6863caa 100644
--- a/lib/system/profiler.nim
+++ b/lib/system/profiler.nim
@@ -51,7 +51,7 @@ proc captureStackTrace(f: PFrame, st: var TStackTrace) =
 
 when defined(memProfiler):
   type
-    TMemProfilerHook* = proc (st: TStackTrace, requestedSize: int) {.nimcall.}
+    TMemProfilerHook* = proc (st: TStackTrace, requestedSize: int) {.nimcall, benign.}
   var
     profilerHook*: TMemProfilerHook
       ## set this variable to provide a procedure that implements a profiler in
diff --git a/lib/system/repr.nim b/lib/system/repr.nim
index 2de603cea..f1029ff6a 100644
--- a/lib/system/repr.nim
+++ b/lib/system/repr.nim
@@ -30,14 +30,16 @@ proc reprStrAux(result: var string, s: string) =
     add result, "nil"
     return
   add result, reprPointer(cast[pointer](s)) & "\""
-  for c in items(s):
+  for i in 0.. <s.len:
+    let c = s[i]
     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)
+    else:
+      result.add(c)
   add result, "\""
 
 proc reprStr(s: string): string {.compilerRtl.} =
@@ -78,7 +80,7 @@ proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
 type
   PByteArray = ptr array[0.. 0xffff, int8]
 
-proc addSetElem(result: var string, elem: int, typ: PNimType) {.gcsafe.} =
+proc addSetElem(result: var string, elem: int, typ: PNimType) {.benign.} =
   case typ.kind
   of tyEnum: add result, reprEnum(elem, typ)
   of tyBool: add result, reprBool(bool(elem))
@@ -147,7 +149,7 @@ when not defined(useNimRtl):
     for i in 0..cl.indent-1: add result, ' '
 
   proc reprAux(result: var string, p: pointer, typ: PNimType,
-               cl: var TReprClosure) {.gcsafe.}
+               cl: var TReprClosure) {.benign.}
 
   proc reprArray(result: var string, p: pointer, typ: PNimType,
                  cl: var TReprClosure) =
@@ -172,7 +174,7 @@ when not defined(useNimRtl):
     add result, "]"
 
   proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
-                     cl: var TReprClosure) {.gcsafe.} =
+                     cl: var TReprClosure) {.benign.} =
     case n.kind
     of nkNone: sysAssert(false, "reprRecordAux")
     of nkSlot:
diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim
index 7908fbe4d..3f860655e 100644
--- a/lib/system/sysio.nim
+++ b/lib/system/sysio.nim
@@ -16,7 +16,7 @@
                        # of the standard library!
 
 
-proc fputs(c: cstring, f: File) {.importc: "fputs", header: "<stdio.h>", 
+proc fputs(c: cstring, f: File) {.importc: "fputs", header: "<stdio.h>",
   tags: [WriteIOEffect].}
 proc fgets(c: cstring, n: int, f: File): cstring {.
   importc: "fgets", header: "<stdio.h>", tags: [ReadIOEffect].}
@@ -26,11 +26,30 @@ proc ungetc(c: cint, f: File) {.importc: "ungetc", header: "<stdio.h>",
   tags: [].}
 proc putc(c: char, stream: File) {.importc: "putc", header: "<stdio.h>",
   tags: [WriteIOEffect].}
-proc fprintf(f: File, frmt: cstring) {.importc: "fprintf", 
+proc fprintf(f: File, frmt: cstring) {.importc: "fprintf",
   header: "<stdio.h>", varargs, tags: [WriteIOEffect].}
 proc strlen(c: cstring): int {.
   importc: "strlen", header: "<string.h>", tags: [].}
 
+when defined(posix):
+  proc getc_unlocked(stream: File): cint {.importc: "getc_unlocked",
+    header: "<stdio.h>", tags: [ReadIOEffect].}
+
+  proc flockfile(stream: File) {.importc: "flockfile", header: "<stdio.h>",
+    tags: [ReadIOEffect].}
+
+  proc funlockfile(stream: File) {.importc: "funlockfile", header: "<stdio.h>",
+    tags: [ReadIOEffect].}
+elif false:
+  # doesn't work on Windows yet:
+  proc getc_unlocked(stream: File): cint {.importc: "_fgetc_nolock",
+    header: "<stdio.h>", tags: [ReadIOEffect].}
+
+  proc flockfile(stream: File) {.importc: "_lock_file", header: "<stdio.h>",
+    tags: [ReadIOEffect].}
+
+  proc funlockfile(stream: File) {.importc: "_unlock_file", header: "<stdio.h>",
+    tags: [ReadIOEffect].}
 
 # C routine that is used here:
 proc fread(buf: pointer, size, n: int, f: File): int {.
@@ -67,39 +86,57 @@ const
 proc raiseEIO(msg: string) {.noinline, noreturn.} =
   sysFatal(IOError, msg)
 
-proc readLine(f: File, line: var TaintedString): bool =
-  # 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
-  setLen(line.string, 0) # reuse the buffer!
-  while true:
-    var c = fgetc(f)
-    if c < 0'i32:
-      if line.len > 0: break
-      else: return false
-    if c == 10'i32: break # LF
-    if c == 13'i32:  # CR
-      c = fgetc(f) # is the next char LF?
-      if c != 10'i32: ungetc(c, f) # no, put the character back
-      break
-    add line.string, chr(int(c))
-  result = true
+when declared(getc_unlocked):
+  proc readLine(f: File, line: var TaintedString): bool =
+    setLen(line.string, 0) # reuse the buffer!
+    flockfile(f)
+    while true:
+      var c = getc_unlocked(f)
+      if c < 0'i32:
+        if line.len > 0: break
+        else: return false
+      if c == 10'i32: break # LF
+      if c == 13'i32:  # CR
+        c = getc_unlocked(f) # is the next char LF?
+        if c != 10'i32: ungetc(c, f) # no, put the character back
+        break
+      add line.string, chr(int(c))
+    result = true
+    funlockfile(f)
+else:
+  proc readLine(f: File, line: var TaintedString): bool =
+    # 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
+    setLen(line.string, 0) # reuse the buffer!
+    while true:
+      var c = fgetc(f)
+      if c < 0'i32:
+        if line.len > 0: break
+        else: return false
+      if c == 10'i32: break # LF
+      if c == 13'i32:  # CR
+        c = fgetc(f) # is the next char LF?
+        if c != 10'i32: ungetc(c, f) # no, put the character back
+        break
+      add line.string, chr(int(c))
+    result = true
 
 proc readLine(f: File): TaintedString =
   result = TaintedString(newStringOfCap(80))
   if not readLine(f, result): raiseEIO("EOF reached")
 
-proc write(f: File, i: int) = 
+proc write(f: File, i: int) =
   when sizeof(int) == 8:
     fprintf(f, "%lld", i)
   else:
     fprintf(f, "%ld", i)
 
-proc write(f: File, i: BiggestInt) = 
+proc write(f: File, i: BiggestInt) =
   when sizeof(BiggestInt) == 8:
     fprintf(f, "%lld", i)
   else:
     fprintf(f, "%ld", i)
-    
+
 proc write(f: File, b: bool) =
   if b: write(f, "true")
   else: write(f, "false")
@@ -110,7 +147,7 @@ proc write(f: File, c: char) = putc(c, f)
 proc write(f: File, a: varargs[string, `$`]) =
   for x in items(a): write(f, x)
 
-proc readAllBuffer(file: File): string = 
+proc readAllBuffer(file: File): string =
   # This proc is for File we want to read but don't know how many
   # bytes we need to read before the buffer is empty.
   result = ""
@@ -123,8 +160,8 @@ proc readAllBuffer(file: File): string =
       buffer.setLen(bytesRead)
       result.add(buffer)
       break
-  
-proc rawFileSize(file: File): int = 
+
+proc rawFileSize(file: File): int =
   # this does not raise an error opposed to `getFileSize`
   var oldPos = ftell(file)
   discard fseek(file, 0, 2) # seek the end of the file
@@ -132,7 +169,7 @@ proc rawFileSize(file: File): int =
   discard fseek(file, clong(oldPos), 0)
 
 proc readAllFile(file: File, len: int): string =
-  # We aquire the filesize beforehand and hope it doesn't change.
+  # We acquire the filesize beforehand and hope it doesn't change.
   # Speeds things up.
   result = newString(int(len))
   if readBuffer(file, addr(result[0]), int(len)) != len:
@@ -141,20 +178,20 @@ proc readAllFile(file: File, len: int): string =
 proc readAllFile(file: File): string =
   var len = rawFileSize(file)
   result = readAllFile(file, len)
-  
-proc readAll(file: File): TaintedString = 
+
+proc readAll(file: File): TaintedString =
   # Separate handling needed because we need to buffer when we
   # don't know the overall length of the File.
-  var len = rawFileSize(file)
-  if len >= 0:
+  let len = if file != stdin: rawFileSize(file) else: -1
+  if len > 0:
     result = readAllFile(file, len).TaintedString
   else:
     result = readAllBuffer(file).TaintedString
-  
+
 proc readFile(filename: string): TaintedString =
   var f = open(filename)
   try:
-    result = readAllFile(f).TaintedString
+    result = readAll(f).TaintedString
   finally:
     close(f)
 
@@ -183,11 +220,17 @@ proc rawEchoNL() {.inline, compilerproc.} = write(stdout, "\n")
 when (defined(windows) and not defined(useWinAnsi)) or defined(nimdoc):
   include "system/widestrs"
 
-when defined(windows) and not defined(useWinAnsi):  
-  proc wfopen(filename, mode: WideCString): pointer {.
-    importc: "_wfopen", nodecl.}
-  proc wfreopen(filename, mode: WideCString, stream: File): File {.
-    importc: "_wfreopen", nodecl.}
+when defined(windows) and not defined(useWinAnsi):
+  when defined(cpp):
+    proc wfopen(filename, mode: WideCString): pointer {.
+      importcpp: "_wfopen((const wchar_t*)#, (const wchar_t*)#)", nodecl.}
+    proc wfreopen(filename, mode: WideCString, stream: File): File {.
+      importcpp: "_wfreopen((const wchar_t*)#, (const wchar_t*)#, #)", nodecl.}
+  else:
+    proc wfopen(filename, mode: WideCString): pointer {.
+      importc: "_wfopen", nodecl.}
+    proc wfreopen(filename, mode: WideCString, stream: File): File {.
+      importc: "_wfreopen", nodecl.}
 
   proc fopen(filename, mode: cstring): pointer =
     var f = newWideCString(filename)
@@ -223,7 +266,7 @@ proc open(f: var File, filename: string,
     elif bufSize == 0:
       discard setvbuf(f, nil, IONBF, 0)
 
-proc reopen(f: File, filename: string, mode: FileMode = fmRead): bool = 
+proc reopen(f: File, filename: string, mode: FileMode = fmRead): bool =
   var p: pointer = freopen(filename, FormatOpen[mode], f)
   result = p != nil
 
@@ -237,23 +280,23 @@ proc open(f: var File, filehandle: FileHandle, mode: FileMode): bool =
 proc fwrite(buf: pointer, size, n: int, f: File): int {.
   importc: "fwrite", noDecl.}
 
-proc readBuffer(f: File, buffer: pointer, len: int): int =
+proc readBuffer(f: File, buffer: pointer, len: Natural): int =
   result = fread(buffer, 1, len, f)
 
-proc readBytes(f: File, a: var openArray[int8], start, len: int): int =
+proc readBytes(f: File, a: var openArray[int8|uint8], start, len: Natural): int =
   result = readBuffer(f, addr(a[start]), len)
 
-proc readChars(f: File, a: var openArray[char], start, len: int): int =
+proc readChars(f: File, a: var openArray[char], start, len: Natural): int =
   result = readBuffer(f, addr(a[start]), len)
 
 {.push stackTrace:off, profiler:off.}
-proc writeBytes(f: File, a: openArray[int8], start, len: int): int =
+proc writeBytes(f: File, a: openArray[int8|uint8], start, len: Natural): int =
   var x = cast[ptr array[0..1000_000_000, int8]](a)
   result = writeBuffer(f, addr(x[start]), len)
-proc writeChars(f: File, a: openArray[char], start, len: int): int =
+proc writeChars(f: File, a: openArray[char], start, len: Natural): int =
   var x = cast[ptr array[0..1000_000_000, int8]](a)
   result = writeBuffer(f, addr(x[start]), len)
-proc writeBuffer(f: File, buffer: pointer, len: int): int =
+proc writeBuffer(f: File, buffer: pointer, len: Natural): int =
   result = fwrite(buffer, 1, len, f)
 
 proc write(f: File, s: string) =
diff --git a/lib/system/sysspawn.nim b/lib/system/sysspawn.nim
index 04f30872d..6f45f1509 100644
--- a/lib/system/sysspawn.nim
+++ b/lib/system/sysspawn.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim
index 440d040a5..5b4020c8c 100644
--- a/lib/system/sysstr.nim
+++ b/lib/system/sysstr.nim
@@ -30,18 +30,30 @@ proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
   if a == b: return true
   if a == nil or b == nil: return false
   return a.len == b.len and
-    c_memcmp(a.data, b.data, a.len * sizeof(char)) == 0'i32
+    c_memcmp(a.data, b.data, a.len) == 0'i32
 
 when declared(allocAtomic):
   template allocStr(size: expr): expr =
     cast[NimString](allocAtomic(size))
+
+  template allocStrNoInit(size: expr): expr =
+    cast[NimString](boehmAllocAtomic(size))
 else:
   template allocStr(size: expr): expr =
     cast[NimString](newObj(addr(strDesc), size))
 
+  template allocStrNoInit(size: expr): expr =
+    cast[NimString](newObjNoInit(addr(strDesc), size))
+
+proc rawNewStringNoInit(space: int): NimString {.compilerProc.} =
+  var s = space
+  if s < 7: s = 7
+  result = allocStrNoInit(sizeof(TGenericSeq) + s + 1)
+  result.reserved = s
+
 proc rawNewString(space: int): NimString {.compilerProc.} =
   var s = space
-  if s < 8: s = 7
+  if s < 7: s = 7
   result = allocStr(sizeof(TGenericSeq) + s + 1)
   result.reserved = s
 
@@ -53,10 +65,10 @@ proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} =
   var start = max(start, 0)
   var len = min(last, s.len-1) - start + 1
   if len > 0:
-    result = rawNewString(len)
+    result = rawNewStringNoInit(len)
     result.len = len
-    c_memcpy(result.data, addr(s.data[start]), len * sizeof(char))
-    #result.data[len] = '\0'
+    c_memcpy(result.data, addr(s.data[start]), len)
+    result.data[len] = '\0'
   else:
     result = rawNewString(len)
 
@@ -64,10 +76,9 @@ proc copyStr(s: NimString, start: int): NimString {.compilerProc.} =
   result = copyStrLast(s, start, s.len-1)
 
 proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} =
-  result = rawNewString(len)
+  result = rawNewStringNoInit(len)
   result.len = len
-  c_memcpy(result.data, str, (len+1) * sizeof(char))
-  #result.data[len] = '\0' # readline relies on this!
+  c_memcpy(result.data, str, len + 1)
 
 proc cstrToNimstr(str: cstring): NimString {.compilerRtl.} =
   result = toNimStr(str, c_strlen(str))
@@ -77,23 +88,24 @@ proc copyString(src: NimString): NimString {.compilerRtl.} =
     if (src.reserved and seqShallowFlag) != 0:
       result = src
     else:
-      result = rawNewString(src.space)
+      result = rawNewStringNoInit(src.len)
       result.len = src.len
-      c_memcpy(result.data, src.data, (src.len + 1) * sizeof(char))
+      c_memcpy(result.data, src.data, src.len + 1)
 
 proc copyStringRC1(src: NimString): NimString {.compilerRtl.} =
   if src != nil:
-    var s = src.space
-    if s < 8: s = 7
     when declared(newObjRC1):
+      var s = src.len
+      if s < 7: s = 7
       result = cast[NimString](newObjRC1(addr(strDesc), sizeof(TGenericSeq) +
                                s+1))
+      result.reserved = s
     else:
-      result = allocStr(sizeof(TGenericSeq) + s + 1)
-    result.reserved = s
+      result = rawNewStringNoInit(src.len)
     result.len = src.len
     c_memcpy(result.data, src.data, src.len + 1)
 
+
 proc hashString(s: string): int {.compilerproc.} =
   # the compiler needs exactly the same hash function!
   # this used to be used for efficient generation of string case statements
@@ -113,7 +125,7 @@ proc addChar(s: NimString, c: char): NimString =
   if result.len >= result.space:
     result.reserved = resize(result.space)
     result = cast[NimString](growObj(result,
-      sizeof(TGenericSeq) + (result.reserved+1) * sizeof(char)))
+      sizeof(TGenericSeq) + result.reserved + 1))
   result.data[result.len] = c
   result.data[result.len+1] = '\0'
   inc(result.len)
@@ -157,7 +169,7 @@ proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} =
     result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1))
     result.reserved = sp
     #result = rawNewString(sp)
-    #copyMem(result, dest, dest.len * sizeof(char) + sizeof(TGenericSeq))
+    #copyMem(result, dest, dest.len + sizeof(TGenericSeq))
     # DO NOT UPDATE LEN YET: dest.len = newLen
 
 proc appendString(dest, src: NimString) {.compilerproc, inline.} =
@@ -203,12 +215,12 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
                                GenericSeqSize))
   elif newLen < result.len:
     # we need to decref here, otherwise the GC leaks!
-    when not defined(boehmGC) and not defined(nogc) and 
+    when not defined(boehmGC) and not defined(nogc) and
          not defined(gcMarkAndSweep):
       when compileOption("gc", "v2"):
         for i in newLen..result.len-1:
           let len0 = gch.tempStack.len
-          forAllChildrenAux(cast[pointer](cast[TAddress](result) +%
+          forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +%
                             GenericSeqSize +% (i*%elemSize)),
                             extGetCellType(result).base, waPush)
           let len1 = gch.tempStack.len
@@ -220,11 +232,11 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
           forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +%
                             GenericSeqSize +% (i*%elemSize)),
                             extGetCellType(result).base, waZctDecRef)
-      
+
     # XXX: zeroing out the memory can still result in crashes if a wiped-out
-    # cell is aliased by another pointer (ie proc paramter or a let variable).
+    # cell is aliased by another pointer (ie proc parameter or a let variable).
     # This is a tought problem, because even if we don't zeroMem here, in the
-    # presense of user defined destructors, the user will expect the cell to be
+    # presence of user defined destructors, the user will expect the cell to be
     # "destroyed" thus creating the same problem. We can destoy the cell in the
     # finalizer of the sequence, but this makes destruction non-deterministic.
     zeroMem(cast[pointer](cast[ByteAddress](result) +% GenericSeqSize +%
@@ -258,13 +270,23 @@ proc nimFloatToStr(f: float): string {.compilerproc.} =
     if buf[i] == ',':
       buf[i] = '.'
       hasDot = true
-    elif buf[i] in {'a'..'z', 'A'..'Z', '.'}: 
+    elif buf[i] in {'a'..'z', 'A'..'Z', '.'}:
       hasDot = true
   if not hasDot:
     buf[n] = '.'
     buf[n+1] = '0'
     buf[n+2] = '\0'
-  result = $buf
+  # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' are produced.
+  # We want to get rid of these here:
+  if buf[n-1] == 'N':
+    result = "nan"
+  elif buf[n-1] == 'F':
+    if buf[0] == '-':
+      result = "-inf"
+    else:
+      result = "inf"
+  else:
+    result = $buf
 
 proc strtod(buf: cstring, endptr: ptr cstring): float64 {.importc,
   header: "<stdlib.h>", noSideEffect.}
@@ -299,7 +321,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
   template addToBuf(c) =
     if ti < t.high:
       t[ti] = c; inc(ti)
-  
+
   # Sign?
   if s[i] == '+' or s[i] == '-':
     if s[i] == '-':
@@ -320,7 +342,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
   if s[i] == 'I' or s[i] == 'i':
     if s[i+1] == 'N' or s[i+1] == 'n':
       if s[i+2] == 'F' or s[i+2] == 'f':
-        if s[i+3] notin IdentChars: 
+        if s[i+3] notin IdentChars:
           number = Inf*sign
           return i+3 - start
     return 0
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index 496c31af1..d8e011ecb 100644
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -84,8 +84,18 @@ when defined(windows):
       importc: "TlsAlloc", stdcall, header: "<windows.h>".}
     proc threadVarSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
       importc: "TlsSetValue", stdcall, header: "<windows.h>".}
-    proc threadVarGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
+    proc tlsGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
       importc: "TlsGetValue", stdcall, header: "<windows.h>".}
+
+    proc getLastError(): uint32 {.
+      importc: "GetLastError", stdcall, header: "<windows.h>".}
+    proc setLastError(x: uint32) {.
+      importc: "SetLastError", stdcall, header: "<windows.h>".}
+
+    proc threadVarGetValue(dwTlsIndex: TThreadVarSlot): pointer =
+      let realLastError = getLastError()
+      result = tlsGetValue(dwTlsIndex)
+      setLastError(realLastError)
   else:
     proc threadVarAlloc(): TThreadVarSlot {.
       importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
@@ -95,7 +105,9 @@ when defined(windows):
       importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
   
 else:
-  {.passL: "-pthread".}
+  when not defined(macosx):
+    {.passL: "-pthread".}
+
   {.passC: "-pthread".}
 
   type
@@ -115,7 +127,7 @@ else:
     importc, header: "<pthread.h>".}
 
   proc pthread_create(a1: var TSysThread, a2: var TPthread_attr,
-            a3: proc (x: pointer) {.noconv.}, 
+            a3: proc (x: pointer): pointer {.noconv.}, 
             a4: pointer): cint {.importc: "pthread_create", 
             header: "<pthread.h>".}
   proc pthread_join(a1: TSysThread, a2: ptr pointer): cint {.
@@ -303,7 +315,7 @@ when defined(windows):
     threadProcWrapperBody(closure)
     # implicitly return 0
 else:
-  proc threadProcWrapper[TArg](closure: pointer) {.noconv.} = 
+  proc threadProcWrapper[TArg](closure: pointer): pointer {.noconv.} = 
     threadProcWrapperBody(closure)
 {.pop.}
 
diff --git a/lib/system/timers.nim b/lib/system/timers.nim
index e58ff7adc..e5de791ac 100644
--- a/lib/system/timers.nim
+++ b/lib/system/timers.nim
@@ -27,9 +27,9 @@ when defined(windows):
   proc `-`(a, b: TTicks): TNanos =
     var frequency: int64
     QueryPerformanceFrequency(frequency)
-    var performanceCounterRate = 1000000000.0 / toFloat(frequency.int)
+    var performanceCounterRate = 1e+9'f64 / float64(frequency)
 
-    result = ((a.int64 - b.int64).int.toFloat * performanceCounterRate).TNanos
+    result = TNanos(float64(a.int64 - b.int64) * performanceCounterRate)
 
 elif defined(macosx):
   type
diff --git a/lib/windows/windows.nim b/lib/windows/windows.nim
index f0895217b..b76dea6c5 100644
--- a/lib/windows/windows.nim
+++ b/lib/windows/windows.nim
@@ -11,7 +11,7 @@
 ## Unicode version.

 

 {.deadCodeElim: on.}

-

+{.push gcsafe.}

 type

   WideChar* = uint16

   PWideChar* = ptr uint16

@@ -11616,7 +11616,7 @@ type
     dwPageSize*: DWORD

     lpMinimumApplicationAddress*: LPVOID

     lpMaximumApplicationAddress*: LPVOID

-    dwActiveProcessorMask*: DWORD

+    dwActiveProcessorMask*: DWORD_PTR

     dwNumberOfProcessors*: DWORD

     dwProcessorType*: DWORD

     dwAllocationGranularity*: DWORD

@@ -23481,7 +23481,7 @@ proc ListView_EnsureVisible(hwndLV: HWND, i, fPartialOK: int32): LRESULT =
                        MAKELPARAM(fPartialOK, 0))

 

 proc ListView_FindItem(wnd: HWND, iStart: int32, lvfi: var LV_FINDINFO): int32 =

-  result = SendMessage(wnd, LVM_FINDITEM, WPARAM(iStart), 

+  result = SendMessage(wnd, LVM_FINDITEM, WPARAM(iStart),

                        cast[LPARAM](addr(lvfi))).int32

 

 proc ListView_GetBkColor(wnd: HWND): LRESULT =

@@ -23615,9 +23615,9 @@ proc ListView_SetTextBkColor(wnd: HWND, clrTextBk: COLORREF): LRESULT =
 proc ListView_SetTextColor(wnd: HWND, clrText: COLORREF): LRESULT =

   result = SendMessage(wnd, LVM_SETTEXTCOLOR, 0, LPARAM(clrText))

 

-proc ListView_SortItems(hwndLV: HWND, pfnCompare: PFNLVCOMPARE, 

+proc ListView_SortItems(hwndLV: HWND, pfnCompare: PFNLVCOMPARE,

                         lPrm: LPARAM): LRESULT =

-  result = SendMessage(hwndLV, LVM_SORTITEMS, WPARAM(lPrm), 

+  result = SendMessage(hwndLV, LVM_SORTITEMS, WPARAM(lPrm),

                        cast[LPARAM](pfnCompare))

 

 proc ListView_Update(hwndLV: HWND, i: int32): LRESULT =

@@ -23924,3 +23924,5 @@ proc LOCALE_NEUTRAL(): DWORD =
 

 proc LOCALE_INVARIANT(): DWORD =

   result = MAKELCID(MAKELANGID(toU16(LANG_INVARIANT), SUBLANG_NEUTRAL), SORT_DEFAULT)

+

+{.pop.}

diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 76d17bc4a..584f7cf48 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -284,6 +284,10 @@ when useWinUnicode:
                  bFailIfExists: cint): cint {.
     importc: "CopyFileW", stdcall, dynlib: "kernel32".}
 
+  proc moveFileW*(lpExistingFileName, lpNewFileName: WideCString,
+                 bFailIfExists: cint): cint {.
+    importc: "MoveFileW", stdcall, dynlib: "kernel32".}
+
   proc getEnvironmentStringsW*(): WideCString {.
     stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW".}
   proc freeEnvironmentStringsW*(para1: WideCString): int32 {.
@@ -308,6 +312,10 @@ else:
                  bFailIfExists: cint): cint {.
     importc: "CopyFileA", stdcall, dynlib: "kernel32".}
 
+  proc moveFileA*(lpExistingFileName, lpNewFileName: cstring,
+                 bFailIfExists: cint): cint {.
+    importc: "MoveFileA", stdcall, dynlib: "kernel32".}
+
   proc getEnvironmentStringsA*(): cstring {.
     stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsA".}
   proc freeEnvironmentStringsA*(para1: cstring): int32 {.
@@ -368,32 +376,32 @@ type
 {.deprecated: [TSocketHandle: SocketHandle].}
 
 type
-  WSAData* {.importc: "WSADATA", header: "Winsock2.h".} = object 
+  WSAData* {.importc: "WSADATA", header: "winsock2.h".} = object 
     wVersion, wHighVersion: int16
     szDescription: array[0..WSADESCRIPTION_LEN, char]
     szSystemStatus: array[0..WSASYS_STATUS_LEN, char]
     iMaxSockets, iMaxUdpDg: int16
     lpVendorInfo: cstring
     
-  SockAddr* {.importc: "SOCKADDR", header: "Winsock2.h".} = object 
+  SockAddr* {.importc: "SOCKADDR", header: "winsock2.h".} = object 
     sa_family*: int16 # unsigned
     sa_data: array[0..13, char]
 
-  InAddr* {.importc: "IN_ADDR", header: "Winsock2.h".} = object
+  InAddr* {.importc: "IN_ADDR", header: "winsock2.h".} = object
     s_addr*: int32  # IP address
   
   Sockaddr_in* {.importc: "SOCKADDR_IN", 
-                  header: "Winsock2.h".} = object
+                  header: "winsock2.h".} = object
     sin_family*: int16
     sin_port*: int16 # unsigned
     sin_addr*: InAddr
     sin_zero*: array[0..7, char]
 
-  In6_addr* {.importc: "IN6_ADDR", header: "Winsock2.h".} = object 
+  In6_addr* {.importc: "IN6_ADDR", header: "winsock2.h".} = object 
     bytes*: array[0..15, char]
 
   Sockaddr_in6* {.importc: "SOCKADDR_IN6", 
-                   header: "Winsock2.h".} = object
+                   header: "winsock2.h".} = object
     sin6_family*: int16
     sin6_port*: int16 # unsigned
     sin6_flowinfo*: int32 # unsigned
@@ -450,22 +458,22 @@ type
 
 
 var
-  SOMAXCONN* {.importc, header: "Winsock2.h".}: cint
-  INVALID_SOCKET* {.importc, header: "Winsock2.h".}: SocketHandle
-  SOL_SOCKET* {.importc, header: "Winsock2.h".}: cint
-  SO_DEBUG* {.importc, header: "Winsock2.h".}: cint ## turn on debugging info recording
-  SO_ACCEPTCONN* {.importc, header: "Winsock2.h".}: cint # socket has had listen()
-  SO_REUSEADDR* {.importc, header: "Winsock2.h".}: cint # allow local address reuse
-  SO_KEEPALIVE* {.importc, header: "Winsock2.h".}: cint # keep connections alive
-  SO_DONTROUTE* {.importc, header: "Winsock2.h".}: cint # just use interface addresses
-  SO_BROADCAST* {.importc, header: "Winsock2.h".}: cint # permit sending of broadcast msgs
-  SO_USELOOPBACK* {.importc, header: "Winsock2.h".}: cint # bypass hardware when possible
-  SO_LINGER* {.importc, header: "Winsock2.h".}: cint # linger on close if data present
-  SO_OOBINLINE* {.importc, header: "Winsock2.h".}: cint # leave received OOB data in line
-
-  SO_DONTLINGER* {.importc, header: "Winsock2.h".}: cint
-  SO_EXCLUSIVEADDRUSE* {.importc, header: "Winsock2.h".}: cint # disallow local address reuse
-  SO_ERROR* {.importc, header: "Winsock2.h".}: cint
+  SOMAXCONN* {.importc, header: "winsock2.h".}: cint
+  INVALID_SOCKET* {.importc, header: "winsock2.h".}: SocketHandle
+  SOL_SOCKET* {.importc, header: "winsock2.h".}: cint
+  SO_DEBUG* {.importc, header: "winsock2.h".}: cint ## turn on debugging info recording
+  SO_ACCEPTCONN* {.importc, header: "winsock2.h".}: cint # socket has had listen()
+  SO_REUSEADDR* {.importc, header: "winsock2.h".}: cint # allow local address reuse
+  SO_KEEPALIVE* {.importc, header: "winsock2.h".}: cint # keep connections alive
+  SO_DONTROUTE* {.importc, header: "winsock2.h".}: cint # just use interface addresses
+  SO_BROADCAST* {.importc, header: "winsock2.h".}: cint # permit sending of broadcast msgs
+  SO_USELOOPBACK* {.importc, header: "winsock2.h".}: cint # bypass hardware when possible
+  SO_LINGER* {.importc, header: "winsock2.h".}: cint # linger on close if data present
+  SO_OOBINLINE* {.importc, header: "winsock2.h".}: cint # leave received OOB data in line
+
+  SO_DONTLINGER* {.importc, header: "winsock2.h".}: cint
+  SO_EXCLUSIVEADDRUSE* {.importc, header: "winsock2.h".}: cint # disallow local address reuse
+  SO_ERROR* {.importc, header: "winsock2.h".}: cint
 
 proc `==`*(x, y: SocketHandle): bool {.borrow.}
 
diff --git a/lib/wrappers/claro.nim b/lib/wrappers/claro.nim
index fb06da818..0fb0882bf 100644
--- a/lib/wrappers/claro.nim
+++ b/lib/wrappers/claro.nim
@@ -64,7 +64,7 @@ proc node_move*(n: ptr TNode, oldlist: ptr TList, newlist: ptr TList){.
     cdecl, importc: "node_move", dynlib: clarodll.}

 

 type 

-  TClaroObj*{.pure.} = object 

+  TClaroObj*{.pure, inheritable.} = object 

     typ*: array[0..64 - 1, char]

     destroy_pending*: cint

     event_handlers*: TList

@@ -86,7 +86,7 @@ type
   TEventHandler*{.pure.} = object 

     typ*: array[0..32 - 1, char]

     data*: pointer

-    func*: TEventFunc   # the function that handles this event 

+    fun*: TEventFunc   # the function that handles this event 

   

 

 # #define event_handler(n) void n ( TClaroObj *object, event_t *event )

@@ -121,10 +121,10 @@ proc object_set_parent*(obj: ptr TClaroObj, parent: ptr TClaroObj){.cdecl,
 # event functions 

 

 proc object_addhandler*(obj: ptr TClaroObj, event: cstring, 

-                        func: TEventFunc){.cdecl, 

+                        fun: TEventFunc){.cdecl, 

     importc: "object_addhandler", dynlib: clarodll.}

 proc object_addhandler_interface*(obj: ptr TClaroObj, event: cstring, 

-                                  func: TEventFunc, data: pointer){.cdecl, 

+                                  fun: TEventFunc, data: pointer){.cdecl, 

     importc: "object_addhandler_interface", dynlib: clarodll.}

 proc event_send*(obj: ptr TClaroObj, event: cstring, fmt: cstring): cint{.

     varargs, cdecl, importc: "event_send", dynlib: clarodll.}

@@ -258,7 +258,7 @@ proc image_load_inline_png*(parent: ptr TClaroObj, data: cstring,
   ##  len size of data

 

 when true:

-  nil

+  discard

 else:

   # status icons are not supported on all platforms yet:

   type 

@@ -682,7 +682,7 @@ const
 type 

   TCanvas*{.pure.} = object of TWidget

     surface*: cairo.PSurface

-    cr*: Cairo.PContext

+    cr*: cairo.PContext

     surfdata*: pointer

     fontdata*: pointer

     font_height*: cint

@@ -854,7 +854,7 @@ proc canvas_cairo_buffered_text_display_count*(widget: ptr TCanvas,
     text: cstring, width: cint): cint{.cdecl, 

     importc: "canvas_cairo_buffered_text_display_count", 

     dynlib: clarodll.}

-proc canvas_get_cairo_context*(widget: ptr TCanvas): Cairo.PContext {.cdecl, 

+proc canvas_get_cairo_context*(widget: ptr TCanvas): cairo.PContext {.cdecl, 

     importc: "canvas_get_cairo_context", dynlib: clarodll.}

 

 type 

@@ -2710,7 +2710,7 @@ proc workspace_window_set_icon*(w: ptr TWorkspaceWindow, icon: ptr TImage){.
 claro_base_init()

 claro_graphics_init()

 

-when isMainModule:

+when not defined(testing) and isMainModule:

   var w = newWindow(nil, newBounds(100, 100, 230, 230), 0)

   window_set_title(w, "Hello, World!")

 

diff --git a/lib/wrappers/iup.nim b/lib/wrappers/iup.nim
index 6695dc5e2..93e14cccd 100644
--- a/lib/wrappers/iup.nim
+++ b/lib/wrappers/iup.nim
@@ -1,13 +1,13 @@
 #
 #    Binding for the IUP GUI toolkit
-#       (c) 2012 Andreas Rumpf 
+#       (c) 2012 Andreas Rumpf
 #    C header files translated by hand
 #    Licence of IUP follows:
 
 
 # ****************************************************************************
 # Copyright (C) 1994-2009 Tecgraf, PUC-Rio.
-# 
+#
 # Permission is hereby granted, free of charge, to any person obtaining
 # a copy of this software and associated documentation files (the
 # "Software"), to deal in the Software without restriction, including
@@ -30,12 +30,12 @@
 
 {.deadCodeElim: on.}
 
-when defined(windows): 
-  const dllname = "iup(30|27|26|25|24).dll"
+when defined(windows):
+  const dllname = "iup(|30|27|26|25|24).dll"
 elif defined(macosx):
-  const dllname = "libiup(3.0|2.7|2.6|2.5|2.4).dylib"
-else: 
-  const dllname = "libiup(3.0|2.7|2.6|2.5|2.4).so.1"
+  const dllname = "libiup(|3.0|2.7|2.6|2.5|2.4).dylib"
+else:
+  const dllname = "libiup(|3.0|2.7|2.6|2.5|2.4).so(|.1)"
 
 const
   IUP_NAME* = "IUP - Portable User Interface"
@@ -67,8 +67,8 @@ proc alarm*(title, msg, b1, b2, b3: cstring): cint {.
   importc: "IupAlarm", dynlib: dllname, cdecl.}
 proc scanf*(format: cstring): cint {.
   importc: "IupScanf", dynlib: dllname, cdecl, varargs.}
-proc listDialog*(theType: cint, title: cstring, size: cint, 
-                 list: cstringArray, op, maxCol, maxLin: cint, 
+proc listDialog*(theType: cint, title: cstring, size: cint,
+                 list: cstringArray, op, maxCol, maxLin: cint,
                  marks: ptr cint): cint {.
                  importc: "IupListDialog", dynlib: dllname, cdecl.}
 proc getText*(title, text: cstring): cint {.
@@ -77,14 +77,14 @@ proc getColor*(x, y: cint, r, g, b: var byte): cint {.
   importc: "IupGetColor", dynlib: dllname, cdecl.}
 
 type
-  Iparamcb* = proc (dialog: PIhandle, paramIndex: cint, 
+  Iparamcb* = proc (dialog: PIhandle, paramIndex: cint,
                     userData: pointer): cint {.cdecl.}
 
-proc getParam*(title: cstring, action: Iparamcb, userData: pointer, 
+proc getParam*(title: cstring, action: Iparamcb, userData: pointer,
                format: cstring): cint {.
                importc: "IupGetParam", cdecl, varargs, dynlib: dllname.}
-proc getParamv*(title: cstring, action: Iparamcb, userData: pointer, 
-                format: cstring, paramCount, paramExtra: cint, 
+proc getParamv*(title: cstring, action: Iparamcb, userData: pointer,
+                format: cstring, paramCount, paramExtra: cint,
                 paramData: pointer): cint {.
                 importc: "IupGetParamv", cdecl, dynlib: dllname.}
 
@@ -96,11 +96,11 @@ proc open*(argc: ptr cint, argv: ptr cstringArray): cint {.
 proc close*() {.importc: "IupClose", cdecl, dynlib: dllname.}
 proc imageLibOpen*() {.importc: "IupImageLibOpen", cdecl, dynlib: dllname.}
 
-proc mainLoop*(): cint {.importc: "IupMainLoop", cdecl, dynlib: dllname, 
+proc mainLoop*(): cint {.importc: "IupMainLoop", cdecl, dynlib: dllname,
                          discardable.}
 proc loopStep*(): cint {.importc: "IupLoopStep", cdecl, dynlib: dllname,
                          discardable.}
-proc mainLoopLevel*(): cint {.importc: "IupMainLoopLevel", cdecl, 
+proc mainLoopLevel*(): cint {.importc: "IupMainLoopLevel", cdecl,
                               dynlib: dllname, discardable.}
 proc flush*() {.importc: "IupFlush", cdecl, dynlib: dllname.}
 proc exitLoop*() {.importc: "IupExitLoop", cdecl, dynlib: dllname.}
@@ -202,15 +202,15 @@ proc nextField*(ih: PIhandle): PIhandle {.
 
 proc getCallback*(ih: PIhandle, name: cstring): Icallback {.
   importc: "IupGetCallback", cdecl, dynlib: dllname.}
-proc setCallback*(ih: PIhandle, name: cstring, func: Icallback): Icallback {.
+proc setCallback*(ih: PIhandle, name: cstring, fn: Icallback): Icallback {.
   importc: "IupSetCallback", cdecl, dynlib: dllname, discardable.}
-  
-proc setCallbacks*(ih: PIhandle, name: cstring, func: Icallback): PIhandle {.
+
+proc setCallbacks*(ih: PIhandle, name: cstring, fn: Icallback): PIhandle {.
   importc: "IupSetCallbacks", cdecl, dynlib: dllname, varargs, discardable.}
 
 proc getFunction*(name: cstring): Icallback {.
   importc: "IupGetFunction", cdecl, dynlib: dllname.}
-proc setFunction*(name: cstring, func: Icallback): Icallback {.
+proc setFunction*(name: cstring, fn: Icallback): Icallback {.
   importc: "IupSetFunction", cdecl, dynlib: dllname, discardable.}
 proc getActionName*(): cstring {.
   importc: "IupGetActionName", cdecl, dynlib: dllname.}
@@ -235,7 +235,7 @@ proc getClassName*(ih: PIhandle): cstring {.
   importc: "IupGetClassName", cdecl, dynlib: dllname.}
 proc getClassType*(ih: PIhandle): cstring {.
   importc: "IupGetClassType", cdecl, dynlib: dllname.}
-proc getClassAttributes*(classname: cstring, names: cstringArray, 
+proc getClassAttributes*(classname: cstring, names: cstringArray,
                          n: cint): cint {.
   importc: "IupGetClassAttributes", cdecl, dynlib: dllname.}
 proc saveClassAttributes*(ih: PIhandle) {.
@@ -378,12 +378,12 @@ const
   IUP_CONTINUE* = cint(-4)
 
   # IupPopup and IupShowXY Parameter Values
-  IUP_CENTER* = cint(0xFFFF) 
-  IUP_LEFT* = cint(0xFFFE) 
-  IUP_RIGHT* = cint(0xFFFD) 
-  IUP_MOUSEPOS* = cint(0xFFFC) 
-  IUP_CURRENT* = cint(0xFFFB) 
-  IUP_CENTERPARENT* = cint(0xFFFA) 
+  IUP_CENTER* = cint(0xFFFF)
+  IUP_LEFT* = cint(0xFFFE)
+  IUP_RIGHT* = cint(0xFFFD)
+  IUP_MOUSEPOS* = cint(0xFFFC)
+  IUP_CURRENT* = cint(0xFFFB)
+  IUP_CENTERPARENT* = cint(0xFFFA)
   IUP_TOP* = IUP_LEFT
   IUP_BOTTOM* = IUP_RIGHT
 
@@ -397,10 +397,10 @@ const
   # SCROLL_CB Callback Values
   IUP_SBUP* = cint(0)
   IUP_SBDN* = cint(1)
-  IUP_SBPGUP* = cint(2)   
+  IUP_SBPGUP* = cint(2)
   IUP_SBPGDN* = cint(3)
   IUP_SBPOSV* = cint(4)
-  IUP_SBDRAGV* = cint(5) 
+  IUP_SBDRAGV* = cint(5)
   IUP_SBLEFT* = cint(6)
   IUP_SBRIGHT* = cint(7)
   IUP_SBPGLEFT* = cint(8)
@@ -433,12 +433,12 @@ const
   IUP_MASK_EFLOAT* = "[+/-]?(/d+/.?/d*|/./d+)([eE][+/-]?/d+)?"
   IUP_MASK_INT* = "[+/-]?/d+"
   IUP_MASK_UINT* = "/d+"
-  
+
 # from 32 to 126, all character sets are equal,
 # the key code i the same as the character code.
 const
   K_SP* = cint(ord(' '))
-  K_exclam* = cint(ord('!'))   
+  K_exclam* = cint(ord('!'))
   K_quotedbl* = cint(ord('\"'))
   K_numbersign* = cint(ord('#'))
   K_dollar* = cint(ord('$'))
@@ -467,51 +467,51 @@ const
   K_semicolon* = cint(ord(';'))
   K_less* = cint(ord('<'))
   K_equal* = cint(ord('='))
-  K_greater* = cint(ord('>'))   
-  K_question* = cint(ord('?'))   
-  K_at* = cint(ord('@'))   
-  K_upperA* = cint(ord('A'))   
-  K_upperB* = cint(ord('B'))   
-  K_upperC* = cint(ord('C'))   
-  K_upperD* = cint(ord('D'))   
-  K_upperE* = cint(ord('E'))   
-  K_upperF* = cint(ord('F'))   
-  K_upperG* = cint(ord('G'))   
-  K_upperH* = cint(ord('H'))   
-  K_upperI* = cint(ord('I'))   
-  K_upperJ* = cint(ord('J'))   
-  K_upperK* = cint(ord('K'))   
-  K_upperL* = cint(ord('L'))   
-  K_upperM* = cint(ord('M'))   
-  K_upperN* = cint(ord('N'))   
-  K_upperO* = cint(ord('O'))   
-  K_upperP* = cint(ord('P'))   
-  K_upperQ* = cint(ord('Q'))  
-  K_upperR* = cint(ord('R'))  
-  K_upperS* = cint(ord('S'))  
-  K_upperT* = cint(ord('T'))  
-  K_upperU* = cint(ord('U'))  
-  K_upperV* = cint(ord('V')) 
-  K_upperW* = cint(ord('W')) 
-  K_upperX* = cint(ord('X'))  
-  K_upperY* = cint(ord('Y'))  
-  K_upperZ* = cint(ord('Z'))  
-  K_bracketleft* = cint(ord('[')) 
-  K_backslash* = cint(ord('\\'))  
-  K_bracketright* = cint(ord(']'))  
-  K_circum* = cint(ord('^'))   
-  K_underscore* = cint(ord('_'))   
-  K_grave* = cint(ord('`'))   
-  K_lowera* = cint(ord('a'))  
-  K_lowerb* = cint(ord('b'))   
-  K_lowerc* = cint(ord('c')) 
-  K_lowerd* = cint(ord('d'))   
-  K_lowere* = cint(ord('e'))   
-  K_lowerf* = cint(ord('f'))  
+  K_greater* = cint(ord('>'))
+  K_question* = cint(ord('?'))
+  K_at* = cint(ord('@'))
+  K_upperA* = cint(ord('A'))
+  K_upperB* = cint(ord('B'))
+  K_upperC* = cint(ord('C'))
+  K_upperD* = cint(ord('D'))
+  K_upperE* = cint(ord('E'))
+  K_upperF* = cint(ord('F'))
+  K_upperG* = cint(ord('G'))
+  K_upperH* = cint(ord('H'))
+  K_upperI* = cint(ord('I'))
+  K_upperJ* = cint(ord('J'))
+  K_upperK* = cint(ord('K'))
+  K_upperL* = cint(ord('L'))
+  K_upperM* = cint(ord('M'))
+  K_upperN* = cint(ord('N'))
+  K_upperO* = cint(ord('O'))
+  K_upperP* = cint(ord('P'))
+  K_upperQ* = cint(ord('Q'))
+  K_upperR* = cint(ord('R'))
+  K_upperS* = cint(ord('S'))
+  K_upperT* = cint(ord('T'))
+  K_upperU* = cint(ord('U'))
+  K_upperV* = cint(ord('V'))
+  K_upperW* = cint(ord('W'))
+  K_upperX* = cint(ord('X'))
+  K_upperY* = cint(ord('Y'))
+  K_upperZ* = cint(ord('Z'))
+  K_bracketleft* = cint(ord('['))
+  K_backslash* = cint(ord('\\'))
+  K_bracketright* = cint(ord(']'))
+  K_circum* = cint(ord('^'))
+  K_underscore* = cint(ord('_'))
+  K_grave* = cint(ord('`'))
+  K_lowera* = cint(ord('a'))
+  K_lowerb* = cint(ord('b'))
+  K_lowerc* = cint(ord('c'))
+  K_lowerd* = cint(ord('d'))
+  K_lowere* = cint(ord('e'))
+  K_lowerf* = cint(ord('f'))
   K_lowerg* = cint(ord('g'))
-  K_lowerh* = cint(ord('h')) 
-  K_loweri* = cint(ord('i')) 
-  K_lowerj* = cint(ord('j')) 
+  K_lowerh* = cint(ord('h'))
+  K_loweri* = cint(ord('i'))
+  K_lowerj* = cint(ord('j'))
   K_lowerk* = cint(ord('k'))
   K_lowerl* = cint(ord('l'))
   K_lowerm* = cint(ord('m'))
@@ -553,19 +553,19 @@ proc isAltXkey*(c: cint): bool = return c > 768 and c < 1024
 proc isSysXkey*(c: cint): bool = return c > 1024 and c < 1280
 
 proc iUPxCODE*(c: cint): cint = return c + cint(128) # Normal (must be above 128)
-proc iUPsxCODE*(c: cint): cint = 
+proc iUPsxCODE*(c: cint): cint =
   return c + cint(256)
-  # Shift (must have range to include the standard keys and the normal 
+  # Shift (must have range to include the standard keys and the normal
   # extended keys, so must be above 256
 
 proc iUPcxCODE*(c: cint): cint = return c + cint(512) # Ctrl
 proc iUPmxCODE*(c: cint): cint = return c + cint(768) # Alt
-proc iUPyxCODE*(c: cint): cint = return c + cint(1024) # Sys (Win or Apple) 
+proc iUPyxCODE*(c: cint): cint = return c + cint(1024) # Sys (Win or Apple)
 
 const
   IUP_NUMMAXCODES* = 1280 ## 5*256=1280  Normal+Shift+Ctrl+Alt+Sys
 
-  K_HOME* = iUPxCODE(1)                
+  K_HOME* = iUPxCODE(1)
   K_UP* = iUPxCODE(2)
   K_PGUP* = iUPxCODE(3)
   K_LEFT* = iUPxCODE(4)
@@ -574,8 +574,8 @@ const
   K_END* = iUPxCODE(7)
   K_DOWN* = iUPxCODE(8)
   K_PGDN* = iUPxCODE(9)
-  K_INS* = iUPxCODE(10)    
-  K_DEL* = iUPxCODE(11)    
+  K_INS* = iUPxCODE(10)
+  K_DEL* = iUPxCODE(11)
   K_PAUSE* = iUPxCODE(12)
   K_ESC* = iUPxCODE(13)
   K_ccedilla* = iUPxCODE(14)
@@ -728,13 +728,13 @@ const
   K_yPrint* = iUPyxCODE(K_Print)
   K_yMenu* = iUPyxCODE(K_Menu)
 
-  K_sPlus* = iUPsxCODE(K_plus)   
-  K_sComma* = iUPsxCODE(K_comma)   
-  K_sMinus* = iUPsxCODE(K_minus)   
-  K_sPeriod* = iUPsxCODE(K_period)   
-  K_sSlash* = iUPsxCODE(K_slash)   
+  K_sPlus* = iUPsxCODE(K_plus)
+  K_sComma* = iUPsxCODE(K_comma)
+  K_sMinus* = iUPsxCODE(K_minus)
+  K_sPeriod* = iUPsxCODE(K_period)
+  K_sSlash* = iUPsxCODE(K_slash)
   K_sAsterisk* = iUPsxCODE(K_asterisk)
-                        
+
   K_cupperA* = iUPcxCODE(K_upperA)
   K_cupperB* = iUPcxCODE(K_upperB)
   K_cupperC* = iUPcxCODE(K_upperC)
@@ -767,16 +767,16 @@ const
   K_c4* = iUPcxCODE(K_4)
   K_c5* = iUPcxCODE(K_5)
   K_c6* = iUPcxCODE(K_6)
-  K_c7* = iUPcxCODE(K_7)        
-  K_c8* = iUPcxCODE(K_8)         
+  K_c7* = iUPcxCODE(K_7)
+  K_c8* = iUPcxCODE(K_8)
   K_c9* = iUPcxCODE(K_9)
   K_c0* = iUPcxCODE(K_0)
-  K_cPlus* = iUPcxCODE(K_plus)   
-  K_cComma* = iUPcxCODE(K_comma)   
-  K_cMinus* = iUPcxCODE(K_minus)   
-  K_cPeriod* = iUPcxCODE(K_period)   
-  K_cSlash* = iUPcxCODE(K_slash)   
-  K_cSemicolon* = iUPcxCODE(K_semicolon) 
+  K_cPlus* = iUPcxCODE(K_plus)
+  K_cComma* = iUPcxCODE(K_comma)
+  K_cMinus* = iUPcxCODE(K_minus)
+  K_cPeriod* = iUPcxCODE(K_period)
+  K_cSlash* = iUPcxCODE(K_slash)
+  K_cSemicolon* = iUPcxCODE(K_semicolon)
   K_cEqual* = iUPcxCODE(K_equal)
   K_cBracketleft* = iUPcxCODE(K_bracketleft)
   K_cBracketright* = iUPcxCODE(K_bracketright)
@@ -815,16 +815,16 @@ const
   K_m4* = iUPmxCODE(K_4)
   K_m5* = iUPmxCODE(K_5)
   K_m6* = iUPmxCODE(K_6)
-  K_m7* = iUPmxCODE(K_7)        
-  K_m8* = iUPmxCODE(K_8)         
+  K_m7* = iUPmxCODE(K_7)
+  K_m8* = iUPmxCODE(K_8)
   K_m9* = iUPmxCODE(K_9)
   K_m0* = iUPmxCODE(K_0)
-  K_mPlus* = iUPmxCODE(K_plus)   
-  K_mComma* = iUPmxCODE(K_comma)   
-  K_mMinus* = iUPmxCODE(K_minus)   
-  K_mPeriod* = iUPmxCODE(K_period)   
-  K_mSlash* = iUPmxCODE(K_slash)   
-  K_mSemicolon* = iUPmxCODE(K_semicolon) 
+  K_mPlus* = iUPmxCODE(K_plus)
+  K_mComma* = iUPmxCODE(K_comma)
+  K_mMinus* = iUPmxCODE(K_minus)
+  K_mPeriod* = iUPmxCODE(K_period)
+  K_mSlash* = iUPmxCODE(K_slash)
+  K_mSemicolon* = iUPmxCODE(K_semicolon)
   K_mEqual* = iUPmxCODE(K_equal)
   K_mBracketleft* = iUPmxCODE(K_bracketleft)
   K_mBracketright* = iUPmxCODE(K_bracketright)
@@ -863,16 +863,16 @@ const
   K_y4* = iUPyxCODE(K_4)
   K_y5* = iUPyxCODE(K_5)
   K_y6* = iUPyxCODE(K_6)
-  K_y7* = iUPyxCODE(K_7)        
-  K_y8* = iUPyxCODE(K_8)         
+  K_y7* = iUPyxCODE(K_7)
+  K_y8* = iUPyxCODE(K_8)
   K_y9* = iUPyxCODE(K_9)
   K_y0* = iUPyxCODE(K_0)
   K_yPlus* = iUPyxCODE(K_plus)
   K_yComma* = iUPyxCODE(K_comma)
-  K_yMinus* = iUPyxCODE(K_minus)   
-  K_yPeriod* = iUPyxCODE(K_period)   
-  K_ySlash* = iUPyxCODE(K_slash)   
-  K_ySemicolon* = iUPyxCODE(K_semicolon) 
+  K_yMinus* = iUPyxCODE(K_minus)
+  K_yPeriod* = iUPyxCODE(K_period)
+  K_ySlash* = iUPyxCODE(K_slash)
+  K_ySemicolon* = iUPyxCODE(K_semicolon)
   K_yEqual* = iUPyxCODE(K_equal)
   K_yBracketleft* = iUPyxCODE(K_bracketleft)
   K_yBracketright* = iUPyxCODE(K_bracketright)
@@ -893,11 +893,11 @@ proc dial*(theType: cstring): PIhandle {.cdecl, importc: "IupDial", dynlib: dlln
 proc matrix*(action: cstring): PIhandle {.cdecl, importc: "IupMatrix", dynlib: dllname.}
 
 # IupMatrix utilities
-proc matSetAttribute*(ih: PIhandle, name: cstring, lin, col: cint, 
+proc matSetAttribute*(ih: PIhandle, name: cstring, lin, col: cint,
                       value: cstring) {.
                       cdecl, importc: "IupMatSetAttribute", dynlib: dllname.}
-proc matStoreAttribute*(ih: PIhandle, name: cstring, lin, col: cint, 
-                        value: cstring) {.cdecl, 
+proc matStoreAttribute*(ih: PIhandle, name: cstring, lin, col: cint,
+                        value: cstring) {.cdecl,
                         importc: "IupMatStoreAttribute", dynlib: dllname.}
 proc matGetAttribute*(ih: PIhandle, name: cstring, lin, col: cint): cstring {.
   cdecl, importc: "IupMatGetAttribute", dynlib: dllname.}
@@ -905,9 +905,9 @@ proc matGetInt*(ih: PIhandle, name: cstring, lin, col: cint): cint {.
   cdecl, importc: "IupMatGetInt", dynlib: dllname.}
 proc matGetFloat*(ih: PIhandle, name: cstring, lin, col: cint): cfloat {.
   cdecl, importc: "IupMatGetFloat", dynlib: dllname.}
-proc matSetfAttribute*(ih: PIhandle, name: cstring, lin, col: cint, 
-                       format: cstring) {.cdecl, 
-                       importc: "IupMatSetfAttribute", 
+proc matSetfAttribute*(ih: PIhandle, name: cstring, lin, col: cint,
+                       format: cstring) {.cdecl,
+                       importc: "IupMatSetfAttribute",
                        dynlib: dllname, varargs.}
 
 # Used by IupColorbar
@@ -931,10 +931,10 @@ proc pPlotAddStr*(ih: PIhandle, x: cstring, y: cfloat) {.
 proc pPlotEnd*(ih: PIhandle): cint {.
   cdecl, importc: "IupPPlotEnd", dynlib: dllname.}
 
-proc pPlotInsertStr*(ih: PIhandle, index, sampleIndex: cint, x: cstring, 
-                     y: cfloat) {.cdecl, importc: "IupPPlotInsertStr", 
+proc pPlotInsertStr*(ih: PIhandle, index, sampleIndex: cint, x: cstring,
+                     y: cfloat) {.cdecl, importc: "IupPPlotInsertStr",
                      dynlib: dllname.}
-proc pPlotInsert*(ih: PIhandle, index, sampleIndex: cint, 
+proc pPlotInsert*(ih: PIhandle, index, sampleIndex: cint,
                   x, y: cfloat) {.
                   cdecl, importc: "IupPPlotInsert", dynlib: dllname.}
 
diff --git a/lib/wrappers/libffi/msvc/win32.c b/lib/wrappers/libffi/msvc/win32.c
index d1149a85e..2754fd35d 100644
--- a/lib/wrappers/libffi/msvc/win32.c
+++ b/lib/wrappers/libffi/msvc/win32.c
@@ -90,7 +90,7 @@ noclean:
 
 // If the return value pointer is NULL, assume no return value.
 /*
-  Intel asm is weird. We have to explicitely specify 'DWORD PTR' in the nexr instruction,
+  Intel asm is weird. We have to explicitly specify 'DWORD PTR' in the nexr instruction,
   otherwise only one BYTE will be compared (instead of a DWORD)!
  */
 		cmp DWORD PTR [ebp + 24], 0
diff --git a/lib/wrappers/libuv.nim b/lib/wrappers/libuv.nim
index 3189ec408..a52ae0f63 100644
--- a/lib/wrappers/libuv.nim
+++ b/lib/wrappers/libuv.nim
@@ -30,9 +30,9 @@ type
   CheckProc* = proc (handle: PCheck, status: cint) {.cdecl.}
   IdleProc* = proc (handle: PIdle, status: cint) {.cdecl.}
 
-  PSockAddr* = ptr TSockAddr
+  PSockAddr* = ptr SockAddr
 
-  GetAddrInfoProc* = proc (handle: PGetAddrInfo, status: cint, res: ptr TAddrInfo)
+  GetAddrInfoProc* = proc (handle: PGetAddrInfo, status: cint, res: ptr AddrInfo)
 
   ExitProc* = proc (a2: PProcess, exit_status: cint, term_signal: cint)
   FsProc* = proc (req: PFS)
@@ -210,7 +210,7 @@ type
   cunsigned = int
 
   UdpSendProc* = proc (req: PUdpSend, status: cint)
-  UdpRecvProc* = proc (handle: PUdp, nread: cssize, buf: TBuf, adr: ptr TSockAddr, flags: cunsigned)
+  UdpRecvProc* = proc (handle: PUdp, nread: cssize, buf: TBuf, adr: ptr SockAddr, flags: cunsigned)
 
   TUdp* {.pure, final, importc: "uv_udp_t", header: "uv.h".} = object
     loop* {.importc: "loop".}: PLoop
@@ -366,7 +366,7 @@ type
     tcp_port* {.importc: "tcp_port".}: TPort
     socket_send_buffer_size* {.importc: "socket_send_buffer_size".}: int
     socket_recv_buffer_size* {.importc: "socket_receive_buffer_size".}: int
-    servers* {.importc: "servers".}: ptr TInAddr
+    servers* {.importc: "servers".}: ptr InAddr
     nservers* {.importc: "nservers".}: int
     domains* {.importc: "domains".}: ptr cstring
     ndomains* {.importc: "ndomains".}: int
@@ -450,19 +450,19 @@ proc write*(req: PWrite, handle: PStream, bufs: ptr TBuf, bufcnt: cint, send_han
 proc tcp_init*(a2: PLoop, handle: PTcp): cint{.
     importc: "uv_tcp_init", header: "uv.h".}
 
-proc tcp_bind*(handle: PTcp, a3: TSockAddrIn): cint{.
+proc tcp_bind*(handle: PTcp, a3: SockAddrIn): cint{.
     importc: "uv_tcp_bind", header: "uv.h".}
 
 proc tcp_bind6*(handle: PTcp, a3: TSockAddrIn6): cint{.
     importc: "uv_tcp_bind6", header: "uv.h".}
 
-proc tcp_getsockname*(handle: PTcp, name: ptr TSockAddr, namelen: var cint): cint{.
+proc tcp_getsockname*(handle: PTcp, name: ptr SockAddr, namelen: var cint): cint{.
     importc: "uv_tcp_getsockname", header: "uv.h".}
 
-proc tcp_getpeername*(handle: PTcp, name: ptr TSockAddr, namelen: var cint): cint{.
+proc tcp_getpeername*(handle: PTcp, name: ptr SockAddr, namelen: var cint): cint{.
     importc: "uv_tcp_getpeername", header: "uv.h".}
 
-proc tcp_connect*(req: PConnect, handle: PTcp, address: TSockAddrIn, cb: ConnectProc): cint{.
+proc tcp_connect*(req: PConnect, handle: PTcp, address: SockAddrIn, cb: ConnectProc): cint{.
     importc: "uv_tcp_connect", header: "uv.h".}
 
 proc tcp_connect6*(req: PConnect, handle: PTcp, address: TSockAddrIn6, cb: ConnectProc): cint{.
@@ -471,16 +471,16 @@ proc tcp_connect6*(req: PConnect, handle: PTcp, address: TSockAddrIn6, cb: Conne
 proc udp_init*(a2: PLoop, handle: PUdp): cint{.
     importc: "uv_udp_init", header: "uv.h".}
 
-proc udp_bind*(handle: PUdp, adr: TSockAddrIn, flags: cunsigned): cint{.
+proc udp_bind*(handle: PUdp, adr: SockAddrIn, flags: cunsigned): cint{.
     importc: "uv_udp_bind", header: "uv.h".}
 
 proc udp_bind6*(handle: PUdp, adr: TSockAddrIn6, flags: cunsigned): cint{.
     importc: "uv_udp_bind6", header: "uv.h".}
 
-proc udp_getsockname*(handle: PUdp, name: ptr TSockAddr, namelen: var cint): cint{.
+proc udp_getsockname*(handle: PUdp, name: ptr SockAddr, namelen: var cint): cint{.
     importc: "uv_udp_getsockname", header: "uv.h".}
 
-proc udp_send*(req: PUdpSend, handle: PUdp, bufs: ptr TBuf, bufcnt: cint, adr: TSockAddrIn, send_cb: UdpSendProc): cint{.
+proc udp_send*(req: PUdpSend, handle: PUdp, bufs: ptr TBuf, bufcnt: cint, adr: SockAddrIn, send_cb: UdpSendProc): cint{.
     importc: "uv_udp_send", header: "uv.h".}
 
 proc udp_send6*(req: PUdpSend, handle: PUdp, bufs: ptr TBuf, bufcnt: cint, adr: TSockAddrIn6, send_cb: UdpSendProc): cint{.
@@ -492,7 +492,7 @@ proc udp_recv_start*(handle: PUdp, alloc_cb: AllocProc, recv_cb: UdpRecvProc): c
 proc udp_recv_stop*(handle: PUdp): cint{.
     importc: "uv_udp_recv_stop", header: "uv.h".}
 
-proc tty_init*(a2: PLoop, a3: pTTy, fd: TFile): cint{.
+proc tty_init*(a2: PLoop, a3: pTTy, fd: File): cint{.
     importc: "uv_tty_init", header: "uv.h".}
 
 proc tty_set_mode*(a2: pTTy, mode: cint): cint{.
@@ -504,13 +504,13 @@ proc tty_get_winsize*(a2: pTTy, width: var cint, height: var cint): cint{.
 proc tty_reset_mode*() {.
     importc: "uv_tty_reset_mode", header: "uv.h".}
 
-proc guess_handle*(file: TFile): THandleType{.
+proc guess_handle*(file: File): THandleType{.
     importc: "uv_guess_handle", header: "uv.h".}
 
 proc pipe_init*(a2: PLoop, handle: PPipe, ipc: int): cint{.
     importc: "uv_pipe_init", header: "uv.h".}
 
-proc pipe_open*(a2: PPipe, file: TFile){.
+proc pipe_open*(a2: PPipe, file: File){.
     importc: "uv_pipe_open", header: "uv.h".}
 
 proc pipe_bind*(handle: PPipe, name: cstring): cint{.
@@ -576,10 +576,10 @@ proc ares_init_options*(a2: PLoop, channel: PAresChannel, options: PAresOptions,
 proc ares_destroy*(a2: PLoop, channel: PAresChannel){.
     importc: "uv_ares_destroy", header: "uv.h".}
 
-proc getaddrinfo*(a2: PLoop, handle: PGetAddrInfo,getaddrinfo_cb: GetAddrInfoProc, node: cstring, service: cstring, hints: ptr TAddrInfo): cint{.
+proc getaddrinfo*(a2: PLoop, handle: PGetAddrInfo,getaddrinfo_cb: GetAddrInfoProc, node: cstring, service: cstring, hints: ptr AddrInfo): cint{.
     importc: "uv_getaddrinfo", header: "uv.h".}
 
-proc freeaddrinfo*(ai: ptr TAddrInfo){.
+proc freeaddrinfo*(ai: ptr AddrInfo){.
     importc: "uv_freeaddrinfo", header: "uv.h".}
 
 proc spawn*(a2: PLoop, a3: PProcess, options: TProcessOptions): cint{.
@@ -594,19 +594,19 @@ proc queue_work*(loop: PLoop, req: PWork, work_cb: WorkProc, after_work_cb: Afte
 proc req_cleanup*(req: PFS){.
     importc: "uv_fs_req_cleanup", header: "uv.h".}
 
-proc close*(loop: PLoop, req: PFS, file: TFile, cb: FsProc): cint{.
+proc close*(loop: PLoop, req: PFS, file: File, cb: FsProc): cint{.
     importc: "uv_fs_close", header: "uv.h".}
 
 proc open*(loop: PLoop, req: PFS, path: cstring, flags: cint, mode: cint, cb: FsProc): cint{.
     importc: "uv_fs_open", header: "uv.h".}
 
-proc read*(loop: PLoop, req: PFS, file: TFile, buf: pointer, length: csize, offset: coff, cb: FsProc): cint{.
+proc read*(loop: PLoop, req: PFS, file: File, buf: pointer, length: csize, offset: coff, cb: FsProc): cint{.
     importc: "uv_fs_read", header: "uv.h".}
 
 proc unlink*(loop: PLoop, req: PFS, path: cstring, cb: FsProc): cint{.
     importc: "uv_fs_unlink", header: "uv.h".}
 
-proc write*(loop: PLoop, req: PFS, file: TFile, buf: pointer, length: csize, offset: coff, cb: FsProc): cint{.
+proc write*(loop: PLoop, req: PFS, file: File, buf: pointer, length: csize, offset: coff, cb: FsProc): cint{.
     importc: "uv_fs_write", header: "uv.h".}
 
 proc mkdir*(loop: PLoop, req: PFS, path: cstring, mode: cint, cb: FsProc): cint{.
@@ -621,22 +621,22 @@ proc readdir*(loop: PLoop, req: PFS, path: cstring, flags: cint, cb: FsProc): ci
 proc stat*(loop: PLoop, req: PFS, path: cstring, cb: FsProc): cint{.
     importc: "uv_fs_stat", header: "uv.h".}
 
-proc fstat*(loop: PLoop, req: PFS, file: TFile, cb: FsProc): cint{.
+proc fstat*(loop: PLoop, req: PFS, file: File, cb: FsProc): cint{.
     importc: "uv_fs_fstat", header: "uv.h".}
 
 proc rename*(loop: PLoop, req: PFS, path: cstring, new_path: cstring, cb: FsProc): cint{.
     importc: "uv_fs_rename", header: "uv.h".}
 
-proc fsync*(loop: PLoop, req: PFS, file: TFile, cb: FsProc): cint{.
+proc fsync*(loop: PLoop, req: PFS, file: File, cb: FsProc): cint{.
     importc: "uv_fs_fsync", header: "uv.h".}
 
-proc fdatasync*(loop: PLoop, req: PFS, file: TFile, cb: FsProc): cint{.
+proc fdatasync*(loop: PLoop, req: PFS, file: File, cb: FsProc): cint{.
     importc: "uv_fs_fdatasync", header: "uv.h".}
 
-proc ftruncate*(loop: PLoop, req: PFS, file: TFile, offset: coff, cb: FsProc): cint{.
+proc ftruncate*(loop: PLoop, req: PFS, file: File, offset: coff, cb: FsProc): cint{.
     importc: "uv_fs_ftruncate", header: "uv.h".}
 
-proc sendfile*(loop: PLoop, req: PFS, out_fd: TFile, in_fd: TFile, in_offset: coff, length: csize, cb: FsProc): cint{.
+proc sendfile*(loop: PLoop, req: PFS, out_fd: File, in_fd: File, in_offset: coff, length: csize, cb: FsProc): cint{.
     importc: "uv_fs_sendfile", header: "uv.h".}
 
 proc chmod*(loop: PLoop, req: PFS, path: cstring, mode: cint, cb: FsProc): cint{.
@@ -645,7 +645,7 @@ proc chmod*(loop: PLoop, req: PFS, path: cstring, mode: cint, cb: FsProc): cint{
 proc utime*(loop: PLoop, req: PFS, path: cstring, atime: cdouble, mtime: cdouble, cb: FsProc): cint{.
     importc: "uv_fs_utime", header: "uv.h".}
 
-proc futime*(loop: PLoop, req: PFS, file: TFile, atime: cdouble, mtime: cdouble, cb: FsProc): cint{.
+proc futime*(loop: PLoop, req: PFS, file: File, atime: cdouble, mtime: cdouble, cb: FsProc): cint{.
     importc: "uv_fs_futime", header: "uv.h".}
 
 proc lstat*(loop: PLoop, req: PFS, path: cstring, cb: FsProc): cint{.
@@ -660,25 +660,25 @@ proc symlink*(loop: PLoop, req: PFS, path: cstring, new_path: cstring, flags: ci
 proc readlink*(loop: PLoop, req: PFS, path: cstring, cb: FsProc): cint{.
     importc: "uv_fs_readlink", header: "uv.h".}
 
-proc fchmod*(loop: PLoop, req: PFS, file: TFile, mode: cint, cb: FsProc): cint{.
+proc fchmod*(loop: PLoop, req: PFS, file: File, mode: cint, cb: FsProc): cint{.
     importc: "uv_fs_fchmod", header: "uv.h".}
 
 proc chown*(loop: PLoop, req: PFS, path: cstring, uid: cint, gid: cint, cb: FsProc): cint{.
     importc: "uv_fs_chown", header: "uv.h".}
 
-proc fchown*(loop: PLoop, req: PFS, file: TFile, uid: cint, gid: cint, cb: FsProc): cint{.
+proc fchown*(loop: PLoop, req: PFS, file: File, uid: cint, gid: cint, cb: FsProc): cint{.
     importc: "uv_fs_fchown", header: "uv.h".}
 
 proc event_init*(loop: PLoop, handle: PFSEvent, filename: cstring, cb: FsEventProc): cint{.
     importc: "uv_fs_event_init", header: "uv.h".}
 
-proc ip4_addr*(ip: cstring, port: cint): TSockAddrIn{.
+proc ip4_addr*(ip: cstring, port: cint): SockAddrIn{.
     importc: "uv_ip4_addr", header: "uv.h".}
 
 proc ip6_addr*(ip: cstring, port: cint): TSockAddrIn6{.
     importc: "uv_ip6_addr", header: "uv.h".}
 
-proc ip4_name*(src: ptr TSockAddrIn, dst: cstring, size: csize): cint{.
+proc ip4_name*(src: ptr SockAddrIn, dst: cstring, size: csize): cint{.
     importc: "uv_ip4_name", header: "uv.h".}
 
 proc ip6_name*(src: ptr TSockAddrIn6, dst: cstring, size: csize): cint{.
diff --git a/lib/wrappers/mysql.nim b/lib/wrappers/mysql.nim
index 945e09ecf..937a8952a 100644
--- a/lib/wrappers/mysql.nim
+++ b/lib/wrappers/mysql.nim
@@ -10,11 +10,15 @@
 {.deadCodeElim: on.}
 {.push, callconv: cdecl.}
 
-when defined(Unix): 
-  const 
-    lib = "libmysqlclient.so.15"
-when defined(Windows): 
-  const 
+when defined(Unix):
+  when defined(macosx):
+    const
+      lib = "libmysqlclient.(15|16|17|18).dylib"
+  else:
+    const
+      lib = "libmysqlclient.so.(15|16|17|18)"
+when defined(Windows):
+  const
     lib = "libmysql.dll"
 type 
   my_bool* = bool
@@ -59,9 +63,9 @@ type
 const 
   SCRAMBLE_LENGTH* = 20 # Length of random string sent by server on handshake; 
                         # this is also length of obfuscated password, 
-                        # recieved from client
+                        # received from client
   SCRAMBLE_LENGTH_323* = 8    # length of password stored in the db: 
-                              # new passwords are preceeded with '*'  
+                              # new passwords are preceded with '*'  
   SCRAMBLED_PASSWORD_CHAR_LENGTH* = SCRAMBLE_LENGTH * 2 + 1
   SCRAMBLED_PASSWORD_CHAR_LENGTH_323* = SCRAMBLE_LENGTH_323 * 2
   NOT_NULL_FLAG* = 1          #  Field can't be NULL
@@ -142,7 +146,7 @@ const
   MAX_MEDIUMINT_WIDTH* = 8    # Max width for a INT24 w.o. sign
   MAX_INT_WIDTH* = 10         # Max width for a LONG w.o. sign
   MAX_BIGINT_WIDTH* = 20      # Max width for a LONGLONG
-  MAX_CHAR_WIDTH* = 255       # Max length for a CHAR colum
+  MAX_CHAR_WIDTH* = 255       # Max length for a CHAR column
   MAX_BLOB_WIDTH* = 8192      # Default width for blob
 
 type 
@@ -554,7 +558,7 @@ type
   Tstatus* = enum 
     STATUS_READY, STATUS_GET_RESULT, STATUS_USE_RESULT
   Tprotocol_type* = enum  # There are three types of queries - the ones that have to go to
-                          # the master, the ones that go to a slave, and the adminstrative
+                          # the master, the ones that go to a slave, and the administrative
                           # type which must happen on the pivot connectioin 
     PROTOCOL_DEFAULT, PROTOCOL_TCP, PROTOCOL_SOCKET, PROTOCOL_PIPE, 
     PROTOCOL_MEMORY
@@ -786,7 +790,7 @@ proc server_init*(argc: cint, argv: cstringArray, groups: cstringArray): cint{.
 proc server_end*(){.cdecl, dynlib: lib, importc: "mysql_server_end".}
   # mysql_server_init/end need to be called when using libmysqld or
   #      libmysqlclient (exactly, mysql_server_init() is called by mysql_init() so
-  #      you don't need to call it explicitely; but you need to call
+  #      you don't need to call it explicitly; but you need to call
   #      mysql_server_end() to free memory). The names are a bit misleading
   #      (mysql_SERVER* to be used when using libmysqlCLIENT). So we add more general
   #      names which suit well whether you're using libmysqld or libmysqlclient. We
diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim
index 6e85fb9dd..03729dbab 100644
--- a/lib/wrappers/openssl.nim
+++ b/lib/wrappers/openssl.nim
@@ -50,7 +50,7 @@ when useWinVersion:
   from winlean import SocketHandle
 else:
   const
-    versions = "(|.1.0.0|.0.9.9|.0.9.8|.0.9.7|.0.9.6|.0.9.5|.0.9.4)"
+    versions = "(.10|.1.0.1|.1.0.0|.0.9.9|.0.9.8)"
   when defined(macosx):
     const
       DLLSSLName = "libssl" & versions & ".dylib"
@@ -89,6 +89,8 @@ type
 {.deprecated: [PSSL: SslPtr, PSSL_CTX: SslCtx, PBIO: BIO].}
 
 const 
+  SSL_SENT_SHUTDOWN* = 1
+  SSL_RECEIVED_SHUTDOWN* = 2
   EVP_MAX_MD_SIZE* = 16 + 20
   SSL_ERROR_NONE* = 0
   SSL_ERROR_SSL* = 1
@@ -139,6 +141,14 @@ const
   SSL_CTRL_GET_MAX_CERT_LIST* = 50
   SSL_CTRL_SET_MAX_CERT_LIST* = 51 #* Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success
                                    # * when just a single record has been written): *
+  SSL_CTRL_SET_TLSEXT_SERVERNAME_CB = 53
+  SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG = 54
+  SSL_CTRL_SET_TLSEXT_HOSTNAME = 55
+  TLSEXT_NAMETYPE_host_name* = 0
+  SSL_TLSEXT_ERR_OK* = 0
+  SSL_TLSEXT_ERR_ALERT_WARNING* = 1
+  SSL_TLSEXT_ERR_ALERT_FATAL* = 2
+  SSL_TLSEXT_ERR_NOACK* = 3
   SSL_MODE_ENABLE_PARTIAL_WRITE* = 1 #* Make it possible to retry SSL_write() with changed buffer location
                                      # * (buffer contents must stay the same!); this is not the default to avoid
                                      # * the misconception that non-blocking SSL_write() behaves like
@@ -233,6 +243,8 @@ proc SSL_CTX_check_private_key*(ctx: SslCtx): cInt{.cdecl, dynlib: DLLSSLName,
 proc SSL_set_fd*(ssl: SslPtr, fd: SocketHandle): cint{.cdecl, dynlib: DLLSSLName, importc.}
 
 proc SSL_shutdown*(ssl: SslPtr): cInt{.cdecl, dynlib: DLLSSLName, importc.}
+proc SSL_set_shutdown*(ssl: SslPtr, mode: cint) {.cdecl, dynlib: DLLSSLName, importc: "SSL_set_shutdown".}
+proc SSL_get_shutdown*(ssl: SslPtr): cint {.cdecl, dynlib: DLLSSLName, importc: "SSL_get_shutdown".}
 proc SSL_connect*(ssl: SslPtr): cint{.cdecl, dynlib: DLLSSLName, importc.}
 proc SSL_read*(ssl: SslPtr, buf: pointer, num: int): cint{.cdecl, dynlib: DLLSSLName, importc.}
 proc SSL_write*(ssl: SslPtr, buf: cstring, num: int): cint{.cdecl, dynlib: DLLSSLName, importc.}
@@ -276,16 +288,57 @@ when not useWinVersion:
   proc CRYPTO_set_mem_functions(a,b,c: pointer){.cdecl, 
     dynlib: DLLUtilName, importc.}
 
+  proc allocWrapper(size: int): pointer {.cdecl.} = alloc(size)
+  proc reallocWrapper(p: pointer; newsize: int): pointer {.cdecl.} =
+    if p == nil:
+      if newSize > 0: result = alloc(newsize)
+    elif newsize == 0: dealloc(p)
+    else: result = realloc(p, newsize)
+  proc deallocWrapper(p: pointer) {.cdecl.} =
+    if p != nil: dealloc(p)
+
 proc CRYPTO_malloc_init*() =
-  when not useWinVersion:
-    CRYPTO_set_mem_functions(alloc, realloc, dealloc)
+  when not useWinVersion and not defined(macosx):
+    CRYPTO_set_mem_functions(allocWrapper, reallocWrapper, deallocWrapper)
 
 proc SSL_CTX_ctrl*(ctx: SslCtx, cmd: cInt, larg: int, parg: pointer): int{.
   cdecl, dynlib: DLLSSLName, importc.}
 
+proc SSL_CTX_callback_ctrl(ctx: SslCtx, typ: cInt, fp: PFunction): int{.
+  cdecl, dynlib: DLLSSLName, importc.}
+
 proc SSLCTXSetMode*(ctx: SslCtx, mode: int): int =
   result = SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, mode, nil)
 
+proc SSL_ctrl*(ssl: SslPtr, cmd: cInt, larg: int, parg: pointer): int{.
+  cdecl, dynlib: DLLSSLName, importc.}
+
+proc SSL_set_tlsext_host_name*(ssl: SslPtr, name: cstring): int =
+  result = SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, name)
+  ## Set the SNI server name extension to be used in a client hello.
+  ## Returns 1 if SNI was set, 0 if current SSL configuration doesn't support SNI.
+
+
+proc SSL_get_servername*(ssl: SslPtr, typ: cInt = TLSEXT_NAMETYPE_host_name): cstring {.cdecl, dynlib: DLLSSLName, importc.}
+  ## Retrieve the server name requested in the client hello. This can be used
+  ## in the callback set in `SSL_CTX_set_tlsext_servername_callback` to
+  ## implement virtual hosting. May return `nil`.
+
+proc SSL_CTX_set_tlsext_servername_callback*(ctx: SslCtx, cb: proc(ssl: SslPtr, cb_id: int, arg: pointer): int {.cdecl.}): int =
+  ## Set the callback to be used on listening SSL connections when the client hello is received.
+  ##
+  ## The callback should return one of:
+  ## * SSL_TLSEXT_ERR_OK
+  ## * SSL_TLSEXT_ERR_ALERT_WARNING
+  ## * SSL_TLSEXT_ERR_ALERT_FATAL
+  ## * SSL_TLSEXT_ERR_NOACK
+  result = SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, cast[PFunction](cb))
+
+proc SSL_CTX_set_tlsext_servername_arg*(ctx: SslCtx, arg: pointer): int =
+  ## Set the pointer to be used in the callback registered to ``SSL_CTX_set_tlsext_servername_callback``.
+  result = SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, arg)
+
+
 proc bioNew*(b: PBIO_METHOD): BIO{.cdecl, dynlib: DLLUtilName, importc: "BIO_new".}
 proc bioFreeAll*(b: BIO){.cdecl, dynlib: DLLUtilName, importc: "BIO_free_all".}
 proc bioSMem*(): PBIO_METHOD{.cdecl, dynlib: DLLUtilName, importc: "BIO_s_mem".}
@@ -314,6 +367,11 @@ proc sslDoHandshake*(ssl: SslPtr): cint {.cdecl,
     dynlib: DLLSSLName, importc: "SSL_do_handshake".}
 
 
+
+proc ErrClearError*(){.cdecl, dynlib: DLLUtilName, importc: "ERR_clear_error".}
+proc ErrFreeStrings*(){.cdecl, dynlib: DLLUtilName, importc: "ERR_free_strings".}
+proc ErrRemoveState*(pid: cInt){.cdecl, dynlib: DLLUtilName, importc: "ERR_remove_state".}
+
 when true:
   discard
 else:
@@ -323,8 +381,6 @@ else:
       dynlib: DLLSSLName, importc.}
 
   proc SslSetFd*(s: PSSL, fd: cInt): cInt{.cdecl, dynlib: DLLSSLName, importc.}
-  proc SslCtrl*(ssl: PSSL, cmd: cInt, larg: int, parg: Pointer): int{.cdecl, 
-      dynlib: DLLSSLName, importc.}
   proc SslCTXCtrl*(ctx: PSSL_CTX, cmd: cInt, larg: int, parg: Pointer): int{.
       cdecl, dynlib: DLLSSLName, importc.}
 
@@ -414,9 +470,7 @@ else:
     #  function ErrErrorString(e: cInt; buf: PChar): PChar;
   proc SSLeayversion*(t: cInt): cstring{.cdecl, dynlib: DLLUtilName, importc.}
 
-  proc ErrClearError*(){.cdecl, dynlib: DLLUtilName, importc.}
-  proc ErrFreeStrings*(){.cdecl, dynlib: DLLUtilName, importc.}
-  proc ErrRemoveState*(pid: cInt){.cdecl, dynlib: DLLUtilName, importc.}
+
   proc OPENSSLaddallalgorithms*(){.cdecl, dynlib: DLLUtilName, importc.}
   proc CRYPTOcleanupAllExData*(){.cdecl, dynlib: DLLUtilName, importc.}
   proc RandScreen*(){.cdecl, dynlib: DLLUtilName, importc.}
diff --git a/lib/wrappers/pcre.nim b/lib/wrappers/pcre.nim
index afa8f447a..67436f026 100644
--- a/lib/wrappers/pcre.nim
+++ b/lib/wrappers/pcre.nim
@@ -1,158 +1,190 @@
 #************************************************
-#       Perl-Compatible Regular Expressions      *
-#***********************************************
+#       Perl-Compatible Regular Expressions     *
+#************************************************
 # This is the public header file for the PCRE library, to be #included by
-#applications that call the PCRE functions.
+# applications that call the PCRE functions.
 #
-#           Copyright (c) 1997-2010 University of Cambridge
+#           Copyright (c) 1997-2014 University of Cambridge
 #
 #-----------------------------------------------------------------------------
-#Redistribution and use in source and binary forms, with or without
-#modification, are permitted provided that the following conditions are met:
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
 #
-#     Redistributions of source code must retain the above copyright notice,
+#    * Redistributions of source code must retain the above copyright notice,
 #      this list of conditions and the following disclaimer.
 #
-#     Redistributions in binary form must reproduce the above copyright
+#    * Redistributions in binary form must reproduce the above copyright
 #      notice, this list of conditions and the following disclaimer in the
 #      documentation and/or other materials provided with the distribution.
 #
-#     Neither the name of the University of Cambridge nor the names of its
+#    * Neither the name of the University of Cambridge nor the names of its
 #      contributors may be used to endorse or promote products derived from
 #      this software without specific prior written permission.
 #
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-#ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-#LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-#CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-#SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-#INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-#CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-#ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-#POSSIBILITY OF SUCH DAMAGE.
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
 #-----------------------------------------------------------------------------
-#
 
-{.deadcodeElim: on.}
-
-when not defined(pcreDll):
-  when hostOS == "windows":
-    const pcreDll = "pcre.dll"
-  elif hostOS == "macosx":
-    const pcreDll = "libpcre(.3|.1|).dylib"
-  else:
-    const pcreDll = "libpcre.so(.3|.1|)"
-  {.pragma: pcreImport, dynlib: pcreDll.}
-else:
-  {.pragma: pcreImport, header: "<pcre.h>".}
+{.deadCodeElim: on.}
 
-# The current PCRE version information. 
+# The current PCRE version information.
 
-const 
-  MAJOR* = 8
-  MINOR* = 31
-  PRERELEASE* = true
-  DATE* = "2012-07-06"
+const
+  PCRE_MAJOR* = 8
+  PCRE_MINOR* = 36
+  PCRE_PRERELEASE* = true
+  PCRE_DATE* = "2014-09-26"
 
 # When an application links to a PCRE DLL in Windows, the symbols that are
 # imported have to be identified as such. When building PCRE, the appropriate
 # export setting is defined in pcre_internal.h, which includes this file. So we
-# don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL. 
-
-# Have to include stdlib.h in order to ensure that size_t is defined;
-# it is needed here for malloc. 
-
-# Allow for C++ users 
-
-# Options. Some are compile-time only, some are run-time only, and some are
-# both, so we keep them all distinct. 
-
-const 
-  CASELESS* = 0x00000001
-  MULTILINE* = 0x00000002
-  DOTALL* = 0x00000004
-  EXTENDED* = 0x00000008
-  ANCHORED* = 0x00000010
-  DOLLAR_ENDONLY* = 0x00000020
-  EXTRA* = 0x00000040
-  NOTBOL* = 0x00000080
-  NOTEOL* = 0x00000100
-  UNGREEDY* = 0x00000200
-  NOTEMPTY* = 0x00000400
-  UTF8* = 0x00000800
-  NO_AUTO_CAPTURE* = 0x00001000
-  NO_UTF8_CHECK* = 0x00002000
-  AUTO_CALLOUT* = 0x00004000
-  PARTIAL_SOFT* = 0x00008000
-  PARTIAL* = 0x00008000       # Backwards compatible synonym 
-  DFA_SHORTEST* = 0x00010000
-  DFA_RESTART* = 0x00020000
-  FIRSTLINE* = 0x00040000
-  DUPNAMES* = 0x00080000
-  NEWLINE_CR* = 0x00100000
-  NEWLINE_LF* = 0x00200000
-  NEWLINE_CRLF* = 0x00300000
-  NEWLINE_ANY* = 0x00400000
-  NEWLINE_ANYCRLF* = 0x00500000
-  BSR_ANYCRLF* = 0x00800000
-  BSR_UNICODE* = 0x01000000
-  JAVASCRIPT_COMPAT* = 0x02000000
-  NO_START_OPTIMIZE* = 0x04000000
-  NO_START_OPTIMISE* = 0x04000000
-  PARTIAL_HARD* = 0x08000000
-  NOTEMPTY_ATSTART* = 0x10000000
-  UCP* = 0x20000000
-
-# Exec-time and get/set-time error codes 
-
-const 
-  ERROR_NOMATCH* = (- 1)
-  ERROR_NULL* = (- 2)
-  ERROR_BADOPTION* = (- 3)
-  ERROR_BADMAGIC* = (- 4)
-  ERROR_UNKNOWN_OPCODE* = (- 5)
-  ERROR_UNKNOWN_NODE* = (- 5) # For backward compatibility 
-  ERROR_NOMEMORY* = (- 6)
-  ERROR_NOSUBSTRING* = (- 7)
-  ERROR_MATCHLIMIT* = (- 8)
-  ERROR_CALLOUT* = (- 9)      # Never used by PCRE itself 
-  ERROR_BADUTF8* = (- 10)
-  ERROR_BADUTF8_OFFSET* = (- 11)
-  ERROR_PARTIAL* = (- 12)
-  ERROR_BADPARTIAL* = (- 13)
-  ERROR_INTERNAL* = (- 14)
-  ERROR_BADCOUNT* = (- 15)
-  ERROR_DFA_UITEM* = (- 16)
-  ERROR_DFA_UCOND* = (- 17)
-  ERROR_DFA_UMLIMIT* = (- 18)
-  ERROR_DFA_WSSIZE* = (- 19)
-  ERROR_DFA_RECURSE* = (- 20)
-  ERROR_RECURSIONLIMIT* = (- 21)
-  ERROR_NULLWSLIMIT* = (- 22) # No longer actually used 
-  ERROR_BADNEWLINE* = (- 23)
-  ERROR_BADOFFSET* = (- 24)
-  ERROR_SHORTUTF8* = (- 25)
-  ERROR_RECURSELOOP* = (- 26)
-  ERROR_JIT_STACKLIMIT* = (- 27)
-  ERROR_BADMODE* = (- 28)
-  ERROR_BADENDIANNESS* = (- 29)
-  ERROR_DFA_BADRESTART* = (- 30)
-
-# Specific error codes for UTF-8 validity checks
+# don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL.
+
+# By default, we use the standard "extern" declarations.
+
+# Allow for C++ users
+
+# Public options. Some are compile-time only, some are run-time only, and some
+# are both. Most of the compile-time options are saved with the compiled regex
+# so that they can be inspected during studying (and therefore JIT compiling).
+# Note that pcre_study() has its own set of options. Originally, all the options
+# defined here used distinct bits. However, almost all the bits in a 32-bit word
+# are now used, so in order to conserve them, option bits that were previously
+# only recognized at matching time (i.e. by pcre_exec() or pcre_dfa_exec()) may
+# also be used for compile-time options that affect only compiling and are not
+# relevant for studying or JIT compiling.
+#
+# Some options for pcre_compile() change its behaviour but do not affect the
+# behaviour of the execution functions. Other options are passed through to the
+# execution functions and affect their behaviour, with or without affecting the
+# behaviour of pcre_compile().
+#
+# Options that can be passed to pcre_compile() are tagged Cx below, with these
+# variants:
+#
+# C1   Affects compile only
+# C2   Does not affect compile; affects exec, dfa_exec
+# C3   Affects compile, exec, dfa_exec
+# C4   Affects compile, exec, dfa_exec, study
+# C5   Affects compile, exec, study
+#
+# Options that can be set for pcre_exec() and/or pcre_dfa_exec() are flagged 
+# with E and D, respectively. They take precedence over C3, C4, and C5 settings 
+# passed from pcre_compile(). Those that are compatible with JIT execution are 
+# flagged with J.
+
+const
+  CASELESS*          = 0x00000001  # C1
+  MULTILINE*         = 0x00000002  # C1
+  DOTALL*            = 0x00000004  # C1
+  EXTENDED*          = 0x00000008  # C1
+  ANCHORED*          = 0x00000010  # C4 E D
+  DOLLAR_ENDONLY*    = 0x00000020  # C2
+  EXTRA*             = 0x00000040  # C1
+  NOTBOL*            = 0x00000080  #    E D J
+  NOTEOL*            = 0x00000100  #    E D J
+  UNGREEDY*          = 0x00000200  # C1
+  NOTEMPTY*          = 0x00000400  #    E D J
+  UTF8*              = 0x00000800  # C4        )
+  UTF16*             = 0x00000800  # C4        ) Synonyms
+  UTF32*             = 0x00000800  # C4        )
+  NO_AUTO_CAPTURE*   = 0x00001000  # C1
+  NO_UTF8_CHECK*     = 0x00002000  # C1 E D J  )
+  NO_UTF16_CHECK*    = 0x00002000  # C1 E D J  ) Synonyms
+  NO_UTF32_CHECK*    = 0x00002000  # C1 E D J  )
+  AUTO_CALLOUT*      = 0x00004000  # C1
+  PARTIAL_SOFT*      = 0x00008000  #    E D J  ) Synonyms
+  PARTIAL*           = 0x00008000  #    E D J  )
+
+# This pair use the same bit.
+const
+  NEVER_UTF*         = 0x00010000  # C1        ) Overlaid
+  DFA_SHORTEST*      = 0x00010000  #      D    ) Overlaid
 
+# This pair use the same bit.
 const
-  UTF8_ERR0* = 0
-  UTF8_ERR1* = 1
-  UTF8_ERR2* = 2
-  UTF8_ERR3* = 3
-  UTF8_ERR4* = 4
-  UTF8_ERR5* = 5
-  UTF8_ERR6* = 6
-  UTF8_ERR7* = 7
-  UTF8_ERR8* = 8
-  UTF8_ERR9* = 9
+  NO_AUTO_POSSESS*   = 0x00020000  # C1        ) Overlaid
+  DFA_RESTART*       = 0x00020000  #      D    ) Overlaid
+
+const
+  FIRSTLINE*         = 0x00040000  # C3
+  DUPNAMES*          = 0x00080000  # C1
+  NEWLINE_CR*        = 0x00100000  # C3 E D
+  NEWLINE_LF*        = 0x00200000  # C3 E D
+  NEWLINE_CRLF*      = 0x00300000  # C3 E D
+  NEWLINE_ANY*       = 0x00400000  # C3 E D
+  NEWLINE_ANYCRLF*   = 0x00500000  # C3 E D
+  BSR_ANYCRLF*       = 0x00800000  # C3 E D
+  BSR_UNICODE*       = 0x01000000  # C3 E D
+  JAVASCRIPT_COMPAT* = 0x02000000  # C5
+  NO_START_OPTIMIZE* = 0x04000000  # C2 E D    ) Synonyms
+  NO_START_OPTIMISE* = 0x04000000  # C2 E D    )
+  PARTIAL_HARD*      = 0x08000000  #    E D J
+  NOTEMPTY_ATSTART*  = 0x10000000  #    E D J
+  UCP*               = 0x20000000  # C3
+
+## Exec-time and get/set-time error codes
+const
+  ERROR_NOMATCH*          =  -1
+  ERROR_NULL*             =  -2
+  ERROR_BADOPTION*        =  -3
+  ERROR_BADMAGIC*         =  -4
+  ERROR_UNKNOWN_OPCODE*   =  -5
+  ERROR_UNKNOWN_NODE*     =  -5 ## For backward compatibility
+  ERROR_NOMEMORY*         =  -6
+  ERROR_NOSUBSTRING*      =  -7
+  ERROR_MATCHLIMIT*       =  -8
+  ERROR_CALLOUT*          =  -9 ## Never used by PCRE itself
+  ERROR_BADUTF8*          = -10 ## Same for 8/16/32
+  ERROR_BADUTF16*         = -10 ## Same for 8/16/32
+  ERROR_BADUTF32*         = -10 ## Same for 8/16/32
+  ERROR_BADUTF8_OFFSET*   = -11 ## Same for 8/16
+  ERROR_BADUTF16_OFFSET*  = -11 ## Same for 8/16
+  ERROR_PARTIAL*          = -12
+  ERROR_BADPARTIAL*       = -13
+  ERROR_INTERNAL*         = -14
+  ERROR_BADCOUNT*         = -15
+  ERROR_DFA_UITEM*        = -16
+  ERROR_DFA_UCOND*        = -17
+  ERROR_DFA_UMLIMIT*      = -18
+  ERROR_DFA_WSSIZE*       = -19
+  ERROR_DFA_RECURSE*      = -20
+  ERROR_RECURSIONLIMIT*   = -21
+  ERROR_NULLWSLIMIT*      = -22 ## No longer actually used
+  ERROR_BADNEWLINE*       = -23
+  ERROR_BADOFFSET*        = -24
+  ERROR_SHORTUTF8*        = -25
+  ERROR_SHORTUTF16*       = -25 ## Same for 8/16
+  ERROR_RECURSELOOP*      = -26
+  ERROR_JIT_STACKLIMIT*   = -27
+  ERROR_BADMODE*          = -28
+  ERROR_BADENDIANNESS*    = -29
+  ERROR_DFA_BADRESTART*   = -30
+  ERROR_JIT_BADOPTION*    = -31
+  ERROR_BADLENGTH*        = -32
+  ERROR_UNSET*            = -33
+
+## Specific error codes for UTF-8 validity checks
+const
+  UTF8_ERR0*  =  0
+  UTF8_ERR1*  =  1
+  UTF8_ERR2*  =  2
+  UTF8_ERR3*  =  3
+  UTF8_ERR4*  =  4
+  UTF8_ERR5*  =  5
+  UTF8_ERR6*  =  6
+  UTF8_ERR7*  =  7
+  UTF8_ERR8*  =  8
+  UTF8_ERR9*  =  9
   UTF8_ERR10* = 10
   UTF8_ERR11* = 11
   UTF8_ERR12* = 12
@@ -165,193 +197,305 @@ const
   UTF8_ERR19* = 19
   UTF8_ERR20* = 20
   UTF8_ERR21* = 21
+  UTF8_ERR22* = 22 # Unused (was non-character)
 
-# Request types for pcre_fullinfo() 
-
-const 
-  INFO_OPTIONS* = 0
-  INFO_SIZE* = 1
-  INFO_CAPTURECOUNT* = 2
-  INFO_BACKREFMAX* = 3
-  INFO_FIRSTBYTE* = 4
-  INFO_FIRSTCHAR* = 4         # For backwards compatibility 
-  INFO_FIRSTTABLE* = 5
-  INFO_LASTLITERAL* = 6
-  INFO_NAMEENTRYSIZE* = 7
-  INFO_NAMECOUNT* = 8
-  INFO_NAMETABLE* = 9
-  INFO_STUDYSIZE* = 10
-  INFO_DEFAULT_TABLES* = 11
-  INFO_OKPARTIAL* = 12
-  INFO_JCHANGED* = 13
-  INFO_HASCRORLF* = 14
-  INFO_MINLENGTH* = 15
-  INFO_JIT* = 16
-  INFO_JITSIZE* = 17
-  INFO_MAXLOOKBEHIND* = 18
-
-# Request types for pcre_config(). Do not re-arrange, in order to remain
-# compatible. 
-
-const 
-  CONFIG_UTF8* = 0
-  CONFIG_NEWLINE* = 1
-  CONFIG_LINK_SIZE* = 2
-  CONFIG_POSIX_MALLOC_THRESHOLD* = 3
-  CONFIG_MATCH_LIMIT* = 4
-  CONFIG_STACKRECURSE* = 5
-  CONFIG_UNICODE_PROPERTIES* = 6
-  CONFIG_MATCH_LIMIT_RECURSION* = 7
-  CONFIG_BSR* = 8
-  CONFIG_JIT* = 9
-  CONFIG_JITTARGET* = 11
-
-# Request types for pcre_study(). Do not re-arrange, in order to remain
-# compatible.
+## Specific error codes for UTF-16 validity checks
+const
+  UTF16_ERR0* = 0
+  UTF16_ERR1* = 1
+  UTF16_ERR2* = 2
+  UTF16_ERR3* = 3
+  UTF16_ERR4* = 4 # Unused (was non-character)
 
+## Specific error codes for UTF-32 validity checks
 const
-  STUDY_JIT_COMPILE* = 0x00000001
-  STUDY_JIT_PARTIAL_SOFT_COMPILE* = 0x00000002
-  STUDY_JIT_PARTIAL_HARD_COMPILE* = 0x00000004
-
-# Bit flags for the pcre_extra structure. Do not re-arrange or redefine
-# these bits, just add new ones on the end, in order to remain compatible. 
-
-const 
-  EXTRA_STUDY_DATA* = 0x00000001
-  EXTRA_MATCH_LIMIT* = 0x00000002
-  EXTRA_CALLOUT_DATA* = 0x00000004
-  EXTRA_TABLES* = 0x00000008
-  EXTRA_MATCH_LIMIT_RECURSION* = 0x00000010
-  EXTRA_MARK* = 0x00000020
-  EXTRA_EXECUTABLE_JIT* = 0x00000040
-
-# Types 
-
-type 
-  TPcre*{.pure, final.} = object
-  PPcre* = ptr TPcre
-  Tjit_stack*{.pure, final.} = object
-  Pjit_stack* = ptr Tjit_stack
-
-# When PCRE is compiled as a C++ library, the subject pointer type can be
-# replaced with a custom type. For conventional use, the public interface is a
-# const char *. 
-
-# The structure for passing additional data to pcre_exec(). This is defined in
-# such as way as to be extensible. Always add new fields at the end, in order to
-# remain compatible. 
-
-type 
-  TExtra*{.pure, final.} = object 
-    flags*: int                 ## Bits for which fields are set 
-    study_data*: pointer        ## Opaque data from pcre_study() 
-    match_limit*: int           ## Maximum number of calls to match() 
-    callout_data*: pointer      ## Data passed back in callouts 
-    tables*: cstring            ## Pointer to character tables 
-    match_limit_recursion*: int ## Max recursive calls to match() 
-    mark*: ptr cstring          ## For passing back a mark pointer 
-    executable_jit*: pointer    ## Contains a pointer to a compiled jit code
-  
-
-# The structure for passing out data via the pcre_callout_function. We use a
-# structure so that new fields can be added on the end in future versions,
-# without changing the API of the function, thereby allowing old clients to work
-# without modification. 
-
-type 
-  TCalloutBlock*{.pure, final.} = object 
-    version*: cint            ## Identifies version of block 
-    callout_number*: cint     ## Number compiled into pattern 
-    offset_vector*: ptr cint  ## The offset vector 
-    subject*: cstring         ## The subject being matched 
-    subject_length*: cint     ## The length of the subject 
-    start_match*: cint        ## Offset to start of this match attempt 
-    current_position*: cint   ## Where we currently are in the subject 
-    capture_top*: cint        ## Max current capture 
-    capture_last*: cint       ## Most recently closed capture 
-    callout_data*: pointer    ## Data passed in with the call 
-    pattern_position*: cint   ## Offset to next item in the pattern 
-    next_item_length*: cint   ## Length of next item in the pattern
-    mark*: cstring            ## Pointer to current mark or NULL
-
-# Indirection for store get and free functions. These can be set to
-#alternative malloc/free functions if required. Special ones are used in the
-#non-recursive case for "frames". There is also an optional callout function
-#that is triggered by the (?) regex item. For Virtual Pascal, these definitions
-#have to take another form.
-
-# User defined callback which provides a stack just before the match starts.
+  UTF32_ERR0* = 0
+  UTF32_ERR1* = 1
+  UTF32_ERR2* = 2 # Unused (was non-character)
+  UTF32_ERR3* = 3
 
+## Request types for pcre_fullinfo()
+const
+  INFO_OPTIONS*             =  0
+  INFO_SIZE*                =  1
+  INFO_CAPTURECOUNT*        =  2
+  INFO_BACKREFMAX*          =  3
+  INFO_FIRSTBYTE*           =  4
+  INFO_FIRSTCHAR*           =  4 ## For backwards compatibility
+  INFO_FIRSTTABLE*          =  5
+  INFO_LASTLITERAL*         =  6
+  INFO_NAMEENTRYSIZE*       =  7
+  INFO_NAMECOUNT*           =  8
+  INFO_NAMETABLE*           =  9
+  INFO_STUDYSIZE*           = 10
+  INFO_DEFAULT_TABLES*      = 11
+  INFO_OKPARTIAL*           = 12
+  INFO_JCHANGED*            = 13
+  INFO_HASCRORLF*           = 14
+  INFO_MINLENGTH*           = 15
+  INFO_JIT*                 = 16
+  INFO_JITSIZE*             = 17
+  INFO_MAXLOOKBEHIND*       = 18
+  INFO_FIRSTCHARACTER*      = 19
+  INFO_FIRSTCHARACTERFLAGS* = 20
+  INFO_REQUIREDCHAR*        = 21
+  INFO_REQUIREDCHARFLAGS*   = 22
+  INFO_MATCHLIMIT*          = 23
+  INFO_RECURSIONLIMIT*      = 24
+  INFO_MATCH_EMPTY*         = 25
+
+## Request types for pcre_config(). Do not re-arrange, in order to remain
+## compatible.
+const
+  CONFIG_UTF8*                   =  0
+  CONFIG_NEWLINE*                =  1
+  CONFIG_LINK_SIZE*              =  2
+  CONFIG_POSIX_MALLOC_THRESHOLD* =  3
+  CONFIG_MATCH_LIMIT*            =  4
+  CONFIG_STACKRECURSE*           =  5
+  CONFIG_UNICODE_PROPERTIES*     =  6
+  CONFIG_MATCH_LIMIT_RECURSION*  =  7
+  CONFIG_BSR*                    =  8
+  CONFIG_JIT*                    =  9
+  CONFIG_UTF16*                  = 10
+  CONFIG_JITTARGET*              = 11
+  CONFIG_UTF32*                  = 12
+  CONFIG_PARENS_LIMIT*           = 13
+
+## Request types for pcre_study(). Do not re-arrange, in order to remain
+## compatible.
+const
+  STUDY_JIT_COMPILE*              = 0x0001
+  STUDY_JIT_PARTIAL_SOFT_COMPILE* = 0x0002
+  STUDY_JIT_PARTIAL_HARD_COMPILE* = 0x0004
+  STUDY_EXTRA_NEEDED*             = 0x0008
+
+## Bit flags for the pcre[16|32]_extra structure. Do not re-arrange or redefine
+## these bits, just add new ones on the end, in order to remain compatible.
+const
+  EXTRA_STUDY_DATA*            = 0x0001
+  EXTRA_MATCH_LIMIT*           = 0x0002
+  EXTRA_CALLOUT_DATA*          = 0x0004
+  EXTRA_TABLES*                = 0x0008
+  EXTRA_MATCH_LIMIT_RECURSION* = 0x0010
+  EXTRA_MARK*                  = 0x0020
+  EXTRA_EXECUTABLE_JIT*        = 0x0040
+
+## Types
+type
+  Pcre* = object
+  Pcre16* = object
+  Pcre32* = object
+  JitStack* = object
+  JitStack16* = object
+  JitStack32* = object
+
+
+## The structure for passing additional data to pcre_exec(). This is defined in
+## such as way as to be extensible. Always add new fields at the end, in order
+## to remain compatible.
+type
+  ExtraData* = object
+    flags*: clong                  ## Bits for which fields are set
+    study_data*: pointer           ## Opaque data from pcre_study()
+    match_limit*: clong            ## Maximum number of calls to match()
+    callout_data*: pointer         ## Data passed back in callouts
+    tables*: pointer               ## Pointer to character tables
+    match_limit_recursion*: clong  ## Max recursive calls to match()
+    mark*: pointer                 ## For passing back a mark pointer
+    executable_jit*: pointer       ## Contains a pointer to a compiled jit code
+
+## The structure for passing out data via the pcre_callout_function. We use a
+## structure so that new fields can be added on the end in future versions,
+## without changing the API of the function, thereby allowing old clients to
+## work without modification.
 type
-  TJitCallback* = proc(p: pointer): ptr Tjit_stack{.cdecl.}
-
-# Exported PCRE functions 
-
-proc compile*(a2: cstring, a3: cint, a4: ptr cstring, a5: ptr cint, 
-              a6: ptr char): ptr TPcre{.cdecl, importc: "pcre_compile", 
-    pcreImport.}
-proc compile2*(a2: cstring, a3: cint, a4: ptr cint, a5: ptr cstring, 
-               a6: ptr cint, a7: ptr char): ptr TPcre{.cdecl, 
-    importc: "pcre_compile2", pcreImport.}
-proc config*(a2: cint, a3: pointer): cint{.cdecl, importc: "pcre_config", 
-    pcreImport.}
-proc copy_named_substring*(a2: ptr TPcre, a3: cstring, a4: ptr cint, a5: cint, 
-                           a6: cstring, a7: cstring, a8: cint): cint{.cdecl, 
-    importc: "pcre_copy_named_substring", pcreImport.}
-proc copy_substring*(a2: cstring, a3: ptr cint, a4: cint, a5: cint, 
-                     a6: cstring, 
-                     a7: cint): cint{.cdecl, importc: "pcre_copy_substring", 
-                                      pcreImport.}
-proc dfa_exec*(a2: ptr TPcre, a3: ptr TExtra, a4: cstring, a5: cint, 
-               a6: cint, a7: cint, a8: ptr cint, a9: cint, a10: ptr cint, 
-               a11: cint): cint{.cdecl, importc: "pcre_dfa_exec", 
-                                 pcreImport.}
-proc exec*(a2: ptr TPcre, a3: ptr TExtra, a4: cstring, a5: cint, a6: cint, 
-           a7: cint, a8: ptr cint, a9: cint): cint {.
-           cdecl, importc: "pcre_exec", pcreImport.}
-proc free_substring*(a2: cstring){.cdecl, importc: "pcre_free_substring", 
-                                   pcreImport.}
-proc free_substring_list*(a2: cstringArray){.cdecl, 
-    importc: "pcre_free_substring_list", pcreImport.}
-proc fullinfo*(a2: ptr TPcre, a3: ptr TExtra, a4: cint, a5: pointer): cint{.
-    cdecl, importc: "pcre_fullinfo", pcreImport.}
-proc get_named_substring*(a2: ptr TPcre, a3: cstring, a4: ptr cint, a5: cint, 
-                          a6: cstring, a7: cstringArray): cint{.cdecl, 
-    importc: "pcre_get_named_substring", pcreImport.}
-proc get_stringnumber*(a2: ptr TPcre, a3: cstring): cint{.cdecl, 
-    importc: "pcre_get_stringnumber", pcreImport.}
-proc get_stringtable_entries*(a2: ptr TPcre, a3: cstring, a4: cstringArray, 
-                              a5: cstringArray): cint{.cdecl, 
-    importc: "pcre_get_stringtable_entries", pcreImport.}
-proc get_substring*(a2: cstring, a3: ptr cint, a4: cint, a5: cint, 
-                    a6: cstringArray): cint{.cdecl, 
-    importc: "pcre_get_substring", pcreImport.}
-proc get_substring_list*(a2: cstring, a3: ptr cint, a4: cint, 
-                         a5: ptr cstringArray): cint{.cdecl, 
-    importc: "pcre_get_substring_list", pcreImport.}
-proc maketables*(): ptr char{.cdecl, importc: "pcre_maketables", 
-                                       pcreImport.}
-proc refcount*(a2: ptr TPcre, a3: cint): cint{.cdecl, importc: "pcre_refcount", 
-    pcreImport.}
-proc study*(a2: ptr TPcre, a3: cint, a4: var cstring): ptr TExtra{.cdecl, 
-    importc: "pcre_study", pcreImport.}
-proc version*(): cstring{.cdecl, importc: "pcre_version", pcreImport.}
+  CalloutBlock* = object
+    version*         : cint       ## Identifies version of block
+    # ------------------------ Version 0 -------------------------------
+    callout_number*  : cint       ## Number compiled into pattern
+    offset_vector*   : ptr cint   ## The offset vector
+    subject*         : cstring    ## The subject being matched
+    subject_length*  : cint       ## The length of the subject
+    start_match*     : cint       ## Offset to start of this match attempt
+    current_position*: cint       ## Where we currently are in the subject
+    capture_top*     : cint       ## Max current capture
+    capture_last*    : cint       ## Most recently closed capture
+    callout_data*    : pointer    ## Data passed in with the call
+    # ------------------- Added for Version 1 --------------------------
+    pattern_position*: cint       ## Offset to next item in the pattern
+    next_item_length*: cint       ## Length of next item in the pattern
+    # ------------------- Added for Version 2 --------------------------
+    mark*            : pointer    ## Pointer to current mark or NULL
+    # ------------------------------------------------------------------
+
+
+## User defined callback which provides a stack just before the match starts.
+type
+  JitCallback* = proc (a: pointer): ptr JitStack {.cdecl.}
+
+
+when not defined(usePcreHeader):
+  when hostOS == "windows":
+    const pcreDll = "pcre.dll"
+  elif hostOS == "macosx":
+    const pcreDll = "libpcre(.3|.1|).dylib"
+  else:
+    const pcreDll = "libpcre.so(.3|.1|)"
+  {.push dynlib: pcreDll.}
+else:
+  {.push header: "<pcre.h>".}
+
+{.push cdecl, importc: "pcre_$1".}
+
+# Exported PCRE functions
+
+proc compile*(pattern: cstring,
+              options: cint,
+              errptr: ptr cstring,
+              erroffset: ptr cint,
+              tableptr: pointer): ptr Pcre
+
+proc compile2*(pattern: cstring,
+               options: cint,
+               errorcodeptr: ptr cint,
+               errptr: ptr cstring,
+               erroffset: ptr cint,
+               tableptr: pointer): ptr Pcre
+
+proc config*(what: cint,
+             where: pointer): cint
+
+proc copy_named_substring*(code: ptr Pcre,
+                           subject: cstring,
+                           ovector: ptr cint,
+                           stringcount: cint,
+                           stringname: cstring,
+                           buffer: cstring,
+                           buffersize: cint): cint
+
+proc copy_substring*(subject: cstring,
+                     ovector: ptr cint,
+                     stringcount: cint,
+                     stringnumber: cint,
+                     buffer: cstring,
+                     buffersize: cint): cint
+
+proc dfa_exec*(code: ptr Pcre,
+               extra: ptr ExtraData,
+               subject: cstring,
+               length: cint,
+               startoffset: cint,
+               options: cint,
+               ovector: ptr cint,
+               ovecsize: cint,
+               workspace: ptr cint,
+               wscount: cint): cint
+
+proc exec*(code: ptr Pcre,
+           extra: ptr ExtraData,
+           subject: cstring,
+           length: cint,
+           startoffset: cint,
+           options: cint,
+           ovector: ptr cint,
+           ovecsize: cint): cint
+
+proc jit_exec*(code: ptr Pcre,
+               extra: ptr ExtraData,
+               subject: cstring,
+               length: cint,
+               startoffset: cint,
+               options: cint,
+               ovector: ptr cint,
+               ovecsize: cint,
+               jstack: ptr JitStack): cint
+
+proc free_substring*(stringptr: cstring)
+
+proc free_substring_list*(stringptr: cstringArray)
+
+proc fullinfo*(code: ptr Pcre,
+               extra: ptr ExtraData,
+               what: cint,
+               where: pointer): cint
+
+proc get_named_substring*(code: ptr Pcre,
+                          subject: cstring,
+                          ovector: ptr cint,
+                          stringcount: cint,
+                          stringname: cstring,
+                          stringptr: cstringArray): cint
+
+proc get_stringnumber*(code: ptr Pcre,
+                       name: cstring): cint
+
+proc get_stringtable_entries*(code: ptr Pcre,
+                              name: cstring,
+                              first: cstringArray,
+                              last: cstringArray): cint
+
+proc get_substring*(subject: cstring,
+                    ovector: ptr cint,
+                    stringcount: cint,
+                    stringnumber: cint,
+                    stringptr: cstringArray): cint
+
+proc get_substring_list*(subject: cstring,
+                         ovector: ptr cint,
+                         stringcount: cint,
+                         listptr: ptr cstringArray): cint
+
+proc maketables*(): pointer
+
+proc refcount*(code: ptr Pcre,
+               adjust: cint): cint
+
+proc study*(code: ptr Pcre,
+            options: cint,
+            errptr: ptr cstring): ptr ExtraData
+
+proc free_study*(extra: ptr ExtraData)
+
+proc version*(): cstring
 
 # Utility functions for byte order swaps.
 
-proc pattern_to_host_byte_order*(a2: ptr TPcre, a3: ptr TExtra,
-    a4: ptr char): cint{.cdecl, importc: "pcre_pattern_to_host_byte_order",
-    pcreImport.}
+proc pattern_to_host_byte_order*(code: ptr Pcre,
+                                 extra: ptr ExtraData,
+                                 tables: pointer): cint
 
 # JIT compiler related functions.
 
-proc jit_stack_alloc*(a2: cint, a3: cint): ptr Tjit_stack{.cdecl,
-    importc: "pcre_jit_stack_alloc", pcreImport.}
-proc jit_stack_free*(a2: ptr Tjit_stack){.cdecl, importc: "pcre_jit_stack_free",
-    pcreImport.}
-proc assign_jit_stack*(a2: ptr TExtra, a3: TJitCallback, a4: pointer){.cdecl,
-    importc: "pcre_assign_jit_stack", pcreImport.}
+proc jit_stack_alloc*(startsize: cint,
+                      maxsize: cint): ptr JitStack
+
+proc jit_stack_free*(stack: ptr JitStack)
+
+proc assign_jit_stack*(extra: ptr ExtraData,
+                       callback: JitCallback,
+                       data: pointer)
+
+proc jit_free_unused_memory*()
+
+
+# There was an odd function with `var cstring` instead of `ptr`
+proc study*(code: ptr Pcre,
+            options: cint,
+            errptr: var cstring): ptr ExtraData {.deprecated.}
+
+{.pop.}
+{.pop.}
+
+
+{.deprecated: [MAJOR: PCRE_MAJOR, MINOR: PCRE_MINOR,
+               PRERELEASE: PCRE_PRERELEASE, DATE: PCRE_DATE].}
+
+{.deprecated: [TPcre: Pcre, TJitStack: JitStack].}
+type
+  PPcre* {.deprecated.} = ptr Pcre
+  PJitStack* {.deprecated.} = ptr JitStack
 
-var 
-  pcre_free*: proc (p: ptr TPcre) {.cdecl.} 
+{.deprecated: [TExtra: ExtraData].}
+{.deprecated: [TCalloutBlock: CalloutBlock].}
+{.deprecated: [TJitCallback: JitCallback].}
diff --git a/lib/wrappers/readline/history.nim b/lib/wrappers/readline/history.nim
index caa857ceb..495bc15e4 100644
--- a/lib/wrappers/readline/history.nim
+++ b/lib/wrappers/readline/history.nim
@@ -231,7 +231,7 @@ proc history_truncate_file*(a2: cstring, a3: cint): cint{.cdecl,
 #  -1) If there was an error in expansion.
 #   2) If the returned line should just be printed.
 #
-#  If an error ocurred in expansion, then OUTPUT contains a descriptive
+#  If an error occurred in expansion, then OUTPUT contains a descriptive
 #  error message. 
 
 proc history_expand*(a2: cstring, a3: cstringArray): cint{.cdecl, 
diff --git a/lib/wrappers/readline/tweaked/history.h b/lib/wrappers/readline/tweaked/history.h
index 53bd642b1..b79123790 100644
--- a/lib/wrappers/readline/tweaked/history.h
+++ b/lib/wrappers/readline/tweaked/history.h
@@ -217,7 +217,7 @@ extern int history_truncate_file PARAMS((const char *, int));
   -1) If there was an error in expansion.
    2) If the returned line should just be printed.
 
-  If an error ocurred in expansion, then OUTPUT contains a descriptive
+  If an error occurred in expansion, then OUTPUT contains a descriptive
   error message. */
 extern int history_expand PARAMS((char *, char **));
 
diff --git a/lib/wrappers/sdl/sdl.nim b/lib/wrappers/sdl/sdl.nim
index 449b651f9..5bb5b7ec2 100644
--- a/lib/wrappers/sdl/sdl.nim
+++ b/lib/wrappers/sdl/sdl.nim
@@ -89,7 +89,7 @@
 #                           As most games will need it.
 #
 #   April    02 2001 - DL : Added SDL_getenv.h definitions and tested version
-#                           1.2.0 compatability.
+#                           1.2.0 compatibility.
 #
 #   March    13 2001 - MT : Added Linux compatibility.
 #
@@ -118,7 +118,7 @@
 #
 #  November  30 2001 - DL : SDL_NOFRAME added as pointed out by Simon Rushton.
 #
-#  December  11 2001 - DL : Added $WEAKPACKAGEUNIT ON to facilitate useage in
+#  December  11 2001 - DL : Added $WEAKPACKAGEUNIT ON to facilitate usage in
 #                           Components
 #
 #  January   05 2002 - DL : Added SDL_Swap32 function as suggested by Matthias
@@ -209,7 +209,7 @@
 #  forgot to apply Michalis Kamburelis' patch to the implementation section. now fixed
 #
 #  Revision 1.14  2004/12/23 23:42:18  savage
-#  Applied Patches supplied by Michalis Kamburelis ( THANKS! ), for greater FreePascal compatability.
+#  Applied Patches supplied by Michalis Kamburelis ( THANKS! ), for greater FreePascal compatibility.
 #
 #  Revision 1.13  2004/09/30 22:31:59  savage
 #  Updated with slightly different header comments
@@ -221,7 +221,7 @@
 #  Updated so that Library name defines are correctly defined for MacOS X.
 #
 #  Revision 1.10  2004/07/20 23:57:33  savage
-#  Thanks to Paul Toth for spotting an error in the SDL Audio Convertion structures.
+#  Thanks to Paul Toth for spotting an error in the SDL Audio Conversion structures.
 #  In TSDL_AudioCVT the filters variable should point to and array of pointers and not what I had there previously.
 #
 #  Revision 1.9  2004/07/03 22:07:22  savage
@@ -243,7 +243,7 @@
 #  SDL_GetEnv Fix so that it is not define twice for FPC. Thanks to Rene Hugentobler for pointing out this bug,
 #
 #  Revision 1.3  2004/02/18 22:35:51  savage
-#  Brought sdl.pas up to 1.2.7 compatability
+#  Brought sdl.pas up to 1.2.7 compatibility
 #  Thus...
 #  Added SDL_GL_STEREO,
 #      SDL_GL_MULTISAMPLEBUFFERS,
diff --git a/lib/wrappers/sdl/sdl_mixer.nim b/lib/wrappers/sdl/sdl_mixer.nim
index 33a71508a..2f8664635 100644
--- a/lib/wrappers/sdl/sdl_mixer.nim
+++ b/lib/wrappers/sdl/sdl_mixer.nim
@@ -136,7 +136,7 @@
 #  Windows unit not used in this file, so it was removed to keep the code tidy.
 #
 #  Revision 1.3  2004/03/31 10:05:08  savage
-#  Better defines for Endianess under FreePascal and Borland compilers.
+#  Better defines for Endianness under FreePascal and Borland compilers.
 #
 #  Revision 1.2  2004/03/30 20:23:28  savage
 #  Tidied up use of UNIX compiler directive.
diff --git a/lib/wrappers/zip/zlib.nim b/lib/wrappers/zip/zlib.nim
index e3530d566..8bdb47106 100644
--- a/lib/wrappers/zip/zlib.nim
+++ b/lib/wrappers/zip/zlib.nim
@@ -232,7 +232,7 @@ proc uncompress*(sourceBuf: cstring, sourceLen: int): string =
     return
 
   # Make sure memory allocated by inflateInit2() is freed eventually.
-  finally: discard inflateEnd(z)
+  defer: discard inflateEnd(z)
 
   # Decompress all of self.
   while true:
diff --git a/readme.md b/readme.md
index d5968982b..740296f4f 100644
--- a/readme.md
+++ b/readme.md
@@ -1,5 +1,5 @@
 # Nim Compiler
-This repo contains the Nim compiler, Nim's stdlib, tools and 
+This repo contains the Nim compiler, Nim's stdlib, tools and
 documentation.
 
 ## Compiling
@@ -8,17 +8,13 @@ the Nim compiler itself is written in the Nim programming language
 the C source of an older version of the compiler are needed to bootstrap the
 latest version. The C sources are available in a separate repo [here](http://github.com/nim-lang/csources).
 
-Pre-compiled snapshots of the compiler are also available on
-[Nimbuild](http://build.nim-lang.org/). Your platform however may not 
-currently be built for.
-
-The compiler currently supports the following platform and architecture 
+The compiler currently supports the following platform and architecture
 combinations:
-  
+
   * Windows (Windows XP or greater) - x86 and x86_64
   * Linux (most, if not all, distributions) - x86, x86_64, ppc64 and armv6l
   * Mac OS X 10.04 or higher - x86, x86_64 and ppc64
-  
+
 In reality a lot more are supported, however they are not tested regularly.
 
 To build from source you will need:
@@ -39,8 +35,7 @@ $ bin/nim c koch
 $ ./koch boot -d:release
 ```
 
-``koch install [dir]`` may then be used to install Nim, or you can simply
-add it to your PATH. More ``koch`` related options are documented in
+``koch install [dir]`` may then be used to install Nim, but lots of things don't work then so don't do that. Add it to your PATH instead. More ``koch`` related options are documented in
 [doc/koch.txt](doc/koch.txt).
 
 The above steps can be performed on Windows in a similar fashion, the
@@ -55,19 +50,35 @@ questions, and you can also get help in the IRC channel on
 tag](http://stackoverflow.com/questions/tagged/nim).
 
 ## License
-The compiler and the standard library are licensed under the MIT license, 
-except for some modules where the documentation suggests otherwise. This means 
-that you can use any license for your own programs developed with Nim, 
+The compiler and the standard library are licensed under the MIT license,
+except for some modules where the documentation suggests otherwise. This means
+that you can use any license for your own programs developed with Nim,
 allowing you to create commercial applications.
 
 Read copying.txt for more details.
 
-Copyright (c) 2006-2014 Andreas Rumpf.
+Copyright (c) 2006-2015 Andreas Rumpf.
 All rights reserved.
 
 # Build Status
-| |Linux|Windows|Mac|
-|---|---|---|---|
-| x86 | ![](http://178.62.143.63:8010/buildstatusimage?builder=linux-x32-builder) | ![](http://178.62.143.63:8010/buildstatusimage?builder=windows-x32-builder) | ![](http://178.62.143.63:8010/buildstatusimage?builder=mac-x32-builder)
-| x86_64 | ![](http://178.62.143.63:8010/buildstatusimage?builder=linux-x64-builder) | ![](http://178.62.143.63:8010/buildstatusimage?builder=windows-x64-builder) | ![](http://178.62.143.63:8010/buildstatusimage?builder=mac-x64-builder)
-| arm | ![](http://178.62.143.63:8010/buildstatusimage?builder=linux-arm5-builder) |
+[**Build Waterfall**][waterfall]
+
+|        | Linux                                                                                                  | Windows                               | Mac                           |
+| ------ | -----                                                                                                  | -------                               | ---                           |
+| x86    | ![linux-x86][linux-x86-img]                                                                            | ![windows-x86][windows-x86-img]       | ![mac-x86][mac-x86-img]       |
+| x86_64 | ![linux-x86_64][linux-x86_64-img]                                                                      | ![windows-x86_64][windows-x86_64-img] | ![mac-x86_64][mac-x86_64-img] |
+| arm    | ![linux-armv5][linux-arm5-img]<br/> ![linux-armv6][linux-arm6-img]<br/> ![linux-armv7][linux-arm7-img] |                                       |                               |
+
+[linux-x86-img]:      http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x32-builder
+[linux-x86_64-img]:   http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x64-builder
+[linux-arm5-img]:     http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm5-builder
+[linux-arm6-img]:     http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm6-builder
+[linux-arm7-img]:     http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm7-builder
+
+[windows-x86-img]:    http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x32-builder
+[windows-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x64-builder
+
+[mac-x86-img]:        http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x32-builder
+[mac-x86_64-img]:     http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x64-builder
+
+[waterfall]: http://buildbot.nim-lang.org/waterfall
diff --git a/tests/actiontable/tactiontable2.nim b/tests/actiontable/tactiontable2.nim
index 99bb3dca0..fbc65a67d 100644
--- a/tests/actiontable/tactiontable2.nim
+++ b/tests/actiontable/tactiontable2.nim
@@ -1,6 +1,5 @@
 discard """
-  line: 21
-  errormsg: "invalid type: 'Table[string, proc (string){.gcsafe.}]'"
+  output: "action 3 arg"
 """
 
 import tables
diff --git a/tests/array/troof1.nim b/tests/array/troof1.nim
new file mode 100644
index 000000000..96669a121
--- /dev/null
+++ b/tests/array/troof1.nim
@@ -0,0 +1,36 @@
+discard """
+  output: '''@[2, 3, 4]321
+9.0 4.0
+(a: 1.0, b: 2.0, c: 8.0)2.0'''
+"""
+
+proc foo[T](x, y: T): T = x
+
+var a = @[1, 2, 3, 4]
+var b: array[3, array[2, float]] = [[1.0,2], [3.0,4], [8.0,9]]
+echo a[1.. ^1], a[^2], a[^3], a[^4]
+echo b[^1][^1], " ", (b[^2]).foo(b[^1])[^1]
+
+type
+  MyArray = object
+    a, b, c: float
+
+var
+  ma = MyArray(a: 1.0, b: 2.0, c: 3.0)
+
+proc len(x: MyArray): int = 3
+
+proc `[]=`(x: var MyArray; idx: range[0..2]; val: float) =
+  case idx
+  of 0: x.a = val
+  of 1: x.b = val
+  of 2: x.c = val
+
+proc `[]`(x: var MyArray; idx: range[0..2]): float =
+  case idx
+  of 0: result = x.a
+  of 1: result = x.b
+  of 2: result = x.c
+
+ma[^1] = 8.0
+echo ma, ma[^2]
diff --git a/tests/array/troof2.nim b/tests/array/troof2.nim
new file mode 100644
index 000000000..d4c1a4982
--- /dev/null
+++ b/tests/array/troof2.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "invalid context for '^' as 'foo()' has side effects"
+  line: "9"
+"""
+
+proc foo(): seq[int] =
+  echo "ha"
+
+let f = foo()[^1]
+
diff --git a/tests/array/troof3.nim b/tests/array/troof3.nim
new file mode 100644
index 000000000..4b6e22223
--- /dev/null
+++ b/tests/array/troof3.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "invalid context for '^' as len!=high+1 for 'a'"
+  line: "8"
+"""
+
+var a: array[1..3, string]
+
+echo a[^1]
diff --git a/tests/array/troof4.nim b/tests/array/troof4.nim
new file mode 100644
index 000000000..7a262d9de
--- /dev/null
+++ b/tests/array/troof4.nim
@@ -0,0 +1,37 @@
+discard """
+  errormsg: "no surrounding array access context for '^'"
+  line: "37"
+"""
+
+proc foo[T](x, y: T): T = x
+
+var a = @[1, 2, 3, 4]
+var b: array[3, array[2, float]] = [[1.0,2], [3.0,4], [8.0,9]]
+echo a[1.. ^1], a[^2], a[^3], a[^4]
+echo b[^1][^1], " ", (b[^2]).foo(b[^1])[^1]
+
+type
+  MyArray = object
+    a, b, c: float
+
+var
+  ma = MyArray(a: 1.0, b: 2.0, c: 3.0)
+
+proc len(x: MyArray): int = 3
+
+proc `[]=`(x: var MyArray; idx: range[0..2]; val: float) =
+  case idx
+  of 0: x.a = val
+  of 1: x.b = val
+  of 2: x.c = val
+
+proc `[]`(x: var MyArray; idx: range[0..2]): float =
+  case idx
+  of 0: result = x.a
+  of 1: result = x.b
+  of 2: result = x.c
+
+ma[^1] = 8.0
+echo ma, ma[^2]
+
+echo(^1)
diff --git a/tests/assert/tfailedassert.nim b/tests/assert/tfailedassert.nim
index 4994e13c8..1e6764471 100644
--- a/tests/assert/tfailedassert.nim
+++ b/tests/assert/tfailedassert.nim
@@ -1,16 +1,16 @@
 discard """
   output: '''
-WARNING: false first asseertion from bar
+WARNING: false first assertion from bar
 ERROR: false second assertion from bar
 -1
-tfailedassert.nim:27 false assertion from foo
+tests/assert/tfailedassert.nim:27 false assertion from foo
 '''
 """
 
 type
   TLineInfo = tuple[filename: string, line: int]
 
-  TMyError = object of E_Base
+  TMyError = object of Exception
     lineinfo: TLineInfo
 
   EMyError = ref TMyError
@@ -30,8 +30,8 @@ proc bar: int =
   # local overrides that are active only
   # in this proc
   onFailedAssert(msg): echo "WARNING: " & msg
-    
-  assert(false, "first asseertion from bar")
+
+  assert(false, "first assertion from bar")
 
   onFailedAssert(msg):
     echo "ERROR: " & msg
diff --git a/tests/assign/moverload_asgn2.nim b/tests/assign/moverload_asgn2.nim
new file mode 100644
index 000000000..6620adbeb
--- /dev/null
+++ b/tests/assign/moverload_asgn2.nim
@@ -0,0 +1,10 @@
+type
+  Concrete* = object
+    a*, b*: string
+    rc*: int # refcount
+
+proc `=`(d: var Concrete; src: Concrete) =
+  shallowCopy(d.a, src.a)
+  shallowCopy(d.b, src.b)
+  dec d.rc
+  d.rc = src.rc + 1
diff --git a/tests/assign/toverload_asgn1.nim b/tests/assign/toverload_asgn1.nim
new file mode 100644
index 000000000..dbc3a71c4
--- /dev/null
+++ b/tests/assign/toverload_asgn1.nim
@@ -0,0 +1,75 @@
+discard """
+  output: '''Concrete '='
+Concrete '='
+Concrete '='
+Concrete '='
+Concrete '='
+GenericT[T] '=' int
+GenericT[T] '=' float
+GenericT[T] '=' float
+GenericT[T] '=' float
+GenericT[T] '=' string
+GenericT[T] '=' int8
+GenericT[T] '=' bool
+GenericT[T] '=' bool
+GenericT[T] '=' bool
+GenericT[T] '=' bool'''
+"""
+
+import typetraits
+
+type
+  Concrete = object
+    a, b: string
+
+proc `=`(d: var Concrete; src: Concrete) =
+  shallowCopy(d.a, src.a)
+  shallowCopy(d.b, src.b)
+  echo "Concrete '='"
+
+var x, y: array[0..2, Concrete]
+var cA, cB: Concrete
+
+var cATup, cBTup: tuple[x: int, ha: Concrete]
+
+x = y
+cA = cB
+cATup = cBTup
+
+type
+  GenericT[T] = object
+    a, b: T
+
+proc `=`[T](d: var GenericT[T]; src: GenericT[T]) =
+  shallowCopy(d.a, src.a)
+  shallowCopy(d.b, src.b)
+  echo "GenericT[T] '=' ", type(T).name
+
+var ag: GenericT[int]
+var bg: GenericT[int]
+
+ag = bg
+
+var xg, yg: array[0..2, GenericT[float]]
+var cAg, cBg: GenericT[string]
+
+var cATupg, cBTupg: tuple[x: int, ha: GenericT[int8]]
+
+xg = yg
+cAg = cBg
+cATupg = cBTupg
+
+var caSeqg, cbSeqg: seq[GenericT[bool]]
+newSeq(cbSeqg, 4)
+caSeqg = cbSeqg
+
+when false:
+  type
+    Foo = object
+      case b: bool
+      of false: xx: GenericT[int]
+      of true: yy: bool
+
+  var
+    a, b: Foo
+  a = b
diff --git a/tests/assign/toverload_asgn2.nim b/tests/assign/toverload_asgn2.nim
new file mode 100644
index 000000000..243c90494
--- /dev/null
+++ b/tests/assign/toverload_asgn2.nim
@@ -0,0 +1,22 @@
+discard """
+  output: '''i value 88
+2aa'''
+"""
+
+import moverload_asgn2
+
+proc passAround(i: int): Concrete =
+  echo "i value ", i
+  result = Concrete(a: "aa", b: "bb", rc: 0)
+
+proc main =
+  let
+    i = 88
+    v = passAround(i)
+    z = v.a
+  var
+    x: Concrete
+  x = v
+  echo x.rc, z # 2aa
+
+main()
diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim
index 5165b0f06..13d531387 100644
--- a/tests/async/tasyncawait.nim
+++ b/tests/async/tasyncawait.nim
@@ -53,9 +53,7 @@ proc createServer(port: TPort) {.async.} =
   
   discard server.SocketHandle.listen()
   while true:
-    var client = await accept(server)
-    asyncCheck readMessages(client)
-    # TODO: Test: readMessages(disp, await disp.accept(server))
+    asyncCheck readMessages(await accept(server))
 
 asyncCheck createServer(TPort(10335))
 asyncCheck launchSwarm(TPort(10335))
diff --git a/tests/async/tasyncexceptions.nim b/tests/async/tasyncexceptions.nim
index 30ef41756..c4379f7d8 100644
--- a/tests/async/tasyncexceptions.nim
+++ b/tests/async/tasyncexceptions.nim
@@ -19,7 +19,6 @@ proc processClient(fd: int) {.async.} =
   var foo = line[0]
   if foo == 'g':
     raise newException(EBase, "foobar")
-  
 
 proc serve() {.async.} =
 
diff --git a/tests/async/tasynciossl.nim b/tests/async/tasynciossl.nim
index b0222e4ff..118b9e74d 100644
--- a/tests/async/tasynciossl.nim
+++ b/tests/async/tasynciossl.nim
@@ -47,7 +47,7 @@ proc serverAccept(s: PAsyncSocket) =
 proc launchSwarm(disp: var PDispatcher, port: TPort, count: int,
                  buffered = true, useSSL = false) =
   for i in 1..count:
-    var client = AsyncSocket()
+    var client = asyncSocket()
     when defined(ssl):
       if useSSL:
         ctx1.wrapSocket(client)
@@ -56,7 +56,7 @@ proc launchSwarm(disp: var PDispatcher, port: TPort, count: int,
     client.connect("localhost", port)
 
 proc createSwarm(port: TPort, buffered = true, useSSL = false) =
-  var server = AsyncSocket()
+  var server = asyncSocket()
   when defined(ssl):
     if useSSL:
       ctx.wrapSocket(server)
diff --git a/tests/async/tasynctry.nim b/tests/async/tasynctry.nim
index 66ea40d49..f77198e2e 100644
--- a/tests/async/tasynctry.nim
+++ b/tests/async/tasynctry.nim
@@ -49,3 +49,56 @@ proc catch() {.async.} =
     assert false
 
 asyncCheck catch()
+
+proc test(): Future[bool] {.async.} =
+  result = false
+  try:
+    raise newException(OSError, "Foobar")
+  except:
+    result = true
+    return
+
+proc foo(): Future[bool] {.async.} = discard
+
+proc test2(): Future[bool] {.async.} =
+  result = false
+  try:
+    discard await foo()
+    raise newException(OSError, "Foobar")
+  except:
+    result = true
+    return
+
+proc test3(): Future[int] {.async.} =
+  result = 0
+  try:
+    try:
+      discard await foo()
+      raise newException(OSError, "Hello")
+    except:
+      result = 1
+      raise
+  except:
+    result = 2
+    return
+
+proc test4(): Future[int] {.async.} =
+  try:
+    discard await foo()
+    raise newException(ValueError, "Test4")
+  except OSError:
+    result = 1
+  except:
+    result = 2
+
+var x = test()
+assert x.read
+
+x = test2()
+assert x.read
+
+var y = test3()
+assert y.read == 2
+
+y = test4()
+assert y.read == 2
diff --git a/tests/async/tasynctry2.nim b/tests/async/tasynctry2.nim
new file mode 100644
index 000000000..444a058be
--- /dev/null
+++ b/tests/async/tasynctry2.nim
@@ -0,0 +1,16 @@
+discard """
+  file: "tasynctry2.nim"
+  errormsg: "\'yield\' cannot be used within \'try\' in a non-inlined iterator"
+  line: 15
+"""
+import asyncdispatch
+
+proc foo(): Future[bool] {.async.} = discard
+
+proc test5(): Future[int] {.async.} =
+  try:
+    discard await foo()
+    raise newException(ValueError, "Test5")
+  except:
+    discard await foo()
+    result = 0
diff --git a/tests/async/tasyncudp.nim b/tests/async/tasyncudp.nim
index fd7f3d568..2a7ed40bf 100644
--- a/tests/async/tasyncudp.nim
+++ b/tests/async/tasyncudp.nim
@@ -42,14 +42,14 @@ proc swarmConnect(s: PAsyncSocket) =
 proc createClient(disp: var PDispatcher, port: TPort,
                   buffered = true) =
   currentClient.inc()
-  var client = AsyncSocket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP,
+  var client = asyncSocket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP,
                            buffered = buffered)
   client.handleConnect = swarmConnect
   disp.register(client)
   client.connect("localhost", port)
 
 proc createServer(port: TPort, buffered = true) =
-  var server = AsyncSocket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP,
+  var server = asyncSocket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP,
                            buffered = buffered)
   server.handleRead = serverRead
   disp.register(server)
@@ -75,4 +75,4 @@ while true:
     break
 
 assert msgCount == messagesToSend * serverCount * swarmSize
-echo(msgCount)
\ No newline at end of file
+echo(msgCount)
diff --git a/tests/bind/tnicerrorforsymchoice.nim b/tests/bind/tnicerrorforsymchoice.nim
index e1ff090dd..5145fdcff 100644
--- a/tests/bind/tnicerrorforsymchoice.nim
+++ b/tests/bind/tnicerrorforsymchoice.nim
@@ -1,17 +1,17 @@
 discard """
   line: 18
-  errormsg: "type mismatch: got (proc (TScgi) | proc (AsyncSocket, StringTableRef, string){.gcsafe.})"
+  errormsg: "type mismatch: got (proc (s: TScgi) | proc (client: AsyncSocket, headers: StringTableRef, input: string){.gcsafe, locks: 0.}"
 """
 
 #bug #442
 import scgi, sockets, asyncio, strtabs
 proc handleSCGIRequest[TScgi: ScgiState | AsyncScgiState](s: TScgi) =
   discard
-proc handleSCGIRequest(client: AsyncSocket, headers: StringTableRef, 
+proc handleSCGIRequest(client: AsyncSocket, headers: StringTableRef,
                        input: string) =
   discard
 
-proc test(handle: proc (client: AsyncSocket, headers: StringTableRef, 
+proc test(handle: proc (client: AsyncSocket, headers: StringTableRef,
                         input: string), b: int) =
   discard
 
diff --git a/tests/caas/idetools_api.nim b/tests/caas/idetools_api.nim
index 8f1061e27..281e562d7 100644
--- a/tests/caas/idetools_api.nim
+++ b/tests/caas/idetools_api.nim
@@ -58,7 +58,7 @@ macro expect*(exceptions: varargs[expr], body: stmt): stmt {.immediate.} =
   ## Expect docstrings
   let exp = callsite()
   template expectBody(errorTypes, lineInfoLit: expr,
-                      body: stmt): PNimrodNode {.dirty.} =
+                      body: stmt): NimNode {.dirty.} =
     try:
       body
       assert false
diff --git a/tests/caas/issue_416_template_shift.txt b/tests/caas/issue_416_template_shift.txt
index b1f47c1ac..e911c1360 100644
--- a/tests/caas/issue_416_template_shift.txt
+++ b/tests/caas/issue_416_template_shift.txt
@@ -6,7 +6,7 @@ def\tskType\tsystem.string\tstring
 > idetools --track:$TESTNIM,12,35 --def $SILENT
 def\tskLet\t$MODULE.failtest.input\tTaintedString
 
-# The following fail because they seem shifted one colum to the right.
+# The following fail because they seem shifted one column to the right.
 > idetools --track:$TESTNIM,12,16 --def $SILENT
 def\tskTemplate\tsequtils.toSeq\tproc \(expr\): expr
 > idetools --track:$TESTNIM,12,22 --def $SILENT
diff --git a/tests/caas/its_full_of_procs.nim b/tests/caas/its_full_of_procs.nim
index 45347490c..8f8b66764 100644
--- a/tests/caas/its_full_of_procs.nim
+++ b/tests/caas/its_full_of_procs.nim
@@ -2,7 +2,7 @@ import unicode, sequtils
 
 # This example shows that idetools returns proc as signature for everything
 # which can be called. While a clever person would use the second column to
-# differentiate betwen procs, methods and others, why does the output contain
+# differentiate between procs, methods and others, why does the output contain
 # incorrect information?
 
 type
diff --git a/tests/casestmt/tcase_emptyset_when.nim b/tests/casestmt/tcase_emptyset_when.nim
new file mode 100644
index 000000000..e9b1ec2df
--- /dev/null
+++ b/tests/casestmt/tcase_emptyset_when.nim
@@ -0,0 +1,24 @@
+discard """
+  file: "tcaseofwhen.nim"
+  outputsub: "compiles for 1\ni am always two\ndefault for 3\nset is 4 not 5\narray is 6 not 7\ndefault for 8"
+  exitcode: "0"
+"""
+
+proc whenCase(a: int) =
+  case a
+  of (when compiles(whenCase(1)): 1 else: {}): echo "compiles for 1"
+  of {}: echo "me not fail"
+  of 2: echo "i am always two"
+  of []: echo "me neither"
+  of {4,5}: echo "set is 4 not 5"
+  of [6,7]: echo "array is 6 not 7"
+  of (when compiles(neverCompilesIBet()): 3 else: {}): echo "compiles for 3"
+  #of {},[]: echo "me neither"
+  else: echo "default for ", a
+
+whenCase(1)
+whenCase(2)
+whenCase(3)
+whenCase(4)
+whenCase(6)
+whenCase(8)
diff --git a/tests/casestmt/tcomputedgoto.nim b/tests/casestmt/tcomputedgoto.nim
index b21fc07a3..f567174af 100644
--- a/tests/casestmt/tcomputedgoto.nim
+++ b/tests/casestmt/tcomputedgoto.nim
@@ -15,7 +15,7 @@ yeah A enumB'''
 
 type
   MyEnum = enum
-    enumA, enumB, enumC, enumD, enumE
+    enumA, enumB, enumC, enumD, enumE, enumLast
 
 proc vm() =
   var instructions: array [0..100, MyEnum]
@@ -42,6 +42,7 @@ proc vm() =
       echo "yeah B ", ra
     of enumE:
       break
+    of enumLast: discard
     inc(pc)
-  
+
 vm()
diff --git a/tests/ccgbugs/tarray_equality.nim b/tests/ccgbugs/tarray_equality.nim
new file mode 100644
index 000000000..66a953439
--- /dev/null
+++ b/tests/ccgbugs/tarray_equality.nim
@@ -0,0 +1,15 @@
+discard """
+  output: '''true
+true'''
+"""
+
+# bug #2489
+
+let a = [1]
+let b = [1]
+echo a == b
+
+# bug #2498
+var x: array[0, int]
+var y: array[0, int]
+echo x == y
diff --git a/tests/ccgbugs/tmissingderef.nim b/tests/ccgbugs/tmissingderef.nim
new file mode 100644
index 000000000..edff1dd4e
--- /dev/null
+++ b/tests/ccgbugs/tmissingderef.nim
@@ -0,0 +1,30 @@
+discard """
+  output: '''255
+1 1
+0.5'''
+"""
+
+# bug #1181
+
+type
+  TFoo = object
+    x: int32
+
+proc mainowar =
+  var foo: TFoo
+  foo.x = 0xff
+  var arr1 = cast[ptr array[4, uint8]](addr foo)[] # Fails.
+  echo arr1[when cpuEndian == littleEndian: 0 else: 3]
+
+  var i = 1i32
+  let x = addr i
+  var arr2 = cast[ptr array[4, uint8]](x)[] # Fails.
+  echo arr2[when cpuEndian == littleEndian: 0 else: 3], " ", i
+
+  # bug #1715
+  var a: array[2, float32] = [0.5'f32, 0.7]
+  let p = addr a
+  var b = p[]
+  echo b[0]
+
+mainowar()
diff --git a/tests/ccgbugs/trecursive_closure.nim b/tests/ccgbugs/trecursive_closure.nim
new file mode 100644
index 000000000..50c363a4a
--- /dev/null
+++ b/tests/ccgbugs/trecursive_closure.nim
@@ -0,0 +1,8 @@
+# bug #2233
+type MalType = object
+  fun: proc: MalType
+
+proc f(x: proc: MalType) =
+  discard x()
+
+f(nil)
diff --git a/tests/ccgbugs/trecursive_table.nim b/tests/ccgbugs/trecursive_table.nim
new file mode 100644
index 000000000..3406a1c31
--- /dev/null
+++ b/tests/ccgbugs/trecursive_table.nim
@@ -0,0 +1,17 @@
+
+# bug #1700
+import tables
+
+type
+  E* = enum
+    eX
+    eY
+  T* = object
+    case kind: E
+    of eX:
+      xVal: Table[string, T]
+    of eY:
+      nil
+
+proc p*(x: Table[string, T]) =
+  discard
diff --git a/tests/ccgbugs/tstringslice.nim b/tests/ccgbugs/tstringslice.nim
new file mode 100644
index 000000000..00c1adf74
--- /dev/null
+++ b/tests/ccgbugs/tstringslice.nim
@@ -0,0 +1,24 @@
+discard """
+  output: '''1
+1234
+1234
+2
+234
+234
+3
+34
+34
+4
+4
+4'''
+"""
+
+# bug #794
+type TRange = range[0..3]
+
+const str = "123456789"
+
+for i in TRange.low .. TRange.high:
+  echo str[i]                          #This works fine
+  echo str[int(i) .. int(TRange.high)] #So does this
+  echo str[i .. TRange.high]           #The compiler complains about this
diff --git a/tests/ccgbugs/tuple_canon.nim b/tests/ccgbugs/tuple_canon.nim
new file mode 100644
index 000000000..960e2aae9
--- /dev/null
+++ b/tests/ccgbugs/tuple_canon.nim
@@ -0,0 +1,80 @@
+# bug #2250
+
+import
+    math, strutils
+
+type
+    Meters = float
+    Point2[T] = tuple[x, y: T]
+
+    HexState* = enum
+        hsOn, hsOff
+
+    Index = uint16
+
+    HexGrid* = object
+        w, h: int                       ## Width and height of the hex grid.
+        radius: Meters                  ## Radius of circle that circumscribes a hexagon.
+        grid: seq[HexState]             ## Information on what hexes are drawn.
+
+    HexVtxIndex = enum
+        hiA, hiB, hiC, hiD, hiE, hiF
+
+    HexCoord* = Point2[int]
+
+const
+    HexDY = sqrt(1.0 - (0.5 * 0.5))     # dy from center to midpoint of 1-2
+    HexDX = sqrt(1.0 - (HexDY * HexDY)) # dx from center to midpoint of 1-5 (0.5)
+
+
+let
+    hexOffsets : array[HexVtxIndex, Point2[float]] = [
+                  (-1.0, 0.0),
+                  (-HexDX, -HexDY),
+                  (HexDX, -HexDY),
+                  (1.0, 0.0),
+                  (HexDX, HexDY),
+                  (-HexDX, HexDY)]
+
+    evenSharingOffsets : array[HexVtxIndex, tuple[hc: HexCoord; idx: HexVtxIndex]] = [
+            ((0,0), hiA),
+            ((0,0), hiB),
+            ((1,-1), hiA),
+            ((1,0), hiB),
+            ((1,0), hiA),
+            ((0,1), hiB)]
+
+    oddSharingOffsets : array[HexVtxIndex, tuple[hc: HexCoord; idx: HexVtxIndex]] = [
+            ((0,0), hiA),
+            ((0,0), hiB),
+            ((1,0), hiA),
+            ((1,1), hiB),
+            ((1,1), hiA),
+            ((0,1), hiB)]
+
+template odd*(i: int) : expr =
+    (i and 1) != 0
+
+proc vidx(hg: HexGrid; col, row: int; i: HexVtxIndex) : Index =
+    #NOTE: this variation compiles
+    #var offset : type(evenSharingOffsets[i])
+    #
+    #if odd(col):
+    #    offset = oddSharingOffsets[i]
+    #else:
+    #    offset = evenSharingOffsets[i]
+
+    let
+        #NOTE: this line generates the bad code
+        offset = (if odd(col): oddSharingOffsets[i] else: evenSharingOffsets[i])
+        x = col + 1 + offset.hc.x
+        y = row + 1 + offset.hc.y
+
+    result = Index(x*2 + y * (hg.w + 2)*2 + int(offset.idx))
+
+proc go() =
+    var hg : HexGrid
+
+    echo "vidx ", $vidx(hg, 1, 2, hiC)
+
+go()
diff --git a/tests/ccgbugs/twrong_tupleconv.nim b/tests/ccgbugs/twrong_tupleconv.nim
new file mode 100644
index 000000000..68413e96e
--- /dev/null
+++ b/tests/ccgbugs/twrong_tupleconv.nim
@@ -0,0 +1,20 @@
+# bug #1833
+iterator myitems*[T](a: var seq[T]): var T {.inline.} =
+  ## iterates over each item of `a` so that you can modify the yielded value.
+  var i = 0
+  let L = len(a)
+  while i < L:
+    yield a[i]
+    inc(i)
+    assert(len(a) == L, "seq modified while iterating over it")
+
+# Works fine
+var xs = @[1,2,3]
+for x in myitems(xs):
+  inc x
+
+# Tuples don't work
+var ys = @[(1,"a"),(2,"b"),(3,"c")]
+for y in myitems(ys):
+  inc y[0]
+
diff --git a/tests/clearmsg/ta.nim b/tests/clearmsg/ta.nim
index b21522d12..38449c319 100644
--- a/tests/clearmsg/ta.nim
+++ b/tests/clearmsg/ta.nim
@@ -1,5 +1,5 @@
 discard """
-  errormsg: 'type mismatch: got (mc.typ)'
+  errormsg: "type mismatch: got (mc.typ)"
   line: 12
 """
 
diff --git a/tests/clearmsg/tconsttypemismatch.nim b/tests/clearmsg/tconsttypemismatch.nim
new file mode 100644
index 000000000..edf480348
--- /dev/null
+++ b/tests/clearmsg/tconsttypemismatch.nim
@@ -0,0 +1,8 @@
+discard """
+  file: "tconsttypemismatch.nim"
+  line: 7
+  errormsg: "type mismatch"
+"""
+# bug #2252
+const foo: int = 1000 / 30
+
diff --git a/tests/closure/tfib50.nim b/tests/closure/tfib50.nim
new file mode 100644
index 000000000..719aa3ad5
--- /dev/null
+++ b/tests/closure/tfib50.nim
@@ -0,0 +1,22 @@
+discard """
+  output: "20365011074"
+"""
+
+import tables
+
+proc memoize(f: proc (a: int64): int64): proc (a: int64): int64 =
+    var previous = initTable[int64, int64]()
+    return proc(i: int64): int64 =
+        if not previous.hasKey i:
+            previous[i] = f(i)
+        return previous[i]
+
+var fib: proc(a: int64): int64
+
+fib = memoize(proc (i: int64): int64 =
+    if i == 0 or i == 1:
+        return 1
+    return fib(i-1) + fib(i-2)
+)
+
+echo fib(50)
diff --git a/tests/closure/tinvalidclosure.nim b/tests/closure/tinvalidclosure.nim
index 06e19df3c..c9136a736 100644
--- a/tests/closure/tinvalidclosure.nim
+++ b/tests/closure/tinvalidclosure.nim
@@ -1,12 +1,12 @@
 discard """
   line: 12
-  errormsg: "type mismatch: got (proc (int){.closure, gcsafe.})"
+  errormsg: "type mismatch: got (proc (x: int){.closure, gcsafe, locks: 0.})"
 """
 
 proc ugh[T](x: T) {.closure.} =
   echo "ugha"
 
 
-proc takeCdecl(p: proc (x: int) {.cdecl.}) = nil
+proc takeCdecl(p: proc (x: int) {.cdecl.}) = discard
 
 takeCDecl(ugh[int])
diff --git a/tests/closure/tissue1642.nim b/tests/closure/tissue1642.nim
new file mode 100644
index 000000000..e3028c88e
--- /dev/null
+++ b/tests/closure/tissue1642.nim
@@ -0,0 +1,7 @@
+discard """
+  file: "tissue1642.nim"
+  disabled: true
+"""
+block:
+  var i = 0
+  proc p() = inc(i)
diff --git a/tests/closure/ttimeinfo.nim b/tests/closure/ttimeinfo.nim
new file mode 100644
index 000000000..3138ae72e
--- /dev/null
+++ b/tests/closure/ttimeinfo.nim
@@ -0,0 +1,15 @@
+# bug #2073
+
+import sequtils
+import times
+
+# 1
+proc f(n: int): TimeInfo =
+  TimeInfo(year: n, month: mJan, monthday: 1)
+
+echo toSeq(2000 || 2015).map(f)
+
+# 2
+echo toSeq(2000 || 2015).map(proc (n: int): TimeInfo =
+  TimeInfo(year: n, month: mJan, monthday: 1)
+)
diff --git a/tests/collections/tindexby.nim b/tests/collections/tindexby.nim
new file mode 100644
index 000000000..f374d5504
--- /dev/null
+++ b/tests/collections/tindexby.nim
@@ -0,0 +1,22 @@
+import tables
+
+doAssert indexBy(newSeq[int](), proc(x: int):int = x) == initTable[int, int](), "empty int table"
+
+var tbl1 = initTable[int, int]()
+tbl1.add(1,1)
+tbl1.add(2,2)
+doAssert indexBy(@[1,2], proc(x: int):int = x) == tbl1, "int table"
+
+type
+  TElem = object
+    foo: int
+    bar: string
+    
+let
+  elem1 = TElem(foo: 1, bar: "bar")
+  elem2 = TElem(foo: 2, bar: "baz")
+  
+var tbl2 = initTable[string, TElem]()
+tbl2.add("bar", elem1)
+tbl2.add("baz", elem2)
+doAssert indexBy(@[elem1,elem2], proc(x: TElem): string = x.bar) == tbl2, "element table"
diff --git a/tests/table/ttableconstr.nim b/tests/collections/ttableconstr.nim
index 1a21a18d1..1a21a18d1 100644
--- a/tests/table/ttableconstr.nim
+++ b/tests/collections/ttableconstr.nim
diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim
index f374d5504..3a923610e 100644
--- a/tests/collections/ttables.nim
+++ b/tests/collections/ttables.nim
@@ -1,22 +1,152 @@
-import tables
-
-doAssert indexBy(newSeq[int](), proc(x: int):int = x) == initTable[int, int](), "empty int table"
-
-var tbl1 = initTable[int, int]()
-tbl1.add(1,1)
-tbl1.add(2,2)
-doAssert indexBy(@[1,2], proc(x: int):int = x) == tbl1, "int table"
-
-type
-  TElem = object
-    foo: int
-    bar: string
-    
-let
-  elem1 = TElem(foo: 1, bar: "bar")
-  elem2 = TElem(foo: 2, bar: "baz")
+discard """
+  output: '''true'''
+"""
+
+import hashes, tables
+
+const
+  data = {
+    "34": 123456, "12": 789,
+    "90": 343, "0": 34404,
+    "1": 344004, "2": 344774,
+    "3": 342244, "4": 3412344,
+    "5": 341232144, "6": 34214544,
+    "7": 3434544, "8": 344544,
+    "9": 34435644, "---00": 346677844,
+    "10": 34484, "11": 34474, "19": 34464,
+    "20": 34454, "30": 34141244, "40": 344114,
+    "50": 344490, "60": 344491, "70": 344492,
+    "80": 344497}
+
+  sorteddata = {
+    "---00": 346677844,
+    "0": 34404,
+    "1": 344004,
+    "10": 34484, 
+    "11": 34474,
+    "12": 789,
+    "19": 34464,
+    "2": 344774, "20": 34454, 
+    "3": 342244, "30": 34141244,
+    "34": 123456,
+    "4": 3412344, "40": 344114,
+    "5": 341232144, "50": 344490, 
+    "6": 34214544, "60": 344491,
+    "7": 3434544, "70": 344492,
+    "8": 344544, "80": 344497,
+    "9": 34435644,
+    "90": 343}
+
+block tableTest1:
+  var t = initTable[tuple[x, y: int], string]()
+  t[(0,0)] = "00"
+  t[(1,0)] = "10"
+  t[(0,1)] = "01"
+  t[(1,1)] = "11"
+  for x in 0..1:
+    for y in 0..1:
+      assert t[(x,y)] == $x & $y
+  assert($t == 
+    "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
+
+block tableTest2:
+  var t = initTable[string, float]()
+  t["test"] = 1.2345
+  t["111"] = 1.000043
+  t["123"] = 1.23
+  t.del("111")
   
-var tbl2 = initTable[string, TElem]()
-tbl2.add("bar", elem1)
-tbl2.add("baz", elem2)
-doAssert indexBy(@[elem1,elem2], proc(x: TElem): string = x.bar) == tbl2, "element table"
+  t["012"] = 67.9
+  t["123"] = 1.5 # test overwriting
+  
+  assert t["123"] == 1.5
+  assert t["111"] == 0.0 # deleted
+  assert(not hasKey(t, "111"))
+  
+  for key, val in items(data): t[key] = val.toFloat
+  for key, val in items(data): assert t[key] == val.toFloat
+
+  assert(not t.hasKeyOrPut("456", 4.0))     # test absent key
+  assert t.hasKeyOrPut("012", 3.0)          # test present key
+  var x = t.mgetOrPut("111", 1.5)           # test absent key
+  x = x * 2
+  assert x == 3.0
+  x = t.mgetOrPut("test", 1.5)              # test present key
+  x = x * 2
+  assert x == 2 * 1.2345
+
+block orderedTableTest1:
+  var t = initOrderedTable[string, int](2)
+  for key, val in items(data): t[key] = val
+  for key, val in items(data): assert t[key] == val
+  var i = 0
+  # `pairs` needs to yield in insertion order:
+  for key, val in pairs(t):
+    assert key == data[i][0]
+    assert val == data[i][1]
+    inc(i)
+
+  for key, val in mpairs(t): val = 99
+  for val in mvalues(t): assert val == 99
+
+block countTableTest1:
+  var s = data.toTable
+  var t = initCountTable[string]()
+  for k in s.keys: t.inc(k)
+  for k in t.keys: assert t[k] == 1
+  t.inc("90", 3)
+  t.inc("12", 2)
+  t.inc("34", 1)
+  assert t.largest()[0] == "90"
+
+  t.sort()
+  var i = 0
+  for k, v in t.pairs:
+    case i
+    of 0: assert k == "90" and v == 4
+    of 1: assert k == "12" and v == 3
+    of 2: assert k == "34" and v == 2
+    else: break
+    inc i
+
+block mpairsTableTest1:
+  var t = initTable[string, int]()
+  t["a"] = 1
+  t["b"] = 2
+  t["c"] = 3
+  t["d"] = 4
+  for k, v in t.mpairs:
+    if k == "a" or k == "c":
+      v = 9
+
+  for k, v in t.pairs:
+    if k == "a" or k == "c":
+      assert v == 9
+    else:
+      assert v != 1 and v != 3
+
+block SyntaxTest:
+  var x = toTable[int, string]({:})
+
+proc orderedTableSortTest() =
+  var t = initOrderedTable[string, int](2)
+  for key, val in items(data): t[key] = val
+  for key, val in items(data): assert t[key] == val
+  t.sort(proc (x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key))
+  var i = 0
+  # `pairs` needs to yield in sorted order:
+  for key, val in pairs(t):
+    doAssert key == sorteddata[i][0]
+    doAssert val == sorteddata[i][1]
+    inc(i)
+
+  # check that lookup still works:
+  for key, val in pairs(t):
+    doAssert val == t[key]
+  # check that insert still works:
+  t["newKeyHere"] = 80
+
+
+orderedTableSortTest()
+echo "true"
+
diff --git a/tests/table/ttables2.nim b/tests/collections/ttables2.nim
index 611f3f8ec..6f3fa841a 100644
--- a/tests/table/ttables2.nim
+++ b/tests/collections/ttables2.nim
@@ -16,5 +16,15 @@ proc run1() =         # occupied Memory stays constant, but
   for i in 1 .. 50:   # aborts at run: 44 on win32 with 3.2GB with out of memory
     TestHashIntInt()
 
+# bug #2107
+
+var delTab = initTable[int,int](4)
+
+for i in 1..4:
+  delTab[i] = i
+  delTab.del(i)
+delTab[5] = 5
+
+
 run1()
 echo "true"
diff --git a/tests/table/ptables.nim b/tests/collections/ttablesref.nim
index 79a9aab17..16b0d831e 100644
--- a/tests/table/ptables.nim
+++ b/tests/collections/ttablesref.nim
@@ -2,7 +2,7 @@ discard """
   output: '''true'''
 """
 
-import hashes, tables
+import hashes, tables, sequtils
 
 const
   data = {
@@ -47,7 +47,7 @@ block tableTest1:
     for y in 0..1:
       assert t[(x,y)] == $x & $y
   assert($t == 
-    "{(x: 0, y: 0): 00, (x: 0, y: 1): 01, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
+    "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
 
 block tableTest2:
   var t = newTable[string, float]()
@@ -84,7 +84,7 @@ block orderedTableTest1:
 block countTableTest1:
   var s = data.toTable
   var t = newCountTable[string]()
-  for k in s.Keys: t.inc(k)
+  for k in s.keys: t.inc(k)
   for k in t.keys: assert t[k] == 1
   t.inc("90", 3)
   t.inc("12", 2)
@@ -103,9 +103,10 @@ block countTableTest1:
 
 block SyntaxTest:
   var x = newTable[int, string]({:})
+  discard x
 
 block nilTest:
-  var i, j: PTable[int, int] = nil
+  var i, j: TableRef[int, int] = nil
   assert i == j
   j = newTable[int, int]()
   assert i != j
@@ -131,6 +132,10 @@ proc orderedTableSortTest() =
   # check that insert still works:
   t["newKeyHere"] = 80
 
+block anonZipTest:
+  let keys = @['a','b','c']
+  let values = @[1, 2, 3]
+  doAssert "{a: 1, b: 2, c: 3}" == $ toTable zip(keys, values)
 
 orderedTableSortTest()
 echo "true"
diff --git a/tests/table/ptables2.nim b/tests/collections/ttablesref2.nim
index 939de2b84..939de2b84 100644
--- a/tests/table/ptables2.nim
+++ b/tests/collections/ttablesref2.nim
diff --git a/tests/concepts/mvarconcept.nim b/tests/concepts/mvarconcept.nim
new file mode 100644
index 000000000..0f9d0beff
--- /dev/null
+++ b/tests/concepts/mvarconcept.nim
@@ -0,0 +1,13 @@
+type RNG* = concept var rng
+  rng.randomUint32() is uint32
+
+type MersenneTwister* = object
+
+proc randomUint32*(self: var MersenneTwister): uint32 = 5
+
+proc randomInt*(rng: var RNG; max: Positive): Natural = 5
+
+var mersenneTwisterInst = MersenneTwister()
+
+proc randomInt*(max: Positive): Natural =
+  mersenneTwisterInst.randomInt(max)
diff --git a/tests/metatype/udtcmanual.nim b/tests/concepts/tmanual.nim
index dd44298dc..7cf08af06 100644
--- a/tests/metatype/udtcmanual.nim
+++ b/tests/concepts/tmanual.nim
@@ -21,10 +21,10 @@ template reject(e: expr) =
   static: assert(not compiles(e))
 
 type
-  Container[T] = generic C
-    C.len is Ordinal
+  Container[T] = concept c
+    c.len is Ordinal
     items(c) is iterator
-    for value in C:
+    for value in c:
       type(value) is T
 
 proc takesIntContainer(c: Container[int]) =
diff --git a/tests/metatype/swizzle.nim b/tests/concepts/tswizzle.nim
index ce18fa234..07205d454 100644
--- a/tests/metatype/swizzle.nim
+++ b/tests/concepts/tswizzle.nim
@@ -3,6 +3,7 @@ discard """
 [1, 3]
 [2, 1, 2]
 '''
+  disabled: "true"
 """
 
 import macros, strutils
@@ -18,14 +19,14 @@ proc swizzleIdx(c: char): int =
     of 'x': 0
     of 'y': 1
     of 'z': 2
-    of 'w': 3    
+    of 'w': 3
     of 'r': 0
     of 'g': 1
     of 'b': 2
-    of 'a': 3    
+    of 'a': 3
     else: 0
 
-proc isSwizzle(s: string): bool =
+proc isSwizzle(s: string): bool {.compileTime.} =
   template trySet(name, set) =
     block search:
       for c in s:
@@ -35,11 +36,11 @@ proc isSwizzle(s: string): bool =
 
   trySet coords, {'x', 'y', 'z', 'w'}
   trySet colors, {'r', 'g', 'b', 'a'}
-  
+
   return false
 
-type 
-  StringIsSwizzle = generic value
+type
+  StringIsSwizzle = concept value
     value.isSwizzle
 
   SwizzleStr = static[string] and StringIsSwizzle
@@ -47,33 +48,33 @@ type
 proc foo(x: SwizzleStr) =
   echo "sw"
 
-accept foo("xx")
+#foo("xx")
 reject foo("xe")
 
-type 
+type
   Vec[N: static[int]; T] = array[N, T]
 
+when false:
+  proc card(x: Vec): int = x.N
+  proc `$`(x: Vec): string = x.repr.strip
 
-proc card(x: Vec): int = x.N
-proc `$`(x: Vec): string = x.repr.strip
+  macro `.`(x: Vec, swizzle: SwizzleStr): expr =
+    var
+      cardinality = swizzle.len
+      values = newNimNode(nnkBracket)
+      v = genSym()
 
-macro `.`(x: Vec, swizzle: SwizzleStr): expr =
-  var
-    cardinality = swizzle.len
-    values = newNimNode(nnkBracket)
-    v = genSym()
+    for c in swizzle:
+      values.add newNimNode(nnkBracketExpr).add(
+        v, c.swizzleIdx.newIntLitNode)
 
-  for c in swizzle:
-    values.add newNimNode(nnkBracketExpr).add(
-      v, c.swizzleIdx.newIntLitNode)
-  
-  return quote do:
-    let `v` = `x`
-    Vec[`cardinality`, `v`.T](`values`)
+    return quote do:
+      let `v` = `x`
+      Vec[`cardinality`, `v`.T](`values`)
 
 var z = Vec([1, 2, 3])
 
-echo z.card
-echo z.xz
-echo z.yxy
+#echo z.card
+#echo z.xz
+#echo z.yxy
 
diff --git a/tests/concepts/tusertypeclasses.nim b/tests/concepts/tusertypeclasses.nim
new file mode 100644
index 000000000..612556949
--- /dev/null
+++ b/tests/concepts/tusertypeclasses.nim
@@ -0,0 +1,68 @@
+discard """
+  output: '''Sortable
+Sortable
+Container
+true
+true
+false
+false
+false
+'''
+"""
+
+import typetraits
+
+type
+  TObj = object
+    x: int
+
+  Sortable = concept x, y
+    (x < y) is bool
+
+  ObjectContainer = concept C
+    C.len is Ordinal
+    for v in items(C):
+      v.type is tuple|object
+
+proc foo(c: ObjectContainer) =
+  echo "Container"
+
+proc foo(x: Sortable) =
+  echo "Sortable"
+
+foo 10
+foo "test"
+foo(@[TObj(x: 10), TObj(x: 20)])
+
+proc intval(x: int): int = 10
+
+# check real and virtual fields
+type
+  TFoo = concept T
+    T.x
+    y(T)
+    intval T.y
+    let z = intval(T.y)
+
+proc y(x: TObj): int = 10
+
+proc testFoo(x: TFoo) = discard
+testFoo(TObj(x: 10))
+
+type
+  Matrix[Rows, Cols: static[int]; T] = concept M
+    M.M == Rows
+    M.N == Cols
+    M.T is T
+
+  MyMatrix[M, N: static[int]; T] = object
+    data: array[M*N, T]
+
+var x: MyMatrix[3, 3, int]
+
+echo x is Matrix
+echo x is Matrix[3, 3, int]
+echo x is Matrix[3, 3, float]
+echo x is Matrix[4, 3, int]
+echo x is Matrix[3, 4, int]
+
diff --git a/tests/metatype/tusertypeclasses2.nim b/tests/concepts/tusertypeclasses2.nim
index 77c70d7a6..ae05540cd 100644
--- a/tests/metatype/tusertypeclasses2.nim
+++ b/tests/concepts/tusertypeclasses2.nim
@@ -1,5 +1,5 @@
 type
-  hasFieldX = generic z
+  hasFieldX = concept z
     z.x is int
 
   obj_x = object
@@ -7,7 +7,7 @@ type
 
   ref_obj_x = ref object
     x: int
-  
+
   ref_to_obj_x = ref obj_x
 
   p_o_x = ptr obj_x
diff --git a/tests/concepts/tvarconcept.nim b/tests/concepts/tvarconcept.nim
new file mode 100644
index 000000000..203ef3cdc
--- /dev/null
+++ b/tests/concepts/tvarconcept.nim
@@ -0,0 +1,9 @@
+discard """
+  output: "5"
+"""
+
+# bug #2346, bug #2404
+
+import mvarconcept
+
+echo randomInt(5)
diff --git a/tests/converter/ttypeconverter1.nim b/tests/converter/ttypeconverter1.nim
index b9a5e88ae..510b84700 100644
--- a/tests/converter/ttypeconverter1.nim
+++ b/tests/converter/ttypeconverter1.nim
@@ -1,3 +1,7 @@
+discard """
+  output: '''foo
+true'''
+"""
 
 converter p(i: int): bool = return i != 0
 
@@ -6,3 +10,6 @@ if 1:
 while 0: 
   echo "bar"
 
+var a: array[3, bool]
+a[0] = 3
+echo a[0]
diff --git a/tests/cpp/tget_subsystem.nim b/tests/cpp/tget_subsystem.nim
new file mode 100644
index 000000000..461914739
--- /dev/null
+++ b/tests/cpp/tget_subsystem.nim
@@ -0,0 +1,23 @@
+discard """
+  cmd: "nim cpp $file"
+"""
+
+{.emit: """
+
+namespace System {
+  struct Input {};
+}
+
+struct SystemManager {
+  template <class T>
+  static T* getSubsystem() { return new T; }
+};
+
+""".}
+
+type Input {.importcpp: "System::Input".} = object
+proc getSubsystem*[T](): ptr T {.
+  importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.}
+
+let input: ptr Input = getSubsystem[Input]()
+
diff --git a/tests/cpp/trawsockets.nim b/tests/cpp/trawsockets.nim
new file mode 100644
index 000000000..bc129de57
--- /dev/null
+++ b/tests/cpp/trawsockets.nim
@@ -0,0 +1,5 @@
+discard """
+  cmd: "nim cpp $file"
+"""
+
+import rawsockets
diff --git a/tests/cpp/tstaticvar_via_typedesc.nim b/tests/cpp/tstaticvar_via_typedesc.nim
new file mode 100644
index 000000000..7a9fa2afc
--- /dev/null
+++ b/tests/cpp/tstaticvar_via_typedesc.nim
@@ -0,0 +1,20 @@
+discard """
+  cmd: "nim cpp $file"
+  output: "42"
+"""
+
+# bug #2324
+
+static: assert defined(cpp), "compile in cpp mode"
+
+{.emit: """
+class Foo {
+public:
+    static int x;
+};
+int Foo::x = 42;
+""".}
+
+type Foo {.importcpp:"Foo".} = object
+proc x* (this: typedesc[Foo]): int {.importcpp:"Foo::x@", nodecl.}
+echo Foo.x
diff --git a/tests/cpp/tthread_createthread.nim b/tests/cpp/tthread_createthread.nim
new file mode 100644
index 000000000..0dc081268
--- /dev/null
+++ b/tests/cpp/tthread_createthread.nim
@@ -0,0 +1,14 @@
+discard """
+  cmd: "nim cpp --hints:on --threads:on $options $file"
+"""
+
+proc threadMain(a: int) {.thread.} =
+    discard
+
+proc main() =
+    var thread: TThread[int]
+
+    thread.createThread(threadMain, 0)
+    thread.joinThreads()
+
+main()
\ No newline at end of file
diff --git a/tests/cpp/ttypeinfo.nim b/tests/cpp/ttypeinfo.nim
new file mode 100644
index 000000000..1529c86e9
--- /dev/null
+++ b/tests/cpp/ttypeinfo.nim
@@ -0,0 +1,5 @@
+discard """
+  cmd: "nim cpp $file"
+"""
+
+import typeinfo
diff --git a/tests/cpp/tvector_iterator.nim b/tests/cpp/tvector_iterator.nim
new file mode 100644
index 000000000..cb5ab33af
--- /dev/null
+++ b/tests/cpp/tvector_iterator.nim
@@ -0,0 +1,19 @@
+discard """
+  cmd: "nim cpp $file"
+"""
+
+{.emit: """
+
+template <class T>
+struct Vector {
+  struct Iterator {};
+};
+
+""".}
+
+type
+  Vector {.importcpp: "Vector".} [T] = object
+  VectorIterator {.importcpp: "Vector<'0>::Iterator".} [T] = object
+
+var x: VectorIterator[void]
+
diff --git a/tests/cpp/tvectorseq.nim b/tests/cpp/tvectorseq.nim
new file mode 100644
index 000000000..6eb5dc9e4
--- /dev/null
+++ b/tests/cpp/tvectorseq.nim
@@ -0,0 +1,38 @@
+discard """
+  output: '''(x: 1.0)
+(x: 0.0)'''
+  cmd: "nim cpp $file"
+  disabled: "true"
+"""
+
+# This cannot work yet because we omit type information for importcpp'ed types.
+# Fixing this is not hard, but also requires fixing Urhonimo.
+
+# bug #2536
+
+{.emit: """/*TYPESECTION*/
+struct Vector3 {
+public:
+  Vector3(): x(5) {}
+  Vector3(float x_): x(x_) {}
+  float x;
+};
+""".}
+
+type Vector3 {.importcpp: "Vector3", nodecl} = object
+  x: cfloat
+
+proc constructVector3(a: cfloat): Vector3 {.importcpp: "Vector3(@)", nodecl}
+
+# hack around another codegen issue: Generics are attached to where they came
+# from:
+proc `$!`(v:  seq[Vector3]): string = "(x: " & $v[0].x & ")"
+
+proc vec3List*(): seq[Vector3] =
+  let s = @[constructVector3(cfloat(1))]
+  echo($!s)
+  result = s
+  echo($!result)
+
+let f = vec3List()
+#echo($!f)
diff --git a/tests/deprecated/tdeprecated.nim b/tests/deprecated/tdeprecated.nim
index f41f0a72f..955a7f6ad 100644
--- a/tests/deprecated/tdeprecated.nim
+++ b/tests/deprecated/tdeprecated.nim
@@ -1,11 +1,9 @@
 discard """
-  line: 9
-  errormsg: "'a' is deprecated [Deprecated]"
+  nimout: "a is deprecated [Deprecated]"
 """
 
 var
   a {.deprecated.}: array[0..11, int]
-  
-a[8] = 1
 
+a[8] = 1
 
diff --git a/tests/destructor/tdestructor.nim b/tests/destructor/tdestructor.nim
index f0ea3c5c6..639dba941 100644
--- a/tests/destructor/tdestructor.nim
+++ b/tests/destructor/tdestructor.nim
@@ -22,6 +22,8 @@ myobj destroyed
 '''
 """
 
+{.experimental.}
+
 type
   TMyObj = object
     x, y: int
@@ -38,7 +40,7 @@ type
     x: A
     y: B
     z: C
-  
+
   TObjKind = enum A, B, C, D
 
   TCaseObj = object
@@ -55,14 +57,14 @@ type
         q: TMyGeneric3[TMyObj, int, int]
       r: string
 
-proc destroy(o: var TMyObj) {.override.} =
+proc `=destroy`(o: var TMyObj) =
   if o.p != nil: dealloc o.p
   echo "myobj destroyed"
 
-proc destroy(o: var TMyGeneric1) {.override.} =
+proc `=destroy`(o: var TMyGeneric1) =
   echo "mygeneric1 destroyed"
 
-proc destroy[A, B](o: var TMyGeneric2[A, B]) {.override.} =
+proc `=destroy`[A, B](o: var TMyGeneric2[A, B]) =
   echo "mygeneric2 destroyed"
 
 proc open: TMyObj =
@@ -81,12 +83,12 @@ proc mygeneric1() =
 
 proc mygeneric2[T](val: T) =
   var a = open()
-  
+
   var b = TMyGeneric2[int, T](x: 10, y: val)
   echo "mygeneric2 constructed"
 
   var c = TMyGeneric3[int, int, string](x: 10, y: 20, z: "test")
-  
+
 proc mygeneric3 =
   var x = TMyGeneric3[int, string, TMyGeneric1[int]](
     x: 10, y: "test", z: TMyGeneric1[int](x: 10))
@@ -109,11 +111,11 @@ proc caseobj =
   block:
     echo "----"
     var o1 = TCaseObj(kind: A, x: TMyGeneric1[int](x: 10))
-  
+
   block:
     echo "----"
     var o2 = TCaseObj(kind: B, y: open())
-  
+
   block:
     echo "----"
     var o3 = TCaseObj(kind: D, innerKind: B, r: "test",
diff --git a/tests/destructor/tdestructor2.nim b/tests/destructor/tdestructor2.nim
index a5b62860c..34fa466af 100644
--- a/tests/destructor/tdestructor2.nim
+++ b/tests/destructor/tdestructor2.nim
@@ -1,21 +1,27 @@
 discard """
-  line: 20
-  errormsg: " usage of a type with a destructor in a non destructible context"
+  line: 23
+  nimout: " usage of a type with a destructor in a non destructible context"
 """
 
-type  
+{.experimental.}
+
+type
   TMyObj = object
     x, y: int
     p: pointer
-    
-proc destroy(o: var TMyObj) {.override.} =
+
+proc `=destroy`(o: var TMyObj) =
   if o.p != nil: dealloc o.p
-  
+
 proc open: TMyObj =
   result = TMyObj(x: 1, y: 2, p: alloc(3))
 
 
 proc `$`(x: TMyObj): string = $x.y
 
-echo open()
+proc foo =
+  discard open()
+
+# XXX doesn't trigger this yet:
+#echo open()
 
diff --git a/tests/dir with space/tspace.nim b/tests/dir with space/tspace.nim
new file mode 100644
index 000000000..8db4b52f2
--- /dev/null
+++ b/tests/dir with space/tspace.nim
@@ -0,0 +1,3 @@
+# Test for the compiler to be able to compile a Nim file with spaces in it.
+
+echo("Successful")
\ No newline at end of file
diff --git a/tests/dll/client.nimrod.cfg b/tests/dll/client.nim.cfg
index 0e044a829..0e044a829 100644
--- a/tests/dll/client.nimrod.cfg
+++ b/tests/dll/client.nim.cfg
diff --git a/tests/dll/server.nimrod.cfg b/tests/dll/server.nim.cfg
index 02393ba8b..02393ba8b 100644
--- a/tests/dll/server.nimrod.cfg
+++ b/tests/dll/server.nim.cfg
diff --git a/tests/effects/teffects1.nim b/tests/effects/teffects1.nim
index e32096b57..ea1ea7b21 100644
--- a/tests/effects/teffects1.nim
+++ b/tests/effects/teffects1.nim
@@ -1,5 +1,4 @@
 discard """
-  line: 2170
   file: "system.nim"
   errormsg: "can raise an unlisted exception: ref IOError"
 """
diff --git a/tests/effects/tgcsafe.nim b/tests/effects/tgcsafe.nim
index 0d5109439..d146794b6 100644
--- a/tests/effects/tgcsafe.nim
+++ b/tests/effects/tgcsafe.nim
@@ -1,5 +1,5 @@
 discard """
-  line: 16
+  line: 17
   errormsg: "'mainUnsafe' is not GC-safe"
   cmd: "nim $target --hints:on --threads:on $options $file"
 """
diff --git a/tests/enum/tenumitems.nim b/tests/enum/tenumitems.nim
index b92cff6bf..04737fa9e 100644
--- a/tests/enum/tenumitems.nim
+++ b/tests/enum/tenumitems.nim
@@ -1,6 +1,6 @@
 discard """
   line: 7
-  errormsg: "expression 'items' cannot be called"
+  errormsg: "undeclared identifier: 'items'"
 """
 
 type a = enum b,c,d
diff --git a/tests/exception/tdefer1.nim b/tests/exception/tdefer1.nim
new file mode 100644
index 000000000..61439530a
--- /dev/null
+++ b/tests/exception/tdefer1.nim
@@ -0,0 +1,18 @@
+discard """
+  output: '''hi
+hi'''
+"""
+
+# bug #1742
+
+template test(): expr =
+    let a = 0
+    defer: echo "hi"
+    a
+
+let i = test()
+
+import strutils
+let x = try: parseInt("133a")
+        except: -1
+        finally: echo "hi"
diff --git a/tests/exception/texceptions.nim b/tests/exception/texceptions.nim
index 69b2d0f6a..bdf338599 100644
--- a/tests/exception/texceptions.nim
+++ b/tests/exception/texceptions.nim
@@ -35,9 +35,9 @@ echo ""
 proc reraise_in_except =
   try:
     echo "BEFORE"
-    raise newException(EIO, "")
+    raise newException(IOError, "")
 
-  except EIO:
+  except IOError:
     echo "EXCEPT"
     raise
 
@@ -52,7 +52,7 @@ echo ""
 proc return_in_except =
   try:
     echo "BEFORE"
-    raise newException(EIO, "")
+    raise newException(IOError, "")
 
   except:
     echo "EXCEPT"
diff --git a/tests/exception/treraise.nim b/tests/exception/treraise.nim
index cbd0b5f8a..b2a11d34f 100644
--- a/tests/exception/treraise.nim
+++ b/tests/exception/treraise.nim
@@ -4,8 +4,8 @@ discard """
   exitcode: "1"
 """
 type
-  ESomething = object of E_Base
-  ESomeOtherErr = object of E_Base
+  ESomething = object of Exception
+  ESomeOtherErr = object of Exception
 
 proc genErrors(s: string) =
   if s == "error!":
diff --git a/tests/exprs/texprstmt.nim b/tests/exprs/texprstmt.nim
index 355da2407..79323d82a 100644
--- a/tests/exprs/texprstmt.nim
+++ b/tests/exprs/texprstmt.nim
@@ -7,6 +7,6 @@ discard """
 
 proc test: string =
   result = "blah"
-  result[1 .. -1]
+  result[1 .. ^1]
 
 echo test()
diff --git a/tests/exprs/thighCString.nim b/tests/exprs/thighCString.nim
new file mode 100644
index 000000000..543966df4
--- /dev/null
+++ b/tests/exprs/thighCString.nim
@@ -0,0 +1,6 @@
+discard """
+  output: "5"
+"""
+let test = cstring("foobar")
+
+echo high(test)
diff --git a/tests/exprs/tresultwarning.nim b/tests/exprs/tresultwarning.nim
new file mode 100644
index 000000000..32934408e
--- /dev/null
+++ b/tests/exprs/tresultwarning.nim
@@ -0,0 +1,6 @@
+discard """
+  nimout: "Special variable 'result' is shadowed. [ResultShadowed]"
+"""
+
+proc test(): string =
+  var result = "foo"
diff --git a/tests/fields/tfielditerator2.nim b/tests/fields/tfielditerator2.nim
index 76fa568f2..70ab9e2ab 100644
--- a/tests/fields/tfielditerator2.nim
+++ b/tests/fields/tfielditerator2.nim
@@ -5,16 +5,19 @@ a char: false
 an int: 5
 an int: 6
 a string: abc
-false
-true
-true
-false
-true
+a string: I'm root!
+CMP false
+CMP true
+CMP true
+CMP false
+CMP true
+CMP true
 a: a
 b: b
 x: 5
 y: 6
 z: abc
+thaRootMan: I'm root!
 myDisc: enC
 c: Z
 enC
@@ -23,7 +26,9 @@ Z
 """
 
 type
-  TMyObj = object
+  SomeRootObj = object of RootObj
+    thaRootMan: string
+  TMyObj = object of SomeRootObj
     a, b: char
     x, y: int
     z: string
@@ -41,6 +46,7 @@ proc p(x: string) = echo "a string: ", x
 
 proc myobj(a, b: char, x, y: int, z: string): TMyObj =
   result.a = a; result.b = b; result.x = x; result.y = y; result.z = z
+  result.thaRootMan = "I'm root!"
 
 var x = myobj('a', 'b', 5, 6, "abc")
 var y = myobj('A', 'b', 5, 9, "abc")
@@ -49,7 +55,7 @@ for f in fields(x):
   p f
 
 for a, b in fields(x, y):
-  echo a == b
+  echo "CMP ", a == b
 
 for key, val in fieldPairs(x):
   echo key, ": ", val
diff --git a/tests/fields/tfields_in_template.nim b/tests/fields/tfields_in_template.nim
new file mode 100644
index 000000000..9352a7a51
--- /dev/null
+++ b/tests/fields/tfields_in_template.nim
@@ -0,0 +1,15 @@
+discard """
+  output: '''n
+n'''
+"""
+
+# bug #1902
+# This works.
+for name, value in (n: "v").fieldPairs:
+  echo name
+
+# This doesn't compile - "expression 'name' has no type (or is ambiguous)".
+template wrapper: stmt =
+  for name, value in (n: "v").fieldPairs:
+    echo name
+wrapper()
diff --git a/tests/fields/tfields_with_break.nim b/tests/fields/tfields_with_break.nim
new file mode 100644
index 000000000..1f2632692
--- /dev/null
+++ b/tests/fields/tfields_with_break.nim
@@ -0,0 +1,33 @@
+discard """
+  output: '''(one: 1, two: 2, three: 3)
+1
+2
+3
+(one: 4, two: 5, three: 6)
+4
+(one: 7, two: 8, three: 9)
+7
+8
+9'''
+"""
+
+# bug #2134
+type
+    TestType = object
+        one: int
+        two: int
+        three: int
+
+var
+    ab = TestType(one:1, two:2, three:3)
+    ac = TestType(one:4, two:5, three:6)
+    ad = TestType(one:7, two:8, three:9)
+    tstSeq = [ab, ac, ad]
+
+for tstElement in mitems(tstSeq):
+    echo tstElement
+    for tstField in fields(tstElement):
+        #for tstField in [1,2,4,6]:
+        echo tstField
+        if tstField == 4:
+            break
diff --git a/tests/gc/closureleak.nim b/tests/gc/closureleak.nim
index 38ee1250a..1c39f43d5 100644
--- a/tests/gc/closureleak.nim
+++ b/tests/gc/closureleak.nim
@@ -7,7 +7,7 @@ from strutils import join
 type
   TFoo * = object
     id: int
-    func: proc(){.closure.}
+    fn: proc(){.closure.}
 var foo_counter = 0
 var alive_foos = newseq[int](0)
 
@@ -26,7 +26,7 @@ for i in 0 .. <10:
 
 for i in 0 .. <10:
   let f = newFoo()
-  f.func = proc = 
+  f.fn = proc = 
     echo f.id
 
 GC_fullcollect()
diff --git a/tests/gc/cyclecollector.nim b/tests/gc/cyclecollector.nim
new file mode 100644
index 000000000..46fed6c45
--- /dev/null
+++ b/tests/gc/cyclecollector.nim
@@ -0,0 +1,21 @@
+
+# Program to detect bug #1796 reliably
+
+type
+  Node = ref object
+    a, b: Node
+    leaf: string
+
+proc createCycle(leaf: string): Node =
+  new result
+  result.a = result
+  shallowCopy result.leaf, leaf
+
+proc main =
+  for i in 0 .. 100_000:
+    var leaf = "this is the leaf. it allocates"
+    let x = createCycle(leaf)
+    let y = createCycle(leaf)
+  echo "done ", getOccupiedMem()
+
+main()
diff --git a/tests/gc/gcleak4.nim b/tests/gc/gcleak4.nim
index 6f2b8a1fe..54e74ac7b 100644
--- a/tests/gc/gcleak4.nim
+++ b/tests/gc/gcleak4.nim
@@ -38,12 +38,14 @@ proc newPlus(a, b: ref TExpr): ref TPlusExpr =
   result.b = b
   result.op2 = $getOccupiedMem()
 
+const Limit = when compileOption("gc", "markAndSweep"): 5*1024*1024 else: 500_000
+
 for i in 0..100_000:
   var s: array[0..11, ref TExpr]
   for j in 0..high(s):
     s[j] = newPlus(newPlus(newLit(j), newLit(2)), newLit(4))
     if eval(s[j]) != j+6:
       quit "error: wrong result"
-  if getOccupiedMem() > 500_000: quit("still a leak!")
+  if getOccupiedMem() > Limit: quit("still a leak!")
 
 echo "no leak: ", getOccupiedMem()
diff --git a/tests/gc/gctest.nim b/tests/gc/gctest.nim
index 27134d7dd..2213a83ac 100644
--- a/tests/gc/gctest.nim
+++ b/tests/gc/gctest.nim
@@ -196,7 +196,8 @@ write(stdout, "starting main...\n")
 main()
 
 GC_fullCollect()
+# the M&S GC fails with this call and it's unclear why. Definitely something
+# we need to fix!
 GC_fullCollect()
 writeln(stdout, GC_getStatistics())
 write(stdout, "finished\n")
-
diff --git a/tests/gc/growobjcrash.nim b/tests/gc/growobjcrash.nim
new file mode 100644
index 000000000..a16468c7e
--- /dev/null
+++ b/tests/gc/growobjcrash.nim
@@ -0,0 +1,29 @@
+discard """
+  output: "works"
+"""
+
+import cgi, strtabs
+
+proc handleRequest(query: string): StringTableRef =
+  iterator foo(): StringTableRef {.closure.} =
+    var params = {:}.newStringTable()
+    for key, val in cgi.decodeData(query):
+      params[key] = val
+    yield params
+
+  let x = foo
+  result = x()
+
+const Limit = when compileOption("gc", "markAndSweep"): 5*1024*1024 else: 700_000
+
+proc main =
+  var counter = 0
+  for i in 0 .. 100_000:
+    for k, v in handleRequest("nick=Elina2&type=activate"):
+      inc counter
+      if counter mod 100 == 0:
+        if getOccupiedMem() > Limit:
+          quit "but now a leak"
+
+main()
+echo "works"
diff --git a/tests/generics/mdotlookup.nim b/tests/generics/mdotlookup.nim
index 0c4d0c87c..2984574c2 100644
--- a/tests/generics/mdotlookup.nim
+++ b/tests/generics/mdotlookup.nim
@@ -11,6 +11,6 @@ import sets
 
 var intset = initSet[int]()
 
-proc func*[T](a: T) =
+proc fn*[T](a: T) =
   if a in intset: echo("true")
   else: echo("false")
diff --git a/tests/generics/t1050.nim b/tests/generics/t1050.nim
new file mode 100644
index 000000000..a6f9a2482
--- /dev/null
+++ b/tests/generics/t1050.nim
@@ -0,0 +1,16 @@
+discard """
+  msg: "int"
+  output: "4"
+"""
+
+import typetraits
+
+type ArrayType[T] = distinct T
+
+proc arrayItem(a: ArrayType): auto =
+  static: echo(name(type(a).T))
+  result = (type(a).T)(4)
+
+var arr: ArrayType[int]
+echo arrayItem(arr)
+
diff --git a/tests/generics/t1056.nim b/tests/generics/t1056.nim
new file mode 100644
index 000000000..b1fe25894
--- /dev/null
+++ b/tests/generics/t1056.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''TMatrix[3, 3, system.int]
+3'''
+"""
+
+import typetraits
+
+type
+  TMatrix*[N,M: static[int], T] = object
+    data*: array[0..N*M-1, T]
+
+  TMat2[T] = TMatrix[2,2,T]
+
+proc echoMatrix(a: TMatrix) =
+  echo a.type.name
+  echo TMatrix.N
+
+proc echoMat2(a: TMat2) =
+  echo TMat2.M
+  
+var m = TMatrix[3,3,int](data: [1,2,3,4,5,6,7,8,9])
+
+echoMatrix m
+#echoMat2 m
+
diff --git a/tests/generics/t1789.nim b/tests/generics/t1789.nim
new file mode 100644
index 000000000..188db88f6
--- /dev/null
+++ b/tests/generics/t1789.nim
@@ -0,0 +1,44 @@
+discard """
+  output: "3\n0"
+"""
+
+# https://github.com/Araq/Nim/issues/1789
+
+type
+  Foo[N: static[int]] = object
+
+proc bindStaticN[N](foo: Foo[N]) =
+  var ar0: array[3, int]
+  var ar1: array[N, int]
+  var ar2: array[1..N, int]
+  var ar3: array[0..(N+10), float]
+  echo N
+
+var f: Foo[3]
+f.bindStaticN
+
+# case 2
+
+type
+  ObjectWithStatic[X, Y: static[int], T] = object
+    bar: array[X * Y, T]   # this one works
+
+  AliasWithStatic[X, Y: static[int], T] = array[X * Y, T]
+
+var
+  x: ObjectWithStatic[1, 2, int]
+  y: AliasWithStatic[2, 3, int]
+
+# case 3
+
+type
+  Bar[N: static[int], T] = object
+    bar: array[N, T]
+
+proc `[]`*[N, T](f: Bar[N, T], n: range[0..(N - 1)]): T =
+  assert high(n) == N-1
+  result = f.bar[n]
+  
+var b: Bar[3, int]
+echo b[2]
+
diff --git a/tests/generics/tableref_is_nil.nim b/tests/generics/tableref_is_nil.nim
new file mode 100644
index 000000000..1ad4b3b0c
--- /dev/null
+++ b/tests/generics/tableref_is_nil.nim
@@ -0,0 +1,9 @@
+discard """
+  output: "true"
+"""
+
+# bug #2221
+import tables
+
+var tblo: TableRef[string, int]
+echo tblo == nil
diff --git a/tests/generics/tarray_with_somenumber.nim b/tests/generics/tarray_with_somenumber.nim
new file mode 100644
index 000000000..0bf2537a1
--- /dev/null
+++ b/tests/generics/tarray_with_somenumber.nim
@@ -0,0 +1,11 @@
+discard """
+  output: '''@[0.9, 0.1]'''
+"""
+
+# bug #2304
+
+type TV2*[T:SomeNumber] = array[0..1, T]
+proc newV2T*[T](x, y: T=0): TV2[T] = [x, y]
+
+let x = newV2T[float](0.9, 0.1)
+echo(@x)
diff --git a/tests/generics/tconfusing_arrow.nim b/tests/generics/tconfusing_arrow.nim
new file mode 100644
index 000000000..6a5a9d682
--- /dev/null
+++ b/tests/generics/tconfusing_arrow.nim
@@ -0,0 +1,15 @@
+import algorithm, future
+
+type Deck = object
+  value: int
+
+proc sort(h: var seq[Deck]) =
+  # works:
+  h.sort(proc (x, y: Deck): auto = 
+    cmp(x.value, y.value))
+  # fails:
+  h.sort((x, y: Deck) => cmp(ord(x.value), ord(y.value)))
+
+var player: seq[Deck] = @[]
+
+player.sort()
diff --git a/tests/generics/tdotlookup.nim b/tests/generics/tdotlookup.nim
index d3deca7fc..17c60ded2 100644
--- a/tests/generics/tdotlookup.nim
+++ b/tests/generics/tdotlookup.nim
@@ -7,4 +7,4 @@ import mdotlookup
 
 foo(7)
 # bug #1444
-func(4)
+fn(4)
diff --git a/tests/generics/tforwardgeneric.nim b/tests/generics/tforwardgeneric.nim
index c5943b966..af0c7daf4 100644
--- a/tests/generics/tforwardgeneric.nim
+++ b/tests/generics/tforwardgeneric.nim
@@ -1,6 +1,7 @@
 discard """
   output: "1.1000000000000001e+00 11"
   ccodecheck: "!@'ClEnv'"
+  disabled: "true"
 """
 
 proc p[T](a, b: T): T
diff --git a/tests/generics/tgeneric3.nim b/tests/generics/tgeneric3.nim
index 6fb929efb..289bf1fd5 100644
--- a/tests/generics/tgeneric3.nim
+++ b/tests/generics/tgeneric3.nim
@@ -188,7 +188,7 @@ proc traceTree[T,D](root: PNode[T,D]) =
     write stdout, space
 
   proc doTrace(n: PNode[T,D], level: int) =
-    var space = repeatChar(2 * level)
+    var space = spaces(2 * level)
     traceln(space)
     write stdout, "node: "
     if n == nil:
diff --git a/tests/generics/tgeneric_closure.nim b/tests/generics/tgeneric_closure.nim
new file mode 100644
index 000000000..7198dce96
--- /dev/null
+++ b/tests/generics/tgeneric_closure.nim
@@ -0,0 +1,37 @@
+# Test to ensure TEventHandler is '.closure'
+
+# bug #1187
+
+type
+  TEventArgs* = object
+    skip*: bool
+  TEventHandler[T] = proc (e: var TEventArgs, data: T) {.closure.}
+  TEvent*[T] = object
+    #handlers: seq[TEventHandler[T]] # Does not work
+    handlers: seq[proc (e: var TEventArgs, data: T) {.closure.}] # works
+
+  TData = object
+    x: int
+
+  TSomething = object
+    s: TEvent[TData]
+
+proc init*[T](e: var TEvent[T]) =
+  e.handlers.newSeq(0)
+
+#proc add*[T](e: var TEvent[T], h: proc (e: var TEventArgs, data: T) {.closure.}) =
+# this line works
+proc add*[T](e: var TEvent[T], h: TEventHandler[T]) =
+  # this line does not work
+  e.handlers.add(h)
+
+proc main () =
+  var something: TSomething
+  something.s.init()
+  var fromOutside = 4711
+
+  something.s.add() do (e: var TEventArgs, data: TData):
+    var x = data.x
+    x = fromOutside
+
+main()
diff --git a/tests/generics/tgeneric_inheritance.nim b/tests/generics/tgeneric_inheritance.nim
new file mode 100644
index 000000000..432228797
--- /dev/null
+++ b/tests/generics/tgeneric_inheritance.nim
@@ -0,0 +1,19 @@
+discard """
+  output: "0.0"
+"""
+
+# bug #1919
+
+type
+  Base[M] = object of RootObj
+    a : M
+
+  Sub1[M] = object of Base[M]
+    b : int
+
+  Sub2[M] = object of Sub1[M]
+    c : int
+
+var x: Sub2[float]
+
+echo x.a
diff --git a/tests/generics/tmetafield.nim b/tests/generics/tmetafield.nim
index bbfca7e3c..7a2375abe 100644
--- a/tests/generics/tmetafield.nim
+++ b/tests/generics/tmetafield.nim
@@ -2,7 +2,7 @@ discard """
   cmd: "nim check $options $file"
   errormsg: "'proc' is not a concrete type"
   errormsg: "'Foo' is not a concrete type."
-  errormsg: "invalid type: 'TBaseMed'"
+  errormsg: "invalid type: 'proc' in this context: 'TBaseMed'"
 """
 
 type
diff --git a/tests/generics/tthread_generic.nim b/tests/generics/tthread_generic.nim
index 5887f7db3..fdd11d9d1 100644
--- a/tests/generics/tthread_generic.nim
+++ b/tests/generics/tthread_generic.nim
@@ -8,22 +8,22 @@ type
     b: proc(val: T) {.thread.}
 
 proc handleThreadFunc(arg: TThreadFuncArgs[int]){.thread.} =
-  var func = arg.a
+  var fn = arg.a
   var callback = arg.b
-  var output = func()
+  var output = fn()
   callback(output)
 
-proc `@||->`*[T](func: proc(): T {.thread.}, 
+proc `@||->`*[T](fn: proc(): T {.thread.}, 
                  callback: proc(val: T){.thread.}): TThread[TThreadFuncArgs[T]] =
   var thr: TThread[TThreadFuncArgs[T]]
   var args: TThreadFuncArgs[T]
-  args.a = func
+  args.a = fn
   args.b = callback
   createThread(thr, handleThreadFunc, args)
   return thr
 
-proc `||->`*[T](func: proc(): T{.thread.}, callback: proc(val: T){.thread.}) =
-  discard func @||-> callback
+proc `||->`*[T](fn: proc(): T{.thread.}, callback: proc(val: T){.thread.}) =
+  discard fn @||-> callback
 
 when isMainModule:
   import os
diff --git a/tests/generics/tunique_type.nim b/tests/generics/tunique_type.nim
new file mode 100644
index 000000000..da2f9e4b2
--- /dev/null
+++ b/tests/generics/tunique_type.nim
@@ -0,0 +1,67 @@
+# Bug #2022
+
+discard """
+  output: '''@[97, 45]
+@[true, false]
+@[false, false]'''
+"""
+
+## The goal of this snippet is to provide and test a construct for general-
+## purpose, random-access mapping. I use an AST-manipulation-based approach
+## because it's more efficient than using procedure pointers and less
+## verbose than defining a new callable type for every invocation of `map`.
+
+import future
+import macros
+import strutils
+
+#===============================================================================
+# Define a system for storing copies of ASTs as static strings.
+# This serves the same purpose as D's `alias` parameters for types, used heavily
+# in its popular `ranges` and `algorithm` modules.
+
+var exprNodes {.compileTime.} = newSeq[NimNode]()
+
+proc refExpr(exprNode: NimNode): string {.compileTime.} =
+  exprNodes.add exprNode.copy
+  "expr" & $(exprNodes.len - 1)
+
+proc derefExpr(exprRef: string): NimNode {.compileTime.} =
+  exprNodes[parseInt(exprRef[4 .. ^1])]
+
+#===============================================================================
+# Define a type that allows a callable expression to be mapped onto elements
+# of an indexable collection.
+
+type Mapped[Input; predicate: static[string]] = object
+  input: Input
+
+macro map(input, predicate: expr): expr =
+  let predicate = callsite()[2]
+  newNimNode(nnkObjConstr).add(
+    newNimNode(nnkBracketExpr).add(
+      ident"Mapped",
+      newNimNode(nnkTypeOfExpr).add(input),
+      newLit(refExpr(predicate))),
+    newNimNode(nnkExprColonExpr).add(
+      ident"input", input))
+
+proc `[]`(m: Mapped, i: int): auto =
+  macro buildResult: expr =
+    newCall(
+      derefExpr(m.predicate),
+      newNimNode(nnkBracketExpr).add(
+        newDotExpr(ident"m", ident"input"),
+        ident"i"))
+  buildResult()
+
+#===============================================================================
+# Test out our generic mapping construct.
+
+let a = "a-string".map(ord)
+let b = @["a", "seq"].map((e: string) => e == "a")
+let c = "another-string".map((e: char) => e == 'o')
+
+echo(@[a[0], a[1]]) # @[97, 45]
+echo(@[b[0], b[1]]) # @[true, false]
+echo(@[c[0], c[1]]) # @[false, false]
diff --git a/tests/generics/twrong_field_caching.nim b/tests/generics/twrong_field_caching.nim
new file mode 100644
index 000000000..595c58eb7
--- /dev/null
+++ b/tests/generics/twrong_field_caching.nim
@@ -0,0 +1,68 @@
+discard """
+  output: '''a23: 2x3
+a32: 3x2
+transpose A
+t32: 3x2
+transpose B
+x23: 2x3 (2x3)
+x32: 3x2 (3x2)'''
+"""
+
+# bug #2125
+# Suppose we have the following type for a rectangular array:
+
+type
+  RectArray*[R, C: static[int], T] = distinct array[R * C, T]
+ 
+var a23: RectArray[2, 3, int]
+var a32: RectArray[3, 2, int]
+ 
+echo "a23: ", a23.R, "x", a23.C
+echo "a32: ", a32.R, "x", a32.C
+
+# Output:
+# a23: 2x3
+# a32: 3x2
+
+# Looking good. Let's add a proc:
+proc transpose*[R, C, T](m: RectArray[R, C, T]): RectArray[C, R, T] =
+  echo "transpose A"
+
+var t32 = a23.transpose
+
+echo "t32: ", t32.R, "x", t32.C
+
+# Output:
+# t32: 3x2
+ 
+ 
+# Everything is still OK. Now let's use the rectangular array inside another
+# generic type:
+type
+  Matrix*[R, C: static[int], T] = object
+    theArray*: RectArray[R, C, T]
+
+#var m23: Matrix[2, 3, int]
+#var m32: Matrix[3, 2, int]
+
+#echo "m23: ", m23.R, "x", m23.C, " (", m23.theArray.R, "x", m23.theArray.C, ")"
+#echo "m32: ", m32.R, "x", m32.C, " (", m32.theArray.R, "x", m32.theArray.C, ")"
+
+# Output:
+# m23: 2x3 (2x3)
+# m32: 3x2 (3x2)
+
+
+# Everything is still as expected. Now let's add the following proc:
+proc transpose*[R, C, T](m: Matrix[R, C, T]): Matrix[C, R, T] =
+  echo "transpose B"
+
+var x23: Matrix[2, 3, int]
+var x32 = x23.transpose
+
+echo "x23: ", x23.R, "x", x23.C, " (", x23.theArray.R, "x", x23.theArray.C, ")"
+echo "x32: ", x32.R, "x", x32.C, " (", x32.theArray.R, "x", x32.theArray.C, ")"
+ 
+# Output:
+# x23: 2x3 (2x3)
+# x32: 3x2 (3x2)  <--- this is incorrect. R and C do not match!
diff --git a/tests/generics/twrong_floatlit_type.nim b/tests/generics/twrong_floatlit_type.nim
new file mode 100644
index 000000000..2db8b4353
--- /dev/null
+++ b/tests/generics/twrong_floatlit_type.nim
@@ -0,0 +1,118 @@
+discard """
+  errormsg: "type mismatch"
+  line: 116
+"""
+
+# bug #2169
+import strutils, math
+
+type
+  Point2D*[S] = object
+    x*, y*: S
+  Matrix2x3*[S] = distinct array[6, S] ## Row major order
+
+  Vector2D*[S] = object
+    x*, y*: S
+
+proc `[]`*[T](m: Matrix2x3[T], i: int): T = array[6, T](m)[i]
+
+template M11*[T](m: Matrix2x3[T]): T = m[0]
+template M12*[T](m: Matrix2x3[T]): T = m[1]
+template M13*[T](m: Matrix2x3[T]): T = m[2]
+template M21*[T](m: Matrix2x3[T]): T = m[3]
+template M22*[T](m: Matrix2x3[T]): T = m[4]
+template M23*[T](m: Matrix2x3[T]): T = m[5]
+
+proc identity*[T](): Matrix2x3[T] =
+    Matrix2x3[T]([T(1.0), 0.0, 0.0,   0.0, 1.0, 0.0])
+
+proc translation*[T](p: Point2D[T]): Matrix2x3[T] =
+    Matrix2x3[T]([T(1.0), T(0.0), p.x, T(0.0), T(1.0), p.y])
+
+proc translation*[T](p: Vector2D[T]): Matrix2x3[T] =
+    Matrix2x3[T]([T(1.0), T(0.0), p.x, T(0.0), T(1.0), p.y])
+
+proc scale*[T](v: Vector2D[T]): Matrix2x3[T] =
+    Matrix2x3[T]([v.x, T(0.0), T(0.0), T(0.0), v.y, T(0.0)])
+
+proc rotation*[T](th: T): Matrix2x3[T] = 
+    let 
+        c = T(cos(th.float))
+        s = T(sin(th.float))
+ 
+    Matrix2x3[T]([c, -s, T(0.0),   s, c, T(0.0)])
+ 
+proc `*`*[T](a, b: Matrix2x3[T]): Matrix2x3[T] = 
+    # Here we pretend that row 3 is [0,0,0,1] without
+    # actually storing it in the matrix.
+    Matrix2x3[T]([a.M11*b.M11 + a.M12*b.M21, 
+                  a.M11*b.M12 + a.M12*b.M22, 
+                  a.M11*b.M13 + a.M12*b.M23 + a.M13, 
+ 
+                  a.M21*b.M11 + a.M22*b.M21,
+                  a.M21*b.M12 + a.M22*b.M22,
+                  a.M21*b.M13 + a.M22*b.M23 + a.M23])
+ 
+proc `*`*[T](a: Matrix2x3[T], p: Point2D[T]): Point2D[T] = 
+    let 
+        x = a.M11*p.x + a.M12*p.y + a.M13
+        y = a.M21*p.x + a.M22*p.y + a.M23
+ 
+    Point2D[T](x: x, y: y)
+ 
+# making these so things like "line" that need a constructor don't stick out.
+# 2x2 determinant:  |a b|
+#                   |c d|  = ad - bc
+ 
+# String rendering
+#
+template ff[S](x: S): string = 
+    formatFloat(float(x), ffDefault, 0)
+ 
+proc `$`*[S](p: Point2D[S]): string = 
+    "P($1, $2)" % [ff(p.x), ff(p.y)]
+ 
+proc `$`*[S](p: Vector2D[S]): string = 
+    "V($1, $2)" % [ff(p.x), ff(p.y)]
+ 
+proc `$`*[S](m: Matrix2x3[S]): string =
+    "M($1 $2 $3/$4 $5 $6)" % [ff(m.M11), ff(m.M12), ff(m.M13), 
+                              ff(m.M21), ff(m.M22), ff(m.M23)]
+
+#
+# Vector operators.
+proc `-`*[S](a: Vector2D[S]): Vector2D[S] =
+  Vector2D[S](x: -a.x, y: -a.y)
+
+proc `+`*[S](a, b: Vector2D[S]): Vector2D[S] =
+  Vector2D[S](x: a.x + b.x, y: a.y + b.y)
+
+proc `-`*[S](a, b: Vector2D[S]): Vector2D[S] =
+  Vector2D[S](x: a.x - b.x, y: a.y - b.y)
+
+proc `*`*[S](v: Vector2D[S], sc: S): Vector2D[S] =
+  Vector2D[S](x: v.x*sc, y: v.y*sc)
+
+proc `*`*[S](sc: S, v: Vector2D[S]): Vector2D[S] =
+  Vector2D[S](x: v.x*sc, y: v.y*sc)
+
+proc `/`*[S](v: Vector2D[S], sc: S): Vector2D[S] =
+  Vector2D[S](x: v.x/sc, y: v.y/sc)
+
+proc `/`*[S](sc: S; v: Vector2D[S]): Vector2D[S] =
+  Vector2D[S](x: sc/v.x, y: sc/v.y)
+
+proc `/`*[S](a, b: Vector2D[S]): Vector2D[S] = 
+  Vector2D[S](x: a.x/b.x, y: a.y/b.y)
+#proc vec[S](x, y: S): Vector2D[S]
+proc vec[S](x, y: S): Vector2D[S] =
+  Vector2D[S](x: x, y: y)
+
+if isMainModule:
+  # Comment out this let, and the program will fail to
+  # compile with a type mismatch, as expected.
+
+  let s3 = scale(vec(4.0, 4.0))
+  let barf = translation(Point2D[float32](x: 1, y: 1)) * rotation(float(0.7))
+
+  echo "Badness ", barf
diff --git a/tests/generics/twrong_generic_object.nim b/tests/generics/twrong_generic_object.nim
new file mode 100644
index 000000000..00d90c55e
--- /dev/null
+++ b/tests/generics/twrong_generic_object.nim
@@ -0,0 +1,21 @@
+discard """
+  errormsg: "cannot instantiate: 'GenericNodeObj'"
+  line: 21
+"""
+# bug #2509
+type
+  GenericNodeObj[T] = ref object
+    obj: T
+
+  Node* = ref object
+    children*: seq[Node]
+    parent*: Node
+
+    nodeObj*: GenericNodeObj # [int]
+
+proc newNode*(nodeObj: GenericNodeObj): Node =
+  result = Node(nodeObj: nodeObj)
+  newSeq(result.children, 10)
+
+var genericObj = GenericNodeObj[int]()
+var myNode = newNode(genericObj)
diff --git a/tests/global/tglobal.nim b/tests/global/tglobal.nim
index 84c4510c1..d44a62afc 100644
--- a/tests/global/tglobal.nim
+++ b/tests/global/tglobal.nim
@@ -1,6 +1,6 @@
 discard """
-  file: "toop1.nim"
   output: "in globalaux2: 10\ntotal globals: 2\nint value: 100\nstring value: second"
+  disabled: "true"
 """
 
 import globalaux, globalaux2
diff --git a/tests/implicit/timplictderef.nim b/tests/implicit/timplictderef.nim
index 99b0b645b..fcb647217 100644
--- a/tests/implicit/timplictderef.nim
+++ b/tests/implicit/timplictderef.nim
@@ -1,9 +1,10 @@
 discard """
-  output: "2"
+  output: '''2
+88'''
 """
 
 type
-  TValue* {.pure, final.} = object of TObject
+  TValue* {.pure, final.} = object of RootObj
     a: int
   PValue = ref TValue
   PPValue = ptr PValue
@@ -16,3 +17,19 @@ var sp: PPValue = addr x
 sp.a = 2
 if sp.a == 2: echo 2  # with sp[].a the error is gone
 
+# Test the new auto-deref a little
+
+{.experimental.}
+
+proc p(x: var int; y: int) = x += y
+
+block:
+  var x: ref int
+  new(x)
+
+  x.p(44)
+
+  var indirect = p
+  x.indirect(44)
+
+  echo x[]
diff --git a/tests/init/tuninit2.nim b/tests/init/tuninit2.nim
new file mode 100644
index 000000000..950895c02
--- /dev/null
+++ b/tests/init/tuninit2.nim
@@ -0,0 +1,54 @@
+# bug #2316
+
+type
+    EventType = enum
+      QuitEvent = 5
+    AppMain* = ref object of RootObj
+        width: int
+        height: int
+        title: string
+        running: bool
+        event_type: EventType
+    App* = ref object of AppMain
+        draw_proc: proc(app: AppMain): void {.closure.}
+        events_proc: proc(app: AppMain): void {.closure.}
+        update_proc: proc(app: AppMain, dt: float): void {.closure.}
+        load_proc: proc(app: AppMain): void {.closure.}
+
+
+proc initApp*(t: string, w, h: int): App =
+    App(width: w, height: h, title: t, event_type: EventType.QuitEvent)
+
+
+method getTitle*(self: AppMain): string = self.title
+method getWidth*(self: AppMain): int = self.width
+method getHeight*(self: AppMain): int = self.height
+
+
+method draw*(self: App, draw: proc(app: AppMain)): void =
+    self.draw_proc = draw
+
+method load*(self: App, load: proc(a: AppMain)): void =
+    self.load_proc = load
+
+method events*(self: App, events: proc(app: AppMain)): void =
+    self.events_proc = events
+
+method update*(self: App, update: proc(app: AppMain, delta: float)): void =
+    self.update_proc = update
+
+method run*(self: App): void = discard
+
+var mygame = initApp("Example", 800, 600)
+
+mygame.load(proc(app: AppMain): void =
+    echo app.getTitle()
+    echo app.getWidth()
+    echo app.getHeight()
+)
+
+mygame.events(proc(app: AppMain): void =
+    discard
+)
+
+mygame.run()
diff --git a/tests/iter/tchainediterators.nim b/tests/iter/tchainediterators.nim
index 18d096761..796672783 100644
--- a/tests/iter/tchainediterators.nim
+++ b/tests/iter/tchainediterators.nim
@@ -6,13 +6,16 @@ discard """
 128
 192
 '''
+  disabled: "true"
 """
 
+# This all relies on non-documented and questionable features.
+
 iterator gaz(it: iterator{.inline.}): type(it) =
   for x in it:
     yield x*2
 
-iterator baz(it: iterator{.inline.}) =
+iterator baz(it: iterator{.inline.}): auto =
   for x in gaz(it):
     yield x*2
 
@@ -28,7 +31,7 @@ iterator foo[T](x: iterator: T{.inline.}): T =
 
 var s = @[1, 2, 3]
 
-# pass an interator several levels deep:
+# pass an iterator several levels deep:
 for x in s.items.foo:
   echo x
 
diff --git a/tests/iter/tconcat.nim b/tests/iter/tconcat.nim
new file mode 100644
index 000000000..477ac5e26
--- /dev/null
+++ b/tests/iter/tconcat.nim
@@ -0,0 +1,24 @@
+discard """
+  output: '''1
+2
+3
+4
+20
+21
+22
+23'''
+"""
+
+proc toIter*[T](s: Slice[T]): iterator: T =
+  iterator it: T {.closure.} =
+    for x in s.a..s.b:
+      yield x
+  return it
+
+iterator concat*[T](its: varargs[T, toIter]): auto =
+  for i in its:
+    for x in i():
+      yield x
+
+for i in concat(1..4, 20..23):
+  echo i
diff --git a/tests/iter/timplicit_auto.nim b/tests/iter/timplicit_auto.nim
new file mode 100644
index 000000000..ccb279fe0
--- /dev/null
+++ b/tests/iter/timplicit_auto.nim
@@ -0,0 +1,18 @@
+# bug #1838
+
+type State = enum Empty, Tree, Fire
+
+const
+  disp: array[State, string] = ["  ", "\e[32m/\\\e[m", "\e[07;31m/\\\e[m"]
+
+proc univ(x, y: int): State = Tree
+
+var w, h = 30
+
+iterator fields(a = (0,0), b = (h-1,w-1)) =
+  for y in max(a[0], 0) .. min(b[0], h-1):
+    for x in max(a[1], 0) .. min(b[1], w-1):
+      yield (y,x)
+
+for y,x in fields():
+  stdout.write disp[univ(x, y)]
diff --git a/tests/iter/tobj_iter.nim b/tests/iter/tobj_iter.nim
new file mode 100644
index 000000000..eb0e37b23
--- /dev/null
+++ b/tests/iter/tobj_iter.nim
@@ -0,0 +1,20 @@
+discard """
+  output: "7"
+"""
+
+# bug #2023
+
+{.deadCodeElim:on.}
+
+type
+    Obj = object
+        iter: iterator (): int8 {.closure.}
+
+iterator test(): int8 {.closure.} =
+    yield 7
+
+proc init():Obj=
+    result.iter = test
+
+var o = init()
+echo(o.iter())
diff --git a/tests/iter/tscheduler.nim b/tests/iter/tscheduler.nim
new file mode 100644
index 000000000..a267f15c4
--- /dev/null
+++ b/tests/iter/tscheduler.nim
@@ -0,0 +1,76 @@
+discard """
+  output: '''a1 5
+a2 10
+a1 3
+a1 1
+a2 8
+a2 6
+a2 4
+a2 2'''
+"""
+
+import os, strutils, times, algorithm
+
+
+type TaskFn = iterator (): float
+
+type Task = object
+    coro: TaskFn
+    next_run: float
+
+
+type Scheduler = object
+    tasks: seq[Task]
+
+
+proc newScheduler(): Scheduler =
+    var s = Scheduler()
+    s.tasks = @[]
+    return s
+
+
+proc start(this: var Scheduler, task: TaskFn) =
+    var t = Task()
+    t.coro = task
+    t.next_run = 0.0
+    this.tasks.add(t)
+
+
+proc run(this: var Scheduler) =
+    while this.tasks.len > 0:
+        var dead: seq[int] = @[]
+        for i in this.tasks.low..this.tasks.high:
+            var task = this.tasks[i]
+            if finished(task.coro):
+                dead.add(i)
+                continue
+            if task.next_run <= epochTime():
+                task.next_run = task.coro() + epochTime()
+            this.tasks[i] = task
+        for i in dead:
+            this.tasks.delete(i)
+        if this.tasks.len > 0:
+            sort(this.tasks, proc (t1: Task, t2: Task): int = cmp(t1.next_run, t2.next_run))
+            sleep(int((this.tasks[0].next_run - epochTime()) * 1000))
+
+
+iterator a1(): float {.closure.} =
+    var k = 5
+    while k > 0:
+        echo "a1 $1" % [$k]
+        dec k, 2
+        yield 0.5
+
+
+iterator a2(): float {.closure.} =
+    var k = 10
+    while k > 0:
+        echo "a2 $1" % [$k]
+        dec k, 2
+        yield 1.5
+
+
+var sched = newScheduler()
+sched.start(a1)
+sched.start(a2)
+sched.run()
diff --git a/tests/iter/tshallowcopy_closures.nim b/tests/iter/tshallowcopy_closures.nim
new file mode 100644
index 000000000..2f024ee7e
--- /dev/null
+++ b/tests/iter/tshallowcopy_closures.nim
@@ -0,0 +1,31 @@
+discard """
+  ccodecheck: "!@('{' \\s* 'NI HEX3Astate;' \\s* '}')"
+"""
+
+# bug #1803
+type TaskFn = iterator (): float
+
+iterator a1(): float {.closure.} =
+    var k = 10
+    while k > 0:
+        echo "a1 ", k
+        dec k
+        yield 1.0
+
+
+iterator a2(): float {.closure.} =
+    var k = 15
+    while k > 0:
+        echo "a2 ", k
+        dec k
+        yield 2.0
+
+var
+  x = a1
+  y = a2
+  z: TaskFn
+
+discard x()
+z = x #shallowCopy(z, x)
+z = y #shallowCopy(z, y)
+discard x()
diff --git a/tests/js/taddr.nim b/tests/js/taddr.nim
new file mode 100644
index 000000000..6a60aa902
--- /dev/null
+++ b/tests/js/taddr.nim
@@ -0,0 +1,36 @@
+type T = object
+  x: int
+  s: string
+
+var obj: T
+var fieldAddr = addr(obj.x)
+var objAddr = addr(obj)
+
+# Integer tests
+var field = fieldAddr[]
+doAssert field == 0
+
+var objDeref = objAddr[]
+doAssert objDeref.x == 0
+
+# Change value
+obj.x = 42
+
+doAssert field == 0
+doAssert objDeref.x == 0
+
+field = fieldAddr[]
+objDeref = objAddr[]
+
+doAssert field == 42
+doAssert objDeref.x == 42
+
+# String tests
+obj.s = "lorem ipsum dolor sit amet"
+var indexAddr = addr(obj.s[2])
+
+doAssert indexAddr[] == '4'
+
+indexAddr[] = 'd'
+
+doAssert indexAddr[] == 'd'
diff --git a/tests/js/tbyvar.nim b/tests/js/tbyvar.nim
index 5ed2de1da..1269e6f66 100644
--- a/tests/js/tbyvar.nim
+++ b/tests/js/tbyvar.nim
@@ -4,12 +4,13 @@ bar 12
 2
 foo 12
 bar 12
-2'''
+2
+'''
 """
 
 # bug #1489
-proc foo(x: int) = echo "foo: ", x
-proc bar(y: var int) = echo "bar: ", y
+proc foo(x: int) = echo "foo ", x
+proc bar(y: var int) = echo "bar ", y
 
 var x = 12
 foo(x)
diff --git a/tests/js/test1.nim b/tests/js/test1.nim
index 09ba30676..7f1d346f0 100644
--- a/tests/js/test1.nim
+++ b/tests/js/test1.nim
@@ -10,9 +10,9 @@ import
 var
   inputElement = "1123"
 
-proc OnButtonClick(inputElement: string) {.exportc.} =
+proc onButtonClick(inputElement: string) {.exportc.} =
   let v = $inputElement
-  if v.allCharsInSet(whiteSpace):
+  if v.allCharsInSet(WhiteSpace):
     echo "only whitespace, hu?"
   else:
     var x = parseInt(v)
diff --git a/tests/js/test2.nim b/tests/js/test2.nim
index 5a734358c..1a42fbfda 100644
--- a/tests/js/test2.nim
+++ b/tests/js/test2.nim
@@ -1,6 +1,7 @@
 discard """
   output: '''foo
-js 3.14'''
+js 3.14
+7'''
 """
 
 # This file tests the JavaScript generator
@@ -20,3 +21,11 @@ else:
   proc foo(val: float): string = "js " & $val
 
 echo foo(3.14)
+
+# #2495
+type C = concept x
+
+proc test(x: C, T: typedesc): T =
+  cast[T](x)
+
+echo 7.test(int8)
diff --git a/tests/js/tfloatround.nim b/tests/js/tfloatround.nim
new file mode 100644
index 000000000..7bc5430e6
--- /dev/null
+++ b/tests/js/tfloatround.nim
@@ -0,0 +1,7 @@
+discard """
+  output: '''
+3
+'''
+"""
+
+echo int(22 / 7)
diff --git a/tests/js/tstringitems.nim b/tests/js/tstringitems.nim
new file mode 100644
index 000000000..f4ea02fec
--- /dev/null
+++ b/tests/js/tstringitems.nim
@@ -0,0 +1,24 @@
+discard """
+  output: '''Hello
+Hello'''
+"""
+
+# bug #2581
+
+const someVars = [ "Hello" ]
+var someVars2 = [ "Hello" ]
+
+proc getSomeVar: string =
+    for i in someVars:
+        if i == "Hello":
+            result = i
+            break
+
+proc getSomeVar2: string =
+    for i in someVars2:
+        if i == "Hello":
+            result = i
+            break
+
+echo getSomeVar()
+echo getSomeVar2()
diff --git a/tests/js/tunittests.nim b/tests/js/tunittests.nim
index af38cd9b9..8a264a5e0 100644
--- a/tests/js/tunittests.nim
+++ b/tests/js/tunittests.nim
@@ -1,3 +1,10 @@
+discard """
+  disabled: "true"
+"""
+
+# Unittest uses lambdalifting at compile-time which we disable for the JS
+# codegen! So this cannot and will not work for quite some time.
+
 import unittest
 
 suite "Bacon":
diff --git a/tests/let/tlet2.nim b/tests/let/tlet2.nim
index 8b1ddf940..66dd5a55b 100644
--- a/tests/let/tlet2.nim
+++ b/tests/let/tlet2.nim
@@ -1,6 +1,6 @@
 discard """
   line: "13"
-  errormsg: "for a 'var' type a variable needs to be passed"
+  errormsg: "type mismatch: got (int literal(8), int literal(5), int, int)"
 """
 
 proc divmod(a, b: int, res, remainder: var int) =
diff --git a/tests/macros/macro_bug.nim b/tests/macros/macro_bug.nim
new file mode 100644
index 000000000..0d0fa76ac
--- /dev/null
+++ b/tests/macros/macro_bug.nim
@@ -0,0 +1,17 @@
+import macros
+
+macro macro_bug*(s: stmt): stmt {.immediate.} =
+  s.expectKind({nnkProcDef, nnkMethodDef})
+
+  var params = s.params
+
+  let genericParams = s[2]
+  result = newNimNode(nnkProcDef).add(
+    s.name, s[1], genericParams, params, pragma(s), newEmptyNode())
+
+  var body = body(s)
+
+  # Fails here.
+  var call = newCall("macro_bug", s.params[1][0])
+  body.insert(0, call)
+  result.add(body)
diff --git a/tests/macros/tbugs.nim b/tests/macros/tbugs.nim
index 3db851dd1..1ecb0d4cc 100644
--- a/tests/macros/tbugs.nim
+++ b/tests/macros/tbugs.nim
@@ -46,13 +46,13 @@ echotest()
 
 # bug #1103
 
-type 
+type
     Td = tuple
         a:string
         b:int
 
 proc get_data(d: Td) : string {.compileTime.} =
-    result = d.a # Works if a literal string is used here. 
+    result = d.a # Works if a literal string is used here.
     # Bugs if line A or B is active. Works with C
     result &= "aa"          # A
     #result.add("aa")       # B
@@ -69,7 +69,7 @@ m(s)
 
 # bug #933
 
-proc nilcheck(): PNimrodNode {.compileTime.} =
+proc nilcheck(): NimNode {.compileTime.} =
   echo(result == nil) # true
   echo(result.isNil) # true
   echo(repr(result)) # nil
diff --git a/tests/closure/tclosuremacro.nim b/tests/macros/tclosuremacro.nim
index 12e463316..d5d9b656c 100644
--- a/tests/closure/tclosuremacro.nim
+++ b/tests/macros/tclosuremacro.nim
@@ -35,9 +35,9 @@ echo noParams(() => 3)
 
 echo doWithOneAndTwo((x, y) => x + y)
 
-noReturn(() -> void => echo("noReturn"))
+noReturn((() -> void) => echo("noReturn"))
 
 proc pass2(f: (int, int) -> int): (int) -> int =
-  (x: int) -> int => f(2, x)
+  ((x: int) -> int) => f(2, x)
 
 echo pass2((x, y) => x + y)(4)
diff --git a/tests/macros/tdumpast.nim b/tests/macros/tdumpast.nim
index 160e4e194..e3388591a 100644
--- a/tests/macros/tdumpast.nim
+++ b/tests/macros/tdumpast.nim
@@ -1,4 +1,4 @@
-# Dump the contents of a PNimrodNode
+# Dump the contents of a NimNode
 
 import macros
 
@@ -7,7 +7,7 @@ template plus(a, b: expr): expr {.dirty} =
 
 macro call(e: expr): expr =
   result = newCall("foo", newStrLitNode("bar"))
-  
+
 macro dumpAST(n: stmt): stmt {.immediate.} =
   # dump AST as a side-effect and return the inner node
   let n = callsite()
@@ -24,10 +24,10 @@ macro dumpAST(n: stmt): stmt {.immediate.} =
   echo e.lispRepr
 
   result = n[1]
-  
+
 dumpAST:
   proc add(x, y: int): int =
     return x + y
-  
+
   proc sub(x, y: int): int = return x - y
 
diff --git a/tests/macros/tdumpast2.nim b/tests/macros/tdumpast2.nim
index 2a7024a01..6b694fa77 100644
--- a/tests/macros/tdumpast2.nim
+++ b/tests/macros/tdumpast2.nim
@@ -1,13 +1,13 @@
-# Dump the contents of a PNimrodNode
+# Dump the contents of a NimNode
 
 import macros
 
-proc dumpit(n: PNimrodNode): string {.compileTime.} = 
+proc dumpit(n: NimNode): string {.compileTime.} =
   if n == nil: return "nil"
   result = $n.kind
   add(result, "(")
   case n.kind
-  of nnkEmpty: discard # same as nil node in this representation 
+  of nnkEmpty: discard # same as nil node in this representation
   of nnkNilLit:                  add(result, "nil")
   of nnkCharLit..nnkInt64Lit:    add(result, $n.intVal)
   of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
@@ -20,17 +20,17 @@ proc dumpit(n: PNimrodNode): string {.compileTime.} =
       add(result, ", ")
       add(result, dumpit(n[j]))
   add(result, ")")
-  
-macro dumpAST(n: stmt): stmt {.immediate.} = 
+
+macro dumpAST(n: stmt): stmt {.immediate.} =
   # dump AST as a side-effect and return the inner node
   let n = callsite()
   echo dumpit(n)
   result = n[1]
-  
+
 dumpAST:
   proc add(x, y: int): int =
     return x + y
-  
+
   proc sub(x, y: int): int = return x - y
 
 
diff --git a/tests/macros/tgensym.nim b/tests/macros/tgensym.nim
index 3f4140ff4..b3aef0a2c 100644
--- a/tests/macros/tgensym.nim
+++ b/tests/macros/tgensym.nim
@@ -2,7 +2,7 @@ import rawsockets, asyncdispatch, macros
 var p = newDispatcher()
 var sock = newAsyncRawSocket()
 
-proc convertReturns(node, retFutureSym: PNimrodNode): PNimrodNode {.compileTime.} =
+proc convertReturns(node, retFutureSym: NimNode): NimNode {.compileTime.} =
   case node.kind
   of nnkReturnStmt:
     result = newCall(newIdentNode("complete"), retFutureSym, node[0])
@@ -19,19 +19,19 @@ macro async2(prc: stmt): stmt {.immediate.} =
   # -> var retFuture = newFuture[T]()
   var retFutureSym = newIdentNode("retFuture") #genSym(nskVar, "retFuture")
   outerProcBody.add(
-    newVarStmt(retFutureSym, 
+    newVarStmt(retFutureSym,
       newCall(
         newNimNode(nnkBracketExpr).add(
           newIdentNode("newFuture"),
           prc[3][0][1])))) # Get type from return type of this proc.
 
-  # -> iterator nameIter(): PFutureBase {.closure.} = <proc_body>
+  # -> iterator nameIter(): FutureBase {.closure.} = <proc_body>
   # Changing this line to: newIdentNode($prc[0].ident & "Iter") # will make it work.
   var iteratorNameSym = genSym(nskIterator, $prc[0].ident & "Iter")
   #var iteratorNameSym = newIdentNode($prc[0].ident & "Iter")
   var procBody = prc[6].convertReturns(retFutureSym)
 
-  var closureIterator = newProc(iteratorNameSym, [newIdentNode("PFutureBase")],
+  var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
                                 procBody, nnkIteratorDef)
   closureIterator[4] = newNimNode(nnkPragma).add(newIdentNode("closure"))
   outerProcBody.add(closureIterator)
@@ -55,8 +55,8 @@ macro async2(prc: stmt): stmt {.immediate.} =
 
   result[6] = outerProcBody
 
-proc readStuff(): PFuture[string] {.async2.} =
-  var fut = connect(sock, "irc.freenode.org", TPort(6667))
+proc readStuff(): Future[string] {.async2.} =
+  var fut = connect(sock, "irc.freenode.org", Port(6667))
   yield fut
   var fut2 = recv(sock, 50)
   yield fut2
diff --git a/tests/macros/tgentemplates.nim b/tests/macros/tgentemplates.nim
index a7727c597..764b94bc7 100644
--- a/tests/macros/tgentemplates.nim
+++ b/tests/macros/tgentemplates.nim
@@ -2,7 +2,7 @@
 
 import parseutils, macros
 
-proc parse_until_symbol(node: PNimrodNode, value: string, index: var int): bool {.compiletime.} =
+proc parse_until_symbol(node: NimNode, value: string, index: var int): bool {.compiletime.} =
     var splitValue: string
     var read = value.parseUntil(splitValue, '$', index)
 
@@ -15,7 +15,7 @@ proc parse_until_symbol(node: PNimrodNode, value: string, index: var int): bool
     if splitValue.len > 0:
         node.insert node.len, newCall("add", ident("result"), newStrLitNode(splitValue))
 
-proc parse_template(node: PNimrodNode, value: string) {.compiletime.} =
+proc parse_template(node: NimNode, value: string) {.compiletime.} =
     var index = 0
     while index < value.len and
         parse_until_symbol(node, value, index): discard
diff --git a/tests/macros/tlexerex.nim b/tests/macros/tlexerex.nim
new file mode 100644
index 000000000..d348a4bcc
--- /dev/null
+++ b/tests/macros/tlexerex.nim
@@ -0,0 +1,16 @@
+
+import macros
+
+macro match*(s: cstring|string; pos: int; sections: untyped): untyped =
+  for sec in sections.children:
+    expectKind sec, nnkOfBranch
+    expectLen sec, 2
+  result = newStmtList()
+
+when isMainModule:
+  var input = "the input"
+  var pos = 0
+  match input, pos:
+  of r"[a-zA-Z_]\w+": echo "an identifier"
+  of r"\d+": echo "an integer"
+  of r".": echo "something else"
diff --git a/tests/macros/tmacro1.nim b/tests/macros/tmacro1.nim
index 3a67c2611..2dd5c31df 100644
--- a/tests/macros/tmacro1.nim
+++ b/tests/macros/tmacro1.nim
@@ -3,17 +3,17 @@ import  macros
 from uri import `/`
 
 macro test*(a: stmt): stmt {.immediate.} =
-  var nodes: tuple[a, b: int]  
+  var nodes: tuple[a, b: int]
   nodes.a = 4
   nodes[1] = 45
-  
+
   type
     TTypeEx = object
       x, y: int
       case b: bool
       of false: nil
       of true: z: float
-      
+
   var t: TTypeEx
   t.b = true
   t.z = 4.5
diff --git a/tests/macros/tmacro3.nim b/tests/macros/tmacro3.nim
index 162212326..d7421ff7f 100644
--- a/tests/macros/tmacro3.nim
+++ b/tests/macros/tmacro3.nim
@@ -4,7 +4,7 @@ discard """
 
 import  macros
 
-type 
+type
     TA = tuple[a: int]
     PA = ref TA
 
@@ -19,7 +19,7 @@ test:
 macro test2*(a: stmt): stmt {.immediate.} =
   proc testproc(recurse: int) =
     echo "Thats weird"
-    var o : PNimrodNode = nil
+    var o : NimNode = nil
     echo "  no its not!"
     o = newNimNode(nnkNone)
     if recurse > 0:
diff --git a/tests/macros/tmacro4.nim b/tests/macros/tmacro4.nim
index 10a23b159..a56369369 100644
--- a/tests/macros/tmacro4.nim
+++ b/tests/macros/tmacro4.nim
@@ -7,7 +7,7 @@ import
 
 macro test_macro*(n: stmt): stmt {.immediate.} =
   result = newNimNode(nnkStmtList)
-  var ass : PNimrodNode = newNimNode(nnkAsgn)
+  var ass : NimNode = newNimNode(nnkAsgn)
   add(ass, newIdentNode("str"))
   add(ass, newStrLitNode("after"))
   add(result, ass)
diff --git a/tests/macros/tmacro5.nim b/tests/macros/tmacro5.nim
index 9882ad90d..d7a4fe8c8 100644
--- a/tests/macros/tmacro5.nim
+++ b/tests/macros/tmacro5.nim
@@ -1,7 +1,7 @@
 import macros,json
 
-var decls{.compileTime.}: seq[PNimrodNode] = @[]
-var impls{.compileTime.}: seq[PNimrodNode] = @[]
+var decls{.compileTime.}: seq[NimNode] = @[]
+var impls{.compileTime.}: seq[NimNode] = @[]
 
 macro importImpl_forward(name, returns): stmt {.immediate.} =
   result = newNimNode(nnkEmpty)
@@ -38,7 +38,7 @@ macro importImpl_forward(name, returns): stmt {.immediate.} =
   decls.add res
   echo(repr(res))
 
-macro importImpl(name, returns: expr, body: stmt): stmt {.immediate.} = 
+macro importImpl(name, returns: expr, body: stmt): stmt {.immediate.} =
   #var res = getAST(importImpl_forward(name, returns))
   discard getAST(importImpl_forward(name, returns))
   var res = copyNimTree(decls[decls.high])
@@ -56,4 +56,4 @@ importImpl(Item, int):
 importImpl(Foo, int16):
   echo 77
 
-okayy
\ No newline at end of file
+okayy
diff --git a/tests/macros/tmacro_in_template.nim b/tests/macros/tmacro_in_template.nim
new file mode 100644
index 000000000..8f7753cea
--- /dev/null
+++ b/tests/macros/tmacro_in_template.nim
@@ -0,0 +1,10 @@
+
+# bug #1944
+import macros
+
+template t(e: expr): stmt =
+  macro m(eNode: expr): stmt =
+    echo eNode.treeRepr
+  m e
+
+t 5
diff --git a/tests/macros/tmacros1.nim b/tests/macros/tmacros1.nim
index 3c814ad6d..1a1073a44 100644
--- a/tests/macros/tmacros1.nim
+++ b/tests/macros/tmacros1.nim
@@ -15,10 +15,10 @@ macro outterMacro*(n: stmt): stmt {.immediate.} =
   expectKind(n, TNimrodNodeKind.nnkCall)
   if n.len != 3 or n[1].kind != TNimrodNodeKind.nnkIdent:
     error("Macro " & callNode.repr &
-      " requires the ident passed as parameter (eg: " & callNode.repr & 
+      " requires the ident passed as parameter (eg: " & callNode.repr &
       "(the_name_you_want)): statements.")
   result = newNimNode(TNimrodNodeKind.nnkStmtList)
-  var ass : PNimrodNode = newNimNode(nnkAsgn)
+  var ass : NimNode = newNimNode(nnkAsgn)
   ass.add(newIdentNode(n[1].ident))
   ass.add(newStrLitNode(innerProc(4)))
   result.add(ass)
diff --git a/tests/macros/tmacrotypes.nim b/tests/macros/tmacrotypes.nim
index f19aa2ddb..991668930 100644
--- a/tests/macros/tmacrotypes.nim
+++ b/tests/macros/tmacrotypes.nim
@@ -1,16 +1,16 @@
 discard """
-  disabled: true
+  nimout: '''void
+int'''
 """
 
-import macros, typetraits
+import macros
 
-macro checkType(ex, expected: expr): stmt {.immediate.} =
-  var t = ex.typ
-  assert t.name == expected.strVal
+macro checkType(ex: stmt; expected: expr): stmt =
+  var t = ex.getType()
+  echo t
 
 proc voidProc = echo "hello"
-proc intProc(a, b): int = 10
+proc intProc(a: int, b: float): int = 10
 
 checkType(voidProc(), "void")
 checkType(intProc(10, 20.0), "int")
-checkType(noproc(10, 20.0), "Error Type")
diff --git a/tests/macros/tnimrodnode_for_runtime.nim b/tests/macros/tnimnode_for_runtime.nim
index e73c8430f..0520cd0dd 100644
--- a/tests/macros/tnimrodnode_for_runtime.nim
+++ b/tests/macros/tnimnode_for_runtime.nim
@@ -1,10 +1,9 @@
 discard """
   output: "bla"
-  disabled: true
 """
 
 import macros
-proc makeMacro: PNimrodNode =
+proc makeMacro: NimNode =
   result = nil
 
 var p = makeMacro()
diff --git a/tests/macros/tsame_name_497.nim b/tests/macros/tsame_name_497.nim
new file mode 100644
index 000000000..ed5d5c6d8
--- /dev/null
+++ b/tests/macros/tsame_name_497.nim
@@ -0,0 +1,9 @@
+discard """
+  disabled: true
+"""
+
+import macro_bug
+
+type TObj = object
+
+proc f(o: TObj) {.macro_bug.} = discard
diff --git a/tests/macros/tstringinterp.nim b/tests/macros/tstringinterp.nim
index a500ed56e..bc79cdaba 100644
--- a/tests/macros/tstringinterp.nim
+++ b/tests/macros/tstringinterp.nim
@@ -19,7 +19,7 @@ template processInterpolations(e: expr) =
 
 macro formatStyleInterpolation(e: expr): expr =
   let e = callsite()
-  var 
+  var
     formatString = ""
     arrayNode = newNimNode(nnkBracket)
     idx = 1
@@ -27,14 +27,14 @@ macro formatStyleInterpolation(e: expr): expr =
   proc addString(s: string) =
     formatString.add(s)
 
-  proc addExpr(e: PNimrodNode) =
+  proc addExpr(e: NimNode) =
     arrayNode.add(e)
     formatString.add("$" & $(idx))
     inc idx
 
   proc addDollar() =
     formatString.add("$$")
-    
+
   processInterpolations(e)
 
   result = parseExpr("\"x\" % [y]")
@@ -43,11 +43,11 @@ macro formatStyleInterpolation(e: expr): expr =
 
 macro concatStyleInterpolation(e: expr): expr =
   let e = callsite()
-  var args: seq[PNimrodNode]
+  var args: seq[NimNode]
   newSeq(args, 0)
 
   proc addString(s: string)    = args.add(newStrLitNode(s))
-  proc addExpr(e: PNimrodNode) = args.add(e)
+  proc addExpr(e: NimNode) = args.add(e)
   proc addDollar()             = args.add(newStrLitNode"$")
 
   processInterpolations(e)
@@ -59,7 +59,7 @@ macro concatStyleInterpolation(e: expr): expr =
 proc sum(a, b, c: int): int =
   return (a + b + c)
 
-var 
+var
   alice = "Alice"
   bob = "Bob"
   a = 10
diff --git a/tests/macros/ttryparseexpr.nim b/tests/macros/ttryparseexpr.nim
index af932eb7d..c7bbc8e5b 100644
--- a/tests/macros/ttryparseexpr.nim
+++ b/tests/macros/ttryparseexpr.nim
@@ -15,5 +15,6 @@ const
   valid = 45
   a = test("foo&&")
   b = test("valid")
+  c = test("\"") # bug #2504
 
 echo a, " ", b
diff --git a/tests/macros/tvarnimnode.nim b/tests/macros/tvarnimnode.nim
index 73fcc16ea..ab0f66caa 100644
--- a/tests/macros/tvarnimnode.nim
+++ b/tests/macros/tvarnimnode.nim
@@ -6,7 +6,7 @@ discard """
 
 import macros
 
-proc test(f: var PNimrodNode) {.compileTime.} =
+proc test(f: var NimNode) {.compileTime.} =
   f = newNimNode(nnkStmtList)
   f.add newCall(newIdentNode("echo"), newLit(10))
 
diff --git a/tests/macros/tvtable.nim b/tests/macros/tvtable.nim
index 51894618c..3e3b9c0e6 100644
--- a/tests/macros/tvtable.nim
+++ b/tests/macros/tvtable.nim
@@ -11,8 +11,8 @@ OBJ 2 bar
 
 type
   # these are the signatures of the virtual procs for each type
-  fooProc[T] = proc (o: var T): int
-  barProc[T] = proc (o: var T)
+  fooProc[T] = proc (o: var T): int {.nimcall.}
+  barProc[T] = proc (o: var T) {.nimcall.}
 
   # an untyped table to store the proc pointers
   # it's also possible to use a strongly typed tuple here
diff --git a/tests/macros/typesapi.nim b/tests/macros/typesapi.nim
new file mode 100644
index 000000000..670b39c9e
--- /dev/null
+++ b/tests/macros/typesapi.nim
@@ -0,0 +1,17 @@
+discard """
+  nimout: '''proc (x: int): string => typeDesc[proc[string, int]]
+proc (x: int): void => typeDesc[proc[void, int]]
+proc (x: int) => typeDesc[proc[void, int]]'''
+"""
+
+#2211
+
+import macros
+
+macro showType(t:stmt): stmt =
+  let ty = t.getType
+  echo t.repr, " => ", ty.repr
+
+showType(proc(x:int): string)
+showType(proc(x:int): void)
+showType(proc(x:int))
diff --git a/tests/macros/typesapi2.nim b/tests/macros/typesapi2.nim
new file mode 100644
index 000000000..2e59d2154
--- /dev/null
+++ b/tests/macros/typesapi2.nim
@@ -0,0 +1,49 @@
+# tests to see if a symbol returned from macros.getType() can
+# be used as a type
+import macros
+
+macro testTypesym (t:stmt): expr =
+    var ty = t.getType
+    if ty.typekind == ntyTypedesc:
+        # skip typedesc get to the real type
+        ty = ty[1].getType
+
+    if ty.kind == nnkSym: return ty
+    assert ty.kind == nnkBracketExpr
+    assert ty[0].kind == nnkSym
+    result = ty[0]
+    return
+
+type TestFN = proc(a,b:int):int
+var iii: testTypesym(TestFN)
+static: assert iii is TestFN
+
+proc foo11 : testTypesym(void) =
+    echo "HI!"
+static: assert foo11 is (proc():void {.nimcall.})
+
+var sss: testTypesym(seq[int])
+static: assert sss is seq[int]
+# very nice :>
+
+static: assert array[2,int] is testTypesym(array[2,int])
+static: assert(ref int is testTypesym(ref int))
+static: assert(void is testTypesym(void))
+
+
+macro tts2 (t:stmt, idx:int): expr =
+    var ty = t.getType
+    if ty.typekind == ntyTypedesc:
+        # skip typedesc get to the real type
+        ty = ty[1].getType
+
+    if ty.kind == nnkSym: return ty
+    assert ty.kind == nnkBracketExpr
+    return ty[idx.intval.int]
+type TestFN2 = proc(a:int,b:float):string
+static:
+    assert(tts2(TestFN2, 0) is TestFN2)
+    assert(tts2(TestFN2, 1) is string)
+    assert(tts2(TestFN2, 2) is int)
+    assert(tts2(TestFN2, 3) is float)
+
diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim
index fec00dbf8..060610ae0 100644
--- a/tests/manyloc/argument_parser/argument_parser.nim
+++ b/tests/manyloc/argument_parser/argument_parser.nim
@@ -1,7 +1,7 @@
 ## Command line parsing module for Nimrod.
 ##
-## `Nim <http://nim-code.org>`_ provides the `parseopt module
-## <http://nim-code.org/parseopt.html>`_ to parse options from the
+## `Nim <http://nim-lang.org>`_ provides the `parseopt module
+## <http://nim-lang.org/parseopt.html>`_ to parse options from the
 ## commandline. This module tries to provide functionality to prevent you from
 ## writing commandline parsing and let you concentrate on providing the best
 ## possible experience for your users.
@@ -302,7 +302,7 @@ template build_specification_lookup():
   ## Returns the table used to keep pointers to all of the specifications.
   var result {.gensym.}: OrderedTable[string, ptr Tparameter_specification]
   result = initOrderedTable[string, ptr Tparameter_specification](
-    nextPowerOfTwo(expected.len))
+    tables.rightSize(expected.len))
   for i in 0..expected.len-1:
     for param_to_detect in expected[i].names:
       if result.hasKey(param_to_detect):
@@ -471,7 +471,7 @@ proc build_help*(expected: seq[Tparameter_specification] = @[],
   let width = prefixes.map(proc (x: string): int = 3 + len(x)).max
 
   for line in zip(prefixes, helps):
-    result.add(line.a & repeatChar(width - line.a.len) & line.b)
+    result.add(line.a & spaces(width - line.a.len) & line.b)
 
 
 proc echo_help*(expected: seq[Tparameter_specification] = @[],
diff --git a/tests/manyloc/argument_parser/ex_wget.nim b/tests/manyloc/argument_parser/ex_wget.nim
index d36947b34..625a6f595 100644
--- a/tests/manyloc/argument_parser/ex_wget.nim
+++ b/tests/manyloc/argument_parser/ex_wget.nim
@@ -8,8 +8,8 @@ const
   PARAM_BACKGROUND = @["-b", "--background"]
   PARAM_OUTPUT = @["-o", "--output"]
   PARAM_NO_CLOBBER = @["-nc", "--no-clobber"]
-  PARAM_PROGRESS = "--progress"
-  PARAM_NO_PROXY = "--no-proxy"
+  PARAM_PROGRESS = @["--progress"]
+  PARAM_NO_PROXY = @["--no-proxy"]
 
 
 template P(tnames: varargs[string], thelp: string, ttype = PK_EMPTY,
@@ -77,8 +77,8 @@ proc process_commandline(): Tcommandline_results =
       quit()
     echo "Will download to $1" % [result.options[PARAM_OUTPUT[0]].str_val]
 
-  if result.options.hasKey(PARAM_PROGRESS):
-    echo "Will use progress type $1" % [result.options[PARAM_PROGRESS].str_val]
+  if result.options.hasKey(PARAM_PROGRESS[0]):
+    echo "Will use progress type $1" % [result.options[PARAM_PROGRESS[0]].str_val]
 
 
 when isMainModule:
diff --git a/tests/manyloc/keineschweine/README.md b/tests/manyloc/keineschweine/README.md
index 2a6b78a8e..1323f4ae3 100644
--- a/tests/manyloc/keineschweine/README.md
+++ b/tests/manyloc/keineschweine/README.md
@@ -4,7 +4,7 @@ Just a dumb little game
 
 ### Dependencies
 
-* Nimrod 0.8.15, Until this version is released I'm working off Nimrod HEAD: https://github.com/Araq/Nimrod
+* nim 0.8.15, Until this version is released I'm working off nim HEAD: https://github.com/Araq/nim
 * SFML 2.0 (git), https://github.com/LaurentGomila/SFML
 * CSFML 2.0 (git), https://github.com/LaurentGomila/CSFML
 * Chipmunk 6.1.1 http://chipmunk-physics.net/downloads.php
@@ -13,7 +13,7 @@ Just a dumb little game
 
 * `git clone --recursive git://github.com/fowlmouth/keineSchweine.git somedir`
 * `cd somedir`
-*  `nimrod c -r nakefile test` or `nimrod c -r keineschweine && ./keineschweine`
+*  `nim c -r nakefile test` or `nim c -r keineschweine && ./keineschweine`
 
 ### Download the game data
 
@@ -22,5 +22,5 @@ http://dl.dropbox.com/u/37533467/data-08-01-2012.7z
 
 Unpack it to the root directory. You can use the nakefile to do this easily: 
 
-* `nimrod c -r nakefile`
+* `nim c -r nakefile`
 * `./nakefile download`
diff --git a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim
index d079a2e72..493a2106c 100644
--- a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim
+++ b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim
@@ -74,7 +74,7 @@ type
     contacts*: PContact
     stamp*: TTimestamp
     handler*: PCollisionHandler
-    swappedColl*: bool32
+    swappedColl*: Bool32
     state*: TArbiterState
   PCollisionHandler* = ptr TCollisionHandler
   TCollisionHandler*{.pf.} = object 
@@ -108,7 +108,7 @@ type
   #/ Collision begin event function callback type.
   #/ Returning false from a begin callback causes the collision to be ignored until
   #/ the the separate callback is called when the objects stop colliding.
-  TCollisionBeginFunc* = proc (arb: PArbiter; space: PSpace; data: pointer): Bool{.
+  TCollisionBeginFunc* = proc (arb: PArbiter; space: PSpace; data: pointer): bool{.
       cdecl.}
   #/ Collision pre-solve event function callback type.
   #/ Returning false from a pre-step callback causes the collision to be ignored until the next step.
@@ -142,14 +142,14 @@ type
   PSpatialIndex = ptr TSpatialIndex
   TSpatialIndex{.pf.} = object 
     klass: PSpatialIndexClass
-    bbfunc: TSpatialIndexBBFunc
+    bbfun: TSpatialIndexBBFunc
     staticIndex: PSpatialIndex
     dynamicIndex: PSpatialIndex
 
   TSpatialIndexDestroyImpl* = proc (index: PSpatialIndex){.cdecl.}
   TSpatialIndexCountImpl* = proc (index: PSpatialIndex): cint{.cdecl.}
   TSpatialIndexEachImpl* = proc (index: PSpatialIndex; 
-                                 func: TSpatialIndexIteratorFunc; data: pointer){.
+                                 fun: TSpatialIndexIteratorFunc; data: pointer){.
       cdecl.}
   TSpatialIndexContainsImpl* = proc (index: PSpatialIndex; obj: pointer; 
                                      hashid: THashValue): Bool32 {.cdecl.}
@@ -161,15 +161,15 @@ type
   TSpatialIndexReindexObjectImpl* = proc (index: PSpatialIndex; 
       obj: pointer; hashid: THashValue){.cdecl.}
   TSpatialIndexReindexQueryImpl* = proc (index: PSpatialIndex; 
-      func: TSpatialIndexQueryFunc; data: pointer){.cdecl.}
+      fun: TSpatialIndexQueryFunc; data: pointer){.cdecl.}
   TSpatialIndexPointQueryImpl* = proc (index: PSpatialIndex; point: TVector; 
-                                       func: TSpatialIndexQueryFunc; 
+                                       fun: TSpatialIndexQueryFunc; 
                                        data: pointer){.cdecl.}
   TSpatialIndexSegmentQueryImpl* = proc (index: PSpatialIndex; obj: pointer; 
-      a: TVector; b: TVector; t_exit: CpFloat; func: TSpatialIndexSegmentQueryFunc; 
+      a: TVector; b: TVector; t_exit: CpFloat; fun: TSpatialIndexSegmentQueryFunc; 
       data: pointer){.cdecl.}
   TSpatialIndexQueryImpl* = proc (index: PSpatialIndex; obj: pointer; 
-                                  bb: TBB; func: TSpatialIndexQueryFunc; 
+                                  bb: TBB; fun: TSpatialIndexQueryFunc; 
                                   data: pointer){.cdecl.}
   PSpatialIndexClass* = ptr TSpatialIndexClass
   TSpatialIndexClass*{.pf.} = object 
@@ -279,14 +279,14 @@ type
   PSegmentQueryInfo* = ptr TSegmentQueryInfo
   #/ Segment query info struct.
   TSegmentQueryInfo*{.pf.} = object 
-    shape*: PShape         #/ The shape that was hit, NULL if no collision occured.
+    shape*: PShape         #/ The shape that was hit, NULL if no collision occurred.
     t*: CpFloat            #/ The normalized distance along the query segment in the range [0, 1].
     n*: TVector            #/ The normal of the surface hit.
   TShapeType*{.size: sizeof(cint).} = enum 
     CP_CIRCLE_SHAPE, CP_SEGMENT_SHAPE, CP_POLY_SHAPE, CP_NUM_SHAPES
   TShapeCacheDataImpl* = proc (shape: PShape; p: TVector; rot: TVector): TBB{.cdecl.}
   TShapeDestroyImpl* = proc (shape: PShape){.cdecl.}
-  TShapePointQueryImpl* = proc (shape: PShape; p: TVector): bool32 {.cdecl.}
+  TShapePointQueryImpl* = proc (shape: PShape; p: TVector): Bool32 {.cdecl.}
   TShapeSegmentQueryImpl* = proc (shape: PShape; a: TVector; b: TVector; 
                                   info: PSegmentQueryInfo){.cdecl.}
   PShapeClass* = ptr TShapeClass
@@ -427,7 +427,7 @@ defGetter(PSpace, CpFloat, currDt, CurrentTimeStep)
 
 
 #/ returns true from inside a callback and objects cannot be added/removed.
-proc isLocked*(space: PSpace): Bool{.inline.} = 
+proc isLocked*(space: PSpace): bool{.inline.} = 
   result = space.locked.bool
 
 #/ Set a default collision handler for this space.
@@ -478,24 +478,24 @@ proc removeBody*(space: PSpace; body: PBody){.
 proc RemoveConstraint*(space: PSpace; constraint: PConstraint){.
   cdecl, importc: "cpSpaceRemoveConstraint", dynlib: Lib.}
 #/ Test if a collision shape has been added to the space.
-proc containsShape*(space: PSpace; shape: PShape): Bool{.
+proc containsShape*(space: PSpace; shape: PShape): bool{.
   cdecl, importc: "cpSpaceContainsShape", dynlib: Lib.}
 #/ Test if a rigid body has been added to the space.
-proc containsBody*(space: PSpace; body: PBody): Bool{.
+proc containsBody*(space: PSpace; body: PBody): bool{.
   cdecl, importc: "cpSpaceContainsBody", dynlib: Lib.}
 #/ Test if a constraint has been added to the space.
 
-proc containsConstraint*(space: PSpace; constraint: PConstraint): Bool{.
+proc containsConstraint*(space: PSpace; constraint: PConstraint): bool{.
   cdecl, importc: "cpSpaceContainsConstraint", dynlib: Lib.}
 #/ Schedule a post-step callback to be called when cpSpaceStep() finishes.
 #/ @c obj is used a key, you can only register one callback per unique value for @c obj
-proc addPostStepCallback*(space: PSpace; func: TPostStepFunc; 
+proc addPostStepCallback*(space: PSpace; fun: TPostStepFunc; 
                                obj: pointer; data: pointer){.
   cdecl, importc: "cpSpaceAddPostStepCallback", dynlib: Lib.}
                                         
 #/ Query the space at a point and call @c func for each shape found.
 proc pointQuery*(space: PSpace; point: TVector; layers: TLayers; 
-                      group: TGroup; func: TSpacePointQueryFunc; data: pointer){.
+                      group: TGroup; fun: TSpacePointQueryFunc; data: pointer){.
   cdecl, importc: "cpSpacePointQuery", dynlib: Lib.}
 
 #/ Query the space at a point and return the first shape found. Returns NULL if no shapes were found.
@@ -506,7 +506,7 @@ proc pointQueryFirst*(space: PSpace; point: TVector; layers: TLayers;
 #/ Perform a directed line segment query (like a raycast) against the space calling @c func for each shape intersected.
 proc segmentQuery*(space: PSpace; start: TVector; to: TVector; 
                     layers: TLayers; group: TGroup; 
-                    func: TSpaceSegmentQueryFunc; data: pointer){.
+                    fun: TSpaceSegmentQueryFunc; data: pointer){.
   cdecl, importc: "cpSpaceSegmentQuery", dynlib: Lib.}
 #/ Perform a directed line segment query (like a raycast) against the space and return the first shape hit. Returns NULL if no shapes were hit.
 proc segmentQueryFirst*(space: PSpace; start: TVector; to: TVector; 
@@ -517,26 +517,26 @@ proc segmentQueryFirst*(space: PSpace; start: TVector; to: TVector;
 #/ Perform a fast rectangle query on the space calling @c func for each shape found.
 #/ Only the shape's bounding boxes are checked for overlap, not their full shape.
 proc BBQuery*(space: PSpace; bb: TBB; layers: TLayers; group: TGroup; 
-                   func: TSpaceBBQueryFunc; data: pointer){.
+                   fun: TSpaceBBQueryFunc; data: pointer){.
   cdecl, importc: "cpSpaceBBQuery", dynlib: Lib.}
 
 #/ Query a space for any shapes overlapping the given shape and call @c func for each shape found.
-proc shapeQuery*(space: PSpace; shape: PShape; func: TSpaceShapeQueryFunc; data: pointer): Bool {.
+proc shapeQuery*(space: PSpace; shape: PShape; fun: TSpaceShapeQueryFunc; data: pointer): bool {.
   cdecl, importc: "cpSpaceShapeQuery", dynlib: Lib.}
 #/ Call cpBodyActivate() for any shape that is overlaps the given shape.
 proc activateShapesTouchingShape*(space: PSpace; shape: PShape){.
     cdecl, importc: "cpSpaceActivateShapesTouchingShape", dynlib: Lib.}
 
 #/ Call @c func for each body in the space.
-proc eachBody*(space: PSpace; func: TSpaceBodyIteratorFunc; data: pointer){.
+proc eachBody*(space: PSpace; fun: TSpaceBodyIteratorFunc; data: pointer){.
   cdecl, importc: "cpSpaceEachBody", dynlib: Lib.}
 
 #/ Call @c func for each shape in the space.
-proc eachShape*(space: PSpace; func: TSpaceShapeIteratorFunc; 
+proc eachShape*(space: PSpace; fun: TSpaceShapeIteratorFunc; 
                      data: pointer){.
   cdecl, importc: "cpSpaceEachShape", dynlib: Lib.}
 #/ Call @c func for each shape in the space.
-proc eachConstraint*(space: PSpace; func: TSpaceConstraintIteratorFunc; 
+proc eachConstraint*(space: PSpace; fun: TSpaceConstraintIteratorFunc; 
                           data: pointer){.
   cdecl, importc: "cpSpaceEachConstraint", dynlib: Lib.}
 #/ Update the collision detection info for the static shapes in the space.
@@ -674,7 +674,7 @@ proc dist*(v1, v2: TVector): CpFloat {.inline.} =
 proc distsq*(v1, v2: TVector): CpFloat {.inline.} = 
   result = (v1 - v2).lenSq  #vlengthsq(vsub(v1, v2))
 #/ Returns true if the distance between v1 and v2 is less than dist.
-proc near*(v1, v2: TVector; dist: CpFloat): Bool{.inline.} = 
+proc near*(v1, v2: TVector; dist: CpFloat): bool{.inline.} = 
   result = v1.distSq(v2) < dist * dist
 
 
@@ -706,13 +706,13 @@ proc Sleep*(body: PBody){.importc: "cpBodySleep", dynlib: Lib.}
 proc SleepWithGroup*(body: PBody; group: PBody){.
     importc: "cpBodySleepWithGroup", dynlib: Lib.}
 #/ Returns true if the body is sleeping.
-proc isSleeping*(body: PBody): Bool {.inline.} = 
+proc isSleeping*(body: PBody): bool {.inline.} = 
   return body.node.root != nil
 #/ Returns true if the body is static.
 proc isStatic*(body: PBody): bool {.inline.} = 
   return body.node.idleTime == CpInfinity
 #/ Returns true if the body has not been added to a space.
-proc isRogue*(body: PBody): Bool {.inline.} = 
+proc isRogue*(body: PBody): bool {.inline.} = 
   return body.space == nil
 
 # #define CP_DefineBodyStructGetter(type, member, name) \
@@ -808,15 +808,15 @@ proc kineticEnergy*(body: PBOdy): CpFloat =
   result = (body.v.dot(body.v) * body.m) + (body.w * body.w * body.i)
 
 #/ Call @c func once for each shape attached to @c body and added to the space.
-proc eachShape*(body: PBody; func: TBodyShapeIteratorFunc; 
+proc eachShape*(body: PBody; fun: TBodyShapeIteratorFunc; 
                       data: pointer){.
   cdecl, importc: "cpBodyEachShape", dynlib: Lib.}
 #/ Call @c func once for each constraint attached to @c body and added to the space.
-proc eachConstraint*(body: PBody; func: TBodyConstraintIteratorFunc; 
+proc eachConstraint*(body: PBody; fun: TBodyConstraintIteratorFunc; 
                            data: pointer) {.
   cdecl, importc: "cpBodyEachConstraint", dynlib: Lib.}
 #/ Call @c func once for each arbiter that is currently active on the body.
-proc eachArbiter*(body: PBody; func: TBodyArbiterIteratorFunc; 
+proc eachArbiter*(body: PBody; fun: TBodyArbiterIteratorFunc; 
                         data: pointer){.
   cdecl, importc: "cpBodyEachArbiter", dynlib: Lib.}
 #/ Allocate a spatial hash.
@@ -824,10 +824,10 @@ proc SpaceHashAlloc*(): PSpaceHash{.
   cdecl, importc: "cpSpaceHashAlloc", dynlib: Lib.}
 #/ Initialize a spatial hash. 
 proc SpaceHashInit*(hash: PSpaceHash; celldim: CpFloat; numcells: cint; 
-                    bbfunc: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{.
+                    bbfun: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{.
   cdecl, importc: "cpSpaceHashInit", dynlib: Lib.}
 #/ Allocate and initialize a spatial hash.
-proc SpaceHashNew*(celldim: CpFloat; cells: cint; bbfunc: TSpatialIndexBBFunc; 
+proc SpaceHashNew*(celldim: CpFloat; cells: cint; bbfun: TSpatialIndexBBFunc; 
                    staticIndex: PSpatialIndex): PSpatialIndex{.
   cdecl, importc: "cpSpaceHashNew", dynlib: Lib.}
 #/ Change the cell dimensions and table size of the spatial hash to tune it.
@@ -842,18 +842,18 @@ proc SpaceHashResize*(hash: PSpaceHash; celldim: CpFloat; numcells: cint){.
 #/ Allocate a bounding box tree.
 proc BBTreeAlloc*(): PBBTree{.cdecl, importc: "cpBBTreeAlloc", dynlib: Lib.}
 #/ Initialize a bounding box tree.
-proc BBTreeInit*(tree: PBBTree; bbfunc: TSpatialIndexBBFunc; 
+proc BBTreeInit*(tree: PBBTree; bbfun: TSpatialIndexBBFunc; 
                  staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.cdecl, 
     importc: "cpBBTreeInit", dynlib: Lib.}
 #/ Allocate and initialize a bounding box tree.
-proc BBTreeNew*(bbfunc: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{.
+proc BBTreeNew*(bbfun: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{.
     cdecl, importc: "cpBBTreeNew", dynlib: Lib.}
 #/ Perform a static top down optimization of the tree.
 proc BBTreeOptimize*(index: PSpatialIndex){.
   cdecl, importc: "cpBBTreeOptimize", dynlib: Lib.}
 #/ Set the velocity function for the bounding box tree to enable temporal coherence.
 
-proc BBTreeSetVelocityFunc*(index: PSpatialIndex; func: TBBTreeVelocityFunc){.
+proc BBTreeSetVelocityFunc*(index: PSpatialIndex; fun: TBBTreeVelocityFunc){.
     cdecl, importc: "cpBBTreeSetVelocityFunc", dynlib: Lib.}
 #MARK: Single Axis Sweep
 
@@ -864,12 +864,12 @@ proc Sweep1DAlloc*(): ptr TSweep1D{.cdecl, importc: "cpSweep1DAlloc",
                                     dynlib: Lib.}
 #/ Initialize a 1D sort and sweep broadphase.
 
-proc Sweep1DInit*(sweep: ptr TSweep1D; bbfunc: TSpatialIndexBBFunc; 
+proc Sweep1DInit*(sweep: ptr TSweep1D; bbfun: TSpatialIndexBBFunc; 
                   staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.cdecl, 
     importc: "cpSweep1DInit", dynlib: Lib.}
 #/ Allocate and initialize a 1D sort and sweep broadphase.
 
-proc Sweep1DNew*(bbfunc: TSpatialIndexBBFunc; staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.
+proc Sweep1DNew*(bbfun: TSpatialIndexBBFunc; staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.
     cdecl, importc: "cpSweep1DNew", dynlib: Lib.}
 
 
@@ -1359,7 +1359,7 @@ defCProp(SlideJoint, TVector, anchr2, Anchr2)
 defCProp(SlideJoint, CpFloat, min, Min)
 defCProp(SlideJoint, CpFloat, max, Max)
 
-proc pivotJointGetClass*(): PConstraintClass {.
+proc PivotJointGetClass*(): PConstraintClass {.
   cdecl, importc: "cpPivotJointGetClass", dynlib: Lib.}
 
 #/ Allocate a pivot joint
diff --git a/tests/manyloc/keineschweine/dependencies/enet/enet.nim b/tests/manyloc/keineschweine/dependencies/enet/enet.nim
index df1b743ee..93857207a 100644
--- a/tests/manyloc/keineschweine/dependencies/enet/enet.nim
+++ b/tests/manyloc/keineschweine/dependencies/enet/enet.nim
@@ -20,7 +20,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 const Lib = "libenet.so.1(|.0.3)"
 
-{.deadCodeElim: ON.}
+{.deadCodeElim: on.}
 const 
   ENET_VERSION_MAJOR* = 1
   ENET_VERSION_MINOR* = 3
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim
index ae9dfb39f..3026cc4b9 100644
--- a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim
@@ -18,9 +18,9 @@ proc `$`*[T](x: seq[T]): string =
     result.add($x[i])
   result.add ']'
 
-macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} = 
+macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
   result = newNimNode(nnkStmtList)
-  let 
+  let
     typeName = quoted2ident(typeNameN)
     packetID = ^"p"
     streamID = ^"s"
@@ -66,7 +66,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
     readBody = newNimNode(nnkStmtList)
     lenNames = 0
   for i in 0.. typeFields.len - 1:
-    let 
+    let
       name = typeFields[i][0]
       dotName = packetID.dot(name)
       resName = newIdentNode(!"result").dot(name)
@@ -91,11 +91,11 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
           newNimNode(nnkDiscardStmt).und(
             newCall("readData", streamID, newNimNode(nnkAddr).und(resName), newCall("sizeof", resName))))
         packBody.add(
-          newCall("writeData", streamID, newNimNode(nnkAddr).und(dotName), newCall("sizeof", dotName))) 
+          newCall("writeData", streamID, newNimNode(nnkAddr).und(dotName), newCall("sizeof", dotName)))
       of "seq":
         ## let lenX = readInt16(s)
         newLenName()
-        let 
+        let
           item = ^"item"  ## item name in our iterators
           seqType = typeFields[i][1][1] ## type of seq
           readName = newIdentNode("read"& $seqType.ident)
@@ -107,7 +107,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
         readBody.add(      ## result.name = @[]
           resName := ("@".prefix(newNimNode(nnkBracket))),
           newNimNode(nnkForStmt).und(  ## for item in 1..len:
-            item, 
+            item,
             infix(1.lit, "..", lenName),
             newNimNode(nnkStmtList).und(
               newCall(  ## add(result.name, unpack[seqType](stream))
@@ -117,7 +117,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
           newNimNode(nnkVarSection).und(newNimNode(nnkIdentDefs).und(
             lenName,  ## var lenName = int16(len(p.name))
             newIdentNode("int16"),
-            newCall("int16", newCall("len", dotName)))), 
+            newCall("int16", newCall("len", dotName)))),
           newCall("writeData", streamID, newNimNode(nnkAddr).und(lenName), 2.lit),
           newNimNode(nnkForStmt).und(  ## for item in 0..length - 1: pack(p.name[item], stream)
             item,
@@ -143,8 +143,8 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
         readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID))
     else:
       error("I dont know what to do with: "& treerepr(typeFields[i]))
-  
-  var 
+
+  var
     toStringFunc = newNimNode(nnkProcDef).und(
       newNimNode(nnkPostfix).und(
         ^"*",
@@ -161,12 +161,12 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
       emptyNode(),
       newNimNode(nnkStmtList).und(#[6]
         newNimNode(nnkAsgn).und(
-          ^"result",                  ## result = 
+          ^"result",                  ## result =
           newNimNode(nnkCall).und(#[6][0][1]
             ^"format",  ## format
             emptyNode()))))  ## "[TypeName   $1   $2]"
     formatStr = "["& $typeName.ident
-  
+
   const emptyFields = {nnkEmpty, nnkNilLit}
   var objFields = newNimNode(nnkRecList)
   for i in 0.. < len(typeFields):
@@ -186,10 +186,10 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
       prefix("$", packetID.dot(fname)))
     formatStr.add "   $"
     formatStr.add($(i + 1))
-  
+
   formatStr.add ']'
   toStringFunc[6][0][1][1] = formatStr.lit()
-  
+
   result.add(
     newNimNode(nnkTypeSection).und(
       newNimNode(nnkTypeDef).und(
@@ -206,15 +206,15 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
   when defined(GenPacketShowOutput):
     echo(repr(result))
 
-proc `->`(a: string, b: string): PNimrodNode {.compileTime.} =
+proc `->`(a: string, b: string): NimNode {.compileTime.} =
   result = newNimNode(nnkIdentDefs).und(^a, ^b, newNimNode(nnkEmpty))
-proc `->`(a: string, b: PNimrodNode): PNimrodNode {.compileTime.} =
+proc `->`(a: string, b: NimNode): NimNode {.compileTime.} =
   result = newNimNode(nnkIdentDefs).und(^a, b, newNimNode(nnkEmpty))
-proc `->`(a, b: PNimrodNode): PNimrodNode {.compileTime.} =
+proc `->`(a, b: NimNode): NimNode {.compileTime.} =
   a[2] = b
   result = a
 
-proc newProc*(name: string, params: varargs[PNimrodNode], resultType: PNimrodNode): PNimrodNode {.compileTime.} =
+proc newProc*(name: string, params: varargs[NimNode], resultType: NimNode): NimNode {.compileTime.} =
   result = newNimNode(nnkProcDef).und(
     ^name,
     emptyNode(),
@@ -227,7 +227,7 @@ proc newProc*(name: string, params: varargs[PNimrodNode], resultType: PNimrodNod
 macro forwardPacket*(typeName: expr, underlyingType: typedesc): stmt {.immediate.} =
   result = newNimNode(nnkStmtList).und(
     newProc(
-      "read"& $typeName.ident, 
+      "read"& $typeName.ident,
       ["s" -> "PStream" -> newNimNode(nnkNilLit)],
       typeName),
     newProc(
@@ -258,21 +258,21 @@ when isMainModule:
       A = 0'i8,
       B, C
   forwardPacket(SomeEnum, int8)
-  
-  
+
+
   defPacket(Foo, tuple[x: array[0..4, int8]])
   var f = newFoo([4'i8, 3'i8, 2'i8, 1'i8, 0'i8])
   var s2 = newStringStream("")
   f.pack(s2)
   assert s2.data == "\4\3\2\1\0"
-  
+
   var s = newStringStream()
   s.flushImpl = proc(s: PStream) =
     var z = PStringStream(s)
     z.setPosition(0)
     z.data.setLen(0)
-  
-  
+
+
   s.setPosition(0)
   s.data.setLen(0)
   var o = B
@@ -283,7 +283,7 @@ when isMainModule:
   o.pack(s)
   assert s.data == "\1\0\2"
   s.flush
-  
+
   defPacket(Y, tuple[z: int8])
   proc `$`(z: Y): string = result = "Y("& $z.z &")"
   defPacket(TestPkt, tuple[x: seq[Y]])
@@ -292,4 +292,4 @@ when isMainModule:
   for itm in test.x:
     echo(itm)
   test.pack(s)
-  echo(repr(s.data))
\ No newline at end of file
+  echo(repr(s.data))
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim
index 44d00db53..7cfd67c49 100644
--- a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim
@@ -9,18 +9,9 @@ template defPacketImports*(): stmt {.immediate, dirty.} =
   import macros, macro_dsl, estreams
   from strutils import format
 
-proc `$`*[T](x: seq[T]): string =
-  result = "[seq len="
-  result.add($x.len)
-  result.add ':'
-  for i in 0.. <len(x):
-    result.add "   "
-    result.add($x[i])
-  result.add ']'
-
-macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} = 
+macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
   result = newNimNode(nnkStmtList)
-  let 
+  let
     typeName = quoted2ident(typeNameN)
     packetID = ^"p"
     streamID = ^"s"
@@ -66,7 +57,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
     readBody = newNimNode(nnkStmtList)
     lenNames = 0
   for i in 0.. typeFields.len - 1:
-    let 
+    let
       name = typeFields[i][0]
       dotName = packetID.dot(name)
       resName = newIdentNode(!"result").dot(name)
@@ -76,7 +67,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
       of "seq":
         ## let lenX = readInt16(s)
         newLenName()
-        let 
+        let
           item = ^"item"  ## item name in our iterators
           seqType = typeFields[i][1][1] ## type of seq
           readName = newIdentNode("read"& $seqType.ident)
@@ -88,7 +79,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
         readBody.add(      ## result.name = @[]
           resName := ("@".prefix(newNimNode(nnkBracket))),
           newNimNode(nnkForStmt).und(  ## for item in 1..len:
-            item, 
+            item,
             infix(1.lit, "..", lenName),
             newNimNode(nnkStmtList).und(
               newCall(  ## add(result.name, unpack[seqType](stream))
@@ -98,7 +89,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
           newNimNode(nnkVarSection).und(newNimNode(nnkIdentDefs).und(
             lenName,  ## var lenName = int16(len(p.name))
             newIdentNode("int16"),
-            newCall("int16", newCall("len", dotName)))), 
+            newCall("int16", newCall("len", dotName)))),
           newCall("writeBE", streamID, lenName),
           newNimNode(nnkForStmt).und(  ## for item in 0..length - 1: pack(p.name[item], stream)
             item,
@@ -124,8 +115,8 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
         readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID))
     else:
       error("I dont know what to do with: "& treerepr(typeFields[i]))
-  
-  var 
+
+  var
     toStringFunc = newNimNode(nnkProcDef).und(
       newNimNode(nnkPostfix).und(
         ^"*",
@@ -142,12 +133,12 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
       emptyNode(),
       newNimNode(nnkStmtList).und(#[6]
         newNimNode(nnkAsgn).und(
-          ^"result",                  ## result = 
+          ^"result",                  ## result =
           newNimNode(nnkCall).und(#[6][0][1]
             ^"format",  ## format
             emptyNode()))))  ## "[TypeName   $1   $2]"
     formatStr = "["& $typeName.ident
-  
+
   const emptyFields = {nnkEmpty, nnkNilLit}
   var objFields = newNimNode(nnkRecList)
   for i in 0.. < len(typeFields):
@@ -167,10 +158,10 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
       prefix("$", packetID.dot(fname)))
     formatStr.add "   $"
     formatStr.add($(i + 1))
-  
+
   formatStr.add ']'
   toStringFunc[6][0][1][1] = formatStr.lit()
-  
+
   result.add(
     newNimNode(nnkTypeSection).und(
       newNimNode(nnkTypeDef).und(
@@ -187,7 +178,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
   when defined(GenPacketShowOutput):
     echo(repr(result))
 
-proc newProc*(name: PNimrodNode; params: varargs[PNimrodNode]; resultType: PNimrodNode): PNimrodNode {.compileTime.} =
+proc newProc*(name: NimNode; params: varargs[NimNode]; resultType: NimNode): NimNode {.compileTime.} =
   result = newNimNode(nnkProcDef).und(
     name,
     emptyNode(),
@@ -198,15 +189,15 @@ proc newProc*(name: PNimrodNode; params: varargs[PNimrodNode]; resultType: PNimr
     newNimNode(nnkStmtList))
   result[3].add(params)
 
-proc body*(procNode: PNimrodNode): PNimrodNode {.compileTime.} =
+proc body*(procNode: NimNode): NimNode {.compileTime.} =
   assert procNode.kind == nnkProcDef and procNode[6].kind == nnkStmtList
   result = procNode[6]
 
-proc iddefs*(a, b: string; c: PNimrodNode): PNimrodNode {.compileTime.} =
+proc iddefs*(a, b: string; c: NimNode): NimNode {.compileTime.} =
   result = newNimNode(nnkIdentDefs).und(^a, ^b, c)
-proc iddefs*(a: string; b: PNimrodNode): PNimrodNode {.compileTime.} =
+proc iddefs*(a: string; b: NimNode): NimNode {.compileTime.} =
   result = newNimNode(nnkIdentDefs).und(^a, b, emptyNode())
-proc varTy*(a: PNimrodNode): PNimrodNode {.compileTime.} =
+proc varTy*(a: NimNode): NimNode {.compileTime.} =
   result = newNimNode(nnkVarTy).und(a)
 
 macro forwardPacket*(typeName: expr, underlyingType: expr): stmt {.immediate.} =
@@ -215,7 +206,7 @@ macro forwardPacket*(typeName: expr, underlyingType: expr): stmt {.immediate.} =
     streamID = ^"s"
   result = newNimNode(nnkStmtList).und(
     newProc(
-      (^("read"& $typeName.ident)).postfix("*"), 
+      (^("read"& $typeName.ident)).postfix("*"),
       [ iddefs("s", "PBuffer", newNimNode(nnkNilLit)) ],
       typeName),
     newProc(
@@ -227,7 +218,7 @@ macro forwardPacket*(typeName: expr, underlyingType: expr): stmt {.immediate.} =
     readBody = result[0][6]
     packBody = result[1][6]
     resName = ^"result"
-  
+
   case underlyingType.kind
   of nnkBracketExpr:
     case $underlyingType[0].ident
@@ -259,21 +250,21 @@ when isMainModule:
       A = 0'i8,
       B, C
   forwardPacket(SomeEnum, int8)
-  
-  
+
+
   defPacket(Foo, tuple[x: array[0..4, int8]])
   var f = newFoo([4'i8, 3'i8, 2'i8, 1'i8, 0'i8])
   var s2 = newStringStream("")
   f.pack(s2)
   assert s2.data == "\4\3\2\1\0"
-  
+
   var s = newStringStream()
   s.flushImpl = proc(s: PStream) =
     var z = PStringStream(s)
     z.setPosition(0)
     z.data.setLen(0)
-  
-  
+
+
   s.setPosition(0)
   s.data.setLen(0)
   var o = B
@@ -284,7 +275,7 @@ when isMainModule:
   o.pack(s)
   assert s.data == "\1\0\2"
   s.flush
-  
+
   defPacket(Y, tuple[z: int8])
   proc `$`(z: Y): string = result = "Y("& $z.z &")"
   defPacket(TestPkt, tuple[x: seq[Y]])
@@ -293,4 +284,4 @@ when isMainModule:
   for itm in test.x:
     echo(itm)
   test.pack(s)
-  echo(repr(s.data))
\ No newline at end of file
+  echo(repr(s.data))
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim b/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim
index c7b577b3d..d3a0c701d 100644
--- a/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim
@@ -1,42 +1,42 @@
 import macros
 {.deadCodeElim: on.}
 #Inline macro.add() to allow for easier nesting
-proc und*(a: PNimrodNode; b: PNimrodNode): PNimrodNode {.compileTime.} =
+proc und*(a: NimNode; b: NimNode): NimNode {.compileTime.} =
   a.add(b)
   result = a
-proc und*(a: PNimrodNode; b: varargs[PNimrodNode]): PNimrodNode {.compileTime.} =
+proc und*(a: NimNode; b: varargs[NimNode]): NimNode {.compileTime.} =
   a.add(b)
   result = a
 
-proc `^`*(a: string): PNimrodNode {.compileTime.} = 
+proc `^`*(a: string): NimNode {.compileTime.} =
   ## new ident node
   result = newIdentNode(!a)
-proc `[]`*(a, b: PNimrodNode): PNimrodNode {.compileTime.} =
+proc `[]`*(a, b: NimNode): NimNode {.compileTime.} =
   ## new bracket expression: node[node] not to be confused with node[indx]
   result = newNimNode(nnkBracketExpr).und(a, b)
-proc `:=`*(left, right: PNimrodNode): PNimrodNode {.compileTime.} =
+proc `:=`*(left, right: NimNode): NimNode {.compileTime.} =
   ## new Asgn node:  left = right
   result = newNimNode(nnkAsgn).und(left, right)
 
-proc lit*(a: string): PNimrodNode {.compileTime.} =
+proc lit*(a: string): NimNode {.compileTime.} =
   result = newStrLitNode(a)
-proc lit*(a: int): PNimrodNode {.compileTime.} =
+proc lit*(a: int): NimNode {.compileTime.} =
   result = newIntLitNode(a)
-proc lit*(a: float): PNimrodNode {.compileTime.} =
+proc lit*(a: float): NimNode {.compileTime.} =
   result = newFloatLitNode(a)
-proc lit*(a: char): PNimrodNode {.compileTime.} =
+proc lit*(a: char): NimNode {.compileTime.} =
   result = newNimNode(nnkCharLit)
   result.intval = a.ord
 
-proc emptyNode*(): PNimrodNode {.compileTime.} =
+proc emptyNode*(): NimNode {.compileTime.} =
   result = newNimNode(nnkEmpty)
 
-proc dot*(left, right: PNimrodNode): PNimrodNode {.compileTime.} =
+proc dot*(left, right: NimNode): NimNode {.compileTime.} =
   result = newNimNode(nnkDotExpr).und(left, right)
-proc prefix*(a: string, b: PNimrodNode): PNimrodNode {.compileTime.} =
+proc prefix*(a: string, b: NimNode): NimNode {.compileTime.} =
   result = newNimNode(nnkPrefix).und(newIdentNode(!a), b)
 
-proc quoted2ident*(a: PNimrodNode): PNimrodNode {.compileTime.} = 
+proc quoted2ident*(a: NimNode): NimNode {.compileTime.} =
   if a.kind != nnkAccQuoted:
     return a
   var pname = ""
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim b/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim
index a9759687f..3c5a7835c 100644
--- a/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim
@@ -1,5 +1,5 @@
 import streams
-from strutils import repeatChar
+from strutils import repeat
 
 proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): TaintedString = 
   var lastChr = length
@@ -10,7 +10,7 @@ proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): TaintedString =
 proc writePaddedStr*(s: PStream, str: string, length: int, padChar = '\0') =
   if str.len < length:
     s.write(str)
-    s.write(repeatChar(length - str.len, padChar))
+    s.write(repeat(padChar, length - str.len))
   elif str.len > length:
     s.write(str.substr(0, length - 1))
   else:
@@ -37,7 +37,7 @@ when isMainModule:
   testStream.setPosition 0
   testStream.writePaddedStr("Sup", 10)
   echo(repr(testStream), testStream.data.len)
-  doAssert testStream.data == "Sup"&repeatChar(7, '\0')
+  doAssert testStream.data == "Sup"&repeat('\0', 7)
   
   testStream.setPosition 0
   res = testStream.readPaddedStr(10)
diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim
index 0d09d40e3..1071ec767 100644
--- a/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim
+++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim
@@ -221,10 +221,10 @@ type
   TTransform* {.pf.} = object
     matrix*: array[0..8, cfloat]
   TColor* {.pf.} = object 
-    r*: Uint8
-    g*: Uint8
-    b*: Uint8
-    a*: Uint8
+    r*: uint8
+    g*: uint8
+    b*: uint8
+    a*: uint8
   PFloatRect* = ptr TFloatRect
   TFloatRect*{.pf.} = object 
     left*: cfloat
@@ -306,7 +306,7 @@ proc close*(window: PRenderWindow) {.
 proc isOpen*(window: PRenderWindow): bool {.
   cdecl, importc: "sfRenderWindow_isOpen", dynlib: LibG.}
 
-#void sfRenderWindow_setIcon(sfRenderWindow* renderWindow, unsigned int width, unsigned int height, const sfUint8* pixels);
+#void sfRenderWindow_setIcon(sfRenderWindow* renderWindow, unsigned int width, unsigned int height, const sfuint8* pixels);
 #proc setIcon*(window: PRenderWindow, width, height: cint, pixels: seq[uint8]) {.
 #  cdecl, importc: "sfRenderWindow_setIcon", dynlib: LibG.}
 
@@ -395,7 +395,7 @@ proc capture*(window: PRenderWindow): PImage {.
   cdecl, importc: "sfRenderWindow_capture", dynlib: LibG.}
 
 #Construct a new render texture
-proc newRenderTexture*(width, height: cint; depthBuffer: Bool): PRenderTexture {.
+proc newRenderTexture*(width, height: cint; depthBuffer: bool): PRenderTexture {.
   cdecl, importc: "sfRenderTexture_create", dynlib: LibG.}
 #Destroy an existing render texture
 proc destroy*(renderTexture: PRenderTexture){.
@@ -522,9 +522,9 @@ proc copy*(font: PFont): PFont {.
   cdecl, importc: "sfFont_copy", dynlib: LibG.}
 proc destroy*(font: PFont) {.
   cdecl, importc: "sfFont_destroy", dynlib: LibG.}
-proc getGlyph*(font: PFont, codePoint: Uint32, characterSize: cint, bold: bool): TGlyph{.
+proc getGlyph*(font: PFont, codePoint: uint32, characterSize: cint, bold: bool): TGlyph{.
   cdecl, importc: "sfFont_getGlyph", dynlib: LibG.}
-proc getKerning*(font: PFont, first: Uint32, second: Uint32, characterSize: cint): cint {.
+proc getKerning*(font: PFont, first: uint32, second: uint32, characterSize: cint): cint {.
   cdecl, importc: "sfFont_getKerning", dynlib: LibG.}
 proc getLineSpacing*(font: PFont, characterSize: cint): cint {.
   cdecl, importc: "sfFont_getLineSpacing", dynlib: LibG.}
@@ -882,7 +882,7 @@ proc getInverseTransform*(text: PText): TTransform {.
   cdecl, importc: "sfText_getInverseTransform", dynlib: LibG.}
 proc setString*(text: PText, string: cstring) {.
   cdecl, importc: "sfText_setString", dynlib: LibG.}
-proc setUnicodeString*(text: PText, string: ptr Uint32) {.
+proc setUnicodeString*(text: PText, string: ptr uint32) {.
   cdecl, importc: "sfText_setUnicodeString", dynlib: LibG.}
 proc setFont*(text: PText, font: PFont) {.
   cdecl, importc: "sfText_setFont", dynlib: LibG.}
@@ -894,13 +894,13 @@ proc setColor*(text: PText, color: TColor) {.
   cdecl, importc: "sfText_setColor", dynlib: LibG.}
 proc getString*(text: PText): cstring {.
   cdecl, importc: "sfText_getString", dynlib: LibG.}
-proc getUnicodeString*(text: PText): ptr Uint32 {.cdecl, 
+proc getUnicodeString*(text: PText): ptr uint32 {.cdecl, 
   importc: "sfText_getUnicodeString", dynlib: LibG.}
 proc getFont*(text: PText): PFont {.
   cdecl, importc: "sfText_getFont", dynlib: LibG.}
 proc getCharacterSize*(text: PText): cint {.
   cdecl, importc: "sfText_getCharacterSize", dynlib: LibG.}
-proc getStyle*(text: PText): Uint32 {.
+proc getStyle*(text: PText): uint32 {.
   cdecl, importc: "sfText_getStyle", dynlib: LibG.}
 proc getColor*(text: PText): TColor {.
   cdecl, importc: "sfText_getColor", dynlib: LibG.}
diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim
index 3cfd33c02..5aa017ac4 100644
--- a/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim
+++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim
@@ -284,7 +284,7 @@ proc newSoundBuffer*(stream: PInputStream): PSoundBuffer{.
 #/ \brief Create a new sound buffer and load it from an array of samples in memory
 #/
 #/ The assumed format of the audio samples is 16 bits signed integer
-#/ (sfInt16).
+#/ (sfint16).
 #/
 #/ \param samples      Pointer to the array of samples in memory
 #/ \param sampleCount  Number of samples in the array
@@ -334,7 +334,7 @@ proc saveToFile*(soundBuffer: PSoundBuffer; filename: cstring): bool {.
 #/ \brief Get the array of audio samples stored in a sound buffer
 #/
 #/ The format of the returned samples is 16 bits signed integer
-#/ (sfInt16). The total number of samples in this array
+#/ (sfint16). The total number of samples in this array
 #/ is given by the sfSoundBuffer_getSampleCount function.
 #/
 #/ \param soundBuffer Sound buffer object
@@ -342,7 +342,7 @@ proc saveToFile*(soundBuffer: PSoundBuffer; filename: cstring): bool {.
 #/ \return Read-only pointer to the array of sound samples
 #/
 #//////////////////////////////////////////////////////////
-proc sfSoundBuffer_getSamples*(soundBuffer: PSoundBuffer): ptr Int16{.
+proc sfSoundBuffer_getSamples*(soundBuffer: PSoundBuffer): ptr int16{.
   cdecl, importc: "sfSoundBuffer_getSamples", dynlib: Lib.}
 #//////////////////////////////////////////////////////////
 #/ \brief Get the number of samples stored in a sound buffer
diff --git a/tests/manyloc/keineschweine/enet_server/enet_client.nim b/tests/manyloc/keineschweine/enet_server/enet_client.nim
index 0c903a733..5ebbdb88b 100644
--- a/tests/manyloc/keineschweine/enet_server/enet_client.nim
+++ b/tests/manyloc/keineschweine/enet_server/enet_client.nim
@@ -105,6 +105,7 @@ proc tryLogin*(b: PButton) =
     passwd = u_passwd.getText())
   dirServer.send HLogin, login
 proc tryTransition*(b: PButton) =
+  discard
   #zone.writePkt HZoneJoinReq, myCreds
 proc tryConnect*(b: PButton) =
   if not dirServer.connected:
diff --git a/tests/manyloc/keineschweine/enet_server/enet_server.nim b/tests/manyloc/keineschweine/enet_server/enet_server.nim
index 6dd1a6a7f..c2e893273 100644
--- a/tests/manyloc/keineschweine/enet_server/enet_server.nim
+++ b/tests/manyloc/keineschweine/enet_server/enet_server.nim
@@ -144,7 +144,7 @@ when isMainModule:
     discard """block:
       var 
         TestFile: FileChallengePair
-        contents = repeatStr(2, "abcdefghijklmnopqrstuvwxyz")
+        contents = repeat("abcdefghijklmnopqrstuvwxyz", 2)
       testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32) 
       testFile.file = checksumStr(contents)
       myAssets.add testFile"""
diff --git a/tests/manyloc/keineschweine/enet_server/nimrod.cfg b/tests/manyloc/keineschweine/enet_server/nim.cfg
index 72ef47ee0..72ef47ee0 100644
--- a/tests/manyloc/keineschweine/enet_server/nimrod.cfg
+++ b/tests/manyloc/keineschweine/enet_server/nim.cfg
diff --git a/tests/manyloc/keineschweine/keineschweine.nim b/tests/manyloc/keineschweine/keineschweine.nim
index e868b96a5..525d8a054 100644
--- a/tests/manyloc/keineschweine/keineschweine.nim
+++ b/tests/manyloc/keineschweine/keineschweine.nim
@@ -113,7 +113,7 @@ when defined(recordMode):
     isRecording = false
   proc zeroPad*(s: string; minLen: int): string =
     if s.len < minLen:
-      result = repeatChar(minLen - s.len, '0')
+      result = repeat(0, minLen - s.len)
       result.add s
     else:
       result = s
@@ -143,7 +143,7 @@ proc mouseToSpace*(): TVector =
 proc explode*(b: PLiveBullet)
 ## TCollisionBeginFunc
 proc collisionBulletPlayer(arb: PArbiter; space: PSpace; 
-                            data: pointer): Bool{.cdecl.} =
+                            data: pointer): bool{.cdecl.} =
   var 
     bullet = cast[PLiveBullet](arb.a.data)
     target = cast[PVehicle](arb.b.data)
@@ -152,7 +152,7 @@ proc collisionBulletPlayer(arb: PArbiter; space: PSpace;
 
 proc angularDampingSim(body: PBody, gravity: TVector, damping, dt: CpFloat){.cdecl.} =
   body.w -= (body.w * 0.98 * dt) 
-  body.updateVelocity(gravity, damping, dt)
+  body.UpdateVelocity(gravity, damping, dt)
 
 proc initLevel() =
   loadAllAssets()
@@ -227,7 +227,7 @@ proc explode*(b: PLiveBullet) =
   playSound(b.record.explosion.sound, b.body.getPos())
 
 proc bulletUpdate(body: PBody, gravity: TVector, damping, dt: CpFloat){.cdecl.} =
-  body.updateVelocity(gravity, damping, dt)
+  body.UpdateVelocity(gravity, damping, dt)
 
 template getPhysical() {.immediate.} =
   result.body = space.addBody(newBody(
@@ -237,7 +237,7 @@ template getPhysical() {.immediate.} =
     chipmunk.newCircleShape(
       result.body,
       record.physics.radius,
-      vectorZero))
+      VectorZero))
 
 proc newBullet*(record: PBulletRecord; fromPlayer: PPlayer): PLiveBullet =
   new(result, free)
@@ -480,7 +480,7 @@ when defined(DebugKeys):
       echo(repr(activeVehicle.record))
     elif keyPressed(KeyH):
       activeVehicle.body.setPos(vector(100.0, 100.0))
-      activeVehicle.body.setVel(vectorZero)
+      activeVehicle.body.setVel(VectorZero)
     elif keyPressed(KeyComma):
       activeVehicle.body.setPos mouseToSpace())
   ingameClient.registerHandler(KeyY, down, proc() =
@@ -507,7 +507,7 @@ when defined(DebugKeys):
       return
     let body = shape.getBody()
     mouseJoint = space.addConstraint(
-      newPivotJoint(mouseBody, body, vectorZero, body.world2local(point)))
+      newPivotJoint(mouseBody, body, VectorZero, body.world2local(point)))
     mouseJoint.maxForce = 50000.0
     mouseJoint.errorBias = pow(1.0 - 0.15, 60))
 
@@ -539,15 +539,15 @@ proc mainUpdate(dt: float) =
   elif not activeVehicle.isNil:
     if keyPressed(KeyUp):
       activeVehicle.accel(dt)
-    elif keyPressed(keyDown):
+    elif keyPressed(KeyDown):
       activeVehicle.reverse(dt)
     if keyPressed(KeyRight):
       activeVehicle.turn_right(dt)
     elif keyPressed(KeyLeft):
       activeVehicle.turn_left(dt)
-    if keyPressed(keyz):
+    if keyPressed(Keyz):
       activeVehicle.strafe_left(dt)
-    elif keyPressed(keyx):
+    elif keyPressed(Keyx):
       activeVehicle.strafe_right(dt)
     if keyPressed(KeyLControl):
       localPlayer.useItem 0
@@ -557,7 +557,7 @@ proc mainUpdate(dt: float) =
       localPlayer.useItem 2
     if keyPressed(KeyW):
       localPlayer.useItem 3
-    if Keypressed(keyA):
+    if keyPressed(KeyA):
       localPlayer.useItem 4
     if keyPressed(sfml.KeyS):
       localPlayer.useItem 5
@@ -666,7 +666,7 @@ when isMainModule:
   import parseopt
   
   localPlayer = newPlayer()
-  LobbyInit()
+  lobbyInit()
   
   videoMode = getClientSettings().resolution
   window = newRenderWindow(videoMode, "sup", sfDefaultStyle)
@@ -683,7 +683,7 @@ when isMainModule:
     mouseSprite.setOutlineThickness 1.4
     mouseSprite.setOrigin vec2f(14, 14)
   
-  LobbyReady()
+  lobbyReady()
   playBtn = specGui.newButton(
     "Unspec - F12", position = vec2f(680.0, 8.0), onClick = proc(b: PButton) =
       toggleSpec())
diff --git a/tests/manyloc/keineschweine/lib/game_objects.nim b/tests/manyloc/keineschweine/lib/game_objects.nim
index 37019ebcb..277ffb6cb 100644
--- a/tests/manyloc/keineschweine/lib/game_objects.nim
+++ b/tests/manyloc/keineschweine/lib/game_objects.nim
@@ -26,7 +26,7 @@ proc newObject*(record: PObjectRecord): PGameObject =
   when false:
     result.sprite = record.anim.spriteSheet.sprite.copy()
   result.body = newBody(result.record.physics.mass, 10.0)
-  result.shape = chipmunk.newCircleShape(result.body, result.record.physics.radius, vectorZero)
+  result.shape = chipmunk.newCircleShape(result.body, result.record.physics.radius, VectorZero)
   result.body.setPos(vector(100, 100))
 proc newObject*(name: string): PGameObject =
   result = newObject(fetchObj(name))
diff --git a/tests/manyloc/keineschweine/lib/gl.nim b/tests/manyloc/keineschweine/lib/gl.nim
index 9387b5bc9..c577f3404 100644
--- a/tests/manyloc/keineschweine/lib/gl.nim
+++ b/tests/manyloc/keineschweine/lib/gl.nim
@@ -38,7 +38,7 @@ type
   PGLclampf* = ptr TGLclampf
   PGLdouble* = ptr TGLdouble
   PGLclampd* = ptr TGLclampd
-  PGLvoid* = Pointer
+  PGLvoid* = pointer
   PPGLvoid* = ptr PGLvoid
   TGLenum* = cint
   TGLboolean* = bool
@@ -983,7 +983,7 @@ const                         # Version
   GL_TEXTURE_COMPONENTS* = GL_TEXTURE_INTERNAL_FORMAT
 
 proc glAccum*(op: TGLenum, value: TGLfloat){.dynlib: dllname, importc: "glAccum".}
-proc glAlphaFunc*(func: TGLenum, theref: TGLclampf){.dynlib: dllname, 
+proc glAlphaFunc*(fun: TGLenum, theref: TGLclampf){.dynlib: dllname, 
     importc: "glAlphaFunc".}
 proc glAreTexturesResident*(n: TGLsizei, textures: PGLuint, 
                             residences: PGLboolean): TGLboolean{.
@@ -998,7 +998,7 @@ proc glBitmap*(width, height: TGLsizei, xorig, yorig: TGLfloat,
 proc glBlendFunc*(sfactor, dfactor: TGLenum){.dynlib: dllname, 
     importc: "glBlendFunc".}
 proc glCallList*(list: TGLuint){.dynlib: dllname, importc: "glCallList".}
-proc glCallLists*(n: TGLsizei, atype: TGLenum, lists: Pointer){.dynlib: dllname, 
+proc glCallLists*(n: TGLsizei, atype: TGLenum, lists: pointer){.dynlib: dllname, 
     importc: "glCallLists".}
 proc glClear*(mask: TGLbitfield){.dynlib: dllname, importc: "glClear".}
 proc glClearAccum*(red, green, blue, alpha: TGLfloat){.dynlib: dllname, 
@@ -1062,7 +1062,7 @@ proc glColorMask*(red, green, blue, alpha: TGLboolean){.dynlib: dllname,
 proc glColorMaterial*(face, mode: TGLenum){.dynlib: dllname, 
     importc: "glColorMaterial".}
 proc glColorPointer*(size: TGLint, atype: TGLenum, stride: TGLsizei, 
-                     pointer: Pointer){.dynlib: dllname, 
+                     p: pointer){.dynlib: dllname, 
                                         importc: "glColorPointer".}
 proc glCopyPixels*(x, y: TGLint, width, height: TGLsizei, atype: TGLenum){.
     dynlib: dllname, importc: "glCopyPixels".}
@@ -1084,7 +1084,7 @@ proc glDeleteLists*(list: TGLuint, range: TGLsizei){.dynlib: dllname,
     importc: "glDeleteLists".}
 proc glDeleteTextures*(n: TGLsizei, textures: PGLuint){.dynlib: dllname, 
     importc: "glDeleteTextures".}
-proc glDepthFunc*(func: TGLenum){.dynlib: dllname, importc: "glDepthFunc".}
+proc glDepthFunc*(fun: TGLenum){.dynlib: dllname, importc: "glDepthFunc".}
 proc glDepthMask*(flag: TGLboolean){.dynlib: dllname, importc: "glDepthMask".}
 proc glDepthRange*(zNear, zFar: TGLclampd){.dynlib: dllname, 
     importc: "glDepthRange".}
@@ -1095,12 +1095,12 @@ proc glDrawArrays*(mode: TGLenum, first: TGLint, count: TGLsizei){.
     dynlib: dllname, importc: "glDrawArrays".}
 proc glDrawBuffer*(mode: TGLenum){.dynlib: dllname, importc: "glDrawBuffer".}
 proc glDrawElements*(mode: TGLenum, count: TGLsizei, atype: TGLenum, 
-                     indices: Pointer){.dynlib: dllname, 
+                     indices: pointer){.dynlib: dllname, 
                                         importc: "glDrawElements".}
 proc glDrawPixels*(width, height: TGLsizei, format, atype: TGLenum, 
-                   pixels: Pointer){.dynlib: dllname, importc: "glDrawPixels".}
+                   pixels: pointer){.dynlib: dllname, importc: "glDrawPixels".}
 proc glEdgeFlag*(flag: TGLboolean){.dynlib: dllname, importc: "glEdgeFlag".}
-proc glEdgeFlagPointer*(stride: TGLsizei, pointer: Pointer){.dynlib: dllname, 
+proc glEdgeFlagPointer*(stride: TGLsizei, p: pointer){.dynlib: dllname, 
     importc: "glEdgeFlagPointer".}
 proc glEdgeFlagv*(flag: PGLboolean){.dynlib: dllname, importc: "glEdgeFlagv".}
 proc glEnable*(cap: TGLenum){.dynlib: dllname, importc: "glEnable".}
@@ -1171,7 +1171,7 @@ proc glGetPixelMapuiv*(map: TGLenum, values: PGLuint){.dynlib: dllname,
     importc: "glGetPixelMapuiv".}
 proc glGetPixelMapusv*(map: TGLenum, values: PGLushort){.dynlib: dllname, 
     importc: "glGetPixelMapusv".}
-proc glGetPointerv*(pname: TGLenum, params: Pointer){.dynlib: dllname, 
+proc glGetPointerv*(pname: TGLenum, params: pointer){.dynlib: dllname, 
     importc: "glGetPointerv".}
 proc glGetPolygonStipple*(mask: PGLubyte){.dynlib: dllname, 
     importc: "glGetPolygonStipple".}
@@ -1188,10 +1188,10 @@ proc glGetTexGenfv*(coord, pname: TGLenum, params: PGLfloat){.dynlib: dllname,
 proc glGetTexGeniv*(coord, pname: TGLenum, params: PGLint){.dynlib: dllname, 
     importc: "glGetTexGeniv".}
 proc glGetTexImage*(target: TGLenum, level: TGLint, format: TGLenum, 
-                    atype: TGLenum, pixels: Pointer){.dynlib: dllname, 
+                    atype: TGLenum, pixels: pointer){.dynlib: dllname, 
     importc: "glGetTexImage".}
 proc glGetTexLevelParameterfv*(target: TGLenum, level: TGLint, pname: TGLenum, 
-                               params: Pointer){.dynlib: dllname, 
+                               params: pointer){.dynlib: dllname, 
     importc: "glGetTexLevelParameterfv".}
 proc glGetTexLevelParameteriv*(target: TGLenum, level: TGLint, pname: TGLenum, 
                                params: PGLint){.dynlib: dllname, 
@@ -1202,7 +1202,7 @@ proc glGetTexParameteriv*(target, pname: TGLenum, params: PGLint){.
     dynlib: dllname, importc: "glGetTexParameteriv".}
 proc glHint*(target, mode: TGLenum){.dynlib: dllname, importc: "glHint".}
 proc glIndexMask*(mask: TGLuint){.dynlib: dllname, importc: "glIndexMask".}
-proc glIndexPointer*(atype: TGLenum, stride: TGLsizei, pointer: Pointer){.
+proc glIndexPointer*(atype: TGLenum, stride: TGLsizei, p: pointer){.
     dynlib: dllname, importc: "glIndexPointer".}
 proc glIndexd*(c: TGLdouble){.dynlib: dllname, importc: "glIndexd".}
 proc glIndexdv*(c: PGLdouble){.dynlib: dllname, importc: "glIndexdv".}
@@ -1215,7 +1215,7 @@ proc glIndexsv*(c: PGLshort){.dynlib: dllname, importc: "glIndexsv".}
 proc glIndexub*(c: TGLubyte){.dynlib: dllname, importc: "glIndexub".}
 proc glIndexubv*(c: PGLubyte){.dynlib: dllname, importc: "glIndexubv".}
 proc glInitNames*(){.dynlib: dllname, importc: "glInitNames".}
-proc glInterleavedArrays*(format: TGLenum, stride: TGLsizei, pointer: Pointer){.
+proc glInterleavedArrays*(format: TGLenum, stride: TGLsizei, p: pointer){.
     dynlib: dllname, importc: "glInterleavedArrays".}
 proc glIsEnabled*(cap: TGLenum): TGLboolean{.dynlib: dllname, 
     importc: "glIsEnabled".}
@@ -1288,7 +1288,7 @@ proc glNormal3i*(nx, ny, nz: TGLint){.dynlib: dllname, importc: "glNormal3i".}
 proc glNormal3iv*(v: PGLint){.dynlib: dllname, importc: "glNormal3iv".}
 proc glNormal3s*(nx, ny, nz: TGLshort){.dynlib: dllname, importc: "glNormal3s".}
 proc glNormal3sv*(v: PGLshort){.dynlib: dllname, importc: "glNormal3sv".}
-proc glNormalPointer*(atype: TGLenum, stride: TGLsizei, pointer: Pointer){.
+proc glNormalPointer*(atype: TGLenum, stride: TGLsizei, p: pointer){.
     dynlib: dllname, importc: "glNormalPointer".}
 proc glOrtho*(left, right, bottom, top, zNear, zFar: TGLdouble){.
     dynlib: dllname, importc: "glOrtho".}
@@ -1360,7 +1360,7 @@ proc glRasterPos4s*(x, y, z, w: TGLshort){.dynlib: dllname,
 proc glRasterPos4sv*(v: PGLshort){.dynlib: dllname, importc: "glRasterPos4sv".}
 proc glReadBuffer*(mode: TGLenum){.dynlib: dllname, importc: "glReadBuffer".}
 proc glReadPixels*(x, y: TGLint, width, height: TGLsizei, 
-                   format, atype: TGLenum, pixels: Pointer){.dynlib: dllname, 
+                   format, atype: TGLenum, pixels: pointer){.dynlib: dllname, 
     importc: "glReadPixels".}
 proc glRectd*(x1, y1, x2, y2: TGLdouble){.dynlib: dllname, importc: "glRectd".}
 proc glRectdv*(v1: PGLdouble, v2: PGLdouble){.dynlib: dllname, 
@@ -1383,7 +1383,7 @@ proc glScissor*(x, y: TGLint, width, height: TGLsizei){.dynlib: dllname,
 proc glSelectBuffer*(size: TGLsizei, buffer: PGLuint){.dynlib: dllname, 
     importc: "glSelectBuffer".}
 proc glShadeModel*(mode: TGLenum){.dynlib: dllname, importc: "glShadeModel".}
-proc glStencilFunc*(func: TGLenum, theref: TGLint, mask: TGLuint){.
+proc glStencilFunc*(fun: TGLenum, theref: TGLint, mask: TGLuint){.
     dynlib: dllname, importc: "glStencilFunc".}
 proc glStencilMask*(mask: TGLuint){.dynlib: dllname, importc: "glStencilMask".}
 proc glStencilOp*(fail, zfail, zpass: TGLenum){.dynlib: dllname, 
@@ -1424,7 +1424,7 @@ proc glTexCoord4s*(s, t, r, q: TGLshort){.dynlib: dllname,
     importc: "glTexCoord4s".}
 proc glTexCoord4sv*(v: PGLshort){.dynlib: dllname, importc: "glTexCoord4sv".}
 proc glTexCoordPointer*(size: TGLint, atype: TGLenum, stride: TGLsizei, 
-                        pointer: Pointer){.dynlib: dllname, 
+                        p: pointer){.dynlib: dllname, 
     importc: "glTexCoordPointer".}
 proc glTexEnvf*(target: TGLenum, pname: TGLenum, param: TGLfloat){.
     dynlib: dllname, importc: "glTexEnvf".}
@@ -1448,10 +1448,10 @@ proc glTexGeniv*(coord: TGLenum, pname: TGLenum, params: PGLint){.
     dynlib: dllname, importc: "glTexGeniv".}
 proc glTexImage1D*(target: TGLenum, level, internalformat: TGLint, 
                    width: TGLsizei, border: TGLint, format, atype: TGLenum, 
-                   pixels: Pointer){.dynlib: dllname, importc: "glTexImage1D".}
+                   pixels: pointer){.dynlib: dllname, importc: "glTexImage1D".}
 proc glTexImage2D*(target: TGLenum, level, internalformat: TGLint, 
                    width, height: TGLsizei, border: TGLint, 
-                   format, atype: TGLenum, pixels: Pointer){.dynlib: dllname, 
+                   format, atype: TGLenum, pixels: pointer){.dynlib: dllname, 
     importc: "glTexImage2D".}
 proc glTexParameterf*(target: TGLenum, pname: TGLenum, param: TGLfloat){.
     dynlib: dllname, importc: "glTexParameterf".}
@@ -1462,11 +1462,11 @@ proc glTexParameteri*(target: TGLenum, pname: TGLenum, param: TGLint){.
 proc glTexParameteriv*(target: TGLenum, pname: TGLenum, params: PGLint){.
     dynlib: dllname, importc: "glTexParameteriv".}
 proc glTexSubImage1D*(target: TGLenum, level, xoffset: TGLint, width: TGLsizei, 
-                      format, atype: TGLenum, pixels: Pointer){.dynlib: dllname, 
+                      format, atype: TGLenum, pixels: pointer){.dynlib: dllname, 
     importc: "glTexSubImage1D".}
 proc glTexSubImage2D*(target: TGLenum, level, xoffset, yoffset: TGLint, 
                       width, height: TGLsizei, format, atype: TGLenum, 
-                      pixels: Pointer){.dynlib: dllname, 
+                      pixels: pointer){.dynlib: dllname, 
                                         importc: "glTexSubImage2D".}
 proc glTranslated*(x, y, z: TGLdouble){.dynlib: dllname, importc: "glTranslated".}
 proc glTranslatef*(x, y, z: TGLfloat){.dynlib: dllname, importc: "glTranslatef".}
@@ -1495,7 +1495,7 @@ proc glVertex4iv*(v: PGLint){.dynlib: dllname, importc: "glVertex4iv".}
 proc glVertex4s*(x, y, z, w: TGLshort){.dynlib: dllname, importc: "glVertex4s".}
 proc glVertex4sv*(v: PGLshort){.dynlib: dllname, importc: "glVertex4sv".}
 proc glVertexPointer*(size: TGLint, atype: TGLenum, stride: TGLsizei, 
-                      pointer: Pointer){.dynlib: dllname, 
+                      p: pointer){.dynlib: dllname, 
     importc: "glVertexPointer".}
 proc glViewport*(x, y: TGLint, width, height: TGLsizei){.dynlib: dllname, 
     importc: "glViewport".}
@@ -1505,28 +1505,28 @@ type
                                      count: TGLsizei)
   PFN_GLVERTEX_POINTER_EXTPROC* = proc (size: TGLint, atype: TGLenum, 
                                         stride, count: TGLsizei, 
-                                        pointer: Pointer)
+                                        p: pointer)
   PFN_GLNORMAL_POINTER_EXTPROC* = proc (atype: TGLenum, stride, count: TGLsizei, 
-                                        pointer: Pointer)
+                                        p: pointer)
   PFN_GLCOLOR_POINTER_EXTPROC* = proc (size: TGLint, atype: TGLenum, 
-                                       stride, count: TGLsizei, pointer: Pointer)
+                                       stride, count: TGLsizei, p: pointer)
   PFN_GLINDEX_POINTER_EXTPROC* = proc (atype: TGLenum, stride, count: TGLsizei, 
-                                       pointer: Pointer)
+                                       p: pointer)
   PFN_GLTEXCOORD_POINTER_EXTPROC* = proc (size: TGLint, atype: TGLenum, 
-      stride, count: TGLsizei, pointer: Pointer)
+      stride, count: TGLsizei, p: pointer)
   PFN_GLEDGEFLAG_POINTER_EXTPROC* = proc (stride, count: TGLsizei, 
       pointer: PGLboolean)
-  PFN_GLGET_POINTER_VEXT_PROC* = proc (pname: TGLenum, params: Pointer)
+  PFN_GLGET_POINTER_VEXT_PROC* = proc (pname: TGLenum, params: pointer)
   PFN_GLARRAY_ELEMENT_ARRAY_EXTPROC* = proc (mode: TGLenum, count: TGLsizei, 
-      pi: Pointer)            # WIN_swap_hint
+      pi: pointer)            # WIN_swap_hint
   PFN_GLADDSWAPHINT_RECT_WINPROC* = proc (x, y: TGLint, width, height: TGLsizei)
   PFN_GLCOLOR_TABLE_EXTPROC* = proc (target, internalFormat: TGLenum, 
                                      width: TGLsizei, format, atype: TGLenum, 
-                                     data: Pointer)
+                                     data: pointer)
   PFN_GLCOLOR_SUBTABLE_EXTPROC* = proc (target: TGLenum, start, count: TGLsizei, 
-                                        format, atype: TGLenum, data: Pointer)
+                                        format, atype: TGLenum, data: pointer)
   PFN_GLGETCOLOR_TABLE_EXTPROC* = proc (target, format, atype: TGLenum, 
-                                        data: Pointer)
+                                        data: pointer)
   PFN_GLGETCOLOR_TABLE_PARAMETER_IVEXTPROC* = proc (target, pname: TGLenum, 
       params: PGLint)
   PFN_GLGETCOLOR_TABLE_PARAMETER_FVEXTPROC* = proc (target, pname: TGLenum, 
diff --git a/tests/manyloc/keineschweine/lib/map_filter.nim b/tests/manyloc/keineschweine/lib/map_filter.nim
index 54173fa61..5776c9225 100644
--- a/tests/manyloc/keineschweine/lib/map_filter.nim
+++ b/tests/manyloc/keineschweine/lib/map_filter.nim
@@ -4,14 +4,14 @@ template filterIt2*(seq, pred: expr, body: stmt): stmt {.immediate, dirty.} =
   for it in items(seq):
     if pred: body
 
-proc map*[A, B](x: seq[A], func: proc(y: A): B {.closure.}): seq[B] =
+proc map*[A, B](x: seq[A], fun: proc(y: A): B {.closure.}): seq[B] =
   result = @[]
   for item in x.items:
-    result.add func(item)
+    result.add fun(item)
 
-proc mapInPlace*[A](x: var seq[A], func: proc(y: A): A {.closure.}) =
+proc mapInPlace*[A](x: var seq[A], fun: proc(y: A): A {.closure.}) =
   for i in 0..x.len-1:
-    x[i] = func(x[i])
+    x[i] = fun(x[i])
 
 template unless*(condition: expr; body: stmt): stmt {.dirty.} =
   if not(condition):
@@ -27,9 +27,9 @@ when isMainModule:
   var res = t.map(proc(z: int): int = result = z * 10)
   dumpSeq res
 
-  from strutils import toHex, repeatStr
+  from strutils import toHex
   var foocakes = t.map(proc(z: int): string = 
-    result = toHex((z * 23).biggestInt, 4))
+    result = toHex((z * 23).BiggestInt, 4))
   dumpSeq foocakes
 
   t.mapInPlace(proc(z: int): int = result = z * 30)
@@ -38,4 +38,4 @@ when isMainModule:
   var someSeq = @[9,8,7,6,5,4,3,2,1] ## numbers < 6 or even
   filterIt2 someSeq, it < 6 or (it and 1) == 0:
     echo(it)
-  echo "-----------"
\ No newline at end of file
+  echo "-----------"
diff --git a/tests/manyloc/keineschweine/lib/sg_assets.nim b/tests/manyloc/keineschweine/lib/sg_assets.nim
index ccd1d9280..c5a39550a 100644
--- a/tests/manyloc/keineschweine/lib/sg_assets.nim
+++ b/tests/manyloc/keineschweine/lib/sg_assets.nim
@@ -122,9 +122,9 @@ var
   nameToBulletID*: TTable[string, int]
   activeState = Lobby
 
-proc newSprite(filename: string; errors: var seq[string]): PSpriteSheet
+proc newSprite*(filename: string; errors: var seq[string]): PSpriteSheet
 proc load*(ss: PSpriteSheet): bool {.discardable.}
-proc newSound(filename: string; errors: var seq[string]): PSoundRecord
+proc newSound*(filename: string; errors: var seq[string]): PSoundRecord
 proc load*(s: PSoundRecord): bool {.discardable.}
 
 proc validateSettings*(settings: PJsonNode; errors: var seq[string]): bool
@@ -146,7 +146,7 @@ proc importHandling(data: PJsonNode): THandlingRecord
 proc importBullet(data: PJsonNode; errors: var seq[string]): PBulletRecord
 proc importSoul(data: PJsonNode): TSoulRecord
 proc importExplosion(data: PJsonNode; errors: var seq[string]): TExplosionRecord
-proc importSound(data: PJsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord
+proc importSound*(data: PJsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord
 
 ## this is the only pipe between lobby and main.nim
 proc getActiveState*(): TGameState =
@@ -466,7 +466,7 @@ proc importPhys(data: PJsonNode): TPhysicsRecord =
     phys.getField("radius", result.radius)
     phys.getField("mass", result.mass)
   when not defined(NoChipmunk):
-    result.moment = momentForCircle(result.mass, 0.0, result.radius, vectorZero) * MomentMult
+    result.moment = momentForCircle(result.mass, 0.0, result.radius, VectorZero) * MomentMult
 proc importHandling(data: PJsonNode): THandlingRecord =
   result.thrust = 45.0
   result.topSpeed = 100.0 #unused
diff --git a/tests/manyloc/keineschweine/lib/sg_packets.nim b/tests/manyloc/keineschweine/lib/sg_packets.nim
index 625436cb6..601054b47 100644
--- a/tests/manyloc/keineschweine/lib/sg_packets.nim
+++ b/tests/manyloc/keineschweine/lib/sg_packets.nim
@@ -9,8 +9,8 @@ template idpacket(pktName, id, s2c, c2s: expr): stmt {.immediate, dirty.} =
   defPacket(`Sc pktName`, s2c)
   defPacket(`Cs pktName`, c2s)
 
-forwardPacketT(Uint8, int8)
-forwardPacketT(Uint16, int16)
+forwardPacketT(uint8, int8)
+forwardPacketT(uint16, int16)
 forwardPacketT(TPort, int16)
 
 idPacket(Login, 'a',
@@ -51,7 +51,7 @@ defPacket(ScTeamList, tuple[teams: seq[ScTeam]])
 let HTeamChange* = 't'
 
 idPacket(ZoneQuery, 'Q',
-  tuple[playerCount: Uint16], ##i should include a time here or something
+  tuple[playerCount: uint16], ##i should include a time here or something
   tuple[pad: char = '\0'])
 
 type SpawnKind = enum
diff --git a/tests/manyloc/keineschweine/lib/vehicles.nim b/tests/manyloc/keineschweine/lib/vehicles.nim
index edbd84ff9..4b11856c6 100644
--- a/tests/manyloc/keineschweine/lib/vehicles.nim
+++ b/tests/manyloc/keineschweine/lib/vehicles.nim
@@ -9,22 +9,22 @@ proc accel*(obj: PVehicle, dt: float) =
   #  sin(obj.angle) * obj.record.handling.thrust.float * dt)
   obj.body.applyImpulse(
     vectorForAngle(obj.body.getAngle()) * dt * obj.record.handling.thrust,
-    vectorZero)
+    VectorZero)
 proc reverse*(obj: PVehicle, dt: float) =
   #obj.velocity += vec2f(
   #  -cos(obj.angle) * obj.record.handling.reverse.float * dt,
   #  -sin(obj.angle) * obj.record.handling.reverse.float * dt)
   obj.body.applyImpulse(
     -vectorForAngle(obj.body.getAngle()) * dt * obj.record.handling.reverse,
-    vectorZero)
+    VectorZero)
 proc strafe_left*(obj: PVehicle, dt: float) =
   obj.body.applyImpulse(
     vectorForAngle(obj.body.getAngle()).perp() * obj.record.handling.strafe * dt,
-    vectorZero)
+    VectorZero)
 proc strafe_right*(obj: PVehicle, dt: float) =
   obj.body.applyImpulse(
     vectorForAngle(obj.body.getAngle()).rperp()* obj.record.handling.strafe * dt,
-    vectorZero)
+    VectorZero)
 proc turn_right*(obj: PVehicle, dt: float) =
   #obj.angle = (obj.angle + (obj.record.handling.rotation.float / 10.0 * dt)) mod TAU
   obj.body.setTorque(obj.record.handling.rotation)
diff --git a/tests/manyloc/keineschweine/lib/zlib_helpers.nim b/tests/manyloc/keineschweine/lib/zlib_helpers.nim
index ef977afb0..fcd0e8d24 100644
--- a/tests/manyloc/keineschweine/lib/zlib_helpers.nim
+++ b/tests/manyloc/keineschweine/lib/zlib_helpers.nim
@@ -8,7 +8,7 @@ proc compress*(source: string): string =
   result.setLen destLen
   var res = zlib.compress(cstring(result), addr destLen, cstring(source), sourceLen)
   if res != Z_OK:
-    echo "Error occured: ", res
+    echo "Error occurred: ", res
   elif destLen < result.len:
     result.setLen(destLen)
 
@@ -17,24 +17,24 @@ proc uncompress*(source: string, destLen: var int): string =
   result.setLen destLen
   var res = zlib.uncompress(cstring(result), addr destLen, cstring(source), source.len)
   if res != Z_OK:
-    echo "Error occured: ", res
+    echo "Error occurred: ", res
     
 
 when isMainModule:
   import strutils
   var r = compress("Hello")
   echo repr(r)
-  var l = "Hello".len
-  var rr = uncompress(r, l)
+  var ln = "Hello".len
+  var rr = uncompress(r, ln)
   echo repr(rr)
   assert rr == "Hello"
 
-  proc `*`(a: string; b: int): string {.inline.} = result = repeatStr(b, a)
+  proc `*`(a: string; b: int): string {.inline.} = result = repeat(a, b)
   var s = "yo dude sup bruh homie" * 50
   r = compress(s)
   echo s.len, " -> ", r.len
 
-  l = s.len
-  rr = uncompress(r, l)
+  ln = s.len
+  rr = uncompress(r, ln)
   echo r.len, " -> ", rr.len
   assert rr == s
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/server/nimrod.cfg b/tests/manyloc/keineschweine/server/nim.cfg
index fdc45a8e1..fdc45a8e1 100644
--- a/tests/manyloc/keineschweine/server/nimrod.cfg
+++ b/tests/manyloc/keineschweine/server/nim.cfg
diff --git a/tests/manyloc/keineschweine/server/old_sg_server.nim b/tests/manyloc/keineschweine/server/old_sg_server.nim
index ac85cbf62..1e57c12a1 100644
--- a/tests/manyloc/keineschweine/server/old_sg_server.nim
+++ b/tests/manyloc/keineschweine/server/old_sg_server.nim
@@ -174,7 +174,7 @@ when isMainModule:
   block:
     var 
       TestFile: FileChallengePair
-      contents = repeatStr(2, "abcdefghijklmnopqrstuvwxyz")
+      contents = repeat("abcdefghijklmnopqrstuvwxyz", 2)
     testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32) 
     testFile.file = checksumStr(contents)
     myAssets.add testFile
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim
index 8e47c1f2f..cdd5aaf03 100644
--- a/tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim
@@ -5,7 +5,8 @@ import
 from strutils import
   formatFloat,
   TFloatFormat,
-  `%`
+  `%`,
+  ffDecimal
 
 from unsigned import
   `shr`,
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim
index e731969c1..22d36ef4d 100644
--- a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim
@@ -54,7 +54,7 @@ else:
     glRealType* = cGLfloat
 
 proc setUniformV4*[T](loc: GLint, vecs: var openarray[TV4[T]]) =
-  glUniform4fv(loc, vecs.len.GLsizei, cast[PGLfloat](vecs[0].addr))
+  glUniform4fv(loc, vecs.len.GLsizei, cast[ptr GLfloat](vecs[0].addr))
 
 proc setUniformV4*[T](loc: GLint, vec: TV4[T]) =
   var vecs = [vec]
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim
index c67748967..8c26c04eb 100644
--- a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim
@@ -16,7 +16,7 @@ type
     i*      : GLuint
     size*   : GLint
     stride* : GLsizei
-    offset* : PGLvoid
+    offset* : GLvoid
   TVertMode* = enum
     vmTriStrip = GLtriangleStrip,
     vmTriFan   = GLtriangleFan
@@ -44,7 +44,7 @@ proc newVertQuad*(min, minRight, maxLeft, max: TV2[TR]): seq[TVert] =
 proc newVert*(rect: rect.TRect): seq[TVert] =
   newVertQuad(rect.min, newV2(rect.max.x, rect.min.y), newV2(rect.min.x, rect.max.y), rect.max)
 
-proc newVertAttrib(i: GLuint, size: GLint, stride: GLsizei, offset: PGLvoid): TVertAttrib =
+proc newVertAttrib(i: GLuint, size: GLint, stride: GLsizei, offset: GLvoid): TVertAttrib =
   TVertAttrib(i: i, size: size, stride: stride, offset: offset)
 
 proc genBuf*[T](vboTarget, objUsage: GLenum, data: var openarray[T]): GLuint =
@@ -90,7 +90,7 @@ proc disableVertAttribArrs*() =
 proc setVertAttribPointers*() =
   let vertSize {.global.} = TVert.sizeof.GLint
   ?glVertexAttribPointer(0, 2, glRealType, false, vertSize, nil)
-  ?glVertexAttribPointer(1, 2, glRealType, false, vertSize, cast[PGLvoid](TR.sizeof * 2))
+  ?glVertexAttribPointer(1, 2, glRealType, false, vertSize, cast[GLvoid](TR.sizeof * 2))
 
 proc updVerts*(o: PPrimitive, start, `end`: int, f: proc(i: int, vert: var TVert)) =
   assert start <= `end`
@@ -105,7 +105,7 @@ proc updVerts*(o: PPrimitive, start, `end`: int, f: proc(i: int, vert: var TVert
   ?glBufferSubData(GLarrayBuffer,
                    byteOffset.GLintptr, # Offset. Is this right?
                    byteLen.GLsizeiptr, # Size.
-                   cast[PGLvoid](cast[int](o.verts[0].addr) + byteOffset))
+                   cast[GLvoid](cast[int](o.verts[0].addr) + byteOffset))
 
 proc updAllVerts(o: PPrimitive, f: proc(i: int, vert: var TVert)) =
   for i in 0 .. <o.verts.len:
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim
index 5972aa4fb..89bb76064 100644
--- a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim
@@ -25,7 +25,7 @@ proc setSrc*(shader: TShader, src: string) =
   ?glShaderSource(shader.id, 1, cast[cstringarray](s.addr), nil)
 
 proc newShader*(id: GL_handle): TShader =
-  if id != 0 and not (?glIsShader(id)).bool:
+  if id.int != 0 and not (?glIsShader(id)).bool:
     raise newException(E_GL, "Invalid shader ID: " & $id)
 
   result.id = id
@@ -33,7 +33,7 @@ proc newShader*(id: GL_handle): TShader =
 proc shaderInfoLog*(o: TShader): string =
   var log {.global.}: array[0..1024, char]
   var logLen: GLsizei
-  ?glGetShaderInfoLog(o.id, log.len.GLsizei, logLen, cast[PGLchar](log.addr))
+  ?glGetShaderInfoLog(o.id.GLuint, log.len.GLsizei, addr logLen, cast[cstring](log.addr))
   cast[string](log.addr).substr(0, logLen)
 
 proc compile*(shader: TShader, path="") =
@@ -67,7 +67,7 @@ proc attach*(o: TProgram, shader: TShader) =
 proc infoLog*(o: TProgram): string =
   var log {.global.}: array[0..1024, char]
   var logLen: GLsizei
-  ?glGetProgramInfoLog(o.id, log.len.GLsizei, logLen, cast[PGLchar](log.addr))
+  ?glGetProgramInfoLog(o.id.GLuint, log.len.GLsizei, addr logLen, cast[cstring](log.addr))
   cast[string](log.addr).substr(0, logLen)
 
 proc link*(o: TProgram) =
@@ -86,11 +86,11 @@ proc validate*(o: TProgram) =
 
 proc newProgram*(shaders: seq[TShader]): TProgram =
   result.id = ?glCreateProgram()
-  if result.id == 0:
+  if result.id.int == 0:
     return
 
   for shader in shaders:
-    if shader.id == 0:
+    if shader.id.int == 0:
       return
 
     ?result.attach(shader)
diff --git a/tests/manyloc/standalone/barebone.nim b/tests/manyloc/standalone/barebone.nim
index 6b452ead0..9d75f8f2e 100644
--- a/tests/manyloc/standalone/barebone.nim
+++ b/tests/manyloc/standalone/barebone.nim
@@ -1,4 +1,7 @@
 
+# bug  #2041: Macros need to be available for os:standalone!
+import macros
+
 proc printf(frmt: cstring) {.varargs, header: "<stdio.h>", cdecl.}
 
 var x = 0
diff --git a/tests/metatype/tautonotgeneric.nim b/tests/metatype/tautonotgeneric.nim
new file mode 100644
index 000000000..a55ae488e
--- /dev/null
+++ b/tests/metatype/tautonotgeneric.nim
@@ -0,0 +1,15 @@
+discard """
+  output: "wof!"
+"""
+
+# bug #1659
+type Animal = ref object {.inheritable.}
+type Dog = ref object of Animal
+
+method say(a: Animal): auto = "wat!"
+method say(a: Dog): auto = "wof!"
+
+proc saySomething(a: Animal): auto = a.say()
+
+var a = Dog()
+echo saySomething(a)
diff --git a/tests/metatype/tautoproc.nim b/tests/metatype/tautoproc.nim
index 9e8ff0bcb..ef5377096 100644
--- a/tests/metatype/tautoproc.nim
+++ b/tests/metatype/tautoproc.nim
@@ -1,7 +1,13 @@
+discard """
+  output: "empty"
+"""
+
 # bug #898
 
+import typetraits
+
 proc measureTime(e: auto) =
-  discard
+  echo e.type.name
 
 proc generate(a: int): void =
   discard
diff --git a/tests/metatype/tcompositetypeclasses.nim b/tests/metatype/tcompositetypeclasses.nim
index 5ae93795f..1cb86e4d7 100644
--- a/tests/metatype/tcompositetypeclasses.nim
+++ b/tests/metatype/tcompositetypeclasses.nim
@@ -30,7 +30,7 @@ accept bar(vbar)
 accept baz(vbar)
 accept baz(vbaz)
 
-reject baz(vnotbaz)
+#reject baz(vnotbaz) # XXX this really shouldn't compile
 reject bar(vfoo)
 
 # https://github.com/Araq/Nim/issues/517
diff --git a/tests/matrix/tmatrix.nim b/tests/metatype/tmatrix.nim
index 90dfde959..90dfde959 100644
--- a/tests/matrix/tmatrix.nim
+++ b/tests/metatype/tmatrix.nim
diff --git a/tests/matrix/tmatrix1.nim b/tests/metatype/tmatrix1.nim
index 0adf30b57..0adf30b57 100644
--- a/tests/matrix/tmatrix1.nim
+++ b/tests/metatype/tmatrix1.nim
diff --git a/tests/matrix/tmatrix2.nim b/tests/metatype/tmatrix2.nim
index 82990f1a5..82990f1a5 100644
--- a/tests/matrix/tmatrix2.nim
+++ b/tests/metatype/tmatrix2.nim
diff --git a/tests/metatype/tmatrix3.nim b/tests/metatype/tmatrix3.nim
new file mode 100644
index 000000000..a143e2bc9
--- /dev/null
+++ b/tests/metatype/tmatrix3.nim
@@ -0,0 +1,19 @@
+discard """
+  output: ""
+"""
+
+type Matrix[M,N: static[int]] = array[M, array[N, float]]
+
+let a = [[1.0,  1.0,  1.0,   1.0],
+         [2.0,  4.0,  8.0,  16.0],
+         [3.0,  9.0, 27.0,  81.0],
+         [4.0, 16.0, 64.0, 256.0]]
+
+proc `$`(m: Matrix): string =
+  result = ""
+
+proc `*`[M,N,M2,N2](a: Matrix[M,N2]; b: Matrix[M2,N]): Matrix[M,N] =
+  discard
+
+echo a * a
+
diff --git a/tests/metatype/tsemistatic.nim b/tests/metatype/tsemistatic.nim
index d187f153c..a13175ba8 100644
--- a/tests/metatype/tsemistatic.nim
+++ b/tests/metatype/tsemistatic.nim
@@ -3,6 +3,13 @@ discard """
   output: "s\nd\nd\ns"
 """
 
+type
+  semistatic[T] =
+    static[T] or T
+
+template isStatic*(x): expr =
+  compiles(static(x))
+
 proc foo(x: semistatic[int]) =
   when isStatic(x):
     static: echo "static ", x
diff --git a/tests/metatype/tstatic_overloading.nim b/tests/metatype/tstatic_overloading.nim
new file mode 100644
index 000000000..ce51052b7
--- /dev/null
+++ b/tests/metatype/tstatic_overloading.nim
@@ -0,0 +1,10 @@
+# bug #2266
+
+import macros
+
+proc impl(op: static[int]) = echo "impl 1 called"
+proc impl(op: static[int], init: int) = echo "impl 2 called"
+
+macro wrapper2: stmt = newCall(bindSym"impl", newLit(0), newLit(0))
+
+wrapper2() # Code generation for this fails.
diff --git a/tests/static/tstaticparammacro.nim b/tests/metatype/tstaticparammacro.nim
index 7fb9e2014..e577efc56 100644
--- a/tests/static/tstaticparammacro.nim
+++ b/tests/metatype/tstaticparammacro.nim
@@ -10,7 +10,11 @@ AST a
 AST b 
 (e: [55, 66], f: [77, 88])
 55
+10
+20Test
+20
 '''
+  disabled: true
 """
 
 import macros
@@ -50,3 +54,22 @@ macro mB(data: static[Tb]): stmt =
 mA(a)
 mB(b)
 
+type
+  Foo[N: static[int], Z: static[string]] = object
+
+macro staticIntMacro(f: static[int]): stmt = echo f
+staticIntMacro 10
+
+var
+  x: Foo[20, "Test"]
+
+macro genericMacro[N; Z: static[string]](f: Foo[N, Z], ll = 3, zz = 12): stmt =
+  echo N, Z
+
+genericMacro x
+
+template genericTemplate[N, Z](f: Foo[N, Z], ll = 3, zz = 12): int = N
+
+static:
+  echo genericTemplate(x) # Error: internal error: (filename: compiler/evaltempl.nim, line: 39)
+
diff --git a/tests/metatype/tstaticparams.nim b/tests/metatype/tstaticparams.nim
index 6d7c569e0..7fc5f479b 100644
--- a/tests/metatype/tstaticparams.nim
+++ b/tests/metatype/tstaticparams.nim
@@ -1,6 +1,6 @@
 discard """
   file: "tstaticparams.nim"
-  output: "abracadabra\ntest\n3\n15\n4\n2"
+  output: "abracadabra\ntest\n3\n15\n4\n2\nfloat\n3\nfloat\nyin\nyang"
 """
 
 type 
@@ -56,3 +56,87 @@ type TTestSub[N: static[int]] = TTest[1, N]
 
 var z: TTestSub[2]
 echo z.high
+
+# issue 1049
+proc matrix_1*[M, N, T](mat: Matrix[M,N,T], a: array[N, int]) = discard
+proc matrix_2*[M, N, T](mat: Matrix[M,N,T], a: array[N+1, int]) = discard
+
+proc matrix_3*[M, N: static[int]; T](mat: Matrix[M,N,T], a: array[N, int]) = discard
+proc matrix_4*[M, N: static[int]; T](mat: Matrix[M,N,T], a: array[N+1, int]) = discard
+
+var
+  tmat: Matrix[4,4,int]
+  ar1: array[4, int]
+  ar2: array[5, int]
+
+matrix_1(tmat, ar1)
+matrix_2(tmat, ar2)
+matrix_3(tmat, ar1)
+matrix_4(tmat, ar2)
+
+template reject(x): stmt =
+  static: assert(not compiles(x))
+
+# test with arrays of wrong size
+reject matrix_1(tmat, ar2)
+reject matrix_2(tmat, ar1)
+reject matrix_3(tmat, ar2)
+reject matrix_4(tmat, ar1)
+
+# bug 1820
+
+type
+  T1820_1[T; Y: static[int]] = object
+    bar: T
+
+proc intOrFloat*[Y](f: T1820_1[int, Y]) = echo "int"
+proc intOrFloat*[Y](f: T1820_1[float, Y]) = echo "float"
+proc threeOrFour*[T](f: T1820_1[T, 3]) =  echo "3"
+proc threeOrFour*[T](f: T1820_1[T, 4]) = echo "4"
+
+var foo_1: T1820_1[float, 3]
+
+foo_1.intOrFloat
+foo_1.threeOrFour
+
+type
+  YinAndYang = enum
+    Yin,
+    Yang
+
+  T1820_2[T; Y: static[YinAndYang]] = object
+    bar: T
+
+proc intOrFloat*[Y](f: T1820_2[int, Y]) = echo "int"
+proc intOrFloat*[Y](f: T1820_2[float, Y]) = echo "float"
+proc yinOrYang*[T](f: T1820_2[T, YinAndYang.Yin]) = echo "yin"
+proc yinOrYang*[T](f: T1820_2[T, Yang]) = echo "yang"
+
+var foo_2: T1820_2[float, Yin]
+var foo_3: T1820_2[float, YinAndYang.Yang]
+
+foo_2.intOrFloat
+foo_2.yinOrYang
+foo_3.yinOrYang
+
+# bug 1859
+
+type 
+  TypeWith2Params[N, M: static[int]] = object
+
+proc bindBothParams[N](x: TypeWith2Params[N, N]) = discard
+proc dontBind1[N,M](x: TypeWith2Params[N, M]) = discard
+proc dontBind2(x: TypeWith2Params) = discard
+
+var bb_1: TypeWith2Params[2, 2]
+var bb_2: TypeWith2Params[2, 3]
+
+bindBothParams(bb_1)
+reject bindBothParams(bb_2)
+
+dontBind1 bb_1
+dontBind1 bb_2
+
+dontBind2 bb_1
+dontBind2 bb_2
+
diff --git a/tests/metatype/tstaticvector.nim b/tests/metatype/tstaticvector.nim
new file mode 100644
index 000000000..c9923f469
--- /dev/null
+++ b/tests/metatype/tstaticvector.nim
@@ -0,0 +1,17 @@
+
+type
+  RectArray*[R, C: static[int], T] = distinct array[R * C, T]
+   
+  StaticMatrix*[R, C: static[int], T] = object
+    elements*: RectArray[R, C, T]
+   
+  StaticVector*[N: static[int], T] = StaticMatrix[N, 1, T]
+ 
+proc foo*[N, T](a: StaticVector[N, T]): T = 0.T
+proc foobar*[N, T](a, b: StaticVector[N, T]): T = 0.T
+ 
+ 
+var a: StaticVector[3, int]
+ 
+echo foo(a) # OK
+echo foobar(a, a) # <--- hangs compiler 
diff --git a/tests/metatype/ttypedesc2.nim b/tests/metatype/ttypedesc2.nim
new file mode 100644
index 000000000..e576ec91a
--- /dev/null
+++ b/tests/metatype/ttypedesc2.nim
@@ -0,0 +1,37 @@
+discard """
+  output: "(x: a)"
+"""
+
+type
+  Bar[T] = object
+    x: T
+
+proc infer(T: typeDesc): Bar[T] = Bar[T](x: 'a')
+
+let foo = infer(char)
+echo foo
+
+when true:
+  # bug #1783
+
+  type
+      uoffset_t* = uint32
+      FlatBufferBuilder* = object
+
+      uarray* {.unchecked.} [T]  = array [0..0, T]
+      Array* [T] = object
+          o*: uoffset_t
+          len*: int
+          data*: ptr uarray[T]
+
+  proc ca* (fbb: ptr FlatBufferBuilder, T: typedesc, len: int): Array[T] {.noinit.} =
+      result.len = len
+
+  var fbb: ptr FlatBufferBuilder
+  let boolarray = ca(fbb, bool, 2)
+  let boolarray2 = fbb.ca(bool, 2)
+
+# bug #1664
+type Point[T] = tuple[x, y: T]
+proc origin(T: typedesc): Point[T] = discard
+discard origin(int)
diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim
index 4344855eb..4c3ad9e0b 100644
--- a/tests/metatype/ttypetraits.nim
+++ b/tests/metatype/ttypetraits.nim
@@ -1,6 +1,7 @@
 discard """
   msg:    "int\nstring\nTBar[int]"
   output: "int\nstring\nTBar[int]\nint\nrange 0..2(int)\nstring"
+  disabled: true
 """
 
 import typetraits
diff --git a/tests/metatype/tusertypeclasses.nim b/tests/metatype/tusertypeclasses.nim
deleted file mode 100644
index a5d575dbf..000000000
--- a/tests/metatype/tusertypeclasses.nim
+++ /dev/null
@@ -1,43 +0,0 @@
-discard """
-  output: "Sortable\nSortable\nContainer"
-"""
-
-import typetraits
-
-type
-  TObj = object
-    x: int
-
-  Sortable = generic x, y
-    (x < y) is bool
-
-  ObjectContainer = generic C
-    C.len is ordinal
-    for v in items(C):
-      v.type is tuple|object
-
-proc foo(c: ObjectContainer) =
-  echo "Container"
-
-proc foo(x: Sortable) =
-  echo "Sortable"
-
-foo 10
-foo "test"
-foo(@[TObj(x: 10), TObj(x: 20)])
-
-proc intval(x: int): int = 10
-
-# check real and virtual fields
-type
-  TFoo = generic T
-    T.x
-    y(T)
-    intval T.y
-    let z = intval(T.y)
-
-proc y(x: TObj): int = 10
-
-proc testFoo(x: TFoo) = discard
-testFoo(TObj(x: 10))
-
diff --git a/tests/matrix/issue1013.nim b/tests/metatype/tymatrix.nim
index 7d3d52f85..7d3d52f85 100644
--- a/tests/matrix/issue1013.nim
+++ b/tests/metatype/tymatrix.nim
diff --git a/tests/metatype/typeclassinference.nim b/tests/metatype/typeclassinference.nim
index 2ac037ac5..fd2d307a9 100644
--- a/tests/metatype/typeclassinference.nim
+++ b/tests/metatype/typeclassinference.nim
@@ -1,6 +1,7 @@
 discard """
   errormsg: "type mismatch: got (string) but expected 'ptr'"
   line: 20
+  disabled: true
 """
 
 import typetraits
diff --git a/tests/metatype/typedesc_as_value.nim b/tests/metatype/typedesc_as_value.nim
new file mode 100644
index 000000000..f6e526987
--- /dev/null
+++ b/tests/metatype/typedesc_as_value.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "'typedesc' metatype is not valid here; typed '=' instead of ':'?"
+"""
+
+
+var x = int
+
+echo x
+
+
+
diff --git a/tests/method/temptybody.nim b/tests/method/temptybody.nim
new file mode 100644
index 000000000..26285d05b
--- /dev/null
+++ b/tests/method/temptybody.nim
@@ -0,0 +1,11 @@
+# bug #2401
+
+type MyClass = ref object of RootObj
+
+method HelloWorld*(obj: MyClass) =
+  when defined(myPragma):
+    echo("Hello World")
+  # discard # with this line enabled it works
+
+var obj = MyClass()
+obj.HelloWorld()
diff --git a/tests/misc/parsecomb.nim b/tests/misc/parsecomb.nim
new file mode 100644
index 000000000..68a61373f
--- /dev/null
+++ b/tests/misc/parsecomb.nim
@@ -0,0 +1,105 @@
+type Input[T] = object
+  toks: seq[T]
+  index: int
+
+type
+  ResultKind* = enum rkSuccess, rkFailure
+  Result*[T, O] = object
+    case kind*: ResultKind
+    of rkSuccess:
+      output*: O
+      input: Input[T]
+    of rkFailure:
+      nil
+
+type
+  Parser*[T, O] = distinct proc (input: Input[T]): Result[T, O]
+
+proc unit*[T, O](v: O): Parser[T, O] =
+  Parser(proc (inp: Input[T]): Result[T, O] =
+    Result[T, O](kind: rkSuccess, output: v, input: inp))
+
+proc fail*[T, O](): Parser[T, O] =
+  Parser(proc (inp: Input[T]): Result[T, O] =
+    Result(kind: rkFailure))
+
+method runInput[T, O](self: Parser[T, O], inp: Input[T]): Result[T, O] =
+  # hmmm ..
+  type tmp = proc (input: Input[T]): Result[T, O]
+  # XXX: above needed for now, as without the `tmp` bit below, it compiles to invalid C.
+  tmp(self)(inp)
+
+method run*[T, O](self: Parser[T, O], toks: seq[T]): Result[T, O] =
+  self.runInput(Input[T](toks: toks, index: 0))
+
+method chain*[T, O1, O2](self: Parser[T, O1], nextp: proc (v: O1): Parser[T, O2]): Parser[T, O2] =
+  Parser(proc (inp: Input[T]): Result[T, O2] =
+    let r = self.runInput(inp)
+    case r.kind:
+    of rkSuccess:
+      nextp(r.output).runInput(r.input)
+    of rkFailure:
+      Result[T, O2](kind: rkFailure))
+
+method skip[T](self: Input[T], n: int): Input[T] =
+  Input[T](toks: self.toks, index: self.index + n)
+
+proc pskip*[T](n: int): Parser[T, tuple[]] =
+  Parser(proc (inp: Input[T]): Result[T, tuple[]] =
+    if inp.index + n <= inp.toks.len:
+      Result[T, tuple[]](kind: rkSuccess, output: (), input: inp.skip(n))
+    else:
+      Result[T, tuple[]](kind: rkFailure))
+
+proc tok*[T](t: T): Parser[T, T] =
+  Parser(proc (inp: Input[T]): Result[T, T] =
+    if inp.index < inp.toks.len and inp.toks[inp.index] == t:
+      pskip[T](1).then(unit[T, T](t)).runInput(inp)
+    else:
+      Result[T, T](kind: rkFailure))
+
+proc `+`*[T, O](first: Parser[T, O], second: Parser[T, O]): Parser[T, O] =
+  Parser(proc (inp: Input[T]): Result[T, O] =
+    let r = first.runInput(inp)
+    case r.kind
+    of rkSuccess:
+      r
+    else:
+      second.runInput(inp))
+
+# end of primitives (definitions involving Parser(..))
+
+method map*[T, O1, O2](self: Parser[T, O1], p: proc (v: O1): O2): Parser[T, O2] =
+  self.chain(proc (v: O1): Parser[T, O2] =
+    unit[T, O2](p(v)))
+
+method then*[T, O1, O2](self: Parser[T, O1], next: Parser[T, O2]): Parser[T, O2] =
+  self.chain(proc (v: O1): Parser[T, O2] =
+    next)
+
+proc `*`*[T, O1, O2](first: Parser[T, O1], second: Parser[T, O2]): Parser[T, (O1, O2)] =
+  first.chain(proc (v1: O1): Parser[T, (O1, O2)] =
+    second.map(proc (v2: O2): (O1, O2) =
+      (v1, v2)))
+
+proc repeat0*[T, O](inner: Parser[T, O]): Parser[T, seq[O]] =
+  var nothing = unit[T, seq[O]](@[])
+  inner.chain(proc(v: O): Parser[T, seq[O]] =
+    repeat0(inner).map(proc(vs: seq[O]): seq[O] =
+      @[v] & vs)) + nothing
+
+proc repeat1*[T, O](inner: Parser[T, O]): Parser[T, seq[O]] =
+  inner.chain(proc(v: O): Parser[T, seq[O]] =
+    repeat0(inner).map(proc(vs: seq[O]): seq[O] =
+      @[v] & vs))
+
+proc leftRec*[T, O, A](inner: Parser[T, O], after: Parser[T, A], fold: proc(i: O, a: A): O): Parser[T, O] =
+  (inner*repeat0(after)).map(proc(ias: (O, seq[A])): O =
+    var (i, asx) = ias
+    for a in asx:
+      i = fold(i, a)
+    i)
+
+proc lazy*[T, O](inner: proc(): Parser[T, O]): Parser[T, O] =
+  unit[T, tuple[]](()).chain(proc(v: tuple[]): Parser[T, O] =
+    inner())
diff --git a/tests/misc/tcharinc.nim b/tests/misc/tcharinc.nim
new file mode 100644
index 000000000..1b5d19c18
--- /dev/null
+++ b/tests/misc/tcharinc.nim
@@ -0,0 +1,10 @@
+discard """
+  output: "1"
+"""
+
+var c = '\0'
+while true:
+  if c == '\xFF': break
+  inc c
+
+echo "1"
diff --git a/tests/misc/tcolonisproc.nim b/tests/misc/tcolonisproc.nim
index e55587dfc..af4077284 100644
--- a/tests/misc/tcolonisproc.nim
+++ b/tests/misc/tcolonisproc.nim
@@ -2,10 +2,11 @@
 proc p(a, b: int, c: proc ()) =
   c()
 
- 
-p(1, 3): 
-  echo 1
-  echo 3
+when false:
+  # language spec changed:
+  p(1, 3):
+    echo 1
+    echo 3
     
 p(1, 1, proc() =
   echo 1
diff --git a/tests/misc/teventemitter.nim b/tests/misc/teventemitter.nim
index bfcf95701..c1cc3d3a9 100644
--- a/tests/misc/teventemitter.nim
+++ b/tests/misc/teventemitter.nim
@@ -10,15 +10,15 @@ type
     events*: Table[string, DoublyLinkedList[proc(e: EventArgs) {.nimcall.}]]
 
 proc emit*(emitter: EventEmitter, event: string, args: EventArgs) =
-  for func in nodes(emitter.events[event]):
-    func.value(args) #call function with args.
+  for fn in nodes(emitter.events[event]):
+    fn.value(args) #call function with args.
 
 proc on*(emitter: var EventEmitter, event: string, 
-         func: proc(e: EventArgs) {.nimcall.}) =
+         fn: proc(e: EventArgs) {.nimcall.}) =
   if not hasKey(emitter.events, event):
     var list: DoublyLinkedList[proc(e: EventArgs) {.nimcall.}]
     add(emitter.events, event, list) #if not, add it.
-  append(emitter.events.mget(event), func)
+  append(emitter.events.mget(event), fn)
 
 proc initEmitter(emitter: var EventEmitter) =
   emitter.events = initTable[string, 
diff --git a/tests/misc/tgtk.nim b/tests/misc/tgtk.nim
deleted file mode 100644
index 82227689d..000000000
--- a/tests/misc/tgtk.nim
+++ /dev/null
@@ -1,53 +0,0 @@
-discard """

-  disabled: true

-"""

-import

-  gtk2, glib2, atk, gdk2, gdk2pixbuf, libglade2, pango,

-  pangoutils

-

-proc hello(widget: PWidget, data: pointer) {.cdecl.} =

-  write(stdout, "Hello World\n")

-

-proc delete_event(widget: PWidget, event: PEvent,

-                  data: pointer): bool {.cdecl.} =

-  # If you return FALSE in the "delete_event" signal handler,

-  # GTK will emit the "destroy" signal. Returning TRUE means

-  # you don't want the window to be destroyed.

-  # This is useful for popping up 'are you sure you want to quit?'

-  # type dialogs.

-  write(stdout, "delete event occurred\n")

-  # Change TRUE to FALSE and the main window will be destroyed with

-  # a "delete_event".

-  return false

-

-# Another callback

-proc mydestroy(widget: PWidget, data: pointer) {.cdecl.} =

-  gtk2.main_quit()

-

-proc mymain() =

-  # GtkWidget is the storage type for widgets

-  gtk2.nimrod_init()

-  var window = window_new(gtk2.WINDOW_TOPLEVEL)

-  discard g_signal_connect(window, "delete_event", 

-                           Gcallback(delete_event), nil)

-  discard g_signal_connect(window, "destroy", Gcallback(mydestroy), nil)

-  # Sets the border width of the window.

-  set_border_width(window, 10)

-

-  # Creates a new button with the label "Hello World".

-  var button = button_new("Hello World")

-

-  discard g_signal_connect(button, "clicked", Gcallback(hello), nil)

-

-  # This packs the button into the window (a gtk container).

-  add(window, button)

-

-  # The final step is to display this newly created widget.

-  show(button)

-

-  # and the window

-  show(window)

-

-  gtk2.main()

-

-mymain()

diff --git a/tests/misc/tinc.nim b/tests/misc/tinc.nim
index 8038a2a01..b74f85591 100644
--- a/tests/misc/tinc.nim
+++ b/tests/misc/tinc.nim
@@ -1,7 +1,7 @@
 discard """
   file: "tinc.nim"
   line: 8
-  errormsg: "for a \'var\' type a variable needs to be passed"
+  errormsg: "type mismatch: got (int)"
 """
 var x = 0
 
diff --git a/tests/misc/tinout.nim b/tests/misc/tinout.nim
index 034c496f5..4e5908428 100644
--- a/tests/misc/tinout.nim
+++ b/tests/misc/tinout.nim
@@ -1,7 +1,7 @@
 discard """
   file: "tinout.nim"
   line: 12
-  errormsg: "for a \'var\' type a variable needs to be passed"
+  errormsg: "type mismatch: got (int literal(3))"
 """
 # Test in out checking for parameters

 

diff --git a/tests/misc/tissue710.nim b/tests/misc/tissue710.nim
index 9e8735eb3..ecfdf653e 100644
--- a/tests/misc/tissue710.nim
+++ b/tests/misc/tissue710.nim
@@ -1,7 +1,7 @@
 discard """
   file: "tissue710.nim"
   line: 8
-  errorMsg: "expression '||' cannot be called"
+  errorMsg: "undeclared identifier: '||'"
 """
 var sum = 0
 for x in 3..1000:
diff --git a/tests/misc/tlibs.nim b/tests/misc/tlibs.nim
deleted file mode 100644
index e7a02c7fd..000000000
--- a/tests/misc/tlibs.nim
+++ /dev/null
@@ -1,28 +0,0 @@
-discard """
-  disabled: true
-"""
-
-# Test wether the bindings at least compile...
-
-import
-  unicode, cgi, terminal, libcurl, 
-  parsexml, parseopt, parsecfg,
-  osproc, complex,
-  sdl, smpeg, sdl_gfx, sdl_net, sdl_mixer, sdl_ttf,
-  sdl_image, sdl_mixer_nosmpeg,
-  cursorfont, xatom, xf86vmode, xkb, xrandr, xshm, xvlib, keysym, xcms, xi,
-  xkblib, xrender, xutil, x, xf86dga, xinerama, xlib, xresource, xv,
-  gtk2, glib2, pango, gdk2,
-  cairowin32, cairoxlib,
-  odbcsql,
-  gl, glut, glu, glx, glext, wingl,
-  lua, lualib, lauxlib, mysql, sqlite3, python, tcl,
-  db_postgres, db_mysql, db_sqlite, ropes, sockets, browsers, httpserver,
-  httpclient, parseutils, unidecode, xmldom, xmldomparser, xmltree, xmlparser,
-  htmlparser, re, graphics, colors, pegs, subexes, dialogs
-  
-when defined(linux):
-  import
-    zlib, zipfiles
-
-writeln(stdout, "test compilation of binding modules")
diff --git a/tests/misc/tnewlibs.nim b/tests/misc/tnewlibs.nim
deleted file mode 100644
index 3b74a9b63..000000000
--- a/tests/misc/tnewlibs.nim
+++ /dev/null
@@ -1,21 +0,0 @@
-discard """
-  disabled: true
-"""
-
-# Test wether the bindings at least compile...
-
-import
-  tcl,
-  sdl, smpeg, sdl_gfx, sdl_net, sdl_mixer, sdl_ttf,
-  sdl_image, sdl_mixer_nosmpeg,
-  gtk2, glib2, pango, gdk2,
-  unicode, cgi, terminal, libcurl, 
-  parsexml, parseopt, parsecfg,
-  osproc,
-  cairowin32, cairoxlib,
-  gl, glut, glu, glx, glext, wingl,
-  lua, lualib, lauxlib, mysql, sqlite3, db_mongo, md5, asyncio, mimetypes,
-  cookies, events, ftpclient, scgi, irc
-  
-
-writeln(stdout, "test compilation of binding modules")
diff --git a/tests/misc/tnoinst.nim b/tests/misc/tnoinst.nim
index db1058d09..4c8d9d1aa 100644
--- a/tests/misc/tnoinst.nim
+++ b/tests/misc/tnoinst.nim
@@ -1,6 +1,7 @@
 discard """
   line: 12
   errormsg: "instantiate 'notConcrete' explicitly"
+  disabled: "true"
 """
 
 proc wrap[T]() =
diff --git a/tests/misc/tnoop.nim b/tests/misc/tnoop.nim
index c79403e11..10c2eb2ec 100644
--- a/tests/misc/tnoop.nim
+++ b/tests/misc/tnoop.nim
@@ -1,12 +1,11 @@
 discard """
   file: "tnoop.nim"
   line: 11
-  errormsg: "expression \'a()\' cannot be called"
+  errormsg: "undeclared identifier: 'a'"
 """
-# Tests the new check in the semantic pass
+
 
 var
   a: int
 
-a()  #ERROR_MSG expression 'a()' cannot be called
-
+a()
diff --git a/tests/misc/tparsecombnum.nim b/tests/misc/tparsecombnum.nim
new file mode 100644
index 000000000..6fe539813
--- /dev/null
+++ b/tests/misc/tparsecombnum.nim
@@ -0,0 +1,55 @@
+import parsecomb
+
+discard """
+  output: "-289096"
+"""
+
+type Num = int
+
+# forward stuff
+var exp3: Parser[string, Num]
+var exp = lazy(proc(): Parser[string, Num] = exp3)
+
+var digit = (proc(): Parser[string, Num] =
+  result = tok("0").then(unit[string, Num](Num(0)))
+  for n in 1..9:
+    result = result + tok($n).then(unit[string, Num](Num(n)))
+)()
+
+var num = repeat1(digit).map(proc(ds: seq[Num]): Num =
+  result = 0
+  for d in ds:
+    result = result*10 + d)
+
+type Op = proc(a, b: Num): Num
+
+var plusOp = tok("+").then(unit[string, Op](proc(a, b: Num): Num = a + b))
+var minusOp = tok("-").then(unit[string, Op](proc(a, b: Num): Num = a - b))
+var timesOp = tok("*").then(unit[string, Op](proc(a, b: Num): Num = a*b))
+var divideOp = tok("/").then(unit[string, Op](proc(a, b: Num): Num = a div b))
+
+var paren = (tok("(") * exp * tok(")")).map(proc(ler: ((string, Num), string)): Num =
+  var (le, r) = ler
+  var (l, e) = le
+  e)
+
+proc foldOp(a: Num, ob: (Op, Num)): Num =
+  var (o, b) = ob
+  o(a, b)
+
+var exp0 = paren + num
+var exp1 = exp0.leftRec((timesOp + divideOp)*exp0, foldOp)
+var exp2 = exp1.leftRec((plusOp + minusOp)*exp1, foldOp)
+exp3 = exp2
+
+proc strsplit(s: string): seq[string] =
+  result = @[]
+  for i in 0 .. s.len - 1:
+    result.add($s[i])
+
+var r = exp.run("523-(1243+411/744*1642/1323)*233".strsplit)
+case r.kind:
+of rkSuccess:
+  echo r.output
+of rkFailure:
+  echo "failed"
diff --git a/tests/misc/trangechecks.nim b/tests/misc/trangechecks.nim
new file mode 100644
index 000000000..2c6f0f66d
--- /dev/null
+++ b/tests/misc/trangechecks.nim
@@ -0,0 +1,43 @@
+discard """
+  output: '''10
+10
+1
+1
+true'''
+"""
+
+# bug #1344
+
+var expected: int
+var x: range[1..10] = 10
+
+try:
+  x += 1
+  echo x
+except OverflowError, RangeError:
+  expected += 1
+  echo x
+
+try:
+  inc x
+  echo x
+except OverflowError, RangeError:
+  expected += 1
+  echo x
+
+x = 1
+try:
+  x -= 1
+  echo x
+except OverflowError, RangeError:
+  expected += 1
+  echo x
+
+try:
+  dec x
+  echo x
+except OverflowError, RangeError:
+  expected += 1
+  echo x
+
+echo expected == 4
diff --git a/tests/misc/tslices.nim b/tests/misc/tslices.nim
index 0de1171e3..388a46509 100644
--- a/tests/misc/tslices.nim
+++ b/tests/misc/tslices.nim
@@ -36,7 +36,7 @@ echo()
 
 
 var myseq = @[1, 2, 3, 4, 5, 6]
-myseq[0..2] = myseq[-3.. -1]
+myseq[0..2] = myseq[^3 .. ^1]
 
 for x in items(myseq): stdout.write(x)
 echo()
@@ -46,7 +46,7 @@ echo mystr
 mystr[4..4] = "u"
 
 # test full replacement
-mystr[.. -2] = "egerichtet"
+mystr[.. ^2] = "egerichtet"
 
 echo mystr
 
@@ -54,6 +54,6 @@ mystr[0..2] = "ve"
 echo mystr
 
 var s = "abcdef"
-s[1 .. -2] = "xyz"
+s[1 .. ^2] = "xyz"
 assert s == "axyzf"
 
diff --git a/tests/misc/tunsigned64mod.nim b/tests/misc/tunsigned64mod.nim
new file mode 100644
index 000000000..3007405a2
--- /dev/null
+++ b/tests/misc/tunsigned64mod.nim
@@ -0,0 +1,26 @@
+
+# bug #1638
+
+import unsigned
+
+let v1 = 7
+let v2 = 7'u64
+
+let t1 = v1 mod 2 # works
+let t2 = 7'u64 mod 2'u64 # works
+let t3 = v2 mod 2'u64 # Error: invalid type: 'range 0..1(uint64)
+let t4 = (v2 mod 2'u64).uint64 # works
+
+# bug #2550
+
+var x: uint # doesn't work
+echo x mod 2 == 0
+
+var y: uint64 # doesn't work
+echo y mod 2 == 0
+
+var z: uint32 # works
+echo z mod 2 == 0
+
+var a: int # works
+echo a mod 2 == 0
diff --git a/tests/misc/tunsignedcomp.nim b/tests/misc/tunsignedcomp.nim
new file mode 100644
index 000000000..19c8876b1
--- /dev/null
+++ b/tests/misc/tunsignedcomp.nim
@@ -0,0 +1,136 @@
+discard """
+  output: ''''''
+  disabled: "true"
+"""
+
+# All operations involving uint64 are commented out
+# as they're not yet supported.
+# All other operations are handled by implicit conversions from uints to ints
+# uint64 could be supported but would need special implementation of the operators
+
+# unsigned < signed
+
+assert 10'u8 < 20'i8
+assert 10'u8 < 20'i16
+assert 10'u8 < 20'i32
+assert 10'u8 < 20'i64
+
+assert 10'u16 < 20'i8
+assert 10'u16 < 20'i16
+assert 10'u16 < 20'i32
+assert 10'u16 < 20'i64
+
+assert 10'u32 < 20'i8
+assert 10'u32 < 20'i16
+assert 10'u32 < 20'i32
+assert 10'u32 < 20'i64
+
+# assert 10'u64 < 20'i8
+# assert 10'u64 < 20'i16
+# assert 10'u64 < 20'i32
+# assert 10'u64 < 20'i64
+
+# signed < unsigned
+assert 10'i8 < 20'u8
+assert 10'i8 < 20'u16
+assert 10'i8 < 20'u32
+# assert 10'i8 < 20'u64
+
+assert 10'i16 < 20'u8
+assert 10'i16 < 20'u16
+assert 10'i16 < 20'u32
+# assert 10'i16 < 20'u64
+
+assert 10'i32 < 20'u8
+assert 10'i32 < 20'u16
+assert 10'i32 < 20'u32
+# assert 10'i32 < 20'u64
+
+assert 10'i64 < 20'u8
+assert 10'i64 < 20'u16
+assert 10'i64 < 20'u32
+# assert 10'i64 < 20'u64
+
+# unsigned <= signed
+assert 10'u8 <= 20'i8
+assert 10'u8 <= 20'i16
+assert 10'u8 <= 20'i32
+assert 10'u8 <= 20'i64
+
+assert 10'u16 <= 20'i8
+assert 10'u16 <= 20'i16
+assert 10'u16 <= 20'i32
+assert 10'u16 <= 20'i64
+
+assert 10'u32 <= 20'i8
+assert 10'u32 <= 20'i16
+assert 10'u32 <= 20'i32
+assert 10'u32 <= 20'i64
+
+# assert 10'u64 <= 20'i8
+# assert 10'u64 <= 20'i16
+# assert 10'u64 <= 20'i32
+# assert 10'u64 <= 20'i64
+
+# signed <= unsigned
+assert 10'i8 <= 20'u8
+assert 10'i8 <= 20'u16
+assert 10'i8 <= 20'u32
+# assert 10'i8 <= 20'u64
+
+assert 10'i16 <= 20'u8
+assert 10'i16 <= 20'u16
+assert 10'i16 <= 20'u32
+# assert 10'i16 <= 20'u64
+
+assert 10'i32 <= 20'u8
+assert 10'i32 <= 20'u16
+assert 10'i32 <= 20'u32
+# assert 10'i32 <= 20'u64
+
+assert 10'i64 <= 20'u8
+assert 10'i64 <= 20'u16
+assert 10'i64 <= 20'u32
+# assert 10'i64 <= 20'u64
+
+# signed == unsigned
+assert 10'i8 == 10'u8
+assert 10'i8 == 10'u16
+assert 10'i8 == 10'u32
+# assert 10'i8 == 10'u64
+
+assert 10'i16 == 10'u8
+assert 10'i16 == 10'u16
+assert 10'i16 == 10'u32
+# assert 10'i16 == 10'u64
+
+assert 10'i32 == 10'u8
+assert 10'i32 == 10'u16
+assert 10'i32 == 10'u32
+# assert 10'i32 == 10'u64
+
+assert 10'i64 == 10'u8
+assert 10'i64 == 10'u16
+assert 10'i64 == 10'u32
+# assert 10'i64 == 10'u64
+
+# unsigned == signed
+assert 10'u8 == 10'i8
+assert 10'u8 == 10'i16
+assert 10'u8 == 10'i32
+# assert 10'u8 == 10'i64
+
+assert 10'u16 == 10'i8
+assert 10'u16 == 10'i16
+assert 10'u16 == 10'i32
+# assert 10'u16 == 10'i64
+
+assert 10'u32 == 10'i8
+assert 10'u32 == 10'i16
+assert 10'u32 == 10'i32
+# assert 10'u32 == 10'i64
+
+# assert 10'u64 == 10'i8
+# assert 10'u64 == 10'i16
+# assert 10'u64 == 10'i32
+# assert 10'u64 == 10'i64
diff --git a/tests/misc/tunsignedconv.nim b/tests/misc/tunsignedconv.nim
new file mode 100644
index 000000000..3032f8de6
--- /dev/null
+++ b/tests/misc/tunsignedconv.nim
@@ -0,0 +1,43 @@
+
+import unsigned
+
+# Tests unsigned literals and implicit conversion between uints and ints
+# Passes if it compiles
+
+var h8:uint8 = 128
+var h16:uint16 = 32768
+var h32:uint32 = 2147483648'u32
+var h64:uint64 = 9223372036854775808'u64
+var foobar:uint64 = 9223372036854775813'u64 # Issue 728
+
+var v8:uint8 = 10
+var v16:uint16 = 10
+var v32:uint32 = 10
+var v64:uint64 = 10
+
+# u8 + literal produces u8:
+var a8: uint8 = v8 + 10
+var a16: uint16 = v16 + 10
+
+when false:
+  var d8  = v8 + 10'i8
+  var d16 = v8 + 10'i16
+  var d32 = v8 + 10'i32
+
+when false:
+  # these dont work yet because unsigned.nim is stupid. XXX We need to fix this.
+  var f8  = v16 + 10'u8
+  var f16 = v16 + 10'u16
+  var f32 = v16 + 10'u32
+
+  var g8  = v32 + 10'u8
+  var g16 = v32 + 10'u16
+  var g32 = v32 + 10'u32
+
+var ar: array[0..20, int]
+var n8 = ar[v8]
+var n16 = ar[v16]
+var n32 = ar[v32]
+var n64 = ar[v64]
+
+
diff --git a/tests/misc/tunsignedinc.nim b/tests/misc/tunsignedinc.nim
new file mode 100644
index 000000000..95622156f
--- /dev/null
+++ b/tests/misc/tunsignedinc.nim
@@ -0,0 +1,14 @@
+discard """
+  output: '''253'''
+"""
+
+# bug #2427
+
+import unsigned
+
+var x = 0'u8
+dec x # OverflowError
+x -= 1 # OverflowError
+x = x - 1 # No error
+
+echo x
diff --git a/tests/misc/tvarious.nim b/tests/misc/tvarious.nim
index ed2964cf9..8124b3fc7 100644
--- a/tests/misc/tvarious.nim
+++ b/tests/misc/tvarious.nim
@@ -1,64 +1,68 @@
-# Test various aspects

+# Test various aspects
 
 # bug #572
 var a=12345678901'u64
-

+
 var x = (x: 42, y: (a: 8, z: 10))
 echo x.y
-

-import

-  mvarious

-

-type

-  PA = ref TA

-  PB = ref TB

-

-  TB = object

-    a: PA

-

-  TA = object

-    b: TB

-    x: int

-

-proc getPA(): PA =

-  var

-    b: bool

-  b = not false

-  return nil

+
+import
+  mvarious
+
+type
+  PA = ref TA
+  PB = ref TB
+
+  TB = object
+    a: PA
+
+  TA = object
+    b: TB
+    x: int
+
+proc getPA(): PA =
+  var
+    b: bool
+  b = not false
+  return nil
 
 # bug #501
 proc f(): int = 54
-

-var

-  global: int

-

-var

-  s: string

-  i: int

-  r: TA

-

-r.b.a.x = 0

-global = global + 1

-exportme()

-write(stdout, "Hallo wie heißt du? ")

-write(stdout, getPA().x)

-s = readLine(stdin)

-i = 0

-while i < s.len:

-  if s[i] == 'c': write(stdout, "'c' in deinem Namen gefunden\n")

-  i = i + 1

-

-write(stdout, "Du heißt " & s)

+
+var
+  global: int
+
+var
+  s: string
+  i: int
+  r: TA
+
+r.b.a.x = 0
+global = global + 1
+exportme()
+write(stdout, "Hallo wie heißt du? ")
+write(stdout, getPA().x)
+s = readLine(stdin)
+i = 0
+while i < s.len:
+  if s[i] == 'c': write(stdout, "'c' in deinem Namen gefunden\n")
+  i = i + 1
+
+write(stdout, "Du heißt " & s)
 
 # bug #544
-when false:
-  # yay, fails again
-  type Bar [T; I:range] = array[I, T]
-  proc foo*[T; I:range](a, b: Bar[T, I]): Bar[T, I] =
-    when len(a) != 3: 
-      # Error: constant expression expected
-      {.fatal:"Dimensions have to be 3".}
-    #...
-  block:
-    var a, b: Bar[int, 0..2]
-    discard foo(a, b)
+
+# yay, fails again
+type Bar [T; I:range] = array[I, T]
+proc foo*[T; I:range](a, b: Bar[T, I]): Bar[T, I] =
+  when len(a) != 3:
+    # Error: constant expression expected
+    {.fatal:"Dimensions have to be 3".}
+  #...
+block:
+  var a, b: Bar[int, range[0..2]]
+  discard foo(a, b)
+
+# bug #1788
+
+echo "hello" & char(ord(' ')) & "world"
diff --git a/tests/module/trecinca.nim b/tests/module/trecinca.nim
deleted file mode 100644
index 62d37783c..000000000
--- a/tests/module/trecinca.nim
+++ /dev/null
@@ -1,12 +0,0 @@
-discard """
-  file: "tests/reject/trecincb.nim"
-  line: 9
-  errormsg: "recursive dependency: 'tests/module/trecincb.nim'"
-"""
-# Test recursive includes
-
-include trecincb #ERROR_MSG recursive dependency: 'tests/trecincb.nim'
-
-echo "trecina"
-
-
diff --git a/tests/module/trecincb.nim b/tests/module/trecincb.nim
deleted file mode 100644
index a2934052f..000000000
--- a/tests/module/trecincb.nim
+++ /dev/null
@@ -1,13 +0,0 @@
-discard """
-  file: "trecincb.nim"
-  line: 9
-  errormsg: "recursive dependency: 'tests/module/trecincb.nim'"
-"""
-# Test recursive includes
-
-
-include trecincb #ERROR_MSG recursive dependency: 'tests/trecincb.nim'
-
-echo "trecinb"
-
-
diff --git a/tests/namspc/mnamspc1.nim b/tests/modules/mnamspc1.nim
index da13c5f24..da13c5f24 100644
--- a/tests/namspc/mnamspc1.nim
+++ b/tests/modules/mnamspc1.nim
diff --git a/tests/namspc/mnamspc2.nim b/tests/modules/mnamspc2.nim
index 84ef8533e..84ef8533e 100644
--- a/tests/namspc/mnamspc2.nim
+++ b/tests/modules/mnamspc2.nim
diff --git a/tests/module/mopaque.nim b/tests/modules/mopaque.nim
index 7eee4bd96..7eee4bd96 100644
--- a/tests/module/mopaque.nim
+++ b/tests/modules/mopaque.nim
diff --git a/tests/module/mrecmod.nim b/tests/modules/mrecmod.nim
index fab9654d5..fab9654d5 100644
--- a/tests/module/mrecmod.nim
+++ b/tests/modules/mrecmod.nim
diff --git a/tests/module/mrecmod2.nim b/tests/modules/mrecmod2.nim
index 9557ce729..9557ce729 100644
--- a/tests/module/mrecmod2.nim
+++ b/tests/modules/mrecmod2.nim
diff --git a/tests/modules/tmismatchedvisibility.nim b/tests/modules/tmismatchedvisibility.nim
index 6f2f79282..325c729c0 100644
--- a/tests/modules/tmismatchedvisibility.nim
+++ b/tests/modules/tmismatchedvisibility.nim
@@ -1,9 +1,9 @@
 discard """
   line: 8
-  errormsg: "public implementation 'tmismatchedvisibility.foo(a: int): int' has non-public forward declaration in tmismatchedvisibility.nim(6,5)"
+  errormsg: "public implementation 'tmismatchedvisibility.foo(a: int)' has non-public forward declaration in "
 """
 
 proc foo(a: int): int
 
 proc foo*(a: int): int =
-  result = a + a
\ No newline at end of file
+  result = a + a
diff --git a/tests/namspc/tnamspc.nim b/tests/modules/tnamspc.nim
index 1e2049cec..1e2049cec 100644
--- a/tests/namspc/tnamspc.nim
+++ b/tests/modules/tnamspc.nim
diff --git a/tests/module/topaque.nim b/tests/modules/topaque.nim
index f0587c959..f0587c959 100644
--- a/tests/module/topaque.nim
+++ b/tests/modules/topaque.nim
diff --git a/tests/modules/trecinca.nim b/tests/modules/trecinca.nim
new file mode 100644
index 000000000..14a91ba5c
--- /dev/null
+++ b/tests/modules/trecinca.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "tests/reject/trecincb.nim"
+  line: 9
+  errormsg: "recursive dependency: 'tests/modules/trecincb.nim'"
+"""
+# Test recursive includes
+
+include trecincb
+
+echo "trecina"
+
+
diff --git a/tests/modules/trecincb.nim b/tests/modules/trecincb.nim
new file mode 100644
index 000000000..299a242e1
--- /dev/null
+++ b/tests/modules/trecincb.nim
@@ -0,0 +1,13 @@
+discard """
+  file: "trecincb.nim"
+  line: 9
+  errormsg: "recursive dependency: 'tests/modules/trecincb.nim'"
+"""
+# Test recursive includes
+
+
+include trecincb
+
+echo "trecinb"
+
+
diff --git a/tests/module/trecmod.nim b/tests/modules/trecmod.nim
index 9d39d3ff7..9d39d3ff7 100644
--- a/tests/module/trecmod.nim
+++ b/tests/modules/trecmod.nim
diff --git a/tests/module/trecmod2.nim b/tests/modules/trecmod2.nim
index 85fe2215f..85fe2215f 100644
--- a/tests/module/trecmod2.nim
+++ b/tests/modules/trecmod2.nim
diff --git a/tests/notnil/tnotnil4.nim b/tests/notnil/tnotnil4.nim
index 23968ee48..2fa888357 100644
--- a/tests/notnil/tnotnil4.nim
+++ b/tests/notnil/tnotnil4.nim
@@ -11,4 +11,10 @@ proc doit() =
    if x[0] != nil:
       check(x[0])
 
-doit()
\ No newline at end of file
+doit()
+
+# bug #2352
+
+proc p(x: proc() {.noconv.} not nil) = discard
+p(proc() {.noconv.} = discard)
+# Error: cannot prove 'proc () {.noconv.} = discard ' is not nil
diff --git a/tests/notnil/tnotnil_in_generic.nim b/tests/notnil/tnotnil_in_generic.nim
new file mode 100644
index 000000000..1e2d8b940
--- /dev/null
+++ b/tests/notnil/tnotnil_in_generic.nim
@@ -0,0 +1,27 @@
+discard """
+  errormsg: "cannot prove 'x' is not nil"
+"""
+
+# bug #2216
+
+type
+    A[T] = ref object
+        x: int
+        ud: T
+
+proc good[T](p: A[T]) = 
+    discard
+
+proc bad[T](p: A[T] not nil) = 
+    discard
+
+
+proc go() = 
+    let s = A[int](x: 1)
+
+    good(s)
+    bad(s)
+    var x: A[int]
+    bad(x)
+
+go()
diff --git a/tests/notnil/tnotnil_in_objconstr.nim b/tests/notnil/tnotnil_in_objconstr.nim
new file mode 100644
index 000000000..2110bda8f
--- /dev/null
+++ b/tests/notnil/tnotnil_in_objconstr.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "field not initialized: bar"
+  line: "13"
+"""
+
+# bug #2355
+type
+  Foo = object
+    foo: string not nil
+    bar: string not nil
+
+# Create instance without initializaing the `bar` field
+var f = Foo(foo: "foo")
+echo f.bar.isNil # true
diff --git a/tests/objects/tillegal_recursion.nim b/tests/objects/tillegal_recursion.nim
new file mode 100644
index 000000000..171a04f87
--- /dev/null
+++ b/tests/objects/tillegal_recursion.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "illegal recursion in type 'object'"
+  line: 7
+"""
+# bug #1691
+type
+  Foo = ref object of Foo
diff --git a/tests/objects/tobjconstr.nim b/tests/objects/tobjconstr.nim
index 3bd785728..226fe98f7 100644
--- a/tests/objects/tobjconstr.nim
+++ b/tests/objects/tobjconstr.nim
@@ -1,14 +1,14 @@
 discard """
-  output: '''(k: kindA, a: (x: abc, z: [1, 1, 3]), empty: ())
-(k: kindA, a: (x: abc, z: [1, 2, 3]), empty: ())
-(k: kindA, a: (x: abc, z: [1, 3, 3]), empty: ())
-(k: kindA, a: (x: abc, z: [1, 4, 3]), empty: ())
-(k: kindA, a: (x: abc, z: [1, 5, 3]), empty: ())
-(k: kindA, a: (x: abc, z: [1, 6, 3]), empty: ())
-(k: kindA, a: (x: abc, z: [1, 7, 3]), empty: ())
-(k: kindA, a: (x: abc, z: [1, 8, 3]), empty: ())
-(k: kindA, a: (x: abc, z: [1, 9, 3]), empty: ())
-(k: kindA, a: (x: abc, z: [1, 10, 3]), empty: ())'''
+  output: '''(k: kindA, a: (x: abc, z: [1, 1, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 2, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 3, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 4, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 5, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 6, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 7, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 8, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 9, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 10, 3]), method: ())'''
 """
 
 type
@@ -20,9 +20,9 @@ type
   TDummy = ref object
     case k: TKind
     of kindXY: x, y: int
-    of kindA: 
+    of kindA:
       a: TArg
-      empty: TEmpty
+      `method`: TEmpty # bug #1791
 
 proc `$`[T](s: seq[T]): string =
   # XXX why is that not in the stdlib?
@@ -34,7 +34,7 @@ proc `$`[T](s: seq[T]): string =
 
 proc main() =
   for i in 1..10:
-    let d = TDummy(k: kindA, a: TArg(x: "abc", z: @[1,i,3]), empty: TEmpty())
+    let d = TDummy(k: kindA, a: TArg(x: "abc", z: @[1,i,3]), `method`: TEmpty())
     echo d[]
 
 main()
diff --git a/tests/objects/tobjloop.nim b/tests/objects/tobjloop.nim
new file mode 100644
index 000000000..9fea1e2fb
--- /dev/null
+++ b/tests/objects/tobjloop.nim
@@ -0,0 +1,15 @@
+discard """
+  output: "is Nil false"
+"""
+# bug #1658
+
+type
+  Loop* = ref object
+    onBeforeSelect*: proc (L: Loop)
+
+var L: Loop
+new L
+L.onBeforeSelect = proc (bar: Loop) =
+  echo "is Nil ", bar.isNil
+
+L.onBeforeSelect(L)
diff --git a/tests/objects/tobjpragma.nim b/tests/objects/tobjpragma.nim
index f9fbd5e40..dda8057b6 100644
--- a/tests/objects/tobjpragma.nim
+++ b/tests/objects/tobjpragma.nim
@@ -7,8 +7,11 @@ discard """
 1
 2
 3'''
+  disabled: "true"
 """
 
+# Disabled since some versions of GCC ignore the 'packed' attribute
+
 # Test 
 
 type
diff --git a/tests/objects/trefobjsyntax.nim b/tests/objects/trefobjsyntax.nim
new file mode 100644
index 000000000..9b48de718
--- /dev/null
+++ b/tests/objects/trefobjsyntax.nim
@@ -0,0 +1,27 @@
+discard """
+  output: '''wohoo
+baz'''
+"""
+
+# Test to ensure the popular 'ref T' syntax works everywhere
+
+type
+  Foo = object
+    a, b: int
+    s: string
+
+  FooBar = object of RootObj
+    n, m: string
+  Baz = object of FooBar
+
+proc invoke(a: ref Baz) =
+  echo "baz"
+
+# check object construction:
+let x = (ref Foo)(a: 0, b: 45, s: "wohoo")
+echo x.s
+
+var y: ref FooBar = (ref Baz)(n: "n", m: "m")
+
+invoke((ref Baz)(y))
+
diff --git a/tests/objects/trefobjsyntax2.nim b/tests/objects/trefobjsyntax2.nim
new file mode 100644
index 000000000..8ee209cc7
--- /dev/null
+++ b/tests/objects/trefobjsyntax2.nim
@@ -0,0 +1,19 @@
+# bug #2508
+
+type
+  GenericNodeObj[T] = ref object
+    obj: T
+
+  Node* = ref object
+    children*: seq[Node]
+    parent*: Node
+
+    nodeObj*: GenericNodeObj[int]
+
+proc newNode*(nodeObj: GenericNodeObj): Node =
+    result = Node(nodeObj: nodeObj)
+    newSeq(result.children, 10)
+
+var genericObj = GenericNodeObj[int]()
+
+var myNode = newNode(genericObj)
diff --git a/tests/objvariant/tadrdisc.nim b/tests/objvariant/tadrdisc.nim
index 0e0324562..1afe7d04f 100644
--- a/tests/objvariant/tadrdisc.nim
+++ b/tests/objvariant/tadrdisc.nim
@@ -1,7 +1,7 @@
 discard """
   file: "tadrdisc.nim"
   line: 20
-  errormsg: "for a \'var\' type a variable needs to be passed"
+  errormsg: "type mismatch: got (TKind)"
 """
 # Test that the address of a dicriminants cannot be taken
 
@@ -12,12 +12,9 @@ type
     of ka: x, y: int
     of kb: a, b: string
     of kc: c, d: float
-    
-proc setKind(k: var TKind) = 
-  k = kc
-  
-var a: TA
-setKind(a.k) #ERROR_MSG for a 'var' type a variable needs to be passed
-
 
+proc setKind(k: var TKind) =
+  k = kc
 
+var a: TA
+setKind(a.k)
diff --git a/tests/objvariant/treassign.nim b/tests/objvariant/treassign.nim
new file mode 100644
index 000000000..2938b30a3
--- /dev/null
+++ b/tests/objvariant/treassign.nim
@@ -0,0 +1,27 @@
+discard """
+  output: "SUCCESS"
+"""
+
+type
+    BasicNumber = object of RootObj
+        value: float32
+    RefChild* = ref object
+        curr*: TokenObject
+    Token* {.pure.} = enum
+        foo,
+        bar,
+    TokenObject = object
+        case kind*: Token
+        of Token.foo:
+            foo*: string
+        of Token.bar:
+            bar*: BasicNumber
+
+
+var t = RefChild()
+
+t.curr = TokenObject(kind: Token.bar, bar: BasicNumber(value: 12.34))
+
+t.curr = TokenObject(kind: Token.foo, foo: "foo")
+
+echo "SUCCESS"
diff --git a/tests/osproc/tstdin.nim b/tests/osproc/tstdin.nim
index 2ea939992..b491c2500 100644
--- a/tests/osproc/tstdin.nim
+++ b/tests/osproc/tstdin.nim
@@ -4,13 +4,16 @@ discard """
 """
 import osproc, os, streams
 
-doAssert fileExists(getCurrentDir() / "tests" / "osproc" / "ta.exe")
+const filename = when defined(Windows): "ta.exe" else: "ta"
 
-var p = startProcess("ta.exe", getCurrentDir() / "tests" / "osproc")
+doAssert fileExists(getCurrentDir() / "tests" / "osproc" / filename)
+
+var p = startProcess(filename, getCurrentDir() / "tests" / "osproc")
 p.inputStream.write("5\n")
+p.inputStream.flush()
 while true:
   let line = p.outputStream.readLine()
   if line != "":
     echo line
   else:
-    break
\ No newline at end of file
+    break
diff --git a/tests/overload/toverprc.nim b/tests/overload/toverprc.nim
index 22b64ed48..78831f744 100644
--- a/tests/overload/toverprc.nim
+++ b/tests/overload/toverprc.nim
@@ -1,14 +1,19 @@
+discard """
+  output: '''another number: 123
+yay'''
+"""
+
 # Test overloading of procs when used as function pointers
 
 import strutils
 
-proc parseInt(x: float): int {.noSideEffect.} = nil
-proc parseInt(x: bool): int {.noSideEffect.} = nil
-proc parseInt(x: float32): int {.noSideEffect.} = nil
-proc parseInt(x: int8): int {.noSideEffect.} = nil
-proc parseInt(x: TFile): int {.noSideEffect.} = nil
-proc parseInt(x: char): int {.noSideEffect.} = nil
-proc parseInt(x: int16): int {.noSideEffect.} = nil
+proc parseInt(x: float): int {.noSideEffect.} = discard
+proc parseInt(x: bool): int {.noSideEffect.} = discard
+proc parseInt(x: float32): int {.noSideEffect.} = discard
+proc parseInt(x: int8): int {.noSideEffect.} = discard
+proc parseInt(x: TFile): int {.noSideEffect.} = discard
+proc parseInt(x: char): int {.noSideEffect.} = discard
+proc parseInt(x: int16): int {.noSideEffect.} = discard
 
 proc parseInt[T](x: T): int = echo x; 34
 
@@ -19,12 +24,13 @@ var
   q = TParseInt(parseInt)
   p: TParseInt = parseInt
 
-proc takeParseInt(x: proc (y: string): int {.noSideEffect.}): int = 
+proc takeParseInt(x: proc (y: string): int {.noSideEffect.}): int =
   result = x("123")
-  
-echo "Give a list of numbers (separated by spaces): "
-var x = stdin.readline.split.map(parseInt).max
-echo x, " is the maximum!"
+
+if false:
+  echo "Give a list of numbers (separated by spaces): "
+  var x = stdin.readline.split.map(parseInt).max
+  echo x, " is the maximum!"
 echo "another number: ", takeParseInt(parseInt)
 
 
diff --git a/tests/overload/tparams_after_varargs.nim b/tests/overload/tparams_after_varargs.nim
new file mode 100644
index 000000000..a93e280b9
--- /dev/null
+++ b/tests/overload/tparams_after_varargs.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''a 1 b 2 x @[3, 4, 5] y 6 z 7
+yay
+12'''
+"""
+
+proc test(a, b: int, x: varargs[int]; y, z: int) =
+  echo "a ", a, " b ", b, " x ", @x, " y ", y, " z ", z
+
+test 1, 2, 3, 4, 5, 6, 7
+
+template takesBlock(a, b: int, x: varargs[expr]; blck: stmt) =
+  blck
+  echo a, b
+
+takesBlock 1, 2, "some", 0.90, "random stuff":
+  echo "yay"
diff --git a/tests/overload/tprefer_specialized_generic.nim b/tests/overload/tprefer_specialized_generic.nim
new file mode 100644
index 000000000..2b41502d1
--- /dev/null
+++ b/tests/overload/tprefer_specialized_generic.nim
@@ -0,0 +1,22 @@
+discard """
+  output: '''ref ref T ptr S'''
+"""
+
+proc foo[T](x: T) =
+  echo "only T"
+
+proc foo[T](x: ref T) =
+  echo "ref T"
+
+proc foo[T, S](x: ref ref T; y: ptr S) =
+  echo "ref ref T ptr S"
+
+proc foo[T, S](x: ref T; y: ptr S) =
+  echo "ref T ptr S"
+
+proc foo[T](x: ref T; default = 0) =
+  echo "ref T; default"
+
+var x: ref ref int
+var y: ptr ptr int
+foo(x, y)
diff --git a/tests/overload/tprefer_tygenericinst.nim b/tests/overload/tprefer_tygenericinst.nim
new file mode 100644
index 000000000..9787af06b
--- /dev/null
+++ b/tests/overload/tprefer_tygenericinst.nim
@@ -0,0 +1,42 @@
+discard """
+  output: '''Version 2 was called.
+This has the highest precedence.
+This has the second-highest precedence.
+This has the lowest precedence.'''
+"""
+
+# bug #2220
+when true:
+  type A[T] = object
+  type B = A[int]
+
+  proc q[X](x: X) =
+    echo "Version 1 was called."
+
+  proc q(x: B) =
+    echo "Version 2 was called."
+
+  q(B()) # This call reported as ambiguous.
+
+# bug #2219
+template testPred(a: expr) =
+  block:
+    type A = object of RootObj
+    type B = object of A
+    type SomeA = A|A # A hack to make "A" a typeclass.
+
+    when a >= 3:
+      proc p[X](x: X) =
+        echo "This has the highest precedence."
+    when a >= 2:
+      proc p[X: A](x: X) =
+        echo "This has the second-highest precedence."
+    when a >= 1:
+      proc p[X: SomeA](x: X) =
+        echo "This has the lowest precedence."
+
+    p(B())
+
+testPred(3)
+testPred(2)
+testPred(1)
diff --git a/tests/overload/tspec.nim b/tests/overload/tspec.nim
new file mode 100644
index 000000000..685df503a
--- /dev/null
+++ b/tests/overload/tspec.nim
@@ -0,0 +1,81 @@
+discard """
+  output: '''not a var
+not a var
+a var
+B
+int
+T
+int16
+T
+ref T
+123
+2
+1
+@[123, 2, 1]'''
+"""
+
+# Things that's even in the spec now!
+
+proc byvar(x: var int) = echo "a var"
+proc byvar(x: int) = echo "not a var"
+byvar(89)
+
+let letSym = 0
+var varSym = 13
+
+byvar(letSym)
+byvar(varSym)
+
+type
+  A = object of RootObj
+  B = object of A
+  C = object of B
+
+proc p(obj: A) =
+  echo "A"
+
+proc p(obj: B) =
+  echo "B"
+
+var c = C()
+# not ambiguous, calls 'B', not 'A' since B is a subtype of A
+# but not vice versa:
+p(c)
+
+proc pp(obj: A, obj2: B) = echo "A B"
+proc pp(obj: B, obj2: A) = echo "B A"
+
+# but this is ambiguous:
+#pp(c, c)
+
+proc takesInt(x: int) = echo "int"
+proc takesInt[T](x: T) = echo "T"
+proc takesInt(x: int16) = echo "int16"
+
+takesInt(4) # "int"
+var x: int32
+takesInt(x) # "T"
+var y: int16
+takesInt(y) # "int16"
+var z: range[0..4] = 0
+takesInt(z) # "T"
+
+proc gen[T](x: ref ref T) = echo "ref ref T"
+proc gen[T](x: ref T) = echo "ref T"
+proc gen[T](x: T) = echo "T"
+
+var ri: ref int
+gen(ri) # "ref T"
+
+
+template rem(x: expr) = discard
+#proc rem[T](x: T) = discard
+
+rem unresolvedExpression(undeclaredIdentifier)
+
+
+proc takeV[T](a: varargs[T]) =
+  for x in a: echo x
+
+takeV([123, 2, 1]) # takeV's T is "int", not "array of int"
+echo(@[123, 2, 1])
diff --git a/tests/overload/tstmtoverload.nim b/tests/overload/tstmtoverload.nim
new file mode 100644
index 000000000..f1944b637
--- /dev/null
+++ b/tests/overload/tstmtoverload.nim
@@ -0,0 +1,38 @@
+
+# bug #2481
+import math
+
+template test(loopCount: int, extraI: int, testBody: stmt): stmt =
+  block:
+    for i in 0..loopCount-1:
+      testBody
+    echo "done extraI=", extraI
+
+template test(loopCount: int, extraF: float, testBody: stmt): stmt =
+  block:
+    test(loopCount, round(extraF), testBody)
+
+template test(loopCount: int, testBody: stmt): stmt =
+  block:
+    test(loopCount, 0, testBody)
+    echo "done extraI passed 0"
+
+when isMainModule:
+  var
+    loops = 0
+
+  test 0, 0:
+    loops += 1
+  echo "test 0 complete, loops=", loops
+
+  test 1, 1.0:
+    loops += 1
+  echo "test 1.0 complete, loops=", loops
+
+  when true:
+    # when true we get the following compile time error:
+    #   b.nim(35, 6) Error: expression 'loops += 1' has no type (or is ambiguous)
+    loops = 0
+    test 2:
+      loops += 1
+    echo "test no extra complete, loops=", loops
diff --git a/tests/overload/tsymtabchange_during_or.nim b/tests/overload/tsymtabchange_during_or.nim
new file mode 100644
index 000000000..b5551bcc7
--- /dev/null
+++ b/tests/overload/tsymtabchange_during_or.nim
@@ -0,0 +1,24 @@
+
+# bug #2229
+
+type Type1 = object
+        id: int
+
+type Type2 = object
+    id: int
+
+proc init(self: var Type1, a: int, b: ref Type2) =
+    echo "1"
+
+proc init(self: var Type2, a: int) =
+    echo """
+        Works when this proc commented out
+        Otherwise error:
+        test.nim(14, 4) Error: ambiguous call; both test.init(self: var Type1, a: int, b: ref Type2) and test.init(self: var Type1, a: int, b: ref Type2) match for: (Type1, int literal(1), ref Type2)
+    """
+
+var a: Type1
+init(a, 1, (
+    var b = new(Type2);
+    b
+))
diff --git a/tests/overload/tsystemcmp.nim b/tests/overload/tsystemcmp.nim
index 54dff0c46..68cbf9fa7 100644
--- a/tests/overload/tsystemcmp.nim
+++ b/tests/overload/tsystemcmp.nim
@@ -7,3 +7,16 @@ import algorithm
 # bug #1657
 var modules = @["hi", "ho", "ha", "huu"]
 sort(modules, system.cmp)
+
+type
+  MyType = object
+    x: string
+
+proc cmp(a, b: MyType): int = cmp(a.x, b.x)
+
+var modulesB = @[MyType(x: "ho"), MyType(x: "ha")]
+sort(modulesB, cmp)
+
+# bug #2397
+
+proc f(x: (proc(a,b: string): int) = system.cmp) = discard
diff --git a/tests/parallel/t5000.nim b/tests/parallel/t5000.nim
index 025c327fa..1dd47a61c 100644
--- a/tests/parallel/t5000.nim
+++ b/tests/parallel/t5000.nim
@@ -1,7 +1,10 @@
 discard """
   output: '''50005000'''
+  disabled: "true"
 """
 
+# XXX this seems to deadlock certain Linux machines
+
 import threadpool, strutils
 
 proc foo(x: int): string = $x
diff --git a/tests/parallel/tarray_of_channels.nim b/tests/parallel/tarray_of_channels.nim
new file mode 100644
index 000000000..11b523401
--- /dev/null
+++ b/tests/parallel/tarray_of_channels.nim
@@ -0,0 +1,26 @@
+# bug #2257
+import threadpool
+
+type StringChannel = TChannel[string]
+var channels: array[1..3, StringChannel]
+
+type
+  MyObject[T] = object
+    x: T
+
+var global: MyObject[string]
+var globalB: MyObject[float]
+
+proc consumer(ix : int) {.thread.} =
+  echo channels[ix].recv() ###### not GC-safe: 'channels'
+  echo globalB
+
+proc main =
+  for ix in 1..3: channels[ix].open()
+  for ix in 1..3: spawn consumer(ix)
+  for ix in 1..3: channels[ix].send("test")
+  sync()
+  for ix in 1..3: channels[ix].close()
+
+when isMainModule:
+  main()
diff --git a/tests/parallel/tconvexhull.nim b/tests/parallel/tconvexhull.nim
index d7e4f7716..dffe5339b 100644
--- a/tests/parallel/tconvexhull.nim
+++ b/tests/parallel/tconvexhull.nim
@@ -6,7 +6,7 @@ true
 true
 true'''
 
-ccodeCheck: "!'deepcopy('"
+ccodeCheck: "\\i ! @'deepCopy(' .*"
 """
 
 # parallel convex hull for Nim bigbreak
diff --git a/tests/parallel/tdont_be_stupid.nim b/tests/parallel/tdont_be_stupid.nim
new file mode 100644
index 000000000..a7e82466a
--- /dev/null
+++ b/tests/parallel/tdont_be_stupid.nim
@@ -0,0 +1,15 @@
+
+import threadpool, os
+
+proc single(time: int) =
+  sleep time
+  echo time
+
+proc sleepsort(nums: openArray[int]) =
+  parallel:
+    var i = 0
+    while i <= len(nums) + -1:
+      spawn single(nums[i])
+      i += 1
+
+sleepsort([50,3,40,25])
diff --git a/tests/parallel/tgc_unsafe.nim b/tests/parallel/tgc_unsafe.nim
new file mode 100644
index 000000000..6548bbec8
--- /dev/null
+++ b/tests/parallel/tgc_unsafe.nim
@@ -0,0 +1,32 @@
+discard """
+  errormsg: "'consumer' is not GC-safe"
+  line: 19
+"""
+
+# bug #2257
+import threadpool
+
+type StringChannel = TChannel[string]
+var channels: array[1..3, StringChannel]
+
+type
+  MyObject[T] = object
+    x: T
+
+var global: MyObject[string]
+var globalB: MyObject[float]
+
+proc consumer(ix : int) {.thread.} =
+  echo channels[ix].recv() ###### not GC-safe: 'channels'
+  echo global
+  echo globalB
+
+proc main =
+  for ix in 1..3: channels[ix].open()
+  for ix in 1..3: spawn consumer(ix)
+  for ix in 1..3: channels[ix].send("test")
+  sync()
+  for ix in 1..3: channels[ix].close()
+
+when isMainModule:
+  main()
diff --git a/tests/parallel/tgc_unsafe2.nim b/tests/parallel/tgc_unsafe2.nim
new file mode 100644
index 000000000..ec4605fe9
--- /dev/null
+++ b/tests/parallel/tgc_unsafe2.nim
@@ -0,0 +1,39 @@
+discard """
+  line: 28
+  nimout: '''tgc_unsafe2.nim(22, 5) Warning: 'trick' is not GC-safe as it accesses 'global' which is a global using GC'ed memory
+tgc_unsafe2.nim(26, 5) Warning: 'track' is not GC-safe as it calls 'trick'
+tgc_unsafe2.nim(28, 5) Error: 'consumer' is not GC-safe as it calls 'track'
+'''
+  errormsg: "'consumer' is not GC-safe as it calls 'track'"
+"""
+
+import threadpool
+
+type StringChannel = TChannel[string]
+var channels: array[1..3, StringChannel]
+
+type
+  MyObject[T] = object
+    x: T
+
+var global: MyObject[string]
+var globalB: MyObject[float]
+
+proc trick(ix: int) =
+  echo global.x
+  echo channels[ix].recv()
+
+proc track(ix: int) = trick(ix)
+
+proc consumer(ix: int) {.thread.} =
+  track(ix)
+
+proc main =
+  for ix in 1..3: channels[ix].open()
+  for ix in 1..3: spawn consumer(ix)
+  for ix in 1..3: channels[ix].send("test")
+  sync()
+  for ix in 1..3: channels[ix].close()
+
+when isMainModule:
+  main()
diff --git a/tests/parallel/tmissing_deepcopy.nim b/tests/parallel/tmissing_deepcopy.nim
new file mode 100644
index 000000000..53481e4df
--- /dev/null
+++ b/tests/parallel/tmissing_deepcopy.nim
@@ -0,0 +1,40 @@
+discard """
+  ccodeCheck: "\\i @'deepCopy(' .*"
+"""
+
+# bug #2286
+
+import threadPool
+
+type
+  Person = ref object
+    name: string
+    friend: Person
+
+var
+  people: seq[Person] = @[]
+
+proc newPerson(name:string): Person =
+  result.new()
+  result.name = name
+
+proc greet(p:Person) =
+  p.friend.name &= "-MUT" # this line crashes the program
+  echo "Person {",
+    " name:", p.name, "(", cast[int](addr p.name),"),",
+    " friend:", p.friend.name, "(", cast[int](addr p.friend.name),") }"
+
+proc setup =
+  for i in 0 .. <20:
+    people.add newPerson("Person" & $(i + 1))
+  for i in 0 .. <20:
+    people[i].friend = people[19-i]
+
+proc update =
+  parallel:
+    for i in 0 .. people.high:
+      spawn people[i].greet()
+
+when isMainModule:
+  setup()
+  update()
diff --git a/tests/parallel/treadafterwrite.nim b/tests/parallel/treadafterwrite.nim
new file mode 100644
index 000000000..f59ad5ae0
--- /dev/null
+++ b/tests/parallel/treadafterwrite.nim
@@ -0,0 +1,31 @@
+discard """
+  errormsg: "'foo' not disjoint from 'foo'"
+  line: 23
+  disabled: "true"
+"""
+
+# bug #1597
+
+import strutils, math, threadpool
+
+type
+  BoxedFloat = object
+    value: float
+
+proc term(k: float): ptr BoxedFloat = 
+  var temp = 4 * math.pow(-1, k) / (2*k + 1)
+  result = cast[ptr BoxedFloat](allocShared(sizeof(BoxedFloat)))
+  result.value = temp
+
+proc pi(n: int): float =
+  var ch = newSeq[ptr BoxedFloat](n+1)
+  parallel:
+    for k in 0..ch.high:
+      let foo = (spawn term(float(k)))
+      assert foo != nil
+  for k in 0..ch.high:
+    var temp = ch[k][].value
+    result += temp
+    deallocShared(ch[k])
+
+echo formatFloat(pi(5000))
diff --git a/tests/parallel/tsimple_array_checks.nim b/tests/parallel/tsimple_array_checks.nim
new file mode 100644
index 000000000..9874d3299
--- /dev/null
+++ b/tests/parallel/tsimple_array_checks.nim
@@ -0,0 +1,41 @@
+# bug #2287
+
+import threadPool
+
+# If `nums` is an array instead of seq,
+# NONE of the iteration ways below work (including high / len-1)
+let nums = @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+
+proc log(n:int) =
+  echo n
+
+proc main =
+  parallel:
+    for n in nums: # Error: cannot prove: i <= len(nums) + -1
+      spawn log(n)
+    #for i in 0 .. <nums.len: # Error: cannot prove: i <= len(nums) + -1
+    #for i in 0 .. nums.len-1: # WORKS!
+    #for i in 0 .. <nums.len: # WORKS!
+    #  spawn log(nums[i])
+
+# Array needs explicit size to work, probably related to issue #2287
+#const a: array[0..5, int] = [1,2,3,4,5,6]
+
+#const a = [1,2,3,4,5,6] # Doesn't work
+const a = @[1,2,3,4,5,6] # Doesn't work
+proc f(n: int) = echo "Hello ", n
+
+proc maino =
+  parallel:
+    # while loop doesn't work:
+    var i = 0
+    while i < a.high:
+      #for i in countup(0, a.high-1, 2):
+      spawn f(a[i])
+      spawn f(a[i+1])
+      i += 2
+
+maino() # Doesn't work outside a proc
+
+when isMainModule:
+  main()
diff --git a/tests/parallel/tuseafterdef.nim b/tests/parallel/tuseafterdef.nim
new file mode 100644
index 000000000..95123e886
--- /dev/null
+++ b/tests/parallel/tuseafterdef.nim
@@ -0,0 +1,31 @@
+discard """
+  errormsg: "(k)..(k) not disjoint from (k)..(k)"
+  line: 23
+"""
+
+# bug #1597
+
+import strutils, math, threadpool
+
+type 
+  BoxedFloat = object
+    value: float
+
+proc term(k: float): ptr BoxedFloat = 
+  var temp = 4 * math.pow(-1, k) / (2*k + 1)
+  result = cast[ptr BoxedFloat](allocShared(sizeof(BoxedFloat)))
+  result.value = temp
+
+proc pi(n: int): float =
+  var ch = newSeq[ptr BoxedFloat](n+1)
+  parallel:
+    for k in 0..ch.high:
+      ch[k] = (spawn term(float(k)))
+      assert ch[k] != nil
+  for k in 0..ch.high:
+    var temp = ch[k][].value
+    result += temp
+    deallocShared(ch[k])
+
+
+echo formatFloat(pi(5000))
diff --git a/tests/parallel/twrong_refcounts.nim b/tests/parallel/twrong_refcounts.nim
new file mode 100644
index 000000000..db32a96d8
--- /dev/null
+++ b/tests/parallel/twrong_refcounts.nim
@@ -0,0 +1,53 @@
+discard """
+  output: "Success"
+"""
+
+import math, threadPool
+
+# ---
+
+type
+  Person = object
+    age: int
+    friend: ref Person
+
+var
+  people: seq[ref Person] = @[]
+
+proc newPerson(age:int): ref Person =
+  result.new()
+  result.age = age
+
+proc greet(p:Person) =
+  #echo p.age, ", ", p.friend.age
+  p.friend.age += 1
+
+# ---
+
+proc setup =
+  for i in 0 .. <20:
+    people.add newPerson(i + 1)
+  for i in 0 .. <20:
+    people[i].friend = people[random(20)]
+
+proc update =
+  var countA: array[20, int]
+  var countB: array[20, int]
+
+  for i, p in people:
+    countA[i] = getRefCount(p)
+  parallel:
+    for i in 0 .. people.high:
+      spawn greet(people[i][])
+  for i, p in people:
+    countB[i] = getRefCount(p)
+
+  for i in 0 .. <20:
+    doAssert countA[i] == countB[i]
+  echo "Success"
+
+# ---
+
+when isMainModule:
+  setup()
+  update()
diff --git a/tests/parser/tcommand_as_expr.nim b/tests/parser/tcommand_as_expr.nim
index 22c49ab3f..730e9cbb7 100644
--- a/tests/parser/tcommand_as_expr.nim
+++ b/tests/parser/tcommand_as_expr.nim
@@ -1,7 +1,8 @@
 discard """
   output: '''140
 5-120-120
-359'''
+359
+77'''
 """
 #import math
 
@@ -16,8 +17,10 @@ proc foo(x, y: int): int = x-y
 let x = optarg foo 7.foo
 let y = singlearg foo(1, foo 8)
 let z = singlearg 1.foo foo 8
-    
+
 echo x, y, z
 
 let a = [2,4,8].map do (d:int) -> int: d + 1
-echo a[0], a[1], a[2]
\ No newline at end of file
+echo a[0], a[1], a[2]
+
+echo(foo 8, foo 8)
diff --git a/tests/parser/tinvcolonlocation1.nim b/tests/parser/tinvcolonlocation1.nim
new file mode 100644
index 000000000..cacde48bd
--- /dev/null
+++ b/tests/parser/tinvcolonlocation1.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "tinvcolonlocation1.nim"
+  line: 8
+  column: 3
+  errormsg: "':' expected"
+"""
+try #<- missing ':'
+  echo "try"
+except:
+  echo "except"
+finally:
+  echo "finally"
diff --git a/tests/parser/tinvcolonlocation2.nim b/tests/parser/tinvcolonlocation2.nim
new file mode 100644
index 000000000..2b6a92b9d
--- /dev/null
+++ b/tests/parser/tinvcolonlocation2.nim
@@ -0,0 +1,15 @@
+discard """
+  file: "tinvcolonlocation2.nim"
+  line: 11
+  column: 1
+  errormsg: "':' expected"
+"""
+try:
+  echo "try"
+except #<- missing ':'
+  echo "except"
+finally:
+#<-- error will be here above, at the beginning of finally,
+#    since compiler tries to consome echo and part of except
+#    expression
+  echo "finally"
diff --git a/tests/parser/tinvcolonlocation3.nim b/tests/parser/tinvcolonlocation3.nim
new file mode 100644
index 000000000..2b30b1dbe
--- /dev/null
+++ b/tests/parser/tinvcolonlocation3.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "tinvcolonlocation3.nim"
+  line: 12
+  column: 3
+  errormsg: "':' expected"
+"""
+try:
+  echo "try"
+except:
+  echo "except"
+finally #<- missing ':'
+  echo "finally"
diff --git a/tests/parser/tprecedence.nim b/tests/parser/tprecedence.nim
index 6b1b250a2..d2c6d0b30 100644
--- a/tests/parser/tprecedence.nim
+++ b/tests/parser/tprecedence.nim
@@ -1,11 +1,15 @@
 discard """
-  output: "true"
+  output: '''holla
+true'''
 """
 
+# Test top level semicolon works properly:
+import os; echo "holla"
+
 # Test the new predence rules
 
 proc `\+` (x, y: int): int = result = x + y
 proc `\*` (x, y: int): int = result = x * y
 
-echo 5 \+ 1 \* 9 == 14
+echo 5 \+ 1 \* 9 == 6*9
 
diff --git a/tests/parser/tproctype_pragmas.nim b/tests/parser/tproctype_pragmas.nim
new file mode 100644
index 000000000..8c7acd0cf
--- /dev/null
+++ b/tests/parser/tproctype_pragmas.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''39
+40'''
+"""
+
+# bug 1802
+# Ensure proc pragmas are attached properly:
+
+proc makeStdcall(s: string): (proc(i: int) {.stdcall.}) =
+  (proc (x: int) {.stdcall.} = echo x)
+
+proc makeNimcall(s: string): (proc(i: int)) {.stdcall.} =
+  (proc (x: int) {.nimcall.} = echo x)
+
+let stdc: proc (y: int) {.stdcall.} = makeStdcall("bu")
+let nimc: proc (y: int) {.closure.} = makeNimcall("ba")
+
+stdc(39)
+nimc(40)
diff --git a/tests/parser/tstrongspaces.nim b/tests/parser/tstrongspaces.nim
index 91506daf0..e70b91988 100644
--- a/tests/parser/tstrongspaces.nim
+++ b/tests/parser/tstrongspaces.nim
@@ -2,6 +2,12 @@
 
 discard """
   output: '''35
+true
+true
+4
+true
+1
+false
 77
 (Field0: 1, Field1: 2, Field2: 2)
 ha
@@ -9,11 +15,26 @@ true
 tester args
 all
 all args
+19
+-3
+false
+-2
 '''
 """
 
 echo 2+5 * 5
 
+# Keyword operators
+echo 1 + 16 shl 1 == 1 + (16 shl 1)
+echo 2 and 1  in  {0, 30}
+echo 2+2 * 2 shr 1
+echo false  or  2 and 1  in  {0, 30}
+
+proc `^`(a, b: int): int = a + b div 2
+echo 19 mod 16 ^ 4  +  2 and 1
+echo 18 mod 16 ^ 4 > 0
+
+# echo $foo gotcha
 let foo = 77
 echo $foo
 
@@ -27,7 +48,7 @@ when true:
   let b = 66
   let c = 90
   let bar = 8000
-  if foo+4 * 4 == 8 and b&c | 9  ++
+  if foo+4 * 4 == 8  and  b&c | 9  ++
       bar:
     echo "ho"
   else:
@@ -50,3 +71,13 @@ const
 echo tester & " " & args|"all"
 echo "all"  |  tester & " " & args
 echo "all"|tester & " " & args
+
+# Test arrow like operators. See also tests/macros/tclosuremacro.nim
+proc `+->`(a, b: int): int = a + b*4
+template `===>`(a, b: int): expr = a - b shr 1
+
+echo 3 +-> 2 + 2 and 4
+var arrowed = 3+->2 + 2 and 4  # arrowed = 4
+echo arrowed ===> 15
+echo (2 * 3+->2) == (2*3 +-> 2)
+echo arrowed ===> 2 + 3+->2
diff --git a/tests/parser/ttupleunpack.nim b/tests/parser/ttupleunpack.nim
new file mode 100644
index 000000000..aaa06f9f4
--- /dev/null
+++ b/tests/parser/ttupleunpack.nim
@@ -0,0 +1,35 @@
+discard """
+  file: "ttupleunpack.nim"
+  output: ""
+  exitcode: 0
+"""
+
+proc returnsTuple(): (int, int, int) = (4, 2, 3)
+
+proc main2 =
+  let (x, _, z) = returnsTuple()
+
+proc main() =
+
+  proc foo(): tuple[x, y, z: int] =
+    return (4, 2, 3)
+
+  var (x, _, y) = foo()
+  doAssert x == 4
+  doAssert y == 3
+
+  var (a, _, _) = foo()
+  doAssert a == 4
+
+  var (aa, _, _) = foo()
+  doAssert aa == 4
+
+  iterator bar(): tuple[x, y, z: int] =
+    yield (1,2,3)
+
+  for x, y, _ in bar():
+    doAssert x == 1
+    doAssert y == 2
+
+main()
+main2()
diff --git a/tests/parser/ttypeof.nim b/tests/parser/ttypeof.nim
new file mode 100644
index 000000000..24f98059e
--- /dev/null
+++ b/tests/parser/ttypeof.nim
@@ -0,0 +1,26 @@
+discard """
+  output: '''12
+int
+int
+int'''
+"""
+
+import typetraits
+
+# bug #1805
+
+proc foob(x: int): string = "foo"
+proc barb(x: string): int = 12
+
+echo(foob(10).barb()) # works
+echo(type(10).name()) # doesn't work
+
+echo(name(type(10))) # works
+echo((type(10)).name()) # works
+
+
+# test that 'addr' still works
+proc poo(x, y: ptr int) = discard
+
+var someInt: int
+poo(addr someInt, addr someInt)
diff --git a/tests/parser/twhen_in_enum.nim b/tests/parser/twhen_in_enum.nim
new file mode 100644
index 000000000..d4a3ea56a
--- /dev/null
+++ b/tests/parser/twhen_in_enum.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "identifier expected, but found 'keyword when'"
+"""
+
+# bug #2123
+type num = enum
+    NUM_NONE = 0
+    NUM_ALL = 1
+    when defined(macosx): NUM_OSX = 10 # only this differs for real
+    NUM_XTRA = 20
+
diff --git a/tests/rodfiles/nimrod.cfg b/tests/rodfiles/nim.cfg
index 78fc8db64..78fc8db64 100644
--- a/tests/rodfiles/nimrod.cfg
+++ b/tests/rodfiles/nim.cfg
diff --git a/tests/seq/tsequtils.nim b/tests/seq/tsequtils.nim
index 3a7eeeffa..ea85a7f21 100644
--- a/tests/seq/tsequtils.nim
+++ b/tests/seq/tsequtils.nim
@@ -7,7 +7,7 @@ Filter Iterator: 7
 Filter: [3, 5, 7]
 FilterIt: [1, 3, 7]
 Concat: [1, 3, 5, 7, 2, 4, 6]
-Distnct: [1, 2, 3, 4, 5, 7]'''
+Deduplicate: [1, 2, 3, 4, 5, 7]'''
 
 """
 
diff --git a/tests/showoff/tdrdobbs_examples.nim b/tests/showoff/tdrdobbs_examples.nim
index 13a685950..78f711325 100644
--- a/tests/showoff/tdrdobbs_examples.nim
+++ b/tests/showoff/tdrdobbs_examples.nim
@@ -13,7 +13,7 @@ var g = 70
 ++g
 g ++ 7
 g.`++`(10, 20)
-echo g 
+echo g
 
 
 #let lv = stdin.readline
@@ -56,7 +56,7 @@ type
     fkLit,        ## element is a literal like 0.1
     fkAdd,        ## element is an addition operation
     fkMul,        ## element is a multiplication operation
-    fkExp         ## element is an exponentiation operation 
+    fkExp         ## element is an exponentiation operation
 
 type
   Formula = ref object
@@ -78,16 +78,16 @@ proc evaluate(n: Formula, varToVal: proc (name: string): float): float =
 echo evaluate(Formula(kind: fkLit, value: 0.4), nil)
 
 proc isPolyTerm(n: Formula): bool =
-  n.kind == fkMul and n.left.kind == fkLit and (let e = n.right; 
+  n.kind == fkMul and n.left.kind == fkLit and (let e = n.right;
     e.kind == fkExp and e.left.kind == fkVar and e.right.kind == fkLit)
 
 proc isPolynomial(n: Formula): bool =
-  isPolyTerm(n) or 
+  isPolyTerm(n) or
     (n.kind == fkAdd and isPolynomial(n.left) and isPolynomial(n.right))
 
 let myFormula = Formula(kind: fkMul,
                         left: Formula(kind: fkLit, value: 2.0),
-                        right: Formula(kind: fkExp, 
+                        right: Formula(kind: fkExp,
                           left: Formula(kind: fkVar, name: "x"),
                           right: Formula(kind: fkLit, value: 5.0)))
 
@@ -104,7 +104,7 @@ proc pat2kind(pattern: string): FormulaKind =
 
 import macros
 
-proc matchAgainst(n, pattern: PNimrodNode): PNimrodNode {.compileTime.} =
+proc matchAgainst(n, pattern: NimNode): NimNode {.compileTime.} =
   template `@`(current, field: expr): expr =
     newDotExpr(current, newIdentNode(astToStr(field)))
 
diff --git a/tests/stdlib/tcount.nim b/tests/stdlib/tcount.nim
new file mode 100644
index 000000000..ce1d14b6c
--- /dev/null
+++ b/tests/stdlib/tcount.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''1
+2
+3
+4
+5
+done'''
+"""
+
+# bug #1845, #2224
+
+var arr = [3,2,1,5,4]
+
+# bubble sort
+for i in low(arr)..high(arr):
+  for j in i+1..high(arr): # Error: unhandled exception: value out of range: 5 [RangeError]
+    if arr[i] > arr[j]:
+      let tmp = arr[i]
+      arr[i] = arr[j]
+      arr[j] = tmp
+
+for i in low(arr)..high(arr):
+  echo arr[i]
+
+# check this terminates:
+for x in countdown('\255', '\0'):
+  discard
+
+echo "done"
diff --git a/tests/stdlib/tdialogs.nim b/tests/stdlib/tdialogs.nim
index d161a976d..f0203d319 100644
--- a/tests/stdlib/tdialogs.nim
+++ b/tests/stdlib/tdialogs.nim
@@ -4,7 +4,7 @@ import dialogs, gtk2
 
 gtk2.nimrod_init()
 
-var x = ChooseFilesToOpen(nil)
+var x = chooseFilesToOpen(nil)
 for a in items(x):
   writeln(stdout, a)
 
@@ -12,6 +12,6 @@ info(nil, "start with an info box")
 warning(nil, "now a warning ...")
 error(nil, "... and an error!")
 
-writeln(stdout, ChooseFileToOpen(nil))
-writeln(stdout, ChooseFileToSave(nil))
-writeln(stdout, ChooseDir(nil))
+writeln(stdout, chooseFileToOpen(nil))
+writeln(stdout, chooseFileToSave(nil))
+writeln(stdout, chooseDir(nil))
diff --git a/tests/stdlib/tgetfileinfo.nim b/tests/stdlib/tgetfileinfo.nim
index 49a019061..8a0538a5f 100644
--- a/tests/stdlib/tgetfileinfo.nim
+++ b/tests/stdlib/tgetfileinfo.nim
@@ -32,7 +32,7 @@ proc caseOneAndTwo(followLink: bool) =
   try:
     discard getFileInfo(getAppFilename(), followLink)
     #echo("String : Existing File : Symlink $# : Success" % $followLink)
-  except EOS:
+  except OSError:
     echo("String : Existing File : Symlink $# : Failure" % $followLink)
 
 proc caseThreeAndFour(followLink: bool) =
@@ -40,7 +40,8 @@ proc caseThreeAndFour(followLink: bool) =
   try:
     discard getFileInfo(invalidName, true)
     echo("String : Non-existing File : Symlink $# : Failure" % $followLink)
-  except EOS:
+  except OSError:
+    discard
     #echo("String : Non-existing File : Symlink $# : Success" % $followLink)
 
 proc testGetFileInfo =
@@ -64,13 +65,13 @@ proc testGetFileInfo =
     try:
       discard getFileInfo(testFile)
       #echo("Handle : Valid File : Success")
-    except EIO:
+    except IOError:
       echo("Handle : Valid File : Failure")
 
     try:
       discard getFileInfo(testHandle)
       #echo("Handle : Valid File : Success")
-    except EIO:
+    except IOError:
       echo("Handle : Valid File : Failure")
 
   # Case 6 and 8
@@ -81,13 +82,15 @@ proc testGetFileInfo =
     try:
       discard getFileInfo(testFile)
       echo("Handle : Invalid File : Failure")
-    except EIO, EOS:
+    except IOError, OSError:
+      discard
       #echo("Handle : Invalid File : Success")
 
     try:
       discard getFileInfo(testHandle)
       echo("Handle : Invalid File : Failure")
-    except EIO, EOS:
+    except IOError, OSError:
+      discard
       #echo("Handle : Invalid File : Success")
 
-testGetFileInfo()
\ No newline at end of file
+testGetFileInfo()
diff --git a/tests/stdlib/tircbot.nim b/tests/stdlib/tircbot.nim
deleted file mode 100644
index b91300762..000000000
--- a/tests/stdlib/tircbot.nim
+++ /dev/null
@@ -1,452 +0,0 @@
-import irc, sockets, asyncio, json, os, strutils, times, redis
-
-type
-  TDb* = object
-    r*: TRedis
-    lastPing: float
-
-  TBuildResult* = enum
-    bUnknown, bFail, bSuccess
-
-  TTestResult* = enum
-    tUnknown, tFail, tSuccess
-
-  TEntry* = tuple[c: TCommit, p: seq[TPlatform]]
-  
-  TCommit* = object
-    commitMsg*, username*, hash*: string
-    date*: TTime
-
-  TPlatform* = object
-    buildResult*: TBuildResult
-    testResult*: TTestResult
-    failReason*, platform*: string
-    total*, passed*, skipped*, failed*: biggestInt
-    csources*: bool
-
-const
-  listName = "commits"
-  failOnExisting = False
-
-proc open*(host = "localhost", port: TPort): TDb =
-  result.r = redis.open(host, port)
-  result.lastPing = epochTime()
-
-discard """proc customHSet(database: TDb, name, field, value: string) =
-  if database.r.hSet(name, field, value).int == 0:
-    if failOnExisting:
-      assert(false)
-    else:
-      echo("[Warning:REDIS] ", field, " already exists in ", name)"""
-
-proc updateProperty*(database: TDb, commitHash, platform, property,
-                    value: string) =
-  var name = platform & ":" & commitHash
-  if database.r.hSet(name, property, value).int == 0:
-    echo("[INFO:REDIS] '$1' field updated in hash" % [property])
-  else:
-    echo("[INFO:REDIS] '$1' new field added to hash" % [property])
-
-proc globalProperty*(database: TDb, commitHash, property, value: string) =
-  if database.r.hSet(commitHash, property, value).int == 0:
-    echo("[INFO:REDIS] '$1' field updated in hash" % [property])
-  else:
-    echo("[INFO:REDIS] '$1' new field added to hash" % [property])
-
-proc addCommit*(database: TDb, commitHash, commitMsg, user: string) =
-  # Add the commit hash to the `commits` list.
-  discard database.r.lPush(listName, commitHash)
-  # Add the commit message, current date and username as a property
-  globalProperty(database, commitHash, "commitMsg", commitMsg)
-  globalProperty(database, commitHash, "date", $int(getTime()))
-  globalProperty(database, commitHash, "username", user)
-
-proc keepAlive*(database: var TDb) =
-  ## Keep the connection alive. Ping redis in this case. This functions does
-  ## not guarantee that redis will be pinged.
-  var t = epochTime()
-  if t - database.lastPing >= 60.0:
-    echo("PING -> redis")
-    assert(database.r.ping() == "PONG")
-    database.lastPing = t
-    
-proc getCommits*(database: TDb,
-                 plStr: var seq[string]): seq[TEntry] =
-  result = @[]
-  var commitsRaw = database.r.lrange("commits", 0, -1)
-  for c in items(commitsRaw):
-    var commit: TCommit
-    commit.hash = c
-    for key, value in database.r.hPairs(c):
-      case normalize(key)
-      of "commitmsg": commit.commitMsg = value
-      of "date": commit.date = TTime(parseInt(value))
-      of "username": commit.username = value
-      else:
-        echo(key)
-        assert(false)
-
-    var platformsRaw = database.r.lrange(c & ":platforms", 0, -1)
-    var platforms: seq[TPlatform] = @[]
-    for p in items(platformsRaw):
-      var platform: TPlatform
-      for key, value in database.r.hPairs(p & ":" & c):
-        case normalize(key)
-        of "buildresult":
-          platform.buildResult = parseInt(value).TBuildResult
-        of "testresult":
-          platform.testResult = parseInt(value).TTestResult
-        of "failreason":
-          platform.failReason = value
-        of "total":
-          platform.total = parseBiggestInt(value)
-        of "passed":
-          platform.passed = parseBiggestInt(value)
-        of "skipped":
-          platform.skipped = parseBiggestInt(value)
-        of "failed":
-          platform.failed = parseBiggestInt(value)
-        of "csources":
-          platform.csources = if value == "t": true else: false
-        else:
-          echo(normalize(key))
-          assert(false)
-      
-      platform.platform = p
-      
-      platforms.add(platform)
-      if p notin plStr:
-        plStr.add(p)
-    result.add((commit, platforms))
-
-proc commitExists*(database: TDb, commit: string, starts = false): bool =
-  # TODO: Consider making the 'commits' list a set.
-  for c in items(database.r.lrange("commits", 0, -1)):
-    if starts:
-      if c.startsWith(commit): return true
-    else:
-      if c == commit: return true
-  return false
-
-proc platformExists*(database: TDb, commit: string, platform: string): bool =
-  for p in items(database.r.lrange(commit & ":" & "platforms", 0, -1)):
-    if p == platform: return true
-
-proc expandHash*(database: TDb, commit: string): string =
-  for c in items(database.r.lrange("commits", 0, -1)):
-    if c.startsWith(commit): return c
-  assert false
-
-proc isNewest*(database: TDb, commit: string): bool =
-  return database.r.lIndex("commits", 0) == commit
-
-proc getNewest*(database: TDb): string =
-  return database.r.lIndex("commits", 0)
-
-proc addPlatform*(database: TDb, commit: string, platform: string) =
-  assert database.commitExists(commit)
-  assert (not database.platformExists(commit, platform))
-  var name = platform & ":" & commit
-  if database.r.exists(name):
-    if failOnExisting: quit("[FAIL] " & name & " already exists!", 1)
-    else: echo("[Warning] " & name & " already exists!")
-
-  discard database.r.lPush(commit & ":" & "platforms", platform)
-
-proc `[]`*(p: seq[TPlatform], name: string): TPlatform =
-  for platform in items(p):
-    if platform.platform == name:
-      return platform
-  raise newException(EInvalidValue, name & " platforms not found in commits.")
-  
-proc contains*(p: seq[TPlatform], s: string): bool =
-  for i in items(p):
-    if i.platform == s:
-      return True
-    
-
-type
-  PState = ref TState
-  TState = object of TObject
-    dispatcher: PDispatcher
-    sock: PAsyncSocket
-    ircClient: PAsyncIRC
-    hubPort: TPort
-    database: TDb
-    dbConnected: bool
-
-  TSeenType = enum
-    PSeenJoin, PSeenPart, PSeenMsg, PSeenNick, PSeenQuit
-  
-  TSeen = object
-    nick: string
-    channel: string
-    timestamp: TTime
-    case kind*: TSeenType
-    of PSeenJoin: nil
-    of PSeenPart, PSeenQuit, PSeenMsg:
-      msg: string
-    of PSeenNick:
-      newNick: string
-
-const
-  ircServer = "irc.freenode.net"
-  joinChans = @["#nim"]
-  botNickname = "NimBot"
-
-proc setSeen(d: TDb, s: TSeen) =
-  discard d.r.del("seen:" & s.nick)
-
-  var hashToSet = @[("type", $s.kind.int), ("channel", s.channel),
-                    ("timestamp", $s.timestamp.int)]
-  case s.kind
-  of PSeenJoin: discard
-  of PSeenPart, PSeenMsg, PSeenQuit:
-    hashToSet.add(("msg", s.msg))
-  of PSeenNick:
-    hashToSet.add(("newnick", s.newNick))
-  
-  d.r.hMSet("seen:" & s.nick, hashToSet)
-
-proc getSeen(d: TDb, nick: string, s: var TSeen): bool =
-  if d.r.exists("seen:" & nick):
-    result = true
-    s.nick = nick
-    # Get the type first
-    s.kind = d.r.hGet("seen:" & nick, "type").parseInt.TSeenType
-    
-    for key, value in d.r.hPairs("seen:" & nick):
-      case normalize(key)
-      of "type":
-        #s.kind = value.parseInt.TSeenType
-      of "channel":
-        s.channel = value
-      of "timestamp":
-        s.timestamp = TTime(value.parseInt)
-      of "msg":
-        s.msg = value
-      of "newnick":
-        s.newNick = value
-
-template createSeen(typ: TSeenType, n, c: string): stmt {.immediate, dirty.} =
-  var seenNick: TSeen
-  seenNick.kind = typ
-  seenNick.nick = n
-  seenNick.channel = c
-  seenNick.timestamp = getTime()
-
-proc parseReply(line: string, expect: string): Bool =
-  var jsonDoc = parseJson(line)
-  return jsonDoc["reply"].str == expect
-
-proc limitCommitMsg(m: string): string =
-  ## Limits the message to 300 chars and adds ellipsis.
-  var m1 = m
-  if NewLines in m1:
-    m1 = m1.splitLines()[0]
-  
-  if m1.len >= 300:
-    m1 = m1[0..300]
-
-  if m1.len >= 300 or NewLines in m: m1.add("... ")
-
-  if NewLines in m: m1.add($m.splitLines().len & " more lines")
-
-  return m1
-
-proc handleWebMessage(state: PState, line: string) =
-  echo("Got message from hub: " & line)
-  var json = parseJson(line)
-  if json.hasKey("payload"):
-    for i in 0..min(4, json["payload"]["commits"].len-1):
-      var commit = json["payload"]["commits"][i]
-      # Create the message
-      var message = ""
-      message.add(json["payload"]["repository"]["owner"]["name"].str & "/" &
-                  json["payload"]["repository"]["name"].str & " ")
-      message.add(commit["id"].str[0..6] & " ")
-      message.add(commit["author"]["name"].str & " ")
-      message.add("[+" & $commit["added"].len & " ")
-      message.add("±" & $commit["modified"].len & " ")
-      message.add("-" & $commit["removed"].len & "]: ")
-      message.add(limitCommitMsg(commit["message"].str))
-
-      # Send message to #nim.
-      state.ircClient.privmsg(joinChans[0], message)
-  elif json.hasKey("redisinfo"):
-    assert json["redisinfo"].hasKey("port")
-    #let redisPort = json["redisinfo"]["port"].num
-    state.dbConnected = true
-
-proc hubConnect(state: PState)
-proc handleConnect(s: PAsyncSocket, state: PState) =
-  try:
-    # Send greeting
-    var obj = newJObject()
-    obj["name"] = newJString("irc")
-    obj["platform"] = newJString("?")
-    state.sock.send($obj & "\c\L")
-
-    # Wait for reply.
-    var line = ""
-    sleep(1500)
-    if state.sock.recvLine(line):
-      assert(line != "")
-      doAssert parseReply(line, "OK")
-      echo("The hub accepted me!")
-    else:
-      raise newException(EInvalidValue,
-                         "Hub didn't accept me. Waited 1.5 seconds.")
-    
-    # ask for the redis info
-    var riobj = newJObject()
-    riobj["do"] = newJString("redisinfo")
-    state.sock.send($riobj & "\c\L")
-    
-  except EOS:
-    echo(getCurrentExceptionMsg())
-    s.close()
-    echo("Waiting 5 seconds...")
-    sleep(5000)
-    state.hubConnect()
-
-proc handleRead(s: PAsyncSocket, state: PState) =
-  var line = ""
-  if state.sock.recvLine(line):
-    if line != "":
-      # Handle the message
-      state.handleWebMessage(line)
-    else:
-      echo("Disconnected from hub: ", OSErrorMsg())
-      s.close()
-      echo("Reconnecting...")
-      state.hubConnect()
-  else:
-    echo(OSErrorMsg())
-
-proc hubConnect(state: PState) =
-  state.sock = AsyncSocket()
-  state.sock.connect("127.0.0.1", state.hubPort)
-  state.sock.handleConnect =
-    proc (s: PAsyncSocket) =
-      handleConnect(s, state)
-  state.sock.handleRead =
-    proc (s: PAsyncSocket) =
-      handleRead(s, state)
-
-  state.dispatcher.register(state.sock)
-
-proc handleIrc(irc: PAsyncIRC, event: TIRCEvent, state: PState) =
-  case event.typ
-  of EvConnected: discard
-  of EvDisconnected:
-    while not state.ircClient.isConnected:
-      try:
-        state.ircClient.connect()
-      except:
-        echo("Error reconnecting: ", getCurrentExceptionMsg())
-      
-      echo("Waiting 5 seconds...")
-      sleep(5000)
-    echo("Reconnected successfully!")
-  of EvMsg:
-    echo("< ", event.raw)
-    case event.cmd
-    of MPrivMsg:
-      let msg = event.params[event.params.len-1]
-      let words = msg.split(' ')
-      template pm(msg: string): stmt =
-        state.ircClient.privmsg(event.origin, msg)
-      case words[0]
-      of "!ping": pm("pong")
-      of "!lag":
-        if state.ircClient.getLag != -1.0:
-          var lag = state.ircClient.getLag
-          lag = lag * 1000.0
-          pm($int(lag) & "ms between me and the server.")
-        else:
-          pm("Unknown.")
-      of "!seen":
-        if words.len > 1:
-          let nick = words[1]
-          if nick == botNickname:
-            pm("Yes, I see myself.")
-          echo(nick)
-          var seenInfo: TSeen
-          if state.database.getSeen(nick, seenInfo):
-            #var mSend = ""
-            case seenInfo.kind
-            of PSeenMsg:
-              pm("$1 was last seen on $2 in $3 saying: $4" %
-                    [seenInfo.nick, $seenInfo.timestamp,
-                     seenInfo.channel, seenInfo.msg])
-            of PSeenJoin:
-              pm("$1 was last seen on $2 joining $3" %
-                        [seenInfo.nick, $seenInfo.timestamp, seenInfo.channel])
-            of PSeenPart:
-              pm("$1 was last seen on $2 leaving $3 with message: $4" %
-                        [seenInfo.nick, $seenInfo.timestamp, seenInfo.channel,
-                         seenInfo.msg])
-            of PSeenQuit:
-              pm("$1 was last seen on $2 quitting with message: $3" %
-                        [seenInfo.nick, $seenInfo.timestamp, seenInfo.msg])
-            of PSeenNick:
-              pm("$1 was last seen on $2 changing nick to $3" %
-                        [seenInfo.nick, $seenInfo.timestamp, seenInfo.newNick])
-            
-          else:
-            pm("I have not seen " & nick)
-        else:
-          pm("Syntax: !seen <nick>")
-
-      # TODO: ... commands
-
-      # -- Seen
-      # Log this as activity.
-      createSeen(PSeenMsg, event.nick, event.origin)
-      seenNick.msg = msg
-      state.database.setSeen(seenNick)
-    of MJoin:
-      createSeen(PSeenJoin, event.nick, event.origin)
-      state.database.setSeen(seenNick)
-    of MPart:
-      createSeen(PSeenPart, event.nick, event.origin)
-      let msg = event.params[event.params.high]
-      seenNick.msg = msg
-      state.database.setSeen(seenNick)
-    of MQuit:
-      createSeen(PSeenQuit, event.nick, event.origin)
-      let msg = event.params[event.params.high]
-      seenNick.msg = msg
-      state.database.setSeen(seenNick)
-    of MNick:
-      createSeen(PSeenNick, event.nick, "#nim")
-      seenNick.newNick = event.params[0]
-      state.database.setSeen(seenNick)
-    else:
-      discard # TODO: ?
-
-proc open(port: TPort = TPort(5123)): PState =
-  var res: PState
-  new(res)
-  res.dispatcher = newDispatcher()
-  
-  res.hubPort = port
-  res.hubConnect()
-  let hirc =
-    proc (a: PAsyncIRC, ev: TIRCEvent) =
-      handleIrc(a, ev, res)
-  # Connect to the irc server.
-  res.ircClient = AsyncIrc(ircServer, nick = botNickname, user = botNickname,
-                 joinChans = joinChans, ircEvent = hirc)
-  res.ircClient.connect()
-  res.dispatcher.register(res.ircClient)
-
-  res.dbConnected = false
-  result = res
-
-var state = tircbot.open() # Connect to the website and the IRC server.
-
-while state.dispatcher.poll():
-  if state.dbConnected:
-    state.database.keepAlive()
diff --git a/tests/stdlib/tmarshal.nim b/tests/stdlib/tmarshal.nim
index 5471d347a..a778d2f77 100644
--- a/tests/stdlib/tmarshal.nim
+++ b/tests/stdlib/tmarshal.nim
@@ -1,16 +1,16 @@
 discard """
-  output: ""
+  output: '''{"age": 12, "name": "Cletus"}'''
 """
 
 import marshal
 
-template testit(x: expr) = echo($$to[type(x)]($$x))
+template testit(x: expr) = discard $$to[type(x)]($$x)
 
-var x: array[0..4, array[0..4, string]] = [

-  ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], 

-  ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], 

-  ["test", "1", "2", "3", "4"]]

-testit(x)

+var x: array[0..4, array[0..4, string]] = [
+  ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
+  ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
+  ["test", "1", "2", "3", "4"]]
+testit(x)
 var test2: tuple[name: string, s: int] = ("tuple test", 56)
 testit(test2)
 
@@ -24,7 +24,7 @@ type
     of blah:
       help: string
     else:
-      nil
+      discard
       
   PNode = ref TNode
   TNode = object
@@ -63,3 +63,15 @@ testit(test7)
 var test6: set[char] = {'A'..'Z', '_'}
 testit(test6)
 
+
+# bug #1352
+
+type
+  Entity = object of RootObj
+    name: string
+
+  Person = object of Entity
+    age: int
+
+var instance1 = Person(name: "Cletus", age: 12)
+echo($$instance1)
diff --git a/tests/stdlib/tmath2.nim b/tests/stdlib/tmath2.nim
index 935b08634..88d96c80a 100644
--- a/tests/stdlib/tmath2.nim
+++ b/tests/stdlib/tmath2.nim
@@ -58,7 +58,7 @@ proc TestLoops() =
       break

     break

 

-  while True:

+  while true:

     break

 

 

@@ -73,7 +73,7 @@ proc main() =
     res: int

     s: string

   #write(stdout, mymax(23, 45))

-  write(stdout, "Hallo! Wie heißt du? ")

+  write(stdout, "Hallo! Wie heisst du? ")

   s = readLine(stdin)

   # test the case statement

   case s

diff --git a/tests/stdlib/tmitems.nim b/tests/stdlib/tmitems.nim
new file mode 100644
index 000000000..2c0a0392a
--- /dev/null
+++ b/tests/stdlib/tmitems.nim
@@ -0,0 +1,136 @@
+discard """
+  output: '''@[11, 12, 13]
+@[11, 12, 13]
+@[1, 3, 5]
+@[1, 3, 5]
+gppcbs
+gppcbs
+fpqeew
+fpqeew
+[11, 12, 13]
+[11, 12, 13]
+[11, 12, 13]
+[11, 12, 13]
+{"key1": 11, "key2": 12, "key3": 13}
+[11, 12, 13]
+<Students>
+  <Student Name="Aprilfoo" />
+  <Student Name="bar" />
+</Students>'''
+"""
+
+block:
+  var xs = @[1,2,3]
+  for x in xs.mitems:
+    x += 10
+  echo xs
+
+block:
+  var xs = [1,2,3]
+  for x in xs.mitems:
+    x += 10
+  echo(@xs)
+
+block:
+  var xs = @[1,2,3]
+  for i, x in xs.mpairs:
+    x += i
+  echo xs
+
+block:
+  var xs = [1,2,3]
+  for i, x in xs.mpairs:
+    x += i
+  echo(@xs)
+
+block:
+  var x = "foobar"
+  for c in x.mitems:
+    inc c
+  echo x
+
+block:
+  var x = "foobar"
+  var y = cast[cstring](addr x[0])
+  for c in y.mitems:
+    inc c
+  echo x
+
+block:
+  var x = "foobar"
+  for i, c in x.mpairs:
+    inc c, i
+  echo x
+
+block:
+  var x = "foobar"
+  var y = cast[cstring](addr x[0])
+  for i, c in y.mpairs:
+    inc c, i
+  echo x
+
+import lists
+
+block:
+  var sl = initSinglyLinkedList[int]()
+  sl.prepend(3)
+  sl.prepend(2)
+  sl.prepend(1)
+  for x in sl.mitems:
+    x += 10
+  echo sl
+
+block:
+  var sl = initDoublyLinkedList[int]()
+  sl.append(1)
+  sl.append(2)
+  sl.append(3)
+  for x in sl.mitems:
+    x += 10
+  echo sl
+
+block:
+  var sl = initDoublyLinkedRing[int]()
+  sl.append(1)
+  sl.append(2)
+  sl.append(3)
+  for x in sl.mitems:
+    x += 10
+  echo sl
+
+import queues
+
+block:
+  var q = initQueue[int]()
+  q.add(1)
+  q.add(2)
+  q.add(3)
+  for x in q.mitems:
+    x += 10
+  echo q
+
+import json
+
+block:
+  var j = parseJson """{"key1": 1, "key2": 2, "key3": 3}"""
+  for key,val in j.pairs:
+    val.num += 10
+  echo j
+
+block:
+  var j = parseJson """[1, 2, 3]"""
+  for x in j.mitems:
+    x.num += 10
+  echo j
+
+import xmltree, xmlparser, streams, strtabs
+
+block:
+  var d = parseXml(newStringStream """<Students>
+    <Student Name="April" Gender="F" DateOfBirth="1989-01-02" />
+    <Student Name="Bob" Gender="M"  DateOfBirth="1990-03-04" />
+  </Students>""")
+  for x in d.mitems:
+    x = <>Student(Name=x.attrs["Name"] & "foo")
+  d.mget(1).attrs["Name"] = "bar"
+  echo d
diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim
new file mode 100644
index 000000000..e8ada05e7
--- /dev/null
+++ b/tests/stdlib/tnet.nim
@@ -0,0 +1,47 @@
+import net
+import unittest
+
+suite "isIpAddress tests":
+  test "127.0.0.1 is valid":
+    check isIpAddress("127.0.0.1") == true
+
+  test "ipv6 localhost is valid":
+    check isIpAddress("::1") == true
+
+  test "fqdn is not an ip address":
+    check isIpAddress("example.com") == false
+
+  test "random string is not an ipaddress":
+    check isIpAddress("foo bar") == false
+
+  test "5127.0.0.1 is invalid":
+    check isIpAddress("5127.0.0.1") == false
+
+  test "ipv6 is valid":
+    check isIpAddress("2001:cdba:0000:0000:0000:0000:3257:9652") == true
+
+  test "invalid ipv6":
+    check isIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652") == false
+
+
+suite "parseIpAddress tests":
+  test "127.0.0.1 is valid":
+    discard parseIpAddress("127.0.0.1")
+
+  test "ipv6 localhost is valid":
+    discard parseIpAddress("::1")
+
+  test "fqdn is not an ip address":
+    expect(ValueError):
+      discard parseIpAddress("example.com")
+
+  test "random string is not an ipaddress":
+    expect(ValueError):
+      discard parseIpAddress("foo bar")
+
+  test "ipv6 is valid":
+    discard parseIpAddress("2001:cdba:0000:0000:0000:0000:3257:9652")
+
+  test "invalid ipv6":
+    expect(ValueError):
+      discard parseIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652")
diff --git a/tests/stdlib/tparsefloat.nim b/tests/stdlib/tparsefloat.nim
deleted file mode 100644
index 38ed2db6d..000000000
--- a/tests/stdlib/tparsefloat.nim
+++ /dev/null
@@ -1,3 +0,0 @@
-import strutils
-
-echo ParseFloat("5000") / ParseFloat("10")
diff --git a/tests/stdlib/tpegs.nim b/tests/stdlib/tpegs.nim
index e5353e4ff..cceea1693 100644
--- a/tests/stdlib/tpegs.nim
+++ b/tests/stdlib/tpegs.nim
@@ -397,7 +397,7 @@ proc esc(c: char, reserved = {'\0'..'\255'}): string =
   elif c in reserved: result = '\\' & c
   else: result = $c
   
-proc singleQuoteEsc(c: Char): string = return "'" & esc(c, {'\''}) & "'"
+proc singleQuoteEsc(c: char): string = return "'" & esc(c, {'\''}) & "'"
 
 proc singleQuoteEsc(str: string): string = 
   result = "'"
@@ -421,11 +421,11 @@ proc charSetEscAux(cc: set[char]): string =
       c1 = c2
     inc(c1)
   
-proc CharSetEsc(cc: set[char]): string =
+proc charSetEsc(cc: set[char]): string =
   if card(cc) >= 128+64: 
-    result = "[^" & CharSetEscAux({'\1'..'\xFF'} - cc) & ']'
+    result = "[^" & charSetEscAux({'\1'..'\xFF'} - cc) & ']'
   else: 
-    result = '[' & CharSetEscAux(cc) & ']'
+    result = '[' & charSetEscAux(cc) & ']'
   
 proc toStrAux(r: TPeg, res: var string) = 
   case r.kind
@@ -522,18 +522,18 @@ proc `$` *(r: TPeg): string {.rtl, extern: "npegsToString".} =
 
 type
   TCaptures* {.final.} = object ## contains the captured substrings.
-    matches: array[0..maxSubpatterns-1, tuple[first, last: int]]
+    matches: array[0..MaxSubpatterns-1, tuple[first, last: int]]
     ml: int
     origStart: int
 
 proc bounds*(c: TCaptures, 
-             i: range[0..maxSubpatterns-1]): tuple[first, last: int] = 
+             i: range[0..MaxSubpatterns-1]): tuple[first, last: int] = 
   ## returns the bounds ``[first..last]`` of the `i`'th capture.
   result = c.matches[i]
 
 when not useUnicode:
   type
-    TRune = char
+    Rune = char
   template fastRuneAt(s, i, ch: expr) =
     ch = s[i]
     inc(i)
@@ -563,7 +563,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {.
       result = -1
   of pkLetter: 
     if s[start] != '\0':
-      var a: TRune
+      var a: Rune
       result = start
       fastRuneAt(s, result, a)
       if isAlpha(a): dec(result, start)
@@ -572,7 +572,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {.
       result = -1
   of pkLower: 
     if s[start] != '\0':
-      var a: TRune
+      var a: Rune
       result = start
       fastRuneAt(s, result, a)
       if isLower(a): dec(result, start)
@@ -581,7 +581,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {.
       result = -1
   of pkUpper: 
     if s[start] != '\0':
-      var a: TRune
+      var a: Rune
       result = start
       fastRuneAt(s, result, a)
       if isUpper(a): dec(result, start)
@@ -590,7 +590,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {.
       result = -1
   of pkTitle: 
     if s[start] != '\0':
-      var a: TRune
+      var a: Rune
       result = start
       fastRuneAt(s, result, a)
       if isTitle(a): dec(result, start) 
@@ -599,7 +599,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {.
       result = -1
   of pkWhitespace: 
     if s[start] != '\0':
-      var a: TRune
+      var a: Rune
       result = start
       fastRuneAt(s, result, a)
       if isWhitespace(a): dec(result, start)
@@ -623,7 +623,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {.
   of pkTerminalIgnoreCase:
     var
       i = 0
-      a, b: TRune
+      a, b: Rune
     result = start
     while i < len(p.term):
       fastRuneAt(p.term, i, a)
@@ -635,15 +635,15 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {.
   of pkTerminalIgnoreStyle:
     var
       i = 0
-      a, b: TRune
+      a, b: Rune
     result = start
     while i < len(p.term):
       while true:
         fastRuneAt(p.term, i, a)
-        if a != TRune('_'): break
+        if a != Rune('_'): break
       while true:
         fastRuneAt(s, result, b)
-        if b != TRune('_'): break
+        if b != Rune('_'): break
       if toLower(a) != toLower(b):
         result = -1
         break
@@ -695,7 +695,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {.
     while start+result < s.len:
       var x = rawMatch(s, p.sons[0], start+result, c)
       if x >= 0:
-        if idx < maxSubpatterns:
+        if idx < MaxSubpatterns:
           c.matches[idx] = (start, start+result-1)
         #else: silently ignore the capture
         inc(result, x)
@@ -739,7 +739,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {.
     inc(c.ml)
     result = rawMatch(s, p.sons[0], start, c)
     if result >= 0:
-      if idx < maxSubpatterns:
+      if idx < MaxSubpatterns:
         c.matches[idx] = (start, start+result-1)
       #else: silently ignore the capture
     else:
@@ -836,7 +836,7 @@ iterator findAll*(s: string, pattern: TPeg, start = 0): string =
   while i < s.len:
     var L = matchLen(s, pattern, matches, i)
     if L < 0: break
-    for k in 0..maxSubPatterns-1: 
+    for k in 0..MaxSubPatterns-1: 
       if isNil(matches[k]): break
       yield matches[k]
     inc(i, L)
@@ -865,8 +865,8 @@ template `=~`*(s: string, pattern: TPeg): expr =
   ##   else:
   ##     echo("syntax error")
   ##  
-  when not definedInScope(matches):
-    var matches {.inject.}: array[0..maxSubpatterns-1, string]
+  when not declaredInScope(matches):
+    var matches {.inject.}: array[0..MaxSubpatterns-1, string]
   match(s, pattern, matches)
 
 # ------------------------- more string handling ------------------------------
@@ -907,7 +907,7 @@ proc replacef*(s: string, sub: TPeg, by: string): string {.
   ##   "var1<-keykey; val2<-key2key2"
   result = ""
   var i = 0
-  var caps: array[0..maxSubpatterns-1, string]
+  var caps: array[0..MaxSubpatterns-1, string]
   while i < s.len:
     var x = matchLen(s, sub, caps, i)
     if x <= 0:
@@ -924,7 +924,7 @@ proc replace*(s: string, sub: TPeg, by = ""): string {.
   ## in `by`.
   result = ""
   var i = 0
-  var caps: array[0..maxSubpatterns-1, string]
+  var caps: array[0..MaxSubpatterns-1, string]
   while i < s.len:
     var x = matchLen(s, sub, caps, i)
     if x <= 0:
@@ -942,7 +942,7 @@ proc parallelReplace*(s: string, subs: varargs[
   ## applied in parallel.
   result = ""
   var i = 0
-  var caps: array[0..maxSubpatterns-1, string]
+  var caps: array[0..MaxSubpatterns-1, string]
   while i < s.len:
     block searchSubs:
       for j in 0..high(subs):
@@ -964,7 +964,7 @@ proc transformFile*(infile, outfile: string,
   ## error occurs. This is supposed to be used for quick scripting.
   var x = readFile(infile)
   if not isNil(x):
-    var f: TFile
+    var f: File
     if open(f, outfile, fmWrite):
       write(f, x.parallelReplace(subs))
       close(f)
@@ -1055,7 +1055,7 @@ type
   TPegLexer {.inheritable.} = object          ## the lexer object.
     bufpos: int               ## the current position within the buffer
     buf: cstring              ## the buffer itself
-    LineNumber: int           ## the current line number
+    lineNumber: int           ## the current line number
     lineStart: int            ## index of last line start in buffer
     colOffset: int            ## column to add
     filename: string
@@ -1118,38 +1118,38 @@ proc getEscapedChar(c: var TPegLexer, tok: var TToken) =
   case c.buf[c.bufpos]
   of 'r', 'R', 'c', 'C': 
     add(tok.literal, '\c')
-    Inc(c.bufpos)
+    inc(c.bufpos)
   of 'l', 'L': 
     add(tok.literal, '\L')
-    Inc(c.bufpos)
+    inc(c.bufpos)
   of 'f', 'F': 
     add(tok.literal, '\f')
     inc(c.bufpos)
   of 'e', 'E': 
     add(tok.literal, '\e')
-    Inc(c.bufpos)
+    inc(c.bufpos)
   of 'a', 'A': 
     add(tok.literal, '\a')
-    Inc(c.bufpos)
+    inc(c.bufpos)
   of 'b', 'B': 
     add(tok.literal, '\b')
-    Inc(c.bufpos)
+    inc(c.bufpos)
   of 'v', 'V': 
     add(tok.literal, '\v')
-    Inc(c.bufpos)
+    inc(c.bufpos)
   of 't', 'T': 
     add(tok.literal, '\t')
-    Inc(c.bufpos)
+    inc(c.bufpos)
   of 'x', 'X': 
     inc(c.bufpos)
     var xi = 0
     handleHexChar(c, xi)
     handleHexChar(c, xi)
     if xi == 0: tok.kind = tkInvalid
-    else: add(tok.literal, Chr(xi))
+    else: add(tok.literal, chr(xi))
   of '0'..'9': 
     var val = ord(c.buf[c.bufpos]) - ord('0')
-    Inc(c.bufpos)
+    inc(c.bufpos)
     var i = 1
     while (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}): 
       val = val * 10 + ord(c.buf[c.bufpos]) - ord('0')
@@ -1159,11 +1159,11 @@ proc getEscapedChar(c: var TPegLexer, tok: var TToken) =
     else: tok.kind = tkInvalid
   of '\0'..'\31':
     tok.kind = tkInvalid
-  elif c.buf[c.bufpos] in strutils.letters:
+  elif c.buf[c.bufpos] in strutils.Letters:
     tok.kind = tkInvalid
   else:
     add(tok.literal, c.buf[c.bufpos])
-    Inc(c.bufpos)
+    inc(c.bufpos)
   
 proc skip(c: var TPegLexer) = 
   var pos = c.bufpos
@@ -1171,7 +1171,7 @@ proc skip(c: var TPegLexer) =
   while true: 
     case buf[pos]
     of ' ', '\t': 
-      Inc(pos)
+      inc(pos)
     of '#':
       while not (buf[pos] in {'\c', '\L', '\0'}): inc(pos)
     of '\c':
@@ -1203,7 +1203,7 @@ proc getString(c: var TPegLexer, tok: var TToken) =
       break      
     else:
       add(tok.literal, buf[pos])
-      Inc(pos)
+      inc(pos)
   c.bufpos = pos
   
 proc getDollar(c: var TPegLexer, tok: var TToken) = 
@@ -1244,7 +1244,7 @@ proc getCharSet(c: var TPegLexer, tok: var TToken) =
       break
     else: 
       ch = buf[pos]
-      Inc(pos)
+      inc(pos)
     incl(tok.charset, ch)
     if buf[pos] == '-':
       if buf[pos+1] == ']':
@@ -1264,7 +1264,7 @@ proc getCharSet(c: var TPegLexer, tok: var TToken) =
           break
         else: 
           ch2 = buf[pos]
-          Inc(pos)
+          inc(pos)
         for i in ord(ch)+1 .. ord(ch2):
           incl(tok.charset, chr(i))
   c.bufpos = pos
@@ -1275,7 +1275,7 @@ proc getSymbol(c: var TPegLexer, tok: var TToken) =
   var buf = c.buf
   while true: 
     add(tok.literal, buf[pos])
-    Inc(pos)
+    inc(pos)
     if buf[pos] notin strutils.IdentChars: break
   c.bufpos = pos
   tok.kind = tkIdentifier
@@ -1312,11 +1312,11 @@ proc getTok(c: var TPegLexer, tok: var TToken) =
     getCharset(c, tok)
   of '(':
     tok.kind = tkParLe
-    Inc(c.bufpos)
+    inc(c.bufpos)
     add(tok.literal, '(')
   of ')':
     tok.kind = tkParRi
-    Inc(c.bufpos)
+    inc(c.bufpos)
     add(tok.literal, ')')
   of '.': 
     tok.kind = tkAny
@@ -1404,8 +1404,8 @@ proc arrowIsNextTok(c: TPegLexer): bool =
 # ----------------------------- parser ----------------------------------------
     
 type
-  EInvalidPeg* = object of EInvalidValue ## raised if an invalid
-                                         ## PEG has been detected
+  EInvalidPeg* = object of ValueError ## raised if an invalid
+                                      ## PEG has been detected
   TPegParser = object of TPegLexer ## the PEG parser object
     tok: TToken
     nonterms: seq[PNonTerminal]
diff --git a/tests/stdlib/tpermutations.nim b/tests/stdlib/tpermutations.nim
new file mode 100644
index 000000000..a6e07ded6
--- /dev/null
+++ b/tests/stdlib/tpermutations.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''@[0, 2, 1]
+@[1, 0, 2]
+@[1, 2, 0]
+@[2, 0, 1]
+@[2, 1, 0]
+@[2, 0, 1]
+@[1, 2, 0]
+@[1, 0, 2]
+@[0, 2, 1]
+@[0, 1, 2]'''
+"""
+import algorithm
+
+var v = @[0, 1, 2]
+while v.nextPermutation():
+  echo v
+while v.prevPermutation():
+  echo v
diff --git a/tests/stdlib/treloop.nim b/tests/stdlib/treloop.nim
new file mode 100644
index 000000000..35236708c
--- /dev/null
+++ b/tests/stdlib/treloop.nim
@@ -0,0 +1,9 @@
+discard """
+  output: "@[(, +,  1,  2, )]"
+"""
+
+import re
+
+let str = "(+ 1 2)"
+var tokenRE = re"""[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)"""
+echo str.findAll(tokenRE)
diff --git a/tests/stdlib/tsinglylinkedring.nim b/tests/stdlib/tsinglylinkedring.nim
new file mode 100644
index 000000000..93f0c69cd
--- /dev/null
+++ b/tests/stdlib/tsinglylinkedring.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''[5]
+[4, 5]
+[3, 4, 5]
+[2, 3, 4, 5]
+[2, 3, 4, 5, 6]
+[2, 3, 4, 5, 6, 7]
+[2, 3, 4, 5, 6, 7, 8]
+[1, 2, 3, 4, 5, 6, 7, 8]'''
+"""
+import lists
+
+var r = initSinglyLinkedRing[int]()
+r.prepend(5)
+echo r
+r.prepend(4)
+echo r
+r.prepend(3)
+echo r
+r.prepend(2)
+echo r
+r.append(6)
+echo r
+r.append(7)
+echo r
+r.append(8)
+echo r
+r.prepend(1)
+echo r
diff --git a/tests/stdlib/tsockets.nim b/tests/stdlib/tsockets.nim
deleted file mode 100644
index ff566df74..000000000
--- a/tests/stdlib/tsockets.nim
+++ /dev/null
@@ -1,12 +0,0 @@
-import sockets, os
-var s: TSocket
-s = socket()
-if s == InvalidSocket: osError(osLastError())
-
-s.connect("www.google.com", TPort(80))
-
-var data: string = ""
-s.readLine(data)
-echo(data)
-
-
diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim
index 80c2f3870..3db484faa 100644
--- a/tests/stdlib/tstrutil.nim
+++ b/tests/stdlib/tstrutil.nim
@@ -2,18 +2,18 @@ discard """
   file: "tstrutil.nim"
   output: "ha/home/a1xyz/usr/bin"
 """
-# test the new strutils module

-

-import

-  strutils

-

-proc testStrip() =

-  write(stdout, strip("  ha  "))

-

-proc main() = 

-  testStrip()

-  for p in split("/home/a1:xyz:/usr/bin", {':'}):

-    write(stdout, p)

+# test the new strutils module
+
+import
+  strutils
+
+proc testStrip() =
+  write(stdout, strip("  ha  "))
+
+proc main() = 
+  testStrip()
+  for p in split("/home/a1:xyz:/usr/bin", {':'}):
+    write(stdout, p)
 
 proc testDelete = 
   var s = "0123456789ABCDEFGH"
@@ -25,21 +25,34 @@ proc testDelete =
   assert s == "1236789ABCDEFG"
 
 testDelete()  
-    

+    
 assert(insertSep($1000_000) == "1_000_000")
 assert(insertSep($232) == "232")
 assert(insertSep($12345, ',') == "12,345")
 assert(insertSep($0) == "0")
-

-assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffix") == 0)

-assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffi1") == 1)

-assert(editDistance("prefix__hallo_suffix", "prefix__HALLO_suffix") == 5)

-assert(editDistance("prefix__hallo_suffix", "prefix__ha_suffix") == 3)

-assert(editDistance("prefix__hallo_suffix", "prefix") == 14)

-assert(editDistance("prefix__hallo_suffix", "suffix") == 14)

-assert(editDistance("prefix__hallo_suffix", "prefix__hao_suffix") == 2)

-

-main()

-#OUT ha/home/a1xyz/usr/bin

 
+assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffix") == 0)
+assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffi1") == 1)
+assert(editDistance("prefix__hallo_suffix", "prefix__HALLO_suffix") == 5)
+assert(editDistance("prefix__hallo_suffix", "prefix__ha_suffix") == 3)
+assert(editDistance("prefix__hallo_suffix", "prefix") == 14)
+assert(editDistance("prefix__hallo_suffix", "suffix") == 14)
+assert(editDistance("prefix__hallo_suffix", "prefix__hao_suffix") == 2)
+
+assert "/1/2/3".rfind('/') == 4
+assert "/1/2/3".rfind('/', 1) == 0
+assert "/1/2/3".rfind('0') == -1
+
+assert(toHex(100i16, 32) == "00000000000000000000000000000064")
+assert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C")
+
+assert(' '.repeat(8)== "        ")
+assert(" ".repeat(8) == "        ")
+assert(spaces(8) == "        ")
+
+assert(' '.repeat(0) == "")
+assert(" ".repeat(0) == "")
+assert(spaces(0) == "")
 
+main()
+#OUT ha/home/a1xyz/usr/bin
diff --git a/tests/system/tsettostring.nim b/tests/system/tsettostring.nim
new file mode 100644
index 000000000..c6846ee99
--- /dev/null
+++ b/tests/system/tsettostring.nim
@@ -0,0 +1,8 @@
+discard """
+  output: "{a, b, c}"
+"""
+
+# bug #2395
+
+let alphaSet: set[char] = {'a'..'c'}
+echo alphaSet
diff --git a/tests/table/ttables.nim b/tests/table/ttables.nim
deleted file mode 100644
index de4aaed5e..000000000
--- a/tests/table/ttables.nim
+++ /dev/null
@@ -1,128 +0,0 @@
-discard """
-  output: '''true'''
-"""
-
-import hashes, tables
-
-const
-  data = {
-    "34": 123456, "12": 789,
-    "90": 343, "0": 34404,
-    "1": 344004, "2": 344774,
-    "3": 342244, "4": 3412344,
-    "5": 341232144, "6": 34214544,
-    "7": 3434544, "8": 344544,
-    "9": 34435644, "---00": 346677844,
-    "10": 34484, "11": 34474, "19": 34464,
-    "20": 34454, "30": 34141244, "40": 344114,
-    "50": 344490, "60": 344491, "70": 344492,
-    "80": 344497}
-
-  sorteddata = {
-    "---00": 346677844,
-    "0": 34404,
-    "1": 344004,
-    "10": 34484, 
-    "11": 34474,
-    "12": 789,
-    "19": 34464,
-    "2": 344774, "20": 34454, 
-    "3": 342244, "30": 34141244,
-    "34": 123456,
-    "4": 3412344, "40": 344114,
-    "5": 341232144, "50": 344490, 
-    "6": 34214544, "60": 344491,
-    "7": 3434544, "70": 344492,
-    "8": 344544, "80": 344497,
-    "9": 34435644,
-    "90": 343}
-
-block tableTest1:
-  var t = initTable[tuple[x, y: int], string]()
-  t[(0,0)] = "00"
-  t[(1,0)] = "10"
-  t[(0,1)] = "01"
-  t[(1,1)] = "11"
-  for x in 0..1:
-    for y in 0..1:
-      assert t[(x,y)] == $x & $y
-  assert($t == 
-    "{(x: 0, y: 0): 00, (x: 0, y: 1): 01, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
-
-block tableTest2:
-  var t = initTable[string, float]()
-  t["test"] = 1.2345
-  t["111"] = 1.000043
-  t["123"] = 1.23
-  t.del("111")
-  
-  t["012"] = 67.9
-  t["123"] = 1.5 # test overwriting
-  
-  assert t["123"] == 1.5
-  assert t["111"] == 0.0 # deleted
-  assert(not hasKey(t, "111"))
-  
-  for key, val in items(data): t[key] = val.toFloat
-  for key, val in items(data): assert t[key] == val.toFloat
-  
-
-block orderedTableTest1:
-  var t = initOrderedTable[string, int](2)
-  for key, val in items(data): t[key] = val
-  for key, val in items(data): assert t[key] == val
-  var i = 0
-  # `pairs` needs to yield in insertion order:
-  for key, val in pairs(t):
-    assert key == data[i][0]
-    assert val == data[i][1]
-    inc(i)
-
-  for key, val in mpairs(t): val = 99
-  for val in mvalues(t): assert val == 99
-
-block countTableTest1:
-  var s = data.toTable
-  var t = initCountTable[string]()
-  for k in s.keys: t.inc(k)
-  for k in t.keys: assert t[k] == 1
-  t.inc("90", 3)
-  t.inc("12", 2)
-  t.inc("34", 1)
-  assert t.largest()[0] == "90"
-
-  t.sort()
-  var i = 0
-  for k, v in t.pairs:
-    case i
-    of 0: assert k == "90" and v == 4
-    of 1: assert k == "12" and v == 3
-    of 2: assert k == "34" and v == 2
-    else: break
-    inc i
-
-block SyntaxTest:
-  var x = toTable[int, string]({:})
-
-proc orderedTableSortTest() =
-  var t = initOrderedTable[string, int](2)
-  for key, val in items(data): t[key] = val
-  for key, val in items(data): assert t[key] == val
-  t.sort(proc (x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key))
-  var i = 0
-  # `pairs` needs to yield in sorted order:
-  for key, val in pairs(t):
-    doAssert key == sorteddata[i][0]
-    doAssert val == sorteddata[i][1]
-    inc(i)
-
-  # check that lookup still works:
-  for key, val in pairs(t):
-    doAssert val == t[key]
-  # check that insert still works:
-  t["newKeyHere"] = 80
-
-
-orderedTableSortTest()
-echo "true"
-
diff --git a/tests/template/t2do.nim b/tests/template/t2do.nim
new file mode 100644
index 000000000..b87e3328c
--- /dev/null
+++ b/tests/template/t2do.nim
@@ -0,0 +1,22 @@
+discard """
+  output: "8.0"
+"""
+
+# bug #2057
+
+proc mpf_get_d(x: int): float = float(x)
+proc mpf_cmp_d(a: int; b: float): int = 0
+
+template toFloatHelper(result: expr; tooSmall, tooLarge: stmt) {.immediate.} =
+  result = mpf_get_d(a)
+  if result == 0.0 and mpf_cmp_d(a,0.0) != 0:
+    tooSmall
+  if result == Inf:
+    tooLarge
+
+proc toFloat*(a: int): float =
+  toFloatHelper(result)
+    do: raise newException(ValueError, "number too small"):
+        raise newException(ValueError, "number too large")
+
+echo toFloat(8)
diff --git a/tests/template/t_otemplates.nim b/tests/template/t_otemplates.nim
index 1a9075d20..db535d818 100644
--- a/tests/template/t_otemplates.nim
+++ b/tests/template/t_otemplates.nim
@@ -18,7 +18,7 @@ const identChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
 

 

 # Procedure Declarations

-proc parse_template(node: PNimrodNode, value: string) {.compiletime.}

+proc parse_template(node: NimNode, value: string) {.compiletime.}

 

 

 # Procedure Definitions

@@ -166,7 +166,7 @@ iterator parse_compound_statements(value, identifier: string, index: int): strin
             get_next_ident(["try", "$except", "$finally"])

 

 

-proc parse_complex_stmt(value, identifier: string, index: var int): PNimrodNode {.compiletime.} =

+proc parse_complex_stmt(value, identifier: string, index: var int): NimNode {.compiletime.} =

     ## Parses if/when/try /elif /else /except /finally statements

 

     # Build up complex statement string

@@ -218,7 +218,7 @@ proc parse_complex_stmt(value, identifier: string, index: var int): PNimrodNode
         inc(resultIndex)

 

 

-proc parse_simple_statement(value: string, index: var int): PNimrodNode {.compiletime.} =

+proc parse_simple_statement(value: string, index: var int): NimNode {.compiletime.} =

     ## Parses for/while

 

     # Detect indentation

@@ -252,7 +252,7 @@ proc parse_simple_statement(value: string, index: var int): PNimrodNode {.compil
     inc(index, value.parse_thru_eol(index))

 

 

-proc parse_until_symbol(node: PNimrodNode, value: string, index: var int): bool {.compiletime.} =

+proc parse_until_symbol(node: NimNode, value: string, index: var int): bool {.compiletime.} =

     ## Parses a string until a $ symbol is encountered, if

     ## two $$'s are encountered in a row, a split will happen

     ## removing one of the $'s from the resulting output

@@ -311,7 +311,7 @@ proc parse_until_symbol(node: PNimrodNode, value: string, index: var int): bool
         node.insert insertionPoint, newCall("add", ident("result"), newStrLitNode(splitValue))

 

 

-proc parse_template(node: PNimrodNode, value: string) =

+proc parse_template(node: NimNode, value: string) =

     ## Parses through entire template, outputing valid

     ## Nim code into the input `node` AST.

     var index = 0

diff --git a/tests/template/texponential_eval.nim b/tests/template/texponential_eval.nim
new file mode 100644
index 000000000..32af9e8f7
--- /dev/null
+++ b/tests/template/texponential_eval.nim
@@ -0,0 +1,47 @@
+# bug #1940
+
+discard """
+  nimout: '''===
+merge (A) with (B)
+merge (A B) with (C)
+merge (A B C) with (D)
+merge (A B C D) with (E)
+merge (A B C D E) with (F)
+==='''
+"""
+
+type SqlStmt = tuple
+  sql: string
+  parts: int
+
+proc sql(q: string): SqlStmt =
+  result.sql = q
+  result.parts = 1
+
+template `&%%`(x, y: SqlStmt): SqlStmt =
+  const a = x
+  const b = y
+
+  static:
+    #echo "some merge"
+    echo "merge (", a.sql, ") with (", b.sql, ")"
+
+
+  const newSql = a.sql & " " & b.sql
+  const newParts = a.parts + b.parts
+
+  SqlStmt((sql: newSql, parts: newParts))
+
+static:
+  echo "==="
+
+let c =(sql("A") &%%
+        sql("B")) &%%
+        sql("C")  &%%
+        sql("D") &%%
+        sql("E") &%%
+        sql("F")
+echo c.sql
+
+static:
+  echo "==="
diff --git a/tests/template/tparams_gensymed.nim b/tests/template/tparams_gensymed.nim
new file mode 100644
index 000000000..6c4413866
--- /dev/null
+++ b/tests/template/tparams_gensymed.nim
@@ -0,0 +1,62 @@
+
+# bug #1915
+
+import macros
+
+# Test that parameters are properly gensym'ed finally:
+
+template genNodeKind(kind, name: expr): stmt =
+  proc name*(children: varargs[PNimrodNode]): PNimrodNode {.compiletime.}=
+    result = newNimNode(kind)
+    for c in children:
+      result.add(c)
+
+genNodeKind(nnkNone, None)
+
+
+# Test that generics in templates still work (regression to fix #1915)
+
+# bug #2004
+
+type Something = object
+
+proc testA(x: Something) = discard
+
+template def(name: expr) {.immediate.} =
+  proc testB[T](reallyUniqueName: T) =
+    `test name`(reallyUniqueName)
+def A
+
+var x: Something
+testB(x)
+
+
+# bug #2215
+# Test that templates in generics still work (regression to fix the
+# regression...)
+
+template forStatic(index: expr, slice: Slice[int], predicate: stmt):
+                   stmt {.immediate.} =
+  const a = slice.a
+  const b = slice.b
+  when a <= b:
+    template iteration(i: int) =
+      block:
+        const index = i
+        predicate
+    template iterateStartingFrom(i: int): stmt =
+      when i <= b:
+        iteration i
+        iterateStartingFrom i + 1
+    iterateStartingFrom a
+
+proc concreteProc(x: int) =
+  forStatic i, 0..3:
+    echo i
+
+proc genericProc(x: any) =
+  forStatic i, 0..3:
+    echo i
+
+concreteProc(7) # This works
+genericProc(7)  # This doesn't compile
diff --git a/tests/template/tscope.nim b/tests/template/tscope.nim
new file mode 100644
index 000000000..2d5841af3
--- /dev/null
+++ b/tests/template/tscope.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "redefinition of 'x'"
+"""
+
+var x = 1
+template quantity(): stmt {.immediate.} =
+  # Causes internal error in compiler/sem.nim
+  proc unit*(x = 1.0): float = 12
+  # Throws the correct error: redefinition of 'x'
+  #proc unit*(y = 1.0): float = 12
+quantity()
+var x = 2
diff --git a/tests/template/tstmt_semchecked_twice.nim b/tests/template/tstmt_semchecked_twice.nim
new file mode 100644
index 000000000..05c16c3c9
--- /dev/null
+++ b/tests/template/tstmt_semchecked_twice.nim
@@ -0,0 +1,30 @@
+
+# bug #2585
+
+type
+    RenderPass = object
+       state: ref int
+
+    RenderData* = object
+        fb: int
+        walls: seq[RenderPass]
+
+    Mat2 = int
+    Vector2[T] = T
+    Pixels=int
+
+template use*(fb: int, st: stmt) : stmt =
+    echo "a ", $fb
+    st
+    echo "a ", $fb
+
+proc render(rdat: var RenderData; passes: var openarray[RenderPass]; proj: Mat2;
+            indexType = 1) =
+    for i in 0 .. <len(passes):
+        echo "blah ", repr(passes[i])
+
+
+
+proc render2*(rdat: var RenderData; screenSz: Vector2[Pixels]; proj: Mat2) =
+    use rdat.fb:
+        render(rdat, rdat.walls, proj, 1)
diff --git a/tests/template/ttempl2.nim b/tests/template/ttempl2.nim
index 142bbb8c7..aaa2f1344 100644
--- a/tests/template/ttempl2.nim
+++ b/tests/template/ttempl2.nim
@@ -3,12 +3,12 @@ discard """
   line: 18
   errormsg: "undeclared identifier: \'b\'"
 """
-template declareInScope(x: expr, t: typeDesc): stmt {.immediate.} =
+template declareInScope(x: untyped, t: typeDesc): untyped {.immediate.} =
   var x: t
-  
-template declareInNewScope(x: expr, t: typeDesc): stmt {.immediate.} =
+
+template declareInNewScope(x: untyped, t: typeDesc): untyped {.immediate.} =
   # open a new scope:
-  block: 
+  block:
     var x: t
 
 declareInScope(a, int)
diff --git a/tests/template/twrongmapit.nim b/tests/template/twrongmapit.nim
index 4b3e1553f..bca1292b8 100644
--- a/tests/template/twrongmapit.nim
+++ b/tests/template/twrongmapit.nim
@@ -1,7 +1,7 @@
 discard """
   errormsg: "'"
   file: "sequtils.nim"
-  line: 416
+  line: 435
 """
 # unfortunately our tester doesn't support multiple lines of compiler
 # error messages yet...
diff --git a/tests/template/utemplates.nim b/tests/template/utemplates.nim
index 38ad4f515..8b9ae5d26 100644
--- a/tests/template/utemplates.nim
+++ b/tests/template/utemplates.nim
@@ -12,7 +12,7 @@ test "previous definitions can be further overloaded or hidden in local scopes":
 
   check t(true) == "bool"
   check t(10) == "int"
-  
+
   template t(a: int): expr = "inner int"
   check t(10) == "inner int"
   check t("test") == "string"
@@ -21,12 +21,12 @@ test "templates can be redefined multiple times":
   template customAssert(cond: bool, msg: string): stmt {.immediate, dirty.} =
     if not cond: fail(msg)
 
-  template assertion_failed(body: stmt) {.immediate.} =
+  template assertion_failed(body: stmt) {.immediate, dirty.} =
     template fail(msg: string): stmt = body
 
   assertion_failed: check msg == "first fail path"
   customAssert false, "first fail path"
 
-  assertion_failed: check msg == "second fail path"  
+  assertion_failed: check msg == "second fail path"
   customAssert false, "second fail path"
 
diff --git a/tests/testament/backend.nim b/tests/testament/backend.nim
index c7122e1b2..11743c337 100644
--- a/tests/testament/backend.nim
+++ b/tests/testament/backend.nim
@@ -1,7 +1,7 @@
 #
 #
 #              The Nim Tester
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    Look at license.txt for more info.
 #    All rights reserved.
diff --git a/tests/testament/caasdriver.nim b/tests/testament/caasdriver.nim
index 8f2eec33b..c61a9f108 100644
--- a/tests/testament/caasdriver.nim
+++ b/tests/testament/caasdriver.nim
@@ -1,4 +1,5 @@
 import osproc, streams, os, strutils, re
+{.experimental.}
 
 ## Compiler as a service tester.
 ##
@@ -10,7 +11,7 @@ type
     ProcRun, CaasRun, SymbolProcRun
 
   NimSession* = object
-    nim: PProcess # Holds the open process for CaasRun sessions, nil otherwise.
+    nim: Process # Holds the open process for CaasRun sessions, nil otherwise.
     mode: TRunMode # Stores the type of run mode the session was started with.
     lastOutput: string # Preserves the last output, needed for ProcRun mode.
     filename: string # Appended to each command starting with '>'. Also a var.
@@ -70,8 +71,10 @@ proc doCaasCommand(session: var NimSession, command: string): string =
       break
 
 proc doProcCommand(session: var NimSession, command: string): string =
-  assert session.mode == ProcRun or session.mode == SymbolProcRun
-  except: result = "FAILED TO EXECUTE: " & command & "\n" & result
+  try:
+    assert session.mode == ProcRun or session.mode == SymbolProcRun
+  except:
+    result = "FAILED TO EXECUTE: " & command & "\n" & result
   var
     process = startProcess(NimBin, args = session.replaceVars(command).split)
     stream = outputStream(process)
@@ -102,11 +105,11 @@ proc doCommand(session: var NimSession, command: string) =
     session.lastOutput = doProcCommand(session,
                                        command & " " & session.filename)
 
-proc close(session: var NimSession) {.destructor.} =
+proc destroy(session: var NimSession) {.destructor.} =
   if session.mode == CaasRun:
     session.nim.close
 
-proc doScenario(script: string, output: PStream, mode: TRunMode, verbose: bool): bool =
+proc doScenario(script: string, output: Stream, mode: TRunMode, verbose: bool): bool =
   result = true
 
   var f = open(script)
@@ -171,7 +174,7 @@ when isMainModule:
     failures = 0
     verbose = false
 
-  for i in 0..ParamCount() - 1:
+  for i in 0..paramCount() - 1:
     let param = string(paramStr(i + 1))
     case param
     of "verbose": verbose = true
diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim
index 566a74cab..4476fccf2 100644
--- a/tests/testament/categories.nim
+++ b/tests/testament/categories.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim Tester
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -22,35 +22,35 @@ proc delNimCache() =
     removeDir(nimcacheDir)
   except OSError:
     echo "[Warning] could not delete: ", nimcacheDir
-    
+
 proc runRodFiles(r: var TResults, cat: Category, options: string) =
   template test(filename: expr): stmt =
     testSpec r, makeTest(rodfilesDir / filename, options, cat, actionRun)
-  
+
   delNimCache()
-  
+
   # test basic recompilation scheme:
   test "hallo"
   test "hallo"
   # test incremental type information:
   test "hallo2"
   delNimCache()
-  
+
   # test type converters:
   test "aconv"
   test "bconv"
   delNimCache()
-  
+
   # test G, A, B example from the documentation; test init sections:
   test "deada"
   test "deada2"
   delNimCache()
-  
+
   # test method generation:
   test "bmethods"
   test "bmethods2"
   delNimCache()
-  
+
   # test generics:
   test "tgeneric1"
   test "tgeneric2"
@@ -79,26 +79,26 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) =
     options & " --app:lib -d:createNimRtl", cat)
   testSpec c, makeTest("tests/dll/server.nim",
     options & " --app:lib -d:useNimRtl", cat)
-  
-  when defined(Windows): 
+
+  when defined(Windows):
     # windows looks in the dir of the exe (yay!):
     var nimrtlDll = DynlibFormat % "nimrtl"
     safeCopyFile("lib" / nimrtlDll, "tests/dll" / nimrtlDll)
   else:
     # posix relies on crappy LD_LIBRARY_PATH (ugh!):
-    var libpath = getenv"LD_LIBRARY_PATH".string
-    if peg"\i '/nim' (!'/')* '/lib'" notin libpath:
-      echo "[Warning] insufficient LD_LIBRARY_PATH"
+    var libpath = getEnv"LD_LIBRARY_PATH".string
+    # Temporarily add the lib directory to LD_LIBRARY_PATH:
+    putEnv("LD_LIBRARY_PATH", "lib:" & libpath)
     var serverDll = DynlibFormat % "server"
     safeCopyFile("tests/dll" / serverDll, "lib" / serverDll)
-  
-  testSpec r, makeTest("tests/dll/client.nim", options & " -d:useNimRtl", 
+
+  testSpec r, makeTest("tests/dll/client.nim", options & " -d:useNimRtl",
                        cat, actionRun)
 
 proc dllTests(r: var TResults, cat: Category, options: string) =
   # dummy compile result:
   var c = initResults()
-  
+
   runBasicDLLTest c, r, cat, options
   runBasicDLLTest c, r, cat, options & " -d:release"
   runBasicDLLTest c, r, cat, options & " --gc:boehm"
@@ -107,30 +107,36 @@ proc dllTests(r: var TResults, cat: Category, options: string) =
 # ------------------------------ GC tests -------------------------------------
 
 proc gcTests(r: var TResults, cat: Category, options: string) =
-  template test(filename: expr): stmt =
+  template testWithoutMs(filename: expr): stmt =
     testSpec r, makeTest("tests/gc" / filename, options, cat, actionRun)
     testSpec r, makeTest("tests/gc" / filename, options &
                   " -d:release", cat, actionRun)
     testSpec r, makeTest("tests/gc" / filename, options &
                   " -d:release -d:useRealtimeGC", cat, actionRun)
+
+  template test(filename: expr): stmt =
+    testWithoutMs filename
     testSpec r, makeTest("tests/gc" / filename, options &
                   " --gc:markAndSweep", cat, actionRun)
     testSpec r, makeTest("tests/gc" / filename, options &
                   " -d:release --gc:markAndSweep", cat, actionRun)
-  
+
+  test "growobjcrash"
   test "gcbench"
   test "gcleak"
   test "gcleak2"
   test "gctest"
   test "gcleak3"
   test "gcleak4"
-  test "gcleak5"
+  # Disabled because it works and takes too long to run:
+  #test "gcleak5"
   test "weakrefs"
   test "cycleleak"
   test "closureleak"
-  test "refarrayleak"
+  testWithoutMs "refarrayleak"
+
   test "stackrefleak"
-  
+  test "cyclecollector"
 
 # ------------------------- threading tests -----------------------------------
 
@@ -141,7 +147,7 @@ proc threadTests(r: var TResults, cat: Category, options: string) =
       " -d:release", cat, actionRun)
     testSpec r, makeTest("tests/threads" / filename, options &
       " --tlsEmulation:on", cat, actionRun)
-  
+
   test "tactors"
   test "tactors2"
   test "threadex"
@@ -176,7 +182,7 @@ proc jsTests(r: var TResults, cat: Category, options: string) =
                          actionRun, targetJS)
     testSpec r, makeTest(filename, options & " -d:nodejs -d:release", cat,
                          actionRun, targetJS)
-    
+
   for t in os.walkFiles("tests/js/t*.nim"):
     test(t)
   for testfile in ["exception/texceptions", "exception/texcpt1",
@@ -193,13 +199,13 @@ proc jsTests(r: var TResults, cat: Category, options: string) =
 
 proc findMainFile(dir: string): string =
   # finds the file belonging to ".nim.cfg"; if there is no such file
-  # it returns the some ".nim" file if there is only one: 
+  # it returns the some ".nim" file if there is only one:
   const cfgExt = ".nim.cfg"
   result = ""
   var nimFiles = 0
   for kind, file in os.walkDir(dir):
     if kind == pcFile:
-      if file.endsWith(cfgExt): return file[.. -(cfgExt.len+1)] & ".nim"
+      if file.endsWith(cfgExt): return file[.. ^(cfgExt.len+1)] & ".nim"
       elif file.endsWith(".nim"):
         if result.len == 0: result = file
         inc nimFiles
@@ -209,7 +215,7 @@ proc manyLoc(r: var TResults, cat: Category, options: string) =
   for kind, dir in os.walkDir("tests/manyloc"):
     if kind == pcDir:
       let mainfile = findMainFile(dir)
-      if mainfile != ".nim":
+      if mainfile != "":
         testNoSpec r, makeTest(mainfile, options, cat)
 
 proc compileExample(r: var TResults, pattern, options: string, cat: Category) =
@@ -224,17 +230,17 @@ proc testStdlib(r: var TResults, pattern, options: string, cat: Category) =
     else:
       testNoSpec r, makeTest(test, options, cat, actionCompile)
 
-# ----------------------------- babel ----------------------------------------
+# ----------------------------- nimble ----------------------------------------
 type PackageFilter = enum
   pfCoreOnly
   pfExtraOnly
   pfAll
 
-let 
-  babelExe = findExe("babel")
-  babelDir = getHomeDir() / ".babel"
-  packageDir = babelDir / "pkgs"
-  packageIndex = babelDir / "packages.json"
+let
+  nimbleExe = findExe("nimble")
+  nimbleDir = getHomeDir() / ".nimble"
+  packageDir = nimbleDir / "pkgs"
+  packageIndex = nimbleDir / "packages.json"
 
 proc waitForExitEx(p: Process): int =
   var outp = outputStream(p)
@@ -249,7 +255,7 @@ proc waitForExitEx(p: Process): int =
 
 proc getPackageDir(package: string): string =
   ## TODO - Replace this with dom's version comparison magic.
-  var commandOutput = execCmdEx("babel path $#" % package)
+  var commandOutput = execCmdEx("nimble path $#" % package)
   if commandOutput.exitCode != QuitSuccess:
     return ""
   else:
@@ -262,7 +268,7 @@ iterator listPackages(filter: PackageFilter): tuple[name, url: string] =
     let
       name = package["name"].str
       url = package["url"].str
-      isCorePackage = "nimrod-code" in normalize(url)
+      isCorePackage = "nim-lang" in normalize(url)
     case filter:
     of pfCoreOnly:
       if isCorePackage:
@@ -273,13 +279,13 @@ iterator listPackages(filter: PackageFilter): tuple[name, url: string] =
     of pfAll:
       yield (name, url)
 
-proc testBabelPackages(r: var TResults, cat: Category, filter: PackageFilter) =
-  if babelExe == "":
-    echo("[Warning] - Cannot run babel tests: Babel binary not found.")
+proc testNimblePackages(r: var TResults, cat: Category, filter: PackageFilter) =
+  if nimbleExe == "":
+    echo("[Warning] - Cannot run nimble tests: Nimble binary not found.")
     return
 
-  if execCmd("$# update" % babelExe) == QuitFailure:
-    echo("[Warning] - Cannot run babel tests: Babel update failed.")
+  if execCmd("$# update" % nimbleExe) == QuitFailure:
+    echo("[Warning] - Cannot run nimble tests: Nimble update failed.")
     return
 
   let packageFileTest = makeTest("PackageFileParsed", "", cat)
@@ -288,7 +294,7 @@ proc testBabelPackages(r: var TResults, cat: Category, filter: PackageFilter) =
       var test = makeTest(name, "", cat)
       echo(url)
       let
-        installProcess = startProcess(babelExe, "", ["install", "-y", name])
+        installProcess = startProcess(nimbleExe, "", ["install", "-y", name])
         installStatus = waitForExitEx(installProcess)
       installProcess.close
       if installStatus != QuitSuccess:
@@ -296,9 +302,8 @@ proc testBabelPackages(r: var TResults, cat: Category, filter: PackageFilter) =
         continue
 
       let
-        buildPath = getPackageDir(name)[0.. -3]
-      let
-        buildProcess = startProcess(babelExe, buildPath, ["build"])
+        buildPath = getPackageDir(name).strip
+        buildProcess = startProcess(nimbleExe, buildPath, ["build"])
         buildStatus = waitForExitEx(buildProcess)
       buildProcess.close
       if buildStatus != QuitSuccess:
@@ -306,13 +311,13 @@ proc testBabelPackages(r: var TResults, cat: Category, filter: PackageFilter) =
       r.addResult(test, "", "", reSuccess)
     r.addResult(packageFileTest, "", "", reSuccess)
   except JsonParsingError:
-    echo("[Warning] - Cannot run babel tests: Invalid package file.")
+    echo("[Warning] - Cannot run nimble tests: Invalid package file.")
     r.addResult(packageFileTest, "", "", reBuildFailed)
 
 
 # ----------------------------------------------------------------------------
 
-const AdditionalCategories = ["debugger", "examples", "stdlib", "babel-core"]
+const AdditionalCategories = ["debugger", "examples", "lib"]
 
 proc `&.?`(a, b: string): string =
   # candidate for the stdlib?
@@ -325,8 +330,9 @@ proc `&?.`(a, b: string): string =
 proc processCategory(r: var TResults, cat: Category, options: string) =
   case cat.string.normalize
   of "rodfiles":
-    compileRodFiles(r, cat, options)
-    runRodFiles(r, cat, options)
+    discard # Disabled for now
+    #compileRodFiles(r, cat, options)
+    #runRodFiles(r, cat, options)
   of "js":
     # XXX JS doesn't need to be special anymore
     jsTests(r, cat, options)
@@ -342,19 +348,19 @@ proc processCategory(r: var TResults, cat: Category, options: string) =
     threadTests r, cat, options & " --threads:on"
   of "io":
     ioTests r, cat, options
-  of "stdlib":
+  of "lib":
     testStdlib(r, "lib/pure/*.nim", options, cat)
     testStdlib(r, "lib/packages/docutils/highlite", options, cat)
   of "examples":
     compileExample(r, "examples/*.nim", options, cat)
     compileExample(r, "examples/gtk/*.nim", options, cat)
     compileExample(r, "examples/talk/*.nim", options, cat)
-  of "babel-core":
-    testBabelPackages(r, cat, pfCoreOnly)
-  of "babel-extra":
-    testBabelPackages(r, cat, pfExtraOnly)
-  of "babel-all":
-    testBabelPackages(r, cat, pfAll)
+  of "nimble-core":
+    testNimblePackages(r, cat, pfCoreOnly)
+  of "nimble-extra":
+    testNimblePackages(r, cat, pfExtraOnly)
+  of "nimble-all":
+    testNimblePackages(r, cat, pfAll)
   else:
     for name in os.walkFiles("tests" & DirSep &.? cat.string / "t*.nim"):
       testSpec r, makeTest(name, options, cat)
diff --git a/tests/testament/htmlgen.nim b/tests/testament/htmlgen.nim
index b9eda5383..a9f739995 100644
--- a/tests/testament/htmlgen.nim
+++ b/tests/testament/htmlgen.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim Tester
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -20,7 +20,7 @@ const
                           <td>Success</td></tr>"""
   TableFooter = "</table>"
   HtmlBegin = """<html>
-    <head> 
+    <head>
       <title>Test results</title>
       <style type="text/css">
       <!--""" & slurp("css/boilerplate.css") & "\n" &
@@ -28,13 +28,13 @@ const
       """
 ul#tabs { list-style-type: none; margin: 30px 0 0 0; padding: 0 0 0.3em 0; }
 ul#tabs li { display: inline; }
-ul#tabs li a { color: #42454a; background-color: #dedbde; 
-               border: 1px solid #c9c3ba; border-bottom: none; 
+ul#tabs li a { color: #42454a; background-color: #dedbde;
+               border: 1px solid #c9c3ba; border-bottom: none;
                padding: 0.3em; text-decoration: none; }
 ul#tabs li a:hover { background-color: #f1f0ee; }
-ul#tabs li a.selected { color: #000; background-color: #f1f0ee; 
+ul#tabs li a.selected { color: #000; background-color: #f1f0ee;
                         font-weight: bold; padding: 0.7em 0.3em 0.38em 0.3em; }
-div.tabContent { border: 1px solid #c9c3ba; 
+div.tabContent { border: 1px solid #c9c3ba;
                  padding: 0.5em; background-color: #f1f0ee; }
 div.tabContent.hide { display: none; }
       -->
@@ -43,7 +43,7 @@ div.tabContent.hide { display: none; }
 
     var tabLinks = new Array();
     var contentDivs = new Array();
-    
+
     function init() {
       // Grab the tab links and content divs from the page
       var tabListItems = document.getElementById('tabs').childNodes;
@@ -103,7 +103,7 @@ div.tabContent.hide { display: none; }
 
     </head>
     <body onload="init()">"""
-  
+
   HtmlEnd = "</body></html>"
 
 proc td(s: string): string =
@@ -115,8 +115,8 @@ proc getCommit(db: TDbConn, c: int): string =
     if commit == 0: result = thisCommit[0]
     inc commit
 
-proc generateHtml*(filename: string, commit: int) =
-  const selRow = """select name, category, target, action, 
+proc generateHtml*(filename: string, commit: int; onlyFailing: bool) =
+  const selRow = """select name, category, target, action,
                            expected, given, result
                     from TestResult
                     where [commit] = ? and machine = ?
@@ -140,17 +140,20 @@ proc generateHtml*(filename: string, commit: int) =
   for m in db.rows(sql"select id, name, os, cpu from Machine order by id"):
     outfile.writeln """<li><a href="#$#">$#: $#, $#</a></li>""" % m
   outfile.write("</ul>")
-  
+
   for currentMachine in db.rows(sql"select id from Machine order by id"):
     let m = currentMachine[0]
     outfile.write("""<div class="tabContent" id="$#">""" % m)
 
     outfile.write(TableHeader)
     for row in db.rows(sql(selRow), lastCommit, m):
-      outfile.write("<tr>")
-      for x in row:
-        outfile.write(x.td)
-      outfile.write("</tr>")
+      if onlyFailing and row.len > 0 and row[row.high] == "reSuccess":
+        discard
+      else:
+        outfile.write("<tr>")
+        for x in row:
+          outfile.write(x.td)
+        outfile.write("</tr>")
 
     outfile.write(TableFooter)
     outfile.write("</div>")
@@ -161,7 +164,7 @@ proc generateHtml*(filename: string, commit: int) =
 proc generateJson*(filename: string, commit: int) =
   const
     selRow = """select count(*),
-                           sum(result = 'reSuccess'), 
+                           sum(result = 'reSuccess'),
                            sum(result = 'reIgnored')
                 from TestResult
                 where [commit] = ? and machine = ?
@@ -174,9 +177,9 @@ proc generateJson*(filename: string, commit: int) =
                 on A.name = B.name and A.category = B.category
                 where A.[commit] = ? and B.[commit] = ? and A.machine = ?
                    and A.result != B.result"""
-    selResults = """select 
-                      category || '/' || target || '/' || name, 
-                      category, target, action, result, expected, given 
+    selResults = """select
+                      category || '/' || target || '/' || name,
+                      category, target, action, result, expected, given
                     from TestResult
                     where [commit] = ?"""
   var db = open(connection="testament.db", user="testament", password="",
diff --git a/tests/testament/specs.nim b/tests/testament/specs.nim
index 37fe8cfee..8bf1a4ad7 100644
--- a/tests/testament/specs.nim
+++ b/tests/testament/specs.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim Tester
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -42,12 +42,14 @@ type
     action*: TTestAction
     file*, cmd*: string
     outp*: string
-    line*, exitCode*: int
+    line*, column*: int
+    exitCode*: int
     msg*: string
     ccodeCheck*: string
     err*: TResultEnum
     substr*, sortoutput*: bool
     targets*: set[TTarget]
+    nimout*: string
 
 const
   targetToExt*: array[TTarget, string] = ["c", "cpp", "m", "js"]
@@ -94,8 +96,11 @@ proc parseSpec*(filename: string): TSpec =
   result.file = filename
   result.msg = ""
   result.outp = ""
+  result.nimout = ""
   result.ccodeCheck = ""
   result.cmd = cmdTemplate
+  result.line = 0
+  result.column = 0
   parseSpecAux:
     case normalize(e.key)
     of "action":
@@ -106,6 +111,7 @@ proc parseSpec*(filename: string): TSpec =
       else: echo ignoreMsg(p, e)
     of "file": result.file = e.value
     of "line": discard parseInt(e.value, result.line)
+    of "column": discard parseInt(e.value, result.column)
     of "output": 
       result.action = actionRun
       result.outp = e.value
@@ -124,6 +130,8 @@ proc parseSpec*(filename: string): TSpec =
     of "errormsg":
       result.msg = e.value
       result.action = actionReject
+    of "nimout":
+      result.nimout = e.value
     of "disabled":
       if parseCfgBool(e.value): result.err = reIgnored
     of "cmd": result.cmd = e.value
diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim
index b74fa99c8..ed39109ad 100644
--- a/tests/testament/tester.nim
+++ b/tests/testament/tester.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim Tester
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -12,7 +12,7 @@
 import
   parseutils, strutils, pegs, os, osproc, streams, parsecfg, json,
   marshal, backend, parseopt, specs, htmlgen, browsers, terminal,
-  algorithm
+  algorithm, compiler/nodejs
 
 const
   resultsFile = "testresults.html"
@@ -30,6 +30,7 @@ Arguments:
   arguments are passed to the compiler
 Options:
   --print                   also print results to the console
+  --failing                 only show failing/ignored tests
 """ % resultsFile
 
 type
@@ -48,8 +49,8 @@ type
 # ----------------------------------------------------------------------------
 
 let
-  pegLineError = 
-    peg"{[^(]*} '(' {\d+} ', ' \d+ ') ' ('Error') ':' \s* {.*}"
+  pegLineError =
+    peg"{[^(]*} '(' {\d+} ', ' {\d+} ') ' ('Error') ':' \s* {.*}"
   pegOtherError = peg"'Error:' \s* {.*}"
   pegSuccess = peg"'Hint: operation successful'.*"
   pegOfInterest = pegLineError / pegOtherError
@@ -57,14 +58,16 @@ let
 proc callCompiler(cmdTemplate, filename, options: string,
                   target: TTarget): TSpec =
   let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target],
-                       "options", options, "file", filename])
-  var p = startProcess(command=c[0], args=c[1.. -1],
+                       "options", options, "file", filename.quoteShell])
+  var p = startProcess(command=c[0], args=c[1.. ^1],
                        options={poStdErrToStdOut, poUseShell})
   let outp = p.outputStream
   var suc = ""
   var err = ""
   var x = newStringOfCap(120)
+  result.nimout = ""
   while outp.readLine(x.TaintedString) or running(p):
+    result.nimout.add(x & "\n")
     if x =~ pegOfInterest:
       # `err` should contain the last error/warning message
       err = x
@@ -74,11 +77,13 @@ proc callCompiler(cmdTemplate, filename, options: string,
   result.msg = ""
   result.file = ""
   result.outp = ""
-  result.line = -1
+  result.line = 0
+  result.column = 0
   if err =~ pegLineError:
     result.file = extractFilename(matches[0])
     result.line = parseInt(matches[1])
-    result.msg = matches[2]
+    result.column = parseInt(matches[2])
+    result.msg = matches[3]
   elif err =~ pegOtherError:
     result.msg = matches[0]
   elif suc =~ pegSuccess:
@@ -105,14 +110,16 @@ proc addResult(r: var TResults, test: TTest,
                expected, given: string, success: TResultEnum) =
   let name = test.name.extractFilename & test.options
   backend.writeTestResult(name = name,
-                          category = test.cat.string, 
+                          category = test.cat.string,
                           target = $test.target,
                           action = $test.action,
                           result = $success,
                           expected = expected,
                           given = given)
   r.data.addf("$#\t$#\t$#\t$#", name, expected, given, $success)
-  if success notin {reSuccess, reIgnored}:
+  if success == reIgnored:
+    styledEcho styleBright, name, fgYellow, " [", $success, "]"
+  elif success != reSuccess:
     styledEcho styleBright, name, fgRed, " [", $success, "]"
     echo"Expected:"
     styledEcho styleBright, expected
@@ -125,8 +132,11 @@ proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest) =
   elif extractFilename(expected.file) != extractFilename(given.file) and
       "internal error:" notin expected.msg:
     r.addResult(test, expected.file, given.file, reFilesDiffer)
-  elif expected.line != given.line and expected.line != 0:
-    r.addResult(test, $expected.line, $given.line, reLinesDiffer)
+  elif expected.line   != given.line   and expected.line   != 0 or
+       expected.column != given.column and expected.column != 0:
+    r.addResult(test, $expected.line & ':' & $expected.column,
+                      $given.line    & ':' & $given.column,
+                      reLinesDiffer)
   else:
     r.addResult(test, expected.msg, given.msg, reSuccess)
     inc(r.passed)
@@ -134,28 +144,53 @@ proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest) =
 proc generatedFile(path, name: string, target: TTarget): string =
   let ext = targetToExt[target]
   result = path / "nimcache" /
-    (if target == targetJS: path.splitPath.tail & "_" else: "") &
+    (if target == targetJS: path.splitPath.tail & "_" else: "compiler_") &
     name.changeFileExt(ext)
 
 proc codegenCheck(test: TTest, check: string, given: var TSpec) =
-  if check.len > 0:
-    try:
-      let (path, name, ext2) = test.name.splitFile
-      let genFile = generatedFile(path, name, test.target)
-      echo genFile
-      let contents = readFile(genFile).string
-      if contents.find(check.peg) < 0:
+  try:
+    let (path, name, ext2) = test.name.splitFile
+    let genFile = generatedFile(path, name, test.target)
+    let contents = readFile(genFile).string
+    if check[0] == '\\':
+      # little hack to get 'match' support:
+      if not contents.match(check.peg):
         given.err = reCodegenFailure
-    except ValueError:
-      given.err = reInvalidPeg
-    except IOError:
-      given.err = reCodeNotFound
+    elif contents.find(check.peg) < 0:
+      given.err = reCodegenFailure
+  except ValueError:
+    given.err = reInvalidPeg
+    echo getCurrentExceptionMsg()
+  except IOError:
+    given.err = reCodeNotFound
+
+proc nimoutCheck(test: TTest; expectedNimout: string; given: var TSpec) =
+  let exp = expectedNimout.strip.replace("\C\L", "\L")
+  let giv = given.nimout.strip.replace("\C\L", "\L")
+  if exp notin giv:
+    given.err = reMsgsDiffer
 
 proc makeDeterministic(s: string): string =
   var x = splitLines(s)
   sort(x, system.cmp)
   result = join(x, "\n")
 
+proc compilerOutputTests(test: TTest, given: var TSpec, expected: TSpec;
+                         r: var TResults) =
+  var expectedmsg: string = ""
+  var givenmsg: string = ""
+  if given.err == reSuccess:
+    if expected.ccodeCheck.len > 0:
+      codegenCheck(test, expected.ccodeCheck, given)
+      expectedmsg = expected.ccodeCheck
+      givenmsg = given.msg
+    if expected.nimout.len > 0:
+      expectedmsg = expected.nimout
+      givenmsg = given.nimout.strip
+      nimoutCheck(test, expectedmsg, given)
+  if given.err == reSuccess: inc(r.passed)
+  r.addResult(test, expectedmsg, givenmsg, given.err)
+
 proc testSpec(r: var TResults, test: TTest) =
   # major entry point for a single test
   let tname = test.name.addFileExt(".nim")
@@ -168,12 +203,9 @@ proc testSpec(r: var TResults, test: TTest) =
   else:
     case expected.action
     of actionCompile:
-      var given = callCompiler(expected.cmd, test.name, test.options,
-                               test.target)
-      if given.err == reSuccess:
-        codegenCheck(test, expected.ccodeCheck, given)
-      r.addResult(test, "", given.msg, given.err)
-      if given.err == reSuccess: inc(r.passed)
+      var given = callCompiler(expected.cmd, test.name,
+        test.options & " --hint[Path]:off --hint[Processing]:off", test.target)
+      compilerOutputTests(test, given, expected, r)
     of actionRun:
       var given = callCompiler(expected.cmd, test.name, test.options,
                                test.target)
@@ -187,12 +219,13 @@ proc testSpec(r: var TResults, test: TTest) =
         else:
           exeFile = changeFileExt(tname, ExeExt)
         if existsFile(exeFile):
-          if test.target == targetJS and findExe("nodejs") == "":
+          let nodejs = findNodeJs()
+          if test.target == targetJS and nodejs == "":
             r.addResult(test, expected.outp, "nodejs binary not in PATH",
                         reExeNotFound)
             return
           var (buf, exitCode) = execCmdEx(
-            (if test.target == targetJS: "nodejs " else: "") & exeFile)
+            (if test.target == targetJS: nodejs & " " else: "") & exeFile)
           if exitCode != expected.exitCode:
             r.addResult(test, "exitcode: " & $expected.exitCode,
                               "exitcode: " & $exitCode, reExitCodesDiffer)
@@ -202,10 +235,7 @@ proc testSpec(r: var TResults, test: TTest) =
             if bufB != strip(expected.outp):
               if not (expected.substr and expected.outp in bufB):
                 given.err = reOutputsDiffer
-            if given.err == reSuccess:
-              codeGenCheck(test, expected.ccodeCheck, given)
-            if given.err == reSuccess: inc(r.passed)
-            r.addResult(test, expected.outp, buf.string, given.err)
+            compilerOutputTests(test, given, expected, r)
         else:
           r.addResult(test, expected.outp, "executable not found", reExeNotFound)
     of actionReject:
@@ -241,11 +271,13 @@ proc main() =
 
   backend.open()
   var optPrintResults = false
+  var optFailing = false
   var p = initOptParser()
   p.next()
-  if p.kind == cmdLongoption:
+  while p.kind == cmdLongoption:
     case p.key.string.normalize
     of "print", "verbose": optPrintResults = true
+    of "failing": optFailing = true
     else: quit Usage
     p.next()
   if p.kind != cmdArgument: quit Usage
@@ -257,7 +289,7 @@ proc main() =
     let testsDir = "tests" & DirSep
     for kind, dir in walkDir(testsDir):
       assert testsDir.startsWith(testsDir)
-      let cat = dir[testsDir.len .. -1]
+      let cat = dir[testsDir.len .. ^1]
       if kind == pcDir and cat notin ["testament", "testdata", "nimcache"]:
         processCategory(r, Category(cat), p.cmdLineRest.string)
     for a in AdditionalCategories:
@@ -269,7 +301,7 @@ proc main() =
   of "html":
     var commit = 0
     discard parseInt(p.cmdLineRest.string, commit)
-    generateHtml(resultsFile, commit)
+    generateHtml(resultsFile, commit, optFailing)
     generateJson(jsonFile, commit)
   else:
     quit Usage
diff --git a/tests/testament/tester.nim.cfg b/tests/testament/tester.nim.cfg
new file mode 100644
index 000000000..27fd67075
--- /dev/null
+++ b/tests/testament/tester.nim.cfg
@@ -0,0 +1 @@
+path = "$nim" # For compiler/nodejs
diff --git a/tests/threads/ttryrecv.nim b/tests/threads/ttryrecv.nim
new file mode 100644
index 000000000..acccf182c
--- /dev/null
+++ b/tests/threads/ttryrecv.nim
@@ -0,0 +1,35 @@
+discard """
+  outputsub: "channel is empty"
+"""
+
+# bug #1816
+
+from math import random
+from os import sleep
+
+type PComm = ptr TChannel[int]
+
+proc doAction(outC: PComm) {.thread.} =
+  for i in 0.. <5:
+    sleep(random(100))
+    send(outC[], i)
+
+var
+  thr: TThread[PComm]
+  chan: TChannel[int]
+
+open(chan)
+createThread[PComm](thr, doAction, addr(chan))
+
+while true:
+  let (flag, x) = tryRecv(chan)
+  if flag:
+    echo("received from chan: " & $x)
+  else:
+    echo "channel is empty"
+    break
+
+echo "Finished listening"
+
+joinThread(thr)                                                       
+close(chan)
diff --git a/tests/trmacros/tor.nim b/tests/trmacros/tor.nim
index dc72a96cd..500851582 100644
--- a/tests/trmacros/tor.nim
+++ b/tests/trmacros/tor.nim
@@ -1,5 +1,5 @@
 discard """
-  output: '''3060
+  output: '''3030
 true
 3'''
 """
diff --git a/tests/tuples/tanontuples.nim b/tests/tuples/tanontuples.nim
index a2babf038..49803e5ac 100644
--- a/tests/tuples/tanontuples.nim
+++ b/tests/tuples/tanontuples.nim
@@ -1,5 +1,5 @@
 discard """
-  output: "61, 125"
+  output: '''61, 125'''
 """
 
 proc `^` (a, b: int): int =
@@ -12,4 +12,3 @@ var n = (56, 3)
 m = (n[0] + m[1], m[1] ^ n[1])
 
 echo m[0], ", ", m[1]
-
diff --git a/tests/tuples/tdifferent_instantiations.nim b/tests/tuples/tdifferent_instantiations.nim
new file mode 100644
index 000000000..93b1777b5
--- /dev/null
+++ b/tests/tuples/tdifferent_instantiations.nim
@@ -0,0 +1,9 @@
+# bug #1910
+import tables
+
+var p: OrderedTable[tuple[a:int], int]
+var q: OrderedTable[tuple[x:int], int]
+for key in p.keys:
+  echo key.a
+for key in q.keys:
+  echo key.x
diff --git a/tests/tuples/tgeneric_tuple.nim b/tests/tuples/tgeneric_tuple.nim
new file mode 100644
index 000000000..32f081596
--- /dev/null
+++ b/tests/tuples/tgeneric_tuple.nim
@@ -0,0 +1,9 @@
+# bug #2121
+
+type
+  Item[K,V] = tuple
+    key: K
+    value: V
+
+var q = newseq[Item[int,int]](0)
+let (x,y) = q[0]
diff --git a/tests/tuples/tgeneric_tuple2.nim b/tests/tuples/tgeneric_tuple2.nim
new file mode 100644
index 000000000..c0c292388
--- /dev/null
+++ b/tests/tuples/tgeneric_tuple2.nim
@@ -0,0 +1,17 @@
+
+# bug #2369
+
+type HashedElem[T] = tuple[num: int, storedVal: ref T]
+
+proc append[T](tab: var seq[HashedElem[T]], n: int, val: ref T) =
+    #tab.add((num: n, storedVal: val))
+    var he: HashedElem[T] = (num: n, storedVal: val)
+    #tab.add(he)
+
+var g: seq[HashedElem[int]] = @[]
+
+proc foo() =
+    var x: ref int
+    new(x)
+    x[] = 77
+    g.append(44, x)
diff --git a/tests/tuples/tuint_tuple.nim b/tests/tuples/tuint_tuple.nim
new file mode 100644
index 000000000..24bcead5e
--- /dev/null
+++ b/tests/tuples/tuint_tuple.nim
@@ -0,0 +1,10 @@
+# bug #1986 found by gdmoore
+
+proc test(): int64 =
+  return 0xdeadbeef.int64
+
+const items = [
+  (var1: test(), var2: 100'u32),
+  (var1: test(), var2: 192'u32)
+]
+
diff --git a/tests/typerel/trectuple.nim b/tests/typerel/trectuple.nim
index ebaaa2ea7..334c4a911 100644
--- a/tests/typerel/trectuple.nim
+++ b/tests/typerel/trectuple.nim
@@ -1,6 +1,7 @@
 discard """
   errormsg: "illegal recursion in type 'TNode'"
   line: 8
+  disabled: true
 """
 
 type
diff --git a/tests/typerel/tregionptrs2.nim b/tests/typerel/tregionptrs2.nim
new file mode 100644
index 000000000..3b32ff93d
--- /dev/null
+++ b/tests/typerel/tregionptrs2.nim
@@ -0,0 +1,23 @@
+
+# bug #2039
+
+type
+    RegionTy = object
+    ThingyPtr = RegionTy ptr Thingy
+    Thingy = object
+        next: ThingyPtr
+        name: string
+
+proc iname(t: ThingyPtr) = 
+    var x = t
+
+    while not x.isNil:
+        echo x.name
+        x = x.next
+
+proc go() = 
+    var athing : ThingyPtr
+
+    iname(athing)
+
+go()
diff --git a/tests/typerel/tsymchoice_for_expr.nim b/tests/typerel/tsymchoice_for_expr.nim
new file mode 100644
index 000000000..4c1f52bef
--- /dev/null
+++ b/tests/typerel/tsymchoice_for_expr.nim
@@ -0,0 +1,15 @@
+# bug #1988
+
+template t(e: expr) = discard
+
+proc positive(x: int): int = +x
+proc negative(x: int): int = -x
+proc negative(x: float): float = -x
+
+proc p1 = t(negative)
+proc p2[X] = t(positive)
+proc p3[X] = t(negative)
+
+p1()      # This compiles.
+p2[int]() # This compiles.
+p3[int]() # This raises an error.
diff --git a/tests/typerel/typedescs.nim b/tests/typerel/typedescs.nim
new file mode 100644
index 000000000..23b9ce64f
--- /dev/null
+++ b/tests/typerel/typedescs.nim
@@ -0,0 +1,7 @@
+# bug #1774
+proc p(T: typedesc) = discard
+
+p(type((5, 6)))       # Compiles
+(type((5, 6))).p      # Doesn't compile (SIGSEGV: Illegal storage access.)
+type T = type((5, 6)) # Doesn't compile (SIGSEGV: Illegal storage access.)
+
diff --git a/tests/types/tauto_canbe_void.nim b/tests/types/tauto_canbe_void.nim
new file mode 100644
index 000000000..60e83c510
--- /dev/null
+++ b/tests/types/tauto_canbe_void.nim
@@ -0,0 +1,9 @@
+
+import future
+
+template tempo(s: expr) =
+  s("arg")
+
+tempo((s: string)->auto => echo(s))
+tempo((s: string) => echo(s))
+
diff --git a/tests/types/temptyseqs.nim b/tests/types/temptyseqs.nim
new file mode 100644
index 000000000..2b07ba679
--- /dev/null
+++ b/tests/types/temptyseqs.nim
@@ -0,0 +1,26 @@
+discard """
+  output: "1"
+"""
+
+# bug #1708
+let foo = {
+  "1" : (bar: @["1"]),
+  "2" : (bar: @[])
+}
+
+# bug #871
+
+when true:
+  import os
+
+  type
+    In_out = tuple[src, dest, options: string]
+
+  let
+    nil_var: In_out = ("hey"/"there", "something", nil)
+    #nil_var2 = ("hey"/"there", "something", nil)
+
+# bug #1721
+const foo2: seq[string] = @[]
+
+echo foo[0][0][0]
diff --git a/tests/types/tforwty2.nim b/tests/types/tforwty2.nim
index d103314c5..52af1c7dd 100644
--- a/tests/types/tforwty2.nim
+++ b/tests/types/tforwty2.nim
@@ -1,5 +1,5 @@
 # Test for a hard to fix internal error

-# occured in the SDL library

+# occurred in the SDL library

 

 {.push dynlib: "SDL.dll", callconv: cdecl.}

 

diff --git a/tests/types/tinfiniterecursion.nim b/tests/types/tinfiniterecursion.nim
new file mode 100644
index 000000000..52eaaa93b
--- /dev/null
+++ b/tests/types/tinfiniterecursion.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "illegal recursion in type 'XIM'"
+  line: 8
+"""
+
+type
+  XIM* = ptr XIM
+  XIMProc* = proc (a2: XIM)
diff --git a/tests/types/tisop.nim b/tests/types/tisop.nim
index 509cc4e95..05c6a1a06 100644
--- a/tests/types/tisop.nim
+++ b/tests/types/tisop.nim
@@ -1,3 +1,7 @@
+discard """
+  disabled: true
+"""
+
 import typetraits
 
 type
@@ -35,7 +39,9 @@ proc p(a, b) =
   var f: TFoo[m(a.type), b.type]
   static:
     assert f.x.type.name == "int"
+    echo  f.y.type.name
     assert f.y.type.name == "float"
+    echo  f.z.type.name
     assert f.z.type.name == "float"
 
 p(A, f)
diff --git a/tests/types/tisopr.nim b/tests/types/tisopr.nim
index 3c2b9ee5e..b9acfa5fb 100644
--- a/tests/types/tisopr.nim
+++ b/tests/types/tisopr.nim
@@ -1,5 +1,11 @@
 discard """
-  output: '''true true false yes'''
+  output: '''true true false yes
+false
+false
+false
+true
+true
+no'''
 """
 
 proc IsVoid[T](): string =
@@ -28,9 +34,57 @@ no  s.items is iterator: float
 yes s.items is iterator: TNumber
 no  s.items is iterator: object
 
-type 
+type
   Iter[T] = iterator: T
 
 yes s.items is Iter[TNumber]
 no  s.items is Iter[float]
 
+type
+  Foo[N: static[int], T] = object
+    field: array[1..N, T]
+
+  Bar[T] = Foo[4, T]
+  Baz[N: static[int]] = Foo[N, float]
+
+no Foo[2, float] is Foo[3, float]
+no Foo[2, float] is Foo[2, int]
+
+yes Foo[4, string] is Foo[4, string]
+yes Bar[int] is Foo[4, int]
+yes Foo[4, int] is Bar[int]
+
+no Foo[4, int] is Baz[4]
+yes Foo[4, float] is Baz[4]
+
+
+# bug #2505
+
+echo(8'i8 is int32)
+
+# bug #1853
+type SeqOrSet[E] = seq[E] or set[E]
+type SeqOfInt = seq[int]
+type SeqOrSetOfInt = SeqOrSet[int]
+
+# This prints "false", which seems less correct that (1) printing "true" or (2)
+# raising a compiler error.
+echo seq is SeqOrSet
+
+# This prints "false", as expected.
+echo seq is SeqOrSetOfInt
+
+# This prints "true", as expected.
+echo SeqOfInt is SeqOrSet
+
+# This causes an internal error (filename: compiler/semtypes.nim, line: 685).
+echo SeqOfInt is SeqOrSetOfInt
+
+# bug #2522
+proc test[T](x: T) =
+  when T is typedesc:
+    echo "yes"
+  else:
+    echo "no"
+
+test(7)
diff --git a/tests/usingstmt/tusingstatement.nim b/tests/usingstmt/tusingstatement.nim
index b58478d74..0d76b2423 100644
--- a/tests/usingstmt/tusingstatement.nim
+++ b/tests/usingstmt/tusingstatement.nim
@@ -3,13 +3,13 @@ discard """
   output: "Using test.Closing test."
 """
 
-import 
+import
   macros
 
 # This macro mimics the using statement from C#
 #
 # It's kept only as a test for the macro system
-# Nim's destructors offer a mechanism for automatic 
+# Nim's destructors offer a mechanism for automatic
 # disposal of resources.
 #
 macro autoClose(e: expr): stmt {.immediate.} =
@@ -20,19 +20,19 @@ macro autoClose(e: expr): stmt {.immediate.} =
 
   var args = e
   var body = e[2]
-  
-  var 
-    variables : seq[PNimrodNode]
-    closingCalls : seq[PNimrodNode]
+
+  var
+    variables : seq[NimNode]
+    closingCalls : seq[NimNode]
 
   newSeq(variables, 0)
   newSeq(closingCalls, 0)
-  
+
   for i in countup(1, args.len-2):
     if args[i].kind == nnkExprEqExpr:
       var varName = args[i][0]
       var varValue = args[i][1]
- 
+
       var varAssignment = newNimNode(nnkIdentDefs)
       varAssignment.add(varName)
       varAssignment.add(newNimNode(nnkEmpty)) # empty means no type
@@ -43,7 +43,7 @@ macro autoClose(e: expr): stmt {.immediate.} =
     else:
       error "Using statement: Unexpected expression. Got " &
         $args[i].kind & " instead of assignment."
-  
+
   var varSection = newNimNode(nnkVarSection)
   varSection.add(variables)
 
@@ -67,10 +67,10 @@ macro autoClose(e: expr): stmt {.immediate.} =
   targetAst[0][1][0] = varSection
   targetAst[0][1][1][0] = body
   targetAst[0][1][1][1][0] = finallyBlock
-  
+
   result = targetAst
 
-type 
+type
   TResource* = object
     field*: string
 
diff --git a/tests/vm/tconsteval.nim b/tests/vm/tconsteval.nim
index 96a1bafe8..4459931c5 100644
--- a/tests/vm/tconsteval.nim
+++ b/tests/vm/tconsteval.nim
@@ -24,7 +24,7 @@ Possible Commands:
   csource [options]        builds the C sources for installation
   zip                      builds the installation ZIP package
   inno                     builds the Inno Setup installer
-""" % [NimVersion & repeatChar(44-len(NimVersion)), 
+""" % [NimVersion & spaces(44-len(NimVersion)), 
        CompileDate, CompileTime]
 
 echo HelpText
diff --git a/tests/vm/tconsttable.nim b/tests/vm/tconsttable.nim
new file mode 100644
index 000000000..64a74a59d
--- /dev/null
+++ b/tests/vm/tconsttable.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''is
+finally
+nice!'''
+"""
+
+import tables
+
+const
+  foo = {"ah": "finally", "this": "is", "possible.": "nice!"}.toTable()
+
+# protect against overly smart compiler:
+var x = "this"
+
+echo foo[x]
+x = "ah"
+echo foo[x]
+x = "possible."
+echo foo[x]
diff --git a/tests/vm/tldconst.nim b/tests/vm/tldconst.nim
new file mode 100644
index 000000000..9eabb7525
--- /dev/null
+++ b/tests/vm/tldconst.nim
@@ -0,0 +1,14 @@
+# Passes if it compiles
+# From issue #1946
+
+type
+  Part = object
+    index: int ## array index of argument to be accessed
+
+proc foobar(): int =
+    var x: Part
+    if x.index < high(int):
+        discard
+    0
+
+const x = foobar()
\ No newline at end of file
diff --git a/tests/vm/triangle_array.nim b/tests/vm/triangle_array.nim
new file mode 100644
index 000000000..054c66f22
--- /dev/null
+++ b/tests/vm/triangle_array.nim
@@ -0,0 +1,17 @@
+discard """
+  output: "56"
+"""
+
+# bug #1781
+
+proc initCombinations: array[11, array[11, int]] =
+  result[0]          = [1,2,3,4,5,6,7,8,9,10,11]
+  result[1][1 .. 10] =   [12,13,14,15,16,17,18,19,20,21]
+  result[2][2 .. 10] =     [22,23,24,25,26,27,28,29,30]
+  result[3][3 .. 10] =       [31,32,33,34,35,36,37,38]
+  result[4][4 .. 10] =         [39,40,41,42,43,44,45]
+  result[5][5 .. 10] =           [46,47,48,49,50,51]
+  result[6][6 .. 10] =             [52,53,54,55,56]
+
+const combinations = initCombinations()
+echo combinations[6][10]
diff --git a/tests/vm/tstringnil.nim b/tests/vm/tstringnil.nim
new file mode 100644
index 000000000..bb546b698
--- /dev/null
+++ b/tests/vm/tstringnil.nim
@@ -0,0 +1,50 @@
+# bug #1744
+
+import macros
+
+type
+  SuiteTest = object
+    suiteName: string
+    suiteDesc: string
+    testName: string
+    testDesc: string
+    testBlock: NimNode
+
+proc buildSuiteContents(suiteName, suiteDesc, suiteBloc: NimNode): tuple[tests: seq[SuiteTest]]  {.compileTime.} =
+  var
+    tests:seq[SuiteTest] = @[]
+
+  for child in suiteBloc.children():
+    case $child[0].ident:
+    of "test":
+
+      var testObj = SuiteTest()
+      if suiteName.kind == nnkNilLit:
+        testObj.suiteName = nil
+      else:
+        testObj.suiteName = $suiteName
+      if suiteDesc.kind == nnkNilLit:
+        testObj.suiteDesc = nil
+      else:
+        testObj.suiteDesc = suiteDesc.strVal
+      testObj.testName = $child[1] # should not ever be nil
+      if child[2].kind == nnkNilLit:
+        testObj.testDesc = nil
+      else:
+        testObj.testDesc = child[2].strVal
+      testObj.testBlock = child[1]
+
+      tests.add(testObj)
+
+    else:
+      discard
+
+  return (tests: tests)
+
+macro suite(suiteName, suiteDesc: expr, suiteBloc: stmt): stmt {.immediate.} =
+  let contents = buildSuiteContents(suiteName, suiteDesc, suiteBloc)
+
+# Test above
+suite basics, "Description of such":
+  test(t5, nil):
+    assert false
diff --git a/tinyc/arm-gen.c b/tinyc/arm-gen.c
index 42feecf73..050a8ad88 100644
--- a/tinyc/arm-gen.c
+++ b/tinyc/arm-gen.c
@@ -1506,7 +1506,7 @@ void gen_opf(int op)
 	  case TOK_UGE:
 	  case TOK_ULE:
 	  case TOK_UGT:
-            error("unsigned comparision on floats?");
+            error("unsigned comparison on floats?");
 	    break;
 	  case TOK_LT:
             op=TOK_Nset;
diff --git a/tinyc/c67-gen.c b/tinyc/c67-gen.c
index 04f8a12b7..77c68a279 100644
--- a/tinyc/c67-gen.c
+++ b/tinyc/c67-gen.c
@@ -235,7 +235,7 @@ void gsym(int t)
 }
 
 // these are regs that tcc doesn't really know about, 
-// but asign them unique values so the mapping routines
+// but assign them unique values so the mapping routines
 // can distinquish them
 
 #define C67_A0 105
diff --git a/tinyc/i386-asm.c b/tinyc/i386-asm.c
index 21b28d7a0..12ff8f2ba 100644
--- a/tinyc/i386-asm.c
+++ b/tinyc/i386-asm.c
@@ -1105,7 +1105,7 @@ static void subst_asm_operand(CString *add_str,
     }
 }
 
-/* generate prolog and epilog code for asm statment */
+/* generate prolog and epilog code for asm statement */
 static void asm_gen_code(ASMOperand *operands, int nb_operands, 
                          int nb_outputs, int is_output,
                          uint8_t *clobber_regs,
diff --git a/tinyc/lib/bcheck.c b/tinyc/lib/bcheck.c
index 0ec2a4b47..c59d04eb8 100644
--- a/tinyc/lib/bcheck.c
+++ b/tinyc/lib/bcheck.c
@@ -628,7 +628,7 @@ int __bound_delete_region(void *p)
 }
 
 /* return the size of the region starting at p, or EMPTY_SIZE if non
-   existant region. */
+   existent region. */
 static unsigned long get_region_size(void *p)
 {
     unsigned long addr = (unsigned long)p;
diff --git a/tinyc/tcc-doc.html b/tinyc/tcc-doc.html
index e40532ed0..bd856d256 100644
--- a/tinyc/tcc-doc.html
+++ b/tinyc/tcc-doc.html
@@ -927,7 +927,7 @@ They can be defined several times in the same source. Use 'b'
 </tr></table>
 <h2 class="section"> 4.4 Directives </h2>
 
-<p>All directives are preceeded by a '.'. The following directives are
+<p>All directives are preceded by a '.'. The following directives are
 supported:
 </p>
 <ul class="toc">
@@ -1365,7 +1365,7 @@ reverse order, a first pass is done to reverse the argument order.
 </tr></table>
 <h2 class="section"> 8.4 Types </h2>
 
-<p>The types are stored in a single 'int' variable. It was choosen in the
+<p>The types are stored in a single 'int' variable. It was chosen in the
 first stages of development when tcc was much simpler. Now, it may not
 be the best solution.
 </p>
@@ -1531,7 +1531,7 @@ current position in the code section.
 </dd>
 <dt> <code>stab_section</code></dt>
 <dt> <code>stabstr_section</code></dt>
-<dd><p>are used when debugging is actived to store debug information
+<dd><p>are used when debugging is activated to store debug information
 </p>
 </dd>
 <dt> <code>symtab_section</code></dt>
diff --git a/tinyc/tcc-doc.texi b/tinyc/tcc-doc.texi
index 7cc61bbdb..47a8c8b00 100644
--- a/tinyc/tcc-doc.texi
+++ b/tinyc/tcc-doc.texi
@@ -673,7 +673,7 @@ They can be defined several times in the same source. Use 'b'
 @cindex asciz directive
 @cindex ascii directive
 
-All directives are preceeded by a '.'. The following directives are
+All directives are preceded by a '.'. The following directives are
 supported:
 
 @itemize
@@ -892,7 +892,7 @@ reverse order, a first pass is done to reverse the argument order.
 
 @section Types
 
-The types are stored in a single 'int' variable. It was choosen in the
+The types are stored in a single 'int' variable. It was chosen in the
 first stages of development when tcc was much simpler. Now, it may not
 be the best solution.
 
@@ -1017,7 +1017,7 @@ are used when bound checking is activated
 
 @item stab_section
 @itemx stabstr_section
-are used when debugging is actived to store debug information
+are used when debugging is activated to store debug information
 
 @item symtab_section
 @itemx strtab_section
diff --git a/tinyc/tccasm.c b/tinyc/tccasm.c
index 8834b53fb..9b5289f77 100644
--- a/tinyc/tccasm.c
+++ b/tinyc/tccasm.c
@@ -229,7 +229,7 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
                 } else {
                     goto cannot_relocate;
                 }
-                pe->sym = NULL; /* same symbols can be substracted to NULL */
+                pe->sym = NULL; /* same symbols can be subtracted to NULL */
             } else {
             cannot_relocate:
                 error("invalid operation with label");
diff --git a/tinyc/tccgen.c b/tinyc/tccgen.c
index 3135e7b37..a88f32819 100644
--- a/tinyc/tccgen.c
+++ b/tinyc/tccgen.c
@@ -1203,7 +1203,7 @@ static inline int is_integer_btype(int bt)
             bt == VT_INT || bt == VT_LLONG);
 }
 
-/* check types for comparison or substraction of pointers */
+/* check types for comparison or subtraction of pointers */
 static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op)
 {
     CType *type1, *type2, tmp_type1, tmp_type2;
@@ -4686,7 +4686,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
                 if (sym->type.t & VT_EXTERN) {
                     /* if the variable is extern, it was not allocated */
                     sym->type.t &= ~VT_EXTERN;
-                    /* set array size if it was ommited in extern
+                    /* set array size if it was omitted in extern
                        declaration */
                     if ((sym->type.t & VT_ARRAY) && 
                         sym->type.ref->c < 0 &&
diff --git a/tinyc/tcctok.h b/tinyc/tcctok.h
index 6dc477821..2be032fa4 100644
--- a/tinyc/tcctok.h
+++ b/tinyc/tcctok.h
@@ -422,7 +422,7 @@
  DEF_FP(mul)
 
  DEF_ASM(fcom)
- DEF_ASM(fcom_1) /* non existant op, just to have a regular table */
+ DEF_ASM(fcom_1) /* non existent op, just to have a regular table */
  DEF_FP1(com)
 
  DEF_FP(comp)
diff --git a/tinyc/win32/include/fcntl.h b/tinyc/win32/include/fcntl.h
index 32f4a90e8..d31bc84d5 100644
--- a/tinyc/win32/include/fcntl.h
+++ b/tinyc/win32/include/fcntl.h
@@ -50,7 +50,7 @@
 
 #define	_O_RANDOM	0x0010
 #define	_O_SEQUENTIAL	0x0020
-#define	_O_TEMPORARY	0x0040	/* Make the file dissappear after closing.
+#define	_O_TEMPORARY	0x0040	/* Make the file disappear after closing.
 				 * WARNING: Even if not created by _open! */
 #define	_O_NOINHERIT	0x0080
 
diff --git a/todo.txt b/todo.txt
index 6068c049b..12e82331f 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,14 +1,37 @@
-version 0.10
-============
+version 0.10.4
+==============
 
-  Repetition renders the ridiculous reasonable.
+- make 'nil' work for 'add':
+  - resizeString
+  - incrSeq
+  - addChar
 
-- introduce ``--experimental`` switch
-- c2nim depends on the compiler
+
+version 0.10.6 (RC1?)
+=====================
+
+- make '--implicitStatic:on' the default; then we can also clean up the
+  'static[T]' mess in the compiler!
+- finish 'parallel' or mark as experimental
+- Deprecate ``immediate`` for templates and macros
+- special case varargs[untyped] and varargs[typed]
+
+
+version 1.0
+===========
+
+- macro support for '='; bind '=' to a memory region
+- remove   echo $foo  gotcha
+- add "all threads are blocked" detection to 'spawn'
+- figure out why C++ bootstrapping is so much slower
+- nimsuggest: auto-completion needs to work in 'class' macros
+- The bitwise 'not' operator will be renamed to 'bnot' to
+  prevent 'not 4 == 5' from compiling. -> requires 'mixin' annotation for procs!
+- iterators always require a return type
 - make nimble part of the distribution
-- split idetools into separate tool
 - split docgen into separate tool
-
+- special rule for ``[]=``, items, pairs
+- BUG: echo with template `$`*(info: TLineInfo): expr = toFileLineCol(info)
 
 
 Concurrency
@@ -26,12 +49,9 @@ Low priority:
 Misc
 ----
 
-- make '--implicitStatic:on' the default
 - make tuple unpacking work in a non-var/let context
-- special rule for ``[]=``, items, pairs
 - built-in 'getImpl'
 - prevent 'alloc(TypeWithGCedMemory)'
-- some table related tests are wrong (memory usage checks)
 
 
 Bugs
@@ -40,37 +60,31 @@ Bugs
 - VM: Pegs do not work at compile-time
 - VM: ptr/ref T cannot work in general
 - scopes are still broken for generic instantiation!
-- bug: type conversions concerning proc types are weird
-- compilation of niminst takes way too long. looks like a regression
-- docgen: sometimes effects are listed twice
 - blocks can "export" an identifier but the CCG generates {} for them ...
+- ConcreteTypes in a 'case' means we don't check for duplicated case branches
+- typedesc matches a generic type T!
 
 
 version 0.9.x
 =============
 
-- implicit deref for parameter matching; but only for  x.f(a, b) --> looks like
-  a nice compromise
-- overloading of '='
+- pragmas need 'bindSym' support
 - allow simple read accesses to global variables --> difficult to ensure that
   no data races happen
-- pragmas need 'bindSym' support
 - pragmas need re-work: 'push' is dangerous, 'hasPragma' does not work
   reliably with user-defined pragmas
 - memory manager: add a measure of fragmentation
 - implement 'bits' pragmas
 - we need a magic thisModule symbol
-- ensure (ref T)(a, b) works as a type conversion and type constructor
 - optimize 'genericReset'; 'newException' leads to code bloat
+- The 'do' notation might be trimmed so that its only purpose is to pass
+  multiple multi line constructs to a macro.
 
 
 version 0.9.X
 =============
 
 - macros as type pragmas
-- implement type API for macros
-- lazy overloading resolution:
-  * special case ``tyStmt``
 - document NimMain and check whether it works for threading
 
 GC
@@ -87,4 +101,3 @@ CGEN
 ====
 - codegen should use "NIM_CAST" macro and respect aliasing rules for GCC
 - ``restrict`` pragma + backend support
-- 'const' objects including case objects
diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim
index a38f2a88f..72e4adc07 100644
--- a/tools/nimgrep.nim
+++ b/tools/nimgrep.nim
@@ -24,7 +24,7 @@ Options:
   --re                pattern is a regular expression (default); extended 
                       syntax for the regular expression is always turned on
   --recursive         process directories recursively
-  --confirm           confirm each occurence/replacement; there is a chance 
+  --confirm           confirm each occurrence/replacement; there is a chance 
                       to abort any time without touching the file
   --stdin             read pattern from stdin (to avoid the shell's confusing
                       quoting rules)
@@ -109,7 +109,7 @@ proc highlight(s, match, repl: string, t: tuple[first, last: int],
   for i in t.last+1 .. y: stdout.write(s[i])
   stdout.write("\n")
   if showRepl:
-    stdout.write(repeatChar(alignment-1), "-> ")
+    stdout.write(spaces(alignment-1), "-> ")
     for i in x .. t.first-1: stdout.write(s[i])
     writeColored(repl)
     for i in t.last+1 .. y: stdout.write(s[i])
diff --git a/tools/niminst/buildbat.tmpl b/tools/niminst/buildbat.tmpl
index 415574273..3a11715bf 100644
--- a/tools/niminst/buildbat.tmpl
+++ b/tools/niminst/buildbat.tmpl
@@ -1,5 +1,5 @@
 #! stdtmpl(subsChar='?') | standard
-#proc generateBuildBatchScript(c: TConfigData, winIndex, cpuIndex: int): string = 
+#proc generateBuildBatchScript(c: ConfigData, winIndex, cpuIndex: int): string = 
 #  result = "@echo off\nREM Generated by niminst\n"
 SET CC=gcc
 SET LINKER=gcc
diff --git a/tools/niminst/buildsh.tmpl b/tools/niminst/buildsh.tmpl
index 4966af07a..52da351be 100644
--- a/tools/niminst/buildsh.tmpl
+++ b/tools/niminst/buildsh.tmpl
@@ -1,7 +1,7 @@
 #! stdtmpl(subsChar='?') | standard
-#proc generateBuildShellScript(c: TConfigData): string = 
+#proc generateBuildShellScript(c: ConfigData): string = 
 #  result = "#! /bin/sh\n# Generated from niminst\n" &
-#           "# Template is in tools/buildsh.tmpl\n" &
+#           "# Template is in tools/niminst/buildsh.tmpl\n" &
 #           "# To regenerate run ``niminst csource`` or ``koch csource``\n"
 
 set -e
@@ -54,10 +54,16 @@ case $uos in
     myos="linux" 
     LINK_FLAGS="$LINK_FLAGS -ldl -lm"
     ;;
-  *freebsd* | *dragonfly* ) 
+  *dragonfly* )
     myos="freebsd"
     LINK_FLAGS="$LINK_FLAGS -lm"
     ;;
+  *freebsd* )
+    myos="freebsd"
+    CC="clang"
+    LINKER="clang"
+    LINK_FLAGS="$LINK_FLAGS -lm"
+    ;;
   *openbsd* )
     myos="openbsd" 
     LINK_FLAGS="$LINK_FLAGS -lm"
@@ -105,7 +111,7 @@ case $ucpu in
       LINK_FLAGS="$LINK_FLAGS -m64"
     fi
     mycpu="powerpc64" ;;
-  *power*|*Power*|*ppc* ) 
+  *power*|*ppc* ) 
     mycpu="powerpc" ;;
   *mips* ) 
     mycpu="mips" ;;
diff --git a/tools/niminst/debcreation.nim b/tools/niminst/debcreation.nim
index 574f7ea6b..bbd997981 100644
--- a/tools/niminst/debcreation.nim
+++ b/tools/niminst/debcreation.nim
@@ -84,7 +84,7 @@ proc createCopyright(pkgName, mtnName, mtnEmail, version: string,
     addN("Files: " & f)
     addN("License: " & license)
 
-proc formatDateTime(t: TTimeInfo, timezone: string): string =
+proc formatDateTime(t: TimeInfo, timezone: string): string =
   var day = ($t.weekday)[0..2] & ", "
   
   return "$1$2 $3 $4 $5:$6:$7 $8" % [day, intToStr(t.monthday, 2),
diff --git a/tools/niminst/deinstall.tmpl b/tools/niminst/deinstall.tmpl
index 15f912af6..c4717a257 100644
--- a/tools/niminst/deinstall.tmpl
+++ b/tools/niminst/deinstall.tmpl
@@ -1,5 +1,5 @@
 #! stdtmpl(subsChar='?') | standard
-#proc generateDeinstallScript(c: TConfigData): string = 
+#proc generateDeinstallScript(c: ConfigData): string = 
 #  result = "#! /bin/sh\n# Generated by niminst\n"
 #  var proj = c.name.toLower
 
diff --git a/tools/niminst/inno.tmpl b/tools/niminst/inno.tmpl
index 3460c22a2..4acf0557c 100644
--- a/tools/niminst/inno.tmpl
+++ b/tools/niminst/inno.tmpl
@@ -1,5 +1,5 @@
 #! stdtmpl | standard
-#proc generateInnoSetup(c: TConfigData): string =
+#proc generateInnoSetup(c: ConfigData): string =
 #  result = ""
 ; Default Template for NimInst
 [Setup]
@@ -19,7 +19,7 @@ ChangesEnvironment=yes
 Name: english; MessagesFile: compiler:Default.isl
 
 [Files] 
-  #for i in low(TFileCategory)..fcWindows:
+  #for i in low(FileCategory)..fcWindows:
   #  for f in items(c.cat[i]):
 Source: ${expandFilename(f).toWin}; DestDir: {app}\${splitFile(f).dir.toWin}; Flags: ignoreversion
   #  end for
diff --git a/tools/niminst/install.tmpl b/tools/niminst/install.tmpl
index 437e13dfb..3ec42c287 100644
--- a/tools/niminst/install.tmpl
+++ b/tools/niminst/install.tmpl
@@ -1,5 +1,5 @@
 #! stdtmpl(subsChar = '?') | standard
-#proc generateInstallScript(c: TConfigData): string = 
+#proc generateInstallScript(c: ConfigData): string = 
 #  result = "#! /bin/sh\n# Generated by niminst\n"
 #  var proj = c.name.toLower
 
diff --git a/tools/niminst/makefile.tmpl b/tools/niminst/makefile.tmpl
new file mode 100644
index 000000000..8ab3b89d1
--- /dev/null
+++ b/tools/niminst/makefile.tmpl
@@ -0,0 +1,168 @@
+#! stdtmpl(subsChar='?') | standard
+#proc generateMakefile(c: ConfigData): string = 
+#  result = "# Generated from niminst\n" &
+#           "# Template is in tools/niminst/makefile.tmpl\n" &
+#           "# To regenerate run ``niminst csource`` or ``koch csource``\n"
+
+CC = gcc
+LINKER = gcc
+COMP_FLAGS = ?{c.ccompiler.flags}
+LINK_FLAGS = ?{c.linker.flags}
+binDir = ?{firstBinPath(c).toUnix}
+
+koch := $(shell sh -c 'test -s ../koch.nim && echo "yes"')
+ifeq ($(koch),yes)
+	binDir = ../bin
+endif
+
+ucpu := $(shell sh -c 'uname -m | tr "[:upper:]" "[:lower:]"')
+uos := $(shell sh -c 'uname | tr "[:upper:]" "[:lower:]"')
+
+ifeq ($(uos),linux)
+	myos = linux
+	LINK_FLAGS += -ldl -lm
+endif
+ifeq ($(uos),dragonfly)
+	myos = freebsd
+	LINK_FLAGS += -lm
+endif
+ifeq ($(uos),freebsd)
+	myos= freebsd
+	CC = clang
+	LINKER = clang
+	LINK_FLAGS += -lm
+endif
+ifeq ($(uos),openbsd)
+	myos = openbsd
+	LINK_FLAGS += -lm
+endif
+ifeq ($(uos),netbsd)
+	myos = netbsd
+	LINK_FLAGS += -lm
+endif
+ifeq ($(uos),darwin)
+	myos = macosx
+	CC = clang
+	LINKER = clang
+	LINK_FLAGS += -ldl -lm
+	ifeq ($HOSTTYPE,x86_64)
+		ucpu = amd64
+	endif
+endif
+ifeq ($(uos),aix)
+	myos = aix
+	LINK_FLAGS += -dl -lm
+endif
+ifeq ($(uos),solaris)
+	myos = solaris
+	LINK_FLAGS += -ldl -lm -lsocket -lnsl
+endif
+ifeq ($(uos),sun)
+	myos = solaris
+	LINK_FLAGS += -ldl -lm -lsocket -lnsl
+endif
+ifeq ($(uos),haiku)
+	myos = haiku
+endif
+ifndef uos
+	@echo "Error: unknown operating system: $(uos)"
+	@exit 1
+endif
+
+ifeq ($(ucpu),i386)
+	mycpu = i386
+endif
+ifeq ($(ucpu),i486)
+	mycpu = i386
+endif
+ifeq ($(ucpu),i586)
+	mycpu = i386
+endif
+ifeq ($(ucpu),i686)
+	mycpu = i386
+endif
+ifeq ($(ucpu),bepc)
+	mycpu = i386
+endif
+ifeq ($(ucpu),i86pc)
+	mycpu = i386
+endif
+ifeq ($(ucpu),amd64)
+	mycpu = amd64
+endif
+ifeq ($(ucpu),x86-64)
+	mycpu = amd64
+endif
+ifeq ($(ucpu),x86_64)
+	mycpu = amd64
+endif
+ifeq ($(ucpu),sparc)
+	mycpu = sparc
+endif
+ifeq ($(ucpu),sun)
+	mycpu = sparc
+endif
+ifeq ($(ucpu),ppc64)
+	mycpu = powerpc64
+	ifeq ($(myos),linux)
+		COMP_FLAGS += -m64
+		LINK_FLAGS += -m64
+	endif
+endif
+ifeq ($(ucpu),powerpc)
+	mycpu = powerpc
+endif
+ifeq ($(ucpu),ppc)
+	mycpu = ppc
+endif
+ifeq ($(ucpu),mips)
+	mycpu = mips
+endif
+ifeq ($(ucpu),arm)
+	mycpu = arm
+endif
+ifeq ($(ucpu),armeb)
+	mycpu = arm
+endif
+ifeq ($(ucpu),armel)
+	mycpu = arm
+endif
+ifeq ($(ucpu),armv6l)
+	mycpu = arm
+endif
+ifndef ucpu
+	@echo "Error: unknown processor : $(ucpu)"
+	@exit 1
+endif
+
+# for osA in 1..c.oses.len:
+ifeq ($(myos),?{c.oses[osA-1]})
+#   for cpuA in 1..c.cpus.len:
+	ifeq ($(mycpu),?{c.cpus[cpuA-1]})
+#     var oFiles = ""
+#     for ff in c.cfiles[osA][cpuA].items:
+#       oFiles.add(" " & changeFileExt(ff.toUnix, "o"))
+#     end for
+		oFiles =?oFiles
+	endif
+#   end for
+endif
+# end for
+
+ifeq ($(strip $(oFiles)),)
+	@echo "Error: no C code generated for: [$(myos): $(mycpu)]"
+	@exit 1
+endif
+
+%.o: %.c
+	$(CC) $(COMP_FLAGS) -Ic_code -c $< -o $@
+
+?{"$(binDir)/" & toLower(c.name)}: $(oFiles)
+	@mkdir -p $(binDir)
+	$(LINKER) -o $@ $^ $(LINK_FLAGS)
+	@echo "SUCCESS"
+
+.PHONY: clean
+
+clean:
+	rm -f $(oFiles) ?{"$(binDir)/" & toLower(c.name)}
diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim
index 9ee3eb9b9..e50b251d3 100644
--- a/tools/niminst/niminst.nim
+++ b/tools/niminst/niminst.nim
@@ -1,7 +1,7 @@
 #
 #
 #        The Nim Installation Generator
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -22,12 +22,13 @@ const
   buildShFile = "build.sh"
   buildBatFile32 = "build.bat"
   buildBatFile64 = "build64.bat"
+  makeFile = "makefile"
   installShFile = "install.sh"
   deinstallShFile = "deinstall.sh"
 
 type
-  TAppType = enum appConsole, appGUI
-  TAction = enum
+  AppType = enum appConsole, appGUI
+  Action = enum
     actionNone,   # action not yet known
     actionCSource # action: create C sources
     actionInno,   # action: create Inno Setup installer
@@ -36,7 +37,7 @@ type
     actionZip,    # action: create zip file
     actionDeb     # action: prepare deb package
 
-  TFileCategory = enum
+  FileCategory = enum
     fcWinBin,     # binaries for Windows
     fcConfig,     # configuration files
     fcData,       # data files
@@ -48,19 +49,19 @@ type
     fcUnixBin,    # binaries for Unix
     fcDocStart    # links to documentation for Windows installer
 
-  TConfigData = object of TObject
-    actions: set[TAction]
-    cat: array[TFileCategory, seq[string]]
+  ConfigData = object of RootObj
+    actions: set[Action]
+    cat: array[FileCategory, seq[string]]
     binPaths, authors, oses, cpus, downloads: seq[string]
     cfiles: array[1..maxOS, array[1..maxCPU, seq[string]]]
     platforms: array[1..maxOS, array[1..maxCPU, bool]]
     ccompiler, linker, innosetup, nsisSetup: tuple[path, flags: string]
     name, displayName, version, description, license, infile, outdir: string
-    libpath: string
+    mainfile, libpath: string
     innoSetupFlag, installScript, uninstallScript: bool
     explicitPlatforms: bool
-    vars: PStringTable
-    app: TAppType
+    vars: StringTableRef
+    app: AppType
     nimArgs: string
     debOpts: TDebOptions
 
@@ -69,9 +70,9 @@ const
     "$configdir", "$datadir", "$docdir", "$libdir"
   ]
 
-proc initConfigData(c: var TConfigData) =
+proc iniConfigData(c: var ConfigData) =
   c.actions = {}
-  for i in low(TFileCategory)..high(TFileCategory): c.cat[i] = @[]
+  for i in low(FileCategory)..high(FileCategory): c.cat[i] = @[]
   c.binPaths = @[]
   c.authors = @[]
   c.oses = @[]
@@ -87,6 +88,7 @@ proc initConfigData(c: var TConfigData) =
   c.description = ""
   c.license = ""
   c.infile = ""
+  c.mainfile = ""
   c.outdir = ""
   c.nimArgs = ""
   c.libpath = ""
@@ -100,7 +102,7 @@ proc initConfigData(c: var TConfigData) =
   c.debOpts.shortDesc = ""
   c.debOpts.licenses = @[]
 
-proc firstBinPath(c: TConfigData): string =
+proc firstBinPath(c: ConfigData): string =
   if c.binPaths.len > 0: result = c.binPaths[0]
   else: result = ""
 
@@ -122,6 +124,7 @@ proc skipRoot(f: string): string =
 include "inno.tmpl"
 include "nsis.tmpl"
 include "buildsh.tmpl"
+include "makefile.tmpl"
 include "buildbat.tmpl"
 include "install.tmpl"
 include "deinstall.tmpl"
@@ -132,7 +135,7 @@ const
   Version = "1.0"
   Usage = "niminst - Nim Installation Generator Version " & Version & """
 
-  (c) 2014 Andreas Rumpf
+  (c) 2015 Andreas Rumpf
 Usage:
   niminst [options] command[;command2...] ini-file[.ini] [compile_options]
 Command:
@@ -144,6 +147,8 @@ Command:
   deb                 create files for debhelper
 Options:
   -o, --output:dir    set the output directory
+  -m, --main:file     set the main nim file, by default ini-file with .nim
+                      extension
   --var:name=value    set the value of a variable
   -h, --help          shows this help
   -v, --version       shows the version
@@ -151,7 +156,7 @@ Compile_options:
   will be passed to the Nim compiler
 """
 
-proc parseCmdLine(c: var TConfigData) =
+proc parseCmdLine(c: var ConfigData) =
   var p = initOptParser()
   while true:
     next(p)
@@ -183,6 +188,7 @@ proc parseCmdLine(c: var TConfigData) =
         stdout.write(Version & "\n")
         quit(0)
       of "o", "output": c.outdir = val
+      of "m", "main": c.mainfile = changeFileExt(val, "nim")
       of "var":
         var idx = val.find('=')
         if idx < 0: quit("invalid command line")
@@ -190,6 +196,7 @@ proc parseCmdLine(c: var TConfigData) =
       else: quit(Usage)
     of cmdEnd: break
   if c.infile.len == 0: quit(Usage)
+  if c.mainfile.len == 0: c.mainfile = changeFileExt(c.infile, "nim")
 
 proc walkDirRecursively(s: var seq[string], root: string) =
   for k, f in walkDir(root):
@@ -209,19 +216,19 @@ proc addFiles(s: var seq[string], patterns: seq[string]) =
         inc(i)
       if i == 0: echo("[Warning] No file found that matches: " & p)
 
-proc pathFlags(p: var TCfgParser, k, v: string,
+proc pathFlags(p: var CfgParser, k, v: string,
                t: var tuple[path, flags: string]) =
   case normalize(k)
   of "path": t.path = v
   of "flags": t.flags = v
   else: quit(errorStr(p, "unknown variable: " & k))
 
-proc filesOnly(p: var TCfgParser, k, v: string, dest: var seq[string]) =
+proc filesOnly(p: var CfgParser, k, v: string, dest: var seq[string]) =
   case normalize(k)
   of "files": addFiles(dest, split(v, {';'}))
   else: quit(errorStr(p, "unknown variable: " & k))
 
-proc yesno(p: var TCfgParser, v: string): bool =
+proc yesno(p: var CfgParser, v: string): bool =
   case normalize(v)
   of "yes", "y", "on", "true":
     result = true
@@ -235,7 +242,7 @@ proc incl(s: var seq[string], x: string): int =
   s.add(x)
   result = s.len-1 
 
-proc platforms(c: var TConfigData, v: string) =
+proc platforms(c: var ConfigData, v: string) =
   for line in splitLines(v):
     let p = line.find(": ")
     if p <= 1: continue
@@ -246,9 +253,9 @@ proc platforms(c: var TConfigData, v: string) =
       let cpuIdx = c.cpus.incl(cpu)
       c.platforms[c.oses.len][cpuIdx+1] = true
 
-proc parseIniFile(c: var TConfigData) =
+proc parseIniFile(c: var ConfigData) =
   var
-    p: TCfgParser
+    p: CfgParser
     section = ""
     hasCpuOs = false
   var input = newFileStream(c.infile, fmRead)
@@ -358,15 +365,15 @@ proc parseIniFile(c: var TConfigData) =
       of cfgOption: quit(errorStr(p, "syntax error"))
       of cfgError: quit(errorStr(p, k.msg))
     close(p)
-    if c.name.len == 0: c.name = changeFileExt(extractFilename(c.infile), "")
+    if c.name.len == 0: c.name = changeFileExt(extractFilename(c.mainfile), "")
     if c.displayName.len == 0: c.displayName = c.name
   else:
     quit("cannot open: " & c.infile)
 
 # ------------------------- generate source based installation ---------------
 
-proc readCFiles(c: var TConfigData, osA, cpuA: int) =
-  var p: TCfgParser
+proc readCFiles(c: var ConfigData, osA, cpuA: int) =
+  var p: CfgParser
   var f = splitFile(c.infile).dir / "mapping.txt"
   c.cfiles[osA][cpuA] = @[]
   var input = newFileStream(f, fmRead)
@@ -402,11 +409,11 @@ proc readCFiles(c: var TConfigData, osA, cpuA: int) =
 proc buildDir(os, cpu: int): string =
   return "c_code" / ($os & "_" & $cpu)
 
-proc getOutputDir(c: var TConfigData): string =
+proc getOutputDir(c: var ConfigData): string =
   if c.outdir.len > 0: c.outdir else: "build"
 
 proc writeFile(filename, content, newline: string) =
-  var f: TFile
+  var f: File
   if open(f, filename, fmWrite):
     for x in splitLines(content):
       write(f, x)
@@ -415,7 +422,7 @@ proc writeFile(filename, content, newline: string) =
   else:
     quit("Cannot open for writing: " & filename)
 
-proc removeDuplicateFiles(c: var TConfigData) =
+proc removeDuplicateFiles(c: var ConfigData) =
   for osA in countdown(c.oses.len, 1):
     for cpuA in countdown(c.cpus.len, 1):
       if c.cfiles[osA][cpuA].isNil: c.cfiles[osA][cpuA] = @[]
@@ -433,13 +440,15 @@ proc removeDuplicateFiles(c: var TConfigData) =
                 removeFile(dup)
                 c.cfiles[osA][cpuA][i] = orig
 
-proc writeInstallScripts(c: var TConfigData) =
+proc writeInstallScripts(c: var ConfigData) =
   if c.installScript:
     writeFile(installShFile, generateInstallScript(c), "\10")
+    inclFilePermissions(installShFile, {fpUserExec, fpGroupExec, fpOthersExec})
   if c.uninstallScript:
     writeFile(deinstallShFile, generateDeinstallScript(c), "\10")
+    inclFilePermissions(deinstallShFile, {fpUserExec, fpGroupExec, fpOthersExec})
 
-proc srcdist(c: var TConfigData) =
+proc srcdist(c: var ConfigData) =
   if not existsDir(getOutputDir(c) / "c_code"):
     createDir(getOutputDir(c) / "c_code")
   for x in walkFiles(c.libpath / "lib/*.h"):
@@ -462,8 +471,7 @@ proc srcdist(c: var TConfigData) =
       var cmd = ("nim compile -f --symbolfiles:off --compileonly " &
                  "--gen_mapping --cc:gcc --skipUserCfg" &
                  " --os:$# --cpu:$# $# $#") %
-                 [osname, cpuname, c.nimArgs,
-                 changeFileExt(c.infile, "nim")]
+                 [osname, cpuname, c.nimArgs, c.mainfile]
       echo(cmd)
       if execShellCmd(cmd) != 0:
         quit("Error: call to nim compiler failed")
@@ -476,6 +484,8 @@ proc srcdist(c: var TConfigData) =
   # second pass: remove duplicate files
   removeDuplicateFiles(c)
   writeFile(getOutputDir(c) / buildShFile, generateBuildShellScript(c), "\10")
+  inclFilePermissions(getOutputDir(c) / buildShFile, {fpUserExec, fpGroupExec, fpOthersExec})
+  writeFile(getOutputDir(c) / makeFile, generateMakefile(c), "\10")
   if winIndex >= 0:
     if intel32Index >= 0:
       writeFile(getOutputDir(c) / buildBatFile32,
@@ -486,7 +496,7 @@ proc srcdist(c: var TConfigData) =
   writeInstallScripts(c)
 
 # --------------------- generate inno setup -----------------------------------
-proc setupDist(c: var TConfigData) =
+proc setupDist(c: var ConfigData) =
   let scrpt = generateInnoSetup(c)
   let n = "build" / "install_$#_$#.iss" % [toLower(c.name), c.version]
   writeFile(n, scrpt, "\13\10")
@@ -503,7 +513,7 @@ proc setupDist(c: var TConfigData) =
       quit("External program failed")
 
 # --------------------- generate NSIS setup -----------------------------------
-proc setupDist2(c: var TConfigData) =
+proc setupDist2(c: var ConfigData) =
   let scrpt = generateNsisSetup(c)
   let n = "build" / "install_$#_$#.nsi" % [toLower(c.name), c.version]
   writeFile(n, scrpt, "\13\10")
@@ -521,9 +531,9 @@ proc setupDist2(c: var TConfigData) =
 
 # ------------------ generate ZIP file ---------------------------------------
 when haveZipLib:
-  proc zipDist(c: var TConfigData) =
-    var proj = toLower(c.name)
-    var n = "$#_$#.zip" % [proj, c.version]
+  proc zipDist(c: var ConfigData) =
+    var proj = toLower(c.name) & "-" & c.version
+    var n = "$#.zip" % proj
     if c.outdir.len == 0: n = "build" / n
     else: n = c.outdir / n
     var z: TZipArchive
@@ -531,6 +541,7 @@ when haveZipLib:
       addFile(z, proj / buildBatFile32, "build" / buildBatFile32)
       addFile(z, proj / buildBatFile64, "build" / buildBatFile64)
       addFile(z, proj / buildShFile, "build" / buildShFile)
+      addFile(z, proj / makeFile, "build" / makeFile)
       addFile(z, proj / installShFile, installShFile)
       addFile(z, proj / deinstallShFile, deinstallShFile)
       for f in walkFiles(c.libpath / "lib/*.h"):
@@ -549,7 +560,7 @@ when haveZipLib:
 
 # -- prepare build files for .deb creation
 
-proc debDist(c: var TConfigData) =
+proc debDist(c: var ConfigData) =
   if not existsFile(getOutputDir(c) / "build.sh"): quit("No build.sh found.")
   if not existsFile(getOutputDir(c) / "install.sh"): quit("No install.sh found.")
   
@@ -571,6 +582,7 @@ proc debDist(c: var TConfigData) =
   
   # Don't copy all files, only the ones specified in the config:
   copyNimDist(buildShFile, buildShFile)
+  copyNimDist(makeFile, makeFile)
   copyNimDist(installShFile, installShFile)
   createDir(workingDir / upstreamSource / "build")
   for f in walkFiles(c.libpath / "lib/*.h"):
@@ -595,8 +607,8 @@ proc debDist(c: var TConfigData) =
 
 # ------------------- main ----------------------------------------------------
 
-var c: TConfigData
-initConfigData(c)
+var c: ConfigData
+iniConfigData(c)
 parseCmdLine(c)
 parseIniFile(c)
 if actionInno in c.actions:
diff --git a/tools/niminst/nsis.tmpl b/tools/niminst/nsis.tmpl
index 40e171d41..c21bfb9d5 100644
--- a/tools/niminst/nsis.tmpl
+++ b/tools/niminst/nsis.tmpl
@@ -1,5 +1,5 @@
 #! stdtmpl(subsChar='?') | standard
-#proc generateNsisSetup(c: TConfigData): string = 
+#proc generateNsisSetup(c: ConfigData): string = 
 #  result = "; NSIS script generated by niminst\n" &
 #           "; To regenerate run ``niminst nsis`` or ``koch nsis``\n"
 
@@ -50,8 +50,8 @@
   SetCompressor /SOLID /FINAL lzma
 
   ; Installer and Uninstaller Icons
-  ; Icon "nimrod.ico"
-  ; UninstallIcon "nimrod.ico"
+  ; Icon "nim.ico"
+  ; UninstallIcon "nim.ico"
 
   ; Set installation details to be shown by default
   ShowInstDetails show
@@ -113,7 +113,7 @@
     SetOverwrite ifnewer
 
     ; Write all the files to the output directory.
-    #for i in low(TFileCategory)..fcWindows:
+    #for i in low(FileCategory)..fcWindows:
     #  for f in items(c.cat[i]):
          SetOutPath "$INSTDIR\?{splitFile(f).dir.toWin}"
          File "?{expandFilename(f).toWin}"
@@ -128,7 +128,7 @@
     ; Write application registry keys
     WriteRegStr HKCU "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\bin\?{c.name}.exe"
     WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
-    WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
+    WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninstaller.exe"
     WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\bin\?{c.name}.exe"
     WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
     WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
diff --git a/tools/nimrepl.nim b/tools/nimrepl.nim
index 0c9f94616..3d818a556 100644
--- a/tools/nimrepl.nim
+++ b/tools/nimrepl.nim
@@ -130,7 +130,7 @@ proc initControls() =
   
   pack_start(MainBox, TopMenu, False, False, 0)
 
-  # VPaned - Seperates the InputTextView and the OutputTextView
+  # VPaned - Separates the InputTextView and the OutputTextView
   var paned = vpaned_new()
   set_position(paned, 450)
   pack_start(MainBox, paned, True, True, 0)
diff --git a/tools/nimweb.nim b/tools/nimweb.nim
index 46c1d0d85..a7301195e 100644
--- a/tools/nimweb.nim
+++ b/tools/nimweb.nim
@@ -1,7 +1,7 @@
 #
 #
 #           Nim Website Generator
-#        (c) Copyright 2014 Andreas Rumpf
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -19,11 +19,17 @@ type
     authors, projectName, projectTitle, logo, infile, outdir, ticker: string
     vars: StringTableRef
     nimArgs: string
+    gitRepo: string
     gitCommit: string
     quotations: Table[string, tuple[quote, author: string]]
     numProcessors: int # Set by parallelBuild:n, only works for values > 0.
+    gaId: string  # google analytics ID, nil means analytics are disabled
   TRssItem = object
     year, month, day, title: string
+  TAction = enum
+    actAll, actOnlyWebsite, actPdf
+
+var action: TAction
 
 proc initConfigData(c: var TConfigData) =
   c.tabs = @[]
@@ -42,6 +48,7 @@ proc initConfigData(c: var TConfigData) =
   c.logo = ""
   c.ticker = ""
   c.vars = newStringTable(modeStyleInsensitive)
+  c.gitRepo = "https://github.com/Araq/Nim/tree"
   c.gitCommit = "master"
   c.numProcessors = countProcessors()
   # Attempts to obtain the git current commit.
@@ -59,7 +66,7 @@ const
   version = "0.7"
   usage = "nimweb - Nim Website Generator Version " & version & """
 
-  (c) 2014 Andreas Rumpf
+  (c) 2015 Andreas Rumpf
 Usage:
   nimweb [options] ini-file[.ini] [compile_options]
 Options:
@@ -67,6 +74,8 @@ Options:
   --var:name=value    set the value of a variable
   -h, --help          shows this help
   -v, --version       shows the version
+  --website           only build the website, not the full documentation
+  --pdf               build the PDF version of the documentation
 Compile_options:
   will be passed to the Nim compiler
 """
@@ -90,8 +99,8 @@ macro updated(e: expr): expr {.immediate.} =
 proc updatedDate(year, month, day: string): string =
   ## wrapper around the update macro with easy input.
   result = updated("$1-$2-$3T00:00:00Z" % [year,
-    repeatStr(2 - len(month), "0") & month,
-    repeatStr(2 - len(day), "0") & day])
+    repeat("0", 2 - len(month)) & month,
+    repeat("0", 2 - len(day)) & day])
 
 macro entry(e: expr): expr {.immediate.} =
   ## generates the rss xml ``entry`` element.
@@ -134,7 +143,14 @@ proc parseCmdLine(c: var TConfigData) =
         var idx = val.find('=')
         if idx < 0: quit("invalid command line")
         c.vars[substr(val, 0, idx-1)] = substr(val, idx+1)
-      else: quit(usage)
+      of "website": action = actOnlyWebsite
+      of "pdf": action = actPdf
+      of "googleanalytics":
+        c.gaId = val
+        c.nimArgs.add("--doc.googleAnalytics:" & val & " ")
+      else:
+        echo("Invalid argument $1" % [key])
+        quit(usage)
     of cmdEnd: break
   if c.infile.len == 0: quit(usage)
 
@@ -252,24 +268,26 @@ proc buildDocSamples(c: var TConfigData, destPath: string) =
   exec("nim doc2 $# -o:$# $#" %
     [c.nimArgs, destPath / "docgen_sample2.html", src])
 
+proc pathPart(d: string): string = splitFile(d).dir.replace('\\', '/')
+
 proc buildDoc(c: var TConfigData, destPath: string) =
   # call nim for the documentation:
   var
     commands = newSeq[string](len(c.doc) + len(c.srcdoc) + len(c.srcdoc2))
     i = 0
   for d in items(c.doc):
-    commands[i] = "nim rst2html $# --docSeeSrcUrl:$# -o:$# --index:on $#" %
-      [c.nimArgs, c.gitCommit,
+    commands[i] = "nim rst2html $# --docSeeSrcUrl:$#/$#/$# -o:$# --index:on $#" %
+      [c.nimArgs, c.gitRepo, c.gitCommit, d.pathPart,
       destPath / changeFileExt(splitFile(d).name, "html"), d]
     i.inc
   for d in items(c.srcdoc):
-    commands[i] = "nim doc $# --docSeeSrcUrl:$# -o:$# --index:on $#" %
-      [c.nimArgs, c.gitCommit,
+    commands[i] = "nim doc $# --docSeeSrcUrl:$#/$#/$# -o:$# --index:on $#" %
+      [c.nimArgs, c.gitRepo, c.gitCommit, d.pathPart,
       destPath / changeFileExt(splitFile(d).name, "html"), d]
     i.inc
   for d in items(c.srcdoc2):
-    commands[i] = "nim doc2 $# --docSeeSrcUrl:$# -o:$# --index:on $#" %
-      [c.nimArgs, c.gitCommit,
+    commands[i] = "nim doc2 $# --docSeeSrcUrl:$#/$#/$# -o:$# --index:on $#" %
+      [c.nimArgs, c.gitRepo, c.gitCommit, d.pathPart,
       destPath / changeFileExt(splitFile(d).name, "html"), d]
     i.inc
 
@@ -301,8 +319,8 @@ proc buildAddDoc(c: var TConfigData, destPath: string) =
   # build additional documentation (without the index):
   var commands = newSeq[string](c.webdoc.len)
   for i, doc in pairs(c.webdoc):
-    commands[i] = "nim doc $# --docSeeSrcUrl:$# -o:$# $#" %
-      [c.nimArgs, c.gitCommit,
+    commands[i] = "nim doc2 $# --docSeeSrcUrl:$#/$#/$# -o:$# $#" %
+      [c.nimArgs, c.gitRepo, c.gitCommit, doc.pathPart,
       destPath / changeFileExt(splitFile(doc).name, "html"), doc]
   mexec(commands, c.numProcessors)
 
@@ -386,10 +404,10 @@ proc buildNewsRss(c: var TConfigData, destPath: string) =
   generateRss(destFilename, parseNewsTitles(srcFilename))
 
 proc buildJS(destPath: string) =
-  exec("nim js -d:release --out:$1 web/babelpkglist.nim" %
-      [destPath / "babelpkglist.js"])
+  exec("nim js -d:release --out:$1 web/nimblepkglist.nim" %
+      [destPath / "nimblepkglist.js"])
 
-proc main(c: var TConfigData) =
+proc buildWebsite(c: var TConfigData) =
   const
     cmd = "nim rst2html --compileonly $1 -o:web/$2.temp web/$2.txt"
   if c.ticker.len > 0:
@@ -400,6 +418,7 @@ proc main(c: var TConfigData) =
   for i in 0..c.tabs.len-1:
     var file = c.tabs[i].val
     let rss = if file in ["news", "index"]: extractFilename(rssUrl) else: ""
+    if '.' in file: continue
     exec(cmd % [c.nimArgs, file])
     var temp = "web" / changeFileExt(file, "temp")
     var content: string
@@ -418,20 +437,22 @@ proc main(c: var TConfigData) =
       quit("[Error] cannot write file: " & outfile)
     removeFile(temp)
   copyDir("web/assets", "web/upload/assets")
-  buildJS("web/upload")
   buildNewsRss(c, "web/upload")
+
+proc main(c: var TConfigData) =
+  buildWebsite(c)
+  buildJS("web/upload")
   buildAddDoc(c, "web/upload")
   buildDocSamples(c, "web/upload")
   buildDoc(c, "web/upload")
   buildDocSamples(c, "doc")
   buildDoc(c, "doc")
-  buildPdfDoc(c, "doc")
 
 var c: TConfigData
 initConfigData(c)
 parseCmdLine(c)
 parseIniFile(c)
-when false:
-  buildPdfDoc(c, "doc")
-else:
-  main(c)
+case action
+of actOnlyWebsite: buildWebsite(c)
+of actPdf: buildPdfDoc(c, "doc")
+of actAll: main(c)
diff --git a/tools/website.tmpl b/tools/website.tmpl
index f3cacdb64..bc3ed8e2c 100644
--- a/tools/website.tmpl
+++ b/tools/website.tmpl
@@ -1,88 +1,210 @@
 #! stdtmpl | standard
 #proc generateHTMLPage(c: var TConfigData, currentTab, content, rss: string): string = 
 #  result = ""
-<!doctype html>
+<!DOCTYPE html>
 <html>
-
-<head>
-  <title>$c.projectTitle</title>
-  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
-  <link rel="stylesheet" type="text/css" href="assets/style.css" />
+  <head>
+    <meta http-equiv="content-type" content="text/html; charset=utf-8">
+    <title>$c.projectTitle</title>
+    <link rel="stylesheet" type="text/css" href="assets/style.css" />
+    <link rel="shortcut icon" href="assets/images/favicon.ico">
   #if len(rss) > 0:
-  <link href="$rss" title="Recent changes" type="application/atom+xml" rel="alternate">
-  #end fi
-</head>
-
-<body>
-  <div id="site">
-    <!-- site_head -->
-    <div id="site_head">
-      <div id="logo"></div>
-    </div>
-
-    <!-- site_neck -->
-    <div id="site_neck">
+    <link href="$rss" title="Recent changes" type="application/atom+xml" rel="alternate">
+  #end if
+  </head>
+  <body>
+    <header id="head">
+      <div class="page-layout tall">
+        <div id="head-logo"></div>
+        <a id="head-logo-link" href="index.html"></a>
+        <nav id="head-links">
       #for i in 0.. c.tabs.len-1:
-      #  var name = c.tabs[i].key
-      #  var t = c.tabs[i].val
-        #if currentTab == t:
-          <a class="active" 
-        #else:
-          <a
-        #end if
-        href="${t}.html" title = "$c.projectName - $name">$name</a>
+      # let t = c.tabs[i].val
+      # if t != "index" and t != "community" and t != "news":
+      #   let name = c.tabs[i].key
+      #   if currentTab == t:
+            <a class="active" 
+      #   else:
+            <a
+      #   end if
+      #   if t.contains('.'):
+            href="${t}" title = "$c.projectName - $name">$name</a>
+      #   else:
+            href="${t}.html" title = "$c.projectName - $name">$name</a>
+      #   end if
+      # end if
       #end for
-    </div>
+        </nav>
+      </div>
+    </header>
 
-    <!-- site_body -->
-    <div id="site_body">
+#  if currentTab == "index":
+    <section id="neck" class="home">
+#  else:
+    <section id="neck">
+#  end
+      <div class="page-layout tall">
+        <div id="glow-arrow"></div>
 
-      <!-- sidebar_wrapper -->
-      <div id="sidebar_wrap">
-        <div id="sidebar">
-          <div id="sidebar_head"></div>
-          <h2>Latest News</h2>
-#  if len(c.ticker) > 0:
-          $c.ticker
-#  end if
+#  if currentTab == "index":
+        <div id="slideshow">
+          <!-- slides -->
+          <div id="slide0" class="active">
+            <h2><a name="why-should-i-be-excited">Why should I be excited?</a></h2>
+            <span class="desc">Nim is the only language that leverages automated proof technology to perform a <i>disjoint check</i> for your parallel code. Working on disjoint data means no locking is required and yet data races are impossible:</span><br><br>
+<pre>
+<span class="kwd">parallel</span>:
+<span class="tab">  </span><span class="kwd">var</span> i = <span class="val">0</span>
+<span class="tab">  </span><span class="kwd">while</span> i <= a.high:
+<span class="tab">  <span class="tab">  </span></span></span><span class="kwd">spawn</span> f(a[i])
+<span class="tab">  <span class="tab">  </span></span></span><span class="kwd">spawn</span> f(a[i+<span class="val">1</span>])
+<span class="tab">  <span class="tab">  </span></span></span><span class="cmt"># ERROR: cannot prove a[i] is disjoint from a[i+1]</span>
+<span class="tab">  <span class="tab">  </span></span></span><span class="cmt"># BUT: replace 'i += 1' with 'i += 2' and the code compiles!</span>
+<span class="tab end">  <span class="tab end">  </span></span>i += <span class="val">1</span>
+</pre>
+          </div>
+          <div id="slide1">
+            <div>
+              <h2>Nim is simple..</h2>
+<pre>
+<span class="cmt"># compute average line length</span>
+<span class="kwd">var</span>
+<span class="tab">  </span>sum = <span class="val">0</span>
+<span class="tab end">  </span>count = <span class="val">0</span>
+
+<span class="kwd">for</span> line <span class="kwd">in</span> stdin.lines:
+<span class="tab">  </span>sum += line.len
+<span class="tab end">  </span>count += <span class="val">1</span>
+
+echo(<span class="val">"Average line length: "</span>,
+  <span class="kwd">if</span> count &gt; <span class="val">0</span>: sum / count <span class="kwd">else</span>: <span class="val">0</span>)
+</pre>
+            </div>
+            <div>
+               <h2>..and type safe...</h2>
+<pre>
+<span class="cmt"># create and greet someone</span>
+<span class="kwd">type</span> <span class="def">Person</span> = <span class="kwd">object</span>
+<span class="tab">  </span>name: <span class="typ">string</span>
+<span class="tab end">  </span>age: <span class="typ">int</span>
+
+<span class="kwd">proc</span> <span class="def">greet</span>(p: <span class="typ">Person</span>) =
+<span class="tab">  </span>echo <span class="val">"Hi, I'm "</span>, p.name, <span class="val">"."</span>
+<span class="tab end">  </span>echo <span class="val">"I am "</span>, p.age, <span class="val">" years old."</span>
+
+<span class="kwd">let</span> p = <span class="typ">Person</span>(name:<span class="val">"Jon"</span>, age:<span class="val">18</span>)
+p.greet() <span class="cmt"># or greet(p)</span>
+</pre>
+             </div>
+          </div>
+          <div id="slide2" class="">
+            <div>
+              <h2>C FFI is easy in Nim..</h2>
+<pre>
+<span class="cmt"># declare a C procedure..</span>
+<span class="kwd">proc</span> <span class="def">unsafeScanf</span>(f: <span class="typ">File</span>, s: <span class="typ">cstring</span>)
+<span class="tab">  </span>{.varargs,
+<span class="tab">    </span>importc: <span class="val">"fscanf"</span>, 
+<span class="tab end">    </span>header: <span class="val">"&lt;stdio.h&gt;"</span>.}
+
+<span class="cmt"># ..and use it...</span>
+<span class="kwd">var</span> x: <span class="typ">cint</span>
+stdin.unsafeScanf(<span class="val">"%d"</span>, <span class="kwd">addr</span> x)
+</pre>
+              <p><span class="desc"><b>Compile and run with:</b><br>&nbsp;&nbsp;&nbsp;&nbsp;&#36; nim c -r example.nim</span></p>
+            </div>
+            <div>
+              <h2>..and DSLs are too...</h2>
+<pre>
+<span class="cmt"># a simple html server</span>
+<span class="kwd">import</span>
+  jester, asyncdispatch, htmlgen
+
+<span class="kwd">routes</span>:
+<span class="tab">  </span><span class="kwd">get</span> <span class="val">"/"</span>:
+<span class="tab end">  <span class="tab end">  </span></span><span class="kwd">resp</span> h1(<span class="val">"Hello world"</span>)
+
+runForever()
+</pre>
+              <p><span class="desc"><b>View in browser at:</b><br>&nbsp;&nbsp;&nbsp;&nbsp;localhost:5000</span></p>
+            </div>
+          </div>
+        </div>
+        <div id="slideshow-nav">
+          <div id="slideControl0" onclick="slideshow_click(0)" class="active"></div>
+          <div id="slideControl1" onclick="slideshow_click(1)"></div>
+          <div id="slideControl2" onclick="slideshow_click(2)"></div>
+        </div>
+#  end
+        <aside id="sidebar">
 
 #  if len(c.links) > 0:
-          <h2>More Links</h2>
+          <h3>More Links</h3>
+          <div id="sidebar-links">
 #         for i in 0..c.links.len-1:
-          <a class="link" href="${c.links[i].val}" id="${c.links[i].id}">${c.links[i].key}</a>
+          <a href="${c.links[i].val}" id="${c.links[i].id}">${c.links[i].key}</a>
 #         end for
+          </div>
 #  end if
-        </div>
-      </div>
-      <!-- page -->
-      <div id="page">
-        #if c.quotations.hasKey(currentTab):
-          <div class="quote-image"></div>
-          <p class="quote">
-            ${c.quotations[currentTab].quote}
-            <br>
-            <b style="float: right">-- ${c.quotations[currentTab].author}</b>
-          </p>
-          <br/>
-        #end if
-      
-        $content
-      </div>
-    </div>
-    <!-- site_foot -->
-    <div id="site_foot">
-       <div id="legal">Copyright &copy; 2014 - Andreas Rumpf &amp; Contributors - All rights reserved - <a href="http://reign-studios.com/philipwitte/">Design by Philip Witte</a></div>
-    </div>
-  </div>
+#  if len(c.ticker) > 0:
+					<h3 class="blue">Latest News</h3>
+					<div id="sidebar-news">
+          $c.ticker
+					</div>
+#  end if
+				</aside>
+			</div>
+		</section>
+
+		<section id="body">
+			<div id="body-border"></div>
+			<div id="glow-line"></div>
+			<div class="page-layout">
+				<article id="content" class="page">
+				$content
+				</article>
+			</div>
+		</section>
+
+		<!--- #foot --->
+		<footer id="foot" class="home">
+			<div class="page-layout tall">
+				<div id="foot-links">
+					<div>
+						<h4>Documentation</h4>
+						<a href="documentation.html">Stable Documentation</a>
+						<a href="learn.html">Learning Resources</a>
+					<!--	<a href="">Development Documentation</a> -->
+						<a href="https://github.com/Araq/Nimrod">Issues &amp; Requests</a>
+					</div>
+					<div>
+						<h4>Community</h4>
+						<a href="http://forum.nim-lang.org">User Forum</a>
+            <a href="http://webchat.freenode.net/?channels=nim">Online IRC</a>
+            <a href="http://irclogs.nim-lang.org/">IRC Logs</a>
+					</div>
+				</div>
+				<div id="foot-legal">
+					<h4>Written in Nim - Powered by <a href="https://github.com/dom96/jester">Jester</a></h4>
+					Web Design by <a href="http://reign-studios.net/philipwitte/">Philip Witte</a> &amp; <a href="http://picheta.me/">Dominik Picheta</a><br>
+					Copyright © 2015 - <a href="http://nim-lang.org/blog/">Andreas Rumpf</a> &amp; <a href="https://github.com/Araq/Nimrod/graphs/contributors">Contributors</a>
+				</div>
+			</div>
+		</footer>
+  
+#  if currentTab == "index":
+  <script src="assets/index.js"></script>
+# end if
+#  if c.gaId != nil:
   <script>
     (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
     (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
     m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
     })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
 
-    ga('create', 'UA-48159761-1', 'nim-lang.org');
+    ga('create', '${c.gaId}', 'nim-lang.org');
     ga('send', 'pageview');
-
   </script>
+#  end if
 </body>
 </html>
diff --git a/web/assets/images/bg.png b/web/assets/images/bg.png
new file mode 100644
index 000000000..91f335913
--- /dev/null
+++ b/web/assets/images/bg.png
Binary files differdiff --git a/web/assets/images/docs-articles.png b/web/assets/images/docs-articles.png
new file mode 100644
index 000000000..7f800ea33
--- /dev/null
+++ b/web/assets/images/docs-articles.png
Binary files differdiff --git a/web/assets/images/docs-examples.png b/web/assets/images/docs-examples.png
new file mode 100644
index 000000000..e6d27e034
--- /dev/null
+++ b/web/assets/images/docs-examples.png
Binary files differdiff --git a/web/assets/images/docs-internals.png b/web/assets/images/docs-internals.png
new file mode 100644
index 000000000..e03a952d5
--- /dev/null
+++ b/web/assets/images/docs-internals.png
Binary files differdiff --git a/web/assets/images/docs-libraries.png b/web/assets/images/docs-libraries.png
new file mode 100644
index 000000000..b14952f7d
--- /dev/null
+++ b/web/assets/images/docs-libraries.png
Binary files differdiff --git a/web/assets/images/docs-tools.png b/web/assets/images/docs-tools.png
new file mode 100644
index 000000000..d83f0faaa
--- /dev/null
+++ b/web/assets/images/docs-tools.png
Binary files differdiff --git a/web/assets/images/docs-tutorials.png b/web/assets/images/docs-tutorials.png
new file mode 100644
index 000000000..926a4b58b
--- /dev/null
+++ b/web/assets/images/docs-tutorials.png
Binary files differdiff --git a/web/assets/images/favicon.ico b/web/assets/images/favicon.ico
new file mode 100644
index 000000000..aed71adb4
--- /dev/null
+++ b/web/assets/images/favicon.ico
Binary files differdiff --git a/web/assets/images/foot.png b/web/assets/images/foot.png
new file mode 100644
index 000000000..dc2561cf3
--- /dev/null
+++ b/web/assets/images/foot.png
Binary files differdiff --git a/web/assets/images/glow-arrow.png b/web/assets/images/glow-arrow.png
new file mode 100644
index 000000000..436d32f03
--- /dev/null
+++ b/web/assets/images/glow-arrow.png
Binary files differdiff --git a/web/assets/images/glow-line.png b/web/assets/images/glow-line.png
new file mode 100644
index 000000000..6607bdee9
--- /dev/null
+++ b/web/assets/images/glow-line.png
Binary files differdiff --git a/web/assets/images/head-link.png b/web/assets/images/head-link.png
new file mode 100644
index 000000000..d97cba5b8
--- /dev/null
+++ b/web/assets/images/head-link.png
Binary files differdiff --git a/web/assets/images/head-link_hover.png b/web/assets/images/head-link_hover.png
new file mode 100644
index 000000000..27edf3b05
--- /dev/null
+++ b/web/assets/images/head-link_hover.png
Binary files differdiff --git a/web/assets/images/head.png b/web/assets/images/head.png
new file mode 100644
index 000000000..009f86728
--- /dev/null
+++ b/web/assets/images/head.png
Binary files differdiff --git a/web/assets/images/logo.png b/web/assets/images/logo.png
index 31ee0a6e1..85d3d2e51 100644
--- a/web/assets/images/logo.png
+++ b/web/assets/images/logo.png
Binary files differdiff --git a/web/assets/images/mascot.png b/web/assets/images/mascot.png
new file mode 100644
index 000000000..9beb62c01
--- /dev/null
+++ b/web/assets/images/mascot.png
Binary files differdiff --git a/web/assets/images/more-links_editors.png b/web/assets/images/more-links_editors.png
new file mode 100644
index 000000000..f5970ff1f
--- /dev/null
+++ b/web/assets/images/more-links_editors.png
Binary files differdiff --git a/web/assets/images/more-links_forum.png b/web/assets/images/more-links_forum.png
new file mode 100644
index 000000000..f33277777
--- /dev/null
+++ b/web/assets/images/more-links_forum.png
Binary files differdiff --git a/web/assets/images/more-links_github.png b/web/assets/images/more-links_github.png
new file mode 100644
index 000000000..4a6a844f4
--- /dev/null
+++ b/web/assets/images/more-links_github.png
Binary files differdiff --git a/web/assets/images/more-links_nimbuild.png b/web/assets/images/more-links_nimbuild.png
new file mode 100644
index 000000000..473fbe4cd
--- /dev/null
+++ b/web/assets/images/more-links_nimbuild.png
Binary files differdiff --git a/web/assets/images/nim-logo.svg b/web/assets/images/nim-logo.svg
new file mode 100644
index 000000000..feae6c3d7
--- /dev/null
+++ b/web/assets/images/nim-logo.svg
@@ -0,0 +1,500 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="163.84375"
+   height="124.67096"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   sodipodi:docname="New document 1">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient3833">
+      <stop
+         style="stop-color:#f7c41a;stop-opacity:1;"
+         offset="0"
+         id="stop3835" />
+      <stop
+         style="stop-color:#bd9510;stop-opacity:1;"
+         offset="1"
+         id="stop3837" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3825">
+      <stop
+         style="stop-color:#f3d673;stop-opacity:1;"
+         offset="0"
+         id="stop3827" />
+      <stop
+         style="stop-color:#c7a23a;stop-opacity:1;"
+         offset="1"
+         id="stop3829" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825"
+       id="radialGradient3831"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,1.3722368,813.17816)"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833"
+       id="radialGradient3839"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,4.9030359,1024.9638)"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833-7"
+       id="radialGradient3839-8"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,4.9030359,1024.9638)"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="linearGradient3833-7">
+      <stop
+         style="stop-color:#f4d779;stop-opacity:1;"
+         offset="0"
+         id="stop3835-5" />
+      <stop
+         style="stop-color:#bd9510;stop-opacity:1;"
+         offset="1"
+         id="stop3837-4" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3831-8"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,1.3722368,813.17816)"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="linearGradient3825-5">
+      <stop
+         style="stop-color:#f3d673;stop-opacity:1;"
+         offset="0"
+         id="stop3827-3" />
+      <stop
+         style="stop-color:#c7a23a;stop-opacity:1;"
+         offset="1"
+         id="stop3829-7" />
+    </linearGradient>
+    <radialGradient
+       r="80.321426"
+       fy="414.17612"
+       fx="407.17349"
+       cy="414.17612"
+       cx="407.17349"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,-153.01531,1007.7817)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3870"
+       xlink:href="#linearGradient3833-7"
+       inkscape:collect="always" />
+    <radialGradient
+       r="80.321426"
+       fy="414.24271"
+       fx="406.47156"
+       cy="414.24271"
+       cx="406.47156"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,-156.54611,795.9961)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3872"
+       xlink:href="#linearGradient3825-5"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833-7"
+       id="radialGradient3908"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,-153.01531,1007.7817)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3910"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,-156.54611,795.9961)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833-7"
+       id="radialGradient3914"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,-153.01531,1007.7817)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3916"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,-156.54611,795.9961)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833-7"
+       id="radialGradient3918"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,-153.01531,1007.7817)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3920"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,-156.54611,795.9961)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833-7"
+       id="radialGradient3924"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,-153.01531,1007.7817)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3926"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,-156.54611,795.9961)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3933"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01462336,-0.89388887,0.97447651,-0.01594169,19.13339,796.92442)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833"
+       id="radialGradient3935"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,4.9030359,1024.9638)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825"
+       id="radialGradient3937"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,1.3722368,813.17816)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833"
+       id="radialGradient3941"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,-75.408823,1015.0037)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825"
+       id="radialGradient3943"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,-78.939622,803.21805)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3949"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01462336,-0.89388887,0.97447651,-0.01594169,19.13339,796.92442)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3953"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01462336,-0.89388887,0.97447651,-0.01594169,19.13339,796.92442)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3957"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01462336,-0.89388887,0.97447651,-0.01594169,-70.86661,796.92442)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3961"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01462336,-0.89388887,0.97447651,-0.01594169,-70.86661,796.92442)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833-79"
+       id="radialGradient3941-1"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,-75.408823,1015.0037)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+    <linearGradient
+       id="linearGradient3833-79">
+      <stop
+         style="stop-color:#f4d779;stop-opacity:1;"
+         offset="0"
+         id="stop3835-55" />
+      <stop
+         style="stop-color:#bd9510;stop-opacity:1;"
+         offset="1"
+         id="stop3837-5" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-3"
+       id="radialGradient3943-5"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,-78.939622,803.21805)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <linearGradient
+       id="linearGradient3825-3">
+      <stop
+         style="stop-color:#f3d673;stop-opacity:1;"
+         offset="0"
+         id="stop3827-0" />
+      <stop
+         style="stop-color:#c7a23a;stop-opacity:1;"
+         offset="1"
+         id="stop3829-2" />
+    </linearGradient>
+    <radialGradient
+       r="80.321426"
+       fy="414.24271"
+       fx="406.47156"
+       cy="414.24271"
+       cx="406.47156"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,91.271992,815.08835)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3985"
+       xlink:href="#linearGradient3825-3"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833"
+       id="radialGradient4029"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,-75.408823,1015.0037)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825"
+       id="radialGradient4031"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,-78.939622,803.21805)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833"
+       id="radialGradient4037"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,71.056847,1015.1237)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833"
+       id="radialGradient4047"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,71.056847,1015.1237)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#595959"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.7"
+     inkscape:cx="-296.38002"
+     inkscape:cy="91.425689"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer2"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:window-width="1920"
+     inkscape:window-height="1027"
+     inkscape:window-x="0"
+     inkscape:window-y="29"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     sodipodi:insensitive="true"
+     style="display:none"
+     transform="translate(-391.875,-406.1875)">
+    <image
+       y="392.14789"
+       x="-90.714287"
+       id="image3047"
+       xlink:href="file:///home/tomasi/Projects/nimrod/logo/new-symbols.png"
+       height="329"
+       width="800" />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     inkscape:label="Layer"
+     style="display:inline"
+     transform="translate(-391.875,-406.1875)">
+    <g
+       id="g4041">
+      <path
+         id="path4019"
+         d="m 474.37925,408.23965 c 0,0 -6.12468,5.3771 -12.34375,10.6875 -6.39764,-0.22532 -18.88846,1.38269 -25.6875,4.125 -6.26333,-4.40055 -11.8125,-9.28125 -11.8125,-9.28125 0,0 -4.69884,9.01564 -7.65625,14.28125 -4.38598,2.58703 -8.76277,5.43142 -12.6875,9.28125 -4.63902,-2.04302 -10.1875,-4.65625 -10.1875,-4.65625 l 6.25,27.875 0.9375,1.875 -1.09375,-1.875 c 0,0 8.86172,24.01192 14.8125,40 25.2159,36.89492 89.61617,39.46428 117.68751,0.71875 5.37871,-13.44336 11.62618,-31.71161 13.90625,-38.4375 l 1.25,-2.8125 5.90625,-26.78125 c 0,0 -6.87234,2.50886 -11.0625,4.28125 -2.40446,-3.40619 -6.05177,-7.01378 -11.25,-9.46875 -3.05538,-6.20497 -7.5,-14.65625 -7.5,-14.65625 0,0 -5.33268,4.38488 -11.4375,9.125 -8.24767,-1.68845 -18.23488,-3.72666 -26.62501,-3.21875 -5.71156,-5.20637 -11.40625,-11.0625 -11.40625,-11.0625 z"
+         style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+         inkscape:connector-curvature="0" />
+      <path
+         sodipodi:nodetypes="cccccccccccccccccccc"
+         inkscape:connector-curvature="0"
+         id="path3054"
+         d="m 400.26095,460.55777 -6.25,-27.85715 c 0,0 5.53955,2.59984 10.17857,4.64286 3.92473,-3.84983 8.2926,-6.69868 12.67858,-9.28571 2.95741,-5.26561 7.67857,-14.28572 7.67857,-14.28572 0,0 5.52238,4.88517 11.78571,9.28572 6.79904,-2.74231 19.31665,-4.33247 25.71429,-4.10715 6.21906,-5.3104 12.32143,-10.71428 12.32143,-10.71428 0,0 5.71701,5.86506 11.42857,11.07143 8.39013,-0.50791 18.35947,1.52583 26.60714,3.21428 6.10482,-4.74012 11.42857,-9.10714 11.42857,-9.10714 0,0 4.44462,8.43789 7.5,14.64286 5.19824,2.45497 8.84554,6.05809 11.25,9.46428 4.19017,-1.77239 11.07143,-4.28571 11.07143,-4.28571 l -5.89286,26.78571 -6.60714,14.82143 c 0,0 -4.31067,-2.70091 -7.32143,-4.28571 -16.93933,-45.69195 -106.71744,-37.02003 -119.46428,-0.71429 -5.78255,1.30574 -8.39286,2.32143 -8.39286,2.32143 z"
+         style="fill:url(#radialGradient4047);fill-opacity:1;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="cccccccccccccc"
+         inkscape:connector-curvature="0"
+         id="path3051"
+         d="m 400.08238,460.55777 c 0,0 8.87064,24.01192 14.82143,40 25.2159,36.89492 89.60723,39.45981 117.67857,0.71428 6.64277,-16.60268 15,-41.60714 15,-41.60714 l -6.07143,11.42857 -7.63525,-0.35714 -11.82903,15 -16.96429,5 -31.07143,-17.85715 -31.25,17.5 -16.96428,-4.82142 -11.54402,-15.59885 -7.56312,2.02742 z"
+         style="fill:#ffffff;stroke:none" />
+      <path
+         sodipodi:nodetypes="scccccccccs"
+         id="path3054-8"
+         d="m 474.88371,439.45394 c 26.96263,-0.0368 50.75931,9.32331 58.9643,31.09821 0.11438,0.0602 0.25716,0.12428 0.375,0.1875 l -0.34375,0 -11.84375,15 -16.93751,5 -31.09375,-17.875 -31.25,17.5 -16.96875,-4.8125 -11.31751,-16.02955 c 6.01205,-17.4758 32.67194,-30.03082 60.41572,-30.06866 z"
+         style="fill:none;stroke:#000000;stroke-width:1.10000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+         inkscape:connector-curvature="0" />
+    </g>
+  </g>
+</svg>
diff --git a/web/assets/images/quotes.png b/web/assets/images/quotes.png
new file mode 100644
index 000000000..0d75b4cc2
--- /dev/null
+++ b/web/assets/images/quotes.png
Binary files differdiff --git a/web/assets/images/sidebar.png b/web/assets/images/sidebar.png
index 77624480e..142db93cf 100644
--- a/web/assets/images/sidebar.png
+++ b/web/assets/images/sidebar.png
Binary files differdiff --git a/web/assets/images/slideshow-nav.png b/web/assets/images/slideshow-nav.png
new file mode 100644
index 000000000..fbfff3e5d
--- /dev/null
+++ b/web/assets/images/slideshow-nav.png
Binary files differdiff --git a/web/assets/images/slideshow-nav_active.png b/web/assets/images/slideshow-nav_active.png
new file mode 100644
index 000000000..525caf355
--- /dev/null
+++ b/web/assets/images/slideshow-nav_active.png
Binary files differdiff --git a/web/assets/images/tabEnd.png b/web/assets/images/tabEnd.png
new file mode 100644
index 000000000..a94af90f1
--- /dev/null
+++ b/web/assets/images/tabEnd.png
Binary files differdiff --git a/web/assets/index.js b/web/assets/index.js
new file mode 100644
index 000000000..f10dc603d
--- /dev/null
+++ b/web/assets/index.js
@@ -0,0 +1,34 @@
+"use strict";
+
+var timer;
+var prevIndex = 0;
+var slideCount = 2;
+
+function setSlideShow(index, short) {
+  if (index >= slideCount) index = 0;
+  document.getElementById("slide"+prevIndex).className = "";
+  document.getElementById("slide"+index).className = "active";
+  document.getElementById("slideControl"+prevIndex).className = "";
+  document.getElementById("slideControl"+index).className = "active";
+  prevIndex = index;
+  startTimer(short ? 8000 : 32000);
+}
+
+function nextSlide() { setSlideShow(prevIndex + 1, true); }
+function startTimer(t) { timer = setTimeout(nextSlide, t); }
+
+function slideshow_enter() { clearTimeout(timer); }
+function slideshow_exit () { startTimer(16000); }
+
+function slideshow_click(index) {
+  clearTimeout(timer);
+  setSlideShow(index, false);
+}
+
+window.onload = function() {
+  var slideshow = document.getElementById("slideshow");
+  slideshow.onmouseenter = slideshow_enter;
+  slideshow.onmouseleave = slideshow_exit;
+  slideCount = slideshow.children.length;
+  startTimer(8000);
+};
\ No newline at end of file
diff --git a/web/assets/style.css b/web/assets/style.css
index 91bb4bd8a..b74cbc486 100644
--- a/web/assets/style.css
+++ b/web/assets/style.css
@@ -1,210 +1,558 @@
+
 * { cursor:default; }
-a, a * { cursor:pointer; text-decoration:none; }
+a, a * { cursor:pointer; }
+
+html { margin:0; overflow-x:auto; }
+body {
+	overflow-x:hidden;
+	min-width:1030px;
+	margin:0;
+	font:13pt "arial";
+	background:#152534 url("images/bg.png") no-repeat center top; 
+	color:rgba(0,0,0,.8); }
 
-html, body {
+pre {
+  color:#fff;
   margin:0;
-  padding:0;
-  width:100%;
-  height:100%;
-  background:#121220;
-  font:14px arial;
-  letter-spacing:1px;
-  line-height:22px;
-}
+  padding:15px 10px;
+  font:10pt monospace;
+  line-height:14pt;
+  background:rgba(0,0,0,.4);
+  border-left:8px solid rgba(0,0,0,.3);
+  box-shadow:1px 2px 16px rgba(28,180,236,.4); }
+pre, pre * { cursor:text; }
+pre .cmt { color:rgb(255,229,106); }
+pre .kwd { color:#43A8CF; font-weight:bold; }
+pre .typ { color:#128B7D; font-weight:bold; }
+pre .atr { color:#128B7D; font-weight:bold; font-style:italic; }
+pre .def { color:#CAD6E4; font-weight:bold; }
+pre .prg { color:#854D6A; font-weight:bold; font-style:italic; }
+pre .val { color:#8AB647; }
+pre .tab { border-left:1px dotted rgba(67,168,207,0.4); }
+pre .end { background:url("images/tabEnd.png") no-repeat left bottom; }
+
+.page pre { background:rgba(0,0,0,.8); }
+.page pre > .Comment { color:rgb(255,229,106); }
+.page pre > .Keyword { color:#43A8CF; font-weight:bold; }
+.page pre > .StringLit,
+.page pre > .DecNumber { color:#8AB647; }
+
+.tall { height:100%; }
+.pre { padding:1px 5px; font:11pt monospace; background:#96A9B7; border-radius:3px; }
+
+.page-layout { margin:0 auto; width:1000px; }
+.docs-layout { margin:0 40px; }
+.talk-layout { margin:0 40px; }
+.wide-layout { margin:0 auto; }
 
-#site { z-index:0; position:relative; margin:0 auto; width:960px; }
-#site > dive { position:relative; }
+#head { height:100px; background:url("images/head.png") repeat-x bottom; }
+#head.docs { margin-left:280px; background:rgba(0,0,0,.25) url("images/head-fade.png") no-repeat right top; }
+#head > div { position:relative }
+	
+	#head-logo {
+		position:absolute;
+		left:-390px;
+		top:0;
+		width:917px;
+		height:268px;
+		pointer-events:none;
+		background:url("images/logo.png") no-repeat; }
+	#head.docs #head-logo { left:-381px; position:fixed; }
+	#head.forum #head-logo { left:-370px; }
+	
+  #head-logo-link {
+    position:absolute;
+    display:block;
+    top:10px;
+    left:10px;
+    width:236px;
+    height:85px; }
+  #head.docs #head-logo-link { left:-260px; }
+  #head.forum #head-logo-link { left:30px; }
+	
+	#head-links { position:absolute; right:0; bottom:13px; }
+	#head.docs #head-links,
+	#head.forum #head-links { right:20px; }
+	#head-links > a {
+		display:block;
+		float:left;
+		padding:10px 25px 25px 25px;
+		color:rgba(255,255,255,.5);
+		font-size:14pt;
+		text-decoration:none;
+		letter-spacing:1px;
+		background:url("images/head-link.png") no-repeat center bottom;
+		transition:
+			color 0.3s ease-in-out,
+			text-shadow 0.4s ease-in-out; }
+	#head-links > a:hover,
+	#head-links > a.active {
+		color:#1cb3ec;
+		text-shadow:0 0 4px rgba(28,179,236,.8);
+		background-image:url("images/head-link_hover.png"); }
 
-  /* site_head */
-  #site_head { z-index:0; height:200px; }
+	#head-banner { width:200px; height:100px; background:#000; }
+
+#neck { z-index:0; height:40px; }
+#neck.home { height:370px; }
+#neck > div { position:relative }
+	
+	#glow-arrow {
+		position:absolute;
+		top:-9px;
+		left:0;
+		right:-16px;
+		height:48px;
+		background:url("images/glow-arrow.png") no-repeat right; }
+  #glow-arrow.docs { left:280px; }
+	
+	#glow-line-vert {
+		position:fixed;
+		top:100px;
+		left:280px;
+		width:3px;
+		height:844px;
+		background:url("images/glow-line-vert.png") no-repeat; }
+	
+	#slideshow { position:absolute; top:10px; left:10px; width:700px; height: 1000px; }
+	#slideshow > div {
+    position:absolute;
+    margin:30px 0 0 10px;
+    visibility:hidden;
+    opacity:0;
+    transition:
+      visibility 0s linear 1s,
+      opacity 1s ease-in-out; }
+	#slideshow > div.active { visibility:visible; opacity:1; transition-delay:0s; }
+	#slideshow > div.init { transition-delay:0s; }
+	#slideshow-nav { z-index:3; position:absolute; top:110px;; right:-12px; }
+	#slideshow-nav > div { margin:5px 0; width:23px; height:23px; background:url("images/slideshow-nav.png") no-repeat; }
+	#slideshow-nav > div:hover { background-image:url("images/slideshow-nav_active.png"); opacity:0.5; }
+	#slideshow-nav > div.active { background-image:url("images/slideshow-nav_active.png"); opacity:1; }
     
-    #logo {
-      z-index:-1;
-      position:absolute;
-      top:-35px;
-      left:-330px;
-      width:868px;
-      height:334px;
-      background:url("images/logo.png") no-repeat;
-    }
-  
-  /* site_neck */
-  #site_neck { z-index:1; float:left; width:100%; height:40px; background:url("images/site_neck.png") bottom no-repeat; }
-  
-    #site_neck > a {
-      display:block;
-      float:left;
-      margin-top:3px;
-      margin-right:10px;
-      padding:4px 20px 0 20px;
-      height:28px;
-      color:#959a9b;
-      background:#394649;
-      font-size:18px;
-    }
+		#slide0 { float:left; width:680px; font:10pt monospace; }
+		#slide0 > div:first-child { margin:0 40px 0 0; }
+		#slide0 h2 { margin:0 0 5px 0; color:rgba(162,198,223,.78); }
+		#slide0 .desc { margin:0 0 5px 0; color:rgba(162,198,223,.78); font:13pt "arial"; }
+		
+		#slide1 > div { float:left; width:320px; font:10pt monospace; }
+		#slide1 > div:first-child { margin:0 40px 0 0; }
+		#slide1 h2 { margin:0 0 5px 0; color:rgba(162,198,223,.78); }
+    
+		#slide2 > div { float:left; width:320px; font:10pt monospace; }
+		#slide2 > div:first-child { margin:0 40px 0 0; }
+		#slide2 h2 { margin:0 0 5px 0; color:rgba(162,198,223,.78); }
     
-    #site_neck > a:hover {
-      margin-top:0;
-      border-top:3px solid #1cb4ec;
-    }
-  
-    #site_neck > a.active {
-      margin-top:0;
-      padding-top:7px;
-      color:#fff;
-      background:#1cb4ec;
-      text-shadow:0 0 4px rgba(255,255,255,0.75);
-    }
+		#slide2 .desc { margin:0 0 5px 0; color:rgba(162,198,223,.78); font:13pt "arial"; }
+    
+		/* back when slide1 was the quote:
+		#slide1 { margin-top:50px; }
+		#slide1 > p {
+			padding:40px 20px 0 20px;
+			font-style:italic;
+			color:rgba(162,198,223,.78);
+			letter-spacing:1px;
+			line-height:25pt;
+			background:url("images/quotes.png") top left no-repeat; }
+		#slide1 > div {
+			float:right;
+			margin-right:40px;
+			font-style:italic;
+			font-weight:bold;
+			color:rgba(93,155,199,.44); }
+    */
+	#sidebar {
+		z-index:2;
+		position:absolute;
+		top:5px; right:0;
+		width:275px;
+		height:726px;
+		padding:210px 0 0 0;
+		background:url("images/sidebar.png") no-repeat; }
+	#sidebar > h3 { margin:0 30px 0 30px; color:rgba(255,255,255,.5); }
+	#sidebar > h3.blue { color:rgba(28,180,236,.5); }
+	#sidebar-links,
+	#sidebar-news {
+		margin:10px 30px 50px 30px;
+		padding:10px 0;
+		background:rgba(0,0,0,.6); }
+	#sidebar-links { box-shadow:1px 2px 12px rgba(255,255,255,.4); }
+	#sidebar-news { box-shadow:1px 2px 12px rgba(28,180,236,.6); }
+	#sidebar-links > a {
+		display:block;
+		margin-left:15px;
+		padding:12px 20px 12px 45px;
+		font-weight:bold;
+		text-decoration:none;
+		letter-spacing:1px;
+		color:rgba(255,255,255,.4);
+		transition:
+			color 0.1s ease-in-out,
+			text-shadow 0.2s ease-in-out; }
+	#sidebar-news > a { transition: color 0.3s ease-in-out; }
+	#sidebar-news > a > h4 { transition: color 0.1s ease-in-out, text-shadow 0.2s ease-in-out; }
+	#sidebar-links > a:hover { color:#fff; text-shadow:0 0 6px #fff; }
+	#sidebar-news > a { display:block; padding:15px; color:rgba(255,255,255,.4); text-decoration:none; }
+	#sidebar-news > a > h4 { margin:0 0 5px 0; color:rgba(28,180,236,.5); }
+	#sidebar-news > a:hover > h4 { margin:0 0 5px 0; color:rgba(28,180,236,.8); text-shadow:0 0 6px rgba(28,180,236,.6); }
+	#sidebar-news > a:hover { color:rgba(255,255,255,1); }
+	#sidebar-news > a.blue { color:rgba(28,180,236,.5); font-weight:bold; }
+	#sidebar-news > a.blue:hover { color:#fff; }
+		
+		#link_forum { background:url("images/more-links_forum.png") no-repeat left center; }
+		#link_github { background:url("images/more-links_github.png") no-repeat left center; }
+		#link_editors { background:url("images/more-links_editors.png") no-repeat left center; }
+		#link_aporia { background:url("images/more-links_editors.png") no-repeat left center; }
+		#link_nimbuild { background:url("images/more-links_nimbuild.png") no-repeat left center; }
+	
+	#overview-bg {
+		position:fixed;
+		top:0;
+		bottom:0;
+		left:0;
+		width:280px;
+		background:rgba(0,0,0,0.25); }
+	#overview {
+		z-index:3;
+		position:fixed;
+		overflow:auto;
+		top:115px;
+		bottom:20px;
+		left:20px;
+		width:245px; }
+	#overview::-webkit-scrollbar { width:5px; }
+	#overview::-webkit-scrollbar-track { border-radius:2px; background:rgba(255,255,255,.03); }
+	#overview::-webkit-scrollbar-thumb { border-radius:2px; background:rgba(28,179,236,.5); }
+	#overview > div { overflow:auto; margin-bottom:40px; }
+	#overview a {
+		display:block;
+		padding:0 10px;
+		margin:2px 5px 2px 0;
+		color:rgba(255,255,255,.6);
+		background:rgba(255,255,255,0.03);
+    border-radius:2px;
+		letter-spacing:1px;
+		text-decoration:none; }
+	#overview a:hover { color:#fff; background:rgba(255,255,255,0.05); }
+	#overview > .types a { border-left:2px solid rgba(28,179,236,.4); }
+	#overview > .procs a { border-left:2px solid rgba(255,223,53,.4); }
+	#overview > .iters a { border-left:2px solid rgba(255,134,53,.4); }
+	#overview > div > h4 {
+		margin:0 5px 10px 0;
+		padding:5px 10px;
+		letter-spacing:1px;
+		color:#fff;
+		border-left:2px solid #fff;
+    border-radius:2px;
+		background:rgba(255,255,255,0.1); }
+	#overview > .types h4 { color:#1cb3ec; border-color:#1cb3ec; }
+	#overview > .procs h4 { color:#ffdf35; border-color:#ffdf35; }
+	#overview > .iters h4 { color:#ff8635; border-color:#ff8635; }
+	#overview h5 {
+		color:rgba(28,179,236,.6);
+		margin:10px 0 5px 0;
+		padding:5px 5px;
+		letter-spacing:1px; }
+
+#body { z-index:1; position:relative; background:rgba(220,231,248,0.8); }
+#body.docs { margin:0 40px 20px 320px; }
+#body.forum { margin:0 40px 20px 40px; }
+	
+	#body-border {
+		position:absolute;
+		top:-25px;
+		left:0;
+		right:0;
+		height:35px;
+		background:rgba(0,0,0,.25); }
+	
+	#body-border-left {
+		position:absolute;
+		left:-25px;
+		top:-25px;
+		bottom:-25px;
+		width:35px;
+		background:rgba(0,0,0,.25); }
+	
+	#body-border-right {
+		position:absolute;
+		right:-25px;
+		top:-25px;
+		bottom:-25px;
+		width:35px;
+		background:rgba(0,0,0,.25); }
+	
+	#body-border-bottom {
+		position:absolute;
+		left:10px;
+		right:10px;
+		bottom:-25px;
+		height:35px;
+		background:rgba(0,0,0,.25); }
+	
+	#body.docs #body-border,
+	#body.forum #body-border { left:10px; right:10px; }
+	
+	#glow-line {
+		position:absolute;
+		top:-27px;
+		left:100px;
+		right:-25px;
+		height:3px;
+		background:url("images/glow-line.png") no-repeat left; }
+	#glow-line-bottom {
+		position:absolute;
+		bottom:-27px;
+		left:-25px;
+		right:100px;
+		height:3px;
+		background:url("images/glow-line2.png") no-repeat right; }
+	
+	#content { padding:40px 0; line-height:150%; }
+	#content.page { width:680px; min-height:800px; padding-left:20px; }
+	#content h1 { font-size:20pt; letter-spacing:1px; color:rgba(0,0,0,.75); }
+	#content h2 { font-size:16pt; letter-spacing:1px; color:rgba(0,0,0,.7); margin-top:40px; }
+	#content p { text-align:justify; }
+	#content a { color:#0E65D1; text-decoration:none; }
+	#content a:hover { text-decoration:underline; }
+	#content ul { padding-left:20px; }
+	#content li { margin-bottom:10px; text-align:justify; }
+	
+		#body.docs #content > div { margin-top:40px; padding-top:40px; border-top:1px dashed rgba(0,0,0,.25); }
+		#body.docs #content > div:first-child { margin-top:0; padding-top:0; border:none; }
+		#body.docs #content > div > h3 {
+			color:#fff;
+			margin:0 0 10px 0;
+			padding:10px 20px;
+			letter-spacing:1px;
+			border-left:8px solid #fff;
+      border-radius:3px;
+			background:rgba(0,0,0,.7);
+			box-shadow:1px 3px 12px rgba(0,0,0,.4); }
+		#body.docs #content > #types-wrap > h3 { color:#1cb3ec; border-color:#1cb3ec; }
+		#body.docs #content > #procs-wrap > h3 { color:#ffdf35; border-color:#ffdf35; }
+		#body.docs #content > #iters-wrap > h3 { color:#ff8635; border-color:#ff8635; }
+		#body.docs #content > div > div > div {
+			overflow:auto;
+			margin:10px 0;
+			border-left:8px solid #fff;
+      border-radius:3px;
+			background:rgba(0,0,0,.1); }
+		#body.docs #content > #types-wrap > div > div { border-color:rgba(28,179,236,.5); }
+		#body.docs #content > #procs-wrap > div > div { border-color:rgba(255,223,53,.5); }
+		#body.docs #content > #iters-wrap > div > div { border-color:rgba(255,134,53,.5); }
+		#body.docs #content > #procs-wrap > div > div.overload-head { margin-bottom:0; }
+		#body.docs #content > #procs-wrap > div > div.overload-tail { margin-top:0; border-top:1px dashed rgba(255,223,53,.5); }
+		#body.docs #content > #procs-wrap > div > div.overload { margin-top:0; margin-bottom:0; border-top:1px dashed rgba(255,223,53,.5); }
+		#body.docs #content > #iters-wrap > div > div.overload-head { margin-bottom:0; }
+		#body.docs #content > #iters-wrap > div > div.overload-tail { margin-top:0; border-top:1px dashed rgba(255,134,53,.5); }
+		#body.docs #content > #iters-wrap > div > div.overload { margin-top:0; margin-bottom:0; border-top:1px dashed rgba(255,134,53,.5); }
+		#body.docs #content > div > div > p { margin:20px 10px 10px 10px; }
+		
+		#body.docs #content > div > div > div > div { float:left; }
+		#body.docs #content > div > div > div > div.head { width:60%; }
+		#body.docs #content > div > div > div > div.data { width:40%; }
     
-    #site_neck > a.active:hover {
+    #body.docs #content > h1 > .symbol {
+      padding:0 8px;
+      border-radius:5px;
+      background:rgba(206,218,233,.4); }
+    
+		#body.docs #content > div > div > div > div.head > .sign {
+			margin:0 10px 5px 10px;
+			padding:10px 10px 0 10px;
+			font-weight:bold;
+			border-bottom:1px dashed rgba(0,0,0,.25); }
+		#body.docs #content > div > div > div > div.head > .desc {
+			padding:0 20px 10px 20px;
+			color:rgba(0,0,0,.75); }
+		#body.docs #content > div > #types > div > div.head > .sign > .symbol {
+			padding:0 5px;
+			border-radius:3px;
+			background:rgba(28,179,236,.4); }
+		#body.docs #content > div > #procs > div > div.head > .sign > .symbol {
+			padding:0 5px;
+			border-radius:3px;
+			background:rgba(255,223,53,.3); }
+		#body.docs #content > div > #iters > div > div.head > .sign > .symbol {
+			padding:0 5px;
+			border-radius:3px;
+			background:rgba(255,134,53,.3); }
+			
+		#body.docs #content > div > div > div > div.data > div {
+			margin:0 20px 5px 10px;
+			padding:10px 0 0 10px;
+			font-style:italic;
+			color:rgba(0,0,0,.6);
+			border-bottom:1px dashed rgba(0,0,0,.25); }
+		#body.docs #content > div > div > div > div.data > ul { margin:0; padding:0 10px; }
+		#body.docs #content > div > div > div > div.data > ul:last-child { margin-bottom:5px; padding-bottom:10px; }
+		#body.docs #content > div > div > div > div.data > ul .symbol { padding:0 5px; border-radius:3px; background:rgba(23,192,23,.25); }
+		#body.docs #content > div > div > div > div.data > ul.pragmas .symbol { background:rgba(106,50,145,.25); }
+		#body.docs #content > div > div > div > div.data > ul > li { margin:0; padding:0 10px; list-style:none; }
+		
+		#body.docs #content pre {
+			overflow:auto;
+			margin:10px 0;
+			padding:15px 10px;
+			font-size:10pt;
+			font-style:normal;
+			line-height:14pt;
+			background:rgba(0,0,0,.75);
+			border-left:8px solid rgba(0,0,0,.3); }
+    
+    #docs-sort { float:right; font-size:75%; }
+    #docs-sort > a {
+      cursor:default;
+      margin:0 0 0 10px;
+      padding:2px 10px;
+      border-radius:5px;
+      color:rgba(0,0,0,.25);
+      background:rgba(0,0,0,.1);
+      box-shadow:inset 0 1px 8px rgba(0,0,0,.4); }
+    #docs-sort > a:hover,
+    #docs-sort > a.active { color:#000; background:rgba(0,0,0,.2); }
+    
+    #talk-heads { overflow:auto; margin:0 8px 0 8px; }
+    #talk-heads > div { float:left; font-size:120%; font-weight:bold; }
+    #talk-heads > .topic { width:55%; }
+    #talk-heads > .detail { width:15%; }
+    #talk-heads > .author { width:15%; }
+    #talk-heads > .reply { width:15%; }
+    #talk-heads > div > div { margin:0 10px 10px 10px; padding:0 10px 10px 10px; border-bottom:1px dashed rgba(0,0,0,0.4); }
+    #talk-heads > .topic > div { margin-left:0; }
+    #talk-heads > .author > div { margin-right:0; }
+    
+    #talk-thread  > div,
+    #talk-threads > div {
+      position:relative;
+      margin:5px 0;
+      overflow:auto;
+      border-radius:3px;
+      border:8px solid rgba(0,0,0,.8);
       border-top:none;
-    }
-  
-  /* site_body */
-  #site_body { z-index:2; float:left; clear:both; width:100%; background:#d1dbe3; }
+      border-bottom:none;
+      background:rgba(0,0,0,0.1); }
+    #talk-thread  > div:nth-child(odd) { background:rgba(255,255,255,0.1); }
+    #talk-threads > div:nth-child(odd) { background:rgba(0,0,0,0.2); }
+    #talk-thread  > div > div,
+    #talk-threads > div > div { float:left; }
+    #talk-thread  > div > div > div,
+    #talk-threads > div > div > div { margin:10px 20px; }
+    #talk-threads > div > .topic { width:55%; }
+    #talk-threads > div > .reply { width:15%; overflow:hidden; }
+    #talk-threads > div > .detail { width:15%; overflow:hidden; }
+    #talk-thread  > div > .author,
+    #talk-threads > div > .author {
+      position:absolute;
+      right:0;
+      top:0;
+      bottom:0;
+      width:15%;
+      overflow:hidden;
+      background:rgba(0,0,0,0.8); }
+    #talk-thread  > div > .author a,
+    #talk-threads > div > .author a { color:#1cb3ec !important; }
+    #talk-thread  > div > .author a:hover,
+    #talk-threads > div > .author a:hover { color:#fff !important; }
+    #talk-threads > div > .topic .pages { float:right; }
+    #talk-threads > div > .topic > div > a { font-weight:bold; }
+    #talk-threads > div > .detail > div { float:left; margin:0; }
+    #talk-threads > div > .detail > div > div { margin-left:20px; padding:10px 10px 10px 22px; }
+    #talk-threads > div > .detail > div { width:50%; }
+    #talk-threads > div > .detail > div:first-child > div { background:url("images/forum-views.png") no-repeat left; }
+    #talk-threads > div > .detail > div:last-child > div { background:url("images/forum-posts.png") no-repeat left; }
     
-    #page { position:relative; float:left; padding:20px 30px 50px 50px; width:620px; color:#343739; }
-      
-      #page h1 { margin-top:40px; line-height: 28px; }
-      #page h2 { margin-top:40px; }
-      
-      #page p { text-align:justify; }
-      
-      #page .quote-image {
-        z-index:0;
-        position:absolute;
-        top:15px;
-        left:20px;
-        width:59px;
-        height:42px;
-        background:url("images/quote.png") no-repeat;
-      }
-      
-      #page p.quote {
-        position:relative;
-        color:#6187a2;
-        font-style:italic;
-        letter-spacing:2px;
-        word-spacing:1px;
-      }
-      
-      #page pre {
-        padding:20px;
-        border-left:10px solid #8f9698;
-        background:#f3f6f8;
-        font-size:15px;
-        font-family:courier, monospace;
-        letter-spacing:0;
-        line-height:17px;
-      }
-      
-      #page span.pre {
-        background-color: #E6EDF2;
-        padding: 1pt 3pt;
-        border-radius: 2pt;
-        -moz-border-radius: 2pt;
-        -webkit-border-radius: 2pt;
-      }
-      
-      #page pre > .Comment { color:#858686; font-style:italic; }
-      #page pre > .Keyword { color:#1cb4ec; font-weight:bold; }
-      #page pre > .Operator { color:#777; }
-      #page pre > .StringLit, #page pre > .DecNumber { color:#ff7302; }
-      
-      #page li { margin-top:10px; }
-      
-      #page a:hover { text-decoration: underline; }
+    #talk-thread > div {  margin:20px 0; min-height:150px; box-shadow:1px 3px 12px rgba(0,0,0,.4) }
+    #talk-thread > div > .author > div > .avatar { margin-top:20px; }
+    #talk-thread > div > .author > div > .avatar > img { box-shadow:0 0 12px #1cb3ec; }
+    #talk-thread > div > .author > div > .name { }
+    #talk-thread > div > .topic { width:85%; padding-bottom:10px; }
+    #talk-thread > div > .topic pre {
+      overflow:auto;
+      margin:0;
+      padding:15px 10px;
+      font-size:10pt;
+      font-style:normal;
+      line-height:14pt;
+      background:rgba(0,0,0,.75);
+      border-left:8px solid rgba(0,0,0,.3); }
     
-      #page table.docutils {
-        background: none repeat scroll 0 0 #F3F6F8;
-        border-collapse: collapse;
-        font-size: 8pt;
-        text-align: left;
-        width: 480px;
-        border-spacing: 0;
-      }
-      
-      #page .docutils th {
-        border-bottom: 2px solid #1a1a1a;
-        font-size: 14px;
-        font-weight: normal;
-        padding: 8px 8px;
-      }
-      
-      #page .docutils td {
-        padding: 3px 8px;
-        color: #4d4d4d;
-      }
+    #talk-head,
+    #talk-info {
+      overflow:auto;
+      border-radius:3px;
+      border:8px solid rgba(0,0,0,.2);
+      border-top:none;
+      border-bottom:none;
+      background:rgba(0,0,0,0.1); }
+    #talk-head { margin-bottom:20px; }
+    #talk-info { margin-top:20px; }
+    #talk-head > div,
+    #talk-info > div { float:left; }
+    #talk-head > .info,
+    #talk-info > .info { width:85%; }
+    #talk-head > .user,
+    #talk-info > .user { width:15%; background:rgba(0,0,0,.2); }
+    #talk-info > .user > div > .reply { font-weight:bold; padding-left:22px; background:url("images/forum-reply.png") no-repeat left; }
+    #talk-head > div > div,
+    #talk-info > div > div { padding:5px 20px; }
+    #talk-head > .detail > div { float:left; margin:0; }
+    #talk-head > .detail > div > div { padding-left:22px; }
+    #talk-head > .detail > div:first-child > div { background:url("images/forum-views.png") no-repeat left; }
+    #talk-head > .detail > div:last-child > div { background:url("images/forum-posts.png") no-repeat left; }
     
-    #sidebar_wrap { float:right; width:260px; }
-      #sidebar {
-        z-index:0;
-        position:relative;
-        left:20px;
-        padding:0 10px 60px 10px;
-        width:200px;
-        background:#394649 url("images/sidebar.png") bottom no-repeat;
-      }
-        
-        #sidebar_head {
-          z-index:-1;
-          position:absolute;
-          top:-220px;
-          left:-30px;
-          width:282px;
-          height:400px;
-          background:url("images/sidebar_head.png") top no-repeat;
-        }
-        
-        #sidebar > h2 {
-          position:relative;
-          left:-40px;
-          margin:20px 0 0 0;
-          padding:19px 0 0 48px;
-          width:204px;
-          height:47px;
-          color:#fff;
-          background:url("images/sidebar_h2.png") no-repeat;
-          text-shadow:0 0 4px rgba(255,255,255,0.75);
-          letter-spacing:2px;
-        }
-        
-        #sidebar > .news { display:block; margin-bottom:20px; padding:0 10px; }
-        #sidebar > .news > h3 { margin:0; color:#cdd1d1; font-size:18px; letter-spacing:2px; }
-        #sidebar > .news > p { margin:0; color:#99a0a1; }
-        #sidebar > .news:hover > h3 { color:#fff; text-shadow:0 0 4px rgba(255,255,255,0.75); }
-        #sidebar > .news:hover > p { color:#eee; text-shadow:0 0 4px rgba(255,255,255,0.5); }
-        
-        #sidebar > .link {
-          display:block;
-          margin:0;
-          padding:15px 20px 0 20px;
-          height:41px;
-          color:#cdd1d1;
-          font-size:18px;
-          font-weight:bold;
-        }
-        
-        #sidebar > .link:hover {
-          color:#fff;
-          text-shadow:0 0 4px rgba(255,255,255,0.75);
-        }
-        
-        #link_forum { background:url("images/link_forum.png") top right no-repeat; }
-        #link_aporia { background:url("images/link_aporia.png") top right no-repeat; }
-        #link_nimbuild { background:url("images/link_nimbuild.png")  top right no-repeat; }
-  
-  /* site_foot */
-  #site_foot { z-index:3; clear:both; padding-top:40px; height:150px; background:url("images/site_foot.png") top no-repeat; }
+    #talk-nav { margin:20px 8px 0 8px; padding-top:10px; border-top:1px dashed rgba(0,0,0,0.4); text-align:center; }
+    #talk-nav > a.active { text-decoration:underline !important; }
     
-    #legal {
-      float:right;
-      margin-top:10px;
-      color:#88888f;
-      font-size:12px;
-      letter-spacing:1px;
-    }
+    .standout {
+      padding:5px 30px;
+      margin-bottom:20px;
+      border:8px solid rgba(0,0,0,.8);
+      border-right-width:16px;
+      border-top-width:0;
+      border-bottom-width:0;
+      border-radius:3px;
+      background:rgba(0,0,0,0.1);
+      box-shadow:1px 3px 12px rgba(0,0,0,.4); }
+    .standout h2 { margin-bottom:10px; padding-bottom:10px; border-bottom:1px dashed rgba(0,0,0,.8); }
+    .standout li { margin:0 !important; padding-top:10px; border-top:1px dashed rgba(0,0,0,.2); }
+    .standout ul { padding-bottom:5px; }
+    .standout .tools     ul { list-style:url("images/docs-tools.png"); }
+    .standout .libraries ul { list-style:url("images/docs-libraries.png"); }
+    .standout .internals ul { list-style:url("images/docs-internals.png"); }
+    .standout .tutorials ul { list-style:url("images/docs-tutorials.png"); }
+    .standout .examples  ul { list-style:url("images/docs-examples.png"); }
+    .standout .articles  ul { list-style:url("images/docs-articles.png"); }
+    .standout li:first-child { padding-top:0; border-top:none; }
+    .standout li p { margin:0 0 10px 0 !important; line-height:130%; }
+    .standout li p > a { font-weight:bold; }
     
-    #legal > a { color:#88888f; }
-    #legal > a:visited { color:#88888f; }
-    #legal > a:hover { color:#fff; }
+    .forum-user-info,
+    .forum-user-info * { cursor:help }
+
+#foot { height:150px; position:relative; top:-10px; letter-spacing:1px; }
+#foot.home { background:url("images/foot.png") repeat-x top; height:200px; }
+#foot.docs { margin-left:320px; margin-right:40px; }
+#foot.forum { margin-left:40px; margin-right:40px; }
+#foot > div { position:relative; }
+#foot.home > div { width:960px; }
+#foot h4 { font-size:11pt; color:rgba(255,255,255,.4); margin:40px 0 6px 0; }
+#foot a:hover { color:#fff; }
+	
+	#foot-links { float:left; }
+	#foot-links > div { float:left; padding:0 40px 0 0; line-height:120%; }
+	#foot-links a { display:block; font-size:10pt; color:rgba(255,255,255,.3); text-decoration:none; }
+	#foot-legal { float:right; font-size:10pt; color:rgba(255,255,255,.3); line-height:150%; text-align:right; }
+	#foot-legal a { color:inherit; text-decoration:none; }
+	#foot-legal > h4 > a { color:inherit; }
+
+
+#body .docutils th {
+    border-bottom: 2px solid #1A1A1A;
+    font-weight: normal;
+    padding: 8px; }
+#body table.docutils {
+    border-collapse: collapse;
+    text-align: left;
+    border-spacing: 0px; }
diff --git a/web/community.txt b/web/community.txt
index bac5e0ada..5d9343c98 100644
--- a/web/community.txt
+++ b/web/community.txt
@@ -1,97 +1,124 @@
-Forum
-=====
+Nim's Community
+===============
 
-The `Nim forum <http://forum.nim-lang.org/>`_ is the place where most 
-discussions related to the language happen. It not only includes discussions
-relating to the design of Nim but also allows for beginners to ask questions
-relating to Nim.
+.. container:: standout
 
-IRC
-====
+  Forum
+  -----
 
-Many Nim developers are a part of the
-`#nim IRC channel <http://webchat.freenode.net/?channels=nim>`_ on
-Freenode. That is the place where the rest of the discussion relating to Nim
-occurs. Be sure to join us there if you wish to discuss Nim in real-time.
-IRC is the perfect place for people just starting to learn Nim and we
-welcome any questions that you may have!
+  The `Nim forum <http://forum.nim-lang.org/>`_ is the place where most 
+  discussions related to the language happen. It not only includes discussions
+  relating to the design of Nim but also allows for beginners to ask questions
+  relating to Nim.
 
-You may also be interested in reading the
-`IRC logs <http://build.nim-lang.org/irclogs/>`_ which are an archive of all
-of the previous discussions that took place in the IRC channel.
 
-Github
-======
+.. container:: standout
 
-Nim's `source code <http://github.com/Araq/Nim>`_ is hosted on Github.
-Together with the `wiki <http://github.com/Araq/Nim/wiki>`_ and
-`issue tracker <http://github.com/Araq/Nim/issues>`_.
+  Mailing list
+  ------------
 
-Github also hosts other projects relating to Nim. These projects are a part
-of the `nim-lang organisation <http://github.com/nim-lang>`_.
-This includes the `Babel package manager <http://github.com/nim-lang/babel>`_
-and its `package repository <http://github.com/nim-lang/packages>`_. 
+  The mailing list can be found here: http://www.freelists.org/list/nim-dev
+  There is no consensus yet about what is discussed via the forum as opposed
+  to the mailing list. Join whatever you like!
 
-Twitter
-=======
 
-Follow us `@nimlang <http://twitter.com/nimlang>`_ for latest news about
-Nim.
+.. container:: standout
 
-Reddit
-======
+  IRC
+  ----
 
-Subscribe to `/r/nim <http://reddit.com/r/nim>`_ for latest news about
-Nim.
+  Many Nim developers are a part of the
+  `#nim IRC channel <http://webchat.freenode.net/?channels=nim>`_ on
+  Freenode. That is the place where the rest of the discussion relating to Nim
+  occurs. Be sure to join us there if you wish to discuss Nim in real-time.
+  IRC is the perfect place for people just starting to learn Nim and we
+  welcome any questions that you may have!
 
-StackOverflow
-=============
+  You may also be interested in reading the
+  `IRC logs <http://irclogs.nim-lang.org/>`_ which are an archive of all
+  of the previous discussions that took place in the IRC channel.
 
-When asking a question relating to Nim, be sure to use the
-`Nim <http://stackoverflow.com/questions/tagged/nim>`_ tag in your 
-question.
 
-How to help
-===========
+.. container:: standout
 
-There are always many things to be done in the main
-`Nim repository <https://github.com/Araq/Nim>`_, check out the 
-`issues <https://github.com/Araq/Nim/issues>`_ for 
-things to do; pull requests are always welcome. You can
-also contribute to the many other projects hosted by the
-`nim-lang <https://github.com/nim-lang>`_ organisation on github. If you
-can't find anything you fancy doing, you can always ask for inspiration on IRC
-(irc.freenode.net #nim) or on the `Nim forums <http://forum.nim-lang.org>`_.
+  Github
+  ------
 
-Donations
----------
+  Nim's `source code <http://github.com/Araq/Nim>`_ is hosted on Github.
+  Together with the `wiki <http://github.com/Araq/Nim/wiki>`_ and
+  `issue tracker <http://github.com/Araq/Nim/issues>`_.
 
-If you love what we do and are feeling generous then you can always donate.
-Contributions of any quantity are greatly appreciated and will contribute to
-making Nim even better!
+  Github also hosts other projects relating to Nim. These projects are a part
+  of the `nim-lang organisation <http://github.com/nim-lang>`_.
+  This includes the `Nimble package manager <https://github.com/nim-lang/nimble>`_
+  and its `package repository <http://github.com/nim-lang/packages>`_. 
 
-Gittip
-``````
 
-  .. raw:: html
+.. container:: standout
 
-    <iframe style="border: 0; margin: 0; padding: 0;"
-             src="https://www.gittip.com/Araq/widget.html"
-             width="48pt" height="22pt"></iframe>
+  Twitter
+  -------
 
-Paypal
-``````
+  Follow us `@nim_lang <http://twitter.com/nim_lang>`_ for latest news about
+  Nim.
 
-  .. raw:: html
+.. container:: standout
 
-    <form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
-    <input type="hidden" name="cmd" value="_s-xclick">
-    <input type="hidden" name="hosted_button_id" value="ZQC6CVEEYNTLN">
-    <input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
-    <img alt="" border="0" src="https://www.paypalobjects.com/de_DE/i/scr/pixel.gif" width="1" height="1">
-    </form>
+  Reddit
+  ------
 
-Bitcoin
-```````
+  Subscribe to `/r/nim <http://reddit.com/r/nim>`_ for latest news about
+  Nim.
 
-  Bitcoin address: 1BXfuKM2uvoD6mbx4g5xM3eQhLzkCK77tJ
+.. container:: standout
+
+  StackOverflow
+  -------------
+
+  When asking a question relating to Nim, be sure to use the
+  `Nim <http://stackoverflow.com/questions/tagged/nim>`_ tag in your 
+  question.
+
+.. container:: standout
+
+  How to help
+  -----------
+
+  There are always many things to be done in the main
+  `Nim repository <https://github.com/Araq/Nim>`_, check out the 
+  `issues <https://github.com/Araq/Nim/issues>`_ for 
+  things to do; pull requests are always welcome. You can
+  also contribute to the many other projects hosted by the
+  `nim-lang <https://github.com/nim-lang>`_ organisation on github. If you
+  can't find anything you fancy doing, you can always ask for inspiration on IRC
+  (irc.freenode.net #nim) or on the `Nim forums <http://forum.nim-lang.org>`_.
+
+
+.. container:: standout
+
+  Donations
+  ---------
+
+  If you love what we do and are feeling generous then you can always donate.
+  Contributions of any quantity are greatly appreciated and will contribute to
+  making Nim even better!
+
+  Gittip
+    .. raw:: html
+
+      <iframe style="border: 0; margin: 0; padding: 0;"
+               src="https://www.gittip.com/Araq/widget.html"
+               width="64pt" height="22pt"></iframe>
+
+  Paypal
+    .. raw:: html
+
+      <form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
+      <input type="hidden" name="cmd" value="_s-xclick">
+      <input type="hidden" name="hosted_button_id" value="ZQC6CVEEYNTLN">
+      <input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+      <img alt="" border="0" src="https://www.paypalobjects.com/de_DE/i/scr/pixel.gif" width="1" height="1">
+      </form>
+
+  Bitcoin
+    Bitcoin address: 1BXfuKM2uvoD6mbx4g5xM3eQhLzkCK77tJ
diff --git a/web/documentation.txt b/web/documentation.txt
index da0313c32..dbb737cd9 100644
--- a/web/documentation.txt
+++ b/web/documentation.txt
@@ -1 +1,56 @@
-.. include:: ../doc/docs.txt
+Nim's Documentation
+===================
+
+.. container:: standout
+
+  Standards & Guides
+  ------------------
+
+  .. container:: libraries
+
+    - | `Standard Library <lib.html>`_
+      | This document describes Nim's standard library.
+
+    - | `Language Manual <manual.html>`_
+      | The Nim manual is a draft that will evolve into a proper specification.
+
+    - | `Compiler User Guide <nimc.html>`_
+      | The user guide lists command line arguments, special features of the
+        compiler, etc.
+
+
+.. container:: standout
+
+  Tools & Features
+  ----------------
+
+  .. container:: tools
+
+    - | `Source Code Filters <filters.html>`_
+      | The Nim compiler supports source code filters as a simple yet powerful
+        builtin templating system.
+
+    - | `Tools Documentation <tools.html>`_
+      | Description of some tools that come with the standard distribution.
+
+
+.. container:: standout
+
+  Internal Details
+  ----------------
+
+  .. container:: internals
+
+    - | `Garbage Collector <gc.html>`_
+      | Additional documentation about Nim's GC and how to operate it in a
+        realtime setting.
+
+    - | `Internal Documentation <intern.html>`_
+      | The internal documentation describes how the compiler is implemented. Read
+        this if you want to hack the compiler.
+
+
+Search Options
+--------------
+
+`Documentation Index <theindex.html>`_ - The generated index. **Index + (Ctrl+F) == Joy**
diff --git a/web/download.txt b/web/download.txt
index 59ecdc3f5..3d47467f2 100644
--- a/web/download.txt
+++ b/web/download.txt
@@ -1,49 +1,51 @@
-You can download the latest version of the Nimrod compiler here.
+Download the compiler
+=====================
 
-**Note:** The Nimrod compiler requires a C compiler to compile software. On
+You can download the latest version of the Nim compiler here.
+
+**Note:** The Nim compiler requires a C compiler to compile software. On
 Windows we recommend that you use
 `Mingw-w64 <http://mingw-w64.sourceforge.net/>`_. GCC is recommended on Linux
-and clang on Mac OS X.
+and Clang on Mac.
 
 
 Binaries
-========
+--------
 
 Unfortunately for now we only provide builds for Windows.
-
-* 32 bit: `nimrod_0.9.6.exe <download/nimrod_0.9.6.exe>`_
-* 64 bit: `nimrod_0.9.6_x64.exe <download/nimrod_0.9.6_x64.exe>`_
+* 32 bit: `nim-0.10.2_x32.exe <download/nim-0.10.2_x32.exe>`_
+* 64 bit: `nim-0.10.2_x64.exe <download/nim-0.10.2_x64.exe>`_
 
 
 Installation based on generated C code
-======================================
+--------------------------------------
 
 This installation method is the preferred way for Linux, Mac OS X, and other Unix
 like systems. Binary packages may be provided later.
 
 
-Download `nimrod_0.9.6.zip <download/nimrod_0.9.6.zip>`_, extract it and follow
+Download `nim-0.10.2.zip <download/nim-0.10.2.zip>`_, extract it and follow
 these instructions:
 
 * sh build.sh
 * Add ``$your_install_dir/bin`` to your PATH.
 
-There are other ways to install Nimrod (like using the ``install.sh`` script),
+There are other ways to install Nim (like using the ``install.sh`` script),
 but these tend to cause more problems.
 
 
 Installation from github
-========================
+------------------------
 
 Use the following commands to build the compiler from source.
 Change the branch to suit your needs::
 
-  git clone -b master git://github.com/Araq/Nimrod.git
-  cd Nimrod
-  git clone -b master --depth 1 git://github.com/nimrod-code/csources
+  git clone -b master git://github.com/Araq/Nim.git
+  cd Nim
+  git clone -b master --depth 1 git://github.com/nim-lang/csources
   cd csources && sh build.sh
   cd ..
-  bin/nimrod c koch
+  bin/nim c koch
   ./koch boot -d:release
 
 The ``master`` branch always contains the latest stable version of the compiler.
diff --git a/web/index.txt b/web/index.txt
index e48c54f17..95cac9316 100644
--- a/web/index.txt
+++ b/web/index.txt
@@ -5,42 +5,26 @@ Home
 Welcome to Nim
 --------------
 
-**Nim** (formerly known as "Nimrod") is a statically typed, imperative 
-programming language that tries to give the programmer ultimate power without 
+**Nim** (formerly known as "Nimrod") is a statically typed, imperative
+programming language that tries to give the programmer ultimate power without
 compromises on runtime efficiency. This means it focuses on compile-time
 mechanisms in all their various forms.
 
-Beneath a nice infix/indentation based syntax with a 
-powerful (AST based, hygienic) macro system lies a semantic model that supports 
-a soft realtime GC on thread local heaps. Asynchronous message passing is used 
-between threads, so no "stop the world" mechanism is necessary. An unsafe 
-shared memory heap is also provided for the increased efficiency that results 
+Beneath a nice infix/indentation based syntax with a
+powerful (AST based, hygienic) macro system lies a semantic model that supports
+a soft realtime GC on thread local heaps. Asynchronous message passing is used
+between threads, so no "stop the world" mechanism is necessary. An unsafe
+shared memory heap is also provided for the increased efficiency that results
 from that model.
 
 
-Nim looks like this:
-====================
-
-.. code-block:: nim
-  # compute average line length
-  var count = 0
-  var sum = 0
-   
-  for line in stdin.lines:
-    count += 1
-    sum += line.len
-   
-  echo "Average line length: ",
-    if count > 0: sum / count else: 0
-
-
 Nim is efficient
 ================
 
 * Native code generation (currently via compilation to C), not dependent on a
   virtual machine: **Nim produces small executables without dependencies
   for easy redistribution.**
-* A fast **non-tracing** garbage collector that supports soft 
+* A fast **non-tracing** garbage collector that supports soft
   real-time systems (like games).
 * System programming features: Ability to manage your own memory and access the
   hardware directly. Pointers to garbage collected memory are distinguished
@@ -49,22 +33,22 @@ Nim is efficient
 * Cross-module inlining.
 * Dynamic method binding with inlining and without virtual method table.
 * Compile time evaluation of user-defined functions.
-* Whole program dead code elimination: Only *used functions* are included in 
+* Whole program dead code elimination: Only *used functions* are included in
   the executable.
-* Value-based datatypes: For instance, objects and arrays can be allocated on 
+* Value-based datatypes: For instance, objects and arrays can be allocated on
   the stack.
 
 
 Nim is expressive
 =================
 
-* **The Nim compiler and all of the standard library are implemented in 
+* **The Nim compiler and all of the standard libraries are implemented in
   Nim.**
 * Built-in high level datatypes: strings, sets, sequences, etc.
-* Modern type system with local type inference, tuples, variants, 
+* Modern type system with local type inference, tuples, variants,
   generics, etc.
 * User-defineable operators; code with new operators is often easier to read
-  than code which overloads built-in operators. For example, a 
+  than code which overloads built-in operators. For example, a
   ``=~`` operator is defined in the ``re`` module.
 * Macros can modify the abstract syntax tree at compile time.
 
@@ -74,7 +58,7 @@ Nim is elegant
 
 * Macros can use the imperative paradigm to construct parse trees. Nim
   does not require a different coding style for meta programming.
-* Macros cannot change Nim's syntax because there is no need for it. 
+* Macros cannot change Nim's syntax because there is no need for it.
   Nim's syntax is flexible enough.
 * Statements are grouped by indentation but can span multiple lines.
   Indentation must not contain tabulators so the compiler always sees
@@ -88,12 +72,12 @@ Nim plays nice with others
   Porting to other platforms is easy.
 * **The Nim Compiler can also generate C++ or Objective C for easier
   interfacing.**
-* There are lots of bindings: for example, bindings to GTK2, the Windows API, 
-  the POSIX API, OpenGL, SDL, Cairo, Python, Lua, TCL, X11, libzip, PCRE, 
+* There are lots of bindings: for example, bindings to GTK2, the Windows API,
+  the POSIX API, OpenGL, SDL, Cairo, Python, Lua, TCL, X11, libzip, PCRE,
   libcurl, mySQL and SQLite are included in the standard distribution or
   can easily be obtained via the
-  `Nimble package manager <https://github.com/nimrod-code/nimble>`_.
-* A C to Nim conversion utility: New bindings to C libraries are easily 
+  `Nimble package manager <https://github.com/nim-lang/nimble>`_.
+* A C to Nim conversion utility: New bindings to C libraries are easily
   generated by ``c2nim``.
 
 
diff --git a/web/learn.txt b/web/learn.txt
new file mode 100644
index 000000000..7a9600e57
--- /dev/null
+++ b/web/learn.txt
@@ -0,0 +1,56 @@
+Learning Nim
+============
+
+.. container:: standout
+
+  Tutorials
+  ---------
+
+  .. container:: tutorials
+
+    - | `Tutorial (part I) <tut1.html>`_
+      | Learn the basics of Nim's types, variables, procedures, control flow, etc...
+
+    - | `Tutorial (part II) <tut2.html>`_
+      | Learn Nim's more advanced features such as OOP, generics, macros, etc...
+
+
+.. container:: standout
+
+  Examples
+  --------
+
+  .. container:: examples
+
+    - | `Nim by Example <http://nim-by-example.github.io/>`_
+      | Nim by Example is an excellent starting place for beginners.
+
+    - | `Nim on Rosetta Code <http://rosettacode.org/wiki/Category:Nimrod>`_
+      | Many different Nim code examples comparable to other languages for reference.
+
+    - | `Nim for C/C++ Programmers <https://github.com/Araq/Nim/wiki/Nim-for-C-programmers>`_
+      | A useful cheat-sheet for those most familiar with C/C++ languages.
+
+
+.. container:: standout
+
+  Articles
+  --------
+
+  .. container:: articles
+
+    - `How I Start: Nim <http://howistart.org/posts/nim/1>`_
+    - `Getting Started With Nim <https://akehrer.github.io/nim/2015/01/05/getting-started-with-nim.html>`_
+    - `Getting Started With Nim - Part 2 <https://akehrer.github.io/nim/2015/01/14/getting-started-with-nim-pt2.html>`_
+    - `What is special about Nim? <http://hookrace.net/blog/what-is-special-about-nim>`_
+    - `What makes Nim practical? <http://hookrace.net/blog/what-makes-nim-practical>`_
+    - `Learn Nim in minutes <http://learnxinyminutes.com/docs/nim>`_
+    - `Dr Dobbs Nimrod Publication <http://www.drdobbs.com/open-source/nimrod-a-new-systems-programming-languag/240165321>`_
+    - `Nim articles by Göran Krampe <http://goran.krampe.se/category/nim>`_
+
+
+Documentation
+-------------
+
+More examples of Nim code can be found in the `Nim Language Documentation <manual.html>`_.
+
diff --git a/web/news.txt b/web/news.txt
index 76541560c..b3453feaf 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -3,83 +3,554 @@ News
 ====
 
 ..
-  2014-10-21 Version 0.10.2 released
+  2015-03-01 Version 0.10.4 released
   ==================================
 
+
   Changes affecting backwards compatibility
   -----------------------------------------
 
-  - **The language has been renamed from Nimrod to Nim.** The name of the
-    compiler changed from ``nimrod`` to ``nim`` too.
-  - ``system.fileHandle`` has been renamed to ``system.getFileHandle`` to
-    prevent name conflicts with the new type ``FileHandle``.
-  - Comments are now not part of the AST, as such you cannot use them in place
-    of ``discard``.
-  - Large parts of the stdlib got rid of the T/P type prefixes. Instead most
-    types now simply start with an uppercased letter. The
-    so called "partial case sensitivity" is now active allowing for code
-    like ``var foo: Foo`` in more contexts.
-  - String case (or any non-ordinal case) statements
-    without 'else' are deprecated.
-  - Recursive tuple types are not allowed anymore. Use ``object`` instead.
-  - The PEGS module returns ``nil`` instead of ``""`` when an optional capture
-    fails to match.
-  - The re module returns ``nil`` instead of ``""`` when an optional capture
-    fails to match.
-  - The "symmetric set difference" operator (``-+-``) never worked and has been
-    removed.
-  - ``defer`` is a keyword now.
-  - The ``using`` language feature now needs to be activated via the new
-    ``{.experimental.}`` pragma that enables experimental language features.
+  - Parameter names are finally properly ``gensym``'ed. This can break
+    templates though that used to rely on the fact that they are not.
+    (Bug #1915.) This means this doesn't compile anymore:
+
+  .. code-block:: nim
+
+    template doIt(body: stmt) {.immediate.} =
+      # this used to inject the 'str' parameter:
+      proc res(str: string) =
+        body
+
+    doIt:
+      echo str # Error: undeclared identifier: 'str'
+
+    Declare the ``doIt`` template as ``immediate, dirty`` to get the old
+    behaviour.
+  - Tuple field names are not ignored anymore, this caused too many problems
+    in practice so now the behaviour as it was for version 0.9.6: If field
+    names exist for the tuple type, they are checked.
+  - ``logging.level`` and ``logging.handlers`` are no longer exported.
+    ``addHandler``, ``getHandlers``, ``setLogFilter`` and ``getLogFilter``
+    should be used instead.
+  - ``nim idetools`` has been replaced by a separate tool `nimsuggest`_.
+  - *arrow like* operators are not right associative anymore.
+  - *arrow like* operators are now required to end with either ``->``, ``~>`` or
+    ``=>``, not just ``>``. Examples of operators still considered arrow like:
+    ``->``, ``==>``, ``+=>``. On the other hand, the following operators are now
+    considered regular operators again: ``|>``, ``-+>``, etc.
+  - Typeless parameters are now only allowed in templates and macros. The old
+    way turned out to be too error-prone.
+  - The 'addr' and 'type' operators are now parsed as unary function
+    application. This means ``type(x).name`` is now parsed as ``(type(x)).name``
+    and not as ``type((x).name)``. Note that this also affects the AST
+    structure; for immediate macro parameters ``nkCall('addr', 'x')`` is
+    produced instead of ``nkAddr('x')``.
+  - ``concept`` is now a keyword and is used instead of ``generic``.
+  - The ``inc``, ``dec``, ``+=``, ``-=`` builtins now produce OverflowError
+    exceptions. This means code like the following:
+
+  .. code-block:: nim
+    var x = low(T)
+    while x <= high(T):
+      echo x
+      inc x
+
+  Needs to be replaced by something like this:
+
+  .. code-block:: nim
+    var x = low(T).int
+    while x <= high(T).int:
+      echo x.T
+      inc x
+
+  - **Negative indexing for slicing does not work anymore!** Instead
+    of ``a[0.. -1]`` you can
+    use ``a[0.. ^1]``. This also works with accessing a single
+    element ``a[^1]``. Note that we cannot detect this reliably as it is
+    determined at **runtime** whether negative indexing is used!
+    ``a[0.. -1]`` now produces the empty string/sequence.
+  - The compiler now warns about code like ``foo +=1`` which uses inconsistent
+    spacing around binary operators. Later versions of the language will parse
+    these as unary operators instead so that ``echo $foo`` finally can do what
+    people expect it to do.
+  - ``system.untyped`` and ``system.typed`` have been introduced as aliases
+    for ``expr`` and ``stmt``. The new names capture the semantics much better
+    and most likely  ``expr`` and ``stmt`` will be deprecated in favor of the
+    new names.
+  - The ``split`` method in module ``re`` has changed. It now handles the case
+    of matches having a length of 0, and empty strings being yielded from the
+    iterator. A notable change might be that a pattern being matched at the
+    beginning and end of a string, will result in an empty string being produced
+    at the start and the end of the iterator.
 
   Language Additions
   ------------------
 
-  - The new concurrency model has been implemented including ``locks`` sections,
-    lock levels and object field ``guards``.
-  - The ``parallel`` statement has been implemented.
-  - ``deepCopy`` has been added to the language.
-  - The builtin ``procCall`` can be used to get ``super``-like functionality
-    for multi methods.
-  - There is a new pragma ``{.experimental.}`` that enables experimental
-    language features per module, or you can enable this features on a global
-    level with the ``--experimental`` command line option.
+  - For empty ``case object`` branches ``discard`` can finally be used instead
+    of ``nil``.
+  - Automatic dereferencing is now done for the first argument of a routine
+    call if overloading resolution produces no match otherwise. This feature
+    has to be enabled with the `experimental`_ pragma.
+  - Objects that do not use inheritance nor ``case`` can be put into ``const``
+    sections. This means that finally this is possible and produces rather
+    nice code:
 
+  .. code-block:: nim
+    import tables
 
-  Compiler Additions
-  ------------------
+    const
+      foo = {"ah": "finally", "this": "is", "possible.": "nice!"}.toTable()
+
+
+  - Ordinary parameters can follow after a varargs parameter. This means the
+    following is finally accepted by the compiler:
+
+  .. code-block:: nim
+    template takesBlock(a, b: int, x: varargs[expr]; blck: stmt) =
+      blck
+      echo a, b
+
+    takesBlock 1, 2, "some", 0.90, "random stuff":
+      echo "yay"
+
+  - Overloading by 'var T' is now finally possible:
 
-  - The compiler now supports *mixed* Objective C / C++ / C code generation:
-    The modules that use ``importCpp`` or ``importObjc`` are compiled to C++
-    or Objective C code, any other module is compiled to C code. This
-    improves interoperability.
-  - There is a new ``parallel`` statement for safe fork&join parallel computing.
-  - ``guard`` and ``lock`` pragmas have been implemented to support safer
-    concurrent programming.
-  - The following procs are now available at compile-time::
-
-      math.sqrt, math.ln, math.log10, math.log2, math.exp, math.round,
-      math.arccos, math.arcsin, math.arctan, math.arctan2, math.cos, math.cosh,
-      math.hypot, math.sinh, math.sin, math.tan, math.tanh, math.pow,
-      math.trunc, math.floor, math.ceil, math.fmod,
-      os.getEnv, os.existsEnv, os.dirExists, os.fileExists,
-      system.writeFile
-
-  - Two backticks now produce a single backtick within an ``emit`` or ``asm``
-    statement.
-  - There is a new tool, `nimfix <nimfix.html>`_ to help you in updating your
-    code from Nimrod to Nim.
-  
-
-  Library Additions
+  .. code-block:: nim
+    proc varOrConst(x: var int) = echo "var"
+    proc varOrConst(x: int) = echo "const"
+
+    var x: int
+    varOrConst(x) # "var"
+    varOrConst(45) # "const"
+
+  - Array and seq indexing can now use the builtin ``^`` operator to access
+    things from backwards: ``a[^1]`` is like Python's ``a[-1]``.
+  - A first version of the specification and implementation of the overloading
+    of the assignment operator has arrived!
+  - ``system.len`` for strings and sequences now returns 0 for nil.
+
+  - A single underscore can now be used to discard values when unpacking tuples.
+
+
+  Library additions
   -----------------
 
-  - Added module ``fenv`` to control the handling of floating-point rounding and
-    exceptions (overflow, division by zero, etc.).
+  - ``reversed`` proc added to the ``unicode`` module.
+  - Added multipart param to httpclient's ``post`` and ``postContent`` together
+    with a ``newMultipartData`` proc.
+  - Added `%*` operator for JSON.
+  - The compiler is now available as Nimble package for c2nim.
+  - Added ``..^`` and ``..<`` templates to system so that the rather annoying
+    space between ``.. <`` and ``.. ^`` is not necessary anymore.
+  - Added ``system.xlen`` for strings and sequences to get back the old ``len``
+    operation that doesn't check for ``nil`` for efficiency.
+
+
+  Bugfixes
+  --------
+
+  - Fixed internal compiler error when using ``char()`` in an echo call
+    (`#1788 <https://github.com/Araq/Nim/issues/1788>`_).
+  - Fixed Windows cross-compilation on Linux.
+  - Overload resolution now works for types distinguished only by a
+    ``static[int]`` param
+    (`#1056 <https://github.com/Araq/Nim/issues/1056>`_).
+  - Other fixes relating to generic types and static params.
+  - Fixed some compiler crashes with unnamed tuples
+    (`#1774 <https://github.com/Araq/Nim/issues/1774>`_).
+  - Fixed ``channels.tryRecv`` blocking
+    (`#1816 <https://github.com/Araq/Nim/issues/1816>`_).
+  - Fixed generic instantiation errors with ``typedesc``
+    (`#419 <https://github.com/Araq/Nim/issues/419>`_).
+  - Fixed generic regression where the compiler no longer detected constant
+    expressions properly (`#544 <https://github.com/Araq/Nim/issues/544>`_).
+  - Fixed internal error with generic proc using ``static[T]`` in a specific
+    way (`#1049 <https://github.com/Araq/Nim/issues/1049>`_).
+  - More fixes relating to generics
+    (`#1820 <https://github.com/Araq/Nim/issues/1820>`_,
+     `#1050 <https://github.com/Araq/Nim/issues/1050>`_,
+     `#1859 <https://github.com/Araq/Nim/issues/1859>`_,
+     `#1858 <https://github.com/Araq/Nim/issues/1858>`_).
+  - Fixed httpclient to properly encode queries.
+  - Many fixes to the ``uri`` module.
+  - Async sockets are now closed on error.
+  - Fixes to httpclient's handling of multipart data.
+  - Fixed GC segfaults with asynchronous sockets
+    (`#1796 <https://github.com/Araq/Nim/issues/1796>`_).
+  - Added more versions to openssl's DLL version list
+    (`076f993 <https://github.com/Araq/Nim/commit/076f993>`_).
+  - Fixed shallow copy in iterators being broken
+    (`#1803 <https://github.com/Araq/Nim/issues/1803>`_).
+  - ``nil`` can now be inserted into tables with the ``db_sqlite`` module
+    (`#1866 <https://github.com/Araq/Nim/issues/1866>`_).
+  - Fixed "Incorrect assembler generated"
+    (`#1907 <https://github.com/Araq/Nim/issues/1907>`_)
+  - Fixed "Expression templates that define macros are unusable in some contexts"
+    (`#1903 <https://github.com/Araq/Nim/issues/1903>`_)
+  - Fixed "a second level generic subclass causes the compiler to crash"
+    (`#1919 <https://github.com/Araq/Nim/issues/1919>`_)
+  - Fixed "nim 0.10.2 generates invalid AsyncHttpClient C code for MSVC "
+    (`#1901 <https://github.com/Araq/Nim/issues/1901>`_)
+  - Fixed "1 shl n produces wrong C code"
+    (`#1928 <https://github.com/Araq/Nim/issues/1928>`_)
+  - Fixed "Internal error on tuple yield"
+    (`#1838 <https://github.com/Araq/Nim/issues/1838>`_)
+  - Fixed "ICE with template"
+    (`#1915 <https://github.com/Araq/Nim/issues/1915>`_)
+  - Fixed "include the tool directory in the installer as it is required by koch"
+    (`#1947 <https://github.com/Araq/Nim/issues/1947>`_)
+  - Fixed "Can't compile if file location contains spaces on Windows"
+    (`#1955 <https://github.com/Araq/Nim/issues/1955>`_)
+  - Fixed "List comprehension macro only supports infix checks as guards"
+    (`#1920 <https://github.com/Araq/Nim/issues/1920>`_)
+  - Fixed "wrong field names of compatible tuples in generic types"
+    (`#1910 <https://github.com/Araq/Nim/issues/1910>`_)
+  - Fixed "Macros within templates no longer work as expected"
+    (`#1944 <https://github.com/Araq/Nim/issues/1944>`_)
+  - Fixed "Compiling for Standalone AVR broken in 0.10.2"
+    (`#1964 <https://github.com/Araq/Nim/issues/1964>`_)
+  - Fixed "Compiling for Standalone AVR broken in 0.10.2"
+    (`#1964 <https://github.com/Araq/Nim/issues/1964>`_)
+  - Fixed "Code generation for mitems with tuple elements"
+    (`#1833 <https://github.com/Araq/Nim/issues/1833>`_)
+  - Fixed "httpclient.HttpMethod should not be an enum"
+    (`#1962 <https://github.com/Araq/Nim/issues/1962>`_)
+  - Fixed "terminal / eraseScreen() throws an OverflowError"
+    (`#1906 <https://github.com/Araq/Nim/issues/1906>`_)
+  - Fixed "setControlCHook(nil) disables registered quit procs"
+    (`#1546 <https://github.com/Araq/Nim/issues/1546>`_)
+  - Fixed "Unexpected idetools behaviour"
+    (`#325 <https://github.com/Araq/Nim/issues/325>`_)
+  - Fixed "Unused lifted lambda does not compile"
+    (`#1642 <https://github.com/Araq/Nim/issues/1642>`_)
+  - Fixed "'low' and 'high' don't work with cstring asguments"
+    (`#2030 <https://github.com/Araq/Nim/issues/2030>`_)
+  - Fixed "Converting to int does not round in JS backend"
+    (`#1959 <https://github.com/Araq/Nim/issues/1959>`_)
+  - Fixed "Internal error genRecordField 2 when adding region to pointer."
+    (`#2039 <https://github.com/Araq/Nim/issues/2039>`_)
+  - Fixed "Macros fail to compile when compiled with --os:standalone"
+    (`#2041 <https://github.com/Araq/Nim/issues/2041>`_)
+  - Fixed "Reading from {.compileTime.} variables can cause code generation to fail"
+    (`#2022 <https://github.com/Araq/Nim/issues/2022>`_)
+  - Fixed "Passing overloaded symbols to templates fails inside generic procedures"
+    (`#1988 <https://github.com/Araq/Nim/issues/1988>`_)
+  - Fixed "Compiling iterator with object assignment in release mode causes "var not init""
+    (`#2023 <https://github.com/Araq/Nim/issues/2023>`_)
+  - Fixed "calling a large number of macros doing some computation fails"
+    (`#1989 <https://github.com/Araq/Nim/issues/1989>`_)
+  - Fixed "Can't get Koch to install nim under Windows"
+    (`#2061 <https://github.com/Araq/Nim/issues/2061>`_)
+  - Fixed "Template with two stmt parameters segfaults compiler"
+    (`#2057 <https://github.com/Araq/Nim/issues/2057>`_)
+  - Fixed "`noSideEffect` not affected by `echo`"
+    (`#2011 <https://github.com/Araq/Nim/issues/2011>`_)
+  - Fixed "Compiling with the cpp backend ignores --passc"
+    (`#1601 <https://github.com/Araq/Nim/issues/1601>`_)
+  - Fixed "Put untyped procedure parameters behind the experimental pragma"
+    (`#1956 <https://github.com/Araq/Nim/issues/1956>`_)
+  - Fixed "generic regression"
+    (`#2073 <https://github.com/Araq/Nim/issues/2073>`_)
+  - Fixed "generic regression"
+    (`#2073 <https://github.com/Araq/Nim/issues/2073>`_)
+  - Fixed "Regression in template lookup with generics"
+    (`#2004 <https://github.com/Araq/Nim/issues/2004>`_)
+  - Fixed "GC's growObj is wrong for edge cases"
+    (`#2070 <https://github.com/Araq/Nim/issues/2070>`_)
+  - Fixed "Compiler internal error when creating an array out of a typeclass"
+    (`#1131 <https://github.com/Araq/Nim/issues/1131>`_)
+  - Fixed "GC's growObj is wrong for edge cases"
+    (`#2070 <https://github.com/Araq/Nim/issues/2070>`_)
+  - Fixed "Invalid Objective-C code generated when calling class method"
+    (`#2068 <https://github.com/Araq/Nim/issues/2068>`_)
+  - Fixed "walkDirRec Error"
+    (`#2116 <https://github.com/Araq/Nim/issues/2116>`_)
+  - Fixed "Typo in code causes compiler SIGSEGV in evalAtCompileTime"
+    (`#2113 <https://github.com/Araq/Nim/issues/2113>`_)
+  - Fixed "Regression on exportc"
+    (`#2118 <https://github.com/Araq/Nim/issues/2118>`_)
+  - Fixed "Error message"
+    (`#2102 <https://github.com/Araq/Nim/issues/2102>`_)
+  - Fixed "hint[path] = off not working in nim.cfg"
+    (`#2103 <https://github.com/Araq/Nim/issues/2103>`_)
+  - Fixed "compiler crashes when getting a tuple from a sequence of generic tuples"
+    (`#2121 <https://github.com/Araq/Nim/issues/2121>`_)
+  - Fixed "nim check hangs with when"
+    (`#2123 <https://github.com/Araq/Nim/issues/2123>`_)
+  - Fixed "static[T] param in nested type resolve/caching issue"
+    (`#2125 <https://github.com/Araq/Nim/issues/2125>`_)
+  - Fixed "repr should display ``\0``"
+    (`#2124 <https://github.com/Araq/Nim/issues/2124>`_)
+  - Fixed "'nim check' never ends in case of recursive dependency "
+    (`#2051 <https://github.com/Araq/Nim/issues/2051>`_)
+  - Fixed "From macros: Error: unhandled exception: sons is not accessible"
+    (`#2167 <https://github.com/Araq/Nim/issues/2167>`_)
+  - Fixed "`fieldPairs` doesn't work inside templates"
+    (`#1902 <https://github.com/Araq/Nim/issues/1902>`_)
+  - Fixed "fields iterator misbehavior on break statement"
+    (`#2134 <https://github.com/Araq/Nim/issues/2134>`_)
+  - Fixed "Fix for compiler not building anymore since #c3244ef1ff"
+    (`#2193 <https://github.com/Araq/Nim/issues/2193>`_)
+  - Fixed "JSON parser fails in cpp output mode"
+    (`#2199 <https://github.com/Araq/Nim/issues/2199>`_)
+  - Fixed "macros.getType mishandles void return"
+    (`#2211 <https://github.com/Araq/Nim/issues/2211>`_)
+  - Fixed "Regression involving templates instantiated within generics"
+    (`#2215 <https://github.com/Araq/Nim/issues/2215>`_)
+  - Fixed ""Error: invalid type" for 'not nil' on generic type."
+    (`#2216 <https://github.com/Araq/Nim/issues/2216>`_)
+  - Fixed "--threads:on breaks async"
+    (`#2074 <https://github.com/Araq/Nim/issues/2074>`_)
+  - Fixed "Type mismatch not always caught, can generate bad code for C backend."
+    (`#2169 <https://github.com/Araq/Nim/issues/2169>`_)
+  - Fixed "Failed C compilation when storing proc to own type in object"
+    (`#2233 <https://github.com/Araq/Nim/issues/2233>`_)
+  - Fixed "Unknown line/column number in constant declaration type conversion error"
+    (`#2252 <https://github.com/Araq/Nim/issues/2252>`_)
+  - Fixed "Adding {.compile.} fails if nimcache already exists."
+    (`#2247 <https://github.com/Araq/Nim/issues/2247>`_)
+  - Fixed "Two different type names generated for a single type (C backend)"
+    (`#2250 <https://github.com/Araq/Nim/issues/2250>`_)
+  - Fixed "Ambigous call when it should not be"
+    (`#2229 <https://github.com/Araq/Nim/issues/2229>`_)
+  - Fixed "Make sure we can load root urls"
+    (`#2227 <https://github.com/Araq/Nim/issues/2227>`_)
+  - Fixed "Failure to slice a string with an int subrange type"
+    (`#794 <https://github.com/Araq/Nim/issues/794>`_)
+  - Fixed "documentation error"
+    (`#2205 <https://github.com/Araq/Nim/issues/2205>`_)
+  - Fixed "Code growth when using `const`"
+    (`#1940 <https://github.com/Araq/Nim/issues/1940>`_)
+  - Fixed "Instances of generic types confuse overload resolution"
+    (`#2220 <https://github.com/Araq/Nim/issues/2220>`_)
+  - Fixed "Compiler error when initializing sdl2's EventType"
+    (`#2316 <https://github.com/Araq/Nim/issues/2316>`_)
+  - Fixed "Parallel disjoint checking can't handle `<`, `items`, or arrays"
+    (`#2287 <https://github.com/Araq/Nim/issues/2287>`_)
+  - Fixed "Strings aren't copied in parallel loop"
+    (`#2286 <https://github.com/Araq/Nim/issues/2286>`_)
+  - Fixed "JavaScript compiler crash with tables"
+    (`#2298 <https://github.com/Araq/Nim/issues/2298>`_)
+  - Fixed "Range checker too restrictive"
+    (`#1845 <https://github.com/Araq/Nim/issues/1845>`_)
+  - Fixed "Failure to slice a string with an int subrange type"
+    (`#794 <https://github.com/Araq/Nim/issues/794>`_)
+  - Fixed "Remind user when compiling in debug mode"
+    (`#1868 <https://github.com/Araq/Nim/issues/1868>`_)
+  - Fixed "Compiler user guide has jumbled options/commands."
+    (`#1819 <https://github.com/Araq/Nim/issues/1819>`_)
+  - Fixed "using `method`: 1 in a objects constructor fails when compiling"
+    (`#1791 <https://github.com/Araq/Nim/issues/1791>`_)
+
+2014-12-29 Version 0.10.2 released
+==================================
 
+This release marks the completion of a very important change to the project:
+the official renaming from Nimrod to Nim. Version 0.10.2 contains many language
+changes, some of which may break your existing code. For your convenience, we
+added a new tool called `nimfix <nimfix.html>`_ that will help you convert your
+existing projects so that it works with the latest version of the compiler.
+
+Progress towards version 1.0
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Although Nim is still pre-1.0, we were able to keep the number of breaking
+changes to a minimum so far. Starting with version 1.0, we will not introduce
+any breaking changes between major release versions.
+One of Nim's goals is to ensure that the compiler is as efficient as possible.
+Take a look at the
+`latest benchmarks <https://github.com/logicchains/LPATHBench/blob/master/writeup.md>`_,
+which show that Nim is consistently near
+the top and already nearly as fast as C and C++. Recent developments, such as
+the new ``asyncdispatch`` module will allow you to write efficient web server
+applications using non-blocking code. Nim now also has a built-in thread pool
+for lightweight threading through the use of ``spawn``.
+
+The unpopular "T" and "P" prefixes on types have been deprecated. Nim also
+became more expressive by weakening the distinction between statements and
+expressions. We also added a new and searchable forum, a new website, and our
+documentation generator ``docgen`` has seen major improvements. Many thanks to
+Nick Greenfield for the much more beautiful documentation!
+
+
+
+What's left to be done
+~~~~~~~~~~~~~~~~~~~~~~
+
+The 1.0 release is actually very close. Apart from bug fixes, there are
+two major features missing or incomplete:
+
+* ``static[T]`` needs to be defined precisely and the bugs in the
+  implementation need to be fixed.
+* Overloading of the assignment operator is required for some generic
+  containers and needs to be implemented.
+
+This means that fancy matrix libraries will finally start to work, which used
+to be a major point of pain in the language.
+
+
+Nimble and other Nim tools
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Outside of the language and the compiler itself many Nim tools have seen
+considerable improvements.
+
+Babel the Nim package manager has been renamed to Nimble. Nimble's purpose
+is the installation of packages containing libraries and/or applications
+written in Nim.
+Even though Nimble is still very young it already is very
+functional. It can install packages by name, it does so by accessing a
+packages repository which is hosted on a Github repo. Packages can also be
+installed via a Git repo URL or Mercurial repo URL. The package repository
+is searchable through Nimble. Anyone is free to add their own packages to
+the package repository by forking the
+`nim-lang/packages <https://github.com/nim-lang/packages>`_ repo and creating
+a pull request. Nimble is fully cross-platform and should be fully functional
+on all major operating systems.
+It is of course completely written in Nim.
+
+Changelog
+~~~~~~~~~
 
-2014-10-19 Nimrod version 0.9.6 released
-========================================
+Changes affecting backwards compatibility
+-----------------------------------------
+
+- **The language has been renamed from Nimrod to Nim.** The name of the
+  compiler changed from ``nimrod`` to ``nim`` too.
+- ``system.fileHandle`` has been renamed to ``system.getFileHandle`` to
+  prevent name conflicts with the new type ``FileHandle``.
+- Comments are now not part of the AST anymore, as such you cannot use them
+  in place of ``discard``.
+- Large parts of the stdlib got rid of the T/P type prefixes. Instead most
+  types now simply start with an uppercased letter. The
+  so called "partial case sensitivity" rule is now active allowing for code
+  like ``var foo: Foo`` in more contexts.
+- String case (or any non-ordinal case) statements
+  without 'else' are deprecated.
+- Recursive tuple types are not allowed anymore. Use ``object`` instead.
+- The PEGS module returns ``nil`` instead of ``""`` when an optional capture
+  fails to match.
+- The re module returns ``nil`` instead of ``""`` when an optional capture
+  fails to match.
+- The "symmetric set difference" operator (``-+-``) never worked and has been
+  removed.
+- ``defer`` is a keyword now.
+- ``func`` is a keyword now.
+- The ``using`` language feature now needs to be activated via the new
+  ``{.experimental.}`` pragma that enables experimental language features.
+- Destructors are now officially *experimental*.
+- Standalone ``except`` and ``finally`` statements are deprecated now.
+  The standalone ``finally`` can be replaced with ``defer``,
+  standalone ``except`` requires an explicit ``try``.
+- Operators ending in ``>`` are considered as "arrow like" and have their
+  own priority level and are right associative. This means that
+  the ``=>`` and ``->`` operators from the `future <future.html>`_ module
+  work better.
+- Field names in tuples are now ignored for type comparisons. This allows
+  for greater interoperability between different modules.
+- Statement lists are not converted to an implicit ``do`` block anymore. This
+  means the confusing ``nnkDo`` nodes when working with macros are gone for
+  good.
+
+
+Language Additions
+------------------
+
+- The new concurrency model has been implemented including ``locks`` sections,
+  lock levels and object field ``guards``.
+- The ``parallel`` statement has been implemented.
+- ``deepCopy`` has been added to the language.
+- The builtin ``procCall`` can be used to get ``super``-like functionality
+  for multi methods.
+- There is a new pragma ``{.experimental.}`` that enables experimental
+  language features per module, or you can enable these features on a global
+  level with the ``--experimental`` command line option.
+
+
+Compiler Additions
+------------------
+
+- The compiler now supports *mixed* Objective C / C++ / C code generation:
+  The modules that use ``importCpp`` or ``importObjc`` are compiled to C++
+  or Objective C code, any other module is compiled to C code. This
+  improves interoperability.
+- There is a new ``parallel`` statement for safe fork&join parallel computing.
+- ``guard`` and ``lock`` pragmas have been implemented to support safer
+  concurrent programming.
+- The following procs are now available at compile-time::
+
+    math.sqrt, math.ln, math.log10, math.log2, math.exp, math.round,
+    math.arccos, math.arcsin, math.arctan, math.arctan2, math.cos,
+    math.cosh, math.hypot, math.sinh, math.sin, math.tan, math.tanh,
+    math.pow, math.trunc, math.floor, math.ceil, math.fmod,
+    os.getEnv, os.existsEnv, os.dirExists, os.fileExists,
+    system.writeFile
+
+- Two backticks now produce a single backtick within an ``emit`` or ``asm``
+  statement.
+- There is a new tool, `nimfix <nimfix.html>`_ to help you in updating your
+  code from Nimrod to Nim.
+- The compiler's output has been prettified.
+
+Library Additions
+-----------------
+
+- Added module ``fenv`` to control the handling of floating-point rounding and
+  exceptions (overflow, division by zero, etc.).
+- ``system.setupForeignThreadGc`` can be used for better interaction with
+  foreign libraries that create threads and run a Nim callback from these
+  foreign threads.
+- List comprehensions have been implemented as a macro in the ``future``
+  module.
+- The new Async module (``asyncnet``) now supports SSL.
+- The ``smtp`` module now has an async implementation.
+- Added module ``asyncfile`` which implements asynchronous file reading
+  and writing.
+- ``osproc.kill`` has been added.
+- ``asyncnet`` and ``asynchttpserver`` now support ``SO_REUSEADDR``.
+
+Bugfixes
+--------
+
+- ``nil`` and ``NULL`` are now preserved between Nim and databases in the
+  ``db_*`` modules.
+- Fixed issue with OS module in non-unicode mode on Windows.
+- Fixed issue with ``x.low``
+  (`#1366 <https://github.com/Araq/Nim/issues/1366>`_).
+- Fixed tuple unpacking issue inside closure iterators
+  (`#1067 <https://github.com/Araq/Nim/issues/1067>`_).
+- Fixed ENDB compilation issues.
+- Many ``asynchttpserver`` fixes.
+- Macros can now keep global state across macro calls
+  (`#903 <https://github.com/Araq/Nim/issues/903>`_).
+- ``osproc`` fixes on Windows.
+- ``osproc.terminate`` fixed.
+- Improvements to exception handling in async procedures.
+  (`#1487 <https://github.com/Araq/Nim/issues/1487>`_).
+- ``try`` now works at compile-time.
+- Fixes ``T = ref T`` to be an illegal recursive type.
+- Self imports are now disallowed.
+- Improved effect inference.
+- Fixes for the ``math`` module on Windows.
+- User defined pragmas will now work for generics that have
+  been instantiated in different modules.
+- Fixed queue exhaustion bug.
+- Many, many more.
+
+2014-12-09 New website design!
+==============================
+
+A brand new website including an improved forum is now live.
+All thanks go to Philip Witte and
+Dominik Picheta, Philip Witte for the design of the website (together with
+the logo) as well as the HTML and CSS code for his template, and Dominik Picheta
+for integrating Philip's design with Nim's forum. We're sure you will
+agree that Philip's design is beautiful.
+
+
+
+2014-10-19 Version 0.9.6 released
+=================================
 
 **Note: 0.9.6 is the last release of Nimrod. The language is being renamed to
 Nim. Nim slightly breaks compatibility.**
@@ -137,7 +608,7 @@ Library Additions
 - ``sequtils.distnct`` has been renamed to ``sequtils.deduplicate``.
 - Added ``algorithm.reversed``
 - Added ``uri.combine`` and ``uri.parseUri``.
-- Some sockets procedures now support a ``SafeDisconn`` flag which causes 
+- Some sockets procedures now support a ``SafeDisconn`` flag which causes
   them to handle disconnection errors and not raise them.
 
 
@@ -147,12 +618,12 @@ Library Additions
 The Nimrod development community is proud to announce the release of version
 0.9.4 of the Nimrod compiler and tools. **Note: This release has to be
 considered beta quality! Lots of new features have been implemented but
-unfortunately some do not fullfill our quality standards yet.**
+unfortunately some do not fulfill our quality standards yet.**
 
 Prebuilt binaries and instructions for building from source are available
 on the `download page <download.html>`_.
 
-This release includes about 
+This release includes about
 `1400 changes <https://github.com/Araq/Nimrod/compare/v0.9.2...v0.9.4>`_
 in total including various bug
 fixes, new languages features and standard library additions and improvements.
@@ -211,10 +682,10 @@ Note that this feature has been implemented with Nimrod's macro system and so
 Syntactic sugar for anonymous procedures has also been introduced. It too has
 been implemented as a macro. The following shows some simple usage of the new
 syntax:
- 
+
 .. code-block::nim
   import future
-  
+
   var s = @[1, 2, 3, 4, 5]
   echo(s.map((x: int) => x * 5))
 
@@ -241,14 +712,14 @@ Library Additions
 Changes affecting backwards compatibility
 -----------------------------------------
 
-- The scoping rules for the ``if`` statement changed for better interaction 
+- The scoping rules for the ``if`` statement changed for better interaction
   with the new syntactic construct ``(;)``.
 - ``OSError`` family of procedures has been deprecated. Procedures with the same
   name but which take different parameters have been introduced. These procs now
   require an error code to be passed to them. This error code can be retrieved
   using the new ``OSLastError`` proc.
 - ``os.parentDir`` now returns "" if there is no parent dir.
-- In CGI scripts stacktraces are shown to the user only 
+- In CGI scripts stacktraces are shown to the user only
   if ``cgi.setStackTraceStdout`` is used.
 - The symbol binding rules for clean templates changed: ``bind`` for any
   symbol that's not a parameter is now the default. ``mixin`` can be used
@@ -282,7 +753,7 @@ Compiler Additions
   evaluation.
 - ``--gc:none`` produces warnings when code uses the GC.
 - A ``union`` pragma for better C interoperability is now supported.
-- A ``packed`` pragma to control the memory packing/alignment of fields in 
+- A ``packed`` pragma to control the memory packing/alignment of fields in
   an object.
 - Arrays can be annotated to be ``unchecked`` for easier low level
   manipulations of memory.
@@ -331,13 +802,13 @@ as the cover story in the February 2014 issue of Dr. Dobb's Journal.
 Andreas Rumpf presented *Nimrod: A New Approach to Metaprogramming* at
 `Strange Loop 2013<https://thestrangeloop.com/sessions/nimrod-a-new-approach-to-meta-programming>`_.
 The `video and slides<http://www.infoq.com/presentations/nimrod>`_
-of the talk are now available.      
+of the talk are now available.
 
 
 2013-05-20 New website design!
 ==============================
 
-A brand new website is now live. All thanks go to Philip Witte and 
+A brand new website is now live. All thanks go to Philip Witte and
 Dominik Picheta, Philip Witte for the design of the website (together with
 the logo) as well as the HTML and CSS code for his template, and Dominik Picheta
 for integrating Philip's design with the ``nimweb`` utility. We're sure you will
@@ -351,11 +822,9 @@ We are pleased to announce that version 0.9.2 of the Nimrod compiler has been
 released. This release has attracted by far the most contributions in comparison
 to any other release.
 
-This release can be downloaded from `here <download.html>`_.
-
 This release brings with it many new features and bug fixes, a list of which
 can be seen later. One of the major new features is the effect system together
-with exception tracking which allows for checked exceptions and more, 
+with exception tracking which allows for checked exceptions and more,
 for further details check out the `manual <manual.html#effect-system>`_.
 Another major new feature is the introduction of statement list expressions,
 more details on these can be found `here <manual.html#statement-list-expression>`_.
@@ -368,12 +837,12 @@ Bugfixes
 --------
 
 - The old GC never collected cycles correctly. Fixed but it can cause
-  performance regressions. However you can deactivate the cycle collector 
-  with ``GC_disableMarkAndSweep`` and run it explicitly at an appropriate time 
-  or not at all. There is also a new GC you can activate 
+  performance regressions. However you can deactivate the cycle collector
+  with ``GC_disableMarkAndSweep`` and run it explicitly at an appropriate time
+  or not at all. There is also a new GC you can activate
   with ``--gc:markAndSweep`` which does not have this problem but is slower in
   general and has no realtime guarantees.
-- ``cast`` for floating point types now does the bitcast as specified in the 
+- ``cast`` for floating point types now does the bitcast as specified in the
   manual. This breaks code that erroneously uses ``cast`` to convert different
   floating point values.
 - SCGI module's performance has been improved greatly, it will no longer block
@@ -384,7 +853,7 @@ Bugfixes
 Library Additions
 -----------------
 
-- There is a new experimental mark&sweep GC which can be faster (or much 
+- There is a new experimental mark&sweep GC which can be faster (or much
   slower) than the default GC. Enable with ``--gc:markAndSweep``.
 - Added ``system.onRaise`` to support a condition system.
 - Added ``system.locals`` that provides access to a proc's locals.
@@ -421,41 +890,41 @@ Compiler Additions
   to be turned on explicitly via ``--warning[ShadowIdent]:on``.
 - The compiler now supports almost every pragma in a ``push`` pragma.
 - Generic converters have been implemented.
-- Added a **highly experimental** ``noforward`` pragma enabling a special 
+- Added a **highly experimental** ``noforward`` pragma enabling a special
   compilation mode that largely eliminates the need for forward declarations.
 
 Language Additions
 ------------------
 
 - ``case expressions`` are now supported.
-- Table constructors now mimic more closely the syntax of the ``case`` 
+- Table constructors now mimic more closely the syntax of the ``case``
   statement.
 - Nimrod can now infer the return type of a proc from its body.
 - Added a ``mixin`` declaration to affect symbol binding rules in generics.
 - Exception tracking has been added and the ``doc2`` command annotates possible
   exceptions for you.
-- User defined effects ("tags") tracking has been added and the ``doc2`` 
+- User defined effects ("tags") tracking has been added and the ``doc2``
   command annotates possible tags for you.
 - Types can be annotated with the new syntax ``not nil`` to explicitly state
   that ``nil`` is not allowed. However currently the compiler performs no
   advanced static checking for this; for now it's merely for documentation
   purposes.
 - An ``export`` statement has been added to the language: It can be used for
-  symbol forwarding so client modules don't have to import a module's 
+  symbol forwarding so client modules don't have to import a module's
   dependencies explicitly.
 - Overloading based on ASTs has been implemented.
 - Generics are now supported for multi methods.
 - Objects can be initialized via an *object constructor expression*.
-- There is a new syntactic construct ``(;)`` unifying expressions and 
+- There is a new syntactic construct ``(;)`` unifying expressions and
   statements.
 - You can now use ``from module import nil`` if you want to import the module
   but want to enforce fully qualified access to every symbol in ``module``.
-  
+
 
 Notes for the future
 --------------------
 
-- The scope rules of ``if`` statements will change in 0.9.4. This affects the 
+- The scope rules of ``if`` statements will change in 0.9.4. This affects the
   ``=~`` pegs/re templates.
 - The ``sockets`` module will become a low-level wrapper of OS-specific socket
   functions. All the high-level features of the current ``sockets`` module
@@ -499,14 +968,14 @@ Library Additions
   assignments.
 - Added ``system.eval`` that can execute an anonymous block of code at
   compile time as if was a macro.
-- Added ``system.staticExec`` and ``system.gorge`` for compile-time execution 
+- Added ``system.staticExec`` and ``system.gorge`` for compile-time execution
   of external programs.
 - Added ``system.staticRead`` as a synonym for ``system.slurp``.
 - Added ``macros.emit`` that can emit an arbitrary computed string as nimrod
   code during compilation.
 - Added ``strutils.parseEnum``.
 - Added ``json.%`` constructor operator.
-- The stdlib can now be avoided to a point where C code generation for 16bit 
+- The stdlib can now be avoided to a point where C code generation for 16bit
   micro controllers is feasible.
 - Added module ``oids``.
 - Added module ``endians``.
@@ -522,7 +991,7 @@ Library Additions
 - Added ``strutils.continuesWith``.
 - Added ``system.getStackTrace``.
 - Added ``system.||`` for parallel ``for`` loop support.
-- The GC supports (soft) realtime systems via ``GC_setMaxPause`` 
+- The GC supports (soft) realtime systems via ``GC_setMaxPause``
   and ``GC_step`` procs.
 - The sockets module now supports ssl through the OpenSSL library, ``recvLine``
   is now much more efficient thanks to the newly implemented sockets buffering.
@@ -533,14 +1002,14 @@ Library Additions
   only support fixed length arrays).
 - Added ``system.compiles`` which can be used to check whether a type supports
   some operation.
-- Added ``strutils.format``, ``subexes.format`` which use the 
+- Added ``strutils.format``, ``subexes.format`` which use the
   new ``varargs`` type.
 - Added module ``fsmonitor``.
 
 Changes affecting backwards compatibility
 -----------------------------------------
 
-- On Windows filenames and paths are supposed to be in UTF-8. 
+- On Windows filenames and paths are supposed to be in UTF-8.
   The ``system``, ``os``, ``osproc`` and ``memfiles`` modules use the wide
   string versions of the WinAPI. Use the ``-d:useWinAnsi`` switch to revert
   back to the old behaviour which uses the Ansi string versions.
@@ -565,21 +1034,21 @@ Changes affecting backwards compatibility
 - Deprecated ``nimrod pretty`` as it never worked good enough and has some
   inherent problems.
 - The integer promotion rules changed; the compiler is now less picky in some
-  situations and more picky in other situations: In particular implicit 
+  situations and more picky in other situations: In particular implicit
   conversions from ``int`` to ``int32`` are now forbidden.
-- ``system.byte`` is now an alias for ``uint8``; it used to be an alias 
+- ``system.byte`` is now an alias for ``uint8``; it used to be an alias
   to ``int8``.
 - ``bind`` expressions in templates are not properly supported anymore. Use
   the declarative ``bind`` statement instead.
 - The default calling convention for a procedural **type** is now ``closure``,
   for procs it remains ``nimcall`` (which is compatible to ``closure``).
-  Activate the warning ``ImplicitClosure`` to make the compiler list the 
-  occurances of proc types which are affected.
+  Activate the warning ``ImplicitClosure`` to make the compiler list the
+  occurrences of proc types which are affected.
 - The Nimrod type system now distinguishes ``openarray`` from ``varargs``.
 - Templates are now ``hygienic``. Use the ``dirty`` pragma to get the old
   behaviour.
-- Objects that have no ancestor are now implicitly ``final``. Use 
-  the ``inheritable`` pragma to introduce new object roots apart 
+- Objects that have no ancestor are now implicitly ``final``. Use
+  the ``inheritable`` pragma to introduce new object roots apart
   from ``TObject``.
 - Macros now receive parameters like templates do; use the ``callsite`` builtin
   to gain access to the invocation AST.
@@ -590,14 +1059,14 @@ Compiler Additions
 ------------------
 
 - Win64 is now an officially supported target.
-- The Nimrod compiler works on BSD again, but has some issues 
+- The Nimrod compiler works on BSD again, but has some issues
   as ``os.getAppFilename`` and ``os.getAppDir`` cannot work reliably on BSD.
 - The compiler can detect and evaluate calls that can be evaluated at compile
   time for optimization purposes with the ``--implicitStatic`` command line
   option or pragma.
 - The compiler now generates marker procs that the GC can use instead of RTTI.
   This speeds up the GC quite a bit.
-- The compiler now includes a new advanced documentation generator 
+- The compiler now includes a new advanced documentation generator
   via the ``doc2`` command. This new generator uses all of the semantic passes
   of the compiler and can thus generate documentation for symbols hiding in
   macros.
@@ -616,7 +1085,7 @@ Language Additions
 - Added ``global`` pragma that can be used to introduce new global variables
   from within procs.
 - ``when`` expressions are now allowed just like ``if`` expressions.
-- The precedence for operators starting with ``@`` is different now 
+- The precedence for operators starting with ``@`` is different now
   allowing for *sigil-like* operators.
 - Stand-alone ``finally`` and ``except`` blocks are now supported.
 - Macros and templates can now be invoked as pragmas.
@@ -624,7 +1093,7 @@ Language Additions
 - Unsigned integer types have been added.
 - The integer promotion rules changed.
 - Nimrod now tracks proper intervals for ``range`` over some built-in operators.
-- In parameter lists a semicolon instead of a comma can be used to improve 
+- In parameter lists a semicolon instead of a comma can be used to improve
   readability: ``proc divmod(a, b: int; resA, resB: var int)``.
 - A semicolon can now be used to have multiple simple statements on a single
   line: ``inc i; inc j``.
@@ -666,9 +1135,9 @@ Bugfixes
 Changes affecting backwards compatibility
 -----------------------------------------
 
-- Removed deprecated ``os.AppendFileExt``, ``os.executeShellCommand``, 
+- Removed deprecated ``os.AppendFileExt``, ``os.executeShellCommand``,
   ``os.iterOverEnvironment``, ``os.pcDirectory``, ``os.pcLinkToDirectory``,
-  ``os.SplitPath``, ``os.extractDir``, ``os.SplitFilename``, 
+  ``os.SplitPath``, ``os.extractDir``, ``os.SplitFilename``,
   ``os.extractFileTrunk``, ``os.extractFileExt``, ``osproc.executeProcess``,
   ``osproc.executeCommand``.
 - Removed deprecated ``parseopt.init``, ``parseopt.getRestOfCommandLine``.
@@ -678,7 +1147,7 @@ Changes affecting backwards compatibility
 - ``implies`` is no keyword anymore.
 - The ``is`` operator is now the ``of`` operator.
 - The ``is`` operator is now used to check type equivalence in generic code.
-- The ``pure`` pragma for procs has been renamed to ``noStackFrame``. 
+- The ``pure`` pragma for procs has been renamed to ``noStackFrame``.
 - The threading API has been completely redesigned.
 - The ``unidecode`` module is now thread-safe and its interface has changed.
 - The ``bind`` expression is deprecated, use a ``bind`` declaration instead.
@@ -688,13 +1157,13 @@ Changes affecting backwards compatibility
 - Changed exception handling/error reporting for ``os.removeFile`` and
   ``os.removeDir``.
 - The algorithm for searching and loading configuration files has been changed.
-- Operators now have diffent precedence rules: Assignment-like operators 
-  (like ``*=``) are now special-cased. 
-- The fields in ``TStream`` have been renamed to have an ``Impl`` suffix 
-  because they should not be used directly anymore. 
+- Operators now have diffent precedence rules: Assignment-like operators
+  (like ``*=``) are now special-cased.
+- The fields in ``TStream`` have been renamed to have an ``Impl`` suffix
+  because they should not be used directly anymore.
   Wrapper procs have been created that should be used instead.
 - ``export`` is now a keyword.
-- ``assert`` is now implemented in pure Nimrod as a template; it's easy 
+- ``assert`` is now implemented in pure Nimrod as a template; it's easy
   to implement your own assertion templates with ``system.astToStr``.
 
 
@@ -702,12 +1171,12 @@ Language Additions
 ------------------
 
 - Added new ``is`` and ``of`` operators.
-- The built-in type ``void`` can be used to denote the absense of any type.
+- The built-in type ``void`` can be used to denote the absence of any type.
   This is useful in generic code.
 - Return types may be of the type ``var T`` to return an l-value.
 - The error pragma can now be used to mark symbols whose *usage* should trigger
   a compile-time error.
-- There is a new ``discardable`` pragma that can be used to mark a routine 
+- There is a new ``discardable`` pragma that can be used to mark a routine
   so that its result can be discarded implicitly.
 - Added a new ``noinit`` pragma to prevent automatic initialization to zero
   of variables.
@@ -718,7 +1187,7 @@ Language Additions
 - ``bind`` (used for symbol binding in templates and generics) is now a
   declarative statement.
 - Nimrod now supports single assignment variables via the ``let`` statement.
-- Iterators named ``items`` and ``pairs`` are implicitly invoked when 
+- Iterators named ``items`` and ``pairs`` are implicitly invoked when
   an explicit iterator is missing.
 - The slice assignment ``a[i..j] = b`` where ``a`` is a sequence or string
   now supports *splicing*.
@@ -736,9 +1205,9 @@ Compiler Additions
   definitions.
 - Added a ``--nimcache:PATH`` configuration option for control over the output
   directory for generated code.
-- The ``--genScript`` option now produces different compilation scripts 
+- The ``--genScript`` option now produces different compilation scripts
   which do not contain absolute paths.
-- Added ``--cincludes:dir``, ``--clibdir:lib`` configuration options for 
+- Added ``--cincludes:dir``, ``--clibdir:lib`` configuration options for
   modifying the C compiler's header/library search path in cross-platform way.
 - Added ``--clib:lib`` configuration option for specifying additional
   C libraries to be linked.
@@ -753,7 +1222,7 @@ Compiler Additions
   are declared with the ``TaintedString`` string type. If the taint
   mode is turned on it is a distinct string type which helps to detect input
   validation errors.
-- The compiler now supports the compilation cache via ``--symbolFiles:on``. 
+- The compiler now supports the compilation cache via ``--symbolFiles:on``.
   This potentially speeds up compilations by an order of magnitude, but is
   still highly experimental!
 - Added ``--import:file`` and ``--include:file`` configuration options
@@ -765,7 +1234,7 @@ Compiler Additions
   for ``on|off`` switches in pragmas. In order to not break existing code,
   ``on`` and ``off`` are now aliases for ``true`` and ``false`` and declared
   in the system module.
-- The compiler finally supports **closures**. This is a preliminary 
+- The compiler finally supports **closures**. This is a preliminary
   implementation, which does not yet support nestings deeper than 1 level
   and still has many known bugs.
 
@@ -773,7 +1242,7 @@ Compiler Additions
 Library Additions
 -----------------
 
-- Added ``system.allocShared``, ``system.allocShared0``, 
+- Added ``system.allocShared``, ``system.allocShared0``,
   ``system.deallocShared``, ``system.reallocShared``.
 - Slicing as implemented by the system module now supports *splicing*.
 - Added explicit channels for thread communication.
@@ -787,8 +1256,8 @@ Library Additions
 - Added ``os.isAbsolute``, ``os.dynLibFormat``, ``os.isRootDir``,
   ``os.parentDirs``.
 - Added ``parseutils.interpolatedFragments``.
-- Added ``macros.treeRepr``, ``macros.lispRepr``, ``macros.dumpTree``, 
-  ``macros.dumpLisp``, ``macros.parseExpr``, ``macros.parseStmt``, 
+- Added ``macros.treeRepr``, ``macros.lispRepr``, ``macros.dumpTree``,
+  ``macros.dumpLisp``, ``macros.parseExpr``, ``macros.parseStmt``,
   ``macros.getAst``.
 - Added ``locks`` core module for more flexible locking support.
 - Added ``irc`` module.
@@ -800,7 +1269,7 @@ Library Additions
 - Added ``actors`` module.
 - Added ``algorithm`` module for generic ``sort``, ``reverse`` etc. operations.
 - Added ``osproc.startCmd``, ``osproc.execCmdEx``.
-- The ``osproc`` module now uses ``posix_spawn`` instead of ``fork`` 
+- The ``osproc`` module now uses ``posix_spawn`` instead of ``fork``
   and ``exec`` on Posix systems. Define the symbol ``useFork`` to revert to
   the old implementation.
 - Added ``intsets.assign``.
@@ -835,20 +1304,20 @@ Bugfixes
 Changes affecting backwards compatibility
 -----------------------------------------
 
-- Operators starting with ``^`` are now right-associative and have the highest 
+- Operators starting with ``^`` are now right-associative and have the highest
   priority.
 - Deprecated ``os.getApplicationFilename``: Use ``os.getAppFilename`` instead.
 - Deprecated ``os.getApplicationDir``: Use ``os.getAppDir`` instead.
 - Deprecated ``system.copy``: Use ``substr`` or string slicing instead.
 - Changed and documented how generalized string literals work: The syntax
   ``module.re"abc"`` is now supported.
-- Changed the behaviour of ``strutils.%``, ``ropes.%`` 
+- Changed the behaviour of ``strutils.%``, ``ropes.%``
   if both notations ``$#`` and ``$i`` are involved.
-- The ``pegs`` and ``re`` modules distinguish between ``replace`` 
+- The ``pegs`` and ``re`` modules distinguish between ``replace``
   and ``replacef`` operations.
 - The pointer dereference operation ``p^`` is deprecated and might become
-  ``^p`` in later versions or be dropped entirely since it is rarely used. 
-  Use the new notation ``p[]`` in the rare cases where you need to 
+  ``^p`` in later versions or be dropped entirely since it is rarely used.
+  Use the new notation ``p[]`` in the rare cases where you need to
   dereference a pointer explicitly.
 - ``system.readFile`` does not return ``nil`` anymore but raises an ``EIO``
   exception instead.
@@ -864,15 +1333,15 @@ Language Additions
 - Case statement branches support constant sets for programming convenience.
 - Tuple unpacking is not enforced in ``for`` loops anymore.
 - The compiler now supports array, sequence and string slicing.
-- A field in an ``enum`` may be given an explicit string representation. 
-  This yields more maintainable code than using a constant 
+- A field in an ``enum`` may be given an explicit string representation.
+  This yields more maintainable code than using a constant
   ``array[TMyEnum, string]`` mapping.
 - Indices in array literals may be explicitly given, enhancing readability:
   ``[enumValueA: "a", enumValueB: "b"]``.
-- Added thread support via the ``threads`` core module and 
+- Added thread support via the ``threads`` core module and
   the ``--threads:on`` command line switch.
 - The built-in iterators ``system.fields`` and ``system.fieldPairs`` can be
-  used to iterate over any field of a tuple. With this mechanism operations 
+  used to iterate over any field of a tuple. With this mechanism operations
   like ``==`` and ``hash`` are lifted to tuples.
 - The slice ``..`` is now a first-class operator, allowing code like:
   ``x in 1000..100_000``.
@@ -882,12 +1351,12 @@ Compiler Additions
 ------------------
 
 - The compiler supports IDEs via the new group of ``idetools`` command line
-  options. 
-- The *interactive mode* (REPL) has been improved and documented for the 
+  options.
+- The *interactive mode* (REPL) has been improved and documented for the
   first time.
 - The compiler now might use hashing for string case statements depending
   on the number of string literals in the case statement.
-  
+
 
 Library Additions
 -----------------
@@ -909,11 +1378,11 @@ Library Additions
   ``\title``, ``\white``.
 - Pegs support the new built-in ``\skip`` operation.
 - Pegs support the ``$`` and ``^`` anchors.
-- Additional operations were added to the ``complex`` module. 
+- Additional operations were added to the ``complex`` module.
 - Added ``strutils.formatFloat``,  ``strutils.formatBiggestFloat``.
 - Added unary ``<`` for nice looking excluding upper bounds in ranges.
 - Added ``math.floor``.
-- Added ``system.reset`` and a version of ``system.open`` that 
+- Added ``system.reset`` and a version of ``system.open`` that
   returns a ``TFile`` and raises an exception in case of an error.
 - Added a wrapper for ``redis``.
 - Added a wrapper for ``0mq`` via the ``zmq`` module.
@@ -939,12 +1408,12 @@ Bugfixes
 - Bugfix: Passing a ``ref`` pointer to the untyped ``pointer`` type is invalid.
 - Bugfix: Updated ``keyval`` example.
 - Bugfix: ``system.splitChunk`` still contained code for debug output.
-- Bugfix: ``dialogs.ChooseFileToSave`` uses ``STOCK_SAVE`` instead of 
+- Bugfix: ``dialogs.ChooseFileToSave`` uses ``STOCK_SAVE`` instead of
   ``STOCK_OPEN`` for the GTK backend.
 - Bugfix: Various bugs concerning exception handling fixed.
 - Bugfix: ``low(somestring)`` crashed the compiler.
 - Bugfix: ``strutils.endsWith`` lacked range checking.
-- Bugfix: Better detection for AMD64 on Mac OS X. 
+- Bugfix: Better detection for AMD64 on Mac OS X.
 
 
 Changes affecting backwards compatibility
@@ -953,7 +1422,7 @@ Changes affecting backwards compatibility
 - Reversed parameter order for ``os.copyFile`` and ``os.moveFile``!!!
 - Procs not marked as ``procvar`` cannot only be passed to a procvar anymore,
   unless they are used in the same module.
-- Deprecated ``times.getStartMilsecs``: Use ``epochTime`` or ``cpuTime`` 
+- Deprecated ``times.getStartMilsecs``: Use ``epochTime`` or ``cpuTime``
   instead.
 - Removed ``system.OpenFile``.
 - Removed ``system.CloseFile``.
@@ -962,7 +1431,7 @@ Changes affecting backwards compatibility
 - Removed ``strutils.splitLinesSeq``.
 - Removed ``strutils.splitSeq``.
 - Removed ``strutils.toString``.
-- If a DLL cannot be loaded (via the ``dynlib`` pragma) ``EInvalidLibrary`` 
+- If a DLL cannot be loaded (via the ``dynlib`` pragma) ``EInvalidLibrary``
   is not raised anymore. Instead ``system.quit()`` is called. This is because
   raising an exception requires heap allocations. However the memory manager
   might be contained in the DLL that failed to load.
@@ -972,19 +1441,19 @@ Changes affecting backwards compatibility
 Additions
 ---------
 
-- The ``{.compile: "file.c".}`` pragma uses a CRC check to see if the file 
+- The ``{.compile: "file.c".}`` pragma uses a CRC check to see if the file
   needs to be recompiled.
-- Added ``system.reopen``. 
+- Added ``system.reopen``.
 - Added ``system.getCurrentException``.
 - Added ``system.appType``.
-- Added ``system.compileOption``. 
-- Added ``times.epochTime`` and ``times.cpuTime``. 
+- Added ``system.compileOption``.
+- Added ``times.epochTime`` and ``times.cpuTime``.
 - Implemented explicit type arguments for generics.
 - Implemented ``{.size: sizeof(cint).}`` pragma for enum types. This is useful
   for interfacing with C.
 - Implemented ``{.pragma.}`` pragma for user defined pragmas.
 - Implemented ``{.extern.}`` pragma for better control of name mangling.
-- The ``importc`` and ``exportc`` pragmas support format strings: 
+- The ``importc`` and ``exportc`` pragmas support format strings:
   ``proc p{.exportc: "nim_$1".}`` exports ``p`` as ``nim_p``. This is useful
   for user defined pragmas.
 - The standard library can be built as a DLL. Generating DLLs has been
@@ -992,7 +1461,7 @@ Additions
 - Added ``expat`` module.
 - Added ``json`` module.
 - Added support for a *Tiny C* backend. Currently this only works on Linux.
-  You need to bootstrap with ``-d:tinyc`` to enable Tiny C support. Nimrod 
+  You need to bootstrap with ``-d:tinyc`` to enable Tiny C support. Nimrod
   can then execute code directly via ``nimrod run myfile``.
 
 
@@ -1011,9 +1480,9 @@ Bugfixes
   zeros.
 - Fixed a bug in ``os.setFilePermissions`` for Windows.
 - An overloadable symbol can now have the same name as an imported module.
-- Fixed a serious bug in ``strutils.cmpIgnoreCase``. 
-- Fixed ``unicode.toUTF8``. 
-- The compiler now rejects ``'\n'`` (use ``"\n"`` instead). 
+- Fixed a serious bug in ``strutils.cmpIgnoreCase``.
+- Fixed ``unicode.toUTF8``.
+- The compiler now rejects ``'\n'`` (use ``"\n"`` instead).
 - ``times.getStartMilsecs()`` now works on Mac OS X.
 - Fixed a bug in ``pegs.match`` concerning start offsets.
 - Lots of other little bugfixes.
@@ -1045,14 +1514,14 @@ Additions
 - Added ``graphics`` module.
 - Added ``colors`` module.
 - Many wrappers now do not contain redundant name prefixes (like ``GTK_``,
-  ``lua``). The old wrappers are still available in ``lib/oldwrappers``. 
+  ``lua``). The old wrappers are still available in ``lib/oldwrappers``.
   You can change your configuration file to use these.
 - Triple quoted strings allow for ``"`` in more contexts.
 - ``""`` within raw string literals stands for a single quotation mark.
 - Arguments to ``openArray`` parameters can be left out.
 - More extensive subscript operator overloading. (To be documented.)
 - The documentation generator supports the ``.. raw:: html`` directive.
-- The Pegs module supports back references via the notation ``$capture_index``. 
+- The Pegs module supports back references via the notation ``$capture_index``.
 
 
 Changes affecting backwards compatibility
@@ -1060,9 +1529,9 @@ Changes affecting backwards compatibility
 
 - Overloading of the subscript operator only works if the type does not provide
   a built-in one.
-- The search order for libraries which is affected by the ``path`` option 
-  has been reversed, so that the project's path is searched before 
-  the standard library's path. 
+- The search order for libraries which is affected by the ``path`` option
+  has been reversed, so that the project's path is searched before
+  the standard library's path.
 - The compiler does not include a Pascal parser for bootstrapping purposes any
   more. Instead there is a ``pas2nim`` tool that contains the old functionality.
 - The procs ``os.copyFile`` and ``os.moveFile`` have been deprecated
@@ -1089,7 +1558,7 @@ Bugfixes
 - Method call syntax for iterators works again (``for x in lines.split()``).
 - Fixed a typo in ``removeDir`` for POSIX that lead to an infinite recursion.
 - The compiler now checks that module filenames are valid identifiers.
-- Empty patterns for the ``dynlib`` pragma are now possible. 
+- Empty patterns for the ``dynlib`` pragma are now possible.
 - ``os.parseCmdLine`` returned wrong results for trailing whitespace.
 - Inconsequent tuple usage (using the same tuple with and without named fields)
   does not crash the code generator anymore.
@@ -1118,11 +1587,11 @@ Changes affecting backwards compatibility
   has changed.
 - ``os.splitFile(".xyz")`` now returns ``("", ".xyz", "")`` instead of
   ``("", "", ".xyz")``. So filenames starting with a dot are handled
-  differently. 
+  differently.
 - ``strutils.split(s: string, seps: set[char])`` never yields the empty string
-  anymore. This behaviour is probably more appropriate for whitespace splitting. 
+  anymore. This behaviour is probably more appropriate for whitespace splitting.
 - The compiler now stops after the ``--version`` command line switch.
-- Removed support for enum inheritance in the parser; enum inheritance has 
+- Removed support for enum inheritance in the parser; enum inheritance has
   never been documented anyway.
 - The ``msg`` field of ``system.E_base`` has now the type ``string``, instead
   of ``cstring``. This improves memory safety.
diff --git a/web/babelpkglist.nim b/web/nimblepkglist.nim
index aeea57a0d..7070f281b 100644
--- a/web/babelpkglist.nim
+++ b/web/nimblepkglist.nim
@@ -41,6 +41,7 @@ proc processContent(content: string) =
       dot = if desc.high > 0 and desc[desc.high] in endings: "" else: "."
       listItem = li(a(href=pkgWeb, pkg["name"].str), " ", desc & dot)
     if pkg["url"].str.startsWith("git://github.com/nimrod-code") or
+       pkg["url"].str.startsWith("git://github.com/nim-lang") or
        "official" in pkg["tags"].elems:
       officialCount.inc
       officialList.add listItem & "\n"
@@ -52,14 +53,14 @@ proc processContent(content: string) =
 
   officialPkgListDiv.innerHTML =
     p("There are currently " & $officialCount &
-      " official packages in the Babel package repository.") &
+      " official packages in the Nimble package repository.") &
     ul(officialList)
 
   var unofficialPkgListDiv = document.getElementById("unofficialPkgList")
 
   unofficialPkgListDiv.innerHTML =
     p("There are currently " & $unofficialCount &
-      " unofficial packages in the Babel package repository.") &
+      " unofficial packages in the Nimble package repository.") &
     ul(unofficialList)
 
 proc gotPackageList(apiReply: TData) {.exportc.} =
diff --git a/web/question.txt b/web/question.txt
index 52809ff90..0733a2455 100644
--- a/web/question.txt
+++ b/web/question.txt
@@ -3,139 +3,166 @@
 ===========================================
 
 
-General
-=======
+General FAQ
+===========
 
-What is Nim?
-------------
 
-Nim (formerly known as "Nimrod") is a statically typed, imperative programming
-language that tries to give the programmer ultimate power without compromises
-on runtime efficiency.
-This means it focuses on compile-time mechanisms in all their
-various forms. Beneath a nice infix/indentation based syntax with a 
-powerful (AST based, hygienic) macro system lies a semantic model that supports 
-a soft realtime GC on thread local heaps. Asynchronous message passing is used 
-between threads, so no "stop the world" mechanism is necessary. An unsafe 
-shared memory heap is also provided for the increased efficiency that results 
-from that model.
+.. container:: standout
 
+  What is Nim?
+  ------------
 
-Why yet another programming language?
--------------------------------------
+  Nim (formerly known as "Nimrod") is a statically typed, imperative programming
+  language that tries to give the programmer ultimate power without compromises
+  on runtime efficiency.
+  This means it focuses on compile-time mechanisms in all their
+  various forms. Beneath a nice infix/indentation based syntax with a 
+  powerful (AST based, hygienic) macro system lies a semantic model that supports 
+  a soft realtime GC on thread local heaps. Asynchronous message passing is used 
+  between threads, so no "stop the world" mechanism is necessary. An unsafe 
+  shared memory heap is also provided for the increased efficiency that results 
+  from that model.
 
-Nim is one of the very few *programmable* statically typed languages, and 
-one of the even fewer that produces native binaries that require no 
-runtime or interpreter.
 
+.. container:: standout
 
-What have been the major influences in the language's design?
--------------------------------------------------------------
+  Why yet another programming language?
+  -------------------------------------
 
-The language borrows heavily from (in order of impact): Modula 3, Delphi, Ada,
-C++, Python, Lisp, Oberon.
+  Nim is one of the very few *programmable* statically typed languages, and 
+  one of the even fewer that produces native binaries that require no 
+  runtime or interpreter.
 
 
+.. container:: standout
 
-What is Nim's take on concurrency?
-----------------------------------
+  What have been the major influences in the language's design?
+  -------------------------------------------------------------
 
-Nim primarily focusses on thread local (and garbage collected) heaps and 
-message passing between threads. Each thread has its own GC, so no 
-"stop the world" mechanism is necessary. An unsafe shared memory heap is also
-provided.
+  The language borrows heavily from (in order of impact): Modula 3, Delphi, Ada,
+  C++, Python, Lisp, Oberon.
 
-Future versions will additionally include a GC "per thread group" 
-and Nim's type system will be enhanced to accurately model this shared
-memory heap.
 
+.. container:: standout
 
-How is Nim licensed?
---------------------
+  What is Nim's take on concurrency?
+  ----------------------------------
 
-The Nim compiler and the library are MIT licensed.
-This means that you can use any license for your own programs developed with
-Nim.
+  Nim primarily focusses on thread local (and garbage collected) heaps and 
+  message passing between threads. Each thread has its own GC, so no 
+  "stop the world" mechanism is necessary. An unsafe shared memory heap is also
+  provided.
 
+  Future versions will additionally include a GC "per thread group" 
+  and Nim's type system will be enhanced to accurately model this shared
+  memory heap.
 
-How stable is Nim?
-------------------
 
-The compiler is in development and some important features are still missing.
-However, the compiler is quite stable already: It is able to compile itself 
-and a substantial body of other code. Until version 1.0.0 is released,
-minor incompatibilities with older versions of the compiler will be introduced.
+.. container:: standout
 
+  How is Nim licensed?
+  --------------------
 
-How fast is Nim?
-----------------
-Benchmarks show it to be comparable to C. Some language features (methods, 
-closures, message passing) are not yet as optimized as they could and will be.
-The only overhead Nim has over C is the GC which has been tuned 
-for years but still needs some work.
+  The Nim compiler and the library are MIT licensed.
+  This means that you can use any license for your own programs developed with
+  Nim.
 
 
-What about JVM/CLR backends?
-----------------------------
+.. container:: standout
 
-A JVM backend is almost impossible. The JVM is not expressive enough. It has
-never been designed as a general purpose VM anyway. A CLR backend is possible
-but would require much work. 
+  How stable is Nim?
+  ------------------
 
-What about editor support?
---------------------------
+  The compiler is in development and some important features are still missing.
+  However, the compiler is quite stable already: It is able to compile itself 
+  and a substantial body of other code. Until version 1.0.0 is released,
+  minor incompatibilities with older versions of the compiler will be introduced.
 
-- Nim IDE: https://github.com/nimrod-code/Aporia
-- Emacs: https://github.com/Tass/nimrod-mode
-- Vim: https://github.com/zah/nimrod.vim/
-- Scite: Included
-- Gedit: The `Aporia .lang file <https://github.com/nimrod-code/Aporia/blob/master/share/gtksourceview-2.0/language-specs/nimrod.lang>`_
-- jEdit: https://github.com/exhu/nimrod-misc/tree/master/jedit
 
+.. container:: standout
 
-Why is it named ``proc``?
--------------------------
+  How fast is Nim?
+  ----------------
+  Benchmarks show it to be comparable to C. Some language features (methods, 
+  closures, message passing) are not yet as optimized as they could and will be.
+  The only overhead Nim has over C is the GC which has been tuned 
+  for years but still needs some work.
 
-*Procedure* used to be the common term as opposed to a *function* which is a
-mathematical entity that has no side effects. It was planned to have ``func``
-as syntactic sugar for ``proc {.noSideEffect.}`` but with the more fine-grained
-effect system it is not yet clear what ``func`` should be a shortcut for.
 
+.. container:: standout
 
-Compilation
-===========
+  What about JVM/CLR backends?
+  ----------------------------
+
+  A JVM backend is almost impossible. The JVM is not expressive enough. It has
+  never been designed as a general purpose VM anyway. A CLR backend is possible
+  but would require much work. 
+
+
+.. container:: standout
+
+  What about editor support?
+  --------------------------
+
+  - Nim IDE: https://github.com/nim-lang/Aporia
+  - Emacs: https://github.com/reactormonk/nim-mode
+  - Vim: https://github.com/zah/nimrod.vim/
+  - Scite: Included
+  - Gedit: The `Aporia .lang file <https://github.com/nim-lang/Aporia/blob/master/share/gtksourceview-2.0/language-specs/nim.lang>`_
+  - jEdit: https://github.com/exhu/nimrod-misc/tree/master/jedit
+  - TextMate: Available in bundle installer (`Repository <https://github.com/textmate/nim.tmbundle>`_)
+  - Sublime Text: Available via Package Control (`Repository <https://github.com/Varriount/NimLime>`_)
+
+
+.. container:: standout
+
+  Why is it named ``proc``?
+  -------------------------
+
+  *Procedure* used to be the common term as opposed to a *function* which is a
+  mathematical entity that has no side effects. It is planned to have ``func``
+  as syntactic sugar for ``proc {.noSideEffect.}`` and ``func`` is already a
+  keyword.
+
+
+Compilation FAQ
+===============
+
+.. container:: standout
 
-Which option to use for the fastest executable?
------------------------------------------------
+  Which option to use for the fastest executable?
+  -----------------------------------------------
 
-For the standard configuration file, ``-d:release`` does the trick.
+  For the standard configuration file, ``-d:release`` does the trick.
 
+.. container:: standout
 
-Which option to use for the smallest executable?
-------------------------------------------------
+  Which option to use for the smallest executable?
+  ------------------------------------------------
 
-For the standard configuration file, ``-d:quick --opt:size`` does the trick.
+  For the standard configuration file, ``-d:quick --opt:size`` does the trick.
 
+.. container:: standout
 
-How do I use a different C compiler than the default one?
----------------------------------------------------------
+  How do I use a different C compiler than the default one?
+  ---------------------------------------------------------
 
-Edit the ``config/nimrod.cfg`` file.
-Change the value of the ``cc`` variable to one of the following:
+  Edit the ``config/nim.cfg`` file.
+  Change the value of the ``cc`` variable to one of the following:
 
-==============  ============================================
-Abbreviation    C/C++ Compiler
-==============  ============================================
-``vcc``         Microsoft's Visual C++
-``gcc``         Gnu C
-``llvm_gcc``    LLVM-GCC compiler
-``icc``         Intel C++ compiler
-``clang``       Clang compiler
-``ucc``         Generic UNIX C compiler
-==============  ============================================
+  ================  ============================================
+  **Abbreviation**  **C/C++ Compiler**
+  ================  ============================================
+  ``vcc``           Microsoft's Visual C++
+  ``gcc``           Gnu C
+  ``llvm_gcc``      LLVM-GCC compiler
+  ``icc``           Intel C++ compiler
+  ``clang``         Clang compiler
+  ``ucc``           Generic UNIX C compiler
+  ================  ============================================
 
-Other C compilers are not officially supported, but might work too.
+  Other C compilers are not officially supported, but might work too.
 
-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.
+  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.
diff --git a/web/support.txt b/web/support.txt
new file mode 100644
index 000000000..f8375b6aa
--- /dev/null
+++ b/web/support.txt
@@ -0,0 +1,39 @@
+Commercial and Community Support
+================================
+
+We offer a multitude of support networks including those in both a community
+and commercial setting.
+
+Commercial support includes:
+
+.. container:: standout
+
+  Priority Bug Fixes
+  ------------------
+
+  File a bug report and we will address them with the highest priority. Once
+  fixed, you will be able to access either the current Git build or at your
+  request a custom build against the latest release with your bug fixed.
+
+
+.. container:: standout
+
+  Feature Requests
+  ----------------
+
+  Suggest to us any feature that you might need, we will examine your request with
+  care and provide a proper answer about its potential for inclusion.
+
+  Communication happens via email or for a slightly higher fee via Skype.
+  The pricing is based on the amount of hours spent on the bugfix / feature
+  implementation and is open to negotiation.
+
+
+All interested parties should email ``support@nim-lang.org``. 
+The bid for contracting work is a commercial offer provided by:
+
+| **Andreas Rumpf**
+| St.-Quentin-Ring 47
+| 67663 Kaiserslautern
+| GERMANY
+| EU VAT-IN: DE297783450
diff --git a/web/ticker.txt b/web/ticker.txt
index 98ad25905..724d29231 100644
--- a/web/ticker.txt
+++ b/web/ticker.txt
@@ -1,54 +1,16 @@
-<a class="news" href="news.html#Z2014-10-19-version-0-9-6-released">
-  <h3>Oct 19, 2014</h3>
-  <p>Nimrod version 0.9.6 has been released!</p>
+<a class="news" href="news.html#Z2014-12-29-version-0-10-2-released">
+  <h4>Dec 29, 2014</h4>
+  <p>Nim version 0.10.2 has been released!</p>
 </a>
 
-<a class="news" href="news.html#Z2014-04-21-version-0-9-4-released">
-  <h3>Apr 21, 2014</h3>
-  <p>Nimrod version 0.9.4 has been released!</p>
+<a class="news" href="news.html#Z2014-12-09-new-website-design">
+  <h4>Dec 9, 2014</h4>
+  <p>The new website design and forum are now online!</p>
 </a>
 
 <a class="news" href="news.html#Z2014-02-11-nimrod-featured-in-dr-dobb-s-journal">
-  <h3>Feb 11, 2014</h3>
+  <h4>Feb 11, 2014</h4>
   <p>Nimrod featured in Dr. Dobb's Journal</p>
 </a>
 
-<a class="news" href="news.html#Z2014-01-15-andreas-rumpf-s-talk-on-nimrod-at-strange-loop-2013-is-now-online">
-  <h3>Jan 15, 2014</h3>
-  <p>Andreas Rumpf's talk on Nimrod at Strange Loop 2013 is now online.</p>
-</a>
-
-<a class="news" href="news.html#Z2013-05-20-new-website-design">
-  <h3>May 20, 2013</h3>
-  <p>New website design!</p>
-</a>
-
-<a class="news" href="news.html#Z2013-05-20-version-0-9-2-released">
-  <h3>May 20, 2013</h3>
-  <p>Nimrod version 0.9.2 has been released!</p>
-</a>
-
-<a class="news" href="news.html#Z2012-09-23-version-0-9-0-released">
-  <h3>Sep 23, 2012</h3>
-  <p>Nimrod version 0.9.0 has been released!</p>
-</a>
-
-<a class="news" href="news.html#Z2012-02-09-version-0-8-14-released">
-  <h3>Feb 9, 2012</h3>
-  <p>Nimrod version 0.8.14 has been released!</p>
-</a>
-
-<a class="news" href="news.html#Z2011-07-10-version-0-8-12-released">
-  <h3>Jul 10, 2011</h3>
-  <p>Nimrod version 0.8.12 has been released!</p>
-</a>
-
-<a class="news" href="news.html#Z2010-10-20-version-0-8-10-released">
-  <h3>Oct 20, 2010</h3>
-  <p>Nimrod version 0.8.10 has been released!</p>
-</a>
-
-<a class="news" href="news.html#Z2010-03-14-version-0-8-8-released">
-  <h3>Mar 14, 2010</h3>
-  <p>Nimrod version 0.8.8 has been released!</p>
-</a>
+<a href="news.html" class="blue">See All News...</a>
diff --git a/web/nim.ini b/web/website.ini
index 6624910d1..6266f05bb 100644
--- a/web/nim.ini
+++ b/web/website.ini
@@ -7,40 +7,32 @@ Authors: "Andreas Rumpf and contributors"
 [Links]
 # Underscores are replaced with a space.
 # Everything after ; is the ID
-User_Forum: "http://forum.nim-lang.org;link_forum"
-Aporia_IDE: "https://github.com/nimrod-code/Aporia;link_aporia"
-Nimbuild: "http://build.nim-lang.org;link_nimbuild"
+Community: "community.html;link_forum"
+Aporia_IDE: "https://github.com/nim-lang/Aporia;link_aporia"
+Github_Repo: "http://github.com/Araq/Nim;link_github"
+
 
 [Tabs]
 # Menu entry: filename
 home: index
-news: news
+learn: learn
 docs: documentation
 download: download
+support: support
+forum: "http://forum.nim-lang.org"
+faq: question
+# these two are not in the list of "tabs", but do exist:
 community: community
-FAQ: question
+news: news
 
 [Ticker]
 file: ticker.txt
 
-[Quotations]
-# Page: quote - Person
-# Bad things will happen if you use multiple dashes here.
-index: """Is it so bad, then, to be misunderstood? Pythagoras was misunderstood,
-and Socrates, and Jesus, and Luther, and Copernicus, and Galileo, and Newton,
-and every pure and wise spirit that ever took flesh. To be great is to be
-misunderstood. - Ralph Waldo Emerson"""
-documentation: """Incorrect documentation is often worse than no documentation. 
-- Bertrand Meyer"""
-download: """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."""
-
-
 [Documentation]
 doc: "endb;intern;apis;lib;manual.txt;tut1;tut2;nimc;overview;filters"
 doc: "tools;niminst;nimgrep;gc;estp;idetools;docgen;koch;backends.txt"
 doc: "nimfix.txt"
-pdf: "manual;lib;tut1;tut2;nimc;niminst;gc"
+pdf: "manual.txt;lib;tut1;tut2;nimc;niminst;gc"
 srcdoc2: "system.nim"
 srcdoc2: "core/macros;pure/marshal;core/typeinfo;core/unsigned"
 srcdoc2: "impure/re;pure/sockets;pure/typetraits"
@@ -57,7 +49,7 @@ srcdoc2: "pure/httpserver;pure/httpclient;pure/smtp;impure/ssl;pure/fsmonitor"
 srcdoc2: "pure/ropes;pure/unidecode/unidecode;pure/xmldom;pure/xmldomparser"
 srcdoc2: "pure/xmlparser;pure/htmlparser;pure/xmltree;pure/colors;pure/mimetypes"
 srcdoc2: "pure/json;pure/base64;pure/scgi;pure/redis;impure/graphics"
-srcdoc2: "impure/rdstdin;wrappers/sphinx"
+srcdoc2: "impure/rdstdin"
 srcdoc2: "pure/collections/tables;pure/collections/sets;pure/collections/lists"
 srcdoc2: "pure/collections/intsets;pure/collections/queues;pure/encodings"
 srcdoc2: "pure/events;pure/collections/sequtils;pure/cookies"
@@ -67,19 +59,17 @@ srcdoc2: "pure/nimprof;pure/unittest;packages/docutils/highlite"
 srcdoc2: "packages/docutils/rst;packages/docutils/rstast"
 srcdoc2: "packages/docutils/rstgen;pure/logging;pure/asyncdispatch;pure/asyncnet"
 srcdoc2: "pure/rawsockets;pure/asynchttpserver;pure/net;pure/selectors;pure/future"
-srcdoc2: "wrappers/expat;wrappers/readline/history"
-srcdoc2: "wrappers/libsvm.nim;wrappers/libuv"
-srcdoc2: "wrappers/zip/zlib;wrappers/zip/libzip"
-srcdoc2: "pure/md5;wrappers/mysql;wrappers/iup"
-srcdoc2: "posix/posix;wrappers/odbcsql"
-srcdoc2: "wrappers/tre;wrappers/openssl;wrappers/pcre"
-srcdoc2: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc"
-srcdoc2: "wrappers/readline/readline;wrappers/readline/rltypedefs"
-srcdoc2: "wrappers/joyent_http_parser"
+srcdoc2: "pure/asyncfile"
+srcdoc2: "pure/md5"
+srcdoc2: "posix/posix"
 srcdoc2: "pure/fenv"
+srcdoc2: "pure/basic2d;pure/basic3d"
+
+; Note: everything under 'webdoc' doesn't get listed in the index, so wrappers
+; should live here
 
-webdoc: "pure/md5;wrappers/mysql;wrappers/iup"
-webdoc: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc"
+webdoc: "wrappers/mysql;wrappers/iup;wrappers/sphinx"
+webdoc: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc;wrappers/odbcsql"
 webdoc: "wrappers/expat;wrappers/pcre"
 webdoc: "wrappers/tre;wrappers/openssl"
 webdoc: "wrappers/libuv;wrappers/joyent_http_parser"