summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.gitmodules3
-rwxr-xr-x[-rw-r--r--]build.sh4
-rw-r--r--compiler/cgen.nim9
-rw-r--r--compiler/extccomp.nim11
-rw-r--r--compiler/jsgen.nim4
-rw-r--r--compiler/main.nim2
-rw-r--r--compiler/modules.nim29
-rw-r--r--compiler/nim.nim9
-rw-r--r--compiler/nimsuggest/nimsuggest.nim210
-rw-r--r--compiler/options.nim20
-rw-r--r--compiler/passes.nim6
-rw-r--r--compiler/sigmatch.nim5
-rw-r--r--compiler/suggest.nim116
-rw-r--r--compiler/vm.nim4
-rw-r--r--config/nim.cfg1
m---------csources0
-rw-r--r--doc/astspec.txt2
-rw-r--r--doc/lib.txt4
-rw-r--r--doc/manual/threads.txt4
-rw-r--r--doc/spawn.txt2
-rw-r--r--doc/tut1.txt4
-rw-r--r--lib/core/macros.nim6
-rw-r--r--lib/impure/re.nim4
-rw-r--r--lib/pure/algorithm.nim19
-rw-r--r--lib/pure/asyncdispatch.nim4
-rw-r--r--lib/pure/collections/tables.nim24
-rw-r--r--lib/pure/concurrency/threadpool.nim2
-rw-r--r--lib/pure/hashes.nim66
-rw-r--r--lib/pure/httpclient.nim16
-rw-r--r--lib/pure/json.nim65
-rw-r--r--lib/pure/math.nim22
-rw-r--r--lib/pure/net.nim10
-rw-r--r--lib/pure/os.nim4
-rw-r--r--lib/pure/osproc.nim26
-rw-r--r--lib/pure/rawsockets.nim4
-rw-r--r--lib/pure/scgi.nim2
-rw-r--r--lib/pure/sexp.nim697
-rw-r--r--lib/pure/sockets.nim18
-rw-r--r--lib/pure/streams.nim99
-rw-r--r--lib/pure/strutils.nim20
-rw-r--r--lib/pure/times.nim21
-rw-r--r--lib/system.nim19
-rw-r--r--lib/system/arithm.nim8
-rw-r--r--lib/system/chcks.nim6
-rw-r--r--lib/windows/windows.nim79
-rw-r--r--tests/collections/tsets.nim48
-rw-r--r--tests/collections/ttables.nim16
-rw-r--r--tests/collections/ttablesref.nim18
-rw-r--r--tests/macros/tgettype.nim20
-rw-r--r--tests/manyloc/standalone/panicoverride.nim6
-rw-r--r--tests/metatype/ttypedesc3.nim19
-rw-r--r--tests/readme.txt5
-rw-r--r--tests/realtimeGC/cmain.c67
-rw-r--r--tests/realtimeGC/main.nim.cfg6
-rw-r--r--tests/realtimeGC/nmain.nim46
-rw-r--r--tests/realtimeGC/readme.txt21
-rw-r--r--tests/realtimeGC/shared.nim63
-rw-r--r--tests/realtimeGC/shared.nim.cfg5
-rw-r--r--tests/testament/categories.nim14
-rw-r--r--tests/testament/tester.nim35
-rw-r--r--web/news.txt5
62 files changed, 1777 insertions, 308 deletions
diff --git a/.gitignore b/.gitignore
index d804fb8f5..462df4efc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,4 +41,3 @@ xcuserdata/
 /testresults.html
 /testresults.json
 testament.db
-/csources/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 000000000..26f35d82c
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "csources"]
+	path = csources
+	url = ../../nim-lang/csources.git
diff --git a/build.sh b/build.sh
index 139c28359..91e169241 100644..100755
--- a/build.sh
+++ b/build.sh
@@ -2,8 +2,8 @@
 set -e
 set -x
 
-if [ ! -d "csources" ]; then
-	git clone --depth 1 https://github.com/nim-lang/csources.git
+if [ ! -e csources/.git ]; then
+	git submodule update --init --depth 1
 fi
 
 cd "csources"
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index da9c6f653..4b0bac28a 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -676,8 +676,11 @@ proc genProcAux(m: BModule, prc: PSym) =
   closureSetup(p, prc)
   genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
   var generatedProc: Rope
+  if sfNoReturn in prc.flags:
+    if hasDeclspec in extccomp.CC[extccomp.cCompiler].props:
+      header = "__declspec(noreturn) " & header
   if sfPure in prc.flags:
-    if hasNakedDeclspec in extccomp.CC[extccomp.cCompiler].props:
+    if hasDeclspec in extccomp.CC[extccomp.cCompiler].props:
       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))
@@ -720,8 +723,10 @@ proc genProcPrototype(m: BModule, sym: PSym) =
     var header = genProcHeader(m, sym)
     if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym):
       header = "extern \"C\" " & header
-    if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props:
+    if sfPure in sym.flags and hasAttribute in CC[cCompiler].props:
       header.add(" __attribute__((naked))")
+    if sfNoReturn in sym.flags and hasAttribute in CC[cCompiler].props:
+      header.add(" __attribute__((noreturn))")
     add(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
 
 proc genProcNoForward(m: BModule, prc: PSym) =
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index 26f0318ee..186a3884d 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -26,8 +26,8 @@ type
     hasAssume,                # CC has __assume (Visual C extension)
     hasGcGuard,               # CC supports GC_GUARD to keep stack roots
     hasGnuAsm,                # CC's asm uses the absurd GNU assembler syntax
-    hasNakedDeclspec,         # CC has __declspec(naked)
-    hasNakedAttribute         # CC has __attribute__((naked))
+    hasDeclspec,              # CC has __declspec(X)
+    hasAttribute,             # CC has __attribute__((X))
   TInfoCCProps* = set[TInfoCCProp]
   TInfoCC* = tuple[
     name: string,        # the short name of the compiler
@@ -85,7 +85,7 @@ compiler gcc:
     structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name
     packedPragma: "__attribute__((__packed__))",
     props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
-            hasNakedAttribute})
+            hasAttribute})
 
 # LLVM Frontend for GCC/G++
 compiler llvmGcc:
@@ -127,7 +127,7 @@ compiler vcc:
     asmStmtFrmt: "__asm{$n$1$n}$n",
     structStmtFmt: "$3$n$1 $2",
     packedPragma: "#pragma pack(1)",
-    props: {hasCpp, hasAssume, hasNakedDeclspec})
+    props: {hasCpp, hasAssume, hasDeclspec})
 
 # Intel C/C++ Compiler
 compiler icl:
@@ -668,7 +668,8 @@ proc callCCompiler*(projectfile: string) =
       it = PStrEntry(it.next)
 
     if optGenStaticLib in gGlobalOptions:
-      linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % gProjectName),
+      let name = splitFile(gProjectName).name
+      linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % name),
                                   "objfiles", objfiles]
     else:
       var linkerExe = getConfigVar(c, ".linkerexe")
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 704713243..5c7071498 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -1052,11 +1052,13 @@ proc genArg(p: PProc, n: PNode, r: var TCompRes) =
 
 proc genArgs(p: PProc, n: PNode, r: var TCompRes) =
   add(r.res, "(")
+  var hasArgs = false
   for i in countup(1, sonsLen(n) - 1):
     let it = n.sons[i]
     if it.typ.isCompileTimeOnly: continue
-    if i > 1: add(r.res, ", ")
+    if hasArgs: add(r.res, ", ")
     genArg(p, it, r)
+    hasArgs = true
   add(r.res, ")")
   r.kind = resExpr
 
diff --git a/compiler/main.nim b/compiler/main.nim
index 0c80c19b7..a01b6fe4f 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -63,7 +63,7 @@ proc commandCompileToC =
   compileProject()
   cgenWriteModules()
   if gCmd != cmdRun:
-    extccomp.callCCompiler(if gProjectName == "-": "stdinfile" else: changeFileExt(gProjectFull, ""))
+    extccomp.callCCompiler(changeFileExt(gProjectFull, ""))
 
   if isServing:
     # caas will keep track only of the compilation commands
diff --git a/compiler/modules.nim b/compiler/modules.nim
index a2b739efc..2fa46f356 100644
--- a/compiler/modules.nim
+++ b/compiler/modules.nim
@@ -10,8 +10,8 @@
 ## implements the module handling
 
 import
-  ast, astalgo, magicsys, crc, rodread, msgs, cgendata, sigmatch, options, 
-  idents, os, lexer, idgen, passes, syntaxes
+  ast, astalgo, magicsys, crc, rodread, msgs, cgendata, sigmatch, options,
+  idents, os, lexer, idgen, passes, syntaxes, llstream
 
 type
   TNeedRecompile* = enum Maybe, No, Yes, Probing, Recompiled
@@ -39,12 +39,12 @@ template crc(x: PSym): expr =
 
 proc crcChanged(fileIdx: int32): bool =
   internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len
-  
+
   template updateStatus =
     gMemCacheData[fileIdx].crcStatus = if result: crcHasChanged
                                        else: crcNotChanged
     # echo "TESTING CRC: ", fileIdx.toFilename, " ", result
-  
+
   case gMemCacheData[fileIdx].crcStatus:
   of crcHasChanged:
     result = true
@@ -96,7 +96,7 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
   if optForceFullMake in gGlobalOptions or
      crcChanged(fileIdx):
        markDirty
-  
+
   if gMemCacheData[fileIdx].deps != nil:
     gMemCacheData[fileIdx].needsRecompile = Probing
     for dep in gMemCacheData[fileIdx].deps:
@@ -104,30 +104,30 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
       if d in {Yes, Recompiled}:
         # echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
         markDirty
-  
+
   gMemCacheData[fileIdx].needsRecompile = No
   return No
 
 proc newModule(fileIdx: int32): PSym =
   # We cannot call ``newSym`` here, because we have to circumvent the ID
-  # mechanism, which we do in order to assign each module a persistent ID. 
+  # mechanism, which we do in order to assign each module a persistent ID.
   new(result)
   result.id = - 1             # for better error checking
   result.kind = skModule
   let filename = fileIdx.toFullPath
   result.name = getIdent(splitFile(filename).name)
-  if result.name.s != "-" and not isNimIdentifier(result.name.s):
+  if not isNimIdentifier(result.name.s):
     rawMessage(errInvalidModuleName, result.name.s)
-  
+
   result.info = newLineInfo(fileIdx, 1, 1)
   result.owner = newSym(skPackage, getIdent(getPackageName(filename)), nil,
                         result.info)
   result.position = fileIdx
-  
+
   growCache gMemCacheData, fileIdx
   growCache gCompiledModules, fileIdx
   gCompiledModules[result.position] = result
-  
+
   incl(result.flags, sfUsed)
   initStrTable(result.tab)
   strTableAdd(result.tab, result) # a module knows itself
@@ -143,12 +143,15 @@ proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym =
     result.flags = result.flags + flags
     if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
       rd = handleSymbolFile(result)
-      if result.id < 0: 
+      if result.id < 0:
         internalError("handleSymbolFile should have set the module\'s ID")
         return
     else:
       result.id = getID()
-    processModule(result, nil, rd)
+    if sfMainModule in flags and gProjectIsStdin:
+      processModule(result, llStreamOpen(stdin), rd)
+    else:
+      processModule(result, nil, rd)
     if optCaasEnabled in gGlobalOptions:
       gMemCacheData[fileIdx].compiledAt = gLastCmdTime
       gMemCacheData[fileIdx].needsRecompile = Recompiled
diff --git a/compiler/nim.nim b/compiler/nim.nim
index b8ba2c6da..89db22e8f 100644
--- a/compiler/nim.nim
+++ b/compiler/nim.nim
@@ -38,7 +38,12 @@ proc handleCmdLine() =
   else:
     # Process command line arguments:
     processCmdLine(passCmd1, "")
-    if gProjectName != "":
+    if gProjectName == "-":
+      gProjectName = "stdinfile"
+      gProjectFull = "stdinfile"
+      gProjectPath = getCurrentDir()
+      gProjectIsStdin = true
+    elif gProjectName != "":
       try:
         gProjectFull = canonicalizePath(gProjectName)
       except OSError:
@@ -61,8 +66,6 @@ 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:
diff --git a/compiler/nimsuggest/nimsuggest.nim b/compiler/nimsuggest/nimsuggest.nim
index 8285d81d9..2c785d118 100644
--- a/compiler/nimsuggest/nimsuggest.nim
+++ b/compiler/nimsuggest/nimsuggest.nim
@@ -9,9 +9,17 @@
 
 ## Nimsuggest is a tool that helps to give editors IDE like capabilities.
 
-import strutils, os, parseopt, parseUtils
+import strutils, os, parseopt, parseutils, sequtils, net
+# Do NOT import suggest. It will lead to wierd bugs with
+# suggestionResultHook, because suggest.nim is included by sigmatch.
+# So we import that one instead.
 import options, commands, modules, sem, passes, passaux, msgs, nimconf,
-  extccomp, condsyms, lists, net, rdstdin
+  extccomp, condsyms, lists, net, rdstdin, sexp, sigmatch, ast
+
+when defined(windows):
+  import winlean
+else:
+  import posix
 
 const Usage = """
 Nimsuggest - Tool to give every editor IDE like capabilities for Nim
@@ -23,17 +31,20 @@ Options:
   --address:HOST          binds to that address, by default ""
   --stdin                 read commands from stdin and write results to
                           stdout instead of using sockets
+  --epc                   use emacs epc mode
 
 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.
 """
+type
+  Mode = enum mstdin, mtcp, mepc
 
 var
   gPort = 6000.Port
   gAddress = ""
-  gUseStdin: bool
+  gMode: Mode
 
 const
   seps = {':', ';', ' ', '\t'}
@@ -42,6 +53,9 @@ const
          "type 'debug' to toggle debug mode on/off\n" &
          "type 'terse' to toggle terse mode on/off"
 
+type
+  EUnexpectedCommand = object of Exception
+
 proc parseQuoted(cmd: string; outp: var string; start: int): int =
   var i = start
   i += skipWhitespace(cmd, i)
@@ -51,7 +65,95 @@ proc parseQuoted(cmd: string; outp: var string; start: int): int =
     i += parseUntil(cmd, outp, seps, i)
   result = i
 
-proc action(cmd: string) =
+proc sexp(s: IdeCmd): SexpNode = sexp($s)
+
+proc sexp(s: TSymKind): SexpNode = sexp($s)
+
+proc sexp(s: Suggest): SexpNode =
+  # If you change the oder here, make sure to change it over in
+  # nim-mode.el too.
+  result = convertSexp([
+    s.section,
+    s.symkind,
+    s.qualifiedPath.map(newSString),
+    s.filePath,
+    s.forth,
+    s.line,
+    s.column,
+    s.doc
+  ])
+
+proc sexp(s: seq[Suggest]): SexpNode =
+  result = newSList()
+  for sug in s:
+    result.add(sexp(sug))
+
+proc listEPC(): SexpNode =
+  let
+    argspecs = sexp("file line column dirtyfile".split(" ").map(newSSymbol))
+    docstring = sexp("line starts at 1, column at 0, dirtyfile is optional")
+  result = newSList()
+  for command in ["sug", "con", "def", "use"]:
+    let
+      cmd = sexp(command)
+      methodDesc = newSList()
+    methodDesc.add(cmd)
+    methodDesc.add(argspecs)
+    methodDesc.add(docstring)
+    result.add(methodDesc)
+
+proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int) =
+  gIdeCmd = cmd
+  if cmd == ideUse:
+    modules.resetAllModules()
+  var isKnownFile = true
+  let dirtyIdx = file.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)
+  gErrorCounter = 0
+  if not isKnownFile:
+    compileProject()
+  compileProject(dirtyIdx)
+
+proc executeEPC(cmd: IdeCmd, args: SexpNode) =
+  let
+    file = args[0].getStr
+    line = args[1].getNum
+    column = args[2].getNum
+  var dirtyfile = ""
+  if len(args) > 3:
+    dirtyfile = args[3].getStr(nil)
+  execute(cmd, file, dirtyfile, int(line), int(column))
+
+proc returnEPC(socket: var Socket, uid: BiggestInt, s: SexpNode, return_symbol = "return") =
+  let response = $convertSexp([newSSymbol(return_symbol), uid, s])
+  socket.send(toHex(len(response), 6))
+  socket.send(response)
+
+proc connectToNextFreePort(server: Socket, host: string, start = 30000): int =
+  result = start
+  while true:
+    try:
+      server.bindaddr(Port(result), host)
+      return
+    except OsError:
+      when defined(windows):
+        let checkFor = WSAEADDRINUSE.OSErrorCode
+      else:
+        let checkFor = EADDRINUSE.OSErrorCode
+      if osLastError() != checkFor:
+        raise getCurrentException()
+      else:
+        result += 1
+
+proc parseCmdLine(cmd: string) =
   template toggle(sw) =
     if sw in gGlobalOptions:
       excl(gGlobalOptions, sw)
@@ -69,9 +171,7 @@ proc action(cmd: string) =
   of "sug": gIdeCmd = ideSug
   of "con": gIdeCmd = ideCon
   of "def": gIdeCmd = ideDef
-  of "use":
-    modules.resetAllModules()
-    gIdeCmd = ideUse
+  of "use": gIdeCmd = ideUse
   of "quit": quit()
   of "debug": toggle optIdeDebug
   of "terse": toggle optIdeTerse
@@ -88,35 +188,18 @@ proc action(cmd: string) =
   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-1)
