diff options
-rw-r--r-- | .travis.yml | 2 | ||||
-rw-r--r-- | changelog.md | 7 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 2 | ||||
-rw-r--r-- | compiler/cgen.nim | 10 | ||||
-rw-r--r-- | compiler/semstmts.nim | 2 | ||||
-rw-r--r-- | compiler/sighashes.nim | 25 | ||||
-rw-r--r-- | lib/genode/alloc.nim (renamed from lib/system/genodealloc.nim) | 43 | ||||
-rw-r--r-- | lib/genode/env.nim | 29 | ||||
-rw-r--r-- | lib/genode_cpp/threads.h | 1 | ||||
-rw-r--r-- | lib/nimbase.h | 5 | ||||
-rw-r--r-- | lib/pure/asynchttpserver.nim | 17 | ||||
-rw-r--r-- | lib/pure/collections/critbits.nim | 25 | ||||
-rw-r--r-- | lib/pure/concurrency/cpuinfo.nim | 8 | ||||
-rw-r--r-- | lib/pure/net.nim | 2 | ||||
-rw-r--r-- | lib/pure/os.nim | 2 | ||||
-rw-r--r-- | lib/pure/strutils.nim | 81 | ||||
-rw-r--r-- | lib/pure/unicode.nim | 114 | ||||
-rw-r--r-- | lib/system.nim | 37 | ||||
-rw-r--r-- | lib/system/osalloc.nim | 2 | ||||
-rw-r--r-- | lib/system/threads.nim | 7 | ||||
-rw-r--r-- | lib/wrappers/openssl.nim | 4 | ||||
-rw-r--r-- | tests/cpp/tempty_generic_obj.nim | 16 | ||||
-rw-r--r-- | tests/generics/t3977.nim | 14 | ||||
-rw-r--r-- | tests/stdlib/tnet.nim | 12 |
24 files changed, 361 insertions, 106 deletions
diff --git a/.travis.yml b/.travis.yml index 3bc9a9778..b7880cd36 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,6 +25,8 @@ before_install: before_script: - 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 - cd csources - sh build.sh diff --git a/changelog.md b/changelog.md index 5ba277898..959990900 100644 --- a/changelog.md +++ b/changelog.md @@ -42,6 +42,12 @@ - ``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. +- 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 - 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 easier. See ``tests/compilerapi/tcompilerapi.nim`` for an example of how to 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. diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index d0433f9ae..82508e37e 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -731,8 +731,6 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = else: addAbiCheck(m, t, result) of tyObject, tyTuple: 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) var i = 0 var chunkStart = 0 diff --git a/compiler/cgen.nim b/compiler/cgen.nim index c66b25b00..ee60e62d2 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1036,14 +1036,19 @@ proc genMainProc(m: BModule) = "}$N$N" GenodeNimMain = - "Libc::Env *genodeEnv;$N" & + "extern Genode::Env *nim_runtime_env;$N" & + "extern void nim_component_construct(Genode::Env*);$N$N" & NimMainBody ComponentConstruct = "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" & + "\t// Initialize runtime and globals$N" & MainProcs & + "\t// Call application construct$N" & + "\t\tnim_component_construct(&env);$N" & "\t});$N" & "}$N$N" @@ -1060,6 +1065,7 @@ proc genMainProc(m: BModule) = elif m.config.target.targetOS == osGenode: nimMain = GenodeNimMain otherMain = ComponentConstruct + m.includeHeader("<libc/component.h>") elif optGenDynLib in m.config.globalOptions: nimMain = PosixNimDllMain otherMain = PosixCDllMain diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 0e143e7c1..af853ec52 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -496,7 +496,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = def = fitNode(c, typ, def, def.info) #changeType(def.skipConv, typ, check=true) else: - typ = skipIntLit(def.typ) + typ = def.typ.skipTypes({tyStatic}).skipIntLit if typ.kind in tyUserTypeClasses and typ.isResolvedUserTypeClass: typ = typ.lastSon if hasEmpty(typ): diff --git a/compiler/sighashes.nim b/compiler/sighashes.nim index 46b83c386..0b95387cd 100644 --- a/compiler/sighashes.nim +++ b/compiler/sighashes.nim @@ -12,7 +12,7 @@ import ast, md5, tables, ropes from hashes import Hash from astalgo import debug -from types import typeToString, preferDesc +import types from strutils import startsWith, contains when false: @@ -148,19 +148,23 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) = of tyGenericInvocation: for i in countup(0, sonsLen(t) - 1): c.hashType t.sons[i], flags - return of tyDistinct: if CoType in flags: c.hashType t.lastSon, flags else: c.hashSym(t.sym) - return - of tyAlias, tySink, tyGenericInst, tyUserTypeClasses: + of tyGenericInst: + 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 - return - else: - discard - case t.kind of tyBool, tyChar, tyInt..tyUInt64: # no canonicalization for integral types, so that e.g. ``pid_t`` is # 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 != {}: c.hashSym(t.sym) of tyObject, tyEnum: - c &= char(t.kind) if t.typeInst != nil: 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 + return + c &= char(t.kind) # Every cyclic type in Nim need to be constructed via some 't.sym', so this # is actually safe without an infinite recursion check: if t.sym != nil: diff --git a/lib/system/genodealloc.nim b/lib/genode/alloc.nim index 3646a842d..52dc1c32c 100644 --- a/lib/system/genodealloc.nim +++ b/lib/genode/alloc.nim @@ -8,10 +8,15 @@ # # Low level dataspace allocator for Genode. +# For interacting with dataspaces outside of the +# standard library see the Genode Nimble package. when not defined(genode): {.error: "Genode only module".} +when not declared(GenodeEnv): + include genode/env + type DataspaceCapability {. importcpp: "Genode::Dataspace_capability", pure.} = object @@ -31,35 +36,35 @@ type const SlabBackendSize = 4096 -proc ramAvail(): int {. - importcpp: "genodeEnv->pd().avail_ram().value".} +proc ramAvail(env: GenodeEnv): int {. + importcpp: "#->pd().avail_ram().value".} ## Return number of bytes available for allocation. -proc capsAvail(): int {. - importcpp: "genodeEnv->pd().avail_caps().value".} +proc capsAvail(env: GenodeEnv): int {. + importcpp: "#->pd().avail_caps().value".} ## Return the number of available capabilities. ## Each dataspace allocation consumes a capability. -proc allocDataspace(size: int): DataspaceCapability {. - importcpp: "genodeEnv->pd().alloc(@)".} +proc allocDataspace(env: GenodeEnv; size: int): DataspaceCapability {. + importcpp: "#->pd().alloc(@)".} ## Allocate a dataspace and its capability. -proc attachDataspace(ds: DataspaceCapability): pointer {. - importcpp: "genodeEnv->rm().attach(@)".} +proc attachDataspace(env: GenodeEnv; ds: DataspaceCapability): pointer {. + importcpp: "#->rm().attach(@)".} ## Attach a dataspace into the component address-space. -proc detachAddress(p: pointer) {. - importcpp: "genodeEnv->rm().detach(@)".} +proc detachAddress(env: GenodeEnv; p: pointer) {. + importcpp: "#->rm().detach(@)".} ## Detach a dataspace from the component address-space. -proc freeDataspace(ds: DataspaceCapability) {. - importcpp: "genodeEnv->pd().free(@)".} +proc freeDataspace(env: GenodeEnv; ds: DataspaceCapability) {. + importcpp: "#->pd().free(@)".} ## Free a dataspace. proc newMapSlab(): ptr MapSlab = let - ds = allocDataspace SlabBackendSize - p = attachDataspace ds + ds = runtimeEnv.allocDataspace SlabBackendSize + p = runtimeEnv.attachDataspace ds result = cast[ptr MapSlab](p) result.meta.ds = ds @@ -89,13 +94,13 @@ proc osAllocPages(size: int): pointer = # tack a new slab on the tail slab = slab.meta.next # move to next slab in linked list - map.ds = allocDataspace size + map.ds = runtimeEnv.allocDataspace size map.size = size - map.attachment = attachDataspace map.ds + map.attachment = runtimeEnv.attachDataspace map.ds result = map.attachment proc osTryAllocPages(size: int): pointer = - if ramAvail() >= size and capsAvail() > 1: + if runtimeEnv.ramAvail() >= size and runtimeEnv.capsAvail() > 4: result = osAllocPages size proc osDeallocPages(p: pointer; size: int) = @@ -107,8 +112,8 @@ proc osDeallocPages(p: pointer; size: int) = if m.size != size: echo "cannot partially detach dataspace" quit -1 - detachAddress m.attachment - freeDataspace m.ds + runtimeEnv.detachAddress m.attachment + runtimeEnv.freeDataspace m.ds m[] = Map() return slab = slab.meta.next diff --git a/lib/genode/env.nim b/lib/genode/env.nim new file mode 100644 index 000000000..2b180d1b3 --- /dev/null +++ b/lib/genode/env.nim @@ -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 diff --git a/lib/genode_cpp/threads.h b/lib/genode_cpp/threads.h index a7cb2f17b..c901efb45 100644 --- a/lib/genode_cpp/threads.h +++ b/lib/genode_cpp/threads.h @@ -13,6 +13,7 @@ #define _GENODE_CPP__THREAD_H_ #include <base/thread.h> +#include <base/env.h> #include <util/reconstructible.h> namespace Nim { struct SysThread; } diff --git a/lib/nimbase.h b/lib/nimbase.h index 20ac9979b..6dc742910 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -502,11 +502,6 @@ typedef int Nim_and_C_compiler_disagree_on_target_architecture[sizeof(NI) == siz # include <sys/types.h> #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 */ #define NIM_CHECK_SIZE(typ, sz) \ _Static_assert(sizeof(typ) == sz, "Nim & C disagree on type size") diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index fe5a835d7..d27c2fb9c 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -129,6 +129,20 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] = proc sendStatus(client: AsyncSocket, status: string): Future[void] = 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], client: AsyncSocket, address: string, lineFut: FutureVar[string], @@ -172,8 +186,7 @@ proc processRequest(server: AsyncHttpServer, req: FutureVar[Request], case i of 0: try: - # TODO: this is likely slow. - request.reqMethod = parseEnum[HttpMethod]("http" & linePart) + request.reqMethod = parseUppercaseMethod(linePart) except ValueError: asyncCheck request.respondError(Http400) return diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index eaba257ae..c94e08098 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -165,16 +165,18 @@ proc containsOrIncl*(c: var CritBitTree[void], key: string): bool = proc inc*(c: var CritBitTree[int]; key: string, val: int = 1) = ## increments `c[key]` by `val`. - let oldCount = c.count var n = rawInsert(c, key) - if c.count >= oldCount or oldCount == 0: - # not a new key: - inc n.val, val + inc n.val, val proc incl*(c: var CritBitTree[void], key: string) = ## includes `key` in `c`. 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) = ## puts a (key, value)-pair into `t`. var n = rawInsert(c, key) @@ -375,3 +377,18 @@ when isMainModule: c.inc("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 diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim index f01488811..6d41aa1b2 100644 --- a/lib/pure/concurrency/cpuinfo.nim +++ b/lib/pure/concurrency/cpuinfo.nim @@ -38,8 +38,10 @@ when defined(macosx) or defined(bsd): importc: "sysctl", nodecl.} when defined(genode): - proc affinitySpaceTotal(): cuint {. - importcpp: "genodeEnv->cpu().affinity_space().total()".} + include genode/env + + proc affinitySpaceTotal(env: GenodeEnvPtr): cuint {. + importcpp: "@->cpu().affinity_space().total()".} proc countProcessors*(): int {.rtl, extern: "ncpi$1".} = ## 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 result = sysconf(SC_NPROC_ONLN) elif defined(genode): - result = affinitySpaceTotal().int + result = runtimeEnv.affinitySpaceTotal().int else: result = sysconf(SC_NPROCESSORS_ONLN) if result <= 0: result = 0 diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 60817484a..5d2efebee 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -447,7 +447,7 @@ proc fromSockAddr*(sa: Sockaddr_storage | SockAddr | Sockaddr_in | Sockaddr_in6, sl: Socklen, address: var IpAddress, port: var Port) {.inline.} = ## Converts `SockAddr` and `Socklen` to `IpAddress` and `Port`. Raises ## `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: CRYPTO_malloc_init() diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 696313e4d..3bc87728b 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1440,7 +1440,7 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} = elif defined(solaris): result = getApplAux("/proc/" & $getpid() & "/path/a.out") elif defined(genode): - raiseOSError("POSIX command line not supported") + raiseOSError(OSErrorCode(-1), "POSIX command line not supported") elif defined(freebsd) or defined(dragonfly): result = getApplFreebsd() # little heuristic that may work on other POSIX-like systems: diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index a4fd20fdb..bea0a0243 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -150,23 +150,52 @@ proc isSpaceAscii*(s: string): bool {.noSideEffect, procvar, ## characters and there is at least one character in `s`. isImpl isSpaceAscii -proc isLowerAscii*(s: string): bool {.noSideEffect, procvar, - rtl, extern: "nsuIsLowerAsciiStr".} = - ## Checks whether or not `s` contains all lower case characters. +template isCaseImpl(s, charProc, skipNonAlpha) = + var hasAtleastOneAlphaChar = false + if s.len == 0: return false + for c in s: + if skipNonAlpha: + var charIsAlpha = c.isAlphaAscii() + if not hasAtleastOneAlphaChar: + hasAtleastOneAlphaChar = charIsAlpha + if charIsAlpha and (not charProc(c)): + return false + else: + if not charProc(c): + return false + return if skipNonAlpha: hasAtleastOneAlphaChar else: true + +proc isLowerAscii*(s: string, skipNonAlpha: bool): bool = + ## Checks whether ``s`` is lower case. ## ## This checks ASCII characters only. - ## Returns true if all characters in `s` are lower case - ## and there is at least one character in `s`. - isImpl isLowerAscii + ## + ## If ``skipNonAlpha`` is true, returns true if all alphabetical + ## 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): bool {.noSideEffect, procvar, - rtl, extern: "nsuIsUpperAsciiStr".} = - ## Checks whether or not `s` contains all upper case characters. +proc isUpperAscii*(s: string, skipNonAlpha: bool): bool = + ## Checks whether ``s`` is upper case. ## ## This checks ASCII characters only. - ## Returns true if all characters in `s` are upper case - ## and there is at least one character in `s`. - isImpl isUpperAscii + ## + ## 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, rtl, extern: "nsuToLowerAsciiChar".} = @@ -2516,19 +2545,34 @@ when isMainModule: doAssert(not isLowerAscii('A')) doAssert(not isLowerAscii('5')) doAssert(not isLowerAscii('&')) + doAssert(not isLowerAscii(' ')) - doAssert isLowerAscii("abcd") - doAssert(not isLowerAscii("abCD")) - doAssert(not isLowerAscii("33aa")) + doAssert isLowerAscii("abcd", false) + doAssert(not isLowerAscii("33aa", false)) + 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(not isUpperAscii('b')) doAssert(not isUpperAscii('5')) doAssert(not isUpperAscii('%')) - doAssert isUpperAscii("ABC") - doAssert(not isUpperAscii("AAcc")) - doAssert(not isUpperAscii("A#$")) + doAssert isUpperAscii("ABC", false) + doAssert(not isUpperAscii("A#$", false)) + 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, maxsplit=1) == @[" foo", "bar"] @@ -2601,4 +2645,3 @@ bar nonStaticTests() staticTests() static: staticTests() - diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index bfd01be55..978f569ac 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -1392,7 +1392,7 @@ proc isCombining*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = (c >= 0xfe20 and c <= 0xfe2f)) 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 var @@ -1403,16 +1403,6 @@ template runeCheck(s, runeProc) = fastRuneAt(s, i, rune, doInc=true) 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, rtl, extern: "nuc$1Str".} = ## 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. 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) = ## Convert runes in `s` using `runeProc` as the converter. result = newString(len(s)) @@ -1755,25 +1795,39 @@ when isMainModule: doAssert(not isSpace("")) doAssert(not isSpace("ΑΓc \td")) - doAssert isLower("a") - doAssert isLower("γ") - doAssert(not isLower("Γ")) - doAssert(not isLower("4")) - doAssert(not isLower("")) - - doAssert isLower("abcdγ") - doAssert(not isLower("abCDΓ")) - doAssert(not isLower("33aaΓ")) - - doAssert isUpper("Γ") - doAssert(not isUpper("b")) - doAssert(not isUpper("α")) - doAssert(not isUpper("✓")) - doAssert(not isUpper("")) - - doAssert isUpper("ΑΒΓ") - doAssert(not isUpper("AAccβ")) - doAssert(not isUpper("A#$β")) + doAssert(not isLower(' '.Rune)) + + doAssert isLower("a", false) + doAssert isLower("γ", true) + 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(not isLower("abCDΓ", true)) + doAssert isLower("a b", true) + doAssert isLower("1, 2, 3 go!", true) + doAssert(not isLower(" ", true)) + doAssert(not isLower("(*&#@(^#$✓ ", true)) # None of the string runes are alphabets + + doAssert(not isUpper(' '.Rune)) + + 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("b") == "B" diff --git a/lib/system.nim b/lib/system.nim index fee9dc314..fb02fde23 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1498,11 +1498,21 @@ when defined(nimdoc): ## macro, use the `error <manual.html#error-pragma>`_ or `fatal ## <manual.html#fatal-pragma>`_ pragmas. - elif defined(genode): - proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn, - importcpp: "genodeEnv->parent().exit(@); Genode::sleep_forever()", - header: "<base/sleep.h>".} + include genode/env + + 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): proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", @@ -4215,3 +4225,22 @@ when not defined(js): type ForLoopStmt* {.compilerProc.} = object ## special type that marks a macro ## 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. diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim index 9609b6d39..a63eadf8e 100644 --- a/lib/system/osalloc.nim +++ b/lib/system/osalloc.nim @@ -78,7 +78,7 @@ when defined(emscripten): munmap(mmapDescr.realPointer, mmapDescr.realSize) elif defined(genode): - include genodealloc # osAllocPages, osTryAllocPages, osDeallocPages + include genode/alloc # osAllocPages, osTryAllocPages, osDeallocPages elif defined(posix): const diff --git a/lib/system/threads.nim b/lib/system/threads.nim index 861bde13f..c8ea03f92 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -116,6 +116,7 @@ when defined(windows): importc: "SetThreadAffinityMask", stdcall, header: "<windows.h>".} elif defined(genode): + import genode/env const GenodeHeader = "genode_cpp/threads.h" type @@ -125,11 +126,12 @@ elif defined(genode): ThreadVarSlot = int proc initThread(s: var SysThread, + env: GenodeEnv, stackSize: culonglong, entry: GenodeThreadProc, arg: pointer, affinity: cuint) {. - importcpp: "#.initThread(genodeEnv, @)".} + importcpp: "#.initThread(@)".} proc threadVarAlloc(): ThreadVarSlot = 0 @@ -569,7 +571,7 @@ when hostOS == "windows": elif defined(genode): 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], tp: proc (arg: TArg) {.thread, nimcall.}, @@ -580,6 +582,7 @@ elif defined(genode): t.dataFn = tp when hasSharedHeap: t.stackSize = ThreadStackSize t.sys.initThread( + runtimeEnv, ThreadStackSize.culonglong, threadProcWrapper[TArg], addr(t), affinityOffset) inc affinityOffset diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index a24575d11..de3bfa616 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -44,6 +44,10 @@ else: const DLLSSLName* = "libssl" & versions & ".dylib" DLLUtilName* = "libcrypto" & versions & ".dylib" + elif defined(genode): + const + DLLSSLName* = "libssl.lib.so" + DLLUtilName* = "libcrypto.lib.so" else: const DLLSSLName* = "libssl.so" & versions diff --git a/tests/cpp/tempty_generic_obj.nim b/tests/cpp/tempty_generic_obj.nim index b4c746a30..b61c699f6 100644 --- a/tests/cpp/tempty_generic_obj.nim +++ b/tests/cpp/tempty_generic_obj.nim @@ -20,3 +20,19 @@ v.doSomething() var vf = initVector[float]() 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() + diff --git a/tests/generics/t3977.nim b/tests/generics/t3977.nim new file mode 100644 index 000000000..eed1a7d63 --- /dev/null +++ b/tests/generics/t3977.nim @@ -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 diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim index 64d690fc9..d364447da 100644 --- a/tests/stdlib/tnet.nim +++ b/tests/stdlib/tnet.nim @@ -66,6 +66,18 @@ block: # "IpAddress/Sockaddr conversion" 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 test("2606:2800:220:1:248:1893:25c8:1946") |