summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/packages/fsmonitor.nim229
-rw-r--r--lib/pure/htmlparser.nim3
-rw-r--r--lib/pure/ioselects/ioselectors_epoll.nim8
-rw-r--r--lib/pure/logging.nim11
-rw-r--r--lib/pure/math.nim54
-rw-r--r--lib/pure/parsesql.nim25
-rw-r--r--lib/pure/parsexml.nim28
-rw-r--r--lib/pure/strscans.nim7
-rw-r--r--lib/pure/strutils.nim2
-rw-r--r--lib/pure/sugar.nim5
-rw-r--r--lib/system.nim72
-rw-r--r--lib/system/excpt.nim10
12 files changed, 165 insertions, 289 deletions
diff --git a/lib/packages/fsmonitor.nim b/lib/packages/fsmonitor.nim
deleted file mode 100644
index 89fad4d42..000000000
--- a/lib/packages/fsmonitor.nim
+++ /dev/null
@@ -1,229 +0,0 @@
-#
-#
-#            Nim's Runtime Library
-#        (c) Copyright 2012 Dominik Picheta
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This module allows you to monitor files or directories for changes using
-## asyncio.
-##
-## **Warning**: This module will likely disappear soon and be moved into a
-## new Nimble package.
-##
-## Windows support is not yet implemented.
-##
-## **Note:** This module uses ``inotify`` on Linux (Other Unixes are not yet
-## supported). ``inotify`` was merged into the 2.6.13 Linux kernel, this
-## module will therefore not work with any Linux kernel prior to that, unless
-## it has been patched to support inotify.
-
-when defined(linux) or defined(nimdoc):
-  from posix import read
-else:
-  {.error: "Your platform is not supported.".}
-
-import inotify, os, asyncio, tables
-
-type
-  FSMonitor* = ref FSMonitorObj
-  FSMonitorObj = object of RootObj
-    fd: cint
-    handleEvent: proc (m: FSMonitor, ev: MonitorEvent) {.closure.}
-    targets: Table[cint, string]
-
-  MonitorEventType* = enum ## Monitor event type
-    MonitorAccess,       ## File was accessed.
-    MonitorAttrib,       ## Metadata changed.
-    MonitorCloseWrite,   ## Writable file was closed.
-    MonitorCloseNoWrite, ## Non-writable file closed.
-    MonitorCreate,       ## Subfile was created.
-    MonitorDelete,       ## Subfile was deleted.
-    MonitorDeleteSelf,   ## Watched file/directory was itself deleted.
-    MonitorModify,       ## File was modified.
-    MonitorMoveSelf,     ## Self was moved.
-    MonitorMoved,        ## File was moved.
-    MonitorOpen,         ## File was opened.
-    MonitorAll           ## Filter for all event types.
-
-  MonitorEvent* = object
-    case kind*: MonitorEventType  ## Type of the event.
-    of MonitorMoveSelf, MonitorMoved:
-      oldPath*: string          ## Old absolute location
-      newPath*: string          ## New absolute location
-    else:
-      fullname*: string         ## Absolute filename of the file/directory affected.
-    name*: string             ## Non absolute filepath of the file/directory
-                              ## affected relative to the directory watched.
-                              ## "" if this event refers to the file/directory
-                              ## watched.
-    wd*: cint                 ## Watch descriptor.
-
-{.deprecated: [PFSMonitor: FSMonitor, TFSMonitor: FSMonitorObj,
-  TMonitorEventType: MonitorEventType, TMonitorEvent: MonitorEvent].}
-
-const
-  MaxEvents = 100
-
-proc newMonitor*(): FSMonitor =
-  ## Creates a new file system monitor.
-  new(result)
-  result.targets = initTable[cint, string]()
-  result.fd = inotifyInit()
-  if result.fd < 0:
-    raiseOSError(osLastError())
-
-proc add*(monitor: FSMonitor, target: string,
-               filters = {MonitorAll}): cint {.discardable.} =
-  ## Adds ``target`` which may be a directory or a file to the list of
-  ## watched paths of ``monitor``.
-  ## You can specify the events to report using the ``filters`` parameter.
-
-  var INFilter = 0
-  for f in filters:
-    case f
-    of MonitorAccess: INFilter = INFilter or IN_ACCESS
-    of MonitorAttrib: INFilter = INFilter or IN_ATTRIB
-    of MonitorCloseWrite: INFilter = INFilter or IN_CLOSE_WRITE
-    of MonitorCloseNoWrite: INFilter = INFilter or IN_CLOSE_NO_WRITE
-    of MonitorCreate: INFilter = INFilter or IN_CREATE
-    of MonitorDelete: INFilter = INFilter or IN_DELETE
-    of MonitorDeleteSelf: INFilter = INFilter or IN_DELETE_SELF
-    of MonitorModify: INFilter = INFilter or IN_MODIFY
-    of MonitorMoveSelf: INFilter = INFilter or IN_MOVE_SELF
-    of MonitorMoved: INFilter = INFilter or IN_MOVED_FROM or IN_MOVED_TO
-    of MonitorOpen: INFilter = INFilter or IN_OPEN
-    of MonitorAll: INFilter = INFilter or IN_ALL_EVENTS
-
-  result = inotifyAddWatch(monitor.fd, target, INFilter.uint32)
-  if result < 0:
-    raiseOSError(osLastError())
-  monitor.targets.add(result, target)
-
-proc del*(monitor: FSMonitor, wd: cint) =
-  ## Removes watched directory or file as specified by ``wd`` from ``monitor``.
-  ##
-  ## If ``wd`` is not a part of ``monitor`` an OSError error is raised.
-  if inotifyRmWatch(monitor.fd, wd) < 0:
-    raiseOSError(osLastError())
-
-proc getEvent(m: FSMonitor, fd: cint): seq[MonitorEvent] =
-  result = @[]
-  let size = (sizeof(INotifyEvent)+2000)*MaxEvents
-  var buffer = newString(size)
-
-  let le = read(fd, addr(buffer[0]), size)
-
-  var movedFrom = initTable[cint, tuple[wd: cint, old: string]]()
-
-  var i = 0
-  while i < le:
-    var event = cast[ptr INotifyEvent](addr(buffer[i]))
-    var mev: MonitorEvent
-    mev.wd = event.wd
-    if event.len.int != 0:
-      let cstr = event.name.addr.cstring
-      mev.name = $cstr
-    else:
-      mev.name = ""
-
-    if (event.mask.int and IN_MOVED_FROM) != 0:
-      # Moved from event, add to m's collection
-      movedFrom.add(event.cookie.cint, (mev.wd, mev.name))
-      inc(i, sizeof(INotifyEvent) + event.len.int)
-      continue
-    elif (event.mask.int and IN_MOVED_TO) != 0:
-      mev.kind = MonitorMoved
-      assert movedFrom.hasKey(event.cookie.cint)
-      # Find the MovedFrom event.
-      mev.oldPath = movedFrom[event.cookie.cint].old
-      mev.newPath = "" # Set later
-      # Delete it from the Table
-      movedFrom.del(event.cookie.cint)
-    elif (event.mask.int and IN_ACCESS) != 0: mev.kind = MonitorAccess
-    elif (event.mask.int and IN_ATTRIB) != 0: mev.kind = MonitorAttrib
-    elif (event.mask.int and IN_CLOSE_WRITE) != 0:
-      mev.kind = MonitorCloseWrite
-    elif (event.mask.int and IN_CLOSE_NOWRITE) != 0:
-      mev.kind = MonitorCloseNoWrite
-    elif (event.mask.int and IN_CREATE) != 0: mev.kind = MonitorCreate
-    elif (event.mask.int and IN_DELETE) != 0:
-      mev.kind = MonitorDelete
-    elif (event.mask.int and IN_DELETE_SELF) != 0:
-      mev.kind = MonitorDeleteSelf
-    elif (event.mask.int and IN_MODIFY) != 0: mev.kind = MonitorModify
-    elif (event.mask.int and IN_MOVE_SELF) != 0:
-      mev.kind = MonitorMoveSelf
-    elif (event.mask.int and IN_OPEN) != 0: mev.kind = MonitorOpen
-
-    if mev.kind != MonitorMoved:
-      mev.fullname = ""
-
-    result.add(mev)
-    inc(i, sizeof(INotifyEvent) + event.len.int)
-
-  # If movedFrom events have not been matched with a moveTo. File has
-  # been moved to an unwatched location, emit a MonitorDelete.
-  for cookie, t in pairs(movedFrom):
-    var mev: MonitorEvent
-    mev.kind = MonitorDelete
-    mev.wd = t.wd
-    mev.name = t.old
-    result.add(mev)
-
-proc FSMonitorRead(h: RootRef) =
-  var events = FSMonitor(h).getEvent(FSMonitor(h).fd)
-  #var newEv: MonitorEvent
-  for ev in events:
-    var target = FSMonitor(h).targets[ev.wd]
-    var newEv = ev
-    if newEv.kind == MonitorMoved:
-      newEv.oldPath = target / newEv.oldPath
-      newEv.newPath = target / newEv.name
-    else:
-      newEv.fullName = target / newEv.name
-    FSMonitor(h).handleEvent(FSMonitor(h), newEv)
-
-proc toDelegate(m: FSMonitor): Delegate =
-  result = newDelegate()
-  result.deleVal = m
-  result.fd = (type(result.fd))(m.fd)
-  result.mode = fmRead
-  result.handleRead = FSMonitorRead
-  result.open = true
-
-proc register*(d: Dispatcher, monitor: FSMonitor,
-               handleEvent: proc (m: FSMonitor, ev: MonitorEvent) {.closure.}) =
-  ## Registers ``monitor`` with dispatcher ``d``.
-  monitor.handleEvent = handleEvent
-  var deleg = toDelegate(monitor)
-  d.register(deleg)
-
-when not defined(testing) and isMainModule:
-  proc main =
-    var
-      disp = newDispatcher()
-      monitor = newMonitor()
-      n = 0
-    n = monitor.add("/tmp")
-    assert n == 1
-    n = monitor.add("/tmp", {MonitorAll})
-    assert n == 1
-    n = monitor.add("/tmp", {MonitorCloseWrite, MonitorCloseNoWrite})
-    assert n == 1
-    n = monitor.add("/tmp", {MonitorMoved, MonitorOpen, MonitorAccess})
-    assert n == 1
-    disp.register(monitor,
-      proc (m: FSMonitor, ev: MonitorEvent) =
-        echo("Got event: ", ev.kind)
-        if ev.kind == MonitorMoved:
-          echo("From ", ev.oldPath, " to ", ev.newPath)
-          echo("Name is ", ev.name)
-        else:
-          echo("Name ", ev.name, " fullname ", ev.fullName))
-
-    while true:
-      if not disp.poll(): break
-  main()
diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim
index fbf2b8e73..2d24050f2 100644
--- a/lib/pure/htmlparser.nim
+++ b/lib/pure/htmlparser.nim
@@ -2014,7 +2014,8 @@ proc parseHtml*(s: Stream, filename: string,
   ## Parses the XML from stream `s` and returns a ``XmlNode``. Every
   ## occurred parsing error is added to the `errors` sequence.
   var x: XmlParser
-  open(x, s, filename, {reportComments, reportWhitespace})
+  open(x, s, filename, {reportComments, reportWhitespace, allowUnquotedAttribs,
+    allowEmptyAttribs})
   next(x)
   # skip the DOCTYPE:
   if x.kind == xmlSpecial: next(x)
diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim
index 8b3f14f34..16d901ff0 100644
--- a/lib/pure/ioselects/ioselectors_epoll.nim
+++ b/lib/pure/ioselects/ioselectors_epoll.nim
@@ -383,14 +383,14 @@ proc selectInto*[T](s: Selector[T], timeout: int,
 
       if (pevents and EPOLLERR) != 0 or (pevents and EPOLLHUP) != 0:
         if (pevents and EPOLLHUP) != 0:
-          rkey.errorCode = ECONNRESET.OSErrorCode
+          rkey.errorCode = OSErrorCode ECONNRESET
         else:
           # Try reading SO_ERROR from fd.
           var error: cint
-          var size = sizeof(error).SockLen
-          if getsockopt(fdi.SocketHandle, SOL_SOCKET, SO_ERROR, addr(error),
+          var size = SockLen sizeof(error)
+          if getsockopt(SocketHandle fdi, SOL_SOCKET, SO_ERROR, addr(error),
                         addr(size)) == 0'i32:
-            rkey.errorCode = error.OSErrorCode
+            rkey.errorCode = OSErrorCode error
 
         rkey.events.incl(Event.Error)
       if (pevents and EPOLLOUT) != 0:
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
index f2f5cac9e..cd13deec3 100644
--- a/lib/pure/logging.nim
+++ b/lib/pure/logging.nim
@@ -80,6 +80,7 @@ type
 
   ConsoleLogger* = ref object of Logger ## logger that writes the messages to the
                                         ## console
+    useStderr*: bool ## will send logs into Stderr if set 
 
 when not defined(js):
   type
@@ -150,16 +151,20 @@ method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) =
       {.emit: "console.log(`cln`);".}
     else:
       try:
-        writeLine(stdout, ln)
-        if level in {lvlError, lvlFatal}: flushFile(stdout)
+        var handle = stdout
+        if logger.useStderr:
+          handle = stderr 
+        writeLine(handle, ln)
+        if level in {lvlError, lvlFatal}: flushFile(handle)
       except IOError:
         discard
 
-proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): ConsoleLogger =
+proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr, useStderr=false): ConsoleLogger =
   ## Creates a new console logger. This logger logs to the console.
   new result
   result.fmtStr = fmtStr
   result.levelThreshold = levelThreshold
