fixes merge conflict

This commit is contained in:
Andreas Rumpf 2018-06-11 01:25:48 +02:00
commit 61d9292095
24 changed files with 360 additions and 105 deletions

View file

@ -25,6 +25,8 @@ before_install:
before_script: before_script:
- set -e - set -e
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then unset -f cd; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then shell_session_update() { :; }; fi
- git clone --depth 1 https://github.com/nim-lang/csources.git - git clone --depth 1 https://github.com/nim-lang/csources.git
- cd csources - cd csources
- sh build.sh - sh build.sh

View file

@ -42,6 +42,12 @@
- ``math.`mod` `` for floats now behaves the same as ``mod`` for integers - ``math.`mod` `` for floats now behaves the same as ``mod`` for integers
(previously it used floor division like Python). Use ``math.floorMod`` for the old behavior. (previously it used floor division like Python). Use ``math.floorMod`` for the old behavior.
- For string inputs, ``unicode.isUpper`` and ``unicode.isLower`` now require a
second mandatory parameter ``skipNonAlpha``.
- For string inputs, ``strutils.isUpperAscii`` and ``strutils.isLowerAscii`` now
require a second mandatory parameter ``skipNonAlpha``.
#### Breaking changes in the compiler #### Breaking changes in the compiler
- The undocumented ``#? braces`` parsing mode was removed. - The undocumented ``#? braces`` parsing mode was removed.
@ -91,6 +97,7 @@
API". Using the Nim compiler and its VM as a scripting engine has never been API". Using the Nim compiler and its VM as a scripting engine has never been
easier. See ``tests/compilerapi/tcompilerapi.nim`` for an example of how to easier. See ``tests/compilerapi/tcompilerapi.nim`` for an example of how to
use the Nim VM in a native Nim application. use the Nim VM in a native Nim application.
- Added the parameter ``val`` for the ``CritBitTree[T].incl`` proc.
- The proc ``tgamma`` was renamed to ``gamma``. ``tgamma`` is deprecated. - The proc ``tgamma`` was renamed to ``gamma``. ``tgamma`` is deprecated.

View file

@ -731,8 +731,6 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
else: addAbiCheck(m, t, result) else: addAbiCheck(m, t, result)
of tyObject, tyTuple: of tyObject, tyTuple:
if isImportedCppType(t) and origTyp.kind == tyGenericInst: if isImportedCppType(t) and origTyp.kind == tyGenericInst:
# for instantiated templates we do not go through the type cache as the
# the type cache is not aware of 'tyGenericInst'.
let cppName = getTypeName(m, t, sig) let cppName = getTypeName(m, t, sig)
var i = 0 var i = 0
var chunkStart = 0 var chunkStart = 0

View file

@ -1036,14 +1036,19 @@ proc genMainProc(m: BModule) =
"}$N$N" "}$N$N"
GenodeNimMain = GenodeNimMain =
"Libc::Env *genodeEnv;$N" & "extern Genode::Env *nim_runtime_env;$N" &
"extern void nim_component_construct(Genode::Env*);$N$N" &
NimMainBody NimMainBody
ComponentConstruct = ComponentConstruct =
"void Libc::Component::construct(Libc::Env &env) {$N" & "void Libc::Component::construct(Libc::Env &env) {$N" &
"\tgenodeEnv = &env;$N" & "\t// Set Env used during runtime initialization$N" &
"\tnim_runtime_env = &env;$N" &
"\tLibc::with_libc([&] () {$N\t" & "\tLibc::with_libc([&] () {$N\t" &
"\t// Initialize runtime and globals$N" &
MainProcs & MainProcs &
"\t// Call application construct$N" &
"\t\tnim_component_construct(&env);$N" &
"\t});$N" & "\t});$N" &
"}$N$N" "}$N$N"
@ -1060,6 +1065,7 @@ proc genMainProc(m: BModule) =
elif m.config.target.targetOS == osGenode: elif m.config.target.targetOS == osGenode:
nimMain = GenodeNimMain nimMain = GenodeNimMain
otherMain = ComponentConstruct otherMain = ComponentConstruct
m.includeHeader("<libc/component.h>")
elif optGenDynLib in m.config.globalOptions: elif optGenDynLib in m.config.globalOptions:
nimMain = PosixNimDllMain nimMain = PosixNimDllMain
otherMain = PosixCDllMain otherMain = PosixCDllMain

View file

@ -496,7 +496,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
def = fitNode(c, typ, def, def.info) def = fitNode(c, typ, def, def.info)
#changeType(def.skipConv, typ, check=true) #changeType(def.skipConv, typ, check=true)
else: else:
typ = skipIntLit(def.typ) typ = def.typ.skipTypes({tyStatic}).skipIntLit
if typ.kind in tyUserTypeClasses and typ.isResolvedUserTypeClass: if typ.kind in tyUserTypeClasses and typ.isResolvedUserTypeClass:
typ = typ.lastSon typ = typ.lastSon
if hasEmpty(typ): if hasEmpty(typ):