-  #echo dirtyfile, gDirtyBufferIdx, " project ", gProjectMainIdx
-  gErrorCounter = 0
-  if not isKnownFile:
-    compileProject(dirtyIdx)
-  else:
-    compileProject()
+  execute(gIdeCmd, orig, dirtyfile, line, col-1)
 
 proc serve() =
-  # do not stop after the first error:
-  msgs.gErrorMax = high(int)
-  if gUseStdin:
+  case gMode:
+  of mstdin:
     echo Help
     var line = ""
     while readLineFromStdin("> ", line):
-      action line
+      parseCmdLine line
       echo ""
       flushFile(stdout)
-  else:
+  of mtcp:
     var server = newSocket()
     server.bindAddr(gPort, gAddress)
     var inp = "".TaintedString
@@ -130,10 +213,55 @@ proc serve() =
       accept(server, stdoutSocket)
 
       stdoutSocket.readLine(inp)
-      action inp.string
+      parseCmdLine inp.string
 
       stdoutSocket.send("\c\L")
       stdoutSocket.close()
+  of mepc:
+    var server = newSocket()
+    let port = connectToNextFreePort(server, "localhost")
+    var inp = "".TaintedString
+    server.listen()
+    echo(port)
+    var client = newSocket()
+    # Wait for connection
+    accept(server, client)
+    while true:
+      var sizeHex = ""
+      if client.recv(sizeHex, 6) != 6:
+        raise newException(ValueError, "didn't get all the hexbytes")
+      var size = 0
+      if parseHex(sizeHex, size) == 0:
+        raise newException(ValueError, "invalid size hex: " & $sizeHex)
+      var messageBuffer = ""
+      if client.recv(messageBuffer, size) != size:
+        raise newException(ValueError, "didn't get all the bytes")
+      let
+        message = parseSexp($messageBuffer)
+        messageType = message[0].getSymbol
+      case messageType:
+      of "call":
+        var results: seq[Suggest] = @[]
+        suggestionResultHook = proc (s: Suggest) =
+          results.add(s)
+
+        let
+          uid = message[1].getNum
+          cmd = parseIdeCmd(message[2].getSymbol)
+          args = message[3]
+        executeEPC(cmd, args)
+        returnEPC(client, uid, sexp(results))
+      of "return":
+        raise newException(EUnexpectedCommand, "no return expected")
+      of "return-error":
+        raise newException(EUnexpectedCommand, "no return expected")
+      of "epc-error":
+        stderr.writeln("recieved epc error: " & $messageBuffer)
+        raise newException(IOError, "epc error")
+      of "methods":
+        returnEPC(client, message[1].getNum, listEPC())
+      else:
+        raise newException(EUnexpectedCommand, "unexpected call: " & messageType)
 
 proc mainCommand =
   registerPass verbosePass
@@ -147,19 +275,29 @@ proc mainCommand =
     # current path is always looked first for modules
     prependStr(searchPaths, gProjectPath)
 
+  # do not stop after the first error:
+  msgs.gErrorMax = high(int)
+  compileProject()
   serve()
 
 proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
   var p = parseopt.initOptParser(cmd)
-  while true:
+  while true: 
     parseopt.next(p)
     case p.kind
-    of cmdEnd: break
-    of cmdLongoption, cmdShortOption:
+    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
+      of "port":
+        gPort = parseInt(p.val).Port
+        gMode = mtcp
+      of "address":
+        gAddress = p.val
+        gMode = mtcp
+      of "stdin": gMode = mstdin
+      of "epc":
+        gMode = mepc
+        gVerbosity = 0          # Port number gotta be first.
       else: processSwitch(pass, p)
     of cmdArgument:
       options.gProjectName = unixToNativePath(p.key)
diff --git a/compiler/options.nim b/compiler/options.nim
index 998ab7781..b3060a180 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -83,11 +83,11 @@ type                          # please make sure we have under 32 options
   TGCMode* = enum             # the selected GC
     gcNone, gcBoehm, gcMarkAndSweep, gcRefc, gcV2, gcGenerational
 
-  TIdeCmd* = enum
+  IdeCmd* = enum
     ideNone, ideSug, ideCon, ideDef, ideUse
 
 var
-  gIdeCmd*: TIdeCmd
+  gIdeCmd*: IdeCmd
 
 const
   ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck,
@@ -149,6 +149,7 @@ var
   gProjectName* = "" # holds a name like 'nimrod'
   gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/
   gProjectFull* = "" # projectPath/projectName
+  gProjectIsStdin* = false # whether we're compiling from stdin
   gProjectMainIdx*: int32 # the canonical path id of the main module
   nimcacheDir* = ""
   command* = "" # the main command (e.g. cc, check, scan, etc)
@@ -395,3 +396,18 @@ template cnimdbg*: expr = p.module.module.fileIdx == gProjectMainIdx
 template pnimdbg*: expr = p.lex.fileIdx == gProjectMainIdx
 template lnimdbg*: expr = L.fileIdx == gProjectMainIdx
 
+proc parseIdeCmd*(s: string): IdeCmd =
+  case s:
+  of "sug": ideSug
+  of "con": ideCon
+  of "def": ideDef
+  of "use": ideUse
+  else: ideNone
+
+proc `$`*(c: IdeCmd): string =
+  case c:
+  of ideSug: "sug"
+  of ideCon: "con"
+  of ideDef: "def"
+  of ideUse: "use"
+  of ideNone: "none"
diff --git a/compiler/passes.nim b/compiler/passes.nim
index 129d8ad47..e031dae10 100644
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -170,11 +170,7 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
     openPasses(a, module)
     if stream == nil:
       let filename = fileIdx.toFullPathConsiderDirty
-      if module.name.s == "-":
-        module.name.s = "stdinfile"
-        s = llStreamOpen(stdin)
-      else:
-        s = llStreamOpen(filename, fmRead)
+      s = llStreamOpen(filename, fmRead)
       if s == nil:
         rawMessage(errCannotOpenFile, filename)
         return
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 2a9d15b5a..7ea2c3d6f 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1281,7 +1281,10 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
     result = implicitConv(nkHiddenStdConv, f, arg, m, c)
   of isSubtype:
     inc(m.subtypeMatches)
-    result = implicitConv(nkHiddenSubConv, f, arg, m, c)
+    if f.kind == tyTypeDesc:
+      result = arg
+    else:
+      result = implicitConv(nkHiddenSubConv, f, arg, m, c)
   of isSubrange:
     inc(m.subtypeMatches)
     if f.kind == tyVar:
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index 6b168670c..659f1fa16 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -15,57 +15,79 @@ import algorithm, sequtils
 
 const
   sep = '\t'
-  sectionSuggest = "sug"
-  sectionDef = "def"
-  sectionContext = "con"
-  sectionUsage = "use"
+
+type
+  Suggest* = object
+    section*: IdeCmd
+    qualifiedPath*: seq[string]
+    filePath*: string
+    line*: int                   # Starts at 1
+    column*: int                 # Starts at 0
+    doc*: string           # Not escaped (yet)
+    symkind*: TSymKind
+    forth*: string               # XXX TODO object on symkind
+
+var
+  suggestionResultHook*: proc (result: Suggest) {.closure.}
 
 #template sectionSuggest(): expr = "##begin\n" & getStackTrace() & "##end\n"
 
 template origModuleName(m: PSym): string = m.name.s
 
-proc symToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string = 
-  result = section
-  result.add(sep)
+proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo): Suggest = 
+  result.section = parseIdeCmd(section)
   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))
+    result.symkind = s.kind
+    result.filePath = toFullPath(li)
+    result.line = toLinenumber(li)
+    result.column = toColumn(li)
   else:
-    result.add($s.kind)
-    result.add(sep)
+    result.symkind = s.kind
+    result.qualifiedPath = @[]
     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(s.name.s)
-    result.add(sep)
+        result.qualifiedPath.add(ow2.origModuleName)
+      result.qualifiedPath.add(ow.origModuleName)
+    result.qualifiedPath.add(s.name.s)
+
     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)
+      result.forth = typeToString(s.typ)
+    else:
+      result.forth = ""
+    result.filePath = toFullPath(li)
+    result.line = toLinenumber(li)
+    result.column = toColumn(li)
     when not defined(noDocgen):
-      result.add(s.extractDocComment.escape)
+      result.doc = s.extractDocComment
+
+proc `$`(suggest: Suggest): string = 
+  result = $suggest.section
+  result.add(sep)
+  result.add($suggest.symkind)
+  result.add(sep)
+  result.add(suggest.qualifiedPath.join("."))
+  result.add(sep)
+  result.add(suggest.forth)
+  result.add(sep)
+  result.add(suggest.filePath)
+  result.add(sep)
+  result.add($suggest.line)
+  result.add(sep)
+  result.add($suggest.column)
+  result.add(sep)
+  when not defined(noDocgen):
+    result.add(suggest.doc.escape)
 
-proc symToStr(s: PSym, isLocal: bool, section: string): string = 
-  result = symToStr(s, isLocal, section, s.info)
+proc symToSuggest(s: PSym, isLocal: bool, section: string): Suggest = 
+  result = symToSuggest(s, isLocal, section, s.info)
+
+proc suggestResult(s: Suggest) =
+  if not isNil(suggestionResultHook):
+    suggestionResultHook(s)
+  else:
+    suggestWriteln($(s))
 
 proc filterSym(s: PSym): bool {.inline.} =
   result = s.kind != skModule
@@ -84,7 +106,7 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} =
 
 proc suggestField(c: PContext, s: PSym, outputs: var int) = 
   if filterSym(s) and fieldVisible(c, s):
-    suggestWriteln(symToStr(s, isLocal=true, sectionSuggest))
+    suggestResult(symToSuggest(s, isLocal=true, $ideSug))
     inc outputs
 
 template wholeSymTab(cond, section: expr) {.immediate.} =
@@ -97,7 +119,7 @@ template wholeSymTab(cond, section: expr) {.immediate.} =
     for item in entries:
       let it {.inject.} = item
       if cond:
-        suggestWriteln(symToStr(it, isLocal = isLocal, section))
+        suggestResult(symToSuggest(it, isLocal = isLocal, section))
         inc outputs
 
 proc suggestSymList(c: PContext, list: PNode, outputs: var int) = 
@@ -140,7 +162,7 @@ proc argsFit(c: PContext, candidate: PSym, n, nOrig: PNode): bool =
 
 proc suggestCall(c: PContext, n, nOrig: PNode, outputs: var int) = 
   wholeSymTab(filterSym(it) and nameFits(c, it, n) and argsFit(c, it, n, nOrig),
-              sectionContext)
+              $ideCon)
 
 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:
@@ -157,7 +179,7 @@ proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} =
 
 proc suggestOperations(c: PContext, n: PNode, typ: PType, outputs: var int) =
   assert typ != nil
-  wholeSymTab(filterSymNoOpr(it) and typeFits(c, it, typ), sectionSuggest)
+  wholeSymTab(filterSymNoOpr(it) and typeFits(c, it, typ), $ideSug)
 
 proc suggestEverything(c: PContext, n: PNode, outputs: var int) =
   # do not produce too many symbols:
@@ -166,7 +188,7 @@ proc suggestEverything(c: PContext, n: PNode, outputs: var int) =
     if scope == c.topLevelScope: isLocal = false
     for it in items(scope.symbols):
       if filterSym(it):
-        suggestWriteln(symToStr(it, isLocal = isLocal, sectionSuggest))
+        suggestResult(symToSuggest(it, isLocal = isLocal, $ideSug))
         inc outputs
     if scope == c.topLevelScope: break
 
@@ -181,12 +203,12 @@ proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) =
         # all symbols accessible, because we are in the current module:
         for it in items(c.topLevelScope.symbols):
           if filterSym(it): 
-            suggestWriteln(symToStr(it, isLocal=false, sectionSuggest))
+            suggestResult(symToSuggest(it, isLocal=false, $ideSug))
             inc outputs
       else: 
         for it in items(n.sym.tab): 
           if filterSym(it): 
-            suggestWriteln(symToStr(it, isLocal=false, sectionSuggest))
+            suggestResult(symToSuggest(it, isLocal=false, $ideSug))
             inc outputs
     else:
       # fallback:
@@ -263,16 +285,16 @@ var
 proc findUsages(info: TLineInfo; s: PSym) =
   if usageSym == nil and isTracked(info, s.name.s.len):
     usageSym = s
-    suggestWriteln(symToStr(s, isLocal=false, sectionUsage))
+    suggestResult(symToSuggest(s, isLocal=false, $ideUse))
   elif s == usageSym:
     if lastLineInfo != info:
-      suggestWriteln(symToStr(s, isLocal=false, sectionUsage, info))
+      suggestResult(symToSuggest(s, isLocal=false, $ideUse, info))
     lastLineInfo = info
 
 proc findDefinition(info: TLineInfo; s: PSym) =
   if s.isNil: return
   if isTracked(info, s.name.s.len):
-    suggestWriteln(symToStr(s, isLocal=false, sectionDef))
+    suggestResult(symToSuggest(s, isLocal=false, $ideDef))
     suggestQuit()
 
 proc ensureIdx[T](x: var T, y: int) =
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 1c6c9a30b..e49bed522 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -1121,7 +1121,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       decodeB(rkInt)
       let a = regs[rb].node
       case a.kind
-      of nkCharLit..nkInt64Lit: regs[ra].intVal = a.intVal
+      of nkCharLit..nkUInt64Lit: regs[ra].intVal = a.intVal
       else: stackTrace(c, tos, pc, errFieldXNotFound, "intVal")
     of opcNFloatVal:
       decodeB(rkFloat)
@@ -1276,7 +1276,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..nkUInt64Lit} and
          regs[rb].kind in {rkInt}:
         dest.intVal = regs[rb].intVal
       else:
diff --git a/config/nim.cfg b/config/nim.cfg
index fef7df79e..0c3ffef4e 100644
--- a/config/nim.cfg
+++ b/config/nim.cfg
@@ -78,6 +78,7 @@ path="$lib/pure/unidecode"
     gcc.options.linker = "-ldl"
     gcc.cpp.options.linker = "-ldl"
     clang.options.linker = "-ldl"
+    clang.cpp.options.linker = "-ldl"
     tcc.options.linker = "-ldl"
   @end
   @if bsd or haiku:
diff --git a/csources b/csources
new file mode 160000
+Subproject 15724e2e1f3e7749d508dfcd995e84fea285080
diff --git a/doc/astspec.txt b/doc/astspec.txt
index 4c27272e2..68bb9f1cd 100644
--- a/doc/astspec.txt
+++ b/doc/astspec.txt
@@ -23,7 +23,7 @@ contains:
       case kind: NimNodeKind           ## the node's kind
       of nnkNone, nnkEmpty, nnkNilLit:
         discard                        ## node contains no additional fields
-      of nnkCharLit..nnkInt64Lit:
+      of nnkCharLit..nnkUInt64Lit:
         intVal: biggestInt             ## the int literal
       of nnkFloatLit..nnkFloat64Lit:
         floatVal: biggestFloat         ## the float literal
diff --git a/doc/lib.txt b/doc/lib.txt
index 1c0278068..f43228151 100644
--- a/doc/lib.txt
+++ b/doc/lib.txt
@@ -325,6 +325,10 @@ Parsers
 * `rstgen <rstgen.html>`_
   This module implements a generator of HTML/Latex from reStructuredText.
 
+* `sexp <sexp.html>`_
+  High performance sexp parser and generator, mainly for communication
+  with emacs.
+
 
 XML Processing
 --------------
diff --git a/doc/manual/threads.txt b/doc/manual/threads.txt
index fc3040c87..f2b79a34f 100644
--- a/doc/manual/threads.txt
+++ b/doc/manual/threads.txt
@@ -37,7 +37,7 @@ that contains GC'ed memory (``string``, ``seq``, ``ref`` or a closure) either
 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``
+otherwise this property is inferred by the compiler. Note that ``noSideEffect``
 implies ``gcsafe``. The only way to create a thread is via ``spawn`` or
 ``createThead``. ``spawn`` is usually the preferable method. Either way
 the invoked proc must not use ``var`` parameters nor must any of its parameters
@@ -146,7 +146,7 @@ wait on multiple flow variables at the same time:
 
   # wait until 2 out of 3 servers received the update:
   proc main =
-    var responses = newSeq[RawFlowVar](3)
+    var responses = newSeq[FlowVarBase](3)
     for i in 0..2:
       responses[i] = spawn tellServer(Update, "key", "value")
     var index = awaitAny(responses)
diff --git a/doc/spawn.txt b/doc/spawn.txt
index fb2f851c7..36bd02e96 100644
--- a/doc/spawn.txt
+++ b/doc/spawn.txt
@@ -33,7 +33,7 @@ variables at the same time:
   
   # wait until 2 out of 3 servers received the update:
   proc main =
-    var responses = newSeq[RawFlowVar](3)
+    var responses = newSeq[FlowVarBase](3)
     for i in 0..2:
       responses[i] = spawn tellServer(Update, "key", "value")
     var index = awaitAny(responses)
diff --git a/doc/tut1.txt b/doc/tut1.txt
index 58ace1dbe..1fa495054 100644
--- a/doc/tut1.txt
+++ b/doc/tut1.txt
@@ -1303,7 +1303,7 @@ type conversions in this context:
 
   myWriteln(stdout, 123, "abc", 4.0)
   # is transformed by the compiler to:
-  myWriteln(stdout, [$123, $"def", $4.0])
+  myWriteln(stdout, [$123, $"abc", $4.0])
 
 In this example `$ <system.html#$>`_ is applied to any argument that is passed
 to the parameter ``a``. Note that `$ <system.html#$>`_ applied to strings is a
@@ -1325,7 +1325,7 @@ define operators which accept Slice objects to define ranges.
     b = "Slices are useless."
 
   echo a[7..12] # --> 'a prog'
-  b[11.. -2] = "useful"
+  b[11.. ^2] = "useful"
   echo b # --> 'Slices are useful.'
 
 In the previous example slices are used to modify a part of a string, and even
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 35f0f61c1..7e6e4ccc9 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -177,6 +177,12 @@ proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.}
   ## resolve recursive types, you have to call 'getType' again. To see what
   ## kind of type it is, call `typeKind` on getType's result.
 
+proc getType*(n: typedesc): NimNode {.magic: "NGetType", noSideEffect.}
+  ## Returns the Nim type node for given type. This can be used to turn macro
+  ## typedesc parameter into proper NimNode representing type, since typedesc
+  ## are an exception in macro calls - they are not mapped implicitly to
+  ## NimNode like any other arguments.
+
 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`.
diff --git a/lib/impure/re.nim b/lib/impure/re.nim
index fb95610f6..279f8aadd 100644
--- a/lib/impure/re.nim
+++ b/lib/impure/re.nim
@@ -146,8 +146,8 @@ 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.
+  ## returns the starting position and end position of ``pattern`` in ``s``.
+  ## If it does not match, ``(-1,0)`` is returned.
   var
     rtarray = initRtArray[cint](3)
     rawMatches = rtarray.getRawData
diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim
index f7ccb9234..0eafb316a 100644
--- a/lib/pure/algorithm.nim
+++ b/lib/pure/algorithm.nim
@@ -24,6 +24,17 @@ proc `*`*(x: int, order: SortOrder): int {.inline.} =
   var y = order.ord - 1
   result = (x xor y) - y
 
+proc fill*[T](a: var openArray[T], first, last: Natural, value: T) =
+  ## fills the array ``a[first..last]`` with `value`.
+  var x = first
+  while x <= last:
+    a[x] = value
+    inc(x)
+
+proc fill*[T](a: var openArray[T], value: T) =
+  ## fills the array `a` with `value`.
+  fill(a, 0, a.high, value)
+
 proc reverse*[T](a: var openArray[T], first, last: Natural) =
   ## reverses the array ``a[first..last]``.
   var x = first
@@ -210,8 +221,7 @@ template sortedByIt*(seq1, op: expr): expr =
   ##     p2: Person = (name: "p2", age: 20)
   ##     p3: Person = (name: "p3", age: 30)
   ##     p4: Person = (name: "p4", age: 30)
-  ##
-  ##   people = @[p1,p2,p4,p3]
+  ##     people = @[p1,p2,p4,p3]
   ##
   ##   echo people.sortedByIt(it.name)
   ##
@@ -233,7 +243,7 @@ template sortedByIt*(seq1, op: expr): expr =
 proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
   ## produces the Cartesian product of the array. Warning: complexity
   ## may explode.
-  result = @[]
+  result = newSeq[seq[T]]()
   if x.len == 0:
     return
   if x.len == 1:
@@ -243,8 +253,7 @@ proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
     indexes = newSeq[int](x.len)
     initial = newSeq[int](x.len)
     index = 0
-  # replace with newSeq as soon as #853 is fixed
-  var next: seq[T] = @[]
+  var next = newSeq[T]()
   next.setLen(x.len)
   for i in 0..(x.len-1):
     if len(x[i]) == 0: return
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index a4d7a1632..8010e9ebc 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -1154,7 +1154,7 @@ else:
 
 proc sleepAsync*(ms: int): Future[void] =
   ## Suspends the execution of the current async procedure for the next
-  ## ``ms`` miliseconds.
+  ## ``ms`` milliseconds.
   var retFuture = newFuture[void]("sleepAsync")
   let p = getGlobalDispatcher()
   p.timers.add((epochTime() + (ms / 1000), retFuture))
@@ -1328,7 +1328,7 @@ proc processBody(node, retFutureSym: NimNode,
     else: discard
   of nnkDiscardStmt:
     # discard await x
-    if node[0].kind != nnkEmpty and node[0][0].kind == nnkIdent and
+    if node[0].kind == nnkCommand and node[0][0].kind == nnkIdent and
           node[0][0].ident == !"await":
       var newDiscard = node
       result.createVar("futureDiscard_" & $toStrLit(node[0][1]), node[0][1],
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index a9357ce67..9496fa2fe 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -215,6 +215,10 @@ proc hasKey*[A, B](t: Table[A, B], key: A): bool =
   var hc: THash
   result = rawGet(t, key, hc) >= 0
 
+proc contains*[A, B](t: Table[A, B], key: A): bool =
+  ## alias of `hasKey` for use with the `in` operator.
+  return hasKey[A, B](t, key)
+
 proc rawInsert[A, B](t: var Table[A, B], data: var KeyValuePairSeq[A, B],
                      key: A, val: B, hc: THash, h: THash) =
   rawInsertImpl()
@@ -411,6 +415,10 @@ proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
   ## returns true iff `key` is in the table `t`.
   result = t[].hasKey(key)
 
+proc contains*[A, B](t: TableRef[A, B], key: A): bool =
+  ## alias of `hasKey` for use with the `in` operator.
+  return hasKey[A, B](t, key)
+
 proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: B) =
   ## puts a (key, value)-pair into `t`.
   t[][key] = val
@@ -532,6 +540,10 @@ proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
   var hc: THash
   result = rawGet(t, key, hc) >= 0
 
+proc contains*[A, B](t: OrderedTable[A, B], key: A): bool =
+  ## alias of `hasKey` for use with the `in` operator.
+  return hasKey[A, B](t, key)
+
 proc rawInsert[A, B](t: var OrderedTable[A, B],
                      data: var OrderedKeyValuePairSeq[A, B],
                      key: A, val: B, hc: THash, h: THash) =
@@ -704,6 +716,10 @@ proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool =
   ## returns true iff `key` is in the table `t`.
   result = t[].hasKey(key)
 
+proc contains*[A, B](t: OrderedTableRef[A, B], key: A): bool =
+  ## alias of `hasKey` for use with the `in` operator.
+  return hasKey[A, B](t, key)
+
 proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: B) =
   ## puts a (key, value)-pair into `t`.
   t[][key] = val
@@ -804,6 +820,10 @@ proc hasKey*[A](t: CountTable[A], key: A): bool =
   ## returns true iff `key` is in the table `t`.
   result = rawGet(t, key) >= 0
 
+proc contains*[A](t: CountTable[A], key: A): bool =
+  ## alias of `hasKey` for use with the `in` operator.
+  return hasKey[A](t, key)
+
 proc rawInsert[A](t: CountTable[A], data: var seq[tuple[key: A, val: int]],
                   key: A, val: int) =
   var h: THash = hash(key) and high(data)
@@ -945,6 +965,10 @@ proc hasKey*[A](t: CountTableRef[A], key: A): bool =
   ## returns true iff `key` is in the table `t`.
   result = t[].hasKey(key)
 
+proc contains*[A](t: CountTableRef[A], key: A): bool =
+  ## alias of `hasKey` for use with the `in` operator.
+  return hasKey[A](t, key)
+
 proc `[]=`*[A](t: CountTableRef[A], key: A, val: int) =
   ## puts a (key, value)-pair into `t`. `val` has to be positive.
   assert val > 0
diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim
index 9f1e53fb8..a431691ad 100644
--- a/lib/pure/concurrency/threadpool.nim
+++ b/lib/pure/concurrency/threadpool.nim
@@ -300,7 +300,7 @@ proc setMinPoolSize*(size: range[1..MaxThreadPoolSize]) =
   minPoolSize = size
 
 proc setMaxPoolSize*(size: range[1..MaxThreadPoolSize]) =
-  ## sets the minimal thread pool size. The default value of this
+  ## sets the maximal thread pool size. The default value of this
   ## is ``MaxThreadPoolSize``.
   maxPoolSize = size
   if currentPoolSize > maxPoolSize:
diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim
index a16342d44..2ce8ac796 100644
--- a/lib/pure/hashes.nim
+++ b/lib/pure/hashes.nim
@@ -37,29 +37,29 @@
 ##    h = h !& hash(x.bar)
 ##    result = !$h
 
-import 
+import
   strutils
 
-type 
-  THash* = int ## a hash value; hash tables using these values should 
+type
+  THash* = int ## a hash value; hash tables using these values should
                ## always have a size of a power of two and can use the ``and``
                ## operator instead of ``mod`` for truncation of the hash value.
 
-proc `!&`*(h: THash, val: int): THash {.inline.} = 
+proc `!&`*(h: THash, val: int): THash {.inline.} =
   ## mixes a hash value `h` with `val` to produce a new hash value. This is
   ## only needed if you need to implement a hash proc for a new datatype.
   result = h +% val
   result = result +% result shl 10
   result = result xor (result shr 6)
 
-proc `!$`*(h: THash): THash {.inline.} = 
+proc `!$`*(h: THash): THash {.inline.} =
   ## finishes the computation of the hash value. This is
   ## only needed if you need to implement a hash proc for a new datatype.
   result = h +% h shl 3
   result = result xor (result shr 11)
   result = result +% result shl 15
 
-proc hashData*(data: pointer, size: int): THash = 
+proc hashData*(data: pointer, size: int): THash =
   ## hashes an array of bytes of size `size`
   var h: THash = 0
   when defined(js):
@@ -69,7 +69,7 @@ proc hashData*(data: pointer, size: int): THash =
     var p = cast[cstring](data)
   var i = 0
   var s = size
-  while s > 0: 
+  while s > 0:
     h = h !& ord(p[i])
     inc(i)
     dec(s)
@@ -78,7 +78,7 @@ proc hashData*(data: pointer, size: int): THash =
 when defined(js):
   var objectID = 0
 
-proc hash*(x: pointer): THash {.inline.} = 
+proc hash*(x: pointer): THash {.inline.} =
   ## efficient hashing of pointers
   when defined(js):
     asm """
@@ -93,7 +93,7 @@ proc hash*(x: pointer): THash {.inline.} =
     """
   else:
     result = (cast[THash](x)) shr 3 # skip the alignment
-  
+
 when not defined(booting):
   proc hash*[T: proc](x: T): THash {.inline.} =
     ## efficient hashing of proc vars; closures are supported too.
@@ -101,58 +101,65 @@ when not defined(booting):
       result = hash(rawProc(x)) !& hash(rawEnv(x))
     else:
       result = hash(pointer(x))
-  
-proc hash*(x: int): THash {.inline.} = 
+
+proc hash*(x: int): THash {.inline.} =
   ## efficient hashing of integers
   result = x
 
-proc hash*(x: int64): THash {.inline.} = 
+proc hash*(x: int64): THash {.inline.} =
   ## efficient hashing of integers
   result = toU32(x)
 
-proc hash*(x: char): THash {.inline.} = 
+proc hash*(x: char): THash {.inline.} =
   ## efficient hashing of characters
   result = ord(x)
 
-proc hash*(x: string): THash = 
+proc hash*(x: string): THash =
   ## efficient hashing of strings
   var h: THash = 0
-  for i in 0..x.len-1: 
+  for i in 0..x.len-1:
     h = h !& ord(x[i])
   result = !$h
-  
-proc hashIgnoreStyle*(x: string): THash = 
+
+proc hashIgnoreStyle*(x: string): THash =
   ## efficient hashing of strings; style is ignored
   var h: THash = 0
-  for i in 0..x.len-1: 
+  for i in 0..x.len-1:
     var c = x[i]
-    if c == '_': 
+    if c == '_':
       continue                # skip _
-    if c in {'A'..'Z'}: 
+    if c in {'A'..'Z'}:
       c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
     h = h !& ord(c)
   result = !$h
 
-proc hashIgnoreCase*(x: string): THash = 
+proc hashIgnoreCase*(x: string): THash =
   ## efficient hashing of strings; case is ignored
   var h: THash = 0
-  for i in 0..x.len-1: 
+  for i in 0..x.len-1:
     var c = x[i]
-    if c in {'A'..'Z'}: 
+    if c in {'A'..'Z'}:
       c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
     h = h !& ord(c)
   result = !$h
-  
-proc hash*[T: tuple](x: T): THash = 
-  ## efficient hashing of tuples.
-  for f in fields(x):
-    result = result !& hash(f)
-  result = !$result
 
 proc hash*(x: float): THash {.inline.} =
   var y = x + 1.0
   result = cast[ptr THash](addr(y))[]
 
+
+# Forward declarations before methods that hash containers. This allows
+# containers to contain other containers
+proc hash*[A](x: openArray[A]): THash
+proc hash*[A](x: set[A]): THash
+
+
+proc hash*[T: tuple](x: T): THash =
+  ## efficient hashing of tuples.
+  for f in fields(x):
+    result = result !& hash(f)
+  result = !$result
+
 proc hash*[A](x: openArray[A]): THash =
   for it in items(x): result = result !& hash(it)
   result = !$result
@@ -160,3 +167,4 @@ proc hash*[A](x: openArray[A]): THash =
 proc hash*[A](x: set[A]): THash =
   for it in items(x): result = result !& hash(it)
   result = !$result
+
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 9c27ecdab..e083d44ea 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -64,7 +64,7 @@
 ## ========
 ## Currently all functions support an optional timeout, by default the timeout is set to
 ## `-1` which means that the function will never time out. The timeout is
-## measured in miliseconds, once it is set any call on a socket which may
+## measured in milliseconds, once it is set any call on a socket which may
 ## block will be susceptible to this timeout, however please remember that the
 ## function as a whole can take longer than the specified timeout, only
 ## individual internal calls on the socket are affected. In practice this means
@@ -386,7 +386,7 @@ proc request*(url: string, httpMethod: string, extraHeaders = "",
   ## | 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
+  ## | An optional timeout can be specified in milliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
   var r = if proxy == nil: parseUri(url) else: proxy.url
   var headers = substr(httpMethod, len("http"))
@@ -440,7 +440,7 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
               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
+  ## | An optional timeout can be specified in milliseconds, 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)
@@ -467,7 +467,7 @@ proc get*(url: string, extraHeaders = "", maxRedirects = 5,
   ## | GETs the ``url`` and returns a ``Response`` object
   ## | 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
+  ## | An optional timeout can be specified in milliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
   result = request(url, httpGET, extraHeaders, "", sslContext, timeout,
                    userAgent, proxy)
@@ -486,7 +486,7 @@ proc getContent*(url: string, extraHeaders = "", maxRedirects = 5,
   ## | GETs the body and returns it 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
+  ## | An optional timeout can be specified in milliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
   var r = get(url, extraHeaders, maxRedirects, sslContext, timeout, userAgent,
               proxy)
@@ -505,7 +505,7 @@ proc post*(url: string, extraHeaders = "", body = "",
   ## | 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
+  ## | An optional timeout can be specified in milliseconds, 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.
@@ -542,7 +542,7 @@ proc postContent*(url: string, extraHeaders = "", body = "",
   ## | 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
+  ## | An optional timeout can be specified in milliseconds, 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.
@@ -558,7 +558,7 @@ proc downloadFile*(url: string, outputFilename: string,
                    timeout = -1, userAgent = defUserAgent,
                    proxy: Proxy = nil) =
   ## | Downloads ``url`` and saves it to ``outputFilename``
-  ## | An optional timeout can be specified in miliseconds, if reading from the
+  ## | An optional timeout can be specified in milliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
   var f: File
   if open(f, outputFilename, fmWrite):
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 5d824d6f8..518572be3 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -761,7 +761,7 @@ proc len*(n: JsonNode): int =
   of JObject: result = n.fields.len
   else: discard
 
-proc `[]`*(node: JsonNode, name: string): JsonNode =
+proc `[]`*(node: JsonNode, name: string): JsonNode {.inline.} =
   ## Gets a field from a `JObject`, which must not be nil.
   ## If the value at `name` does not exist, returns nil
   assert(not isNil(node))
@@ -771,7 +771,7 @@ proc `[]`*(node: JsonNode, name: string): JsonNode =
       return item
   return nil
 
-proc `[]`*(node: JsonNode, index: int): JsonNode =
+proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} =
   ## Gets the node at `index` in an Array. Result is undefined if `index`
   ## is out of bounds
   assert(not isNil(node))
@@ -799,7 +799,7 @@ proc add*(obj: JsonNode, key: string, val: JsonNode) =
   assert obj.kind == JObject
   obj.fields.add((key, val))
 
-proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) =
+proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} =
   ## Sets a field from a `JObject`. Performs a check for duplicate keys.
   assert(obj.kind == JObject)
   for i in 0..obj.fields.len-1:
@@ -815,7 +815,7 @@ proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
   result = node
   for key in keys:
     if isNil(result) or result.kind!=JObject:
-      return nil    
+      return nil
     result=result[key]
 
 proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) =
@@ -949,10 +949,46 @@ proc pretty*(node: JsonNode, indent = 2): string =
   result = ""
   toPretty(result, node, indent)
 
+proc toUgly*(result: var string, node: JsonNode) =
+  ## Converts `node` to its JSON Representation, without
+  ## regard for human readability. Meant to improve ``$`` string
+  ## conversion performance.
+  ##
+  ## This provides higher efficiency than the ``toPretty`` procedure as it
+  ## does **not** attempt to format the resulting JSON to make it human readable.
+  var comma = false
+  case node.kind:
+  of JArray:
+    result.add "["
+    for child in node.elems:
+      if comma: result.add ","
+      else:     comma = true
+      result.toUgly child
+    result.add "]"
+  of JObject:
+    result.add "{"
+    for key, value in items(node.fields):
+      if comma: result.add ","
+      else:     comma = true
+      result.add key.escapeJson()
+      result.add ":"
+      result.toUgly value
+    result.add "}"
+  of JString:
+    result.add node.str.escapeJson()
+  of JInt:
+    result.add($node.num)
+  of JFloat:
+    result.add($node.fnum)
+  of JBool:
+    result.add(if node.bval: "true" else: "false")
+  of JNull:
+    result.add "null"
+
 proc `$`*(node: JsonNode): string =
   ## Converts `node` to its JSON Representation on one line.
-  result = ""
-  toPretty(result, node, 0, false)
+  result = newStringOfCap(node.len shl 1)
+  toUgly(result, node)
 
 iterator items*(node: JsonNode): JsonNode =
   ## Iterator for the items of `node`. `node` has to be a JArray.
@@ -1153,7 +1189,7 @@ when false:
 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")
 
@@ -1176,6 +1212,11 @@ when isMainModule:
   testJson{["c", "d"]} = %true
   assert(testJson["c"]["d"].bval)
 
+  # test `$`
+  let stringified = $testJson
+  let parsedAgain = parseJson(stringified)
+  assert(parsedAgain["b"].str == "asd")
+
   # Bounds checking
   try:
     let a = testJson["a"][9]
@@ -1192,17 +1233,17 @@ when isMainModule:
   except:
     assert(false, "EInvalidIndex thrown for valid index")
 
-  assert(testJson{"b"}.str=="asd", "Couldn't fetch a singly nested key with {}") 
-  assert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil") 
+  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}] 
+  assert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
 
   var j2 = %*
     [
@@ -1230,7 +1271,7 @@ when isMainModule:
       }
     ]
   assert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
-  
+
   when not defined(testing):
     discard """
     while true:
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index daa108460..a9e9010f6 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -85,7 +85,7 @@ proc fac*(n: int): int {.noSideEffect.} =
 proc isPowerOfTwo*(x: int): bool {.noSideEffect.} =
   ## returns true, if `x` is a power of two, false otherwise.
   ## Zero and negative numbers are not a power of two.
-  return (x != 0) and ((x and (x - 1)) == 0)
+  return (x > 0) and ((x and (x - 1)) == 0)
 
 proc nextPowerOfTwo*(x: int): int {.noSideEffect.} =
   ## returns `x` rounded up to the nearest power of two.
@@ -114,18 +114,23 @@ proc sum*[T](x: openArray[T]): T {.noSideEffect.} =
   ## If `x` is empty, 0 is returned.
   for i in items(x): result = result + i
 
-proc mean*(x: openArray[float]): float {.noSideEffect.} = 
-  ## computes the mean of the elements in `x`. 
+template toFloat(f: float): float = f
+
+proc mean*[T](x: openArray[T]): float {.noSideEffect.} =
+  ## computes the mean of the elements in `x`, which are first converted to floats.
   ## If `x` is empty, NaN is returned.
-  result = sum(x) / toFloat(len(x))
+  ## ``toFloat(x: T): float`` must be defined.
+  for i in items(x): result = result + toFloat(i)
+  result = result / toFloat(len(x))
 
-proc variance*(x: openArray[float]): float {.noSideEffect.} = 
+proc variance*[T](x: openArray[T]): float {.noSideEffect.} =
   ## computes the variance of the elements in `x`. 
   ## If `x` is empty, NaN is returned.
+  ## ``toFloat(x: T): float`` must be defined.
   result = 0.0
   var m = mean(x)
-  for i in 0 .. high(x):
-    var diff = x[i] - m
+  for i in items(x):
+    var diff = toFloat(i) - m
     result = result + diff*diff
   result = result / toFloat(len(x))
 
@@ -347,6 +352,9 @@ proc `^`*[T](x, y: T): T =
 
 proc gcd*[T](x, y: T): T =
   ## Computes the greatest common divisor of ``x`` and ``y``.
+  ## Note that for floats, the result cannot always be interpreted as
+  ## "greatest decimal `z` such that ``z*N == x and z*M == y``
+  ## where N and M are positive integers."
   var (x,y) = (x,y)
   while y != 0:
     x = x mod y
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index ffbc6e320..cf37c271e 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -704,7 +704,7 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int,
 
 proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {.
   tags: [ReadIOEffect, TimeEffect].} =
-  ## overload with a ``timeout`` parameter in miliseconds.
+  ## overload with a ``timeout`` parameter in milliseconds.
   var waited = 0.0 # number of seconds already waited  
   
   var read = 0
@@ -729,7 +729,7 @@ proc recv*(socket: Socket, data: var string, size: int, timeout = -1,
   ## This function will throw an EOS exception when an error occurs. A value
   ## lower than 0 is never returned.
   ##
-  ## A timeout may be specified in miliseconds, if enough data is not received
+  ## A timeout may be specified in milliseconds, if enough data is not received
   ## within the time specified an ETimeout exception will be raised.
   ##
   ## **Note**: ``data`` must be initialised.
@@ -777,7 +777,7 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1,
   ##
   ## An EOS exception will be raised in the case of a socket error.
   ##
-  ## A timeout can be specified in miliseconds, if data is not received within
+  ## A timeout can be specified in milliseconds, if data is not received within
   ## the specified time an ETimeout exception will be raised.
   ##
   ## **Warning**: Only the ``SafeDisconn`` flag is currently supported.
@@ -844,7 +844,7 @@ proc recvFrom*(socket: Socket, data: var string, length: int,
 proc skip*(socket: Socket, size: int, timeout = -1) =
   ## Skips ``size`` amount of bytes.
   ##
-  ## An optional timeout can be specified in miliseconds, if skipping the
+  ## An optional timeout can be specified in milliseconds, if skipping the
   ## bytes takes longer than specified an ETimeout exception will be raised.
   ##
   ## Returns the number of skipped bytes.
@@ -967,7 +967,7 @@ proc connect*(socket: Socket, address: string, port = Port(0), timeout: int,
              af: Domain = AF_INET) {.tags: [ReadIOEffect, WriteIOEffect].} =
   ## Connects to server as specified by ``address`` on port specified by ``port``.
   ##
-  ## The ``timeout`` paremeter specifies the time in miliseconds to allow for
+  ## The ``timeout`` paremeter specifies the time in milliseconds to allow for
   ## the connection to the server to be made.
   socket.fd.setBlocking(false)
   
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index f53abe81d..3a5bcbfa1 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -2033,10 +2033,10 @@ proc getFileInfo*(path: string, followSymlink = true): FileInfo =
   else:
     var rawInfo: TStat
     if followSymlink:
-      if lstat(path, rawInfo) < 0'i32:
+      if stat(path, rawInfo) < 0'i32:
         raiseOSError(osLastError())
     else:
-      if stat(path, rawInfo) < 0'i32:
+      if lstat(path, rawInfo) < 0'i32:
         raiseOSError(osLastError())
     rawToFormalFileInfo(rawInfo, result)
 
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index dce0673ba..dc6f21174 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -195,43 +195,43 @@ proc peekExitCode*(p: Process): int {.tags: [].}
 proc inputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].}
   ## returns ``p``'s input stream for writing to.
   ##
-  ## **Warning**: The returned `PStream` should not be closed manually as it
-  ## is closed when closing the PProcess ``p``.
+  ## **Warning**: The returned `Stream` should not be closed manually as it
+  ## is closed when closing the Process ``p``.
 
 proc outputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].}
   ## returns ``p``'s output stream for reading from.
   ##
-  ## **Warning**: The returned `PStream` should not be closed manually as it
-  ## is closed when closing the PProcess ``p``.
+  ## **Warning**: The returned `Stream` should not be closed manually as it
+  ## is closed when closing the Process ``p``.
 
 proc errorStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].}
   ## returns ``p``'s error stream for reading from.
   ##
-  ## **Warning**: The returned `PStream` should not be closed manually as it
-  ## is closed when closing the PProcess ``p``.
+  ## **Warning**: The returned `Stream` should not be closed manually as it
+  ## is closed when closing the Process ``p``.
 
 proc inputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1",
   tags: [].} =
   ## returns ``p``'s input file handle for writing to.
   ##
-  ## **Warning**: The returned `TFileHandle` should not be closed manually as
-  ## it is closed when closing the PProcess ``p``.
+  ## **Warning**: The returned `FileHandle` should not be closed manually as
+  ## it is closed when closing the Process ``p``.
   result = p.inHandle
 
 proc outputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1",
   tags: [].} =
   ## returns ``p``'s output file handle for reading from.
   ##
-  ## **Warning**: The returned `TFileHandle` should not be closed manually as
-  ## it is closed when closing the PProcess ``p``.
+  ## **Warning**: The returned `FileHandle` should not be closed manually as
+  ## it is closed when closing the Process ``p``.
   result = p.outHandle
 
 proc errorHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1",
   tags: [].} =
   ## returns ``p``'s error file handle for reading from.
   ##
-  ## **Warning**: The returned `TFileHandle` should not be closed manually as
-  ## it is closed when closing the PProcess ``p``.
+  ## **Warning**: The returned `FileHandle` should not be closed manually as
+  ## it is closed when closing the Process ``p``.
   result = p.errHandle
 
 proc countProcessors*(): int {.rtl, extern: "nosp$1".} =
@@ -303,7 +303,7 @@ proc execProcesses*(cmds: openArray[string],
       close(p)
 
 proc select*(readfds: var seq[Process], timeout = 500): int
-  ## `select` with a sensible Nim interface. `timeout` is in miliseconds.
+  ## `select` with a sensible Nim interface. `timeout` is in milliseconds.
   ## Specify -1 for no timeout. Returns the number of processes that are
   ## ready to read from. The processes that are ready to be read from are
   ## removed from `readfds`.
diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim
index a30c23ada..d08c5b769 100644
--- a/lib/pure/rawsockets.nim
+++ b/lib/pure/rawsockets.nim
@@ -392,7 +392,7 @@ proc select*(readfds: var seq[SocketHandle], timeout = 500): int =
   ## Traditional select function. This function will return the number of
   ## sockets that are ready to be read from, written to, or which have errors.
   ## If there are none; 0 is returned. 
-  ## ``Timeout`` is in miliseconds and -1 can be specified for no timeout.
+  ## ``Timeout`` is in milliseconds and -1 can be specified for no timeout.
   ## 
   ## A socket is removed from the specific ``seq`` when it has data waiting to
   ## be read/written to or has errors (``exceptfds``).
@@ -416,7 +416,7 @@ proc selectWrite*(writefds: var seq[SocketHandle],
   ## written to. The sockets which can be written to will also be removed
   ## from ``writefds``.
   ##
-  ## ``timeout`` is specified in miliseconds and ``-1`` can be specified for
+  ## ``timeout`` is specified in milliseconds and ``-1`` can be specified for
   ## an unlimited time.
   var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
   
diff --git a/lib/pure/scgi.nim b/lib/pure/scgi.nim
index f3e2b583c..3de422c87 100644
--- a/lib/pure/scgi.nim
+++ b/lib/pure/scgi.nim
@@ -126,7 +126,7 @@ proc close*(s: var ScgiState) =
   s.server.close()
 
 proc next*(s: var ScgiState, timeout: int = -1): bool = 
-  ## proceed to the first/next request. Waits ``timeout`` miliseconds for a
+  ## proceed to the first/next request. Waits ``timeout`` milliseconds for a
   ## request, if ``timeout`` is `-1` then this function will never time out.
   ## Returns `true` if a new request has been processed.
   var rsocks = @[s.server]
diff --git a/lib/pure/sexp.nim b/lib/pure/sexp.nim
new file mode 100644
index 000000000..3c9fbc150
--- /dev/null
+++ b/lib/pure/sexp.nim
@@ -0,0 +1,697 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf, Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import
+  hashes, strutils, lexbase, streams, unicode, macros
+
+type
+  SexpEventKind* = enum  ## enumeration of all events that may occur when parsing
+    sexpError,           ## an error occurred during parsing
+    sexpEof,             ## end of file reached
+    sexpString,          ## a string literal
+    sexpSymbol,          ## a symbol
+    sexpInt,             ## an integer literal
+    sexpFloat,           ## a float literal
+    sexpNil,             ## the value ``nil``
+    sexpDot,             ## the dot to separate car/cdr
+    sexpListStart,       ## start of a list: the ``(`` token
+    sexpListEnd,         ## end of a list: the ``)`` token
+
+  TTokKind = enum        # must be synchronized with SexpEventKind!
+    tkError,
+    tkEof,
+    tkString,
+    tkSymbol,
+    tkInt,
+    tkFloat,
+    tkNil,
+    tkDot,
+    tkParensLe,
+    tkParensRi
+    tkSpace
+
+  SexpError* = enum        ## enumeration that lists all errors that can occur
+    errNone,               ## no error
+    errInvalidToken,       ## invalid token
+    errParensRiExpected,    ## ``)`` expected
+    errQuoteExpected,      ## ``"`` expected
+    errEofExpected,        ## EOF expected
+
+  SexpParser* = object of BaseLexer ## the parser object.
+    a: string
+    tok: TTokKind
+    kind: SexpEventKind
+    err: SexpError
+
+const
+  errorMessages: array [SexpError, string] = [
+    "no error",
+    "invalid token",
+    "')' expected",
+    "'\"' or \"'\" expected",
+    "EOF expected",
+  ]
+  tokToStr: array [TTokKind, string] = [
+    "invalid token",
+    "EOF",
+    "string literal",
+    "symbol",
+    "int literal",
+    "float literal",
+    "nil",
+    ".",
+    "(", ")", "space"
+  ]
+
+proc close*(my: var SexpParser) {.inline.} =
+  ## closes the parser `my` and its associated input stream.
+  lexbase.close(my)
+
+proc str*(my: SexpParser): string {.inline.} =
+  ## returns the character data for the events: ``sexpInt``, ``sexpFloat``,
+  ## ``sexpString``
+  assert(my.kind in {sexpInt, sexpFloat, sexpString})
+  result = my.a
+
+proc getInt*(my: SexpParser): BiggestInt {.inline.} =
+  ## returns the number for the event: ``sexpInt``
+  assert(my.kind == sexpInt)
+  result = parseBiggestInt(my.a)
+
+proc getFloat*(my: SexpParser): float {.inline.} =
+  ## returns the number for the event: ``sexpFloat``
+  assert(my.kind == sexpFloat)
+  result = parseFloat(my.a)
+
+proc kind*(my: SexpParser): SexpEventKind {.inline.} =
+  ## returns the current event type for the SEXP parser
+  result = my.kind
+
+proc getColumn*(my: SexpParser): int {.inline.} =
+  ## get the current column the parser has arrived at.
+  result = getColNumber(my, my.bufpos)
+
+proc getLine*(my: SexpParser): int {.inline.} =
+  ## get the current line the parser has arrived at.
+  result = my.lineNumber
+
+proc errorMsg*(my: SexpParser): string =
+  ## returns a helpful error message for the event ``sexpError``
+  assert(my.kind == sexpError)
+  result = "($1, $2) Error: $3" % [$getLine(my), $getColumn(my), errorMessages[my.err]]
+
+proc errorMsgExpected*(my: SexpParser, e: string): string =
+  ## returns an error message "`e` expected" in the same format as the
+  ## other error messages
+  result = "($1, $2) Error: $3" % [$getLine(my), $getColumn(my), e & " expected"]
+
+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'))
+  of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10)
+  of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
+  else: result = false # error
+
+proc parseString(my: var SexpParser): TTokKind =
+  result = tkString
+  var pos = my.bufpos + 1
+  var buf = my.buf
+  while true:
+    case buf[pos]
+    of '\0':
+      my.err = errQuoteExpected
+      result = tkError
+      break
+    of '"':
+      inc(pos)
+      break
+    of '\\':
+      case buf[pos+1]
+      of '\\', '"', '\'', '/':
+        add(my.a, buf[pos+1])
+        inc(pos, 2)
+      of 'b':
+        add(my.a, '\b')
+        inc(pos, 2)
+      of 'f':
+        add(my.a, '\f')
+        inc(pos, 2)
+      of 'n':
+        add(my.a, '\L')
+        inc(pos, 2)
+      of 'r':
+        add(my.a, '\C')
+        inc(pos, 2)
+      of 't':
+        add(my.a, '\t')
+        inc(pos, 2)
+      of 'u':
+        inc(pos, 2)
+        var r: int
+        if handleHexChar(buf[pos], r): inc(pos)
+        if handleHexChar(buf[pos], r): inc(pos)
+        if handleHexChar(buf[pos], r): inc(pos)
+        if handleHexChar(buf[pos], r): inc(pos)
+        add(my.a, toUTF8(Rune(r)))
+      else:
+        # don't bother with the error
+        add(my.a, buf[pos])
+        inc(pos)
+    of '\c':
+      pos = lexbase.handleCR(my, pos)
+      buf = my.buf
+      add(my.a, '\c')
+    of '\L':
+      pos = lexbase.handleLF(my, pos)
+      buf = my.buf
+      add(my.a, '\L')
+    else:
+      add(my.a, buf[pos])
+      inc(pos)
+  my.bufpos = pos # store back
+
+proc parseNumber(my: var SexpParser) =
+  var pos = my.bufpos
+  var buf = my.buf
+  if buf[pos] == '-':
+    add(my.a, '-')
+    inc(pos)
+  if buf[pos] == '.':
+    add(my.a, "0.")
+    inc(pos)
+  else:
+    while buf[pos] in Digits:
+      add(my.a, buf[pos])
+      inc(pos)
+    if buf[pos] == '.':
+      add(my.a, '.')
+      inc(pos)
+  # digits after the dot:
+  while buf[pos] in Digits:
+    add(my.a, buf[pos])
+    inc(pos)
+  if buf[pos] in {'E', 'e'}:
+    add(my.a, buf[pos])
+    inc(pos)
+    if buf[pos] in {'+', '-'}:
+      add(my.a, buf[pos])
+      inc(pos)
+    while buf[pos] in Digits:
+      add(my.a, buf[pos])
+      inc(pos)
+  my.bufpos = pos
+
+proc parseSymbol(my: var SexpParser) =
+  var pos = my.bufpos
+  var buf = my.buf
+  if buf[pos] in IdentStartChars:
+    while buf[pos] in IdentChars:
+      add(my.a, buf[pos])
+      inc(pos)
+  my.bufpos = pos
+
+proc getTok(my: var SexpParser): TTokKind =
+  setLen(my.a, 0)
+  case my.buf[my.bufpos]
+  of '-', '0'..'9': # numbers that start with a . are not parsed
+                    # correctly.
+    parseNumber(my)
+    if {'.', 'e', 'E'} in my.a:
+      result = tkFloat
+    else:
+      result = tkInt
+  of '"': #" # gotta fix nim-mode
+    result = parseString(my)
+  of '(':
+    inc(my.bufpos)
+    result = tkParensLe
+  of ')':
+    inc(my.bufpos)
+    result = tkParensRi
+  of '\0':
+    result = tkEof
+  of 'a'..'z', 'A'..'Z', '_':
+    parseSymbol(my)
+    if my.a == "nil":
+      result = tkNil
+    else:
+      result = tkSymbol
+  of ' ':
+    result = tkSpace
+    inc(my.bufpos)
+  of '.':
+    result = tkDot
+    inc(my.bufpos)
+  else:
+    inc(my.bufpos)
+    result = tkError
+  my.tok = result
+
+# ------------- higher level interface ---------------------------------------
+
+type
+  SexpNodeKind* = enum ## possible SEXP node types
+    SNil,
+    SInt,
+    SFloat,
+    SString,
+    SSymbol,
+    SList,
+    SCons
+
+  SexpNode* = ref SexpNodeObj ## SEXP node
+  SexpNodeObj* {.acyclic.} = object
+    case kind*: SexpNodeKind
+    of SString:
+      str*: string
+    of SSymbol:
+      symbol*: string
+    of SInt:
+      num*: BiggestInt
+    of SFloat:
+      fnum*: float
+    of SList:
+      elems*: seq[SexpNode]
+    of SCons:
+      car: SexpNode
+      cdr: SexpNode
+    of SNil:
+      discard
+
+  Cons = tuple[car: SexpNode, cdr: SexpNode]
+
+  SexpParsingError* = object of ValueError ## is raised for a SEXP error
+
+proc raiseParseErr*(p: SexpParser, msg: string) {.noinline, noreturn.} =
+  ## raises an `ESexpParsingError` exception.
+  raise newException(SexpParsingError, errorMsgExpected(p, msg))
+
+proc newSString*(s: string): SexpNode {.procvar.}=
+  ## Creates a new `SString SexpNode`.
+  new(result)
+  result.kind = SString
+  result.str = s
+
+proc newSStringMove(s: string): SexpNode =
+  new(result)
+  result.kind = SString
+  shallowCopy(result.str, s)
+
+proc newSInt*(n: BiggestInt): SexpNode {.procvar.} =
+  ## Creates a new `SInt SexpNode`.
+  new(result)
+  result.kind = SInt
+  result.num  = n
+
+proc newSFloat*(n: float): SexpNode {.procvar.} =
+  ## Creates a new `SFloat SexpNode`.
+  new(result)
+  result.kind = SFloat
+  result.fnum  = n
+
+proc newSNil*(): SexpNode {.procvar.} =
+  ## Creates a new `SNil SexpNode`.
+  new(result)
+
+proc newSCons*(car, cdr: SexpNode): SexpNode {.procvar.} =
+  ## Creates a new `SCons SexpNode`
+  new(result)
+  result.kind = SCons
+  result.car = car
+  result.cdr = cdr
+
+proc newSList*(): SexpNode {.procvar.} =
+  ## Creates a new `SList SexpNode`
+  new(result)
+  result.kind = SList
+  result.elems = @[]
+
+proc newSSymbol*(s: string): SexpNode {.procvar.} =
+  new(result)
+  result.kind = SSymbol
+  result.symbol = s
+
+proc newSSymbolMove(s: string): SexpNode =
+  new(result)
+  result.kind = SSymbol
+  shallowCopy(result.symbol, s)
+
+proc getStr*(n: SexpNode, default: string = ""): string =
+  ## Retrieves the string value of a `SString SexpNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``SString``.
+  if n.kind != SString: return default
+  else: return n.str
+
+proc getNum*(n: SexpNode, default: BiggestInt = 0): BiggestInt =
+  ## Retrieves the int value of a `SInt SexpNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``SInt``.
+  if n.kind != SInt: return default
+  else: return n.num
+
+proc getFNum*(n: SexpNode, default: float = 0.0): float =
+  ## Retrieves the float value of a `SFloat SexpNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``SFloat``.
+  if n.kind != SFloat: return default
+  else: return n.fnum
+
+proc getSymbol*(n: SexpNode, default: string = ""): string =
+  ## Retrieves the int value of a `SList SexpNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``SList``.
+  if n.kind != SSymbol: return default
+  else: return n.symbol
+
+proc getElems*(n: SexpNode, default: seq[SexpNode] = @[]): seq[SexpNode] =
+  ## Retrieves the int value of a `SList SexpNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``SList``.
+  if n.kind == SNil: return @[]
+  elif n.kind != SList: return default
+  else: return n.elems
+
+proc getCons*(n: SexpNode, defaults: Cons = (newSNil(), newSNil())): Cons =
+  ## Retrieves the cons value of a `SList SexpNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``SList``.
+  if n.kind == SCons: return (n.car, n.cdr)
+  elif n.kind == SList: return (n.elems[0], n.elems[1])
+  else: return defaults
+
+proc sexp*(s: string): SexpNode =
+  ## Generic constructor for SEXP data. Creates a new `SString SexpNode`.
+  new(result)
+  result.kind = SString
+  result.str = s
+
+proc sexp*(n: BiggestInt): SexpNode =
+  ## Generic constructor for SEXP data. Creates a new `SInt SexpNode`.
+  new(result)
+  result.kind = SInt
+  result.num  = n
+
+proc sexp*(n: float): SexpNode =
+  ## Generic constructor for SEXP data. Creates a new `SFloat SexpNode`.
+  new(result)
+  result.kind = SFloat
+  result.fnum  = n
+
+proc sexp*(b: bool): SexpNode =
+  ## Generic constructor for SEXP data. Creates a new `SSymbol
+  ## SexpNode` with value t or `SNil SexpNode`.
+  new(result)
+  if b:
+    result.kind = SSymbol
+    result.symbol = "t"
+  else:
+    result.kind = SNil
+
+proc sexp*(elements: openArray[SexpNode]): SexpNode =
+  ## Generic constructor for SEXP data. Creates a new `SList SexpNode`
+  new(result)
+  result.kind = SList
+  newSeq(result.elems, elements.len)
+  for i, p in pairs(elements): result.elems[i] = p
+
+proc sexp*(s: SexpNode): SexpNode =
+  result = s
+
+proc toSexp(x: NimNode): NimNode {.compiletime.} =
+  case x.kind
+  of nnkBracket:
+    result = newNimNode(nnkBracket)
+    for i in 0 .. <x.len:
+      result.add(toSexp(x[i]))
+
+  else:
+    result = x
+
+  result = prefix(result, "sexp")
+
+macro convertSexp*(x: expr): expr =
+  ## Convert an expression to a SexpNode directly, without having to specify
+  ## `%` for every element.
+  result = toSexp(x)
+
+proc `==`* (a,b: SexpNode): bool =
+  ## Check two nodes for equality
+  if a.isNil:
+    if b.isNil: return true
+    return false
+  elif b.isNil or a.kind != b.kind:
+    return false
+  else:
+    return case a.kind
+    of SString:
+      a.str == b.str
+    of SInt:
+      a.num == b.num
+    of SFloat:
+      a.fnum == b.fnum
+    of SNil:
+      true
+    of SList:
+      a.elems == b.elems
+    of SSymbol:
+      a.symbol == b.symbol
+    of SCons:
+      a.car == b.car and a.cdr == b.cdr
+
+proc hash* (n:SexpNode): THash =
+  ## Compute the hash for a SEXP node
+  case n.kind
+  of SList:
+    result = hash(n.elems)
+  of SInt:
+    result = hash(n.num)
+  of SFloat:
+    result = hash(n.fnum)
+  of SString:
+    result = hash(n.str)
+  of SNil:
+    result = hash(0)
+  of SSymbol:
+    result = hash(n.symbol)
+  of SCons:
+    result = hash(n.car) !& hash(n.cdr)
+
+proc len*(n: SexpNode): int =
+  ## If `n` is a `SList`, it returns the number of elements.
+  ## If `n` is a `JObject`, it returns the number of pairs.
+  ## Else it returns 0.
+  case n.kind
+  of SList: result = n.elems.len
+  else: discard
+
+proc `[]`*(node: SexpNode, index: int): SexpNode =
+  ## Gets the node at `index` in a List. Result is undefined if `index`
+  ## is out of bounds
+  assert(not isNil(node))
+  assert(node.kind == SList)
+  return node.elems[index]
+
+proc add*(father, child: SexpNode) =
+  ## Adds `child` to a SList node `father`.
+  assert father.kind == SList
+  father.elems.add(child)
+
+# ------------- pretty printing ----------------------------------------------
+
+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) =
+  if ml: s.add("\n")
+
+proc escapeJson*(s: string): string =
+  ## Converts a string `s` to its JSON representation.
+  result = newStringOfCap(s.len + s.len shr 3)
+  result.add("\"")
+  for x in runes(s):
+    var r = int(x)
+    if r >= 32 and r <= 127:
+      var c = chr(r)
+      case c
+      of '"': result.add("\\\"") #" # gotta fix nim-mode
+      of '\\': result.add("\\\\")
+      else: result.add(c)
+    else:
+      result.add("\\u")
+      result.add(toHex(r, 4))
+  result.add("\"")
+
+proc copy*(p: SexpNode): SexpNode =
+  ## Performs a deep copy of `a`.
+  case p.kind
+  of SString:
+    result = newSString(p.str)
+  of SInt:
+    result = newSInt(p.num)
+  of SFloat:
+    result = newSFloat(p.fnum)
+  of SNil:
+    result = newSNil()
+  of SSymbol:
+    result = newSSymbol(p.symbol)
+  of SList:
+    result = newSList()
+    for i in items(p.elems):
+      result.elems.add(copy(i))
+  of SCons:
+    result = newSCons(copy(p.car), copy(p.cdr))
+
+proc toPretty(result: var string, node: SexpNode, indent = 2, ml = true,
+              lstArr = false, currIndent = 0) =
+  case node.kind
+  of SString:
+    if lstArr: result.indent(currIndent)
+    result.add(escapeJson(node.str))
+  of SInt:
+    if lstArr: result.indent(currIndent)
+    result.add($node.num)
+  of SFloat:
+    if lstArr: result.indent(currIndent)
+    result.add($node.fnum)
+  of SNil:
+    if lstArr: result.indent(currIndent)
+    result.add("nil")
+  of SSymbol:
+    if lstArr: result.indent(currIndent)
+    result.add($node.symbol)
+  of SList:
+    if lstArr: result.indent(currIndent)
+    if len(node.elems) != 0:
+      result.add("(")
+      result.nl(ml)
+      for i in 0..len(node.elems)-1:
+        if i > 0:
+          result.add(" ")
+          result.nl(ml) # New Line
+        toPretty(result, node.elems[i], indent, ml,
+            true, newIndent(currIndent, indent, ml))
+      result.nl(ml)
+      result.indent(currIndent)
+      result.add(")")
+    else: result.add("nil")
+  of SCons:
+    if lstArr: result.indent(currIndent)
+    result.add("(")
+    toPretty(result, node.car, indent, ml,
+        true, newIndent(currIndent, indent, ml))
+    result.add(" . ")
+    toPretty(result, node.cdr, indent, ml,
+        true, newIndent(currIndent, indent, ml))
+    result.add(")")
+
+proc pretty*(node: SexpNode, indent = 2): string =
+  ## Converts `node` to its Sexp Representation, with indentation and
+  ## on multiple lines.
+  result = ""
+  toPretty(result, node, indent)
+
+proc `$`*(node: SexpNode): string =
+  ## Converts `node` to its SEXP Representation on one line.
+  result = ""
+  toPretty(result, node, 0, false)
+
+iterator items*(node: SexpNode): SexpNode =
+  ## Iterator for the items of `node`. `node` has to be a SList.
+  assert node.kind == SList
+  for i in items(node.elems):
+    yield i
+
+iterator mitems*(node: var SexpNode): var SexpNode =
+  ## Iterator for the items of `node`. `node` has to be a SList. Items can be
+  ## modified.
+  assert node.kind == SList
+  for i in mitems(node.elems):
+    yield i
+
+proc eat(p: var SexpParser, tok: TTokKind) =
+  if p.tok == tok: discard getTok(p)
+  else: raiseParseErr(p, tokToStr[tok])
+
+proc parseSexp(p: var SexpParser): SexpNode =
+  ## Parses SEXP from a SEXP Parser `p`.
+  case p.tok
+  of tkString:
+    # we capture 'p.a' here, so we need to give it a fresh buffer afterwards:
+    result = newSStringMove(p.a)
+    p.a = ""
+    discard getTok(p)
+  of tkInt:
+    result = newSInt(parseBiggestInt(p.a))
+    discard getTok(p)
+  of tkFloat:
+    result = newSFloat(parseFloat(p.a))
+    discard getTok(p)
+  of tkNil:
+    result = newSNil()
+    discard getTok(p)
+  of tkSymbol:
+    result = newSSymbolMove(p.a)
+    p.a = ""
+    discard getTok(p)
+  of tkParensLe:
+    result = newSList()
+    discard getTok(p)
+    while p.tok notin {tkParensRi, tkDot}:
+      result.add(parseSexp(p))
+      if p.tok != tkSpace: break
+      discard getTok(p)
+    if p.tok == tkDot:
+      eat(p, tkDot)
+      eat(p, tkSpace)
+      result.add(parseSexp(p))
+      result = newSCons(result[0], result[1])
+    eat(p, tkParensRi)
+  of tkSpace, tkDot, tkError, tkParensRi, tkEof:
+    raiseParseErr(p, "(")
+
+proc open*(my: var SexpParser, input: Stream) =
+  ## initializes the parser with an input stream.
+  lexbase.open(my, input)
+  my.kind = sexpError
+  my.a = ""
+
+proc parseSexp*(s: Stream): SexpNode =
+  ## Parses from a buffer `s` into a `SexpNode`.
+  var p: SexpParser
+  p.open(s)
+  discard getTok(p) # read first token
+  result = p.parseSexp()
+  p.close()
+
+proc parseSexp*(buffer: string): SexpNode =
+  ## Parses Sexp from `buffer`.
+  result = parseSexp(newStringStream(buffer))
+
+when isMainModule:
+  let testSexp = parseSexp("""(1 (98 2) nil (2) foobar "foo" 9.234)""")
+  assert(testSexp[0].getNum == 1)
+  assert(testSexp[1][0].getNum == 98)
+  assert(testSexp[2].getElems == @[])
+  assert(testSexp[4].getSymbol == "foobar")
+  assert(testSexp[5].getStr == "foo")
+
+  let alist = parseSexp("""((1 . 2) (2 . "foo"))""")
+  assert(alist[0].getCons.car.getNum == 1)
+  assert(alist[0].getCons.cdr.getNum == 2)
+  assert(alist[1].getCons.cdr.getStr == "foo")
+
+  # Generator:
+  var j = convertSexp([true, false, "foobar", [1, 2, "baz"]])
+  assert($j == """(t nil "foobar" (1 2 "baz"))""")
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
index 3afb545c8..64e2cdcd3 100644
--- a/lib/pure/sockets.nim
+++ b/lib/pure/sockets.nim
@@ -986,7 +986,7 @@ proc select*(readfds, writefds, exceptfds: var seq[Socket],
   ## Traditional select function. This function will return the number of
   ## sockets that are ready to be read from, written to, or which have errors.
   ## If there are none; 0 is returned. 
-  ## ``Timeout`` is in miliseconds and -1 can be specified for no timeout.
+  ## ``Timeout`` is in milliseconds and -1 can be specified for no timeout.
   ## 
   ## Sockets which are **not** ready for reading, writing or which don't have
   ## errors waiting on them are removed from the ``readfds``, ``writefds``,
@@ -1040,7 +1040,7 @@ proc selectWrite*(writefds: var seq[Socket],
   ## written to. The sockets which **cannot** be written to will also be removed
   ## from ``writefds``.
   ##
-  ## ``timeout`` is specified in miliseconds and ``-1`` can be specified for
+  ## ``timeout`` is specified in milliseconds and ``-1`` can be specified for
   ## an unlimited time.
   var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
   
@@ -1174,7 +1174,7 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int,
 
 proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {.
   tags: [ReadIOEffect, TimeEffect].} =
-  ## overload with a ``timeout`` parameter in miliseconds.
+  ## overload with a ``timeout`` parameter in milliseconds.
   var waited = 0.0 # number of seconds already waited  
   
   var read = 0
@@ -1197,7 +1197,7 @@ proc recv*(socket: Socket, data: var string, size: int, timeout = -1): int =
   ## This function will throw an EOS exception when an error occurs. A value
   ## lower than 0 is never returned.
   ##
-  ## A timeout may be specified in miliseconds, if enough data is not received
+  ## A timeout may be specified in milliseconds, if enough data is not received
   ## within the time specified an ETimeout exception will be raised.
   ##
   ## **Note**: ``data`` must be initialised.
@@ -1258,7 +1258,7 @@ proc recvLine*(socket: Socket, line: var TaintedString, timeout = -1): bool {.
   ## If the socket is disconnected, ``line`` will be set to ``""`` and ``True``
   ## will be returned.
   ##
-  ## A timeout can be specified in miliseconds, if data is not received within
+  ## A timeout can be specified in milliseconds, if data is not received within
   ## the specified time an ETimeout exception will be raised.
   ##
   ## **Deprecated since version 0.9.2**: This function has been deprecated in
@@ -1302,7 +1302,7 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1) {.
   ##
   ## An EOS exception will be raised in the case of a socket error.
   ##
-  ## A timeout can be specified in miliseconds, if data is not received within
+  ## A timeout can be specified in milliseconds, if data is not received within
   ## the specified time an ETimeout exception will be raised.
   
   template addNLIfEmpty(): stmt =
@@ -1433,7 +1433,7 @@ proc recv*(socket: Socket): TaintedString {.tags: [ReadIOEffect], deprecated.} =
 proc recvTimeout*(socket: Socket, timeout: int): TaintedString {.
   tags: [ReadIOEffect], deprecated.} =
   ## overloaded variant to support a ``timeout`` parameter, the ``timeout``
-  ## parameter specifies the amount of miliseconds to wait for data on the
+  ## parameter specifies the amount of milliseconds to wait for data on the
   ## socket.
   ##
   ## **Deprecated since version 0.9.2**: This function is not safe for use.
@@ -1554,7 +1554,7 @@ proc skip*(socket: Socket) {.tags: [ReadIOEffect], deprecated.} =
 proc skip*(socket: Socket, size: int, timeout = -1) =
   ## Skips ``size`` amount of bytes.
   ##
-  ## An optional timeout can be specified in miliseconds, if skipping the
+  ## An optional timeout can be specified in milliseconds, if skipping the
   ## bytes takes longer than specified an ETimeout exception will be raised.
   ##
   ## Returns the number of skipped bytes.
@@ -1708,7 +1708,7 @@ proc connect*(socket: Socket, address: string, port = Port(0), timeout: int,
              af: Domain = AF_INET) {.tags: [ReadIOEffect, WriteIOEffect].} =
   ## Connects to server as specified by ``address`` on port specified by ``port``.
   ##
-  ## The ``timeout`` paremeter specifies the time in miliseconds to allow for
+  ## The ``timeout`` paremeter specifies the time in milliseconds to allow for
   ## the connection to the server to be made.
   let originalStatus = not socket.nonblocking
   socket.setBlocking(false)
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index e706f2016..77698d329 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -1,7 +1,7 @@
 #
 #
 #            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.
@@ -31,6 +31,8 @@ type
     getPositionImpl*: proc (s: Stream): int {.nimcall, tags: [], gcsafe.}
     readDataImpl*: proc (s: Stream, buffer: pointer,
                          bufLen: int): int {.nimcall, tags: [ReadIOEffect], gcsafe.}
+    peekDataImpl*: proc (s: Stream, buffer: pointer, 
+                         bufLen: int): int {.nimcall, tags: [ReadIOEffect], gcsafe.}
     writeDataImpl*: proc (s: Stream, buffer: pointer, bufLen: int) {.nimcall,
       tags: [WriteIOEffect], gcsafe.}
     flushImpl*: proc (s: Stream) {.nimcall, tags: [WriteIOEffect], gcsafe.}
@@ -84,6 +86,11 @@ proc readData*(s, unused: Stream, buffer: pointer,
   ## low level proc that reads data into an untyped `buffer` of `bufLen` size.
   result = s.readDataImpl(s, buffer, bufLen)
 
+proc peekData*(s: Stream, buffer: pointer, bufLen: int): int =
+  ## low level proc that reads data into an untyped `buffer` of `bufLen` size
+  ## without moving stream position
+  result = s.peekDataImpl(s, buffer, bufLen)
+
 proc writeData*(s: Stream, buffer: pointer, bufLen: int) =
   ## low level proc that writes an untyped `buffer` of `bufLen` size
   ## to the stream `s`.
@@ -121,39 +128,77 @@ proc read[T](s: Stream, result: var T) =
   if readData(s, addr(result), sizeof(T)) != sizeof(T):
     raise newEIO("cannot read from stream")
 
+proc peek[T](s: Stream, result: var T) =
+  ## generic peek procedure. Peeks `result` from the stream `s`.
+  if peekData(s, addr(result), sizeof(T)) != sizeof(T):
+    raise newEIO("cannot read from stream")
+
 proc readChar*(s: Stream): char =
   ## 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 peekChar*(s: Stream): char =
+  ## peeks a char from the stream `s`. Raises `EIO` if an error occurred.
+  ## Returns '\0' as an EOF marker.
+  if peekData(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 occurred.
   read(s, result)
 
+proc peekBool*(s: Stream): bool =
+  ## peeks a bool from the stream `s`. Raises `EIO` if an error occured.
+  peek(s, result)
+
 proc readInt8*(s: Stream): int8 = 
   ## reads an int8 from the stream `s`. Raises `EIO` if an error occurred.
   read(s, result)
 
+proc peekInt8*(s: Stream): int8 =
+  ## peeks an int8 from the stream `s`. Raises `EIO` if an error occurred.
+  peek(s, result)
+
 proc readInt16*(s: Stream): int16 = 
   ## reads an int16 from the stream `s`. Raises `EIO` if an error occurred.
   read(s, result)
 
+proc peekInt16*(s: Stream): int16 = 
+  ## peeks an int16 from the stream `s`. Raises `EIO` if an error occurred.
+  peek(s, result)
+
 proc readInt32*(s: Stream): int32 = 
   ## reads an int32 from the stream `s`. Raises `EIO` if an error occurred.
   read(s, result)
 
+proc peekInt32*(s: Stream): int32 = 
+  ## peeks an int32 from the stream `s`. Raises `EIO` if an error occurred.
+  peek(s, result)
+
 proc readInt64*(s: Stream): int64 = 
   ## reads an int64 from the stream `s`. Raises `EIO` if an error occurred.
   read(s, result)
 
+proc peekInt64*(s: Stream): int64 = 
+  ## peeks an int64 from the stream `s`. Raises `EIO` if an error occurred.
+  peek(s, result)
+
 proc readFloat32*(s: Stream): float32 = 
   ## reads a float32 from the stream `s`. Raises `EIO` if an error occurred.
   read(s, result)
 
+proc peekFloat32*(s: Stream): float32 = 
+  ## peeks a float32 from the stream `s`. Raises `EIO` if an error occurred.
+  peek(s, result)
+
 proc readFloat64*(s: Stream): float64 = 
   ## reads a float64 from the stream `s`. Raises `EIO` if an error occurred.
   read(s, result)
 
+proc peekFloat64*(s: Stream): float64 = 
+  ## peeks a float64 from the stream `s`. Raises `EIO` if an error occurred.
+  peek(s, result)
+
 proc readStr*(s: Stream, length: int): TaintedString = 
   ## reads a string of length `length` from the stream `s`. Raises `EIO` if 
   ## an error occurred.
@@ -161,6 +206,13 @@ proc readStr*(s: Stream, length: int): TaintedString =
   var L = readData(s, addr(string(result)[0]), length)
   if L != length: setLen(result.string, L)
 
+proc peekStr*(s: Stream, length: int): TaintedString = 
+  ## peeks a string of length `length` from the stream `s`. Raises `EIO` if 
+  ## an error occurred.
+  result = newString(length).TaintedString
+  var L = peekData(s, addr(string(result)[0]), length)
+  if L != length: setLen(result.string, L)
+
 proc readLine*(s: Stream, line: var TaintedString): bool =
   ## reads a line of text from the stream `s` into `line`. `line` must not be
   ## ``nil``! May throw an IO exception.
@@ -181,6 +233,17 @@ proc readLine*(s: Stream, line: var TaintedString): bool =
     line.string.add(c)
   result = true
 
+proc peekLine*(s: Stream, line: var TaintedString): bool =
+  ## peeks a line of text from the stream `s` into `line`. `line` must not be
+  ## ``nil``! 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.
+  ## Returns ``false`` if the end of the file has been reached, ``true``
+  ## otherwise. If ``false`` is returned `line` contains no new data.
+  let pos = getPosition(s)
+  defer: setPosition(s, pos)
+  readLine(s, line)
+
 proc readLine*(s: Stream): TaintedString =
   ## Reads a line from a stream `s`. Note: This is not very efficient. Raises 
   ## `EIO` if an error occurred.
@@ -195,6 +258,13 @@ proc readLine*(s: Stream): TaintedString =
     else:
       result.string.add(c)
 
+proc peekLine*(s: Stream): TaintedString =
+  ## Peeks a line from a stream `s`. Note: This is not very efficient. Raises 
+  ## `EIO` if an error occurred.
+  let pos = getPosition(s)
+  defer: setPosition(s, pos)
+  readLine(s)
+
 type
   StringStream* = ref StringStreamObj ## a stream that encapsulates a string
   StringStreamObj* = object of StreamObj
@@ -222,6 +292,12 @@ proc ssReadData(s: Stream, buffer: pointer, bufLen: int): int =
     copyMem(buffer, addr(s.data[s.pos]), result)
     inc(s.pos, result)
 
+proc ssPeekData(s: Stream, buffer: pointer, bufLen: int): int =
+  var s = StringStream(s)
+  result = min(bufLen, s.data.len - s.pos)
+  if result > 0: 
+    copyMem(buffer, addr(s.data[s.pos]), result)
+
 proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) = 
   var s = StringStream(s)
   if bufLen <= 0:
@@ -245,6 +321,7 @@ proc newStringStream*(s: string = ""): StringStream =
   result.setPositionImpl = ssSetPosition
   result.getPositionImpl = ssGetPosition
   result.readDataImpl = ssReadData
+  result.peekDataImpl = ssPeekData
   result.writeDataImpl = ssWriteData
 
 when not defined(js):
@@ -266,6 +343,11 @@ when not defined(js):
 
   proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int =
     result = readBuffer(FileStream(s).f, buffer, bufLen)
+  
+  proc fsPeekData(s: Stream, buffer: pointer, bufLen: int): int =
+    let pos = fsGetPosition(s)
+    defer: fsSetPosition(s, pos)
+    result = readBuffer(FileStream(s).f, buffer, bufLen)
 
   proc fsWriteData(s: Stream, buffer: pointer, bufLen: int) =
     if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen:
@@ -280,6 +362,7 @@ when not defined(js):
     result.setPositionImpl = fsSetPosition
     result.getPositionImpl = fsGetPosition
     result.readDataImpl = fsReadData
+    result.peekDataImpl = fsPeekData
     result.writeDataImpl = fsWriteData
     result.flushImpl = fsFlush
 
@@ -329,6 +412,9 @@ else:
     proc hsReadData(s: FileHandleStream, buffer: pointer, bufLen: int): int = 
       result = posix.read(s.handle, buffer, bufLen)
       inc(s.pos, result)
+    
+    proc hsPeekData(s: FileHandleStream, buffer: pointer, bufLen: int): int =
+      result = posix.read(s.handle, buffer, bufLen)
       
     proc hsWriteData(s: FileHandleStream, buffer: pointer, bufLen: int) = 
       if posix.write(s.handle, buffer, bufLen) != bufLen: 
@@ -344,6 +430,7 @@ else:
     result.setPosition = hsSetPosition
     result.getPosition = hsGetPosition
     result.readData = hsReadData
+    result.peekData = hsPeekData
     result.writeData = hsWriteData
 
   proc newFileHandleStream*(filename: string, 
@@ -361,3 +448,13 @@ else:
       var handle = open(filename, flags)
       if handle < 0: raise newEOS("posix.open() call failed")
     result = newFileHandleStream(handle)
+
+when defined(testing):
+  var ss = newStringStream("The quick brown fox jumped over the lazy dog.\nThe lazy dog ran")
+  assert(ss.getPosition == 0)
+  assert(ss.peekStr(5) == "The q")
+  assert(ss.getPosition == 0) # haven't moved
+  assert(ss.readStr(5) == "The q")
+  assert(ss.getPosition == 5) # did move
+  assert(ss.peekLine() == "uick brown fox jumped over the lazy dog.")
+  assert(ss.getPosition == 5) # haven't moved
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 59cebf7fa..eb4be719a 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -169,14 +169,12 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
 
 {.pop.}
 
-proc strip*(s: string, leading = true, trailing = true): string {.noSideEffect,
-  rtl, extern: "nsuStrip".} =
-  ## Strips whitespace from `s` and returns the resulting string.
+proc strip*(s: string, leading = true, trailing = true, chars: set[char] = Whitespace): string 
+  {.noSideEffect, rtl, extern: "nsuStrip".} =
+  ## Strips `chars` from `s` and returns the resulting string.
   ##
-  ## If `leading` is true, leading whitespace is stripped.
-  ## If `trailing` is true, trailing whitespace is stripped.
-  const
-    chars: set[char] = Whitespace
+  ## If `leading` is true, leading `chars` are stripped.
+  ## If `trailing` is true, trailing `chars` are stripped.
   var
     first = 0
     last = len(s)-1
@@ -1433,3 +1431,11 @@ when isMainModule:
   doAssert count("foofoofoo", "foofoo", overlapping = true) == 2
   doAssert count("foofoofoo", 'f') == 3
   doAssert count("foofoofoobar", {'f','b'}) == 4
+
+  doAssert strip("  foofoofoo  ") == "foofoofoo"
+  doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo"
+  doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo"
+  doAssert strip("stripme but don't strip this stripme",
+                 chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) == " but don't strip this "
+  doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo"
+  doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos"
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 5f8835c6a..b8836c15b 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -119,7 +119,7 @@ type
                               ## in the range 0 to 23.
     monthday*: range[1..31]   ## The day of the month, in the range 1 to 31.
     month*: Month             ## The current month.
-    year*: range[-10_000..10_000] ## The current year.
+    year*: int                ## The current year.
     weekday*: WeekDay         ## The current day of the week.
     yearday*: range[0..365]   ## The number of days since January 1,
                               ## in the range 0 to 365.
@@ -134,7 +134,7 @@ type
   ## everything should be positive or everything negative. Zero is
   ## fine too. Mixed signs will lead to unexpected results.
   TimeInterval* = object ## a time interval
-    miliseconds*: int ## The number of miliseconds
+    milliseconds*: int ## The number of milliseconds
     seconds*: int     ## The number of seconds
     minutes*: int     ## The number of minutes
     hours*: int       ## The number of hours
@@ -145,6 +145,11 @@ type
 {.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time,
     TTimeInterval: TimeInterval, TTimeInfo: TimeInfo].}
 
+proc miliseconds*(t: TimeInterval): int {.deprecated.} = t.milliseconds
+
+proc `miliseconds=`*(t:var TimeInterval, milliseconds: int) {.deprecated.} =
+  t.milliseconds = milliseconds
+
 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
@@ -208,13 +213,13 @@ 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], benign.}
-  ## get the miliseconds from the start of the program. **Deprecated since
+  ## get the milliseconds 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*(milliseconds, seconds, minutes, hours, days, months,
                    years: int = 0): TimeInterval =
   ## creates a new ``TimeInterval``.
-  result.miliseconds = miliseconds
+  result.milliseconds = milliseconds
   result.seconds = seconds
   result.minutes = minutes
   result.hours = hours
@@ -264,7 +269,7 @@ proc toSeconds(a: TimeInfo, interval: TimeInterval): float =
   result += float(newinterv.hours * 60 * 60)
   result += float(newinterv.minutes * 60)
   result += float(newinterv.seconds)
-  result += newinterv.miliseconds / 1000
+  result += newinterv.milliseconds / 1000
 
 proc `+`*(a: TimeInfo, interval: TimeInterval): TimeInfo =
   ## adds ``interval`` time.
@@ -379,7 +384,7 @@ when not defined(JS):
     result.hour = t.hour
     result.monthday = t.monthday
     result.month = ord(t.month)
-    result.year = t.year - 1900
+    result.year = cint(t.year - 1900)
     result.weekday = weekDays[t.weekday]
     result.yearday = t.yearday
     result.isdst = if t.isDST: 1 else: 0
@@ -530,7 +535,7 @@ elif defined(JS):
     startMilsecs = getTime()
 
   proc getStartMilsecs(): int =
-    ## get the miliseconds from the start of the program
+    ## get the milliseconds from the start of the program
     return int(getTime() - startMilsecs)
 
   proc valueOf(time: Time): float {.importcpp: "getTime", tags:[]}
diff --git a/lib/system.nim b/lib/system.nim
index ca4c81411..1e6f76f3d 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1110,7 +1110,7 @@ var programResult* {.exportc: "nim_program_result".}: int
   ## prematurely using ``quit``, this value is ignored.
 
 proc quit*(errorcode: int = QuitSuccess) {.
-  magic: "Exit", importc: "exit", header: "<stdlib.h>", noReturn.}
+  magic: "Exit", importc: "exit", header: "<stdlib.h>", noreturn.}
   ## Stops the program immediately with an exit code.
   ##
   ## Before stopping the program the "quit procedures" are called in the