+  result.useStderr = useStderr
 
 when not defined(js):
   method log*(logger: FileLogger, level: Level, args: varargs[string, `$`]) =
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index f04cb5050..e2ad626de 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -168,16 +168,19 @@ when not defined(JS): # C
   proc sqrt*(x: float32): float32 {.importc: "sqrtf", header: "<math.h>".}
   proc sqrt*(x: float64): float64 {.importc: "sqrt", header: "<math.h>".}
     ## Computes the square root of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo sqrt(1.44) ## 1.2
   proc cbrt*(x: float32): float32 {.importc: "cbrtf", header: "<math.h>".}
   proc cbrt*(x: float64): float64 {.importc: "cbrt", header: "<math.h>".}
     ## Computes the cubic root of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo cbrt(2.197) ## 1.3
   proc ln*(x: float32): float32 {.importc: "logf", header: "<math.h>".}
   proc ln*(x: float64): float64 {.importc: "log", header: "<math.h>".}
     ## Computes the `natural logarithm <https://en.wikipedia.org/wiki/Natural_logarithm>`_ of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo ln(exp(4.0)) ## 4.0
 else: # JS
@@ -189,6 +192,7 @@ else: # JS
 
 proc log*[T: SomeFloat](x, base: T): T =
   ## Computes the logarithm of ``x`` to base ``base``.