View file

@ -12,7 +12,7 @@
import ast, md5, tables, ropes import ast, md5, tables, ropes
from hashes import Hash from hashes import Hash
from astalgo import debug from astalgo import debug
from types import typeToString, preferDesc import types
from strutils import startsWith, contains from strutils import startsWith, contains
when false: when false:
@ -148,19 +148,23 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
of tyGenericInvocation: of tyGenericInvocation:
for i in countup(0, sonsLen(t) - 1): for i in countup(0, sonsLen(t) - 1):
c.hashType t.sons[i], flags c.hashType t.sons[i], flags
return
of tyDistinct: of tyDistinct:
if CoType in flags: if CoType in flags:
c.hashType t.lastSon, flags c.hashType t.lastSon, flags
else: else:
c.hashSym(t.sym) c.hashSym(t.sym)
return of tyGenericInst:
of tyAlias, tySink, tyGenericInst, tyUserTypeClasses: if sfInfixCall in t.base.sym.flags:
# This is an imported C++ generic type.
# We cannot trust the `lastSon` to hold a properly populated and unique
# value for each instantiation, so we hash the generic parameters here:
let normalizedType = t.skipGenericAlias
for i in 0 .. normalizedType.len - 2:
c.hashType t.sons[i], flags
else:
c.hashType t.lastSon, flags
of tyAlias, tySink, tyUserTypeClasses:
c.hashType t.lastSon, flags c.hashType t.lastSon, flags
return
else:
discard
case t.kind
of tyBool, tyChar, tyInt..tyUInt64: of tyBool, tyChar, tyInt..tyUInt64:
# no canonicalization for integral types, so that e.g. ``pid_t`` is # no canonicalization for integral types, so that e.g. ``pid_t`` is
# produced instead of ``NI``: # produced instead of ``NI``:
@ -168,11 +172,12 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
if t.sym != nil and {sfImportc, sfExportc} * t.sym.flags != {}: if t.sym != nil and {sfImportc, sfExportc} * t.sym.flags != {}:
c.hashSym(t.sym) c.hashSym(t.sym)
of tyObject, tyEnum: of tyObject, tyEnum:
c &= char(t.kind)
if t.typeInst != nil: if t.typeInst != nil:
assert t.typeInst.kind == tyGenericInst assert t.typeInst.kind == tyGenericInst
for i in countup(1, sonsLen(t.typeInst) - 2): for i in countup(0, sonsLen(t.typeInst) - 2):
c.hashType t.typeInst.sons[i], flags c.hashType t.typeInst.sons[i], flags
return
c &= char(t.kind)
# Every cyclic type in Nim need to be constructed via some 't.sym', so this # Every cyclic type in Nim need to be constructed via some 't.sym', so this
# is actually safe without an infinite recursion check: # is actually safe without an infinite recursion check:
if t.sym != nil: if t.sym != nil:

View file

