Merge branch 'devel' into araq-misc

This commit is contained in:
Andreas Rumpf
2018-08-16 01:22:21 +02:00
28 changed files with 286 additions and 71 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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)

View File

@@ -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

View File

@@ -12,7 +12,7 @@
{.deadCodeElim: on.} # dce option deprecated
when defined(Posix) and not defined(haiku):
when defined(Posix):
{.passl: "-lm".}
var

View File

@@ -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
@@ -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:

View File

@@ -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)

View File

@@ -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:

View File

@@ -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:

View File

@@ -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

View File

@@ -1327,7 +1327,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:

View File

@@ -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

View File

@@ -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

View File

@@ -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