+  ##
   ## .. code-block:: nim
   ##  echo log(9.0, 3.0) ## 2.0
   ln(x) / ln(base)
@@ -197,51 +201,60 @@ when not defined(JS): # C
   proc log10*(x: float32): float32 {.importc: "log10f", header: "<math.h>".}
   proc log10*(x: float64): float64 {.importc: "log10", header: "<math.h>".}
     ## Computes the common logarithm (base 10) of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo log10(100.0) ## 2.0
   proc exp*(x: float32): float32 {.importc: "expf", header: "<math.h>".}
   proc exp*(x: float64): float64 {.importc: "exp", header: "<math.h>".}
     ## Computes the exponential function of ``x`` (pow(E, x)).
+    ##
     ## .. code-block:: nim
     ##  echo exp(1.0) ## 2.718281828459045
     ##  echo ln(exp(4.0)) ## 4.0
   proc sin*(x: float32): float32 {.importc: "sinf", header: "<math.h>".}
   proc sin*(x: float64): float64 {.importc: "sin", header: "<math.h>".}
     ## Computes the sine of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo sin(PI / 6) ## 0.4999999999999999
     ##  echo sin(degToRad(90.0)) ## 1.0
   proc cos*(x: float32): float32 {.importc: "cosf", header: "<math.h>".}
   proc cos*(x: float64): float64 {.importc: "cos", header: "<math.h>".}
     ## Computes the cosine of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo cos(2 * PI) ## 1.0
     ##  echo cos(degToRad(60.0)) ## 0.5000000000000001
   proc tan*(x: float32): float32 {.importc: "tanf", header: "<math.h>".}
   proc tan*(x: float64): float64 {.importc: "tan", header: "<math.h>".}
     ## Computes the tangent of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo tan(degToRad(45.0)) ## 0.9999999999999999
     ##  echo tan(PI / 4) ## 0.9999999999999999
   proc sinh*(x: float32): float32 {.importc: "sinhf", header: "<math.h>".}
   proc sinh*(x: float64): float64 {.importc: "sinh", header: "<math.h>".}
     ## Computes the `hyperbolic sine <https://en.wikipedia.org/wiki/Hyperbolic_function#Definitions>`_ of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo sinh(1.0) ## 1.175201193643801
   proc cosh*(x: float32): float32 {.importc: "coshf", header: "<math.h>".}
   proc cosh*(x: float64): float64 {.importc: "cosh", header: "<math.h>".}
     ## Computes the `hyperbolic cosine <https://en.wikipedia.org/wiki/Hyperbolic_function#Definitions>`_ of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo cosh(1.0) ## 1.543080634815244
   proc tanh*(x: float32): float32 {.importc: "tanhf", header: "<math.h>".}
   proc tanh*(x: float64): float64 {.importc: "tanh", header: "<math.h>".}
     ## Computes the `hyperbolic tangent <https://en.wikipedia.org/wiki/Hyperbolic_function#Definitions>`_ of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo tanh(1.0) ## 0.7615941559557649
 
   proc arccos*(x: float32): float32 {.importc: "acosf", header: "<math.h>".}
   proc arccos*(x: float64): float64 {.importc: "acos", header: "<math.h>".}
     ## Computes the arc cosine of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo arccos(1.0) ## 0.0
   proc arcsin*(x: float32): float32 {.importc: "asinf", header: "<math.h>".}
