summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.gitignore397
-rw-r--r--compiler/ccgcalls.nim2
-rw-r--r--compiler/ccgstmts.nim7
-rw-r--r--compiler/cgen.nim21
-rw-r--r--compiler/cgendata.nim1
-rw-r--r--compiler/docgen.nim284
-rw-r--r--compiler/extccomp.nim35
-rw-r--r--compiler/main.nim58
-rw-r--r--compiler/nimrod.nim20
-rw-r--r--compiler/options.nim1
-rw-r--r--compiler/pragmas.nim8
-rw-r--r--compiler/semthreads.nim3
-rw-r--r--compiler/wordrecg.nim5
-rw-r--r--doc/idetools.txt20
-rw-r--r--doc/manual.txt18
-rw-r--r--doc/nimrodc.txt13
-rw-r--r--examples/cgi/cgi_server.py11
-rw-r--r--examples/cgi/cgi_stacktrace.nim5
-rw-r--r--examples/cgi/example.nim7
-rw-r--r--lib/core/macros.nim36
-rw-r--r--lib/packages/docutils/rstgen.nim99
-rw-r--r--lib/pure/actors.nimrod.cfg (renamed from lib/pure/actors.cfg)0
-rw-r--r--lib/pure/browsers.nim4
-rw-r--r--lib/pure/cgi.nim36
-rw-r--r--lib/pure/os.nim28
-rw-r--r--lib/pure/osproc.nim73
-rw-r--r--lib/pure/strutils.nim4
-rw-r--r--lib/system.nim20
-rw-r--r--lib/system/alloc.nim2
-rw-r--r--lib/system/excpt.nim44
-rw-r--r--lib/system/gc.nim13
-rw-r--r--lib/system/mmdisp.nim3
-rw-r--r--lib/windows/winlean.nim30
-rw-r--r--tools/niminst/niminst.nim5
-rw-r--r--web/news.txt3
35 files changed, 1047 insertions, 269 deletions
diff --git a/.gitignore b/.gitignore
index d67d9f2cf..f5719848b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,7 +63,10 @@ examples/cross_calculator/android/tags
 /examples/allany
 /examples/cairoex
 /examples/cgiex
+/examples/cgi/cgi_stacktrace
+/examples/cgi/example
 /examples/curlex
+/examples/debugging
 /examples/docstrings
 /examples/filterex
 /examples/fizzbuzz
@@ -89,6 +92,12 @@ examples/cross_calculator/android/tags
 /examples/pythonex
 /examples/sdlex
 /examples/statcsv
+/examples/talk/dsl
+/examples/talk/formatoptimizer
+/examples/talk/hoisting
+/examples/talk/lazyeval
+/examples/talk/quasiquote
+/examples/talk/tags
 /examples/tclex
 /examples/transff
 /examples/tunit
@@ -96,10 +105,13 @@ examples/cross_calculator/android/tags
 /examples/x11ex
 /lib/libnimrtl.dylib
 /lib/libserver.dylib
+/lib/packages/docutils/highlite
 /lib/pure/actors
 /lib/pure/algorithm
 /lib/pure/asyncio
 /lib/pure/base64
+/lib/pure/basic2d
+/lib/pure/basic3d
 /lib/pure/browsers
 /lib/pure/cgi
 /lib/pure/collections/sequtils
@@ -111,6 +123,7 @@ examples/cross_calculator/android/tags
 /lib/pure/encodings
 /lib/pure/endians
 /lib/pure/events
+/lib/pure/fsmonitor
 /lib/pure/ftpclient
 /lib/pure/gentabs
 /lib/pure/hashes
@@ -127,19 +140,23 @@ examples/cross_calculator/android/tags
 /lib/pure/math
 /lib/pure/md5
 /lib/pure/memfiles
+/lib/pure/mersenne
 /lib/pure/mimetypes
 /lib/pure/nimprof
+/lib/pure/numeric
 /lib/pure/oids
 /lib/pure/os
 /lib/pure/osproc
 /lib/pure/parsecfg
 /lib/pure/parsecsv
 /lib/pure/parseopt
+/lib/pure/parseopt2
 /lib/pure/parsesql
 /lib/pure/parseurl
 /lib/pure/parseutils
 /lib/pure/parsexml
 /lib/pure/pegs
+/lib/pure/poly
 /lib/pure/redis
 /lib/pure/romans
 /lib/pure/ropes
@@ -167,9 +184,9 @@ examples/cross_calculator/android/tags
 /run.json
 /testresults.html
 /testresults.json
-/tests/caas/SymbolProcRun.*/
 /tests/caas/absurd_nesting
 /tests/caas/completion_dot_syntax_main
+/tests/caasdriver
 /tests/caas/forward_declarations
 /tests/caas/idetools_api
 /tests/caas/imported
@@ -178,6 +195,380 @@ examples/cross_calculator/android/tags
 /tests/caas/issue_477_dynamic_dispatch
 /tests/caas/its_full_of_procs
 /tests/caas/main
-/tests/caasdriver
-/tools/nimgrep
+/tests/caas/SymbolProcRun.*/
+/tests/ccg/tmissingbracket
+/tests/compile/talias
+/tests/compile/tambsym2
+/tests/compile/tarrindx
+/tests/compile/tassign
+/tests/compile/tbindoverload
+/tests/compile/tcan_alias_generic
+/tests/compile/tcan_alias_specialised_generic
+/tests/compile/tcan_inherit_generic
+/tests/compile/tcan_specialise_generic
+/tests/compile/tccgen1
+/tests/compile/tclosure4
+/tests/compile/tclosurebug2
+/tests/compile/tcmdline
+/tests/compile/tcodegenbug1
+/tests/compile/tcolonisproc
+/tests/compile/tcolors
+/tests/compile/tcommontype
+/tests/compile/tcompiles
+/tests/compile/tcomputedgoto
+/tests/compile/tconsteval
+/tests/compile/tconstraints
+/tests/compile/tconvcolors
+/tests/compile/tcputime
+/tests/compile/tdefaultprocparam
+/tests/compile/tdictdestruct
+/tests/compile/tdiscardable
+/tests/compile/tdllvar
+/tests/compile/tdumpast
+/tests/compile/tdumpast2
+/tests/compile/techo
+/tests/compile/teffects1
+/tests/compile/temptyecho
+/tests/compile/tendian
+/tests/compile/tenum
+/tests/compile/tenum2
+/tests/compile/tenum3
+/tests/compile/teval1
+/tests/compile/texport
+/tests/compile/tfib
+/tests/compile/tforwardgeneric
+/tests/compile/tforwty
+/tests/compile/tforwty2
+/tests/compile/tgeneric
+/tests/compile/tgeneric2
+/tests/compile/tgeneric3
+/tests/compile/tgeneric4
+/tests/compile/tgenericmatcher
+/tests/compile/tgenericmatcher2
+/tests/compile/tgenericprocvar
+/tests/compile/tgenericprop
+/tests/compile/tgenericrefs
+/tests/compile/tgenerictmpl
+/tests/compile/tgenericvariant
+/tests/compile/tgensymgeneric
+/tests/compile/tgetstartmilsecs
+/tests/compile/tglobalforvar
+/tests/compile/thallo
+/tests/compile/theaproots
+/tests/compile/thexrange
+/tests/compile/thygienictempl
+/tests/compile/tident
+/tests/compile/timplicititems
+/tests/compile/timplictderef
+/tests/compile/tinheritref
+/tests/compile/tio
+/tests/compile/tircbot
+/tests/compile/titer
+/tests/compile/titer2
+/tests/compile/titer_no_tuple_unpack
+/tests/compile/titerovl
+/tests/compile/tlastmod
+/tests/compile/tlinearscanend
+/tests/compile/tloops
+/tests/compile/tmacro1
+/tests/compile/tmacro2
+/tests/compile/tmacroaspragma
+/tests/compile/tmacrostmt
+/tests/compile/tmandelbrot
+/tests/compile/tmarshal
+/tests/compile/tmath
+/tests/compile/tmatrix1
+/tests/compile/tmatrix2
+/tests/compile/tmongo
+/tests/compile/tnamedparamanonproc
+/tests/compile/tnamedparams
+/tests/compile/tnestedproc
+/tests/compile/tnew
+/tests/compile/tnewsets
+/tests/compile/tnewuns
+/tests/compile/tnoargopenarray
+/tests/compile/tnoforward
+/tests/compile/tobjconstr2
+/tests/compile/tobjcov
+/tests/compile/tobject2
+/tests/compile/tobject3
+/tests/compile/tobjects
+/tests/compile/toop
+/tests/compile/toptions
+/tests/compile/tos
+/tests/compile/toverprc
+/tests/compile/tparedef
+/tests/compile/tparscfg
+/tests/compile/tparsefloat
+/tests/compile/tparsopt
+/tests/compile/tposix
+/tests/compile/tprep
+/tests/compile/tprocvars
+/tests/compile/tpush
+/tests/compile/tquicksort
+/tests/compile/tquit
+/tests/compile/tradix
+/tests/compile/treadln
+/tests/compile/treadx
+/tests/compile/trecmod
+/tests/compile/trecmod2
+/tests/compile/trectuple
+/tests/compile/trectuples
+/tests/compile/tredef
+/tests/compile/trepr
+/tests/compile/tsecondarrayproperty
+/tests/compile/tseq2
+/tests/compile/tseqcon2
+/tests/compile/tshadow_magic_type
+/tests/compile/tsizeof
+/tests/compile/tslurp
+/tests/compile/tsockets
+/tests/compile/tsortcall
+/tests/compile/tspecialised_is_equivalent
+/tests/compile/tstrace
+/tests/compile/tstrdesc
+/tests/compile/tstrdist
+/tests/compile/tstreams
+/tests/compile/tstrset
+/tests/compile/tstrtabs
+/tests/compile/ttableconstr
+/tests/compile/ttempl
+/tests/compile/ttempl3
+/tests/compile/ttempl4
+/tests/compile/ttempl5
+/tests/compile/ttemplreturntype
+/tests/compile/tthread_generic
+/tests/compile/ttime
+/tests/compile/ttuple1
+/tests/compile/ttypeclasses
+/tests/compile/ttypeconverter1
+/tests/compile/tuserpragma
+/tests/compile/tvoid
+/tests/compile/twalker
+/tests/compile/typalias
+/tests/dll/client
+/tests/gc/closureleak
+/tests/gc/cycleleak
+/tests/gc/gcbench
+/tests/gc/gcleak
+/tests/gc/gcleak2
+/tests/gc/gcleak3
+/tests/gc/gctest
+/tests/gc/weakrefs
+/tests/manyloc/argument_parser/ex_wget
+/tests/manyloc/nake/nakefile
+/tests/manyloc/packages/noconflicts
+/tests/manyloc/standalone/barebone
+/tests/patterns/targlist
+/tests/patterns/tcse
+/tests/patterns/thoist
+/tests/patterns/tmatrix
+/tests/patterns/tnoalias
+/tests/patterns/tnoendlessrec
+/tests/patterns/tor
+/tests/patterns/tpartial
+/tests/patterns/tstar
+/tests/patterns/tstmtlist
+/tests/reject/t99bott
+/tests/reject/tcheckedfield1
+/tests/reject/tdeprecated
+/tests/reject/tdisallowif
+/tests/reject/tuninit1
+/tests/rodfiles/aconv
+/tests/rodfiles/bconv
+/tests/rodfiles/bmethods
+/tests/rodfiles/bmethods2
+/tests/rodfiles/deada
+/tests/rodfiles/deada2
+/tests/rodfiles/hallo
+/tests/rodfiles/hallo2
+/tests/rodfiles/tgeneric1
+/tests/rodfiles/tgeneric2
+/tests/run/tack
+/tests/run/tactiontable
+/tests/run/tambsym2
+/tests/run/tambsys
+/tests/run/tanontuples
+/tests/run/tarray
+/tests/run/tarray2
+/tests/run/tarray3
+/tests/run/tarraycons
+/tests/run/tassert
+/tests/run/tastoverload1
+/tests/run/tasynciossl
+/tests/run/tasyncudp
+/tests/run/tbind1
+/tests/run/tbind3
+/tests/run/tbintre2
+/tests/run/tbintree
+/tests/run/tborrow
+/tests/run/tbug499771
+/tests/run/tbug511622
+/tests/run/tcase_setconstr
+/tests/run/tcasestm
+/tests/run/tcgbug
+/tests/run/tclosure2
+/tests/run/tclosure3
+/tests/run/tcnstseq
+/tests/run/tcnstseq2
+/tests/run/tcnstseq3
+/tests/run/tconcat
+/tests/run/tconstr2
+/tests/run/tcontinue
+/tests/run/tcontinuexc
+/tests/run/tcopy
+/tests/run/tcountup
+/tests/run/tcritbits
+/tests/run/tcurrncy
+/tests/run/tdestructor
+/tests/run/tdrdobbs_examples
+/tests/run/temit
+/tests/run/tenumhole
+/tests/run/tenumitems
+/tests/run/teventemitter
+/tests/run/tevents
+/tests/run/texceptions
+/tests/run/texcpt1
+/tests/run/texcsub
+/tests/run/texplicitgeneric1
+/tests/run/tfieldindex
+/tests/run/tfielditerator
+/tests/run/tfielditerator2
+/tests/run/tfilter
+/tests/run/tfinally
+/tests/run/tfinally2
+/tests/run/tfinally3
+/tests/run/tfinalobj
+/tests/run/tfloat1
+/tests/run/tfloat2
+/tests/run/tfloat3
+/tests/run/tformat
+/tests/run/tfriends
+/tests/run/tgenericassign
+/tests/run/tgenericassigntuples
+/tests/run/tgenericconverter
+/tests/run/tgenericprocvar
+/tests/run/tgenerics1
+/tests/run/tgensym
+/tests/run/tglobal
+/tests/run/thashes
+/tests/run/thexlit
+/tests/run/thintoff
+/tests/run/tidgen
+/tests/run/tindent1
+/tests/run/tinit
+/tests/run/tinterf
+/tests/run/tints
+/tests/run/tisopr
+/tests/run/titer3
+/tests/run/titer5
+/tests/run/titer6
+/tests/run/titer7
+/tests/run/titer8
+/tests/run/titer9
+/tests/run/titerslice
+/tests/run/titervaropenarray
+/tests/run/tkoeniglookup
+/tests/run/tlet
+/tests/run/tlists
+/tests/run/tlocals
+/tests/run/tlowhigh
+/tests/run/tmacro2
+/tests/run/tmacro3
+/tests/run/tmacro4
+/tests/run/tmacros1
+/tests/run/tmath
+/tests/run/tmatrix
+/tests/run/tmemoization
+/tests/run/tmethods1
+/tests/run/tmixin
+/tests/run/tmoditer
+/tests/run/tmultim1
+/tests/run/tmultim2
+/tests/run/tmultim3
+/tests/run/tmultim4
+/tests/run/tmultim6
+/tests/run/tnamedenumfields
+/tests/run/tnestif
+/tests/run/tnestprc
+/tests/run/tnewderef
+/tests/run/tnodeadlocks
+/tests/run/tobjasgn
+/tests/run/tobjconstr
+/tests/run/tobject
+/tests/run/tofopr
+/tests/run/tonraise
+/tests/run/toop1
+/tests/run/topenarrayrepr
+/tests/run/topenlen
+/tests/run/toprprec
+/tests/run/toverflw
+/tests/run/toverflw2
+/tests/run/toverl2
+/tests/run/toverl3
+/tests/run/toverwr
+/tests/run/tovfint
+/tests/run/tpatterns
+/tests/run/tpegs
+/tests/run/tpos
+/tests/run/tprecedence
+/tests/run/tprintf
+/tests/run/tprocvar
+/tests/run/tquotewords
+/tests/run/tregex
+/tests/run/treguse
+/tests/run/trepr
+/tests/run/treraise
+/tests/run/tromans
+/tests/run/tseqcon
+/tests/run/tseqtuple
+/tests/run/tsequtils
+/tests/run/tsets
+/tests/run/tsets2
+/tests/run/tsidee2
+/tests/run/tsidee3
+/tests/run/tsimmeth
+/tests/run/tsimplesort
+/tests/run/tslices
+/tests/run/tsortdev
+/tests/run/tsplit
+/tests/run/tstempl
+/tests/run/tstmtexprs
+/tests/run/tstrange
+/tests/run/tstringinterp
+/tests/run/tstrlits
+/tests/run/tstrutil
+/tests/run/tsubrange
+/tests/run/tsubrange2
+/tests/run/ttables
+/tests/run/ttables2
+/tests/run/ttoseq
+/tests/run/ttypedesc1
+/tests/run/tunhandledexc
+/tests/run/tunidecode
+/tests/run/tunittests
+/tests/run/tuserassert
+/tests/run/tvarargs_vs_generic
+/tests/run/tvardecl
+/tests/run/tvariantasgn
+/tests/run/tvariantstack
+/tests/run/tvarious1
+/tests/run/tvarnums
+/tests/run/tvarres1
+/tests/run/tvarres2
+/tests/run/tvartup
+/tests/run/tvtable
+/tests/run/twrongexc
+/tests/run/txmlgen
+/tests/run/txmltree
+/tests/run/tzeroarray
+/tests/system/helpers/readall_echo
+/tests/system/io
 /tests/system/params