@@ -2270,20 +2270,21 @@ when hostOS == "standalone":
   include panicoverride
 
 when not declared(sysFatal):
-  template sysFatal(exceptn: typedesc, message: string) =
-    when hostOS == "standalone":
+  when hostOS == "standalone":
+    proc sysFatal(exceptn: typedesc, message: string) {.inline.} =
       panic(message)
-    else:
+
+    proc sysFatal(exceptn: typedesc, message, arg: string) {.inline.} =
+      rawoutput(message)
+      panic(arg)
+  else:
+    proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} =
       var e: ref exceptn
       new(e)
       e.msg = message
       raise e
 
-  template sysFatal(exceptn: typedesc, message, arg: string) =
-    when hostOS == "standalone":
-      rawoutput(message)
-      panic(arg)
-    else:
+    proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noReturn.} =
       var e: ref exceptn
       new(e)
       e.msg = message & arg
diff --git a/lib/system/arithm.nim b/lib/system/arithm.nim
index f68e2dcd9..ef153417c 100644
--- a/lib/system/arithm.nim
+++ b/lib/system/arithm.nim
@@ -10,11 +10,11 @@
 
 # simple integer arithmetic with overflow checking
 
-proc raiseOverflow {.compilerproc, noinline, noreturn.} =
+proc raiseOverflow {.compilerproc, noinline.} =
   # a single proc to reduce code size to a minimum
   sysFatal(OverflowError, "over- or underflow")
 