@@ -250,6 +263,7 @@ when not defined(JS): # C
   proc arctan*(x: float32): float32 {.importc: "atanf", header: "<math.h>".}
   proc arctan*(x: float64): float64 {.importc: "atan", header: "<math.h>".}
     ## Calculate the arc tangent of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo arctan(1.0) ## 0.7853981633974483
     ##  echo radToDeg(arctan(1.0)) ## 45.0
@@ -259,6 +273,7 @@ when not defined(JS): # C
     ## `arctan2` returns the arc tangent of ``y`` / ``x``; it produces correct
     ## results even when the resulting angle is near pi/2 or -pi/2
     ## (``x`` near 0).
+    ##
     ## .. code-block:: nim
     ##  echo arctan2(1.0, 0.0) ## 1.570796326794897
     ##  echo radToDeg(arctan2(1.0, 0.0)) ## 90.0
@@ -332,6 +347,7 @@ when not defined(JS): # C
   proc hypot*(x, y: float64): float64 {.importc: "hypot", header: "<math.h>".}
     ## Computes the hypotenuse of a right-angle triangle with ``x`` and
     ## ``y`` as its base and height. Equivalent to ``sqrt(x*x + y*y)``.
+    ##
     ## .. code-block:: nim
     ##  echo hypot(4.0, 3.0) ## 5.0
   proc pow*(x, y: float32): float32 {.importc: "powf", header: "<math.h>".}
@@ -339,6 +355,7 @@ when not defined(JS): # C
     ## computes x to power raised of y.
     ##
     ## To compute power between integers, use ``^`` e.g. 2 ^ 6
+    ##
     ## .. code-block:: nim
     ##  echo pow(16.0, 0.5) ## 4.0
 
@@ -361,7 +378,7 @@ when not defined(JS): # C
       ## **Deprecated since version 0.19.0**: Use ``gamma`` instead.
     proc lgamma*(x: float32): float32 {.importc: "lgammaf", header: "<math.h>".}
     proc lgamma*(x: float64): float64 {.importc: "lgamma", header: "<math.h>".}
-      ## Computes the natural log of the gamma function for ``x``. 
+      ## Computes the natural log of the gamma function for ``x``.
 
   proc floor*(x: float32): float32 {.importc: "floorf", header: "<math.h>".}
   proc floor*(x: float64): float64 {.importc: "floor", header: "<math.h>".}