@ -8,10 +8,15 @@
# #
# Low level dataspace allocator for Genode. # Low level dataspace allocator for Genode.
# For interacting with dataspaces outside of the
# standard library see the Genode Nimble package.
when not defined(genode): when not defined(genode):
{.error: "Genode only module".} {.error: "Genode only module".}
when not declared(GenodeEnv):
include genode/env
type DataspaceCapability {. type DataspaceCapability {.
importcpp: "Genode::Dataspace_capability", pure.} = object importcpp: "Genode::Dataspace_capability", pure.} = object
@ -31,35 +36,35 @@ type
const SlabBackendSize = 4096 const SlabBackendSize = 4096
proc ramAvail(): int {. proc ramAvail(env: GenodeEnv): int {.
importcpp: "genodeEnv->pd().avail_ram().value".} importcpp: "#->pd().avail_ram().value".}
## Return number of bytes available for allocation. ## Return number of bytes available for allocation.
proc capsAvail(): int {. proc capsAvail(env: GenodeEnv): int {.
importcpp: "genodeEnv->pd().avail_caps().value".} importcpp: "#->pd().avail_caps().value".}
## Return the number of available capabilities. ## Return the number of available capabilities.
## Each dataspace allocation consumes a capability. ## Each dataspace allocation consumes a capability.
proc allocDataspace(size: int): DataspaceCapability {. proc allocDataspace(env: GenodeEnv; size: int): DataspaceCapability {.
importcpp: "genodeEnv->pd().alloc(@)".} importcpp: "#->pd().alloc(@)".}
## Allocate a dataspace and its capability. ## Allocate a dataspace and its capability.
proc attachDataspace(ds: DataspaceCapability): pointer {. proc attachDataspace(env: GenodeEnv; ds: DataspaceCapability): pointer {.
importcpp: "genodeEnv->rm().attach(@)".} importcpp: "#->rm().attach(@)".}
## Attach a dataspace into the component address-space. ## Attach a dataspace into the component address-space.
proc detachAddress(p: pointer) {. proc detachAddress(env: GenodeEnv; p: pointer) {.
importcpp: "genodeEnv->rm().detach(@)".} importcpp: "#->rm().detach(@)".}
## Detach a dataspace from the component address-space. ## Detach a dataspace from the component address-space.
proc freeDataspace(ds: DataspaceCapability) {. proc freeDataspace(env: GenodeEnv; ds: DataspaceCapability) {.
importcpp: "genodeEnv->pd().free(@)".} importcpp: "#->pd().free(@)".}
## Free a dataspace. ## Free a dataspace.
proc newMapSlab(): ptr MapSlab = proc newMapSlab(): ptr MapSlab =
let let
ds = allocDataspace SlabBackendSize ds = runtimeEnv.allocDataspace SlabBackendSize
p = attachDataspace ds p = runtimeEnv.attachDataspace ds
result = cast[ptr MapSlab](p) result = cast[ptr MapSlab](p)
result.meta.ds = ds result.meta.ds = ds
@ -89,13 +94,13 @@ proc osAllocPages(size: int): pointer =
# tack a new slab on the tail # tack a new slab on the tail
slab = slab.meta.next slab = slab.meta.next
# move to next slab in linked list # move to next slab in linked list
map.ds = allocDataspace size map.ds = runtimeEnv.allocDataspace size
map.size = size map.size = size
map.attachment = attachDataspace map.ds map.attachment = runtimeEnv.attachDataspace map.ds
result = map.attachment result = map.attachment
proc osTryAllocPages(size: int): pointer = proc osTryAllocPages(size: int): pointer =
if ramAvail() >= size and capsAvail() > 1: if runtimeEnv.ramAvail() >= size and runtimeEnv.capsAvail() > 4:
result = osAllocPages size result = osAllocPages size
proc osDeallocPages(p: pointer; size: int) = proc osDeallocPages(p: pointer; size: int) =
@ -107,8 +112,8 @@ proc osDeallocPages(p: pointer; size: int) =
if m.size != size: if m.size != size:
echo "cannot partially detach dataspace" echo "cannot partially detach dataspace"
quit -1 quit -1
detachAddress m.attachment runtimeEnv.detachAddress m.attachment
freeDataspace m.ds runtimeEnv.freeDataspace m.ds
m[] = Map() m[] = Map()
return return
slab = slab.meta.next slab = slab.meta.next

29
lib/genode/env.nim Normal file
View file

@ -0,0 +1,29 @@
#
#
# Nim's Runtime Library
# (c) Copyright 2018 Emery Hemingway
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
#
# This file contains the minimum required definitions
# for interacting with the initial Genode environment.
# It is reserved for use only within the standard
# library. See ``componentConstructHook`` in the system
# module for accessing the Genode environment after the
# standard library has finished initializating.
#
when not defined(genode):
{.error: "Genode only include".}
type
GenodeEnvObj {.importcpp: "Genode::Env", header: "<base/env.h>", pure.} = object
GenodeEnvPtr = ptr GenodeEnvObj
const runtimeEnvSym = "nim_runtime_env"
when not defined(nimscript):
var runtimeEnv {.importcpp: runtimeEnvSym.}: GenodeEnvPtr

View file

@ -13,6 +13,7 @@
#define _GENODE_CPP__THREAD_H_ #define _GENODE_CPP__THREAD_H_
#include <base/thread.h> #include <base/thread.h>
#include <base/env.h>
#include <util/reconstructible.h> #include <util/reconstructible.h>
namespace Nim { struct SysThread; } namespace Nim { struct SysThread; }

View file