-proc raiseDivByZero {.compilerproc, noinline, noreturn.} =
+proc raiseDivByZero {.compilerproc, noinline.} =
   sysFatal(DivByZeroError, "division by zero")
 
 proc addInt64(a, b: int64): int64 {.compilerProc, inline.} =
@@ -327,13 +327,13 @@ when not declared(mulInt):
 # We avoid setting the FPU control word here for compatibility with libraries
 # written in other languages.
 
-proc raiseFloatInvalidOp {.noinline, noreturn.} =
+proc raiseFloatInvalidOp {.noinline.} =
   sysFatal(FloatInvalidOpError, "FPU operation caused a NaN result")
 
 proc nanCheck(x: float64) {.compilerProc, inline.} =
   if x != x: raiseFloatInvalidOp()
 
-proc raiseFloatOverflow(x: float64) {.noinline, noreturn.} =
+proc raiseFloatOverflow(x: float64) {.noinline.} =
   if x > 0.0:
     sysFatal(FloatOverflowError, "FPU operation caused an overflow")
   else:
diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim
index 2f6d25a12..6caf99d27 100644
--- a/lib/system/chcks.nim
+++ b/lib/system/chcks.nim
@@ -9,16 +9,16 @@
 
 # Implementation of some runtime checks.
 
-proc raiseRangeError(val: BiggestInt) {.compilerproc, noreturn, noinline.} =
+proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} =
   when hostOS == "standalone":
     sysFatal(RangeError, "value out of range")
   else:
     sysFatal(RangeError, "value out of range: ", $val)
 