@@ -456,7 +473,11 @@ when not defined(JS): # C
     ## Computes the modulo operation for float values (the remainder of ``x`` divided by ``y``).
     ##
     ## .. code-block:: nim
-    ##  echo 2.5 mod 0.3 ## 0.1
+    ##  ( 6.5 mod  2.5) ==  1.5
+    ##  (-6.5 mod  2.5) == -1.5
+    ##  ( 6.5 mod -2.5) ==  1.5
+    ##  (-6.5 mod -2.5) == -1.5
+
 else: # JS
   proc hypot*[T: float32|float64](x, y: T): T = return sqrt(x*x + y*y)
   proc pow*(x, y: float32): float32 {.importC: "Math.pow", nodecl.}
@@ -474,7 +495,10 @@ else: # JS
     ## Computes the modulo operation for float values (the remainder of ``x`` divided by ``y``).
     ##
     ## .. code-block:: nim
-    ##  echo 2.5 mod 0.3 ## 0.1
+    ##  ( 6.5 mod  2.5) ==  1.5
+    ##  (-6.5 mod  2.5) == -1.5
+    ##  ( 6.5 mod -2.5) ==  1.5
+    ##  (-6.5 mod -2.5) == -1.5
 
 proc round*[T: float32|float64](x: T, places: int): T {.deprecated: "use format instead".} =
   ## Decimal rounding on a binary floating point number.
@@ -498,19 +522,25 @@ proc floorDiv*[T: SomeInteger](x, y: T): T =
   ## This is different from the ``div`` operator, which is defined
   ## as ``trunc(x / y)``. That is, ``div`` rounds towards ``0`` and ``floorDiv``
   ## rounds down.
+  ##
   ## .. code-block:: nim
-  ##  echo floorDiv(13, 3) # 4
-  ##  echo floorDiv(-13, 3) # -5
+  ##  echo floorDiv( 13,  3) #  4
+  ##  echo floorDiv(-13,  3) # -5
+  ##  echo floorDiv( 13, -3) # -5
+  ##  echo floorDiv(-13, -3) #  4
   result = x div y
   let r = x mod y
   if (r > 0 and y < 0) or (r < 0 and y > 0): result.dec 1
 
 proc floorMod*[T: SomeNumber](x, y: T): T =
-  ## Floor modulus is conceptually defined as ``x - (floorDiv(x, y) * y).
+  ## Floor modulus is conceptually defined as ``x - (floorDiv(x, y) * y)``.
   ## This proc behaves the same as the ``%`` operator in Python.
+  ##
   ## .. code-block:: nim
-  ##  echo floorMod(13, 3) # 1
-  ##  echo floorMod(-13, 3) # 2
+  ##  echo floorMod( 13,  3) #  1
+  ##  echo floorMod(-13,  3) #  2
+  ##  echo floorMod( 13, -3) # -2
+  ##  echo floorMod(-13, -3) # -1
   result = x mod y
   if (result > 0 and y < 0) or (result < 0 and y > 0): result += y
 
@@ -525,6 +555,7 @@ when not defined(JS):
     ## and less than 1) and the integer value n such that ``x`` (the original
     ## float value) equals ``m * 2**n``. frexp stores n in `exponent` and returns
     ## m.
+    ##
     ## .. code-block:: nim
     ##  var x : int
     ##  echo frexp(5.0, x) # 0.625
@@ -579,6 +610,7 @@ proc splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] =
   ##
   ## Both parts have the same sign as ``x``.  Analogous to the ``modf``
   ## function in C.
+  ##
   ## .. code-block:: nim
   ##  echo splitDecimal(5.25) # (intpart: 5.0, floatpart: 0.25)
   var
@@ -594,12 +626,14 @@ proc splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] =
 
 proc degToRad*[T: float32|float64](d: T): T {.inline.} =
   ## Convert from degrees to radians
+  ##
   ## .. code-block:: nim
   ##  echo degToRad(180.0) # 3.141592653589793
   result = T(d) * RadPerDeg
 
 proc radToDeg*[T: float32|float64](d: T): T {.inline.} =
   ## Convert from radians to degrees
+
   ## .. code-block:: nim
   ##  echo degToRad(2 * PI) # 360.0
   result = T(d) / RadPerDeg
@@ -608,6 +642,7 @@ proc sgn*[T: SomeNumber](x: T): int {.inline.} =
   ## Sign function. Returns -1 for negative numbers and ``NegInf``, 1 for
   ## positive numbers and ``Inf``, and 0 for positive zero, negative zero and
   ## ``NaN``.
+  ##
   ## .. code-block:: nim
   ##  echo sgn(-5) # 1
   ##  echo sgn(-4.1) # -1
@@ -619,6 +654,7 @@ proc sgn*[T: SomeNumber](x: T): int {.inline.} =
 proc `^`*[T](x: T, y: Natural): T =
   ## Computes ``x`` to the power ``y``. ``x`` must be non-negative, use
   ## `pow <#pow,float,float>`_ for negative exponents.
+  ##
   ## .. code-block:: nim
   ##  echo 2 ^ 3 # 8
   when compiles(y >= T(0)):