+/tests/tester
+/tests/threads/tactors
+/tests/threads/tactors2
+/tests/threads/tthreadanalysis2
+/tests/threads/tthreadanalysis3
+/tests/threads/tthreadheapviolation1
+/tools/nimgrep
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 1d6df3c15..07fba95a3 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -290,6 +290,7 @@ proc genCall(p: BProc, e: PNode, d: var TLoc) =
     genNamedParamCall(p, e, d)
   else:
     genPrefixCall(p, nil, e, d)
+  postStmtActions(p)
   when false:
     if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
 
@@ -303,6 +304,7 @@ proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
     genNamedParamCall(p, ri, d)
   else:
     genPrefixCall(p, le, ri, d)
+  postStmtActions(p)
   when false:
     if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
 
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index d71d65ceb..d9e6d83d0 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -921,7 +921,12 @@ proc genPragma(p: BProc, n: PNode) =
     of wEmit: genEmit(p, it)
     of wBreakpoint: genBreakPoint(p, it)
     of wWatchpoint: genWatchpoint(p, it)
-    else: nil
+    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 = 
   if optFieldCheck in p.options:
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index b0c90de76..6ccef5fde 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -289,6 +289,9 @@ proc genLineDir(p: BProc, t: PNode) =
     linefmt(p, cpsStmts, "nimln($1, $2);$n",
             line.toRope, t.info.quotedFilename)
 
+proc postStmtActions(p: BProc) {.inline.} =
+  app(p.s(cpsStmts), p.module.injectStmt)
+
 proc accessThreadLocalVar(p: BProc, s: PSym)
 proc emulatedThreadVars(): bool {.inline.}
 
@@ -1119,6 +1122,9 @@ proc newPostInitProc(m: BModule): BProc =
   # little hack so that unique temporaries are generated:
   result.labels = 200_000
 
+proc initProcOptions(m: BModule): TOptions = 
+  if sfSystemModule in m.module.flags: gOptions-{optStackTrace} else: gOptions
+
 proc rawNewModule(module: PSym, filename: string): BModule =
   new(result)
   InitLinkedList(result.headerFiles)
@@ -1131,7 +1137,7 @@ proc rawNewModule(module: PSym, filename: string): BModule =
   result.module = module
   result.typeInfoMarker = initIntSet()
   result.initProc = newProc(nil, result)
-  result.initProc.options = gOptions
+  result.initProc.options = initProcOptions(result)
   result.preInitProc = newPreInitProc(result)
   result.postInitProc = newPostInitProc(result)
   initNodeTable(result.dataCache)
@@ -1139,7 +1145,12 @@ proc rawNewModule(module: PSym, filename: string): BModule =
   result.forwardedProcs = @[]
   result.typeNodesName = getTempName()
   result.nimTypesName = getTempName()
-  result.PreventStackTrace = sfSystemModule in module.flags
+  # no line tracing for the init sections of the system module so that we
+  # don't generate a TFrame which can confuse the stack botton initialization:
+  if sfSystemModule in module.flags:
+    result.PreventStackTrace = true
+    excl(result.preInitProc.options, optStackTrace)
+    excl(result.postInitProc.options, optStackTrace)
 
 proc nullify[T](arr: var T) =
   for i in low(arr)..high(arr):
@@ -1152,7 +1163,7 @@ proc resetModule*(m: var BModule) =
   m.declaredProtos = initIntSet()
   initIdTable(m.forwTypeCache)
   m.initProc = newProc(nil, m)
-  m.initProc.options = gOptions
+  m.initProc.options = initProcOptions(m)
   m.preInitProc = newPreInitProc(m)
   m.postInitProc = newPostInitProc(m)
   initNodeTable(m.dataCache)
@@ -1242,7 +1253,7 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
   result = n
   if b == nil or passes.skipCodegen(n): return
   var m = BModule(b)
-  m.initProc.options = gOptions
+  m.initProc.options = initProcOptions(m)
   genStmts(m.initProc, n)
 
 proc finishModule(m: BModule) = 
@@ -1329,7 +1340,7 @@ proc myClose(b: PPassContext, n: PNode): PNode =
   if b == nil or passes.skipCodegen(n): return 
   var m = BModule(b)
   if n != nil: 
-    m.initProc.options = gOptions
+    m.initProc.options = initProcOptions(m)
     genStmts(m.initProc, n)
   # cached modules need to registered too: 
   registerModuleToMain(m.module)
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index c156c40fe..a803c0ba1 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -111,6 +111,7 @@ type
     labels*: natural          # for generating unique module-scope names
     extensionLoaders*: array['0'..'9', PRope] # special procs for the
                                               # OpenGL wrapper
+    injectStmt*: PRope
 
 var
   mainModProcs*, mainModInit*, mainDatInit*: PRope # parts of the main module
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 9929b4bd9..d44018a2b 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -11,10 +11,10 @@
 # semantic checking is done for the code. Cross-references are generated
 # by knowing how the anchors are going to be named.
 
-import 
-  ast, strutils, strtabs, options, msgs, os, ropes, idents, 
-  wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite, 
-  importer, sempass2
+import
+  ast, strutils, strtabs, options, msgs, os, ropes, idents,
+  wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite,
+  importer, sempass2, json
 
 type
   TSections = array[TSymKind, PRope]
@@ -25,7 +25,7 @@ type
     indexValFilename: string
 
   PDoc* = ref TDocumentor
-  
+
 proc compilerMsgHandler(filename: string, line, col: int,
                         msgKind: rst.TMsgKind, arg: string) {.procvar.} =
   # translate msg kind:
@@ -41,69 +41,69 @@ proc compilerMsgHandler(filename: string, line, col: int,
   of mwUnknownSubstitution: k = warnUnknownSubstitutionX
   of mwUnsupportedLanguage: k = warnLanguageXNotSupported
   GlobalError(newLineInfo(filename, line, col), k, arg)
-  
+
 proc parseRst(text, filename: string,
               line, column: int, hasToc: var bool,
               rstOptions: TRstParseOptions): PRstNode =
   result = rstParse(text, filename, line, column, hasToc, rstOptions,
                     options.FindFile, compilerMsgHandler)
 
-proc newDocumentor*(filename: string, config: PStringTable): PDoc = 
+proc newDocumentor*(filename: string, config: PStringTable): PDoc =
   new(result)
   initRstGenerator(result[], (if gCmd != cmdRst2Tex: outHtml else: outLatex),
                    options.gConfigVars, filename, {roSupportRawDirective},
                    options.FindFile, compilerMsgHandler)
   result.id = 100
 
-proc dispA(dest: var PRope, xml, tex: string, args: openarray[PRope]) = 
+proc dispA(dest: var PRope, xml, tex: string, args: openarray[PRope]) =
   if gCmd != cmdRst2Tex: appf(dest, xml, args)
   else: appf(dest, tex, args)
-  
-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 ropeFormatNamedVars(frmt: TFormatStr, varnames: openarray[string], 
-                         varvalues: openarray[PRope]): PRope = 
+proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openarray[string],
+                         varvalues: openarray[PRope]): PRope =
   var i = 0
   var L = len(frmt)
   result = nil
   var num = 0
-  while i < L: 
-    if frmt[i] == '$': 
+  while i < L:
+    if frmt[i] == '$':
       inc(i)                  # skip '$'
       case frmt[i]
-      of '#': 
+      of '#':
         app(result, varvalues[num])
         inc(num)
         inc(i)
-      of '$': 
+      of '$':
         app(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 + 0 - 1) or not (frmt[i] in {'0'..'9'}): break 
+          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])
-      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 not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break 
+          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)
-      of '{': 
+      of '{':
         var id = ""
         inc(i)
-        while frmt[i] != '}': 
+        while frmt[i] != '}':
           if frmt[i] == '\0': rawMessage(errTokenExpected, "}")
           add(id, frmt[i])
           inc(i)
@@ -124,17 +124,17 @@ proc genComment(d: PDoc, n: PNode): string =
   var dummyHasToc: bool
   if n.comment != nil and startsWith(n.comment, "##"):
     renderRstToOut(d[], parseRst(n.comment, toFilename(n.info),
-                               toLineNumber(n.info), toColumn(n.info), 
+                               toLineNumber(n.info), toColumn(n.info),
                                dummyHasToc, d.options + {roSkipPounds}), result)
 
-proc genRecComment(d: PDoc, n: PNode): PRope = 
+proc genRecComment(d: PDoc, n: PNode): PRope =
   if n == nil: return nil
   result = genComment(d, n).toRope
-  if result == nil: 
+  if result == nil:
     if n.kind notin {nkEmpty..nkNilLit}:
       for i in countup(0, len(n)-1):
         result = genRecComment(d, n.sons[i])
-        if result != nil: return 
+        if result != nil: return
   else:
     n.comment = nil
 
@@ -158,10 +158,10 @@ proc extractDocComment*(s: PSym, d: PDoc = nil): string =
     else:
       result = n.comment.substr(2).replace("\n##", "\n").strip
 
-proc isVisible(n: PNode): bool = 
+proc isVisible(n: PNode): bool =
   result = false
-  if n.kind == nkPostfix: 
-    if n.len == 2 and n.sons[0].kind == nkIdent: 
+  if n.kind == nkPostfix:
+    if n.len == 2 and n.sons[0].kind == nkIdent:
       var v = n.sons[0].ident
       result = v.id == ord(wStar) or v.id == ord(wMinus)
   elif n.kind == nkSym:
@@ -171,36 +171,36 @@ proc isVisible(n: PNode): bool =
     result = {sfExported, sfFromGeneric, sfForward}*n.sym.flags == {sfExported}
   elif n.kind == nkPragmaExpr:
     result = isVisible(n.sons[0])
-    
-proc getName(d: PDoc, n: PNode, splitAfter = -1): string = 
+
+proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
   case n.kind
   of nkPostfix: result = getName(d, n.sons[1], splitAfter)
   of nkPragmaExpr: result = getName(d, n.sons[0], splitAfter)
   of nkSym: result = esc(d.target, n.sym.renderDefinitionName, splitAfter)
   of nkIdent: result = esc(d.target, n.ident.s, splitAfter)
-  of nkAccQuoted: 
-    result = esc(d.target, "`") 
+  of nkAccQuoted:
+    result = esc(d.target, "`")
     for i in 0.. <n.len: result.add(getName(d, n[i], splitAfter))
     result.add esc(d.target, "`")
   else:
     internalError(n.info, "getName()")
     result = ""
 
-proc getRstName(n: PNode): PRstNode = 
+proc getRstName(n: PNode): PRstNode =
   case n.kind
   of nkPostfix: result = getRstName(n.sons[1])
   of nkPragmaExpr: result = getRstName(n.sons[0])
   of nkSym: result = newRstNode(rnLeaf, n.sym.renderDefinitionName)
   of nkIdent: result = newRstNode(rnLeaf, n.ident.s)
-  of nkAccQuoted: 
+  of nkAccQuoted:
     result = getRstName(n.sons[0])
     for i in 1 .. <n.len: result.text.add(getRstName(n[i]).text)
   else:
     internalError(n.info, "getRstName()")
     result = nil
 
-proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = 
-  if not isVisible(nameNode): return 
+proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
+  if not isVisible(nameNode): return
   var name = toRope(getName(d, nameNode))
   var result: PRope = nil
   var literal = ""
@@ -208,73 +208,89 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
   var comm = genRecComment(d, n)  # call this here for the side-effect!
   var r: TSrcGen
   initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
-  while true: 
+  while true:
     getNextTok(r, kind, literal)
     case kind
-    of tkEof: 
-      break 
-    of tkComment: 
-      dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}", 
+    of tkEof:
+      break
+    of tkComment:
+      dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
             [toRope(esc(d.target, literal))])
-    of tokKeywordLow..tokKeywordHigh: 
-      dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}", 
+    of tokKeywordLow..tokKeywordHigh:
+      dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
             [toRope(literal)])
-    of tkOpr: 
-      dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}", 
+    of tkOpr:
+      dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
             [toRope(esc(d.target, literal))])
-    of tkStrLit..tkTripleStrLit: 
-      dispA(result, "<span class=\"StringLit\">$1</span>", 
+    of tkStrLit..tkTripleStrLit:
+      dispA(result, "<span class=\"StringLit\">$1</span>",
             "\\spanStringLit{$1}", [toRope(esc(d.target, literal))])
-    of tkCharLit: 
-      dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}", 
+    of tkCharLit:
+      dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
             [toRope(esc(d.target, literal))])
-    of tkIntLit..tkUInt64Lit: 
-      dispA(result, "<span class=\"DecNumber\">$1</span>", 
+    of tkIntLit..tkUInt64Lit:
+      dispA(result, "<span class=\"DecNumber\">$1</span>",
             "\\spanDecNumber{$1}", [toRope(esc(d.target, literal))])
-    of tkFloatLit..tkFloat128Lit: 
-      dispA(result, "<span class=\"FloatNumber\">$1</span>", 
+    of tkFloatLit..tkFloat128Lit:
+      dispA(result, "<span class=\"FloatNumber\">$1</span>",
             "\\spanFloatNumber{$1}", [toRope(esc(d.target, literal))])
-    of tkSymbol: 
-      dispA(result, "<span class=\"Identifier\">$1</span>", 
+    of tkSymbol:
+      dispA(result, "<span class=\"Identifier\">$1</span>",
             "\\spanIdentifier{$1}", [toRope(esc(d.target, literal))])
-    of tkSpaces, tkInvalid: 
+    of tkSpaces, tkInvalid:
       app(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}", 
+    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))])
   inc(d.id)
-  app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"), 
-                                        ["name", "header", "desc", "itemID"], 
+  app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
+                                        ["name", "header", "desc", "itemID"],
                                         [name, result, comm, toRope(d.id)]))
-  app(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"), 
+  app(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
                                     ["name", "header", "desc", "itemID"], [
       toRope(getName(d, nameNode, d.splitAfter)), result, comm, toRope(d.id)]))
   setIndexTerm(d[], $d.id, getName(d, nameNode))
 
-proc checkForFalse(n: PNode): bool = 
+proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): PJsonNode =
+  if not isVisible(nameNode): return
+  var
+    name = getName(d, nameNode)
+    comm = genRecComment(d, n).ropeToStr()
+    r: TSrcGen
+
+  initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
+
+  result = %{ "name": %name, "type": %($k) }
+
+  if comm != nil and comm != "":
+    result["description"] = %comm
+  if r.buf != nil:
+    result["code"] = %r.buf
+
+proc checkForFalse(n: PNode): bool =
   result = n.kind == nkIdent and IdentEq(n.ident, "false")
-  
-proc traceDeps(d: PDoc, n: PNode) = 
+
+proc traceDeps(d: PDoc, n: PNode) =
   const k = skModule
   if d.section[k] != nil: app(d.section[k], ", ")
