From ed4a267399ed6420d979b4594f60edb698229084 Mon Sep 17 00:00:00 2001
From: hlaaf <hlaaftana@users.noreply.github.com>
Date: Tue, 14 Aug 2018 01:33:56 +0300
Subject: Small documentation typo in math

---
 lib/pure/math.nim | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'lib/pure')

diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index eb09bf4a7..641f07c43 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -529,8 +529,8 @@ proc sgn*[T: SomeNumber](x: T): int {.inline.} =
 {.pop.}
 
 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.
+  ## Computes ``x`` to the power ``y``. ``x`` must be non-negative, use
+  ## `pow <#pow,float,float>`_ for negative exponents.
   when compiles(y >= T(0)):
     assert y >= T(0)
   else:
-- 
cgit 1.4.1-2-gfad0


From feda366d86e723ff1877a1751cb3eadde8b00cb0 Mon Sep 17 00:00:00 2001
From: Dominik Picheta <dominikpicheta@googlemail.com>
Date: Tue, 14 Aug 2018 00:09:08 +0100
Subject: Adds get for Option[T]. (#8462)

---
 lib/pure/options.nim | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

(limited to 'lib/pure')

diff --git a/lib/pure/options.nim b/lib/pure/options.nim
index ce58943f9..b547c722a 100644
--- a/lib/pure/options.nim
+++ b/lib/pure/options.nim
@@ -129,7 +129,7 @@ proc get*[T](self: Option[T]): T =
   ## Returns contents of the Option. If it is none, then an exception is
   ## thrown.
   if self.isNone:
-    raise UnpackError(msg : "Can't obtain a value from a `none`")
+    raise UnpackError(msg: "Can't obtain a value from a `none`")
   self.val
 
 proc get*[T](self: Option[T], otherwise: T): T =
@@ -139,6 +139,13 @@ proc get*[T](self: Option[T], otherwise: T): T =
   else:
     otherwise
 
+proc get*[T](self: var Option[T]): var T =
+  ## Returns contents of the Option. If it is none, then an exception is
+  ## thrown.
+  if self.isNone:
+    raise UnpackError(msg: "Can't obtain a value from a `none`")
+  return self.val
+
 proc map*[T](self: Option[T], callback: proc (input: T)) =
   ## Applies a callback to the value in this Option
   if self.isSome:
-- 
cgit 1.4.1-2-gfad0


From 7ef268274f387530b85f5a9f704e0eda5a7aa022 Mon Sep 17 00:00:00 2001
From: alaviss <alaviss@users.noreply.github.com>
Date: Tue, 14 Aug 2018 14:35:07 +0700
Subject: Haiku support for Nim (#8542)

* posix_other: Haiku now has spawn.h

This is added per https://dev.haiku-os.org/ticket/13446

* posix_other: Add Haiku specific Dirent members

* cpuinfo: Add an implementation for Haiku

* distros: Add basic Haiku support

* encodings: update Haiku support

* fenv, math: Haiku now provides libm

* times: Add Haiku struct members

* ansi_c, osalloc: Add Haiku constants

* threads: Add Haiku support

* testament: Haiku uses LIBRARY_PATH

* nim.cfg: Update Haiku support

libnetwork should only be linked if network functions are used

* threads: Haiku does not support -pthread switch

* tworkingdir: Haiku's env is in /bin

* posix_other: add SIGKILLTHR for Haiku

* sockets: link with libnetwork on Haiku

* coro: correct ucontext.h location

http://pubs.opengroup.org/onlinepubs/009696699/basedefs/ucontext.h.html

* coro: ucontext backend is not available on Haiku

Haiku doesn't provide the <ucontext.h> header, as it was removed from POSIX

* coro: fix setjmp backend

The compiler does not allow statements after a noreturn function

* nativesockets: Haiku doesn't support AI_V4MAPPED

* system: hostOS can contains "haiku"

* os: add support for Haiku's packagefs

packagefs is read-only, but there are writable holes to the underlying
file system as well

* os: update constant for Haiku
---
 config/nim.cfg                   | 16 +++++++++-------
 lib/deprecated/pure/sockets.nim  |  2 ++
 lib/posix/posix_other.nim        | 12 +++++++++++-
 lib/pure/concurrency/cpuinfo.nim | 12 ++++++++++++
 lib/pure/coro.nim                | 18 +++++++++++-------
 lib/pure/distros.nim             |  6 ++++++
 lib/pure/encodings.nim           |  4 +++-
 lib/pure/fenv.nim                |  2 +-
 lib/pure/math.nim                |  2 +-
 lib/pure/nativesockets.nim       |  5 +++--
 lib/pure/os.nim                  | 13 ++++++++++++-
 lib/pure/times.nim               |  2 +-
 lib/system.nim                   |  2 +-
 lib/system/ansi_c.nim            | 11 +++++++++++
 lib/system/osalloc.nim           |  3 +++
 lib/system/threads.nim           | 16 ++++++++++++++--
 tests/osproc/texitsignal.nim     |  5 ++++-
 tests/osproc/tworkingdir.nim     |  2 ++
 tests/testament/categories.nim   | 10 +++++++---
 19 files changed, 114 insertions(+), 29 deletions(-)

(limited to 'lib/pure')

diff --git a/config/nim.cfg b/config/nim.cfg
index c30190a18..af9df9c55 100644
--- a/config/nim.cfg
+++ b/config/nim.cfg
@@ -82,19 +82,21 @@ path="$lib/pure"
     clang.cpp.options.linker = "-ldl"
     tcc.options.linker = "-ldl"
   @end
-  @if bsd or haiku:
+  @if bsd:
     # BSD got posix_spawn only recently, so we deactivate it for osproc:
     define:useFork
     # at least NetBSD has problems with thread local storage:
     tlsEmulation:on
   @end
   @if haiku:
-    # -fopenmp
-    gcc.options.linker = "-lroot -lnetwork"
-    gcc.cpp.options.linker = "-lroot -lnetwork"
-    clang.options.linker = "-lroot -lnetwork"
-    clang.cpp.options.linker = "-lroot -lnetwork"
-    tcc.options.linker = "-lroot -lnetwork"
+    # Haiku currently have problems with TLS
+    # https://dev.haiku-os.org/ticket/14342
+    tlsEmulation:on
+    gcc.options.linker = "-Wl,--as-needed -lnetwork"
+    gcc.cpp.options.linker = "-Wl,--as-needed -lnetwork"
+    clang.options.linker = "-Wl,--as-needed -lnetwork"
+    clang.cpp.options.linker = "-Wl,--as-needed -lnetwork"
+    tcc.options.linker = "-Wl,--as-needed -lnetwork"
   @end
 @end
 
diff --git a/lib/deprecated/pure/sockets.nim b/lib/deprecated/pure/sockets.nim
index 05aebef76..76a9044d8 100644
--- a/lib/deprecated/pure/sockets.nim
+++ b/lib/deprecated/pure/sockets.nim
@@ -36,6 +36,8 @@ include "system/inclrtl"
 
 when hostOS == "solaris":
   {.passl: "-lsocket -lnsl".}
+elif hostOS == "haiku":
+  {.passl: "-lnetwork".}
 
 import os, parseutils
 from times import epochTime
diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim
index b7570bd15..99d67824e 100644
--- a/lib/posix/posix_other.nim
+++ b/lib/posix/posix_other.nim
@@ -10,7 +10,7 @@
 {.deadCodeElim: on.}  # dce option deprecated
 
 const
-  hasSpawnH = not defined(haiku) # should exist for every Posix system nowadays
+  hasSpawnH = true # should exist for every Posix system nowadays
   hasAioH = defined(linux)
 
 when defined(linux) and not defined(android):
@@ -43,6 +43,9 @@ type
 
   Dirent* {.importc: "struct dirent",
              header: "<dirent.h>", final, pure.} = object ## dirent_t struct
+    when defined(haiku):
+      d_dev*: Dev ## Device (not POSIX)
+      d_pdev*: Dev ## Parent device (only for queries) (not POSIX)
     d_ino*: Ino  ## File serial number.
     when defined(dragonfly):
       # DragonflyBSD doesn't have `d_reclen` field.
@@ -54,6 +57,9 @@ type
                     ## (not POSIX)
       when defined(linux) or defined(openbsd):
         d_off*: Off  ## Not an offset. Value that ``telldir()`` would return.
+    elif defined(haiku):
+      d_pino*: Ino ## Parent inode (only for queries) (not POSIX)
+      d_reclen*: cushort ## Length of this record. (not POSIX)
 
     d_name*: array[0..255, char] ## Name of entry.
 
@@ -599,6 +605,10 @@ else:
     MSG_NOSIGNAL* {.importc, header: "<sys/socket.h>".}: cint
       ## No SIGPIPE generated when an attempt to send is made on a stream-oriented socket that is no longer connected.
 
+when defined(haiku):
+  const
+    SIGKILLTHR* = 21 ## BeOS specific: Kill just the thread, not team
+
 when hasSpawnH:
   when defined(linux):
     # better be safe than sorry; Linux has this flag, macosx doesn't, don't
diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim
index 6d41aa1b2..541265da9 100644
--- a/lib/pure/concurrency/cpuinfo.nim
+++ b/lib/pure/concurrency/cpuinfo.nim
@@ -43,6 +43,14 @@ when defined(genode):
   proc affinitySpaceTotal(env: GenodeEnvPtr): cuint {.
     importcpp: "@->cpu().affinity_space().total()".}
 
+when defined(haiku):
+  {.emit: "#include <OS.h>".}
+  type
+    SystemInfo {.importc: "system_info", bycopy.} = object
+      cpuCount {.importc: "cpu_count".}: uint32
+
+  proc getSystemInfo(info: ptr SystemInfo): int32 {.importc: "get_system_info".}
+
 proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
   ## returns the numer of the processors/cores the machine has.
   ## Returns 0 if it cannot be detected.
@@ -86,6 +94,10 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
     result = sysconf(SC_NPROC_ONLN)
   elif defined(genode):
     result = runtimeEnv.affinitySpaceTotal().int
+  elif defined(haiku):
+    var sysinfo: SystemInfo
+    if getSystemInfo(addr sysinfo) == 0:
+      result = sysinfo.cpuCount.int
   else:
     result = sysconf(SC_NPROCESSORS_ONLN)
   if result <= 0: result = 0
diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim
index b6ef30e7c..6d7dcf078 100644
--- a/lib/pure/coro.nim
+++ b/lib/pure/coro.nim
@@ -43,6 +43,10 @@ when defined(windows):
     {.warning: "ucontext coroutine backend is not available on windows, defaulting to fibers.".}
   when defined(nimCoroutinesSetjmp):
     {.warning: "setjmp coroutine backend is not available on windows, defaulting to fibers.".}
+elif defined(haiku):
+  const coroBackend = CORO_BACKEND_SETJMP
+  when defined(nimCoroutinesUcontext):
+    {.warning: "ucontext coroutine backend is not available on haiku, defaulting to setjmp".}
 elif defined(nimCoroutinesSetjmp) or defined(nimCoroutinesSetjmpBundled):
   const coroBackend = CORO_BACKEND_SETJMP
 else:
@@ -55,21 +59,21 @@ when coroBackend == CORO_BACKEND_FIBERS:
 
 elif coroBackend == CORO_BACKEND_UCONTEXT:
   type
-    stack_t {.importc, header: "<sys/ucontext.h>".} = object
+    stack_t {.importc, header: "<ucontext.h>".} = object
       ss_sp: pointer
       ss_flags: int
       ss_size: int
 
-    ucontext_t {.importc, header: "<sys/ucontext.h>".} = object
+    ucontext_t {.importc, header: "<ucontext.h>".} = object
       uc_link: ptr ucontext_t
       uc_stack: stack_t
 
     Context = ucontext_t
 
-  proc getcontext(context: var ucontext_t): int32 {.importc, header: "<sys/ucontext.h>".}
-  proc setcontext(context: var ucontext_t): int32 {.importc, header: "<sys/ucontext.h>".}
-  proc swapcontext(fromCtx, toCtx: var ucontext_t): int32 {.importc, header: "<sys/ucontext.h>".}
-  proc makecontext(context: var ucontext_t, fn: pointer, argc: int32) {.importc, header: "<sys/ucontext.h>", varargs.}
+  proc getcontext(context: var ucontext_t): int32 {.importc, header: "<ucontext.h>".}
+  proc setcontext(context: var ucontext_t): int32 {.importc, header: "<ucontext.h>".}
+  proc swapcontext(fromCtx, toCtx: var ucontext_t): int32 {.importc, header: "<ucontext.h>".}
+  proc makecontext(context: var ucontext_t, fn: pointer, argc: int32) {.importc, header: "<ucontext.h>", varargs.}
 
 elif coroBackend == CORO_BACKEND_SETJMP:
   proc coroExecWithStack*(fn: pointer, stack: pointer) {.noreturn, importc: "narch_$1", fastcall.}
@@ -190,7 +194,7 @@ proc switchTo(current, to: CoroutinePtr) =
         elif to.state == CORO_CREATED:
           # Coroutine is started.
           coroExecWithStack(runCurrentTask, to.stack.bottom)
-          doAssert false
+          #doAssert false
     else:
       {.error: "Invalid coroutine backend set.".}
   # Execution was just resumed. Restore frame information and set active stack.
diff --git a/lib/pure/distros.nim b/lib/pure/distros.nim
index 0adba5b1e..5847cfadb 100644
--- a/lib/pure/distros.nim
+++ b/lib/pure/distros.nim
@@ -126,6 +126,8 @@ type
     OpenBSD
     DragonFlyBSD
 
+    Haiku
+
 
 const
   LacksDevPackages* = {Distribution.Gentoo, Distribution.Slackware,
@@ -166,6 +168,8 @@ proc detectOsImpl(d: Distribution): bool =
   of Distribution.Solaris:
     let uname = toLowerAscii(uname())
     result = ("sun" in uname) or ("solaris" in uname)
+  of Distribution.Haiku:
+    result = defined(haiku)
   else:
     let dd = toLowerAscii($d)
     result = dd in toLowerAscii(uname()) or dd in toLowerAscii(release())
@@ -224,6 +228,8 @@ proc foreignDepInstallCmd*(foreignPackageName: string): (string, bool) =
       result = ("pacman -S " & p, true)
     else:
       result = ("<your package manager here> install " & p, true)
+  elif defined(haiku):
+    result = ("pkgman install " & p, true)
   else:
     result = ("brew install " & p, false)
 
diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim
index 3c1cf73f4..2039a31be 100644
--- a/lib/pure/encodings.nim
+++ b/lib/pure/encodings.nim
@@ -255,7 +255,7 @@ when defined(windows):
 
 else:
   when defined(haiku):
-    const iconvDll = "(libc.so.6|libiconv.so|libtextencoding.so)"
+    const iconvDll = "libiconv.so"
   elif defined(macosx):
     const iconvDll = "libiconv.dylib"
   else:
@@ -272,6 +272,8 @@ else:
     const EILSEQ = 86.cint
   elif defined(solaris):
     const EILSEQ = 88.cint
+  elif defined(haiku):
+    const EILSEQ = -2147454938.cint
 
   var errno {.importc, header: "<errno.h>".}: cint
 
diff --git a/lib/pure/fenv.nim b/lib/pure/fenv.nim
index c946c4261..0725973ca 100644
--- a/lib/pure/fenv.nim
+++ b/lib/pure/fenv.nim
@@ -12,7 +12,7 @@
 
 {.deadCodeElim: on.}  # dce option deprecated
 
-when defined(Posix) and not defined(haiku):
+when defined(Posix):
   {.passl: "-lm".}
 
 var
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index eb09bf4a7..785d4c183 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -49,7 +49,7 @@ proc fac*(n: int): int =
 
 {.push checks:off, line_dir:off, stack_trace:off.}
 
-when defined(Posix) and not defined(haiku):
+when defined(Posix):
   {.passl: "-lm".}
 
 const
diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim
index 5545ca2d1..d5fb0f89b 100644
--- a/lib/pure/nativesockets.nim
+++ b/lib/pure/nativesockets.nim
@@ -248,9 +248,10 @@ proc getAddrInfo*(address: string, port: Port, domain: Domain = AF_INET,
   hints.ai_socktype = toInt(sockType)
   hints.ai_protocol = toInt(protocol)
   # OpenBSD doesn't support AI_V4MAPPED and doesn't define the macro AI_V4MAPPED.
-  # FreeBSD doesn't support AI_V4MAPPED but defines the macro.
+  # FreeBSD, Haiku don't support AI_V4MAPPED but defines the macro.
   # https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=198092
-  when not defined(freebsd) and not defined(openbsd) and not defined(netbsd) and not defined(android):
+  # https://dev.haiku-os.org/ticket/14323
+  when not defined(freebsd) and not defined(openbsd) and not defined(netbsd) and not defined(android) and not defined(haiku):
     if domain == AF_INET6:
       hints.ai_flags = AI_V4MAPPED
   var gaiResult = getaddrinfo(address, $port, addr(hints), result)
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 9cc83c372..c05e33e31 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -615,7 +615,10 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
 
 when not declared(ENOENT) and not defined(Windows):
   when NoFakeVars:
-    const ENOENT = cint(2) # 2 on most systems including Solaris
+    when not defined(haiku):
+      const ENOENT = cint(2) # 2 on most systems including Solaris
+    else:
+      const ENOENT = cint(-2147459069)
   else:
     var ENOENT {.importc, header: "<errno.h>".}: cint
 
@@ -972,6 +975,14 @@ proc rawCreateDir(dir: string): bool =
       result = false
     else:
       raiseOSError(osLastError(), dir)
+  elif defined(haiku):
+    let res = mkdir(dir, 0o777)
+    if res == 0'i32:
+      result = true
+    elif errno == EEXIST or errno == EROFS:
+      result = false
+    else:
+      raiseOSError(osLastError(), dir)
   elif defined(posix):
     let res = mkdir(dir, 0o777)
     if res == 0'i32:
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index cdb7a4466..073216e22 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -892,7 +892,7 @@ else:
           weekday {.importc: "tm_wday".},
           yearday {.importc: "tm_yday".},
           isdst {.importc: "tm_isdst".}: cint
-        when defined(linux) and defined(amd64):
+        when defined(linux) and defined(amd64) or defined(haiku):
           gmtoff {.importc: "tm_gmtoff".}: clong
           zone {.importc: "tm_zone".}: cstring
   type
diff --git a/lib/system.nim b/lib/system.nim
index 53605f9fd..de6e96611 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1365,7 +1365,7 @@ const
   hostOS* {.magic: "HostOS".}: string = ""
     ## a string that describes the host operating system. Possible values:
     ## "windows", "macosx", "linux", "netbsd", "freebsd", "openbsd", "solaris",
-    ## "aix", "standalone".
+    ## "aix", "haiku", "standalone".
 
   hostCPU* {.magic: "HostCPU".}: string = ""
     ## a string that describes the host CPU. Possible values:
diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim
index f593d4c99..c6b89afe1 100644
--- a/lib/system/ansi_c.nim
+++ b/lib/system/ansi_c.nim
@@ -59,6 +59,15 @@ elif defined(macosx) or defined(linux) or defined(freebsd) or
     SIGSEGV = cint(11)
     SIGTERM = cint(15)
     SIGPIPE = cint(13)
+elif defined(haiku):
+  const
+    SIGABRT = cint(6)
+    SIGFPE = cint(8)
+    SIGILL = cint(4)
+    SIGINT = cint(2)
+    SIGSEGV = cint(11)
+    SIGTERM = cint(15)
+    SIGPIPE = cint(7)
 else:
   when NoFakeVars:
     {.error: "SIGABRT not ported to your platform".}
@@ -74,6 +83,8 @@ else:
 
 when defined(macosx):
   const SIGBUS = cint(10)
+elif defined(haiku):
+  const SIGBUS = cint(30)
 else:
   template SIGBUS: untyped = SIGSEGV
 
diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim
index 85c796ba0..06e89f130 100644
--- a/lib/system/osalloc.nim
+++ b/lib/system/osalloc.nim
@@ -207,6 +207,9 @@ elif defined(posix):
     # some arches like mips and alpha use different values
     const MAP_ANONYMOUS = 0x20
     const MAP_PRIVATE = 0x02        # Changes are private
+  elif defined(haiku):
+    const MAP_ANONYMOUS = 0x08
+    const MAP_PRIVATE = 0x02
   else:
     var
       MAP_ANONYMOUS {.importc: "MAP_ANONYMOUS", header: "<sys/mman.h>".}: cint
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index 3bfaa1dc2..2434ea21e 100644
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -162,10 +162,12 @@ elif defined(genode):
       mainTls
 
 else:
-  when not defined(macosx):
+  when not (defined(macosx) or defined(haiku)):
     {.passL: "-pthread".}
 
-  {.passC: "-pthread".}
+  when not defined(haiku):
+    {.passC: "-pthread".}
+
   const
     schedh = "#define _GNU_SOURCE\n#include <sched.h>"
     pthreadh = "#define _GNU_SOURCE\n#include <pthread.h>"
@@ -714,3 +716,13 @@ elif defined(solaris):
     if threadId == 0:
       threadId = int(thr_self())
     result = threadId
+
+elif defined(haiku):
+  type thr_id {.importc: "thread_id", header: "<OS.h>".} = distinct int32
+  proc find_thread(name: cstring): thr_id {.importc, header: "<OS.h>".}
+
+  proc getThreadId*(): int =
+    ## get the ID of the currently running thread.
+    if threadId == 0:
+      threadId = int(find_thread(nil))
+    result = threadId
diff --git a/tests/osproc/texitsignal.nim b/tests/osproc/texitsignal.nim
index c0bed70ee..fbf5068ea 100644
--- a/tests/osproc/texitsignal.nim
+++ b/tests/osproc/texitsignal.nim
@@ -28,9 +28,12 @@ if paramCount() == 0:
     # windows kill happens using TerminateProcess(h, 0), so we should get a
     # 0 here
     echo p.waitForExit() == 0
+  elif defined(haiku):
+    # on Haiku, the program main thread receive SIGKILLTHR
+    echo p.waitForExit() == 128 + SIGKILLTHR
   else:
     # on posix (non-windows), kill sends SIGKILL
     echo p.waitForExit() == 128 + SIGKILL
 
 else:
-  sleep(5000)  # should get killed before this
\ No newline at end of file
+  sleep(5000)  # should get killed before this
diff --git a/tests/osproc/tworkingdir.nim b/tests/osproc/tworkingdir.nim
index eeed9240d..7d58d5ae6 100644
--- a/tests/osproc/tworkingdir.nim
+++ b/tests/osproc/tworkingdir.nim
@@ -12,6 +12,8 @@ else:
   var process: Process
   when defined(android):
     process = startProcess("/system/bin/env", "/system/bin", ["true"])
+  elif defined(haiku):
+    process = startProcess("/bin/env", "/bin", ["true"])
   else:
     process = startProcess("/usr/bin/env", "/usr/bin", ["true"])
   let dir2 = getCurrentDir()
diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim
index 95521449a..fca6927d4 100644
--- a/tests/testament/categories.nim
+++ b/tests/testament/categories.nim
@@ -109,10 +109,14 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) =
     safeCopyFile("lib" / nimrtlDll, "tests/dll" / nimrtlDll)
   else:
     # posix relies on crappy LD_LIBRARY_PATH (ugh!):
-    var libpath = getEnv"LD_LIBRARY_PATH".string
+    const libpathenv = when defined(haiku):
+                         "LIBRARY_PATH"
+                       else:
+                         "LD_LIBRARY_PATH"
+    var libpath = getEnv(libpathenv).string
     # Temporarily add the lib directory to LD_LIBRARY_PATH:
-    putEnv("LD_LIBRARY_PATH", "tests/dll" & (if libpath.len > 0: ":" & libpath else: ""))
-    defer: putEnv("LD_LIBRARY_PATH", libpath)
+    putEnv(libpathenv, "tests/dll" & (if libpath.len > 0: ":" & libpath else: ""))
+    defer: putEnv(libpathenv, libpath)
     var nimrtlDll = DynlibFormat % "nimrtl"
     safeCopyFile("lib" / nimrtlDll, "tests/dll" / nimrtlDll)
 
-- 
cgit 1.4.1-2-gfad0


From ed9fd2b63cde3b82dac26bbe9f92634cfd009884 Mon Sep 17 00:00:00 2001
From: Timothee Cour <timothee.cour2@gmail.com>
Date: Tue, 14 Aug 2018 01:44:28 -0700
Subject: fixes #8577, fixes #8580, other bug fixes (#8584)

---
 lib/pure/collections/sequtils.nim | 124 ++++++++++++++++++++++++++------------
 1 file changed, 86 insertions(+), 38 deletions(-)

(limited to 'lib/pure')

diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index 99ce91979..c8080546a 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -25,6 +25,28 @@ import macros
 when not defined(nimhygiene):
   {.pragma: dirty.}
 
+
+macro evalOnceAs(expAlias, exp: untyped, letAssigneable: static[bool]): untyped =
+  ## Injects ``expAlias`` in caller scope, to avoid bugs involving multiple
+  ##  substitution in macro arguments such as
+  ## https://github.com/nim-lang/Nim/issues/7187
+  ## ``evalOnceAs(myAlias, myExp)`` will behave as ``let myAlias = myExp``
+  ## except when ``letAssigneable`` is false (eg to handle openArray) where
+  ## it just forwards ``exp`` unchanged
+  expectKind(expAlias, nnkIdent)
+  var val = exp
+
+  result = newStmtList()
+  # If `exp` is not a symbol we evaluate it once here and then use the temporary
+  # symbol as alias
+  if exp.kind != nnkSym and letAssigneable:
+    val = genSym()
+    result.add(newLetStmt(val, exp))
+
+  result.add(
+    newProc(name = genSym(nskTemplate, $expAlias), params = [getType(untyped)],
+      body = val, procType = nnkTemplateDef))
+
 proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
   ## Takes several sequences' items and returns them inside a new sequence.
   ##
@@ -635,30 +657,7 @@ template mapIt*(s, typ, op: untyped): untyped =
     result.add(op)
   result
 
-# This is needed in order not to break the bootstrap, the fallback
-# implementation is a "dumb" let that won't work in some cases (eg. when `exp`
-# is an openArray)
-when declared(macros.symKind):
-  macro evalOnce(v, exp: untyped): untyped =
-    expectKind(v, nnkIdent)
-    var val = exp
-
-    result = newStmtList()
-
-    # Not a parameter we can pass as-is, evaluate and store in a temporary
-    # variable
-    if exp.kind != nnkSym or exp.symKind != nskParam:
-      val = genSym()
-      result.add(newLetStmt(val, exp))
-
-    result.add(
-      newProc(name = genSym(nskTemplate, $v), params = [getType(untyped)],
-        body = val, procType = nnkTemplateDef))
-else:
-  macro evalOnce(v, exp: untyped): untyped =
-    result = newLetStmt(v, exp)
-
-template mapIt*(s, op: untyped): untyped =
+template mapIt*(s: typed, op: untyped): untyped =
   ## Convenience template around the ``map`` proc to reduce typing.
   ##
   ## The template injects the ``it`` variable which you can use directly in an
@@ -675,19 +674,24 @@ template mapIt*(s, op: untyped): untyped =
     block:
       var it{.inject.}: type(items(s));
       op))
-  var result: seq[outType]
   when compiles(s.len):
-    evalOnce(t, s)
-    var i = 0
-    result = newSeq[outType](t.len)
-    for it {.inject.} in t:
-      result[i] = op
-      i += 1
+    block: # using a block avoids https://github.com/nim-lang/Nim/issues/8580
+
+      # BUG: `evalOnceAs(s2, s, false)` would lead to C compile errors
+      # (`error: use of undeclared identifier`) instead of Nim compile errors
+      evalOnceAs(s2, s, compiles((let _ = s)))
+
+      var i = 0
+      var result = newSeq[outType](s2.len)
+      for it {.inject.} in s2:
+        result[i] = op
+        i += 1
+      result
   else:
-    result = @[]
+    var result: seq[outType] = @[]
     for it {.inject.} in s:
       result.add(op)
-  result
+    result
 
 template applyIt*(varSeq, op: untyped) =
   ## Convenience template around the mutable ``apply`` proc to reduce typing.
@@ -774,6 +778,14 @@ macro mapLiterals*(constructor, op: untyped;
 
 when isMainModule:
   import strutils
+
+  # helper for testing double substitution side effects which are handled
+  # by `evalOnceAs`
+  var counter = 0
+  proc identity[T](a:T):auto=
+    counter.inc
+    a
+
   block: # concat test
     let
       s1 = @[1, 2, 3]
@@ -1045,10 +1057,12 @@ when isMainModule:
     assert multiplication == 495, "Multiplication is (5*(9*(11)))"
     assert concatenation == "nimiscool"
 
-  block: # mapIt tests
+  block: # mapIt + applyIt test
+    counter = 0
     var
       nums = @[1, 2, 3, 4]
-      strings = nums.mapIt($(4 * it))
+      strings = nums.identity.mapIt($(4 * it))
+    doAssert counter == 1
     nums.applyIt(it * 3)
     assert nums[0] + nums[3] == 15
     assert strings[2] == "12"
@@ -1067,9 +1081,43 @@ when isMainModule:
     doAssert mapLiterals(([1], ("abc"), 2), `$`, nested=true) == (["1"], "abc", "2")
 
   block: # mapIt with openArray
-    when declared(macros.symKind):
-      proc foo(x: openArray[int]): seq[int] = x.mapIt(it + 1)
-      doAssert foo([1,2,3]) == @[2,3,4]
+    counter = 0
+    proc foo(x: openArray[int]): seq[int] = x.mapIt(it * 10)
+    doAssert foo([identity(1),identity(2)]) == @[10, 20]
+    doAssert counter == 2
+
+  block: # mapIt with direct openArray
+    proc foo1(x: openArray[int]): seq[int] = x.mapIt(it * 10)
+    counter = 0
+    doAssert foo1(openArray[int]([identity(1),identity(2)])) == @[10,20]
+    doAssert counter == 2
+
+    template foo2(x: openArray[int]): seq[int] = x.mapIt(it * 10)
+    counter = 0
+    doAssert foo2(openArray[int]([identity(1),identity(2)])) == @[10,20]
+    # TODO: this fails; not sure how to fix this case
+    # doAssert counter == 2
+
+  block: # mapIt empty test, see https://github.com/nim-lang/Nim/pull/8584#pullrequestreview-144723468
+    # NOTE: `[].mapIt(it)` is illegal, just as `let a = @[]` is (lacks type
+    # of elements)
+    doAssert: not compiles(mapIt(@[], it))
+    doAssert: not compiles(mapIt([], it))
+    doAssert newSeq[int](0).mapIt(it) == @[]
+
+  block: # mapIt redifinition check, see https://github.com/nim-lang/Nim/issues/8580
+    let t = [1,2].mapIt(it)
+    doAssert t == @[1,2]
+
+  block:
+    var counter = 0
+    proc getInput():auto =
+      counter.inc
+      [1, 2]
+    doAssert getInput().mapIt(it*2).mapIt(it*10) == @[20, 40]
+    # make sure argument evaluated only once, analog to
+    # https://github.com/nim-lang/Nim/issues/7187 test case
+    doAssert counter == 1
 
   block: # mapIt with invalid RHS for `let` (#8566)
     type X = enum
-- 
cgit 1.4.1-2-gfad0