summary refs log tree commit diff stats
diff options
context:
space:
mode:
-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.nim8
-rw-r--r--compiler/options.nim1
-rw-r--r--compiler/passes.nim6
-rw-r--r--compiler/vm.nim4
-rw-r--r--config/nim.cfg1
-rw-r--r--doc/astspec.txt2
-rw-r--r--doc/lib.txt4
-rw-r--r--doc/manual/threads.txt2
-rw-r--r--doc/spawn.txt2
-rw-r--r--doc/tut1.txt2
-rw-r--r--lib/core/macros.nim6
-rw-r--r--lib/pure/algorithm.nim11
-rw-r--r--lib/pure/asyncdispatch.nim4
-rw-r--r--lib/pure/httpclient.nim16
-rw-r--r--lib/pure/json.nim65
-rw-r--r--lib/pure/net.nim10
-rw-r--r--lib/pure/osproc.nim2
-rw-r--r--lib/pure/rawsockets.nim4
-rw-r--r--lib/pure/scgi.nim2
-rw-r--r--lib/pure/sockets.nim18
-rw-r--r--lib/pure/times.nim17
-rw-r--r--tests/macros/tgettype.nim20
-rw-r--r--web/news.txt5
27 files changed, 177 insertions, 79 deletions
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 3b4aa658d..2c785d118 100644
--- a/compiler/nimsuggest/nimsuggest.nim
+++ b/compiler/nimsuggest/nimsuggest.nim
@@ -119,9 +119,8 @@ proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int) =
   gTrackPos = newLineInfo(dirtyIdx, line, col)
   gErrorCounter = 0
   if not isKnownFile:
-    compileProject(dirtyIdx)
-  else:
     compileProject()
+  compileProject(dirtyIdx)
 
 proc executeEPC(cmd: IdeCmd, args: SexpNode) =
   let
@@ -192,8 +191,6 @@ proc parseCmdLine(cmd: string) =
   execute(gIdeCmd, orig, dirtyfile, line, col-1)
 
 proc serve() =
-  # do not stop after the first error:
-  msgs.gErrorMax = high(int)
   case gMode:
   of mstdin:
     echo Help
@@ -278,6 +275,9 @@ 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) =
diff --git a/compiler/options.nim b/compiler/options.nim
index d07342fce..b3060a180 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -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)
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/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/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 11380f757..f2b79a34f 100644
--- a/doc/manual/threads.txt
+++ b/doc/manual/threads.txt
@@ -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 cf27ac788..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
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/pure/algorithm.nim b/lib/pure/algorithm.nim
index 352b177e2..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
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/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/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/osproc.nim b/lib/pure/osproc.nim
index 8150f902a..dc6f21174 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -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/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/times.nim b/lib/pure/times.nim
index 1b9fa4599..b8836c15b 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -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.
@@ -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/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/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