@@ -650,6 +686,7 @@ proc gcd*[T](x, y: T): T =
 proc gcd*(x, y: SomeInteger): SomeInteger =
   ## Computes the greatest common (positive) divisor of ``x`` and ``y``.
   ## Using binary GCD (aka Stein's) algorithm.
+  ##
   ## .. code-block:: nim
   ##  echo gcd(24, 30) # 6
   when x is SomeSignedInt:
@@ -677,6 +714,7 @@ proc gcd*(x, y: SomeInteger): SomeInteger =
 
 proc lcm*[T](x, y: T): T =
   ## Computes the least common multiple of ``x`` and ``y``.
+  ##
   ## .. code-block:: nim
   ##  echo lcm(24, 30) # 120
   x div gcd(x, y) * y
diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim
index 9aef43c1b..4b841b9e1 100644
--- a/lib/pure/parsesql.nim
+++ b/lib/pure/parsesql.nim
@@ -566,7 +566,6 @@ type
   SqlParser* = object of SqlLexer ## SQL parser object
     tok: Token
 
-
 {.deprecated: [EInvalidSql: SqlParseError, PSqlNode: SqlNode,
     TSqlNode: SqlNodeObj, TSqlParser: SqlParser, TSqlNodeKind: SqlNodeKind].}
 
@@ -591,6 +590,7 @@ proc len*(n: SqlNode): int =
     result = n.sons.len
 
 proc `[]`*(n: SqlNode; i: int): SqlNode = n.sons[i]
+proc `[]`*(n: SqlNode; i: BackwardsIndex): SqlNode = n.sons[n.len - int(i)]
 
 proc add*(father, n: SqlNode) =
   add(father.sons, n)
@@ -674,7 +674,7 @@ proc getPrecedence(p: SqlParser): int =
     result = 5
   elif isOpr(p, "=") or isOpr(p, "<") or isOpr(p, ">") or isOpr(p, ">=") or
        isOpr(p, "<=") or isOpr(p, "<>") or isOpr(p, "!=") or isKeyw(p, "is") or
-       isKeyw(p, "like"):
+       isKeyw(p, "like") or isKeyw(p, "in"):
     result = 4
   elif isKeyw(p, "and"):
     result = 3
@@ -717,7 +717,10 @@ proc identOrLiteral(p: var SqlParser): SqlNode =
   of tkParLe:
     getTok(p)
     result = newNode(nkPrGroup)
-    result.add(parseExpr(p))
+    while true:
+      result.add(parseExpr(p))
+      if p.tok.kind != tkComma: break
+      getTok(p)
     eat(p, tkParRi)
   else:
     if p.tok.literal == "*":
@@ -1465,6 +1468,22 @@ proc `$`*(n: SqlNode): string =
   ## an alias for `renderSQL`.
   renderSQL(n)
 
+proc treeReprAux(s: SqlNode, level: int, result: var string) =
+  result.add('\n')
+  for i in 0 ..< level: result.add("  ")
+
+  result.add($s.kind)
+  if s.kind in LiteralNodes:
+    result.add(' ')
+    result.add(s.strVal)
+  else:
+    for son in s.sons:
+      treeReprAux(son, level + 1, result)
+
+proc treeRepr*(s: SqlNode): string =
+  result = newStringOfCap(128)
+  treeReprAux(s, 0, result)
+
 when not defined(js):
   import streams
 
diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim
index d8d5a7a2d..0967f7983 100644
--- a/lib/pure/parsexml.nim
+++ b/lib/pure/parsexml.nim
@@ -180,6 +180,7 @@ type
     errEqExpected,           ## ``=`` expected
     errQuoteExpected,        ## ``"`` or ``'`` expected
     errEndOfCommentExpected  ## ``-->`` expected
+    errAttributeValueExpected ## non-empty attribute value expected
 
   ParserState = enum
     stateStart, stateNormal, stateAttr, stateEmptyElementTag, stateError
@@ -187,6 +188,8 @@ type
   XmlParseOption* = enum  ## options for the XML parser
     reportWhitespace,      ## report whitespace
     reportComments         ## report comments
+    allowUnquotedAttribs   ## allow unquoted attribute values (for HTML)
+    allowEmptyAttribs      ## allow empty attributes (without explicit value)
 
   XmlParser* = object of BaseLexer ## the parser object.
     a, b, c: string
@@ -207,7 +210,8 @@ const
     "'>' expected",
     "'=' expected",
     "'\"' or \"'\" expected",
