summary refs log tree commit diff stats
path: root/lib/system.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/system.nim')
-rw-r--r--lib/system.nim186
1 files changed, 104 insertions, 82 deletions
diff --git a/lib/system.nim b/lib/system.nim
index ba0690ace..1e6f76f3d 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -76,6 +76,10 @@ type
   void* {.magic: "VoidType".}   ## meta type to denote the absence of any type
   auto* = expr
   any* = distinct auto
+  untyped* {.magic: Expr.} ## meta type to denote an expression that
+                           ## is not resolved (for templates)
+  typed* {.magic: Stmt.}   ## meta type to denote an expression that
+                           ## is resolved (for templates)
 
   SomeSignedInt* = int|int8|int16|int32|int64
     ## type class matching all signed integer types
@@ -173,12 +177,6 @@ proc new*(T: typedesc): ref T =
   ## reference to it as result value
   new(result)
 
-proc unsafeNew*[T](a: var ref T, size: int) {.magic: "New", noSideEffect.}
-  ## creates a new object of type ``T`` and returns a safe (traced)
-  ## reference to it in ``a``. This is **unsafe** as it allocates an object
-  ## of the passed ``size``. This should only be used for optimization
-  ## purposes when you know what you're doing!
-
 proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.}
   ## leaked implementation detail. Do not use.
 
@@ -513,7 +511,13 @@ type
   ESynch: Exception
 ].}
 
-proc sizeof*[T](x: T): Natural {.magic: "SizeOf", noSideEffect.}
+proc unsafeNew*[T](a: var ref T, size: Natural) {.magic: "New", noSideEffect.}
+  ## creates a new object of type ``T`` and returns a safe (traced)
+  ## reference to it in ``a``. This is **unsafe** as it allocates an object
+  ## of the passed ``size``. This should only be used for optimization
+  ## purposes when you know what you're doing!
+
+proc sizeof*[T](x: T): int {.magic: "SizeOf", noSideEffect.}
   ## returns the size of ``x`` in bytes. Since this is a low-level proc,
   ## its usage is discouraged - using ``new`` for the most cases suffices
   ## that one never needs to know ``x``'s size. As a special semantic rule,
@@ -547,7 +551,7 @@ proc dec*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Dec", noSideEffect.
   ## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
   ## short notation for: ``x = pred(x, y)``.
 
-proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
+proc newSeq*[T](s: var seq[T], len: Natural) {.magic: "NewSeq", noSideEffect.}
   ## creates a new sequence of type ``seq[T]`` with length ``len``.
   ## This is equivalent to ``s = @[]; setlen(s, len)``, but more
   ## efficient since no reallocation is needed.
@@ -565,7 +569,7 @@ proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
   ##   inputStrings[2] = "would crash"
   ##   #inputStrings[3] = "out of bounds"
 
-proc newSeq*[T](len = 0): seq[T] =
+proc newSeq*[T](len = 0.Natural): seq[T] =
   ## creates a new sequence of type ``seq[T]`` with length ``len``.
   ##
   ## Note that the sequence will be filled with zeroed entries, which can be a
@@ -659,7 +663,7 @@ proc `+` *(x: int): int {.magic: "UnaryPlusI", noSideEffect.}
 proc `+` *(x: int8): int8 {.magic: "UnaryPlusI", noSideEffect.}
 proc `+` *(x: int16): int16 {.magic: "UnaryPlusI", noSideEffect.}
 proc `+` *(x: int32): int32 {.magic: "UnaryPlusI", noSideEffect.}
-proc `+` *(x: int64): int64 {.magic: "UnaryPlusI64", noSideEffect.}
+proc `+` *(x: int64): int64 {.magic: "UnaryPlusI", noSideEffect.}
   ## Unary `+` operator for an integer. Has no effect.
 
 proc `-` *(x: int): int {.magic: "UnaryMinusI", noSideEffect.}