-proc raiseIndexError() {.compilerproc, noreturn, noinline.} =
+proc raiseIndexError() {.compilerproc, noinline.} =
   sysFatal(IndexError, "index out of bounds")
 
-proc raiseFieldError(f: string) {.compilerproc, noreturn, noinline.} =
+proc raiseFieldError(f: string) {.compilerproc, noinline.} =
   sysFatal(FieldError, f, " is not accessible")
 
 proc chckIndx(i, a, b: int): int =
diff --git a/lib/windows/windows.nim b/lib/windows/windows.nim
index b76dea6c5..02c87132a 100644
--- a/lib/windows/windows.nim
+++ b/lib/windows/windows.nim
@@ -18513,11 +18513,15 @@ proc DisableThreadLibraryCalls*(hLibModule: HMODULE): WINBOOL{.stdcall,
 proc GetProcAddress*(hModule: HINST, lpProcName: LPCSTR): FARPROC{.stdcall,

     dynlib: "kernel32", importc: "GetProcAddress".}

 proc GetVersion*(): DWORD{.stdcall, dynlib: "kernel32", importc: "GetVersion".}

-proc GlobalAlloc*(uFlags: int32, dwBytes: DWORD): HGLOBAL{.stdcall,

+proc GlobalAlloc*(uFlags: int32, dwBytes: SIZE_T): HGLOBAL{.stdcall,

     dynlib: "kernel32", importc: "GlobalAlloc".}

-proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: DWORD, uFlags: int32): HGLOBAL{.

+proc GlobalAlloc*(uFlags: int32, dwBytes: DWORD): HGLOBAL{.stdcall,

+    dynlib: "kernel32", importc: "GlobalAlloc", deprecated.}

+proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: SIZE_T, uFlags: int32): HGLOBAL{.

     stdcall, dynlib: "kernel32", importc: "GlobalReAlloc".}

-proc GlobalSize*(hMem: HGLOBAL): DWORD{.stdcall, dynlib: "kernel32",

+proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: DWORD, uFlags: int32): HGLOBAL{.

+    stdcall, dynlib: "kernel32", importc: "GlobalReAlloc", deprecated.}

+proc GlobalSize*(hMem: HGLOBAL): SIZE_T{.stdcall, dynlib: "kernel32",

                                         importc: "GlobalSize".}

 proc GlobalFlags*(hMem: HGLOBAL): WINUINT{.stdcall, dynlib: "kernel32",

                                         importc: "GlobalFlags".}

@@ -18541,10 +18545,14 @@ proc GlobalUnWire*(hMem: HGLOBAL): WINBOOL{.stdcall, dynlib: "kernel32",
     importc: "GlobalUnWire".}

 proc GlobalMemoryStatus*(lpBuffer: LPMEMORYSTATUS){.stdcall, dynlib: "kernel32",

     importc: "GlobalMemoryStatus".}

-proc LocalAlloc*(uFlags: WINUINT, uBytes: WINUINT): HLOCAL{.stdcall,

+proc LocalAlloc*(uFlags: WINUINT, uBytes: SIZE_T): HLOCAL{.stdcall,

     dynlib: "kernel32", importc: "LocalAlloc".}

-proc LocalReAlloc*(hMem: HLOCAL, uBytes: WINUINT, uFlags: WINUINT): HLOCAL{.stdcall,

+proc LocalAlloc*(uFlags: WINUINT, uBytes: DWORD): HLOCAL{.stdcall,

+    dynlib: "kernel32", importc: "LocalAlloc", deprecated.}

+proc LocalReAlloc*(hMem: HLOCAL, uBytes: SIZE_T, uFlags: WINUINT): HLOCAL{.stdcall,

     dynlib: "kernel32", importc: "LocalReAlloc".}

+proc LocalReAlloc*(hMem: HLOCAL, uBytes: DWORD, uFlags: WINUINT): HLOCAL{.stdcall,

+    dynlib: "kernel32", importc: "LocalReAlloc", deprecated.}

 proc LocalLock*(hMem: HLOCAL): LPVOID{.stdcall, dynlib: "kernel32",

                                        importc: "LocalLock".}

 proc LocalHandle*(pMem: LPCVOID): HLOCAL{.stdcall, dynlib: "kernel32",

@@ -18564,38 +18572,71 @@ proc LocalCompact*(uMinFree: WINUINT): WINUINT{.stdcall, dynlib: "kernel32",
 proc FlushInstructionCache*(hProcess: HANDLE, lpBaseAddress: LPCVOID,

                             dwSize: DWORD): WINBOOL{.stdcall,

     dynlib: "kernel32", importc: "FlushInstructionCache".}

-proc VirtualAlloc*(lpAddress: LPVOID, dwSize: DWORD, flAllocationType: DWORD,

+proc VirtualAlloc*(lpAddress: LPVOID, dwSize: SIZE_T, flAllocationType: DWORD,

                    flProtect: DWORD): LPVOID{.stdcall, dynlib: "kernel32",

     importc: "VirtualAlloc".}

-proc VirtualFree*(lpAddress: LPVOID, dwSize: DWORD, dwFreeType: DWORD): WINBOOL{.

+proc VirtualAlloc*(lpAddress: LPVOID, dwSize: DWORD, flAllocationType: DWORD,

+                   flProtect: DWORD): LPVOID{.stdcall, dynlib: "kernel32",

+    importc: "VirtualAlloc", deprecated.}

+proc VirtualAllocEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: SIZE_T,

+                     flAllocationType: DWORD, flProtect: DWORD): LPVOID

+                     {.stdcall, dynlib: "kernel32", importc: "VirtualAllocEx".}

+proc VirtualAllocEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD,

+                     flAllocationType: DWORD, flProtect: DWORD): LPVOID

+                     {.stdcall, dynlib: "kernel32", importc: "VirtualAllocEx", 

+                       deprecated.}

+proc VirtualFree*(lpAddress: LPVOID, dwSize: SIZE_T, dwFreeType: DWORD): WINBOOL{.

     stdcall, dynlib: "kernel32", importc: "VirtualFree".}

-proc VirtualProtect*(lpAddress: LPVOID, dwSize: DWORD, flNewProtect: DWORD,

+proc VirtualFree*(lpAddress: LPVOID, dwSize: DWORD, dwFreeType: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "VirtualFree", deprecated.}

+proc VirtualFreeEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: SIZE_T,

+                    dwFreeType: DWORD): WINBOOL

+                    {.stdcall, dynlib: "kernel32", importc: "VirtualFree".}

+proc VirtualFreeEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD,

+                    dwFreeType: DWORD): WINBOOL

+                    {.stdcall, dynlib: "kernel32", importc: "VirtualFree".}

+proc VirtualProtect*(lpAddress: LPVOID, dwSize: SIZE_T, flNewProtect: DWORD,

                      lpflOldProtect: PDWORD): WINBOOL{.stdcall,

     dynlib: "kernel32", importc: "VirtualProtect".}

+proc VirtualProtect*(lpAddress: LPVOID, dwSize: DWORD, flNewProtect: DWORD,

+                     lpflOldProtect: PDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "VirtualProtect", deprecated.}

 proc VirtualQuery*(lpAddress: LPCVOID, lpBuffer: PMEMORY_BASIC_INFORMATION,

                    dwLength: DWORD): DWORD{.stdcall, dynlib: "kernel32",

     importc: "VirtualQuery".}

-proc VirtualProtectEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD,

+proc VirtualProtectEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: SIZE_T,

                        flNewProtect: DWORD, lpflOldProtect: PDWORD): WINBOOL{.

     stdcall, dynlib: "kernel32", importc: "VirtualProtectEx".}

+proc VirtualProtectEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD,

+                       flNewProtect: DWORD, lpflOldProtect: PDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "VirtualProtectEx", deprecated.}

 proc VirtualQueryEx*(hProcess: HANDLE, lpAddress: LPCVOID,

-                     lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: DWORD): DWORD{.

+                     lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: SIZE_T): DWORD{.

     stdcall, dynlib: "kernel32", importc: "VirtualQueryEx".}

-proc HeapCreate*(flOptions: DWORD, dwInitialSize: DWORD, dwMaximumSize: DWORD): HANDLE{.

+proc VirtualQueryEx*(hProcess: HANDLE, lpAddress: LPCVOID,

+                     lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: DWORD): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "VirtualQueryEx", deprecated.}

+proc HeapCreate*(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T): HANDLE{.

     stdcall, dynlib: "kernel32", importc: "HeapCreate".}

+proc HeapCreate*(flOptions: DWORD, dwInitialSize: DWORD, dwMaximumSize: DWORD): HANDLE{.

+    stdcall, dynlib: "kernel32", importc: "HeapCreate", deprecated.}

 proc HeapDestroy*(hHeap: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32",

     importc: "HeapDestroy".}

-proc HeapAlloc*(hHeap: HANDLE, dwFlags: DWORD, dwBytes: DWORD): LPVOID{.stdcall,

+proc HeapAlloc*(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T): LPVOID{.stdcall,

     dynlib: "kernel32", importc: "HeapAlloc".}

-proc HeapReAlloc*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: DWORD): LPVOID{.

+proc HeapAlloc*(hHeap: HANDLE, dwFlags: DWORD, dwBytes: DWORD): LPVOID{.stdcall,

+    dynlib: "kernel32", importc: "HeapAlloc", deprecated.}

+proc HeapReAlloc*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T): LPVOID{.

     stdcall, dynlib: "kernel32", importc: "HeapReAlloc".}

+proc HeapReAlloc*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: DWORD): LPVOID{.

+    stdcall, dynlib: "kernel32", importc: "HeapReAlloc", deprecated.}

 proc HeapFree*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID): WINBOOL{.stdcall,

     dynlib: "kernel32", importc: "HeapFree".}