@ -502,11 +502,6 @@ typedef int Nim_and_C_compiler_disagree_on_target_architecture[sizeof(NI) == siz
# include <sys/types.h> # include <sys/types.h>
#endif #endif
#if defined(__GENODE__)
#include <libc/component.h>
extern Libc::Env *genodeEnv;
#endif
/* Compile with -d:checkAbi and a sufficiently C11:ish compiler to enable */ /* Compile with -d:checkAbi and a sufficiently C11:ish compiler to enable */
#define NIM_CHECK_SIZE(typ, sz) \ #define NIM_CHECK_SIZE(typ, sz) \
_Static_assert(sizeof(typ) == sz, "Nim & C disagree on type size") _Static_assert(sizeof(typ) == sz, "Nim & C disagree on type size")

View file

@ -129,6 +129,20 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
proc sendStatus(client: AsyncSocket, status: string): Future[void] = proc sendStatus(client: AsyncSocket, status: string): Future[void] =
client.send("HTTP/1.1 " & status & "\c\L\c\L") client.send("HTTP/1.1 " & status & "\c\L\c\L")
proc parseUppercaseMethod(name: string): HttpMethod =
result =
case name
of "GET": HttpGet
of "POST": HttpPost
of "HEAD": HttpHead
of "PUT": HttpPut
of "DELETE": HttpDelete
of "PATCH": HttpPatch
of "OPTIONS": HttpOptions
of "CONNECT": HttpConnect
of "TRACE": HttpTrace
else: raise newException(ValueError, "Invalid HTTP method " & name)
proc processRequest(server: AsyncHttpServer, req: FutureVar[Request], proc processRequest(server: AsyncHttpServer, req: FutureVar[Request],
client: AsyncSocket, client: AsyncSocket,
address: string, lineFut: FutureVar[string], address: string, lineFut: FutureVar[string],
@ -172,8 +186,7 @@ proc processRequest(server: AsyncHttpServer, req: FutureVar[Request],
case i case i
of 0: of 0:
try: try:
# TODO: this is likely slow. request.reqMethod = parseUppercaseMethod(linePart)
request.reqMethod = parseEnum[HttpMethod]("http" & linePart)
except ValueError: except ValueError:
asyncCheck request.respondError(Http400) asyncCheck request.respondError(Http400)
return return

View file

@ -165,16 +165,18 @@ proc containsOrIncl*(c: var CritBitTree[void], key: string): bool =
proc inc*(c: var CritBitTree[int]; key: string, val: int = 1) = proc inc*(c: var CritBitTree[int]; key: string, val: int = 1) =
## increments `c[key]` by `val`. ## increments `c[key]` by `val`.
let oldCount = c.count
var n = rawInsert(c, key) var n = rawInsert(c, key)
if c.count >= oldCount or oldCount == 0: inc n.val, val
# not a new key:
inc n.val, val
proc incl*(c: var CritBitTree[void], key: string) = proc incl*(c: var CritBitTree[void], key: string) =
## includes `key` in `c`. ## includes `key` in `c`.
discard rawInsert(c, key) discard rawInsert(c, key)
proc incl*[T](c: var CritBitTree[T], key: string, val: T) =
## inserts `key` with value `val` into `c`.
var n = rawInsert(c, key)
n.val = val
proc `[]=`*[T](c: var CritBitTree[T], key: string, val: T) = proc `[]=`*[T](c: var CritBitTree[T], key: string, val: T) =
## puts a (key, value)-pair into `t`. ## puts a (key, value)-pair into `t`.
var n = rawInsert(c, key) var n = rawInsert(c, key)
@ -375,3 +377,18 @@ when isMainModule:
c.inc("a", 1) c.inc("a", 1)
assert c["a"] == 1 assert c["a"] == 1
var cf = CritBitTree[float]()
cf.incl("a", 1.0)
assert cf["a"] == 1.0
cf.incl("b", 2.0)
assert cf["b"] == 2.0
cf.incl("c", 3.0)
assert cf["c"] == 3.0
assert cf.len == 3
cf.excl("c")
assert cf.len == 2

View file

@ -38,8 +38,10 @@ when defined(macosx) or defined(bsd):
importc: "sysctl", nodecl.} importc: "sysctl", nodecl.}
when defined(genode): when defined(genode):
proc affinitySpaceTotal(): cuint {. include genode/env
importcpp: "genodeEnv->cpu().affinity_space().total()".}
proc affinitySpaceTotal(env: GenodeEnvPtr): cuint {.
importcpp: "@->cpu().affinity_space().total()".}
proc countProcessors*(): int {.rtl, extern: "ncpi$1".} = proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
## returns the numer of the processors/cores the machine has. ## returns the numer of the processors/cores the machine has.
@ -83,7 +85,7 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
var SC_NPROC_ONLN {.importc: "_SC_NPROC_ONLN", header: "<unistd.h>".}: cint var SC_NPROC_ONLN {.importc: "_SC_NPROC_ONLN", header: "<unistd.h>".}: cint
result = sysconf(SC_NPROC_ONLN) result = sysconf(SC_NPROC_ONLN)
elif defined(genode): elif defined(genode):
result = affinitySpaceTotal().int result = runtimeEnv.affinitySpaceTotal().int
else: else:
result = sysconf(SC_NPROCESSORS_ONLN) result = sysconf(SC_NPROCESSORS_ONLN)
if result <= 0: result = 0 if result <= 0: result = 0

View file

@ -447,7 +447,7 @@ proc fromSockAddr*(sa: Sockaddr_storage | SockAddr | Sockaddr_in | Sockaddr_in6,
sl: Socklen, address: var IpAddress, port: var Port) {.inline.} = sl: Socklen, address: var IpAddress, port: var Port) {.inline.} =
## Converts `SockAddr` and `Socklen` to `IpAddress` and `Port`. Raises ## Converts `SockAddr` and `Socklen` to `IpAddress` and `Port`. Raises
## `ObjectConversionError` in case of invalid `sa` and `sl` arguments. ## `ObjectConversionError` in case of invalid `sa` and `sl` arguments.
fromSockAddrAux(unsafeAddr sa, sl, address, port) fromSockAddrAux(cast[ptr Sockaddr_storage](unsafeAddr sa), sl, address, port)
when defineSsl: when defineSsl:
CRYPTO_malloc_init() CRYPTO_malloc_init()

View file

@ -1440,7 +1440,7 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} =
elif defined(solaris): elif defined(solaris):
result = getApplAux("/proc/" & $getpid() & "/path/a.out") result = getApplAux("/proc/" & $getpid() & "/path/a.out")
elif defined(genode): elif defined(genode):
raiseOSError("POSIX command line not supported") raiseOSError(OSErrorCode(-1), "POSIX command line not supported")
elif defined(freebsd) or defined(dragonfly): elif defined(freebsd) or defined(dragonfly):
result = getApplFreebsd() result = getApplFreebsd()
# little heuristic that may work on other POSIX-like systems: # little heuristic that may work on other POSIX-like systems:

View file

@ -150,23 +150,52 @@ proc isSpaceAscii*(s: string): bool {.noSideEffect, procvar,
## characters and there is at least one character in `s`. ## characters and there is at least one character in `s`.
isImpl isSpaceAscii isImpl isSpaceAscii
proc isLowerAscii*(s: string): bool {.noSideEffect, procvar, template isCaseImpl(s, charProc, skipNonAlpha) =
rtl, extern: "nsuIsLowerAsciiStr".} = var hasAtleastOneAlphaChar = false
## Checks whether or not `s` contains all lower case characters. if s.len == 0: return false
## for c in s:
## This checks ASCII characters only. if skipNonAlpha:
## Returns true if all characters in `s` are lower case var charIsAlpha = c.isAlphaAscii()
## and there is at least one character in `s`. if not hasAtleastOneAlphaChar:
isImpl isLowerAscii hasAtleastOneAlphaChar = charIsAlpha
if charIsAlpha and (not charProc(c)):
return false
else:
if not charProc(c):
return false
return if skipNonAlpha: hasAtleastOneAlphaChar else: true
proc isUpperAscii*(s: string): bool {.noSideEffect, procvar, proc isLowerAscii*(s: string, skipNonAlpha: bool): bool =
rtl, extern: "nsuIsUpperAsciiStr".} = ## Checks whether ``s`` is lower case.
## Checks whether or not `s` contains all upper case characters.
## ##
## This checks ASCII characters only. ## This checks ASCII characters only.
## Returns true if all characters in `s` are upper case ##
## and there is at least one character in `s`. ## If ``skipNonAlpha`` is true, returns true if all alphabetical
isImpl isUpperAscii ## characters in ``s`` are lower case. Returns false if none of the
## characters in ``s`` are alphabetical.
##
## If ``skipNonAlpha`` is false, returns true only if all characters
## in ``s`` are alphabetical and lower case.
##
## For either value of ``skipNonAlpha``, returns false if ``s`` is
## an empty string.
isCaseImpl(s, isLowerAscii, skipNonAlpha)
proc isUpperAscii*(s: string, skipNonAlpha: bool): bool =
## Checks whether ``s`` is upper case.
##
## This checks ASCII characters only.
##
## If ``skipNonAlpha`` is true, returns true if all alphabetical
## characters in ``s`` are upper case. Returns false if none of the
## characters in ``s`` are alphabetical.
##
## If ``skipNonAlpha`` is false, returns true only if all characters
## in ``s`` are alphabetical and upper case.
##
## For either value of ``skipNonAlpha``, returns false if ``s`` is
## an empty string.
isCaseImpl(s, isUpperAscii, skipNonAlpha)
proc toLowerAscii*(c: char): char {.noSideEffect, procvar, proc toLowerAscii*(c: char): char {.noSideEffect, procvar,
rtl, extern: "nsuToLowerAsciiChar".} = rtl, extern: "nsuToLowerAsciiChar".} =
@ -2516,19 +2545,34 @@ when isMainModule:
doAssert(not isLowerAscii('A')) doAssert(not isLowerAscii('A'))
doAssert(not isLowerAscii('5')) doAssert(not isLowerAscii('5'))
doAssert(not isLowerAscii('&')) doAssert(not isLowerAscii('&'))
doAssert(not isLowerAscii(' '))
doAssert isLowerAscii("abcd") doAssert isLowerAscii("abcd", false)
doAssert(not isLowerAscii("abCD")) doAssert(not isLowerAscii("33aa", false))
doAssert(not isLowerAscii("33aa")) doAssert(not isLowerAscii("a b", false))
doAssert(not isLowerAscii("abCD", true))
doAssert isLowerAscii("33aa", true)
doAssert isLowerAscii("a b", true)
doAssert isLowerAscii("1, 2, 3 go!", true)
doAssert(not isLowerAscii(" ", true))
doAssert(not isLowerAscii("(*&#@(^#$ ", true)) # None of the string chars are alphabets
doAssert isUpperAscii('A') doAssert isUpperAscii('A')
doAssert(not isUpperAscii('b')) doAssert(not isUpperAscii('b'))
doAssert(not isUpperAscii('5')) doAssert(not isUpperAscii('5'))
doAssert(not isUpperAscii('%')) doAssert(not isUpperAscii('%'))
doAssert isUpperAscii("ABC") doAssert isUpperAscii("ABC", false)
doAssert(not isUpperAscii("AAcc")) doAssert(not isUpperAscii("A#$", false))
doAssert(not isUpperAscii("A#$")) doAssert(not isUpperAscii("A B", false))
doAssert(not isUpperAscii("AAcc", true))
doAssert isUpperAscii("A#$", true)
doAssert isUpperAscii("A B", true)
doAssert isUpperAscii("1, 2, 3 GO!", true)
doAssert(not isUpperAscii(" ", true))
doAssert(not isUpperAscii("(*&#@(^#$ ", true)) # None of the string chars are alphabets
doAssert rsplit("foo bar", seps=Whitespace) == @["foo", "bar"] doAssert rsplit("foo bar", seps=Whitespace) == @["foo", "bar"]
doAssert rsplit(" foo bar", seps=Whitespace, maxsplit=1) == @[" foo", "bar"] doAssert rsplit(" foo bar", seps=Whitespace, maxsplit=1) == @[" foo", "bar"]
@ -2601,4 +2645,3 @@ bar
nonStaticTests() nonStaticTests()
staticTests() staticTests()
static: staticTests() static: staticTests()

View file

@ -1392,7 +1392,7 @@ proc isCombining*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
(c >= 0xfe20 and c <= 0xfe2f)) (c >= 0xfe20 and c <= 0xfe2f))
template runeCheck(s, runeProc) = template runeCheck(s, runeProc) =
## Common code for rune.isLower, rune.isUpper, etc ## Common code for isAlpha and isSpace.
result = if len(s) == 0: false else: true result = if len(s) == 0: false else: true
var var
@ -1403,16 +1403,6 @@ template runeCheck(s, runeProc) =
fastRuneAt(s, i, rune, doInc=true) fastRuneAt(s, i, rune, doInc=true)
result = runeProc(rune) and result result = runeProc(rune) and result
proc isUpper*(s: string): bool {.noSideEffect, procvar,
rtl, extern: "nuc$1Str".} =
## Returns true iff `s` contains all upper case unicode characters.
runeCheck(s, isUpper)
proc isLower*(s: string): bool {.noSideEffect, procvar,
rtl, extern: "nuc$1Str".} =
## Returns true iff `s` contains all lower case unicode characters.
runeCheck(s, isLower)
proc isAlpha*(s: string): bool {.noSideEffect, procvar, proc isAlpha*(s: string): bool {.noSideEffect, procvar,
rtl, extern: "nuc$1Str".} = rtl, extern: "nuc$1Str".} =
## Returns true iff `s` contains all alphabetic unicode characters. ## Returns true iff `s` contains all alphabetic unicode characters.
@ -1423,6 +1413,56 @@ proc isSpace*(s: string): bool {.noSideEffect, procvar,
## Returns true iff `s` contains all whitespace unicode characters. ## Returns true iff `s` contains all whitespace unicode characters.
runeCheck(s, isWhiteSpace) runeCheck(s, isWhiteSpace)
template runeCaseCheck(s, runeProc, skipNonAlpha) =
## Common code for rune.isLower and rune.isUpper.
if len(s) == 0: return false
var
i = 0
rune: Rune
hasAtleastOneAlphaRune = false
while i < len(s):
fastRuneAt(s, i, rune, doInc=true)
if skipNonAlpha:
var runeIsAlpha = isAlpha(rune)
if not hasAtleastOneAlphaRune:
hasAtleastOneAlphaRune = runeIsAlpha
if runeIsAlpha and (not runeProc(rune)):
return false
else:
if not runeProc(rune):
return false
return if skipNonAlpha: hasAtleastOneAlphaRune else: true
proc isLower*(s: string, skipNonAlpha: bool): bool =
## Checks whether ``s`` is lower case.
##
## If ``skipNonAlpha`` is true, returns true if all alphabetical
## runes in ``s`` are lower case. Returns false if none of the
## runes in ``s`` are alphabetical.
##
## If ``skipNonAlpha`` is false, returns true only if all runes in
## ``s`` are alphabetical and lower case.
##
## For either value of ``skipNonAlpha``, returns false if ``s`` is
## an empty string.
runeCaseCheck(s, isLower, skipNonAlpha)
proc isUpper*(s: string, skipNonAlpha: bool): bool =
## Checks whether ``s`` is upper case.
##
## If ``skipNonAlpha`` is true, returns true if all alphabetical
## runes in ``s`` are upper case. Returns false if none of the
## runes in ``s`` are alphabetical.
##
## If ``skipNonAlpha`` is false, returns true only if all runes in
## ``s`` are alphabetical and upper case.
##
## For either value of ``skipNonAlpha``, returns false if ``s`` is
## an empty string.
runeCaseCheck(s, isUpper, skipNonAlpha)
template convertRune(s, runeProc) = template convertRune(s, runeProc) =
## Convert runes in `s` using `runeProc` as the converter. ## Convert runes in `s` using `runeProc` as the converter.
result = newString(len(s)) result = newString(len(s))
@ -1755,25 +1795,39 @@ when isMainModule:
doAssert(not isSpace("")) doAssert(not isSpace(""))
doAssert(not isSpace("ΑΓc \td")) doAssert(not isSpace("ΑΓc \td"))
doAssert isLower("a") doAssert(not isLower(' '.Rune))
doAssert isLower("γ")
doAssert(not isLower("Γ"))
doAssert(not isLower("4"))
doAssert(not isLower(""))
doAssert isLower("abcdγ") doAssert isLower("a", false)
doAssert(not isLower("abCDΓ")) doAssert isLower("γ", true)
doAssert(not isLower("33aaΓ")) doAssert(not isLower("Γ", false))
doAssert(not isLower("4", true))
doAssert(not isLower("", false))
doAssert isLower("abcdγ", false)
doAssert(not isLower("33aaΓ", false))
doAssert(not isLower("a b", false))
doAssert isUpper("Γ") doAssert(not isLower("abCDΓ", true))
doAssert(not isUpper("b")) doAssert isLower("a b", true)
doAssert(not isUpper("α")) doAssert isLower("1, 2, 3 go!", true)
doAssert(not isUpper("✓")) doAssert(not isLower(" ", true))
doAssert(not isUpper("")) doAssert(not isLower("(*&#@(^#$✓ ", true)) # None of the string runes are alphabets
doAssert isUpper("ΑΒΓ") doAssert(not isUpper(' '.Rune))
doAssert(not isUpper("AAccβ"))
doAssert(not isUpper("A#$β")) doAssert isUpper("Γ", false)
doAssert(not isUpper("α", false))
doAssert(not isUpper("", false))
doAssert isUpper("ΑΒΓ", false)
doAssert(not isUpper("A#$β", false))
doAssert(not isUpper("A B", false))
doAssert(not isUpper("b", true))
doAssert(not isUpper("✓", true))
doAssert(not isUpper("AAccβ", true))
doAssert isUpper("A B", true)
doAssert isUpper("1, 2, 3 GO!", true)
doAssert(not isUpper(" ", true))
doAssert(not isUpper("(*&#@(^#$✓ ", true)) # None of the string runes are alphabets
doAssert toUpper("Γ") == "Γ" doAssert toUpper("Γ") == "Γ"
doAssert toUpper("b") == "B" doAssert toUpper("b") == "B"

View file

@ -1498,11 +1498,21 @@ when defined(nimdoc):
## macro, use the `error <manual.html#error-pragma>`_ or `fatal ## macro, use the `error <manual.html#error-pragma>`_ or `fatal
## <manual.html#fatal-pragma>`_ pragmas. ## <manual.html#fatal-pragma>`_ pragmas.
elif defined(genode): elif defined(genode):
proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn, include genode/env
importcpp: "genodeEnv->parent().exit(@); Genode::sleep_forever()",
header: "<base/sleep.h>".} var systemEnv {.exportc: runtimeEnvSym.}: GenodeEnvPtr
type GenodeEnv* = GenodeEnvPtr
## Opaque type representing Genode environment.
proc quit*(env: GenodeEnv; errorcode: int) {.magic: "Exit", noreturn,
importcpp: "#->parent().exit(@); Genode::sleep_forever()", header: "<base/sleep.h>".}
proc quit*(errorcode: int = QuitSuccess) =
systemEnv.quit(errorCode)
elif defined(nodejs): elif defined(nodejs):
proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit",
@ -4215,3 +4225,22 @@ when not defined(js):
type type
ForLoopStmt* {.compilerProc.} = object ## special type that marks a macro ForLoopStmt* {.compilerProc.} = object ## special type that marks a macro
## as a `for-loop macro`:idx: ## as a `for-loop macro`:idx:
when defined(genode):
var componentConstructHook*: proc (env: GenodeEnv) {.nimcall.}
## Hook into the Genode component bootstrap process.
## This hook is called after all globals are initialized.
## When this hook is set the component will not automatically exit,
## call ``quit`` explicitly to do so. This is the only available method
## of accessing the initial Genode environment.
proc nim_component_construct(env: GenodeEnv) {.exportc.} =
## Procedure called during ``Component::construct`` by the loader.
if componentConstructHook.isNil:
env.quit(programResult)
# No native Genode application initialization,
# exit as would POSIX.
else:
componentConstructHook(env)
# Perform application initialization
# and return to thread entrypoint.