@@ -704,6 +708,7 @@ proc `div` *(x, y: int32): int32 {.magic: "DivI", noSideEffect.}
 proc `div` *(x, y: int64): int64 {.magic: "DivI64", noSideEffect.}
   ## computes the integer division. This is roughly the same as
   ## ``floor(x/y)``.
+  ##
   ## .. code-block:: Nim
   ##   1 div 2 == 0
   ##   2 div 2 == 1
@@ -723,6 +728,7 @@ proc `shr` *(x, y: int16): int16 {.magic: "ShrI", noSideEffect.}
 proc `shr` *(x, y: int32): int32 {.magic: "ShrI", noSideEffect.}
 proc `shr` *(x, y: int64): int64 {.magic: "ShrI64", noSideEffect.}
   ## computes the `shift right` operation of `x` and `y`.
+  ##
   ## .. code-block:: Nim
   ##   0b0001_0000'i8 shr 2 == 0b0100_0000'i8
   ##   0b1000_0000'i8 shr 2 == 0b0000_0000'i8
@@ -937,7 +943,7 @@ proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {.
   ## sequences with the array constructor: ``@[1, 2, 3]`` has the type
   ## ``seq[int]``, while ``[1, 2, 3]`` has the type ``array[0..2, int]``.
 
-proc setLen*[T](s: var seq[T], newlen: int) {.
+proc setLen*[T](s: var seq[T], newlen: Natural) {.
   magic: "SetLengthSeq", noSideEffect.}
   ## sets the length of `s` to `newlen`.
   ## ``T`` may be any sequence type.
@@ -945,14 +951,14 @@ proc setLen*[T](s: var seq[T], newlen: int) {.
   ## ``s`` will be truncated. `s` cannot be nil! To initialize a sequence with
   ## a size, use ``newSeq`` instead.
 
-proc setLen*(s: var string, newlen: int) {.
+proc setLen*(s: var string, newlen: Natural) {.
   magic: "SetLengthStr", noSideEffect.}
   ## sets the length of `s` to `newlen`.
   ## If the current length is greater than the new length,
   ## ``s`` will be truncated. `s` cannot be nil! To initialize a string with
   ## a size, use ``newString`` instead.
 
-proc newString*(len: int): string {.
+proc newString*(len: Natural): string {.
   magic: "NewString", importc: "mnewString", noSideEffect.}
   ## returns a new string of length ``len`` but with uninitialized
   ## content. One needs to fill the string character after character
@@ -960,7 +966,7 @@ proc newString*(len: int): string {.
   ## optimization purposes; the same effect can be achieved with the
   ## ``&`` operator or with ``add``.
 
-proc newStringOfCap*(cap: int): string {.
+proc newStringOfCap*(cap: Natural): string {.
   magic: "NewStringOfCap", importc: "rawNewString", noSideEffect.}
   ## returns a new string of length ``0`` but with capacity `cap`.This
   ## procedure exists only for optimization purposes; the same effect can
@@ -1104,7 +1110,7 @@ var programResult* {.exportc: "nim_program_result".}: int
   ## prematurely using ``quit``, this value is ignored.
 
 proc quit*(errorcode: int = QuitSuccess) {.
-  magic: "Exit", importc: "exit", header: "<stdlib.h>", noReturn.}
+  magic: "Exit", importc: "exit", header: "<stdlib.h>", noreturn.}
   ## Stops the program immediately with an exit code.
   ##
   ## Before stopping the program the "quit procedures" are called in the
@@ -1150,21 +1156,21 @@ proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".}
   ## is a reason why the default assignment does a deep copy of sequences
   ## and strings.
 
-proc del*[T](x: var seq[T], i: int) {.noSideEffect.} =
+proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
   ## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
   ## This is an O(1) operation.
   let xl = x.len
   shallowCopy(x[i], x[xl-1])
   setLen(x, xl-1)
 
-proc delete*[T](x: var seq[T], i: int) {.noSideEffect.} =
+proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
   ## deletes the item at index `i` by moving ``x[i+1..]`` by one position.
   ## This is an O(n) operation.
   let xl = x.len
   for j in i..xl-2: shallowCopy(x[j], x[j+1])
   setLen(x, xl-1)
 
-proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} =
+proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} =
   ## inserts `item` into `x` at position `i`.
   let xl = x.len
   setLen(x, xl+1)
@@ -1310,19 +1316,19 @@ proc substr*(s: string, first, last: int): string {.
   ## or `limit`:idx: a string's length.
 
 when not defined(nimrodVM):
-  proc zeroMem*(p: pointer, size: int) {.importc, noDecl, benign.}
+  proc zeroMem*(p: pointer, size: Natural) {.importc, noDecl, benign.}
     ## overwrites the contents of the memory at ``p`` with the value 0.
     ## Exactly ``size`` bytes will be overwritten. Like any procedure
     ## dealing with raw memory this is *unsafe*.
 
-  proc copyMem*(dest, source: pointer, size: int) {.
+  proc copyMem*(dest, source: pointer, size: Natural) {.
     importc: "memcpy", header: "<string.h>", benign.}
     ## copies the contents from the memory at ``source`` to the memory
     ## at ``dest``. Exactly ``size`` bytes will be copied. The memory
     ## regions may not overlap. Like any procedure dealing with raw
     ## memory this is *unsafe*.
 
-  proc moveMem*(dest, source: pointer, size: int) {.
+  proc moveMem*(dest, source: pointer, size: Natural) {.
     importc: "memmove", header: "<string.h>", benign.}
     ## copies the contents from the memory at ``source`` to the memory
     ## at ``dest``. Exactly ``size`` bytes will be copied. The memory
@@ -1330,7 +1336,7 @@ when not defined(nimrodVM):
     ## and is thus somewhat more safe than ``copyMem``. Like any procedure
     ## dealing with raw memory this is still *unsafe*, though.
 
-  proc equalMem*(a, b: pointer, size: int): bool {.
+  proc equalMem*(a, b: pointer, size: Natural): bool {.
     importc: "equalMem", noDecl, noSideEffect.}
     ## compares the memory blocks ``a`` and ``b``. ``size`` bytes will
     ## be compared. If the blocks are equal, true is returned, false
@@ -1338,7 +1344,7 @@ when not defined(nimrodVM):
     ## *unsafe*.
 
   when hostOS != "standalone":
-    proc alloc*(size: int): pointer {.noconv, rtl, tags: [], benign.}
+    proc alloc*(size: Natural): pointer {.noconv, rtl, tags: [], benign.}
       ## allocates a new memory block with at least ``size`` bytes. The
       ## block has to be freed with ``realloc(block, 0)`` or
       ## ``dealloc(block)``. The block is not initialized, so reading
@@ -1353,7 +1359,7 @@ when not defined(nimrodVM):
       ## The allocated memory belongs to its allocating thread!
       ## Use `createSharedU` to allocate from a shared heap.
       cast[ptr T](alloc(T.sizeof * size))
-    proc alloc0*(size: int): pointer {.noconv, rtl, tags: [], benign.}
+    proc alloc0*(size: Natural): pointer {.noconv, rtl, tags: [], benign.}
       ## allocates a new memory block with at least ``size`` bytes. The
       ## block has to be freed with ``realloc(block, 0)`` or
       ## ``dealloc(block)``. The block is initialized with all bytes
@@ -1368,8 +1374,8 @@ when not defined(nimrodVM):
       ## The allocated memory belongs to its allocating thread!
       ## Use `createShared` to allocate from a shared heap.
       cast[ptr T](alloc0(T.sizeof * size))
-    proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [],
-                                                       benign.}
+    proc realloc*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [],
+                                                           benign.}
       ## grows or shrinks a given memory block. If p is **nil** then a new
       ## memory block is returned. In either way the block has at least
       ## ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
@@ -1396,7 +1402,7 @@ when not defined(nimrodVM):
       ## Use `deallocShared` to deallocate from a shared heap.
     proc free*[T](p: ptr T) {.inline, benign.} =
       dealloc(p)
-    proc allocShared*(size: int): pointer {.noconv, rtl, benign.}
+    proc allocShared*(size: Natural): pointer {.noconv, rtl, benign.}
       ## allocates a new memory block on the shared heap with at
       ## least ``size`` bytes. The block has to be freed with
       ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
@@ -1410,7 +1416,7 @@ when not defined(nimrodVM):
       ## is not initialized, so reading from it before writing to it is
       ## undefined behaviour!
       cast[ptr T](allocShared(T.sizeof * size))
-    proc allocShared0*(size: int): pointer {.noconv, rtl, benign.}
+    proc allocShared0*(size: Natural): pointer {.noconv, rtl, benign.}
       ## allocates a new memory block on the shared heap with at
       ## least ``size`` bytes. The block has to be freed with
       ## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
@@ -1423,8 +1429,8 @@ when not defined(nimrodVM):
       ## The block is initialized with all bytes
       ## containing zero, so it is somewhat safer than ``createSharedU``.
       cast[ptr T](allocShared0(T.sizeof * size))
-    proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl,
-                                                             benign.}
+    proc reallocShared*(p: pointer, newSize: Natural): pointer {.noconv, rtl,
+                                                                 benign.}
       ## grows or shrinks a given memory block on the heap. If p is **nil**
       ## then a new memory block is returned. In either way the block has at
       ## least ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
@@ -1526,10 +1532,10 @@ const
   NimMajor*: int = 0
     ## is the major number of Nim's version.
 
-  NimMinor*: int = 10
+  NimMinor*: int = 11
     ## is the minor number of Nim's version.
 
-  NimPatch*: int = 3
+  NimPatch*: int = 2
     ## is the patch number of Nim's version.
 
   NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
@@ -1632,7 +1638,7 @@ proc min*(x, y: int16): int16 {.magic: "MinI", noSideEffect.} =
   if x <= y: x else: y
 proc min*(x, y: int32): int32 {.magic: "MinI", noSideEffect.} =
   if x <= y: x else: y
-proc min*(x, y: int64): int64 {.magic: "MinI64", noSideEffect.} =
+proc min*(x, y: int64): int64 {.magic: "MinI", noSideEffect.} =
   ## The minimum value of two integers.
   if x <= y: x else: y
 
@@ -1650,7 +1656,7 @@ proc max*(x, y: int16): int16 {.magic: "MaxI", noSideEffect.} =
   if y <= x: x else: y
 proc max*(x, y: int32): int32 {.magic: "MaxI", noSideEffect.} =
   if y <= x: x else: y
-proc max*(x, y: int64): int64 {.magic: "MaxI64", noSideEffect.} =
+proc max*(x, y: int64): int64 {.magic: "MaxI", noSideEffect.} =
   ## The maximum value of two integers.
   if y <= x: x else: y
 
@@ -1738,6 +1744,12 @@ iterator items*(E: typedesc[enum]): E =
   for v in low(E)..high(E):
     yield v
 
+iterator items*[T](s: Slice[T]): T =
+  ## iterates over the slice `s`, yielding each value between `s.a` and `s.b`
+  ## (inclusively).
+  for x in s.a..s.b:
+    yield x
+
 iterator pairs*[T](a: openArray[T]): tuple[key: int, val: T] {.inline.} =
   ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
   var i = 0
@@ -2258,20 +2270,21 @@ when hostOS == "standalone":
   include panicoverride
 
 when not declared(sysFatal):
-  template sysFatal(exceptn: typedesc, message: string) =
-    when hostOS == "standalone":
+  when hostOS == "standalone":
+    proc sysFatal(exceptn: typedesc, message: string) {.inline.} =
       panic(message)
-    else:
+
+    proc sysFatal(exceptn: typedesc, message, arg: string) {.inline.} =
+      rawoutput(message)
+      panic(arg)
+  else:
+    proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} =
       var e: ref exceptn
       new(e)
       e.msg = message
       raise e
 
-  template sysFatal(exceptn: typedesc, message, arg: string) =
-    when hostOS == "standalone":
-      rawoutput(message)
-      panic(arg)
-    else:
+    proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noReturn.} =
       var e: ref exceptn
       new(e)
       e.msg = message & arg
@@ -2487,37 +2500,37 @@ when not defined(JS): #and not defined(NimrodVM):
     proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.}
       ## retrieves the file size (in bytes) of `f`.
 
-    proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: int): int {.
+    proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: Natural): int {.
       tags: [ReadIOEffect], benign.}
       ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
       ## the actual number of bytes that have been read which may be less than
       ## `len` (if not as many bytes are remaining), but not greater.
 
-    proc readChars*(f: File, a: var openArray[char], start, len: int): int {.
+    proc readChars*(f: File, a: var openArray[char], start, len: Natural): int {.
       tags: [ReadIOEffect], benign.}
       ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
       ## the actual number of bytes that have been read which may be less than
       ## `len` (if not as many bytes are remaining), but not greater.
 
-    proc readBuffer*(f: File, buffer: pointer, len: int): int {.
+    proc readBuffer*(f: File, buffer: pointer, len: Natural): int {.
       tags: [ReadIOEffect], benign.}
       ## reads `len` bytes into the buffer pointed to by `buffer`. Returns
       ## the actual number of bytes that have been read which may be less than
       ## `len` (if not as many bytes are remaining), but not greater.
 
-    proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: int): int {.
+    proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: Natural): int {.
       tags: [WriteIOEffect], benign.}
       ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
       ## the number of actual written bytes, which may be less than `len` in case
       ## of an error.
 
-    proc writeChars*(f: File, a: openArray[char], start, len: int): int {.
+    proc writeChars*(f: File, a: openArray[char], start, len: Natural): int {.
       tags: [WriteIOEffect], benign.}
       ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
       ## the number of actual written bytes, which may be less than `len` in case
       ## of an error.
 
-    proc writeBuffer*(f: File, buffer: pointer, len: int): int {.
+    proc writeBuffer*(f: File, buffer: pointer, len: Natural): int {.
       tags: [WriteIOEffect], benign.}
       ## writes the bytes of buffer pointed to by the parameter `buffer` to the
       ## file `f`. Returns the number of actual written bytes, which may be less
@@ -2539,7 +2552,7 @@ when not defined(JS): #and not defined(NimrodVM):
     when not defined(nimfix):
       {.deprecated: [fileHandle: getFileHandle].}
 
-    proc cstringArrayToSeq*(a: cstringArray, len: int): seq[string] =
+    proc cstringArrayToSeq*(a: cstringArray, len: Natural): seq[string] =
       ## converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be
       ## of length ``len``.
       newSeq(result, len)
@@ -2809,14 +2822,14 @@ elif defined(JS):
   proc getTotalMem(): int = return -1
 
   proc dealloc(p: pointer) = discard
-  proc alloc(size: int): pointer = discard
-  proc alloc0(size: int): pointer = discard
-  proc realloc(p: pointer, newsize: int): pointer = discard
+  proc alloc(size: Natural): pointer = discard
+  proc alloc0(size: Natural): pointer = discard
+  proc realloc(p: pointer, newsize: Natural): pointer = discard
 
-  proc allocShared(size: int): pointer = discard
-  proc allocShared0(size: int): pointer = discard
+  proc allocShared(size: Natural): pointer = discard
+  proc allocShared0(size: Natural): pointer = discard
   proc deallocShared(p: pointer) = discard
-  proc reallocShared(p: pointer, newsize: int): pointer = discard
+  proc reallocShared(p: pointer, newsize: Natural): pointer = discard
 
   when defined(JS):
     include "system/jssys"
@@ -3028,8 +3041,8 @@ proc instantiationInfo*(index = -1, fullPaths = false): tuple[
   ##     result = a[pos]
   ##
   ##   when isMainModule:
-  ##     testException(EInvalidIndex, tester(30))
-  ##     testException(EInvalidIndex, tester(1))
+  ##     testException(IndexError, tester(30))
+  ##     testException(IndexError, tester(1))
   ##     # --> Test failure at example.nim:20 with 'tester(1)'
 
 template currentSourcePath*: string = instantiationInfo(-1, true).filename
@@ -3038,13 +3051,12 @@ template currentSourcePath*: string = instantiationInfo(-1, true).filename
 proc raiseAssert*(msg: string) {.noinline.} =
   sysFatal(AssertionError, msg)
 
-when true:
-  proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
-    # trick the compiler to not list ``EAssertionFailed`` when called
-    # by ``assert``.
-    type THide = proc (msg: string) {.noinline, raises: [], noSideEffect,
-                                      tags: [].}
-    THide(raiseAssert)(msg)
+proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
+  # trick the compiler to not list ``AssertionError`` when called
+  # by ``assert``.
+  type THide = proc (msg: string) {.noinline, raises: [], noSideEffect,
+                                    tags: [].}
+  THide(raiseAssert)(msg)
 
 template assert*(cond: bool, msg = "") =
   ## Raises ``AssertionError`` with `msg` if `cond` is false. Note
@@ -3109,24 +3121,18 @@ when not defined(nimhygiene):
 
 template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} =
   ## Sets an assertion failure handler that will intercept any assert
-  ## statements following `onFailedAssert` in the current lexical scope.
-  ## Can be defined multiple times in a single function.
+  ## statements following `onFailedAssert` in the current module scope.
   ##
   ## .. code-block:: nim
-  ##
-  ##   proc example(x: int): TErrorCode =
-  ##     onFailedAssert(msg):
-  ##       log msg
-  ##       return E_FAIL
-  ##
-  ##     assert(...)
-  ##
-  ##     onFailedAssert(msg):
-  ##       raise newException(EMyException, msg)
-  ##
-  ##     assert(...)
-  ##
-  template failedAssertImpl(msgIMPL: string): stmt {.dirty, immediate.} =
+  ##  # module-wide policy to change the failed assert
+  ##  # exception type in order to include a lineinfo
+  ##  onFailedAssert(msg):
+  ##    var e = new(TMyError)
+  ##    e.msg = msg
+  ##    e.lineinfo = instantiationInfo(-2)
+  ##    raise e
+  ##
+  template failedAssertImpl(msgIMPL: string): stmt {.dirty.} =
     let msg = msgIMPL
     code
 
@@ -3162,7 +3168,7 @@ when false:
     payload()
 
 when hostOS != "standalone":
-  proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} =
+  proc insert*(x: var string, item: string, i = 0.Natural) {.noSideEffect.} =
     ## inserts `item` into `x` at position `i`.
     var xl = x.len
     setLen(x, xl+item.len)
@@ -3202,7 +3208,7 @@ when hostOS != "standalone":
     if x == nil: x = y
     else: x.add(y)
 
-proc locals*(): RootObj {.magic: "Locals", noSideEffect.} =
+proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} =
   ## generates a tuple constructor expression listing all the local variables
   ## in the current scope. This is quite fast as it does not rely
   ## on any debug or runtime information. Note that in constrast to what
@@ -3251,4 +3257,20 @@ proc `^`*(x: int): int {.noSideEffect, magic: "Roof".} =
   ## overloaded ``[]`` or ``[]=`` accessors.
   discard
 
+template `..^`*(a, b: expr): expr =
+  ## a shortcut for '.. ^' to avoid the common gotcha that a space between
+  ## '..' and '^' is required.
+  a .. ^b
+
+template `..<`*(a, b: expr): expr =
+  ## a shortcut for '.. <' to avoid the common gotcha that a space between
+  ## '..' and '<' is required.
+  a .. <b
+
+proc xlen*(x: string): int {.magic: "XLenStr", noSideEffect.} = discard
+proc xlen*[T](x: seq[T]): int {.magic: "XLenSeq", noSideEffect.} =
+  ## returns the length of a sequence or a string without testing for 'nil'.
+  ## This is an optimization that rarely makes sense.
+  discard
+
 {.pop.} #{.push warning[GcMem]: off.}