-proc HeapSize*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPCVOID): DWORD{.stdcall,

+proc HeapSize*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPCVOID): SIZE_T{.stdcall,

     dynlib: "kernel32", importc: "HeapSize".}

 proc HeapValidate*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPCVOID): WINBOOL{.

     stdcall, dynlib: "kernel32", importc: "HeapValidate".}

-proc HeapCompact*(hHeap: HANDLE, dwFlags: DWORD): WINUINT{.stdcall,

+proc HeapCompact*(hHeap: HANDLE, dwFlags: DWORD): SIZE_T{.stdcall,

     dynlib: "kernel32", importc: "HeapCompact".}

 proc GetProcessHeap*(): HANDLE{.stdcall, dynlib: "kernel32",

                                 importc: "GetProcessHeap".}

@@ -19221,10 +19262,14 @@ proc FindNextChangeNotification*(hChangeHandle: HANDLE): WINBOOL{.stdcall,
     dynlib: "kernel32", importc: "FindNextChangeNotification".}

 proc FindCloseChangeNotification*(hChangeHandle: HANDLE): WINBOOL{.stdcall,

     dynlib: "kernel32", importc: "FindCloseChangeNotification".}

-proc VirtualLock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall,

+proc VirtualLock*(lpAddress: LPVOID, dwSize: SIZE_T): WINBOOL{.stdcall,

     dynlib: "kernel32", importc: "VirtualLock".}

-proc VirtualUnlock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall,

+proc VirtualLock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "VirtualLock", deprecated.}

+proc VirtualUnlock*(lpAddress: LPVOID, dwSize: SIZE_T): WINBOOL{.stdcall,

     dynlib: "kernel32", importc: "VirtualUnlock".}