View file

@ -78,7 +78,7 @@ when defined(emscripten):
munmap(mmapDescr.realPointer, mmapDescr.realSize) munmap(mmapDescr.realPointer, mmapDescr.realSize)
elif defined(genode): elif defined(genode):
include genodealloc # osAllocPages, osTryAllocPages, osDeallocPages include genode/alloc # osAllocPages, osTryAllocPages, osDeallocPages
elif defined(posix): elif defined(posix):
const const

View file

@ -116,6 +116,7 @@ when defined(windows):
importc: "SetThreadAffinityMask", stdcall, header: "<windows.h>".} importc: "SetThreadAffinityMask", stdcall, header: "<windows.h>".}
elif defined(genode): elif defined(genode):
import genode/env
const const
GenodeHeader = "genode_cpp/threads.h" GenodeHeader = "genode_cpp/threads.h"
type type
@ -125,11 +126,12 @@ elif defined(genode):
ThreadVarSlot = int ThreadVarSlot = int
proc initThread(s: var SysThread, proc initThread(s: var SysThread,
env: GenodeEnv,
stackSize: culonglong, stackSize: culonglong,
entry: GenodeThreadProc, entry: GenodeThreadProc,
arg: pointer, arg: pointer,
affinity: cuint) {. affinity: cuint) {.
importcpp: "#.initThread(genodeEnv, @)".} importcpp: "#.initThread(@)".}
proc threadVarAlloc(): ThreadVarSlot = 0 proc threadVarAlloc(): ThreadVarSlot = 0
@ -569,7 +571,7 @@ when hostOS == "windows":
elif defined(genode): elif defined(genode):
var affinityOffset: cuint = 1 var affinityOffset: cuint = 1
# CPU affinity offset for next thread, safe to roll-over ## CPU affinity offset for next thread, safe to roll-over
proc createThread*[TArg](t: var Thread[TArg], proc createThread*[TArg](t: var Thread[TArg],
tp: proc (arg: TArg) {.thread, nimcall.}, tp: proc (arg: TArg) {.thread, nimcall.},
@ -580,6 +582,7 @@ elif defined(genode):
t.dataFn = tp t.dataFn = tp
when hasSharedHeap: t.stackSize = ThreadStackSize when hasSharedHeap: t.stackSize = ThreadStackSize
t.sys.initThread( t.sys.initThread(
runtimeEnv,
ThreadStackSize.culonglong, ThreadStackSize.culonglong,
threadProcWrapper[TArg], addr(t), affinityOffset) threadProcWrapper[TArg], addr(t), affinityOffset)
inc affinityOffset inc affinityOffset

View file

@ -44,6 +44,10 @@ else:
const const
DLLSSLName* = "libssl" & versions & ".dylib" DLLSSLName* = "libssl" & versions & ".dylib"
DLLUtilName* = "libcrypto" & versions & ".dylib" DLLUtilName* = "libcrypto" & versions & ".dylib"
elif defined(genode):
const
DLLSSLName* = "libssl.lib.so"
DLLUtilName* = "libcrypto.lib.so"
else: else:
const const
DLLSSLName* = "libssl.so" & versions DLLSSLName* = "libssl.so" & versions

View file

@ -20,3 +20,19 @@ v.doSomething()
var vf = initVector[float]() var vf = initVector[float]()
vf.doSomething() # Nim uses doSomething[int] here in C++ vf.doSomething() # Nim uses doSomething[int] here in C++
# Alternative definition:
# https://github.com/nim-lang/Nim/issues/7653
type VectorAlt* {.importcpp: "std::vector", header: "<vector>", nodecl.} [T] = object
proc mkVector*[T]: VectorAlt[T] {.importcpp: "std::vector<'*0>()", header: "<vector>", constructor, nodecl.}
proc foo(): VectorAlt[cint] =
mkVector[cint]()
proc bar(): VectorAlt[cstring] =
mkVector[cstring]()
var x = foo()
var y = bar()

14
tests/generics/t3977.nim Normal file
View file

@ -0,0 +1,14 @@
discard """
output: "42\n42"
"""
type
Foo[N: static[int]] = object
proc foo[N](x: Foo[N]) =
let n = N
echo N
echo n
var f1: Foo[42]
f1.foo

View file

@ -66,6 +66,18 @@ block: # "IpAddress/Sockaddr conversion"
doAssert(ipaddr_1 == ipaddr_2) doAssert(ipaddr_1 == ipaddr_2)
doAssert($ipaddr_1 == $ipaddr_2) doAssert($ipaddr_1 == $ipaddr_2)
if sockaddr.ss_family == AF_INET.toInt:
var sockaddr4: Sockaddr_in
copyMem(addr sockaddr4, addr sockaddr, sizeof(sockaddr4))
fromSockAddr(sockaddr4, socklen, ipaddr_2, port_2)
elif sockaddr.ss_family == AF_INET6.toInt:
var sockaddr6: Sockaddr_in6
copyMem(addr sockaddr6, addr sockaddr, sizeof(sockaddr6))
fromSockAddr(sockaddr6, socklen, ipaddr_2, port_2)
doAssert(ipaddr_1 == ipaddr_2)
doAssert($ipaddr_1 == $ipaddr_2)
# ipv6 address of example.com # ipv6 address of example.com
test("2606:2800:220:1:248:1893:25c8:1946") test("2606:2800:220:1:248:1893:25c8:1946")