diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/packages/fsmonitor.nim | 229 | ||||
-rw-r--r-- | lib/pure/htmlparser.nim | 3 | ||||
-rw-r--r-- | lib/pure/ioselects/ioselectors_epoll.nim | 8 | ||||
-rw-r--r-- | lib/pure/logging.nim | 11 | ||||
-rw-r--r-- | lib/pure/math.nim | 54 | ||||
-rw-r--r-- | lib/pure/parsesql.nim | 25 | ||||
-rw-r--r-- | lib/pure/parsexml.nim | 28 | ||||
-rw-r--r-- | lib/pure/strscans.nim | 7 | ||||
-rw-r--r-- | lib/pure/strutils.nim | 2 | ||||
-rw-r--r-- | lib/pure/sugar.nim | 5 | ||||
-rw-r--r-- | lib/system.nim | 72 | ||||
-rw-r--r-- | lib/system/excpt.nim | 10 |
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") |