+proc VirtualUnlock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "VirtualUnlock", deprecated.}

 proc MapViewOfFileEx*(hFileMappingObject: HANDLE, dwDesiredAccess: DWORD,

                       dwFileOffsetHigh: DWORD, dwFileOffsetLow: DWORD,

                       dwNumberOfBytesToMap: DWORD, lpBaseAddress: LPVOID): LPVOID{.

diff --git a/tests/collections/tsets.nim b/tests/collections/tsets.nim
index 656c5b3f2..a5bbe8dbd 100644
--- a/tests/collections/tsets.nim
+++ b/tests/collections/tsets.nim
@@ -1,17 +1,37 @@
-discard """
-  output: '''true
-true'''
-"""
-
 import sets
-var
-  a = initSet[int]()
-  b = initSet[int]()
-  c = initSet[string]()
 
-for i in 0..5: a.incl(i)
-for i in 1..6: b.incl(i)
-for i in 0..5: c.incl($i)
+block setEquality:
+  var
+    a = initSet[int]()
+    b = initSet[int]()
+    c = initSet[string]()
+
+  for i in 0..5: a.incl(i)
+  for i in 1..6: b.incl(i)
+  for i in 0..5: c.incl($i)
+
+  doAssert map(a, proc(x: int): int = x + 1) == b
+  doAssert map(a, proc(x: int): string = $x) == c
+
+
+block setsContainingTuples:
+  var set = initSet[tuple[i: int, i64: int64, f: float]]()
+  set.incl( (i: 123, i64: 123'i64, f: 3.14) )
+  doAssert set.contains( (i: 123, i64: 123'i64, f: 3.14) )
+  doAssert( not set.contains( (i: 456, i64: 789'i64, f: 2.78) ) )
+
+
+block setWithTuplesWithSeqs:
+  var s = initSet[tuple[s: seq[int]]]()
+  s.incl( (s: @[1, 2, 3]) )
+  doAssert s.contains( (s: @[1, 2, 3]) )
+  doAssert( not s.contains((s: @[4, 5, 6])) )
+
+
+block setWithSequences:
+  var s = initSet[seq[int]]()
+  s.incl( @[1, 2, 3] )
+  doAssert s.contains(@[1, 2, 3])
+  doAssert( not s.contains(@[4, 5, 6]) )
+
 
-echo map(a, proc(x: int): int = x + 1) == b
-echo map(a, proc(x: int): string = $x) == c
diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim
index 3a923610e..a10606843 100644
--- a/tests/collections/ttables.nim
+++ b/tests/collections/ttables.nim
@@ -22,15 +22,15 @@ const
     "---00": 346677844,
     "0": 34404,
     "1": 344004,
-    "10": 34484, 
+    "10": 34484,
     "11": 34474,
     "12": 789,
     "19": 34464,
-    "2": 344774, "20": 34454, 
+    "2": 344774, "20": 34454,
     "3": 342244, "30": 34141244,
     "34": 123456,
     "4": 3412344, "40": 344114,
-    "5": 341232144, "50": 344490, 
+    "5": 341232144, "50": 344490,
     "6": 34214544, "60": 344491,
     "7": 3434544, "70": 344492,
     "8": 344544, "80": 344497,
@@ -46,7 +46,7 @@ block tableTest1:
   for x in 0..1:
     for y in 0..1:
       assert t[(x,y)] == $x & $y
-  assert($t == 
+  assert($t ==
     "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
 
 block tableTest2:
@@ -55,14 +55,16 @@ block tableTest2:
   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"))
-  
+  assert "123" in t
+  assert("111" notin t)
+
   for key, val in items(data): t[key] = val.toFloat
   for key, val in items(data): assert t[key] == val.toFloat
 
diff --git a/tests/collections/ttablesref.nim b/tests/collections/ttablesref.nim
index 16b0d831e..0b641ebc7 100644
--- a/tests/collections/ttablesref.nim
+++ b/tests/collections/ttablesref.nim
@@ -22,15 +22,15 @@ const
     "---00": 346677844,
     "0": 34404,
     "1": 344004,
-    "10": 34484, 
+    "10": 34484,
     "11": 34474,
     "12": 789,
     "19": 34464,
-    "2": 344774, "20": 34454, 
+    "2": 344774, "20": 34454,
     "3": 342244, "30": 34141244,
     "34": 123456,
     "4": 3412344, "40": 344114,
-    "5": 341232144, "50": 344490, 
+    "5": 341232144, "50": 344490,
     "6": 34214544, "60": 344491,
     "7": 3434544, "70": 344492,
     "8": 344544, "80": 344497,
@@ -46,7 +46,7 @@ block tableTest1:
   for x in 0..1:
     for y in 0..1:
       assert t[(x,y)] == $x & $y
-  assert($t == 
+  assert($t ==
     "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
 
 block tableTest2:
@@ -55,17 +55,19 @@ block tableTest2:
   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 "123" in t
   assert(not hasKey(t, "111"))
-  
+  assert "111" notin t
+
   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 = newOrderedTable[string, int](2)
diff --git a/tests/macros/tgettype.nim b/tests/macros/tgettype.nim
new file mode 100644
index 000000000..0eab6c0a0
--- /dev/null
+++ b/tests/macros/tgettype.nim
@@ -0,0 +1,20 @@
+discard """
+msg: '''ObjectTy(Sym(Model), RecList(Sym(name), Sym(password)))
+BracketExpr(Sym(typeDesc), Sym(User))'''
+"""
+import strutils, macros
+
+type
+  Model = object of RootObj
+  User = object of Model
+    name : string
+    password : string
+
+macro testUser: expr =
+  return newLit(User.getType.lispRepr)
+
+macro testGeneric(T: typedesc[Model]): expr =
+  return newLit(T.getType.lispRepr)
+
+echo testUser
+echo User.testGeneric
diff --git a/tests/manyloc/standalone/panicoverride.nim b/tests/manyloc/standalone/panicoverride.nim
index efd2b21f9..d9b3f4388 100644
--- a/tests/manyloc/standalone/panicoverride.nim
+++ b/tests/manyloc/standalone/panicoverride.nim
@@ -7,13 +7,13 @@ proc exit(code: int) {.importc, header: "<stdlib.h>", cdecl.}
 proc rawoutput(s: string) =
   printf("%s\n", s)
 
-proc panic(s: string) =
+proc panic(s: string) {.noreturn.} =
   rawoutput(s)
   exit(1)
 
 # Alternatively we also could implement these 2 here:
 #
-# template sysFatal(exceptn: typeDesc, message: string)
-# template sysFatal(exceptn: typeDesc, message, arg: string)
+# proc sysFatal(exceptn: typeDesc, message: string) {.noReturn.}
+# proc sysFatal(exceptn: typeDesc, message, arg: string) {.noReturn.}
 
 {.pop.}
diff --git a/tests/metatype/ttypedesc3.nim b/tests/metatype/ttypedesc3.nim
new file mode 100644
index 000000000..3d40b25b2
--- /dev/null
+++ b/tests/metatype/ttypedesc3.nim
@@ -0,0 +1,19 @@
+import typetraits
+
+type
+  Base = object of RootObj
+  Child = object of Base
+
+proc pr(T: typedesc[Base]) = echo "proc " & T.name
+method me(T: typedesc[Base]) = echo "method " & T.name
+iterator it(T: typedesc[Base]) = yield "yield " & T.name
+
+Base.pr
+Child.pr
+
+Base.me
+when false:
+  Child.me #<- bug #2710
+
+for s in Base.it: echo s
+for s in Child.it: echo s #<- bug #2662
diff --git a/tests/readme.txt b/tests/readme.txt
index 0d33a81c7..2cfc79f9a 100644
--- a/tests/readme.txt
+++ b/tests/readme.txt
@@ -3,8 +3,11 @@ Each test must have a filename of the form: ``t*.nim``
 

 Each test can contain a spec in a ``discard """"""`` block.

 

-The folder ``rodfiles`` contains special tests that test incremental 

+The folder ``rodfiles`` contains special tests that test incremental

 compilation via symbol files.

 

 The folder ``dll`` contains simple DLL tests.

 

+The folder ``realtimeGC`` contains a test for validating that the realtime GC

+can run properly without linking against the nimrtl.dll/so. It includes a C

+client and platform specific build files for manual compilation.

diff --git a/tests/realtimeGC/cmain.c b/tests/realtimeGC/cmain.c
new file mode 100644
index 000000000..e9a46d7ce
--- /dev/null
+++ b/tests/realtimeGC/cmain.c
@@ -0,0 +1,67 @@
+
+#ifdef WIN
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+
+#define RUNTIME (15*60)
+
+
+typedef void (*pFunc)(void);
+
+int main(int argc, char* argv[])
+{
+    int i;
+    void* hndl;
+    pFunc status;
+    pFunc count;
+    pFunc checkOccupiedMem;
+
+#ifdef WIN
+    hndl = (void*) LoadLibrary((char const*)"./tests/realtimeGC/shared.dll");
+    status = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"status");
+    count = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"count");
+    checkOccupiedMem = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"checkOccupiedMem");
+#else /* OSX || NIX */
+    hndl = (void*) dlopen((char const*)"./tests/realtimeGC/libshared.so", RTLD_LAZY);
+    status = (pFunc) dlsym(hndl, (char const*)"status");
+    count = (pFunc) dlsym(hndl, (char const*)"count");
+    checkOccupiedMem = (pFunc) dlsym(hndl, (char const*)"checkOccupiedMem");
+#endif
+
+    assert(hndl);
+    assert(status);
+    assert(count);
+    assert(checkOccupiedMem);
+
+    time_t startTime = time((time_t*)0);
+    time_t runTime = (time_t)(RUNTIME);
+    time_t accumTime = 0;
+    while (accumTime < runTime) {
+        for (i = 0; i < 10; i++)
+            count();
+        /* printf("1. sleeping...\n"); */
+        sleep(1);
+        for (i = 0; i < 10; i++)
+            status();
+        /* printf("2. sleeping...\n"); */
+        sleep(1);
+        checkOccupiedMem();
+        accumTime = time((time_t*)0) - startTime;
+        /* printf("--- Minutes left to run: %d\n", (int)(runTime-accumTime)/60); */
+    }
+    printf("Cleaning up the shared object pointer...\n");
+#ifdef WIN
+    FreeLibrary((HMODULE)hndl);
+#else /* OSX || NIX */
+    dlclose(hndl);
+#endif
+    printf("Done\n");
+    return 0;
+}
diff --git a/tests/realtimeGC/main.nim.cfg b/tests/realtimeGC/main.nim.cfg
new file mode 100644
index 000000000..fed4fa471
--- /dev/null
+++ b/tests/realtimeGC/main.nim.cfg
@@ -0,0 +1,6 @@
+
+--app:console
+--threads:on
+
+-d:release
+-d:useRealtimeGC
diff --git a/tests/realtimeGC/nmain.nim b/tests/realtimeGC/nmain.nim
new file mode 100644
index 000000000..c9f558dbc
--- /dev/null
+++ b/tests/realtimeGC/nmain.nim
@@ -0,0 +1,46 @@
+discard """
+  cmd: "nim $target --debuginfo $options $file"
+  output: "Done"
+"""
+
+import times, os, threadpool
+
+const RUNTIME = 15 * 60 # 15 minutes
+
+when defined(windows):
+  const dllname = "./tests/realtimeGC/shared.dll"
+elif defined(macosx):
+  const dllname = "./tests/realtimeGC/libshared.dylib"
+else:
+  const dllname = "./tests/realtimeGC/libshared.so"
+
+proc status() {.importc: "status", dynlib: dllname.}
+proc count() {.importc: "count", dynlib: dllname.}
+proc checkOccupiedMem() {.importc: "checkOccupiedMem", dynlib: dllname.}
+
+proc process() =
+  let startTime = getTime()
+  let runTime = cast[Time](RUNTIME) #
+  var accumTime: Time
+  while accumTime < runTime:
+    for i in 0..10:
+      count()
+    # echo("1. sleeping... ")
+    sleep(500)
+    for i in 0..10:
+      status()
+    # echo("2. sleeping... ")
+    sleep(500)
+    checkOccupiedMem()
+    accumTime = cast[Time]((getTime() - startTime))
+    # echo("--- Minutes left to run: ", int(int(runTime-accumTime)/60))
+
+proc main() =
+  process()
+  # parallel:
+  #   for i in 0..0:
+  #     spawn process()
+  # sync()
+  echo("Done")
+
+main()
diff --git a/tests/realtimeGC/readme.txt b/tests/realtimeGC/readme.txt
new file mode 100644
index 000000000..035a00001
--- /dev/null
+++ b/tests/realtimeGC/readme.txt
@@ -0,0 +1,21 @@
+Test the realtime GC without linking nimrtl.dll/so.

+

+Note, this is a long running test, default is 35 minutes. To change the

+the run time see RUNTIME in main.nim and main.c.

+

+You can build shared.nim, main.nim, and main.c by running make (nix systems)

+or maike.bat (Windows systems). They both assume GCC and that it's in your

+path. Output: shared.(dll/so), camin(.exe), nmain(.exe).

+

+To run the test: execute either nmain or cmain in a shell window.

+

+To build buy hand:

+

+  - build the shared object (shared.nim):

+

+    $ nim c shared.nim

+

+  - build the client executables:

+

+    $ nim c -o:nmain main.nim

+    $ gcc -o cmain main.c -ldl

diff --git a/tests/realtimeGC/shared.nim b/tests/realtimeGC/shared.nim
new file mode 100644
index 000000000..2d1dd6c3c
--- /dev/null
+++ b/tests/realtimeGC/shared.nim
@@ -0,0 +1,63 @@
+discard """
+  cmd: "nim $target --debuginfo --hints:on --app:lib $options $file"
+"""
+
+import strutils
+
+# Global state, accessing with threads, no locks. Don't do this at
+# home.
+var gCounter: uint64
+var gTxStatus: bool
+var gRxStatus: bool
+var gConnectStatus: bool
+var gPttStatus: bool
+var gComm1Status: bool
+var gComm2Status: bool
+
+proc getTxStatus(): string =
+  result = if gTxStatus: "On" else: "Off"
+  gTxStatus = not gTxStatus
+
+proc getRxStatus(): string =
+  result = if gRxStatus: "On" else: "Off"
+  gRxStatus = not gRxStatus
+
+proc getConnectStatus(): string =
+  result = if gConnectStatus: "Yes" else: "No"
+  gConnectStatus = not gConnectStatus
+
+proc getPttStatus(): string =
+  result = if gPttStatus: "PTT: On" else: "PTT: Off"
+  gPttStatus = not gPttStatus
+
+proc getComm1Status(): string =
+  result = if gComm1Status: "On" else: "Off"
+  gComm1Status = not gComm1Status
+
+proc getComm2Status(): string =
+  result = if gComm2Status: "On" else: "Off"
+  gComm2Status = not gComm2Status
+
+proc status() {.exportc: "status", dynlib.} =
+  var tx_status = getTxStatus()
+  var rx_status = getRxStatus()
+  var connected = getConnectStatus()
+  var ptt_status = getPttStatus()
+  var str1: string = "[PilotEdge] Connected: $1  TX: $2  RX: $3" % [connected, tx_status, rx_status]
+  var a = getComm1Status()
+  var b = getComm2Status()
+  var str2: string = "$1  COM1: $2  COM2: $3" % [ptt_status, a, b]
+  # echo(str1)
+  # echo(str2)
+
+proc count() {.exportc: "count", dynlib.} =
+  var temp: uint64
+  for i in 0..100_000:
+    temp += 1
+  gCounter += 1
+  # echo("gCounter: ", gCounter)
+
+proc checkOccupiedMem() {.exportc: "checkOccupiedMem", dynlib.} =
+  if getOccupiedMem() > 10_000_000:
+    quit 1
+  discard
diff --git a/tests/realtimeGC/shared.nim.cfg b/tests/realtimeGC/shared.nim.cfg
new file mode 100644
index 000000000..e153b26fa
--- /dev/null
+++ b/tests/realtimeGC/shared.nim.cfg
@@ -0,0 +1,5 @@
+--app:lib
+--threads:on
+
+-d:release
+-d:useRealtimeGC
diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim
index 07a2421a6..4de1edeee 100644
--- a/tests/testament/categories.nim
+++ b/tests/testament/categories.nim
@@ -138,6 +138,18 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
   test "stackrefleak"
   test "cyclecollector"
 
+proc longGCTests(r: var TResults, cat: Category, options: string) =
+  when defined(windows):
+    let cOptions = "gcc -ldl -DWIN"
+  else:
+    let cOptions = "gcc -ldl"
+
+  var c = initResults()
+  # According to ioTests, this should compile the file
+  testNoSpec c, makeTest("tests/realtimeGC/shared", options, cat, actionCompile)
+  testC r, makeTest("tests/realtimeGC/cmain", cOptions, cat, actionRun)
+  testSpec r, makeTest("tests/realtimeGC/nmain", options & "--threads: on", cat, actionRun)
+
 # ------------------------- threading tests -----------------------------------
 
 proc threadTests(r: var TResults, cat: Category, options: string) =
@@ -340,6 +352,8 @@ proc processCategory(r: var TResults, cat: Category, options: string) =
     dllTests(r, cat, options)
   of "gc":
     gcTests(r, cat, options)
+  of "longgc":
+    longGCTests(r, cat, options)
   of "debugger":
     debuggerTests(r, cat, options)
   of "manyloc":
diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim
index b3e65959a..0308ce940 100644
--- a/tests/testament/tester.nim
+++ b/tests/testament/tester.nim
@@ -89,6 +89,25 @@ proc callCompiler(cmdTemplate, filename, options: string,
   elif suc =~ pegSuccess:
     result.err = reSuccess
 
+proc callCCompiler(cmdTemplate, filename, options: string,
+                  target: TTarget): TSpec =
+  let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target],
+                       "options", options, "file", filename.quoteShell])
+  var p = startProcess(command="gcc", args=c[5.. ^1],
+                       options={poStdErrToStdOut, poUsePath})
+  let outp = p.outputStream
+  var x = newStringOfCap(120)
+  result.nimout = ""
+  result.msg = ""
+  result.file = ""
+  result.outp = ""
+  result.line = -1
+  while outp.readLine(x.TaintedString) or running(p):
+    result.nimout.add(x & "\n")
+  close(p)
+  if p.peekExitCode == 0:
+    result.err = reSuccess
+
 proc initResults: TResults =
   result.total = 0
   result.passed = 0
@@ -257,8 +276,22 @@ proc testNoSpec(r: var TResults, test: TTest) =
   r.addResult(test, "", given.msg, given.err)
   if given.err == reSuccess: inc(r.passed)
 
+proc testC(r: var TResults, test: TTest) =
+  # runs C code. Doesn't support any specs, just goes by exit code.
+  let tname = test.name.addFileExt(".c")
+  inc(r.total)
+  styledEcho "Processing ", fgCyan, extractFilename(tname)
+  var given = callCCompiler(cmdTemplate, test.name & ".c", test.options, test.target)
+  if given.err != reSuccess:
+    r.addResult(test, "", given.msg, given.err)
+  elif test.action == actionRun:
+    let exeFile = changeFileExt(test.name, ExeExt)
+    var (buf, exitCode) = execCmdEx(exeFile, options = {poStdErrToStdOut, poUseShell})
+    if exitCode != 0: given.err = reExitCodesDiffer
+  if given.err == reSuccess: inc(r.passed)
+
 proc makeTest(test, options: string, cat: Category, action = actionCompile,
-              target = targetC): TTest =
+              target = targetC, env: string = ""): TTest =
   # start with 'actionCompile', will be overwritten in the spec:
   result = TTest(cat: cat, name: test, options: options,
                  target: target, action: action)
diff --git a/web/news.txt b/web/news.txt
index 9719fb8d7..22ea03157 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -9,6 +9,10 @@ News
   Changes affecting backwards compatibility
   -----------------------------------------
 
+  - The ``miliseconds`` property of ``times.TimeInterval`` is now ``milliseconds``.
+    Code accessing that property is deprecated and code using ``miliseconds``
+    during object initialization or as a named parameter of ``initInterval()``
+    will need to be updated.
 
   Language Additions
   ------------------
@@ -223,6 +227,7 @@ Library additions
   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.
+- Added sexp.nim to parse and generate sexp.
 
 
 Bugfixes