-    "'-->' expected"
+    "'-->' expected",
+    "attribute value expected"
   ]
 
 proc open*(my: var XmlParser, input: Stream, filename: string,
@@ -618,10 +622,15 @@ proc parseAttribute(my: var XmlParser) =
   if my.a.len == 0:
     markError(my, errGtExpected)
     return
+
+  let startPos = my.bufpos
   parseWhitespace(my, skip=true)
   if my.buf[my.bufpos] != '=':
-    markError(my, errEqExpected)
+    if allowEmptyAttribs notin my.options or
+        (my.buf[my.bufpos] != '>' and my.bufpos == startPos):
+      markError(my, errEqExpected)
     return
+
   inc(my.bufpos)
   parseWhitespace(my, skip=true)
 
@@ -669,6 +678,21 @@ proc parseAttribute(my: var XmlParser) =
             pendingSpace = false
           add(my.b, buf[pos])
           inc(pos)
+  elif allowUnquotedAttribs in my.options:
+    const disallowedChars = {'"', '\'', '`', '=', '<', '>', ' ',
+                             '\0', '\t', '\L', '\F', '\f'}
+    let startPos = pos
+    while (let c = buf[pos]; c notin disallowedChars):
+      if c == '&':
+        my.bufpos = pos
+        parseEntity(my, my.b)
+        my.kind = xmlAttribute # parseEntity overwrites my.kind!
+        pos = my.bufpos
+      else:
+        add(my.b, c)
+        inc(pos)
+    if pos == startPos:
+      markError(my, errAttributeValueExpected)
   else:
     markError(my, errQuoteExpected)
     # error corrections: guess what was meant
diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim
index 77763ff43..c1c535e55 100644
--- a/lib/pure/strscans.nim
+++ b/lib/pure/strscans.nim
@@ -129,7 +129,7 @@ to use prefix instead of postfix operators.
 ``+E``           One or more
 ``?E``           Zero or One
 ``E{n,m}``       From ``n`` up to ``m`` times ``E``
-``~Ε``           Not predicate
+``~E``           Not predicate
 ``a ^* b``       Shortcut for ``?(a *(b a))``. Usually used for separators.
 ``a ^* b``       Shortcut for ``?(a +(b a))``. Usually used for separators.
 ``'a'``          Matches a single character
@@ -456,10 +456,11 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
 
 template atom*(input: string; idx: int; c: char): bool =
   ## Used in scanp for the matching of atoms (usually chars).
-  idx < input.len and input[idx] == c
+  ## EOF is matched as ``'\0'``.
+  (idx < input.len and input[idx] == c) or (idx == input.len and c == '\0')
 
 template atom*(input: string; idx: int; s: set[char]): bool =
-  idx < input.len and input[idx] in s
+  (idx < input.len and input[idx] in s) or (idx == input.len and '\0' in s)
 
 template hasNxt*(input: string; idx: int): bool = idx < input.len
 
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 82c6dc8b9..e266275cf 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -909,7 +909,7 @@ proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect,
 proc toHex*[T: SomeInteger](x: T): string =
   ## Shortcut for ``toHex(x, T.sizeOf * 2)``
   runnableExamples:
-    doAssert toHex(1984) == "00000000000007C0"
+    doAssert toHex(1984'i64) == "00000000000007C0"
   toHex(BiggestInt(x), T.sizeOf * 2)
 
 proc toHex*(s: string): string {.noSideEffect, rtl.} =
diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim
index 8ded552d9..53c31e8c9 100644
--- a/lib/pure/sugar.nim
+++ b/lib/pure/sugar.nim
@@ -125,6 +125,8 @@ macro `->`*(p, b: untyped): untyped =
 type ListComprehension = object
 var lc*: ListComprehension
 
+template `|`*(lc: ListComprehension, comp: untyped): untyped = lc
+
 macro `[]`*(lc: ListComprehension, comp, typ: untyped): untyped =
   ## List comprehension, returns a sequence. `comp` is the actual list
   ## comprehension, for example ``x | (x <- 1..10, x mod 2 == 0)``. `typ` is
@@ -140,8 +142,7 @@ macro `[]`*(lc: ListComprehension, comp, typ: untyped): untyped =
 
   expectLen(comp, 3)
   expectKind(comp, nnkInfix)
-  expectKind(comp[0], nnkIdent)
-  assert($comp[0].ident == "|")
+  assert($comp[0] == "|")
 
   result = newCall(
     newDotExpr(
diff --git a/lib/system.nim b/lib/system.nim
index f852a0aed..2c2783dfb 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -203,23 +203,6 @@ proc `or`*(x, y: bool): bool {.magic: "Or", noSideEffect.}
 proc `xor`*(x, y: bool): bool {.magic: "Xor", noSideEffect.}
   ## Boolean `exclusive or`; returns true iff ``x != y``.
 
-proc new*[T](a: var ref T) {.magic: "New", noSideEffect.}
-  ## creates a new object of type ``T`` and returns a safe (traced)
-  ## reference to it in ``a``.
-
-proc new*(T: typedesc): auto =
-  ## creates a new object of type ``T`` and returns a safe (traced)
-  ## reference to it as result value.
-  ##
-  ## When ``T`` is a ref type then the resulting type will be ``T``,
-  ## otherwise it will be ``ref T``.
-  when (T is ref):
-    var r: T
-  else:
-    var r: ref T
-  new(r)
-  return r
-
 const ThisIsSystem = true
 
 proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.}
@@ -1001,10 +984,13 @@ proc `div`*(x, y: int32): int32 {.magic: "DivI", noSideEffect.}
   ## ``trunc(x/y)``.
   ##
   ## .. code-block:: Nim
-  ##   1 div 2 == 0
-  ##   2 div 2 == 1
-  ##   3 div 2 == 1
-  ##   7 div 5 == 1
+  ##   ( 1 div  2) ==  0
+  ##   ( 2 div  2) ==  1
+  ##   ( 3 div  2) ==  1
+  ##   ( 7 div  3) ==  2
+  ##   (-7 div  3) == -2
+  ##   ( 7 div -3) == -2
+  ##   (-7 div -3) ==  2
 
 when defined(nimnomagic64):
   proc `div`*(x, y: int64): int64 {.magic: "DivI", noSideEffect.}
@@ -1020,7 +1006,10 @@ proc `mod`*(x, y: int32): int32 {.magic: "ModI", noSideEffect.}
   ## ``x - (x div y) * y``.
   ##
   ## .. code-block:: Nim
-  ##   (7 mod 5) == 2
+  ##   ( 7 mod  5) ==  2
+  ##   (-7 mod  5) == -2
+  ##   ( 7 mod -5) ==  2
+  ##   (-7 mod -5) == -2
 
 when defined(nimnomagic64):
   proc `mod`*(x, y: int64): int64 {.magic: "ModI", noSideEffect.}
@@ -1325,6 +1314,23 @@ proc `is`*[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
 template `isnot`*(x, y: untyped): untyped = not (x is y)
   ## Negated version of `is`. Equivalent to ``not(x is y)``.
 
+proc new*[T](a: var ref T) {.magic: "New", noSideEffect.}
+  ## creates a new object of type ``T`` and returns a safe (traced)
+  ## reference to it in ``a``.
+
+proc new*(T: typedesc): auto =
+  ## creates a new object of type ``T`` and returns a safe (traced)
+  ## reference to it as result value.
+  ##
+  ## When ``T`` is a ref type then the resulting type will be ``T``,
+  ## otherwise it will be ``ref T``.
+  when (T is ref):
+    var r: T
+  else:
+    var r: ref T
+  new(r)
+  return r
+
 proc `of`*[T, S](x: typeDesc[T], y: typeDesc[S]): bool {.magic: "Of", noSideEffect.}
 proc `of`*[T, S](x: T, y: typeDesc[S]): bool {.magic: "Of", noSideEffect.}
 proc `of`*[T, S](x: T, y: S): bool {.magic: "Of", noSideEffect.}
@@ -2084,6 +2090,8 @@ when not defined(nimscript) and hasAlloc:
       ## returns the number of bytes on the shared heap that are owned by the
       ## process. This is only available when threads are enabled.
 
+proc `|`*(a, b: typedesc): typedesc = discard
+
 when sizeof(int) <= 2:
   type IntLikeForCount = int|int8|int16|char|bool|uint8|enum
 else:
@@ -2634,6 +2642,16 @@ proc `<`*[T: tuple](x, y: T): bool =
     if c > 0: return false
   return false
 
+proc compiles*(x: untyped): bool {.magic: "Compiles", noSideEffect, compileTime.} =
+  ## Special compile-time procedure that checks whether `x` can be compiled
+  ## without any semantic error.
+  ## This can be used to check whether a type supports some operation:
+  ##
+  ## .. code-block:: Nim
+  ##   when compiles(3 + 4):
+  ##     echo "'+' for integers is available"
+  discard
+
 proc `$`*[T: tuple|object](x: T): string =
   ## generic ``$`` operator for tuples that is lifted from the components
   ## of `x`. Example:
@@ -4045,16 +4063,6 @@ when hasAlloc:
       x[j+i] = item[j]
       inc(j)
 
-proc compiles*(x: untyped): bool {.magic: "Compiles", noSideEffect, compileTime.} =
-  ## Special compile-time procedure that checks whether `x` can be compiled
-  ## without any semantic error.
-  ## This can be used to check whether a type supports some operation:
-  ##
-  ## .. code-block:: Nim
-  ##   when compiles(3 + 4):
-  ##     echo "'+' for integers is available"
-  discard
-
 when declared(initDebugger):
   initDebugger()
 
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 7d5f5af7f..20ca143ca 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -381,6 +381,8 @@ proc raiseExceptionAux(e: ref Exception) =
           xadd(buf, s, s.len)
         var buf: array[0..2000, char]
         var L = 0
+        if e.trace.len != 0:
+          add(buf, $e.trace) # gc allocation      
         add(buf, "Error: unhandled exception: ")
         add(buf, e.msg)
         add(buf, " [")
@@ -394,7 +396,7 @@ proc raiseExceptionAux(e: ref Exception) =
           showErrorMessage(tbuf())
           quitOrDebug()
 
-proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =
+proc raiseExceptionEx(e: ref Exception, ename, procname, filename: cstring, line: int) {.compilerRtl.} =
   if e.name.isNil: e.name = ename
   when hasSomeStackTrace:
     if e.trace.len == 0:
@@ -403,8 +405,14 @@ proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =
       e.trace.add reraisedFrom(reraisedFromBegin)
       auxWriteStackTrace(framePtr, e.trace)
       e.trace.add reraisedFrom(reraisedFromEnd)
+  else:
+    if procname != nil and filename != nil:
+      e.trace.add StackTraceEntry(procname: procname, filename: filename, line: line)
   raiseExceptionAux(e)
 
+proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =
+  raiseExceptionEx(e, ename, nil, nil, 0)
+
 proc reraiseException() {.compilerRtl.} =
   if currException == nil:
     sysFatal(ReraiseError, "no exception to reraise")