-  dispA(d.section[k], 
-        "<a class=\"reference external\" href=\"$1.html\">$1</a>", 
+  dispA(d.section[k],
+        "<a class=\"reference external\" href=\"$1.html\">$1</a>",
         "$1", [toRope(getModuleName(n))])
 
-proc generateDoc*(d: PDoc, n: PNode) = 
+proc generateDoc*(d: PDoc, n: PNode) =
   case n.kind
   of nkCommentStmt: app(d.modDesc, genComment(d, n))
-  of nkProcDef: 
+  of nkProcDef:
     when useEffectSystem: documentRaises(n)
     genItem(d, n, n.sons[namePos], skProc)
   of nkMethodDef:
     when useEffectSystem: documentRaises(n)
     genItem(d, n, n.sons[namePos], skMethod)
-  of nkIteratorDef: 
+  of nkIteratorDef:
     when useEffectSystem: documentRaises(n)
     genItem(d, n, n.sons[namePos], skIterator)
   of nkMacroDef: genItem(d, n, n.sons[namePos], skMacro)
@@ -284,27 +300,69 @@ proc generateDoc*(d: PDoc, n: PNode) =
     genItem(d, n, n.sons[namePos], skConverter)
   of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
     for i in countup(0, sonsLen(n) - 1):
-      if n.sons[i].kind != nkCommentStmt: 
+      if n.sons[i].kind != nkCommentStmt:
         # order is always 'type var let const':
-        genItem(d, n.sons[i], n.sons[i].sons[0], 
+        genItem(d, n.sons[i], n.sons[i].sons[0],
                 succ(skType, ord(n.kind)-ord(nkTypeSection)))
-  of nkStmtList: 
+  of nkStmtList:
     for i in countup(0, sonsLen(n) - 1): generateDoc(d, n.sons[i])
-  of nkWhenStmt: 
+  of nkWhenStmt:
     # generate documentation for the first branch only:
     if not checkForFalse(n.sons[0].sons[0]):
       generateDoc(d, lastSon(n.sons[0]))
   of nkImportStmt:
-    for i in 0 .. sonsLen(n)-1: traceDeps(d, n.sons[i]) 
+    for i in 0 .. sonsLen(n)-1: traceDeps(d, n.sons[i])
   of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
   else: nil
 
-proc genSection(d: PDoc, kind: TSymKind) = 
+proc generateJson(d: PDoc, n: PNode, jArray: PJsonNode = nil): PJsonNode =
+  case n.kind
+  of nkCommentStmt:
+    if n.comment != nil and startsWith(n.comment, "##"):
+      let stripped = n.comment.substr(2).strip
+      result = %{ "comment": %stripped }
+  of nkProcDef:
+    when useEffectSystem: documentRaises(n)
+    result = genJSONItem(d, n, n.sons[namePos], skProc)
+  of nkMethodDef:
+    when useEffectSystem: documentRaises(n)
+    result = genJSONItem(d, n, n.sons[namePos], skMethod)
+  of nkIteratorDef:
+    when useEffectSystem: documentRaises(n)
+    result = genJSONItem(d, n, n.sons[namePos], skIterator)
+  of nkMacroDef:
+    result = genJSONItem(d, n, n.sons[namePos], skMacro)
+  of nkTemplateDef:
+    result = genJSONItem(d, n, n.sons[namePos], skTemplate)
+  of nkConverterDef:
+    when useEffectSystem: documentRaises(n)
+    result = genJSONItem(d, n, n.sons[namePos], skConverter)
+  of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
+    for i in countup(0, sonsLen(n) - 1):
+      if n.sons[i].kind != nkCommentStmt:
+        # order is always 'type var let const':
+        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()
+    for i in countup(0, sonsLen(n) - 1):
+      var r = generateJson(d, n.sons[i], elem)
+      if r != nil:
+        elem.add(r)
+        if result == nil: result = elem
+  of nkWhenStmt:
+    # generate documentation for the first branch only:
+    if not checkForFalse(n.sons[0].sons[0]) and jArray != nil:
+      discard generateJson(d, lastSon(n.sons[0]), jArray)
+  else: nil
+
+proc genSection(d: PDoc, kind: TSymKind) =
   const sectionNames: array[skModule..skTemplate, string] = [
-    "Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Methods", 
+    "Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Methods",
     "Iterators", "Converters", "Macros", "Templates"
   ]
-  if d.section[kind] == nil: return 
+  if d.section[kind] == nil: return
   var title = sectionNames[kind].toRope
   d.section[kind] = ropeFormatNamedVars(getConfigVar("doc.section"), [
       "sectionid", "sectionTitle", "sectionTitleID", "content"], [
@@ -313,7 +371,7 @@ proc genSection(d: PDoc, kind: TSymKind) =
       "sectionid", "sectionTitle", "sectionTitleID", "content"], [
       ord(kind).toRope, title, toRope(ord(kind) + 50), d.toc[kind]])
 
-proc genOutFile(d: PDoc): PRope = 
+proc genOutFile(d: PDoc): PRope =
   var
     code, content: PRope
     title = ""
@@ -321,7 +379,7 @@ proc genOutFile(d: PDoc): PRope =
   var tmp = ""
   renderTocEntries(d[], j, 1, tmp)
   var toc = tmp.toRope
-  for i in countup(low(TSymKind), high(TSymKind)): 
+  for i in countup(low(TSymKind), high(TSymKind)):
     genSection(d, i)
     app(toc, d.toc[i])
   if toc != nil:
@@ -329,30 +387,30 @@ proc genOutFile(d: PDoc): PRope =
   for i in countup(low(TSymKind), high(TSymKind)): app(code, d.section[i])
   if d.meta[metaTitle].len != 0: title = d.meta[metaTitle]
   else: title = "Module " & extractFilename(changeFileExt(d.filename, ""))
-  
+
   let bodyname = if d.hasToc: "doc.body_toc" else: "doc.body_no_toc"
-  content = ropeFormatNamedVars(getConfigVar(bodyname), ["title", 
+  content = ropeFormatNamedVars(getConfigVar(bodyname), ["title",
       "tableofcontents", "moduledesc", "date", "time", "content"],
-      [title.toRope, toc, d.modDesc, toRope(getDateStr()), 
+      [title.toRope, toc, d.modDesc, toRope(getDateStr()),
       toRope(getClockStr()), code])
-  if optCompileOnly notin gGlobalOptions: 
+  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, 
+    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])
-  else: 
+  else:
     code = content
   result = code
 
 proc generateIndex*(d: PDoc) =
   if optGenIndex in gGlobalOptions:
-    writeIndexFile(d[], splitFile(options.outFile).dir / 
+    writeIndexFile(d[], splitFile(options.outFile).dir /
                         splitFile(d.filename).name & indexExt)
 
-proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) = 
+proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
   var content = genOutFile(d)
   if optStdout in gGlobalOptions:
     writeRope(stdout, content)
@@ -361,7 +419,7 @@ proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
 
 proc CommandDoc*() =
   var ast = parseFile(gProjectMainIdx)
-  if ast == nil: return 
+  if ast == nil: return
   var d = newDocumentor(gProjectFull, options.gConfigVars)
   d.hasToc = true
   generateDoc(d, ast)
@@ -388,12 +446,26 @@ proc CommandRst2TeX*() =
   splitter = "\\-"
   CommandRstAux(gProjectFull, TexExt)
 
+proc CommandJSON*() =
+  var ast = parseFile(gProjectMainIdx)
+  if ast == nil: return
+  var d = newDocumentor(gProjectFull, options.gConfigVars)
+  d.hasToc = true
+  var json = generateJson(d, ast)
+  var content = newRope(pretty(json))
+
+  if optStdout in gGlobalOptions:
+    writeRope(stdout, content)
+  else:
+    echo getOutFile(gProjectFull, JsonExt)
+    writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
+
 proc CommandBuildIndex*() =
   var content = mergeIndexes(gProjectFull).toRope
-  
-  let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title", 
-      "tableofcontents", "moduledesc", "date", "time", 
-      "content", "author", "version"], 
-      ["Index".toRope, nil, nil, toRope(getDateStr()), 
+
+  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])
   writeRope(code, getOutFile("theindex", HtmlExt))
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index 13eb972f6..d3b3cee75 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -463,9 +463,9 @@ proc getCompileOptions: string =
 proc getLinkOptions: string =
   result = linkOptions
   for linkedLib in items(cLinkedLibs):
-    result.add(cc[ccompiler].linkLibCmd % linkedLib.quoteIfContainsWhite)
+    result.add(cc[ccompiler].linkLibCmd % linkedLib.quoteShell)
   for libDir in items(cLibs):
-    result.add([cc[ccompiler].linkDirCmd, libDir.quoteIfContainsWhite])
+    result.add([cc[ccompiler].linkDirCmd, libDir.quoteShell])
 
 proc needsExeExt(): bool {.inline.} =
   result = (optGenScript in gGlobalOptions and targetOS == osWindows) or
@@ -485,10 +485,10 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
   var includeCmd, compilePattern: string
   if not noAbsolutePaths(): 
     # compute include paths:
-    includeCmd = cc[c].includeCmd & quoteIfContainsWhite(libpath)
+    includeCmd = cc[c].includeCmd & quoteShell(libpath)
 
     for includeDir in items(cIncludes):
-      includeCmd.add([cc[c].includeCmd, includeDir.quoteIfContainsWhite])
+      includeCmd.add([cc[c].includeCmd, includeDir.quoteShell])
 
     compilePattern = JoinPath(ccompilerpath, exe)
   else: 
@@ -501,17 +501,17 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
                   toObjFile(cfile) 
                 else: 
                   completeCFilePath(toObjFile(cfile))
-  cfile = quoteIfContainsWhite(AddFileExt(cfile, cExt))
-  objfile = quoteIfContainsWhite(objfile)
-  result = quoteIfContainsWhite(compilePattern % [
+  cfile = quoteShell(AddFileExt(cfile, cExt))
+  objfile = quoteShell(objfile)
+  result = quoteShell(compilePattern % [
     "file", cfile, "objfile", objfile, "options", options, 
     "include", includeCmd, "nimrod", getPrefixDir(), "lib", libpath])
   add(result, ' ')
   addf(result, cc[c].compileTmpl, [
     "file", cfile, "objfile", objfile, 
     "options", options, "include", includeCmd, 
-    "nimrod", quoteIfContainsWhite(getPrefixDir()), 
-    "lib", quoteIfContainsWhite(libpath)])
+    "nimrod", quoteShell(getPrefixDir()), 
+    "lib", quoteShell(libpath)])
 
 proc footprint(filename: string): TCrc32 =
   result = crcFromFile(filename) ><
@@ -590,7 +590,7 @@ proc CallCCompiler*(projectfile: string) =
     while it != nil:
       let objFile = if noAbsolutePaths(): it.data.extractFilename else: it.data
       add(objfiles, ' ')
-      add(objfiles, quoteIfContainsWhite(
+      add(objfiles, quoteShell(
           addFileExt(objFile, cc[ccompiler].objExt)))
       it = PStrEntry(it.next)
 
@@ -602,8 +602,8 @@ proc CallCCompiler*(projectfile: string) =
       var linkerExe = getConfigVar(c, ".linkerexe")
       if len(linkerExe) == 0: linkerExe = cc[c].linkerExe
       if needsExeExt(): linkerExe = addFileExt(linkerExe, "exe")
-      if noAbsolutePaths(): linkCmd = quoteIfContainsWhite(linkerExe)
-      else: linkCmd = quoteIfContainsWhite(JoinPath(ccompilerpath, linkerExe))
+      if noAbsolutePaths(): linkCmd = quoteShell(linkerExe)
+      else: linkCmd = quoteShell(JoinPath(ccompilerpath, linkerExe))
       if optGenGuiApp in gGlobalOptions: buildGui = cc[c].buildGui
       else: buildGui = ""
       var exefile: string
@@ -616,18 +616,19 @@ proc CallCCompiler*(projectfile: string) =
       if options.outFile.len > 0: 
         exefile = options.outFile
       if not noAbsolutePaths():
-        exefile = joinPath(splitFile(projectFile).dir, exefile)
-      exefile = quoteIfContainsWhite(exefile)
+        if not exeFile.isAbsolute():
+          exefile = joinPath(splitFile(projectFile).dir, exefile)
+      exefile = quoteShell(exefile)
       let linkOptions = getLinkOptions()
-      linkCmd = quoteIfContainsWhite(linkCmd % ["builddll", builddll,
+      linkCmd = quoteShell(linkCmd % ["builddll", builddll,
           "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
           "exefile", exefile, "nimrod", getPrefixDir(), "lib", libpath])
       linkCmd.add ' '
       addf(linkCmd, cc[c].linkTmpl, ["builddll", builddll,
           "buildgui", buildgui, "options", linkOptions,
           "objfiles", objfiles, "exefile", exefile,
-          "nimrod", quoteIfContainsWhite(getPrefixDir()),
-          "lib", quoteIfContainsWhite(libpath)])
+          "nimrod", quoteShell(getPrefixDir()),
+          "lib", quoteShell(libpath)])
       if optCompileOnly notin gGlobalOptions: execExternalProgram(linkCmd)
   else:
     linkCmd = ""
diff --git a/compiler/main.nim b/compiler/main.nim
index 2a4143823..b91b596b0 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -9,8 +9,8 @@
 
 # implements the command dispatcher and several commands
 
-import 
-  llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs, 
+import
+  llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
   os, condsyms, rodread, rodwrite, times,
   wordrecg, sem, semdata, idents, passes, docgen, extccomp,
   cgen, jsgen, json, nversion,
@@ -98,7 +98,7 @@ proc CommandCompileToC =
       # rodread.rodcompilerProcs
       # rodread.gTypeTable
       # rodread.gMods
-      
+
       # !! ropes.cache
       # semthreads.computed?
       #
@@ -166,7 +166,7 @@ proc commandEval(exp: string) =
 proc CommandPrettyOld =
   var projectFile = addFileExt(mainCommandArg(), NimExt)
   var module = parseFile(projectFile.fileInfoIdx)
-  if module != nil: 
+  if module != nil:
     renderModule(module, getOutFile(mainCommandArg(), "pretty." & NimExt))
 
 proc CommandPretty =
@@ -175,24 +175,24 @@ proc CommandPretty =
   registerPass(prettyPass)
   compileProject()
   pretty.overwriteFiles()
-  
+
 proc CommandScan =
   var f = addFileExt(mainCommandArg(), nimExt)
   var stream = LLStreamOpen(f, fmRead)
-  if stream != nil: 
-    var 
+  if stream != nil:
+    var
       L: TLexer
       tok: TToken
     initToken(tok)
     openLexer(L, f, stream)
-    while true: 
+    while true:
       rawGetTok(L, tok)
       PrintTok(tok)
-      if tok.tokType == tkEof: break 
+      if tok.tokType == tkEof: break
     CloseLexer(L)
-  else: 
+  else:
     rawMessage(errCannotOpenFile, f)
-  
+
 proc CommandSuggest =
   if isServing:
     # XXX: hacky work-around ahead
@@ -246,7 +246,7 @@ proc resetMemory =
   for i in low(buckets)..high(buckets):
     buckets[i] = nil
   idAnon = nil
-  
+
   # XXX: clean these global vars
   # ccgstmts.gBreakpoints
   # ccgthreadvars.nimtv
@@ -262,7 +262,7 @@ proc resetMemory =
   # rodread.rodcompilerProcs
   # rodread.gTypeTable
   # rodread.gMods
-  
+
   # !! ropes.cache
   # semthreads.computed?
   #
@@ -289,7 +289,7 @@ const
 proc MainCommand* =
   when SimiluateCaasMemReset:
     gGlobalOptions.incl(optCaasEnabled)
-      
+
   # In "nimrod serve" scenario, each command must reset the registered passes
   clearPasses()
   gLastCmdTime = epochTime()
@@ -301,7 +301,7 @@ proc MainCommand* =
   passes.gIncludeFile = includeModule
   passes.gImportModule = importModule
   case command.normalize
-  of "c", "cc", "compile", "compiletoc": 
+  of "c", "cc", "compile", "compiletoc":
     # compile means compileToC currently
     gCmd = cmdCompileToC
     wantMainModule()
@@ -325,13 +325,13 @@ proc MainCommand* =
     when hasTinyCBackend:
       extccomp.setCC("tcc")
       CommandCompileToC()
-    else: 
+    else:
       rawMessage(errInvalidCommandX, command)
-  of "js", "compiletojs": 
+  of "js", "compiletojs":
     gCmd = cmdCompileToJS
     wantMainModule()
     CommandCompileToJS()
-  of "compiletollvm": 
+  of "compiletollvm":
     gCmd = cmdCompileToLLVM
     wantMainModule()
     when has_LLVM_Backend:
@@ -353,21 +353,27 @@ proc MainCommand* =
     wantMainModule()
     DefineSymbol("nimdoc")
     CommandDoc2()
-  of "rst2html": 
+  of "rst2html":
     gCmd = cmdRst2html
     LoadConfigs(DocConfig)
     wantMainModule()
     CommandRst2Html()
-  of "rst2tex": 
+  of "rst2tex":
     gCmd = cmdRst2tex
     LoadConfigs(DocTexConfig)
     wantMainModule()
     CommandRst2TeX()
+  of "jsondoc":
+    gCmd = cmdDoc
+    LoadConfigs(DocConfig)
+    wantMainModule()
+    DefineSymbol("nimdoc")
+    CommandJSON()
   of "buildindex":
     gCmd = cmdDoc
     LoadConfigs(DocConfig)
     CommandBuildIndex()
-  of "gendepend": 
+  of "gendepend":
     gCmd = cmdGenDepend
     wantMainModule()
     CommandGenDepend()
@@ -400,16 +406,16 @@ proc MainCommand* =
     gCmd = cmdCheck
     wantMainModule()
     CommandCheck()
-  of "parse": 
+  of "parse":
     gCmd = cmdParse
     wantMainModule()
     discard parseFile(gProjectMainIdx)
-  of "scan": 
+  of "scan":
     gCmd = cmdScan
     wantMainModule()
     CommandScan()
     MsgWriteln("Beware: Indentation tokens depend on the parser\'s state!")
-  of "i": 
+  of "i":
     gCmd = cmdInteractive
     CommandInteractive()
   of "e":
@@ -427,11 +433,11 @@ proc MainCommand* =
   of "serve":
     isServing = true
     gGlobalOptions.incl(optCaasEnabled)
-    msgs.gErrorMax = high(int)  # do not stop after first error     
+    msgs.gErrorMax = high(int)  # do not stop after first error
     serve(MainCommand)
   else:
     rawMessage(errInvalidCommandX, command)
-  
+
   if (msgs.gErrorCounter == 0 and
       gCmd notin {cmdInterpret, cmdRun, cmdDump} and
       gVerbosity > 0):
diff --git a/compiler/nimrod.nim b/compiler/nimrod.nim
index 2f10e32e3..2bc94e3f8 100644
--- a/compiler/nimrod.nim
+++ b/compiler/nimrod.nim
@@ -13,9 +13,9 @@ when defined(gcc) and defined(windows):
   else:
     {.link: "icons/nimrod_icon.o".}
 
-import 
-  commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes, 
-  extccomp, strutils, os, platform, main, parseopt, service
+import
+  commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
+  extccomp, strutils, os, osproc, platform, main, parseopt, service
 
 when hasTinyCBackend:
   import tccgen
@@ -23,7 +23,7 @@ when hasTinyCBackend:
 when defined(profiler) or defined(memProfiler):
   {.hint: "Profiling support is turned on!".}
   import nimprof
-  
+
 proc prependCurDir(f: string): string =
   when defined(unix):
     if os.isAbsolute(f): result = f
@@ -61,12 +61,18 @@ proc HandleCmdLine() =
           tccgen.run()
       if optRun in gGlobalOptions:
         if gCmd == cmdCompileToJS:
-          var ex = quoteIfContainsWhite(
+          var ex = quoteShell(
             completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
           execExternalProgram("node " & ex & ' ' & service.arguments)
         else:
-          var ex = quoteIfContainsWhite(
-            changeFileExt(gProjectFull, exeExt).prependCurDir)
+          var binPath: string
+          if options.outFile.len > 0:
+            # If the user specified an outFile path, use that directly.
+            binPath = options.outFile.prependCurDir
+          else:
+            # Figure out ourselves a valid binary name.
+            binPath = changeFileExt(gProjectFull, exeExt).prependCurDir
+          var ex = quoteShell(binPath)
           execExternalProgram(ex & ' ' & service.arguments)
 
 when defined(GC_setMaxPause):
diff --git a/compiler/options.nim b/compiler/options.nim
index ea6b91321..d4122c7b2 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -132,6 +132,7 @@ const
   NimExt* = "nim"
   RodExt* = "rod"
   HtmlExt* = "html"
+  JsonExt* = "json"
   TexExt* = "tex"
   IniExt* = "ini"
   DefaultConfig* = "nimrod.cfg"
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 8c2425de3..6f1e7af25 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -43,7 +43,8 @@ const
     wFatal, wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop,
     wBreakpoint, wWatchpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated,
     wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
-    wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto}
+    wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
+    wInjectStmt}
   lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, 
     wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, 
     wDeprecated, wExtern, wThread, wImportcpp, wImportobjc, wNoStackFrame,
@@ -722,6 +723,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
         of wOperator:
           if sym == nil: invalidPragma(it)
           else: sym.position = expectIntLit(c, it)
+        of wInjectStmt:
+          if it.kind != nkExprColonExpr:
+            localError(it.info, errExprExpected)
+          else: 
+            it.sons[1] = c.semExpr(c, it.sons[1])
         else: invalidPragma(it)
       else: invalidPragma(it)
   else: processNote(c, it)
diff --git a/compiler/semthreads.nim b/compiler/semthreads.nim
index 595ab0454..eded99325 100644
--- a/compiler/semthreads.nim
+++ b/compiler/semthreads.nim
@@ -380,7 +380,8 @@ proc analyseThreadProc*(prc: PSym) =
   var formals = skipTypes(prc.typ, abstractInst).n
   for i in 1 .. formals.len-1:
     var formal = formals.sons[i].sym 
-    c.mapping[formal.id] = toTheirs # thread receives foreign data!
+    # the input is copied and belongs to the thread:
+    c.mapping[formal.id] = toMine
   discard analyse(c, prc.getBody)
 
 proc needsGlobalAnalysis*: bool =
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index 9e86a260e..5f0e5be94 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -60,7 +60,7 @@ type
     wPassc, wPassl, wBorrow, wDiscardable,
     wFieldChecks, 
     wWatchPoint, wSubsChar, 
-    wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto,
+    wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, wInjectStmt,
     wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit, 
     wNoStackFrame,
     wImplicitStatic, wGlobal, wCodegenDecl,
@@ -142,7 +142,8 @@ const
     "compiletime", "noinit",
     "passc", "passl", "borrow", "discardable", "fieldchecks",
     "watchpoint",
-    "subschar", "acyclic", "shallow", "unroll", "linearscanend", "computedgoto",
+    "subschar", "acyclic", "shallow", "unroll", "linearscanend",
+    "computedgoto", "injectstmt",
     "write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
     "nostackframe", "implicitstatic", "global", "codegendecl",
     
diff --git a/doc/idetools.txt b/doc/idetools.txt
index fdc4ebde6..c1eba9e5f 100644
--- a/doc/idetools.txt
+++ b/doc/idetools.txt
@@ -8,6 +8,11 @@
 .. contents::
 
 
+.. raw:: html
+  <blockquote><p>
+  "yes, I'm the creator" -- Araq, 2013-07-26 19:28:32.
+  </p></blockquote>
+
 Nimrod differs from many other compilers in that it is really fast,
 and being so fast makes it suited to provide external queries for
 text editors about the source code being written. Through the
@@ -522,21 +527,6 @@ At the moment idetools support is still in development so the test
 suite is not integrated with the main test suite and you have to
 run it manually. First you have to compile the tester::
 
-	$ cd my/nimrod/checkout
-	$ nimrod c tests/tester.nim
-
-Running the tester without parameters will display some options.
-To run the caas test suite (and other special tests) you need to
-use the `special` command. You need to run this command from the
-root of the checkout or it won't be able to open the required files::
-
-	$ ./tests/tester special
-
-However this is a roundabout way of running the test suite. You can
-also compile and run ``tests/caasdriver.nim`` manually. In fact,
-running it manually will allow you to specify special parameters
-too. Example::
-
 	$ cd my/nimrod/checkout/tests
 	$ nimrod c caasdriver.nim
 
diff --git a/doc/manual.txt b/doc/manual.txt
index dabff3d69..0a9aec8d0 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -4708,7 +4708,11 @@ fatal pragma
 ------------
 The `fatal`:idx: pragma is used to make the compiler output an error message
 with the given content. In contrast to the ``error`` pragma, compilation
-is guaranteed to be aborted by this pragma.
+is guaranteed to be aborted by this pragma. Example:
+
+.. code-block:: nimrod
+  when not defined(objc):
+    {.fatal: "Compile this program with the objc command!".}
 
 warning pragma
 --------------
@@ -5053,6 +5057,18 @@ Note that this pragma is somewhat of a misnomer: Other backends will provide
 the same feature under the same name.
 
 
+Extern pragma
+-------------
+Like ``exportc`` or ``importc`` the `extern`:idx: pragma affects name
+mangling. The string literal passed to ``extern`` can be a format string:
+
+.. code-block:: Nimrod
+  proc p(s: string) {.extern: "prefix$1".} =
+    echo s
+
+In the example the external name of ``p`` is set to ``prefixp``.
+
+
 Bycopy pragma
 -------------
 
diff --git a/doc/nimrodc.txt b/doc/nimrodc.txt
index d494a0922..f5fbf3ebb 100644
--- a/doc/nimrodc.txt
+++ b/doc/nimrodc.txt
@@ -468,6 +468,19 @@ proc is declared in the generated code:
 
   proc myinterrupt() {.codegenDecl: "__interrupt $# $#$#".} =
     echo "realistic interrupt handler"
+
+
+InjectStmt pragma
+-----------------
+
+The `injectStmt`:idx: pragma can be used to inject a statement before every
+other statement in the current module. It is only supposed to be used for
+debugging:
+
+.. code-block:: nimrod
+  {.injectStmt: gcInvariants().}
+  
+  # ... complex code here that produces crashes ...
 

 

 LineDir option

diff --git a/examples/cgi/cgi_server.py b/examples/cgi/cgi_server.py
new file mode 100644
index 000000000..1907515e8
--- /dev/null
+++ b/examples/cgi/cgi_server.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+import BaseHTTPServer
+import CGIHTTPServer
+
+server = BaseHTTPServer.HTTPServer
+handler = CGIHTTPServer.CGIHTTPRequestHandler
+server_address = ('localhost', 8008)
+handler.cgi_directories = ['/']
+
+httpd = server(server_address, handler)
+httpd.serve_forever()
diff --git a/examples/cgi/cgi_stacktrace.nim b/examples/cgi/cgi_stacktrace.nim
new file mode 100644
index 000000000..e9f2f567c
--- /dev/null
+++ b/examples/cgi/cgi_stacktrace.nim
@@ -0,0 +1,5 @@
+import cgi
+cgi.setStackTraceStdout()
+
+var a: string = nil
+a.add "foobar"
diff --git a/examples/cgi/example.nim b/examples/cgi/example.nim
new file mode 100644
index 000000000..17629982a
--- /dev/null
+++ b/examples/cgi/example.nim
@@ -0,0 +1,7 @@
+import cgi
+
+write(stdout, "Content-type: text/html\n\n")
+write(stdout, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n")
+write(stdout, "<html><head><title>Test</title></head><body>\n")
+write(stdout, "Hello!")
+writeln(stdout, "</body></html>")
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index fb47ba3a8..8ffd268ff 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -274,6 +274,8 @@ proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst".}
   ##
   ## Example:
   ##   
+  ## .. code-block:: nimrod
+  ##
   ##   macro check(ex: expr): stmt =
   ##     # this is a simplified version of the check macro from the
   ##     # unittest module.
@@ -296,6 +298,8 @@ template emit*(e: expr[string]): stmt =
   ## that should be inserted verbatim in the program
   ## Example:
   ##
+  ## .. code-block:: nimrod
+  ##
   ##   emit("echo " & '"' & "hello world".toUpper & '"')
   ##
   eval: result = e.parseStmt
@@ -480,6 +484,34 @@ proc newDotExpr*(a, b: PNimrodNode): PNimrodNode {.compileTime.} =
 
 proc newIdentDefs*(name, kind: PNimrodNode; 
                    default = newEmptyNode()): PNimrodNode {.compileTime.} = 
+  ## Creates a new ``nnkIdentDefs`` node of a specific kind and value.
+  ##
+  ## ``nnkIdentDefs`` need to have at least three children, but they can have
+  ## more: first comes a list of identifiers followed by a type and value
+  ## nodes. This helper proc creates a three node subtree, the first subnode
+  ## being a single identifier name. Both the ``kind`` node and ``default``
+  ## (value) nodes may be empty depending on where the ``nnkIdentDefs``
+  ## appears: tuple or object definitions will have an empty ``default`` node,
+  ## ``let`` or ``var`` blocks may have an empty ``kind`` node if the
+  ## identifier is being assigned a value. Example:
+  ##
+  ## .. code-block:: nimrod
+  ##
+  ##   var varSection = newNimNode(nnkVarSection).add(
+  ##     newIdentDefs(ident("a"), ident("string")),
+  ##     newIdentDefs(ident("b"), newEmptyNode(), newLit(3)))
+  ##   # --> var
+  ##   #       a: string
+  ##   #       b = 3
+  ##
+  ## If you need to create multiple identifiers you need to use the lower level
+  ## ``newNimNode``:
+  ##
+  ## .. code-block:: nimrod
+  ##
+  ##   result = newNimNode(nnkIdentDefs).add(
+  ##     ident("a"), ident("b"), ident("c"), ident("string"),
+  ##       newStrLitNode("Hello"))
   newNimNode(nnkIdentDefs).add(name, kind, default)
 
 proc newNilLit*(): PNimrodNode {.compileTime.} =
@@ -503,11 +535,11 @@ from strutils import cmpIgnoreStyle, format
 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] = [];  
+proc newProc*(name = newEmptyNode(); params: openarray[PNimrodNode] = [newEmptyNode()];  
     body: PNimrodNode = newStmtList(), procType = nnkProcDef): PNimrodNode {.compileTime.} =
   ## shortcut for creating a new proc
   ##
-  ## The ``params`` array should 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(
diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim
index 364f847cc..09c6ba8b8 100644
--- a/lib/packages/docutils/rstgen.nim
+++ b/lib/packages/docutils/rstgen.nim
@@ -7,7 +7,18 @@
 #    distribution, for details about the copyright.
 #
 
-## This module implements a generator of HTML/Latex from `reStructuredText`:idx:.
+## This module implements a generator of HTML/Latex from
+## `reStructuredText`:idx: (see http://docutils.sourceforge.net/rst.html for
+## information on this markup syntax). You can generate HTML output through the
+## convenience proc ``rstToHtml``, which provided an input string with rst
+## markup returns a string with the generated HTML. The final output is meant
+## to be embedded inside a full document you provide yourself, so it won't
+## contain the usual ``<header>`` or ``<body>`` parts.
+##
+## You can also create a ``TRstGenerator`` structure and populate it with the
+## other lower level methods to finally build complete documents. This requires
+## many options and tweaking, but you are not limited to snippets and can
+## generate `LaTeX documents <https://en.wikipedia.org/wiki/LaTeX>`_ too.
 
 import strutils, os, hashes, strtabs, rstast, rst, highlite
 
@@ -40,13 +51,51 @@ type
     filename*: string
     meta*: array[TMetaEnum, string]
   
-  PDoc = var TRstGenerator
+  PDoc = var TRstGenerator ## Alias to type less.
 
 proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
                        config: PStringTable, filename: string,
                        options: TRstParseOptions,
                        findFile: TFindFileHandler,
                        msgHandler: TMsgHandler) =
+  ## Initializes a ``TRstGenerator``.
+  ##
+  ## You need to call this before using a ``TRstGenerator`` with any other
+  ## procs in this module. Pass a non ``nil`` ``PStringTable`` value as
+  ## ``config`` with parameters used by the HTML output generator.  If you
+  ## don't know what to use, pass the results of the ``defaultConfig()`` proc.
+  ## The ``filename`` is symbolic and used only for error reporting, you can
+  ## pass any non ``nil`` string here.
+  ##
+  ## The ``TRstParseOptions``, ``TFindFileHandler`` and ``TMsgHandler`` types
+  ## are defined in the the `packages/docutils/rst module <rst.html>`_.
+  ## ``options`` selects the behaviour of the rst parser.
+  ##
+  ## ``findFile`` is a proc used by the rst ``include`` directive among others.
+  ## The purpose of this proc is to mangle or filter paths. It receives paths
+  ## specified in the rst document and has to return a valid path to existing
+  ## files or the empty string otherwise.  If you pass ``nil``, a default proc
+  ## will be used which given a path returns the input path only if the file
+  ## exists. One use for this proc is to transform relative paths found in the
+  ## document to absolute path, useful if the rst file and the resources it
+  ## references are not in the same directory as the current working directory.
+  ##
+  ## The ``msgHandler`` is a proc used for user error reporting. It will be
+  ## called with the filename, line, col, and type of any error found during
+  ## parsing. If you pass ``nil``, a default message handler will be used which
+  ## writes the messages to the standard output.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:: nimrod
+  ##
+  ##   import packages/docutils/rstgen
+  ##
+  ##   var gen: TRstGenerator
+  ##
+  ##   gen.initRstGenerator(outHtml, defaultConfig(),
+  ##     "filename", {}, nil, nil)
+
   g.config = config
   g.target = target
   g.tocPart = @[]
@@ -147,7 +196,19 @@ proc dispA(target: TOutputTarget, dest: var string,
   if target != outLatex: addf(dest, xml, args)
   else: addf(dest, tex, args)
   
-proc renderRstToOut*(d: PDoc, n: PRstNode, result: var string)
+proc renderRstToOut*(d: var TRstGenerator, n: PRstNode, result: var string)
+  ## Writes into ``result`` the rst ast ``n`` using the ``d`` configuration.
+  ##
+  ## Before using this proc you need to initialise a ``TRstGenerator`` with
+  ## ``initRstGenerator`` and parse a rst file with ``rstParse`` from the
+  ## `packages/docutils/rst module <rst.html>`_. Example:
+  ##
+  ## .. code-block:: nimrod
+  ##
+  ##   # ...configure gen and rst vars...
+  ##   var generatedHTML = ""
+  ##   renderRstToOut(gen, rst, generatedHTML)
+  ##   echo generatedHTML
 
 proc renderAux(d: PDoc, n: PRstNode, result: var string) = 
   for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], result)
@@ -162,7 +223,7 @@ proc renderAux(d: PDoc, n: PRstNode, frmtA, frmtB: string, result: var string) =
 
 # ---------------- index handling --------------------------------------------
 
-proc setIndexTerm*(d: PDoc, id, term: string) =
+proc setIndexTerm*(d: var TRstGenerator, id, term: string) =
   d.theIndex.add(term)
   d.theIndex.add('\t')
   let htmlFile = changeFileExt(extractFilename(d.filename), HtmlExt)
@@ -295,7 +356,7 @@ proc renderTocEntry(d: PDoc, e: TTocEntry, result: var string) =
     "<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: PDoc, j: var int, lvl: int, result: var string) = 
+proc renderTocEntries*(d: var TRstGenerator, j: var int, lvl: int, result: var string) =
   var tmp = ""
   while j <= high(d.tocPart): 
     var a = abs(d.tocPart[j].n.level)
@@ -678,8 +739,26 @@ $content
 
 proc rstToHtml*(s: string, options: TRstParseOptions, 
                 config: PStringTable): string =
-  ## exported for *nimforum*.
-  
+  ## Converts an input rst string into embeddable HTML.
+  ##
+  ## This convenience proc parses any input string using rst markup (it doesn't
+  ## have to be a full document!) and returns an embeddable piece of HTML. The
+  ## proc is meant to be used in *online* environments without access to a
+  ## meaningful filesystem, and therefore rst ``include`` like directives won't
+  ## work. For an explanation of the ``config`` parameter see the
+  ## ``initRstGenerator`` proc. Example:
+  ##
+  ## .. code-block:: nimrod
+  ##   import packages/docutils/rstgen, strtabs
+  ##
+  ##   echo rstToHtml("*Hello* **world**!", {},
+  ##     newStringTable(modeStyleInsensitive))
+  ##   # --> <em>Hello</em> <strong>world</strong>!
+  ##
+  ## If you need to allow the rst ``include`` directive or tweak the generated
+  ## output you have to create your own ``TRstGenerator`` with
+  ## ``initRstGenerator`` and related procs.
+
   proc myFindFile(filename: string): string = 
     # we don't find any files in online mode:
     result = ""
@@ -692,4 +771,8 @@ proc rstToHtml*(s: string, options: TRstParseOptions,
   var rst = rstParse(s, filen, 0, 1, dummyHasToc, options)
   result = ""
   renderRstToOut(d, rst, result)
-  
+
+
+when isMainModule:
+  echo rstToHtml("*Hello* **world**!", {},
+    newStringTable(modeStyleInsensitive))
diff --git a/lib/pure/actors.cfg b/lib/pure/actors.nimrod.cfg
index c6bb9c545..c6bb9c545 100644
--- a/lib/pure/actors.cfg
+++ b/lib/pure/actors.nimrod.cfg
diff --git a/lib/pure/browsers.nim b/lib/pure/browsers.nim
index 6f5bf7ddb..b44f406c5 100644
--- a/lib/pure/browsers.nim
+++ b/lib/pure/browsers.nim
@@ -33,10 +33,10 @@ proc openDefaultBrowser*(url: string) =
     else:
       discard ShellExecuteA(0'i32, "open", url, nil, nil, SW_SHOWNORMAL)
   elif defined(macosx):
-    discard execShellCmd("open " & quoteIfContainsWhite(url))
+    discard execShellCmd("open " & quoteShell(url))
   else:
     const attempts = ["gnome-open ", "kde-open ", "xdg-open "]
-    var u = quoteIfContainsWhite(url)
+    var u = quoteShell(url)
     for a in items(attempts):
       if execShellCmd(a & u) == 0: return
     for b in getEnv("BROWSER").string.split(PathSep):
diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim
index c499abdc0..29c686fd7 100644
--- a/lib/pure/cgi.nim
+++ b/lib/pure/cgi.nim
@@ -342,16 +342,35 @@ proc writeContentType*() =
   ##
   ## .. code-block:: Nimrod
   ##     write(stdout, "Content-type: text/html\n\n")
-  ##
-  ## It also modifies the debug stack traces so that they contain
-  ## ``<br />`` and are easily readable in a browser.
   write(stdout, "Content-type: text/html\n\n")
-  system.stackTraceNewLine = "<br />\n"
 
-proc setStackTraceNewLine*() =
-  ## Modifies the debug stack traces so that they contain
-  ## ``<br />`` and are easily readable in a browser.
-  system.stackTraceNewLine = "<br />\n"
+proc resetForStacktrace() =
+  stdout.write """<!--: spam
+Content-Type: text/html
+
+<body bgcolor=#f0f0f8><font color=#f0f0f8 size=-5> -->
+<body bgcolor=#f0f0f8><font color=#f0f0f8 size=-5> --> -->
+</font> </font> </font> </script> </object> </blockquote> </pre>
+</table> </table> </table> </table> </table> </font> </font> </font>
+"""
+
+proc writeErrorMessage*(data: string) =
+  ## Tries to reset browser state and writes `data` to stdout in
+  ## <plaintext> tag.
+  resetForStacktrace()
+  # We use <plaintext> here, instead of escaping, so stacktrace can
+  # be understood by human looking at source.
+  stdout.write("<plaintext>\n")
+  stdout.write(data)
+
+proc setStackTraceStdout*() =
+  ## Makes Nimrod output stacktraces to stdout, instead of server log.
+  errorMessageWriter = writeErrorMessage
+
+proc setStackTraceNewLine*() {.deprecated.} =
+  ## Makes Nimrod output stacktraces to stdout, instead of server log.
+  ## Depracated alias for setStackTraceStdout.
+  setStackTraceStdout()
 
 proc setCookie*(name, value: string) =
   ## Sets a cookie.
@@ -374,4 +393,3 @@ when isMainModule:
   const test1 = "abc\L+def xyz"
   assert UrlEncode(test1) == "abc%0A%2Bdef+xyz"
   assert UrlDecode(UrlEncode(test1)) == test1
-
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index d5c4acaec..91893d169 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -956,17 +956,37 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
   if crename(source, dest) != 0'i32:
     raise newException(EOS, $strerror(errno))
 
-when not defined(ENOENT):
+when not defined(ENOENT) and not defined(Windows):
   var ENOENT {.importc, header: "<errno.h>".}: cint
 
+when defined(Windows):
+  when useWinUnicode:
+    template DeleteFile(file: expr): expr {.immediate.} = DeleteFileW(file)
+    template SetFileAttributes(file, attrs: expr): expr {.immediate.} = 
+      SetFileAttributesW(file, attrs)
+  else:
+    template DeleteFile(file: expr): expr {.immediate.} = DeleteFileA(file)
+    template SetFileAttributes(file, attrs: expr): expr {.immediate.} = 
+      SetFileAttributesA(file, attrs)
+
 proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
   ## Removes the `file`. If this fails, `EOS` 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):
-    setFilePermissions(file, {fpUserWrite})
-  if cremove(file) != 0'i32 and errno != ENOENT:
-    raise newException(EOS, $strerror(errno))
+    when useWinUnicode:
+      let f = newWideCString(file)
+    else:
+      let f = file
+    if DeleteFile(f) == 0:
+      if GetLastError() == ERROR_ACCESS_DENIED: 
+        if SetFileAttributes(f, FILE_ATTRIBUTE_NORMAL) == 0:
+          OSError(OSLastError())
+        if DeleteFile(f) == 0:
+          OSError(OSLastError())
+  else:
+    if cremove(file) != 0'i32 and errno != ENOENT:
+      raise newException(EOS, $strerror(errno))
 
 proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
   tags: [FExecIO].} =
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index 754e34b85..61b940ce8 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -41,6 +41,58 @@ type
     poStdErrToStdOut,    ## merge stdout and stderr to the stdout stream
     poParentStreams      ## use the parent's streams
 
+proc quoteShellWindows*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
+  ## Quote s, so it can be safely passed to Windows API.
+  ## Based on Python's subprocess.list2cmdline
+  ## See http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
+  let needQuote = {' ', '\t'} in s or s.len == 0
+
+  result = ""
+  var backslashBuff = ""
+  if needQuote:
+    result.add("\"")
+
+  for c in s:
+    if c == '\\':
+      backslashBuff.add(c)
+    elif c == '\"':
+      result.add(backslashBuff)
+      result.add(backslashBuff)
+      backslashBuff.setLen(0)
+      result.add("\\\"")
+    else:
+      if backslashBuff.len != 0:
+        result.add(backslashBuff)
+        backslashBuff.setLen(0)
+      result.add(c)
+
+  if needQuote:
+    result.add("\"")
+
+proc quoteShellPosix*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
+  ## Quote s, so it can be safely passed to POSIX shell.
+  ## Based on Python's pipes.quote
+  const safeUnixChars = {'%', '+', '-', '.', '/', '_', ':', '=', '@',
+                         '0'..'9', 'A'..'Z', 'a'..'z'}
+  if s.len == 0:
+    return "''"
+
+  let safe = s.allCharsInSet(safeUnixChars)
+
+  if safe:
+    return s
+  else:
+    return "'" & s.replace("'", "'\"'\"'") & "'"
+
+proc quoteShell*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
+  ## Quote s, so it can be safely passed to shell.
+  when defined(Windows):
+    return quoteShellWindows(s)
+  elif defined(posix):
+    return quoteShellPosix(s)
+  else:
+    {.error:"quoteShell is not supported on your system".}
+
 proc execProcess*(command: string,
                   options: set[TProcessOption] = {poStdErrToStdOut,
                                                   poUseShell}): TaintedString {.
@@ -307,10 +359,10 @@ when defined(Windows) and not defined(useNimRtl):
     result.writeDataImpl = hsWriteData
 
   proc buildCommandLine(a: string, args: openarray[string]): cstring =
-    var res = quoteIfContainsWhite(a)
+    var res = quoteShell(a)
     for i in 0..high(args):
       res.add(' ')
-      res.add(quoteIfContainsWhite(args[i]))
+      res.add(quoteShell(args[i]))
     result = cast[cstring](alloc0(res.len+1))
     copyMem(result, cstring(res), res.len)
 
@@ -510,10 +562,10 @@ elif not defined(useNimRtl):
     writeIdx = 1
 
   proc addCmdArgs(command: string, args: openarray[string]): string =
-    result = quoteIfContainsWhite(command)
+    result = quoteShell(command)
     for i in 0 .. high(args):
       add(result, " ")
-      add(result, quoteIfContainsWhite(args[i]))
+      add(result, quoteShell(args[i]))
 
   proc toCStringArray(b, a: openarray[string]): cstringArray =
     result = cast[cstringArray](alloc0((a.len + b.len + 1) * sizeof(cstring)))
@@ -792,5 +844,14 @@ proc execCmdEx*(command: string, options: set[TProcessOption] = {
   close(p)
 
 when isMainModule:
-  var x = execProcess("gcc -v")
-  echo "ECHO ", x
+  assert quoteShellWindows("aaa") == "aaa"
+  assert quoteShellWindows("aaa\"") == "aaa\\\""
+  assert quoteShellWindows("") == "\"\""
+
+  assert quoteShellPosix("aaa") == "aaa"
+  assert quoteShellPosix("aaa a") == "'aaa a'"
+  assert quoteShellPosix("") == "''"
+  assert quoteShellPosix("a'a") == "'a'\"'\"'a'"
+
+  when defined(posix):
+    assert quoteShell("") == "''"
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 79525aa18..e290226d2 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -709,9 +709,11 @@ proc rfind*(s, sub: string, start: int = -1): int {.noSideEffect.} =
     if result != -1: return
   return -1
 

-proc quoteIfContainsWhite*(s: string): string =

+proc quoteIfContainsWhite*(s: string): string {.deprecated.} =
   ## returns ``'"' & s & '"'`` if `s` contains a space and does not

   ## start with a quote, else returns `s`

+  ## DEPRECATED as it was confused for shell quoting function.
+  ## For this application use osproc.quoteShell.
   if find(s, {' ', '\t'}) >= 0 and s[0] != '"':

     result = '"' & s & '"'

   else:

diff --git a/lib/system.nim b/lib/system.nim
index dc5a406d1..106eb04a3 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -923,6 +923,10 @@ proc quit*(errorcode: int = QuitSuccess) {.
   ## The proc ``quit(QuitSuccess)`` is called implicitly when your nimrod
   ## program finishes without incident. A raised unhandled exception is
   ## equivalent to calling ``quit(QuitFailure)``.
+  ##
+  ## Note that this is a *runtime* call and using ``quit`` inside a macro won't
+  ## have any compile time effect. If you need to stop the compiler inside a
+  ## macro, use the ``error`` or ``fatal`` pragmas.
 
 template sysAssert(cond: bool, msg: string) =
   when defined(useSysAssert):
@@ -1947,15 +1951,13 @@ when not defined(JS): #and not defined(NimrodVM):
         ## The standard output stream.
       stderr* {.importc: "stderr", header: "<stdio.h>".}: TFile
         ## The standard error stream.
-        ##
-        ## Note: In my opinion, this should not be used -- the concept of a
-        ## separate error stream is a design flaw of UNIX. A separate *message
-        ## stream* is a good idea, but since it is named ``stderr`` there are few
-        ## programs out there that distinguish properly between ``stdout`` and
-        ## ``stderr``. So, that's what you get if you don't name your variables
-        ## appropriately. It also annoys people if redirection
-        ## via ``>output.txt`` does not work because the program writes
-        ## to ``stderr``.
+
+    when defined(useStdoutAsStdmsg):
+      template stdmsg*: TFile = stdout
+    else:
+      template stdmsg*: TFile = stderr
+        ## Template which expands to either stdout or stderr depending on
+        ## `useStdoutAsStdmsg` compile-time switch.
 
     proc Open*(f: var TFile, filename: string,
                mode: TFileMode = fmRead, bufSize: int = -1): Bool {.tags: [].}
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index 2bab79212..17258cf68 100644
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -760,7 +760,7 @@ proc getOccupiedMem(a: TMemRegion): int {.inline.} =
 # ---------------------- thread memory region -------------------------------
 
 template InstantiateForRegion(allocator: expr) =
-  when false:
+  when defined(fulldebug):
     proc interiorAllocatedPtr*(p: pointer): pointer =
       result = interiorAllocatedPtr(allocator, p)
 
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 7937d9738..9b6a64fb0 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -11,14 +11,13 @@
 # use the heap (and nor exceptions) do not include the GC or memory allocator.
 
 var
-  stackTraceNewLine*: string ## undocumented feature; it is replaced by ``<br>``
-                             ## for CGI applications
-
-template stackTraceNL: expr =
-  (if IsNil(stackTraceNewLine): "\n" else: stackTraceNewLine)
+  errorMessageWriter*: (proc(msg: string): void {.tags: [FWriteIO].})
+    ## Function that will be called
+    ## instead of stdmsg.write when printing stacktrace.
+    ## Unstable API.
 
 when not defined(windows) or not defined(guiapp):
-  proc writeToStdErr(msg: CString) = write(stdout, msg)
+  proc writeToStdErr(msg: CString) = write(stdmsg, msg)
 
 else:
   proc MessageBoxA(hWnd: cint, lpText, lpCaption: cstring, uType: int): int32 {.
@@ -27,6 +26,12 @@ else:
   proc writeToStdErr(msg: CString) =
     discard MessageBoxA(0, msg, nil, 0)
 
+proc showErrorMessage(data: cstring) =
+  if errorMessageWriter != nil:
+    errorMessageWriter($data)
+  else:
+    writeToStdErr(data)
+
 proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
 proc chckRange(i, a, b: int): int {.inline, compilerproc.}
 proc chckRangeF(x, a, b: float): float {.inline, compilerproc.}
@@ -111,7 +116,7 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
             add(s, tempDlInfo.dli_sname)
         else:
           add(s, '?')
-        add(s, stackTraceNL)
+        add(s, "\n")
       else:
         if dlresult != 0 and tempDlInfo.dli_sname != nil and
             c_strcmp(tempDlInfo.dli_sname, "signalHandler") == 0'i32:
@@ -172,21 +177,18 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
         add(s, ')')
       for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ')
       add(s, tempFrames[j].procname)
-    add(s, stackTraceNL)
+    add(s, "\n")
 
 when hasSomeStackTrace:
   proc rawWriteStackTrace(s: var string) =
     when nimrodStackTrace:
       if framePtr == nil:
-        add(s, "No stack traceback available")
-        add(s, stackTraceNL)
+        add(s, "No stack traceback available\n")
       else:
-        add(s, "Traceback (most recent call last)")
-        add(s, stackTraceNL)
+        add(s, "Traceback (most recent call last)\n")
         auxWriteStackTrace(framePtr, s)
     elif defined(nativeStackTrace) and nativeStackTraceSupported:
-      add(s, "Traceback from system (most recent call last)")
-      add(s, stackTraceNL)
+      add(s, "Traceback from system (most recent call last)\n")
       auxWriteStackTraceWithBacktrace(s)
     else:
       add(s, "No stack traceback available\n")
@@ -207,7 +209,7 @@ proc raiseExceptionAux(e: ref E_Base) =
       pushCurrentException(e)
       c_longjmp(excHandler.context, 1)
   elif e[] of EOutOfMemory:
-    writeToStdErr(e.name)
+    showErrorMessage(e.name)
     quitOrDebug()
   else:
     when hasSomeStackTrace:
@@ -219,7 +221,7 @@ proc raiseExceptionAux(e: ref E_Base) =
       add(buf, " [")
       add(buf, $e.name)
       add(buf, "]\n")
-      writeToStdErr(buf)
+      showErrorMessage(buf)
     else:
       # ugly, but avoids heap allocations :-)
       template xadd(buf, s, slen: expr) =
@@ -235,7 +237,7 @@ proc raiseExceptionAux(e: ref E_Base) =
       add(buf, " [")
       xadd(buf, e.name, c_strlen(e.name))
       add(buf, "]\n")
-      writeToStdErr(buf)
+      showErrorMessage(buf)
     quitOrDebug()
 
 proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
@@ -255,9 +257,9 @@ proc WriteStackTrace() =
   when hasSomeStackTrace:
     var s = ""
     rawWriteStackTrace(s)
-    writeToStdErr(s)
+    showErrorMessage(s)
   else:
-    writeToStdErr("No stack traceback available\n")
+    showErrorMessage("No stack traceback available\n")
 
 proc getStackTrace(): string =
   when hasSomeStackTrace:
@@ -298,13 +300,13 @@ when not defined(noSignalHandler):
       var buf = newStringOfCap(2000)
       rawWriteStackTrace(buf)
       processSignal(sig, buf.add) # nice hu? currying a la nimrod :-)
-      writeToStdErr(buf)
+      showErrorMessage(buf)
       GC_enable()
     else:
       var msg: cstring
       template asgn(y: expr) = msg = y
       processSignal(sig, asgn)
-      writeToStdErr(msg)
+      showErrorMessage(msg)
     when defined(endb): dbgAborting = True
     quit(1) # always quit when SIGABRT
 
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index d2b065d6b..68e8b423d 100644
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -345,8 +345,9 @@ proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp) =
 
 proc forAllChildren(cell: PCell, op: TWalkOp) =
   gcAssert(cell != nil, "forAllChildren: 1")
-  gcAssert(cell.typ != nil, "forAllChildren: 2")
-  gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 3"
+  gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2")
+  gcAssert(cell.typ != nil, "forAllChildren: 3")
+  gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 4"
   let marker = cell.typ.marker
   if marker != nil:
     marker(cellToUsr(cell), op.int)
@@ -361,7 +362,7 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
         for i in 0..s.len-1:
           forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +%
             GenericSeqSize), 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.
@@ -408,8 +409,10 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
     add(gch.zct, res)
 
 {.push stackTrace: off, profiler:off.}
-proc gcInvariant*(msg: string) =
-  sysAssert(allocInv(gch.region), msg)
+proc gcInvariant*() =
+  sysAssert(allocInv(gch.region), "injected")
+  when defined(markForDebug):
+    markForDebug(gch)
 {.pop.}
 
 proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index 118272ee3..942b6778e 100644
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -18,7 +18,8 @@ const
   logGC = false
   traceGC = false # extensive debugging
   alwaysCycleGC = false
-  alwaysGC = false # collect after every memory allocation (for debugging)
+  alwaysGC = defined(fulldebug) # collect after every memory
+                                # allocation (for debugging)
   leakDetector = false
   overwriteFree = false
   trackAllocationSource = leakDetector
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 56d279db6..264285d09 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -416,17 +416,17 @@ var
   SOMAXCONN* {.importc, header: "Winsock2.h".}: cint
   INVALID_SOCKET* {.importc, header: "Winsock2.h".}: TSocketHandle
   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_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
 
 proc `==`*(x, y: TSocketHandle): bool {.borrow.}
@@ -553,18 +553,26 @@ const
 
   FILE_FLAG_BACKUP_SEMANTICS* = 33554432'i32
 
+# Error Constants
+const
+  ERROR_ACCESS_DENIED* = 5
+
 when useWinUnicode:
   proc CreateFileW*(lpFileName: widecstring, dwDesiredAccess, dwShareMode: DWORD,
                     lpSecurityAttributes: pointer,
                     dwCreationDisposition, dwFlagsAndAttributes: DWORD,
                     hTemplateFile: THANDLE): THANDLE {.
       stdcall, dynlib: "kernel32", importc: "CreateFileW".}
+  proc DeleteFileW*(pathName: widecstring): int32 {.
+    importc: "DeleteFileW", dynlib: "kernel32", stdcall.}
 else:
   proc CreateFileA*(lpFileName: cstring, dwDesiredAccess, dwShareMode: DWORD,
                     lpSecurityAttributes: pointer,
                     dwCreationDisposition, dwFlagsAndAttributes: DWORD,
                     hTemplateFile: THANDLE): THANDLE {.
       stdcall, dynlib: "kernel32", importc: "CreateFileA".}
+  proc DeleteFileA*(pathName: cstring): int32 {.
+    importc: "DeleteFileA", dynlib: "kernel32", stdcall.}
 
 proc SetEndOfFile*(hFile: THANDLE): WINBOOL {.stdcall, dynlib: "kernel32",
     importc: "SetEndOfFile".}
diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim
index 25ec0d283..0c9717e12 100644
--- a/tools/niminst/niminst.nim
+++ b/tools/niminst/niminst.nim
@@ -14,7 +14,7 @@ when haveZipLib:
   import zipfiles
 
 import
-  os, strutils, parseopt, parsecfg, strtabs, streams, debcreation
+  os, osproc, strutils, parseopt, parsecfg, strtabs, streams, debcreation
 
 const
   maxOS = 20 # max number of OSes
@@ -486,7 +486,7 @@ proc setupDist(c: var TConfigData) =
     if c.innoSetup.path.len == 0:
       c.innoSetup.path = "iscc.exe"
     var outcmd = if c.outdir.len == 0: "build" else: c.outdir
-    var cmd = "$# $# /O$# $#" % [quoteIfContainsWhite(c.innoSetup.path),
+    var cmd = "$# $# /O$# $#" % [quoteShell(c.innoSetup.path),
                                  c.innoSetup.flags, outcmd, n]
     echo(cmd)
     if execShellCmd(cmd) == 0:
@@ -587,4 +587,3 @@ if actionZip in c.actions:
     quit("libzip is not installed")
 if actionDeb in c.actions:
   debDist(c)
-
diff --git a/web/news.txt b/web/news.txt
index 7bb0676ee..c87c9f974 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -28,7 +28,8 @@ Changes affecting backwards compatibility
   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 user only if cgi.setStackTraceStdout
+  is used.
 
 Compiler Additions
 ------------------