mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-07 21:43:33 +00:00
Merge branch 'devel' into araq
This commit is contained in:
@@ -944,7 +944,6 @@ proc genEcho(p: BProc, n: PNode) =
|
||||
# this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
|
||||
# is threadsafe.
|
||||
internalAssert n.kind == nkBracket
|
||||
p.module.includeHeader("<stdio.h>")
|
||||
var args: Rope = nil
|
||||
var a: TLoc
|
||||
for i in countup(0, n.len-1):
|
||||
@@ -953,9 +952,15 @@ proc genEcho(p: BProc, n: PNode) =
|
||||
else:
|
||||
initLocExpr(p, n.sons[i], a)
|
||||
addf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
|
||||
linefmt(p, cpsStmts, "printf($1$2);$n",
|
||||
makeCString(repeat("%s", n.len) & tnl), args)
|
||||
linefmt(p, cpsStmts, "fflush(stdout);$n")
|
||||
if platform.targetOS == osGenode:
|
||||
# bypass libc and print directly to the Genode LOG session
|
||||
p.module.includeHeader("<base/log.h>")
|
||||
linefmt(p, cpsStmts, """Genode::log(""$1);$n""", args)
|
||||
else:
|
||||
p.module.includeHeader("<stdio.h>")
|
||||
linefmt(p, cpsStmts, "printf($1$2);$n",
|
||||
makeCString(repeat("%s", n.len) & tnl), args)
|
||||
linefmt(p, cpsStmts, "fflush(stdout);$n")
|
||||
|
||||
proc gcUsage(n: PNode) =
|
||||
if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
|
||||
|
||||
@@ -966,6 +966,19 @@ proc genMainProc(m: BModule) =
|
||||
MainProcs &
|
||||
"}$N$N"
|
||||
|
||||
GenodeNimMain =
|
||||
"Libc::Env *genodeEnv;$N" &
|
||||
NimMainBody
|
||||
|
||||
ComponentConstruct =
|
||||
"void Libc::Component::construct(Libc::Env &env) {$N" &
|
||||
"\tgenodeEnv = &env;$N" &
|
||||
"\tLibc::with_libc([&] () {$n\t" &
|
||||
MainProcs &
|
||||
"\t});$N" &
|
||||
"\tenv.parent().exit(0);$N" &
|
||||
"}$N$N"
|
||||
|
||||
var nimMain, otherMain: FormatStr
|
||||
if platform.targetOS == osWindows and
|
||||
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}:
|
||||
@@ -976,6 +989,9 @@ proc genMainProc(m: BModule) =
|
||||
nimMain = WinNimDllMain
|
||||
otherMain = WinCDllMain
|
||||
m.includeHeader("<windows.h>")
|
||||
elif platform.targetOS == osGenode:
|
||||
nimMain = GenodeNimMain
|
||||
otherMain = ComponentConstruct
|
||||
elif optGenDynLib in gGlobalOptions:
|
||||
nimMain = PosixNimDllMain
|
||||
otherMain = PosixCDllMain
|
||||
|
||||
@@ -1626,22 +1626,56 @@ proc genToArray(p: PProc; n: PNode; r: var TCompRes) =
|
||||
localError(x.info, "'toArray' needs an array literal")
|
||||
r.res.add(")")
|
||||
|
||||
proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = nil) =
|
||||
useMagic(p, magic)
|
||||
add(r.res, magic & "(")
|
||||
var a: TCompRes
|
||||
|
||||
gen(p, n.sons[1], a)
|
||||
if magic == "reprAny":
|
||||
# the pointer argument in reprAny is expandend to
|
||||
# (pointedto, pointer), so we need to fill it
|
||||
if a.address.isNil:
|
||||
add(r.res, a.res)
|
||||
add(r.res, ", null")
|
||||
else:
|
||||
add(r.res, "$1, $2" % [a.address, a.res])
|
||||
else:
|
||||
add(r.res, a.res)
|
||||
|
||||
if not typ.isNil:
|
||||
add(r.res, ", ")
|
||||
add(r.res, typ)
|
||||
add(r.res, ")")
|
||||
|
||||
proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
if p.target == targetPHP:
|
||||
localError(n.info, "'repr' not available for PHP backend")
|
||||
return
|
||||
let t = skipTypes(n.sons[1].typ, abstractVarRange)
|
||||
case t.kind
|
||||
of tyInt..tyUInt64:
|
||||
unaryExpr(p, n, r, "", "(\"\"+ ($1))")
|
||||
case t.kind:
|
||||
of tyInt..tyInt64, tyUInt..tyUInt64:
|
||||
genReprAux(p, n, r, "reprInt")
|
||||
of tyChar:
|
||||
genReprAux(p, n, r, "reprChar")
|
||||
of tyBool:
|
||||
genReprAux(p, n, r, "reprBool")
|
||||
of tyFloat..tyFloat128:
|
||||
genReprAux(p, n, r, "reprFloat")
|
||||
of tyString:
|
||||
genReprAux(p, n, r, "reprStr")
|
||||
of tyEnum, tyOrdinal:
|
||||
gen(p, n.sons[1], r)
|
||||
useMagic(p, "cstrToNimstr")
|
||||
r.kind = resExpr
|
||||
r.res = "cstrToNimstr($1.node.sons[$2].name)" % [genTypeInfo(p, t), r.res]
|
||||
genReprAux(p, n, r, "reprEnum", genTypeInfo(p, t))
|
||||
of tySet:
|
||||
genReprAux(p, n, r, "reprSet", genTypeInfo(p, t))
|
||||
of tyEmpty, tyVoid:
|
||||
localError(n.info, "'repr' doesn't support 'void' type")
|
||||
of tyPointer:
|
||||
genReprAux(p, n, r, "reprPointer")
|
||||
of tyOpenArray, tyVarargs:
|
||||
genReprAux(p, n, r, "reprJSONStringify")
|
||||
else:
|
||||
# XXX:
|
||||
internalError(n.info, "genRepr: Not implemented")
|
||||
genReprAux(p, n, r, "reprAny", genTypeInfo(p, t))
|
||||
|
||||
proc genOf(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var x: TCompRes
|
||||
|
||||
@@ -21,7 +21,7 @@ type
|
||||
# conditionals to condsyms (end of module).
|
||||
osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
|
||||
osIrix, osNetbsd, osFreebsd, osOpenbsd, osDragonfly, osAix, osPalmos, osQnx,
|
||||
osAmiga, osAtari, osNetware, osMacos, osMacosx, osHaiku, osVxworks,
|
||||
osAmiga, osAtari, osNetware, osMacos, osMacosx, osHaiku, osVxworks, osGenode
|
||||
osJS, osNimrodVM, osStandalone
|
||||
|
||||
type
|
||||
@@ -147,6 +147,11 @@ const
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ";", dirSep: "\\",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: ".vxe", extSep: ".",
|
||||
props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}),
|
||||
(name: "Genode", pardir: "..", dllFrmt: "$1.lib.so", altDirSep: "/",
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
|
||||
scriptExt: "", curDir: "/", exeExt: "", extSep: ".",
|
||||
props: {ospNeedsPIC, ospLacksThreadVars}),
|
||||
|
||||
(name: "JS", parDir: "..",
|
||||
dllFrmt: "lib$1.so", altDirSep: "/",
|
||||
objExt: ".o", newLine: "\x0A",
|
||||
|
||||
@@ -256,6 +256,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
f.ident.s[0..f.ident.s.len-2]).withInfo(n.info)
|
||||
let callOp = newIdentNode(getIdent".=", n.info)
|
||||
n.sons[0..1] = [callOp, n[1], calleeName]
|
||||
excl(n.flags, nfDotSetter)
|
||||
orig.sons[0..1] = [callOp, orig[1], calleeName]
|
||||
pickBest(callOp)
|
||||
|
||||
|
||||
@@ -472,7 +472,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||
var r = replaceTypeVarsT(cl, result.sons[i])
|
||||
if result.kind == tyObject:
|
||||
# carefully coded to not skip the precious tyGenericInst:
|
||||
let r2 = r.skipTypes({tyGenericInst, tyAlias})
|
||||
let r2 = r.skipTypes({tyAlias})
|
||||
if r2.kind in {tyPtr, tyRef}:
|
||||
r = skipTypes(r2, {tyPtr, tyRef})
|
||||
result.sons[i] = r
|
||||
|
||||
@@ -1268,7 +1268,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
# crossing path with metatypes/aliases, so we need to separate them
|
||||
# by checking sym.id
|
||||
let genericSubtype = isGenericSubType(c, x, f, depth, f)
|
||||
if not (genericSubtype and aobj.sym.id != fobj.sym.id):
|
||||
if not (genericSubtype and aobj.sym.id != fobj.sym.id) and aOrig.kind != tyGenericBody:
|
||||
depth = -1
|
||||
|
||||
if depth >= 0:
|
||||
|
||||
@@ -174,7 +174,8 @@ typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
|
||||
typeDef = identWithPragmaDot genericParamList? '=' optInd typeDefAux
|
||||
indAndComment?
|
||||
varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr
|
||||
variable = (varTuple / identColonEquals) indAndComment
|
||||
colonBody = colcom stmt doBlocks?
|
||||
variable = (varTuple / identColonEquals) colonBody? indAndComment
|
||||
bindStmt = 'bind' optInd qualifiedIdent ^+ comma
|
||||
mixinStmt = 'mixin' optInd qualifiedIdent ^+ comma
|
||||
pragmaStmt = pragma (':' COMMENT? stmt)?
|
||||
|
||||
@@ -39,7 +39,7 @@ directly or indirectly through a call to a GC unsafe proc.
|
||||
The `gcsafe`:idx: annotation can be used to mark a proc to be gcsafe,
|
||||
otherwise this property is inferred by the compiler. Note that ``noSideEffect``
|
||||
implies ``gcsafe``. The only way to create a thread is via ``spawn`` or
|
||||
``createThead``. ``spawn`` is usually the preferable method. Either way
|
||||
``createThread``. ``spawn`` is usually the preferable method. Either way
|
||||
the invoked proc must not use ``var`` parameters nor must any of its parameters
|
||||
contain a ``ref`` or ``closure`` type. This enforces
|
||||
the *no heap sharing restriction*.
|
||||
|
||||
78
lib/genode_cpp/syslocks.h
Normal file
78
lib/genode_cpp/syslocks.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
*
|
||||
* Nim's Runtime Library
|
||||
* (c) Copyright 2017 Emery Hemingway
|
||||
*
|
||||
* See the file "copying.txt", included in this
|
||||
* distribution, for details about the copyright.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _GENODE_CPP__SYSLOCKS_H_
|
||||
#define _GENODE_CPP__SYSLOCKS_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/semaphore.h>
|
||||
#include <base/lock.h>
|
||||
|
||||
namespace Nim {
|
||||
struct SysLock;
|
||||
struct SysCond;
|
||||
}
|
||||
|
||||
struct Nim::SysLock
|
||||
{
|
||||
Genode::Lock _lock_a, _lock_b;
|
||||
bool _locked;
|
||||
|
||||
void acquireSys()
|
||||
{
|
||||
_lock_a.lock();
|
||||
_locked = true;
|
||||
_lock_a.unlock();
|
||||
_lock_b.lock();
|
||||
}
|
||||
|
||||
bool tryAcquireSys()
|
||||
{
|
||||
if (_locked)
|
||||
return false;
|
||||
|
||||
_lock_a.lock();
|
||||
if (_locked) {
|
||||
_lock_a.unlock();
|
||||
return false;
|
||||
} else {
|
||||
_locked = true;
|
||||
_lock_b.lock();
|
||||
_lock_a.unlock();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void releaseSys()
|
||||
{
|
||||
_locked = false;
|
||||
_lock_a.unlock();
|
||||
_lock_b.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
struct Nim::SysCond
|
||||
{
|
||||
Genode::Semaphore _semaphore;
|
||||
|
||||
void waitSysCond(SysLock &syslock)
|
||||
{
|
||||
syslock.releaseSys();
|
||||
_semaphore.down();
|
||||
syslock.acquireSys();
|
||||
}
|
||||
|
||||
void signalSysCond()
|
||||
{
|
||||
_semaphore.up();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
69
lib/genode_cpp/threads.h
Normal file
69
lib/genode_cpp/threads.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
*
|
||||
* Nim's Runtime Library
|
||||
* (c) Copyright 2017 Emery Hemingway
|
||||
*
|
||||
* See the file "copying.txt", included in this
|
||||
* distribution, for details about the copyright.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _GENODE_CPP__THREAD_H_
|
||||
#define _GENODE_CPP__THREAD_H_
|
||||
|
||||
#include <base/thread.h>
|
||||
#include <util/avl_tree.h>
|
||||
#include <util/reconstructible.h>
|
||||
|
||||
namespace Nim { struct SysThread; }
|
||||
|
||||
struct Nim::SysThread
|
||||
{
|
||||
typedef void (Entry)(void*);
|
||||
|
||||
struct Thread : Genode::Thread
|
||||
{
|
||||
void *_tls;
|
||||
|
||||
Entry *_func;
|
||||
void *_arg;
|
||||
|
||||
void entry() override {
|
||||
(_func)(_arg); }
|
||||
|
||||
Thread(Genode::Env &env, Genode::size_t stack_size, Entry func, void *arg)
|
||||
: Genode::Thread(env, "nim-thread", stack_size), _func(func), _arg(arg)
|
||||
{
|
||||
Genode::Thread::start();
|
||||
}
|
||||
};
|
||||
|
||||
Genode::Constructible<Thread> _thread;
|
||||
|
||||
void initThread(Genode::Env *env, Genode::size_t stack_size, Entry func, void *arg) {
|
||||
_thread.construct(*env, stack_size, func, arg); }
|
||||
|
||||
void joinThread() {
|
||||
_thread->join(); }
|
||||
|
||||
static bool offMainThread() {
|
||||
return dynamic_cast<SysThread::Thread*>(Genode::Thread::myself()); }
|
||||
|
||||
static void *threadVarGetValue()
|
||||
{
|
||||
SysThread::Thread *thr =
|
||||
static_cast<SysThread::Thread*>(Genode::Thread::myself());
|
||||
return thr->_tls;
|
||||
}
|
||||
|
||||
static void threadVarSetValue(void *value)
|
||||
{
|
||||
SysThread::Thread *thr =
|
||||
static_cast<SysThread::Thread*>(Genode::Thread::myself());
|
||||
thr->_tls = value;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -498,6 +498,11 @@ 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")
|
||||
|
||||
@@ -1862,10 +1862,10 @@ when hasAioH:
|
||||
a4: ptr SigEvent): cint {.importc, header: "<aio.h>".}
|
||||
|
||||
# arpa/inet.h
|
||||
proc htonl*(a1: int32): int32 {.importc, header: "<arpa/inet.h>".}
|
||||
proc htons*(a1: int16): int16 {.importc, header: "<arpa/inet.h>".}
|
||||
proc ntohl*(a1: int32): int32 {.importc, header: "<arpa/inet.h>".}
|
||||
proc ntohs*(a1: int16): int16 {.importc, header: "<arpa/inet.h>".}
|
||||
proc htonl*(a1: uint32): uint32 {.importc, header: "<arpa/inet.h>".}
|
||||
proc htons*(a1: uint16): uint16 {.importc, header: "<arpa/inet.h>".}
|
||||
proc ntohl*(a1: uint32): uint32 {.importc, header: "<arpa/inet.h>".}
|
||||
proc ntohs*(a1: uint16): uint16 {.importc, header: "<arpa/inet.h>".}
|
||||
|
||||
proc inet_addr*(a1: cstring): InAddrT {.importc, header: "<arpa/inet.h>".}
|
||||
proc inet_ntoa*(a1: InAddr): cstring {.importc, header: "<arpa/inet.h>".}
|
||||
@@ -2423,11 +2423,15 @@ proc sigset*(a1: int, a2: proc (x: cint) {.noconv.}) {.
|
||||
proc sigsuspend*(a1: var Sigset): cint {.importc, header: "<signal.h>".}
|
||||
|
||||
when defined(android):
|
||||
proc sigtimedwait*(a1: var Sigset, a2: var SigInfo,
|
||||
a3: var Timespec, sigsetsize: csize = sizeof(culong)*2): cint {.importc: "__rt_sigtimedwait", header:"<signal.h>".}
|
||||
proc syscall(arg: clong): clong {.varargs, importc: "syscall", header: "<unistd.h>".}
|
||||
var NR_rt_sigtimedwait {.importc: "__NR_rt_sigtimedwait", header: "<sys/syscall.h>".}: clong
|
||||
var NSIGMAX {.importc: "NSIG", header: "<signal.h>".}: clong
|
||||
|
||||
proc sigtimedwait*(a1: var Sigset, a2: var SigInfo, a3: var Timespec): cint =
|
||||
result = cint(syscall(NR_rt_sigtimedwait, addr(a1), addr(a2), addr(a3), NSIGMAX div 8))
|
||||
else:
|
||||
proc sigtimedwait*(a1: var Sigset, a2: var SigInfo,
|
||||
a3: var Timespec): cint {.importc, header: "<signal.h>".}
|
||||
a3: var Timespec): cint {.importc, header: "<signal.h>".}
|
||||
|
||||
proc sigwait*(a1: var Sigset, a2: var cint): cint {.
|
||||
importc, header: "<signal.h>".}
|
||||
|
||||
@@ -37,6 +37,10 @@ when defined(macosx) or defined(bsd):
|
||||
a: var csize, b: pointer, c: int): cint {.
|
||||
importc: "sysctl", nodecl.}
|
||||
|
||||
when defined(genode):
|
||||
proc affinitySpaceTotal(): cuint {.
|
||||
importcpp: "genodeEnv->cpu().affinity_space().total()".}
|
||||
|
||||
proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
|
||||
## returns the numer of the processors/cores the machine has.
|
||||
## Returns 0 if it cannot be detected.
|
||||
@@ -61,7 +65,8 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
|
||||
elif defined(irix):
|
||||
var SC_NPROC_ONLN {.importc: "_SC_NPROC_ONLN", header: "<unistd.h>".}: cint
|
||||
result = sysconf(SC_NPROC_ONLN)
|
||||
elif defined(genode):
|
||||
result = affinitySpaceTotal().int
|
||||
else:
|
||||
result = sysconf(SC_NPROCESSORS_ONLN)
|
||||
if result <= 0: result = 1
|
||||
|
||||
|
||||
@@ -320,7 +320,7 @@ proc parseResponse(s: Socket, getBody: bool, timeout: int): Response =
|
||||
if line[linei] != ':': httpError("invalid headers")
|
||||
inc(linei) # Skip :
|
||||
|
||||
result.headers[name] = line[linei.. ^1].strip()
|
||||
result.headers.add(name, line[linei.. ^1].strip())
|
||||
# Ensure the server isn't trying to DoS us.
|
||||
if result.headers.len > headerLimit:
|
||||
httpError("too many headers")
|
||||
@@ -1010,7 +1010,7 @@ proc parseResponse(client: HttpClient | AsyncHttpClient,
|
||||
if line[linei] != ':': httpError("invalid headers")
|
||||
inc(linei) # Skip :
|
||||
|
||||
result.headers[name] = line[linei.. ^1].strip()
|
||||
result.headers.add(name, line[linei.. ^1].strip())
|
||||
if result.headers.len > headerLimit:
|
||||
httpError("too many headers")
|
||||
|
||||
|
||||
@@ -825,16 +825,16 @@ proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} =
|
||||
else:
|
||||
add environment, (key & '=' & val)
|
||||
indx = high(environment)
|
||||
when defined(unix):
|
||||
if c_putenv(environment[indx]) != 0'i32:
|
||||
raiseOSError(osLastError())
|
||||
else:
|
||||
when defined(windows):
|
||||
when useWinUnicode:
|
||||
var k = newWideCString(key)
|
||||
var v = newWideCString(val)
|
||||
if setEnvironmentVariableW(k, v) == 0'i32: raiseOSError(osLastError())
|
||||
else:
|
||||
if setEnvironmentVariableA(key, val) == 0'i32: raiseOSError(osLastError())
|
||||
else:
|
||||
if c_putenv(environment[indx]) != 0'i32:
|
||||
raiseOSError(osLastError())
|
||||
|
||||
iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [ReadEnvEffect].} =
|
||||
## Iterate over all `environments variables`:idx:. In the first component
|
||||
@@ -1091,7 +1091,7 @@ proc rawCreateDir(dir: string): bool =
|
||||
result = false
|
||||
else:
|
||||
raiseOSError(osLastError())
|
||||
elif defined(unix):
|
||||
elif defined(posix):
|
||||
let res = mkdir(dir, 0o777)
|
||||
if res == 0'i32:
|
||||
result = true
|
||||
@@ -1452,7 +1452,9 @@ elif defined(windows):
|
||||
if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLine())
|
||||
return TaintedString(ownArgv[i])
|
||||
|
||||
elif not defined(createNimRtl) and not(defined(posix) and appType == "lib"):
|
||||
elif not defined(createNimRtl) and
|
||||
not(defined(posix) and appType == "lib") and
|
||||
not defined(genode):
|
||||
# On Posix, there is no portable way to get the command line from a DLL.
|
||||
var
|
||||
cmdCount {.importc: "cmdCount".}: cint
|
||||
@@ -1606,6 +1608,8 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} =
|
||||
result = getApplAux("/proc/self/exe")
|
||||
elif defined(solaris):
|
||||
result = getApplAux("/proc/" & $getpid() & "/path/a.out")
|
||||
elif defined(genode):
|
||||
raiseOSError("POSIX command line not supported")
|
||||
elif defined(freebsd) or defined(dragonfly):
|
||||
result = getApplFreebsd()
|
||||
# little heuristic that may work on other POSIX-like systems:
|
||||
|
||||
@@ -1384,25 +1384,34 @@ var programResult* {.exportc: "nim_program_result".}: int
|
||||
## under normal circumstances. When the program is terminated
|
||||
## prematurely using ``quit``, this value is ignored.
|
||||
|
||||
proc quit*(errorcode: int = QuitSuccess) {.
|
||||
magic: "Exit", importc: "exit", header: "<stdlib.h>", noreturn.}
|
||||
## Stops the program immediately with an exit code.
|
||||
##
|
||||
## Before stopping the program the "quit procedures" are called in the
|
||||
## opposite order they were added with `addQuitProc <#addQuitProc>`_.
|
||||
## ``quit`` never returns and ignores any exception that may have been raised
|
||||
## by the quit procedures. It does *not* call the garbage collector to free
|
||||
## all the memory, unless a quit procedure calls `GC_fullCollect
|
||||
## <#GC_fullCollect>`_.
|
||||
##
|
||||
## The proc ``quit(QuitSuccess)`` is called implicitly when your nim
|
||||
## program finishes without incident. A raised unhandled exception is
|
||||
## equivalent to calling ``quit(QuitFailure)``.
|
||||
##
|
||||
## Note that this is a *runtime* call and using ``quit`` inside a macro won't
|
||||
## have any compile time effect. If you need to stop the compiler inside a
|
||||
## macro, use the `error <manual.html#error-pragma>`_ or `fatal
|
||||
## <manual.html#fatal-pragma>`_ pragmas.
|
||||
when defined(nimdoc):
|
||||
proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn.}
|
||||
## Stops the program immediately with an exit code.
|
||||
##
|
||||
## Before stopping the program the "quit procedures" are called in the
|
||||
## opposite order they were added with `addQuitProc <#addQuitProc>`_.
|
||||
## ``quit`` never returns and ignores any exception that may have been raised
|
||||
## by the quit procedures. It does *not* call the garbage collector to free
|
||||
## all the memory, unless a quit procedure calls `GC_fullCollect
|
||||
## <#GC_fullCollect>`_.
|
||||
##
|
||||
## The proc ``quit(QuitSuccess)`` is called implicitly when your nim
|
||||
## program finishes without incident. A raised unhandled exception is
|
||||
## equivalent to calling ``quit(QuitFailure)``.
|
||||
##
|
||||
## Note that this is a *runtime* call and using ``quit`` inside a macro won't
|
||||
## have any compile time effect. If you need to stop the compiler inside a
|
||||
## 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(@)", header: "<base/env.h>".}
|
||||
|
||||
else:
|
||||
proc quit*(errorcode: int = QuitSuccess) {.
|
||||
magic: "Exit", importc: "exit", header: "<stdlib.h>", noreturn.}
|
||||
|
||||
template sysAssert(cond: bool, msg: string) =
|
||||
when defined(useSysAssert):
|
||||
|
||||
@@ -146,6 +146,17 @@ elif defined(windows) or defined(dos):
|
||||
if result != nil: return
|
||||
procAddrError(name)
|
||||
|
||||
elif defined(genode):
|
||||
|
||||
proc nimUnloadLibrary(lib: LibHandle) {.
|
||||
error: "nimUnloadLibrary not implemented".}
|
||||
|
||||
proc nimLoadLibrary(path: string): LibHandle {.
|
||||
error: "nimLoadLibrary not implemented".}
|
||||
|
||||
proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr {.
|
||||
error: "nimGetProcAddr not implemented".}
|
||||
|
||||
else:
|
||||
{.error: "no implementation for dyncalls".}
|
||||
|
||||
|
||||
@@ -77,6 +77,19 @@ when defined(emscripten):
|
||||
var mmapDescr = cast[EmscriptenMMapBlock](mmapDescrPos)
|
||||
munmap(mmapDescr.realPointer, mmapDescr.realSize)
|
||||
|
||||
elif defined(genode):
|
||||
|
||||
proc osAllocPages(size: int): pointer {.
|
||||
importcpp: "genodeEnv->rm().attach(genodeEnv->ram().alloc(@))".}
|
||||
|
||||
proc osTryAllocPages(size: int): pointer =
|
||||
{.emit: """try {""".}
|
||||
result = osAllocPages size
|
||||
{.emit: """} catch (...) { }""".}
|
||||
|
||||
proc osDeallocPages(p: pointer, size: int) {.
|
||||
importcpp: "genodeEnv->rm().detach(#)".}
|
||||
|
||||
elif defined(posix):
|
||||
const
|
||||
PROT_READ = 1 # page can be read
|
||||
|
||||
@@ -6,18 +6,272 @@
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
# The generic ``repr`` procedure for the javascript backend.
|
||||
|
||||
proc reprInt(x: int64): string {.compilerproc.} = return $x
|
||||
proc reprFloat(x: float): string {.compilerproc.} =
|
||||
# Js toString doesn't differentiate between 1.0 and 1,
|
||||
# but we do.
|
||||
if $x == $(x.int): $x & ".0"
|
||||
else: $x
|
||||
|
||||
proc reprPointer(p: pointer): string {.compilerproc.} =
|
||||
# Do we need to generate the full 8bytes ? In js a pointer is an int anyway
|
||||
var tmp: int
|
||||
{. emit: """
|
||||
if (`p`_Idx == null) {
|
||||
`tmp` = 0;
|
||||
} else {
|
||||
`tmp` = `p`_Idx;
|
||||
}
|
||||
""" .}
|
||||
result = $tmp
|
||||
|
||||
proc reprBool(x: bool): string {.compilerRtl.} =
|
||||
if x: result = "true"
|
||||
else: result = "false"
|
||||
|
||||
proc isUndefined[T](x: T): bool {.inline.} = {.emit: "`result` = `x` === undefined;"}
|
||||
|
||||
proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
|
||||
if ntfEnumHole notin typ.flags:
|
||||
if e <% typ.node.len:
|
||||
return $typ.node.sons[e].name
|
||||
if not typ.node.sons[e].isUndefined:
|
||||
result = $typ.node.sons[e].name
|
||||
else:
|
||||
# ugh we need a slow linear search:
|
||||
var n = typ.node
|
||||
var s = n.sons
|
||||
for i in 0 .. n.len-1:
|
||||
if s[i].offset == e: return $s[i].name
|
||||
result = $e & " (invalid data!)"
|
||||
result = $e & " (invalid data!)"
|
||||
|
||||
proc reprChar(x: char): string {.compilerRtl.} =
|
||||
result = "\'"
|
||||
case x
|
||||
of '"': add(result, "\\\"")
|
||||
of '\\': add(result, "\\\\")
|
||||
of '\128'..'\255', '\0'..'\31': add( result, "\\" & reprInt(ord(x)) )
|
||||
else: add(result, x)
|
||||
add(result, "\'")
|
||||
|
||||
proc reprStrAux(result: var string, s: cstring, len: int) =
|
||||
add(result, "\"")
|
||||
for i in 0 .. <len:
|
||||
let c = s[i]
|
||||
case c
|
||||
of '"': add(result, "\\\"")
|
||||
of '\\': add(result, "\\\\")
|
||||
of '\10': add(result, "\\10\"\n\"")
|
||||
of '\128'..'\255', '\0'..'\9', '\11'..'\31':
|
||||
add( result, "\\" & reprInt(ord(c)) )
|
||||
else:
|
||||
add( result, reprInt(ord(c)) ) # Not sure about this.
|
||||
add(result, "\"")
|
||||
|
||||
proc reprStr(s: string): string {.compilerRtl.} =
|
||||
result = ""
|
||||
if cast[pointer](s).isNil:
|
||||
# Handle nil strings here because they don't have a length field in js
|
||||
# TODO: check for null/undefined before generating call to length in js?
|
||||
# Also: c backend repr of a nil string is <pointer>"", but repr of an
|
||||
# array of string that is not initialized is [nil, nil, ...] ??
|
||||
add(result, "nil")
|
||||
else:
|
||||
reprStrAux(result, s, s.len)
|
||||
|
||||
proc addSetElem(result: var string, elem: int, typ: PNimType) =
|
||||
# Dispatch each set element to the correct repr<Type> proc
|
||||
case typ.kind:
|
||||
of tyEnum: add(result, reprEnum(elem, typ))
|
||||
of tyBool: add(result, reprBool(bool(elem)))
|
||||
of tyChar: add(result, reprChar(chr(elem)))
|
||||
of tyRange: addSetElem(result, elem, typ.base) # Note the base to advance towards the element type
|
||||
of tyInt..tyInt64, tyUInt8, tyUInt16: add result, reprInt(elem)
|
||||
else: # data corrupt --> inform the user
|
||||
add(result, " (invalid data!)")
|
||||
|
||||
iterator setKeys(s: int): int {.inline.} =
|
||||
# The type of s is a lie, but it's expected to be a set.
|
||||
# Iterate over the JS object representing a set
|
||||
# and returns the keys as int.
|
||||
var len: int
|
||||
var yieldRes: int
|
||||
var i: int = 0
|
||||
{. emit: """
|
||||
var setObjKeys = Object.getOwnPropertyNames(`s`);
|
||||
`len` = setObjKeys.length;
|
||||
""" .}
|
||||
while i < len:
|
||||
{. emit: "`yieldRes` = parseInt(setObjKeys[`i`],10);\n" .}
|
||||
yield yieldRes
|
||||
inc i
|
||||
|
||||
proc reprSetAux(result: var string, s: int, typ: PNimType) =
|
||||
add(result, "{")
|
||||
var first: bool = true
|
||||
for el in setKeys(s):
|
||||
if first:
|
||||
first = false
|
||||
else:
|
||||
add(result, ", ")
|
||||
addSetElem(result, el, typ.base)
|
||||
add(result, "}")
|
||||
|
||||
proc reprSet(e: int, typ: PNimType): string {.compilerRtl.} =
|
||||
result = ""
|
||||
reprSetAux(result, e, typ)
|
||||
|
||||
type
|
||||
ReprClosure {.final.} = object
|
||||
recDepth: int # do not recurse endlessly
|
||||
indent: int # indentation
|
||||
|
||||
proc initReprClosure(cl: var ReprClosure) =
|
||||
cl.recDepth = -1 # default is to display everything!
|
||||
cl.indent = 0
|
||||
|
||||
proc reprAux(result: var string, p: pointer, typ: PNimType, cl: var ReprClosure)
|
||||
|
||||
proc reprArray(a: pointer, typ: PNimType,
|
||||
cl: var ReprClosure): string {.compilerRtl.} =
|
||||
var isNilArrayOrSeq: bool
|
||||
# isnil is not enough here as it would try to deref `a` without knowing what's inside
|
||||
{. emit: """
|
||||
if (`a` == null) {
|
||||
`isNilArrayOrSeq` = true;
|
||||
} else if (`a`[0] == null) {
|
||||
`isNilArrayOrSeq` = true;
|
||||
} else {
|
||||
`isNilArrayOrSeq` = false;
|
||||
};
|
||||
""" .}
|
||||
if typ.kind == tySequence and isNilArrayOrSeq:
|
||||
return "nil"
|
||||
|
||||
# We prepend @ to seq, the C backend prepends the pointer to the seq.
|
||||
result = if typ.kind == tySequence: "@[" else: "["
|
||||
var len: int = 0
|
||||
var i: int = 0
|
||||
|
||||
{. emit: "`len` = `a`.length;\n" .}
|
||||
var dereffed: pointer = a
|
||||
for i in 0 .. < len:
|
||||
if i > 0 :
|
||||
add(result, ", ")
|
||||
# advance pointer and point to element at index
|
||||
{. emit: """
|
||||
`dereffed`_Idx = `i`;
|
||||
`dereffed` = `a`[`dereffed`_Idx];
|
||||
""" .}
|
||||
reprAux(result, dereffed, typ.base, cl)
|
||||
|
||||
add(result, "]")
|
||||
|
||||
proc isPointedToNil(p: pointer): bool {.inline.}=
|
||||
{. emit: "if (`p` === null) {`result` = true};\n" .}
|
||||
|
||||
proc reprRef(result: var string, p: pointer, typ: PNimType,
|
||||
cl: var ReprClosure) =
|
||||
if p.isPointedToNil:
|
||||
add(result , "nil")
|
||||
return
|
||||
add( result, "ref " & reprPointer(p) )
|
||||
add(result, " --> ")
|
||||
if typ.base.kind != tyArray:
|
||||
{. emit: """
|
||||
if (`p` != null && `p`.length > 0) {
|
||||
`p` = `p`[`p`_Idx];
|
||||
}
|
||||
""" .}
|
||||
reprAux(result, p, typ.base, cl)
|
||||
|
||||
proc reprRecordAux(result: var string, o: pointer, typ: PNimType, cl: var ReprClosure) =
|
||||
add(result, "[")
|
||||
|
||||
var first: bool = true
|
||||
var val: pointer = o
|
||||
if typ.node.len == 0:
|
||||
# if the object has only one field, len is 0 and sons is nil, the field is in node
|
||||
let key: cstring = typ.node.name
|
||||
add(result, $key & " = ")
|
||||
{. emit: "`val` = `o`[`key`];\n" .}
|
||||
reprAux(result, val, typ.node.typ, cl)
|
||||
else:
|
||||
# if the object has more than one field, sons is not nil and contains the fields.
|
||||
for i in 0 .. <typ.node.len:
|
||||
if first: first = false
|
||||
else: add(result, ",\n")
|
||||
|
||||
let key: cstring = typ.node.sons[i].name
|
||||
add(result, $key & " = ")
|
||||
{. emit: "`val` = `o`[`key`];\n" .} # access the field by name
|
||||
reprAux(result, val, typ.node.sons[i].typ, cl)
|
||||
add(result, "]")
|
||||
|
||||
proc reprRecord(o: pointer, typ: PNimType, cl: var ReprClosure): string {.compilerRtl.} =
|
||||
result = ""
|
||||
reprRecordAux(result, o, typ,cl)
|
||||
|
||||
|
||||
proc reprJSONStringify(p: int): string {.compilerRtl.} =
|
||||
# As a last resort, use stringify
|
||||
# We use this for tyOpenArray, tyVarargs while genTypeInfo is not implemented
|
||||
var tmp: cstring
|
||||
{. emit: "`tmp` = JSON.stringify(`p`);\n" .}
|
||||
result = $tmp
|
||||
|
||||
proc reprAux(result: var string, p: pointer, typ: PNimType,
|
||||
cl: var ReprClosure) =
|
||||
if cl.recDepth == 0:
|
||||
add(result, "...")
|
||||
return
|
||||
dec(cl.recDepth)
|
||||
case typ.kind
|
||||
of tyInt..tyInt64, tyUInt..tyUInt64:
|
||||
add( result, reprInt(cast[int](p)) )
|
||||
of tyChar:
|
||||
add( result, reprChar(cast[char](p)) )
|
||||
of tyBool:
|
||||
add( result, reprBool(cast[bool](p)) )
|
||||
of tyFloat..tyFloat128:
|
||||
add( result, reprFloat(cast[float](p)) )
|
||||
of tyString:
|
||||
var fp: int
|
||||
{. emit: "`fp` = `p`;\n" .}
|
||||
if cast[string](fp).isNil:
|
||||
add(result, "nil")
|
||||
else:
|
||||
add( result, reprStr(cast[string](p)) )
|
||||
of tyCString:
|
||||
var fp: cstring
|
||||
{. emit: "`fp` = `p`;\n" .}
|
||||
if fp.isNil:
|
||||
add(result, "nil")
|
||||
else:
|
||||
reprStrAux(result, fp, fp.len)
|
||||
of tyEnum, tyOrdinal:
|
||||
var fp: int
|
||||
{. emit: "`fp` = `p`;\n" .}
|
||||
add(result, reprEnum(fp, typ))
|
||||
of tySet:
|
||||
var fp: int
|
||||
{. emit: "`fp` = `p`;\n" .}
|
||||
add(result, reprSet(fp, typ))
|
||||
of tyRange: reprAux(result, p, typ.base, cl)
|
||||
of tyObject, tyTuple:
|
||||
add(result, reprRecord(p, typ, cl))
|
||||
of tyArray, tyArrayConstr, tySequence:
|
||||
add(result, reprArray(p, typ, cl))
|
||||
of tyPointer:
|
||||
add(result, reprPointer(p))
|
||||
of tyPtr, tyRef:
|
||||
reprRef(result, p, typ, cl)
|
||||
of tyProc:
|
||||
if p.isPointedToNil:
|
||||
add(result, "nil")
|
||||
else:
|
||||
add(result, reprPointer(p))
|
||||
else:
|
||||
add( result, "(invalid data!)" & reprJsonStringify(cast[int](p)) )
|
||||
inc(cl.recDepth)
|
||||
|
||||
proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl.} =
|
||||
var cl: ReprClosure
|
||||
initReprClosure(cl)
|
||||
result = ""
|
||||
reprAux(result, p, typ, cl)
|
||||
add(result, "\n")
|
||||
@@ -75,6 +75,28 @@ when defined(Windows):
|
||||
proc waitSysCondWindows(cond: var SysCond) =
|
||||
discard waitForSingleObject(cond, -1'i32)
|
||||
|
||||
elif defined(genode):
|
||||
const
|
||||
Header = "genode_cpp/syslocks.h"
|
||||
type
|
||||
SysLock {.importcpp: "Nim::SysLock", pure, final,
|
||||
header: Header.} = object
|
||||
SysCond {.importcpp: "Nim::SysCond", pure, final,
|
||||
header: Header.} = object
|
||||
|
||||
proc initSysLock(L: var SysLock) = discard
|
||||
proc deinitSys(L: var SysLock) = discard
|
||||
proc acquireSys(L: var SysLock) {.noSideEffect, importcpp.}
|
||||
proc tryAcquireSys(L: var SysLock): bool {.noSideEffect, importcpp.}
|
||||
proc releaseSys(L: var SysLock) {.noSideEffect, importcpp.}
|
||||
|
||||
proc initSysCond(L: var SysCond) = discard
|
||||
proc deinitSysCond(L: var SysCond) = discard
|
||||
proc waitSysCond(cond: var SysCond, lock: var SysLock) {.
|
||||
noSideEffect, importcpp.}
|
||||
proc signalSysCond(cond: var SysCond) {.
|
||||
noSideEffect, importcpp.}
|
||||
|
||||
else:
|
||||
type
|
||||
SysLock {.importc: "pthread_mutex_t", pure, final,
|
||||
|
||||
@@ -46,7 +46,11 @@ const
|
||||
maxRegisters = 256 # don't think there is an arch with more registers
|
||||
useStackMaskHack = false ## use the stack mask hack for better performance
|
||||
StackGuardSize = 4096
|
||||
ThreadStackMask = 1024*256*sizeof(int)-1
|
||||
ThreadStackMask =
|
||||
when defined(genode):
|
||||
1024*64*sizeof(int)-1
|
||||
else:
|
||||
1024*256*sizeof(int)-1
|
||||
ThreadStackSize = ThreadStackMask+1 - StackGuardSize
|
||||
|
||||
when defined(windows):
|
||||
@@ -115,6 +119,49 @@ when defined(windows):
|
||||
## get the ID of the currently running thread.
|
||||
result = int(getCurrentThreadId())
|
||||
|
||||
elif defined(genode):
|
||||
const
|
||||
GenodeHeader = "genode_cpp/threads.h"
|
||||
type
|
||||
SysThread* {.importcpp: "Nim::SysThread",
|
||||
header: GenodeHeader, final, pure.} = object
|
||||
GenodeThreadProc = proc (x: pointer) {.noconv.}
|
||||
ThreadVarSlot = int
|
||||
|
||||
proc initThread(s: var SysThread,
|
||||
stackSize: culonglong,
|
||||
entry: GenodeThreadProc,
|
||||
arg: pointer) {.
|
||||
importcpp: "#.initThread(genodeEnv, @)".}
|
||||
|
||||
proc threadVarAlloc(): ThreadVarSlot = 0
|
||||
|
||||
proc offMainThread(): bool {.
|
||||
importcpp: "Nim::SysThread::offMainThread",
|
||||
header: GenodeHeader.}
|
||||
|
||||
proc threadVarSetValue(value: pointer) {.
|
||||
importcpp: "Nim::SysThread::threadVarSetValue(@)",
|
||||
header: GenodeHeader.}
|
||||
|
||||
proc threadVarGetValue(): pointer {.
|
||||
importcpp: "Nim::SysThread::threadVarGetValue()",
|
||||
header: GenodeHeader.}
|
||||
|
||||
var mainTls: pointer
|
||||
|
||||
proc threadVarSetValue(s: ThreadVarSlot, value: pointer) {.inline.} =
|
||||
if offMainThread():
|
||||
threadVarSetValue(value);
|
||||
else:
|
||||
mainTls = value
|
||||
|
||||
proc threadVarGetValue(s: ThreadVarSlot): pointer {.inline.} =
|
||||
if offMainThread():
|
||||
threadVarGetValue();
|
||||
else:
|
||||
mainTls
|
||||
|
||||
else:
|
||||
when not defined(macosx):
|
||||
{.passL: "-pthread".}
|
||||
@@ -451,6 +498,9 @@ when defined(windows):
|
||||
proc threadProcWrapper[TArg](closure: pointer): int32 {.stdcall.} =
|
||||
threadProcWrapperBody(closure)
|
||||
# implicitly return 0
|
||||
elif defined(genode):
|
||||
proc threadProcWrapper[TArg](closure: pointer) {.noconv.} =
|
||||
threadProcWrapperBody(closure)
|
||||
else:
|
||||
proc threadProcWrapper[TArg](closure: pointer): pointer {.noconv.} =
|
||||
threadProcWrapperBody(closure)
|
||||
@@ -482,6 +532,14 @@ when hostOS == "windows":
|
||||
cast[ptr SysThread](addr(a)), 1, -1)
|
||||
inc(k, MAXIMUM_WAIT_OBJECTS)
|
||||
|
||||
elif defined(genode):
|
||||
proc joinThread*[TArg](t: Thread[TArg]) {.importcpp.}
|
||||
## waits for the thread `t` to finish.
|
||||
|
||||
proc joinThreads*[TArg](t: varargs[Thread[TArg]]) =
|
||||
## waits for every thread in `t` to finish.
|
||||
for i in 0..t.high: joinThread(t[i])
|
||||
|
||||
else:
|
||||
proc joinThread*[TArg](t: Thread[TArg]) {.inline.} =
|
||||
## waits for the thread `t` to finish.
|
||||
@@ -531,6 +589,21 @@ when hostOS == "windows":
|
||||
## shouldn't use this proc.
|
||||
setThreadAffinityMask(t.sys, uint(1 shl cpu))
|
||||
|
||||
elif defined(genode):
|
||||
proc createThread*[TArg](t: var Thread[TArg],
|
||||
tp: proc (arg: TArg) {.thread, nimcall.},
|
||||
param: TArg) =
|
||||
when TArg isnot void: t.data = param
|
||||
t.dataFn = tp
|
||||
when hasSharedHeap: t.stackSize = ThreadStackSize
|
||||
t.sys.initThread(
|
||||
ThreadStackSize.culonglong,
|
||||
threadProcWrapper[TArg], addr(t))
|
||||
|
||||
proc pinToCpu*[Arg](t: var Thread[Arg]; cpu: Natural) =
|
||||
{.hint: "cannot change Genode thread CPU affinity after initialization".}
|
||||
discard
|
||||
|
||||
else:
|
||||
proc createThread*[TArg](t: var Thread[TArg],
|
||||
tp: proc (arg: TArg) {.thread, nimcall.},
|
||||
|
||||
@@ -33,8 +33,8 @@ proc prepareAddress(intaddr: uint32, intport: uint16): ptr Sockaddr_in =
|
||||
result.sin_family = toInt(nativesockets.AF_INET).int16
|
||||
else:
|
||||
result.sin_family = toInt(nativesockets.AF_INET)
|
||||
result.sin_port = htons(intport)
|
||||
result.sin_addr.s_addr = htonl(intaddr)
|
||||
result.sin_port = nativesockets.htons(intport)
|
||||
result.sin_addr.s_addr = nativesockets.htonl(intaddr)
|
||||
|
||||
proc launchSwarm(name: ptr SockAddr) {.async.} =
|
||||
var i = 0
|
||||
@@ -90,7 +90,7 @@ proc readMessages(server: AsyncFD) {.async.} =
|
||||
await sendTo(server, addr grammString[0], len(grammString),
|
||||
cast[ptr SockAddr](addr saddr), slen)
|
||||
inc(msgCount)
|
||||
saveReceivedPort(ntohs(saddr.sin_port).int)
|
||||
saveReceivedPort(nativesockets.ntohs(saddr.sin_port).int)
|
||||
inc(i)
|
||||
|
||||
proc createServer() {.async.} =
|
||||
|
||||
42
tests/generics/tobjecttyperel2.nim
Normal file
42
tests/generics/tobjecttyperel2.nim
Normal file
@@ -0,0 +1,42 @@
|
||||
discard """
|
||||
output: '''1
|
||||
a
|
||||
13'''
|
||||
"""
|
||||
|
||||
# bug #5621 #5615
|
||||
type
|
||||
Obj5[T] = ref object of RootObj
|
||||
x_impl: T
|
||||
|
||||
proc x[T](v476205: Obj5[T]): T {.used.} =
|
||||
v476205.x_impl
|
||||
|
||||
type
|
||||
Obj6[T, U] = ref object of Obj5[T]
|
||||
y_impl: U
|
||||
|
||||
proc newObj6[T, U](x: T; y: U): Obj6[T, U] =
|
||||
new(result)
|
||||
result.x_impl = x
|
||||
result.y_impl = y
|
||||
|
||||
proc x[T, U](v477606: Obj6[T, U]): T {.used.} =
|
||||
v477606.x_impl
|
||||
|
||||
proc y[T, U](v477608: Obj6[T, U]): U {.used.} =
|
||||
v477608.y_impl
|
||||
|
||||
let e = newObj6(1, "a")
|
||||
echo e.x
|
||||
echo e.y
|
||||
|
||||
type
|
||||
Fruit[T] = ref object of RootObj
|
||||
Apple[T] = ref object of Fruit[T]
|
||||
|
||||
proc getColor[T](v: Fruit[T]): T = 13
|
||||
|
||||
var w: Apple[int]
|
||||
let r = getColor(w)
|
||||
echo r
|
||||
12
tests/generics/tobjecttyperel3.nim
Normal file
12
tests/generics/tobjecttyperel3.nim
Normal file
@@ -0,0 +1,12 @@
|
||||
discard """
|
||||
output: '''OK'''
|
||||
"""
|
||||
#bug #5632
|
||||
type
|
||||
Option*[T] = object
|
||||
|
||||
proc point*[A](v: A, t: typedesc[Option[A]]): Option[A] =
|
||||
discard
|
||||
|
||||
discard point(1, Option)
|
||||
echo "OK"
|
||||
422
tests/js/trepr.nim
Normal file
422
tests/js/trepr.nim
Normal file
@@ -0,0 +1,422 @@
|
||||
discard """
|
||||
action: run
|
||||
"""
|
||||
|
||||
block ints:
|
||||
let
|
||||
na: int8 = -120'i8
|
||||
nb: int16 = -32700'i16
|
||||
nc: int32 = -2147483000'i32
|
||||
nd: int64 = -9223372036854775000'i64
|
||||
ne: int = -1234567
|
||||
pa: int8 = 120'i8
|
||||
pb: int16 = 32700'i16
|
||||
pc: int32 = 2147483000'i32
|
||||
pd: int64 = 9223372036854775000'i64
|
||||
pe: int = 1234567
|
||||
|
||||
doAssert(repr(na) == "-120")
|
||||
doAssert(repr(nb) == "-32700")
|
||||
doAssert(repr(nc) == "-2147483000")
|
||||
doAssert(repr(nd) == "-9223372036854775000")
|
||||
doAssert(repr(ne) == "-1234567")
|
||||
doAssert(repr(pa) == "120")
|
||||
doAssert(repr(pb) == "32700")
|
||||
doAssert(repr(pc) == "2147483000")
|
||||
doAssert(repr(pd) == "9223372036854775000")
|
||||
doAssert(repr(pe) == "1234567")
|
||||
|
||||
block uints:
|
||||
let
|
||||
a: uint8 = 254'u8
|
||||
b: uint16 = 65300'u16
|
||||
c: uint32 = 4294967290'u32
|
||||
# d: uint64 = 18446744073709551610'u64 -> unknown node type
|
||||
e: uint = 1234567
|
||||
|
||||
doAssert(repr(a) == "254")
|
||||
doAssert(repr(b) == "65300")
|
||||
doAssert(repr(c) == "4294967290")
|
||||
# doAssert(repr(d) == "18446744073709551610")
|
||||
doAssert(repr(e) == "1234567")
|
||||
|
||||
block floats:
|
||||
let
|
||||
a: float32 = 3.4e38'f32
|
||||
b: float64 = 1.7976931348623157e308'f64
|
||||
c: float = 1234.567e89
|
||||
|
||||
when defined js:
|
||||
doAssert(repr(a) == "3.4e+38") # in C: 3.399999952144364e+038
|
||||
doAssert(repr(b) == "1.7976931348623157e+308") # in C: 1.797693134862316e+308
|
||||
doAssert(repr(c) == "1.234567e+92") # in C: 1.234567e+092
|
||||
|
||||
block bools:
|
||||
let
|
||||
a: bool = true
|
||||
b: bool = false
|
||||
|
||||
doAssert(repr(a) == "true")
|
||||
doAssert(repr(b) == "false")
|
||||
|
||||
block enums:
|
||||
type
|
||||
AnEnum = enum
|
||||
aeA
|
||||
aeB
|
||||
aeC
|
||||
HoledEnum = enum
|
||||
heA = -12
|
||||
heB = 15
|
||||
heC = 123
|
||||
|
||||
doAssert(repr(aeA) == "aeA")
|
||||
doAssert(repr(aeB) == "aeB")
|
||||
doAssert(repr(aeC) == "aeC")
|
||||
doAssert(repr(heA) == "heA")
|
||||
doAssert(repr(heB) == "heB")
|
||||
doAssert(repr(heC) == "heC")
|
||||
|
||||
block chars:
|
||||
let
|
||||
a = 'a'
|
||||
b = 'z'
|
||||
one = '1'
|
||||
nl = '\x0A'
|
||||
|
||||
doAssert(repr(a) == "'a'")
|
||||
doAssert(repr(b) == "'z'")
|
||||
doAssert(repr(one) == "'1'")
|
||||
doAssert(repr(nl) == "'\\10'")
|
||||
|
||||
block strings:
|
||||
let
|
||||
a: string = "12345"
|
||||
b: string = "hello,repr"
|
||||
c: string = "hi\nthere"
|
||||
when defined js: # C prepends the pointer, JS does not.
|
||||
doAssert(repr(a) == "\"12345\"")
|
||||
doAssert(repr(b) == "\"hello,repr\"")
|
||||
doAssert(repr(c) == "\"hi\nthere\"")
|
||||
|
||||
block sets:
|
||||
let
|
||||
a: set[int16] = {1'i16, 2'i16, 3'i16}
|
||||
b: set[char] = {'A', 'k'}
|
||||
|
||||
doAssert(repr(a) == "{1, 2, 3}")
|
||||
doAssert(repr(b) == "{'A', 'k'}")
|
||||
|
||||
block ranges:
|
||||
let
|
||||
a: range[0..12] = 6
|
||||
b: range[-12..0] = -6
|
||||
doAssert(repr(a) == "6")
|
||||
doAssert(repr(b) == "-6")
|
||||
|
||||
block tuples:
|
||||
type
|
||||
ATuple = tuple
|
||||
a: int
|
||||
b: float
|
||||
c: string
|
||||
d: OtherTuple
|
||||
OtherTuple = tuple
|
||||
a: bool
|
||||
b: int8
|
||||
|
||||
let
|
||||
ot: OtherTuple = (a: true, b: 120'i8)
|
||||
t: ATuple = (a: 42, b: 12.34, c: "tuple", d: ot)
|
||||
when defined js:
|
||||
doAssert(repr(ot) == """
|
||||
[Field0 = true,
|
||||
Field1 = 120]
|
||||
""")
|
||||
doAssert(repr(t) == """
|
||||
[Field0 = 42,
|
||||
Field1 = 12.34,
|
||||
Field2 = "tuple",
|
||||
Field3 = [Field0 = true,
|
||||
Field1 = 120]]
|
||||
""")
|
||||
|
||||
block objects:
|
||||
type
|
||||
AnObj = object
|
||||
a: int
|
||||
b: float
|
||||
c: OtherObj
|
||||
OtherObj = object
|
||||
a: bool
|
||||
b: int8
|
||||
let
|
||||
oo: OtherObj = OtherObj(a: true, b: 120'i8)
|
||||
o: AnObj = AnObj(a: 42, b: 12.34, c: oo)
|
||||
|
||||
doAssert(repr(oo) == """
|
||||
[a = true,
|
||||
b = 120]
|
||||
""")
|
||||
doAssert(repr(o) == """
|
||||
[a = 42,
|
||||
b = 12.34,
|
||||
c = [a = true,
|
||||
b = 120]]
|
||||
""")
|
||||
|
||||
block arrays:
|
||||
type
|
||||
AObj = object
|
||||
x: int
|
||||
y: array[3,float]
|
||||
let
|
||||
a = [0.0, 1, 2]
|
||||
b = [a, a, a]
|
||||
o = AObj(x: 42, y: a)
|
||||
c = [o, o, o]
|
||||
d = ["hi", "array", "!"]
|
||||
|
||||
doAssert(repr(a) == "[0.0, 1.0, 2.0]\n")
|
||||
doAssert(repr(b) == "[[0.0, 1.0, 2.0], [0.0, 1.0, 2.0], [0.0, 1.0, 2.0]]\n")
|
||||
doAssert(repr(c) == """
|
||||
[[x = 42,
|
||||
y = [0.0, 1.0, 2.0]], [x = 42,
|
||||
y = [0.0, 1.0, 2.0]], [x = 42,
|
||||
y = [0.0, 1.0, 2.0]]]
|
||||
""")
|
||||
doAssert(repr(d) == "[\"hi\", \"array\", \"!\"]\n")
|
||||
|
||||
block seqs:
|
||||
type
|
||||
AObj = object
|
||||
x: int
|
||||
y: seq[float]
|
||||
let
|
||||
a = @[0.0, 1, 2]
|
||||
b = @[a, a, a]
|
||||
o = AObj(x: 42, y: a)
|
||||
c = @[o, o, o]
|
||||
d = @["hi", "array", "!"]
|
||||
|
||||
doAssert(repr(a) == "@[0.0, 1.0, 2.0]\n")
|
||||
doAssert(repr(b) == "@[@[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0]]\n")
|
||||
doAssert(repr(c) == """
|
||||
@[[x = 42,
|
||||
y = @[0.0, 1.0, 2.0]], [x = 42,
|
||||
y = @[0.0, 1.0, 2.0]], [x = 42,
|
||||
y = @[0.0, 1.0, 2.0]]]
|
||||
""")
|
||||
doAssert(repr(d) == "@[\"hi\", \"array\", \"!\"]\n")
|
||||
|
||||
block ptrs:
|
||||
type
|
||||
AObj = object
|
||||
x: ptr array[2, AObj]
|
||||
y: int
|
||||
var
|
||||
a = [12.0, 13.0, 14.0]
|
||||
b = addr a[0]
|
||||
c = addr a[2]
|
||||
d = AObj()
|
||||
|
||||
doAssert(repr(a) == "[12.0, 13.0, 14.0]\n")
|
||||
doAssert(repr(b) == "ref 0 --> 12.0\n")
|
||||
doAssert(repr(c) == "ref 2 --> 14.0\n")
|
||||
doAssert(repr(d) == """
|
||||
[x = nil,
|
||||
y = 0]
|
||||
""")
|
||||
|
||||
block ptrs:
|
||||
type
|
||||
AObj = object
|
||||
x: ref array[2, AObj]
|
||||
y: int
|
||||
var
|
||||
a = AObj()
|
||||
|
||||
new(a.x)
|
||||
|
||||
doAssert(repr(a) == """
|
||||
[x = ref 0 --> [[x = nil,
|
||||
y = 0], [x = nil,
|
||||
y = 0]],
|
||||
y = 0]
|
||||
""")
|
||||
|
||||
block procs:
|
||||
proc test(): int =
|
||||
echo "hello"
|
||||
var
|
||||
ptest = test
|
||||
nilproc: proc(): int
|
||||
|
||||
doAssert(repr(test) == "0\n")
|
||||
doAssert(repr(ptest) == "0\n")
|
||||
doAssert(repr(nilproc) == "nil\n")
|
||||
|
||||
block bunch:
|
||||
type
|
||||
AnEnum = enum
|
||||
eA, eB, eC
|
||||
B = object
|
||||
a: string
|
||||
b: seq[char]
|
||||
A = object
|
||||
a: uint32
|
||||
b: int
|
||||
c: float
|
||||
d: char
|
||||
e: AnEnum
|
||||
f: string
|
||||
g: set[char]
|
||||
h: set[int16]
|
||||
i: array[3,string]
|
||||
j: seq[string]
|
||||
k: range[-12..12]
|
||||
l: B
|
||||
m: ref B
|
||||
n: ptr B
|
||||
o: tuple[x: B, y: string]
|
||||
p: proc(b: B): ref B
|
||||
q: cstring
|
||||
|
||||
proc refB(b:B):ref B =
|
||||
new result
|
||||
result[] = b
|
||||
|
||||
var
|
||||
aa: A
|
||||
bb: B = B(a: "inner", b: @['o', 'b', 'j'])
|
||||
cc: A = A(a: 12, b: 1, c: 1.2, d: '\0', e: eC,
|
||||
f: "hello", g: {'A'}, h: {2'i16},
|
||||
i: ["hello", "world", "array"],
|
||||
j: @["hello", "world", "seq"], k: -1,
|
||||
l: bb, m: refB(bb), n: addr bb,
|
||||
o: (bb, "tuple!"), p: refB, q: "cstringtest" )
|
||||
|
||||
doAssert(repr(aa) == """
|
||||
[a = 0,
|
||||
b = 0,
|
||||
c = 0.0,
|
||||
d = '\0',
|
||||
e = eA,
|
||||
f = nil,
|
||||
g = {},
|
||||
h = {},
|
||||
i = [nil, nil, nil],
|
||||
j = nil,
|
||||
k = 0,
|
||||
l = [a = nil,
|
||||
b = nil],
|
||||
m = nil,
|
||||
n = nil,
|
||||
o = [Field0 = [a = nil,
|
||||
b = nil],
|
||||
Field1 = nil],
|
||||
p = nil,
|
||||
q = nil]
|
||||
""")
|
||||
doAssert(repr(cc) == """
|
||||
[a = 12,
|
||||
b = 1,
|
||||
c = 1.2,
|
||||
d = '\0',
|
||||
e = eC,
|
||||
f = "hello",
|
||||
g = {'A'},
|
||||
h = {2},
|
||||
i = ["hello", "world", "array"],
|
||||
j = @["hello", "world", "seq"],
|
||||
k = -1,
|
||||
l = [a = "inner",
|
||||
b = @['o', 'b', 'j']],
|
||||
m = ref 0 --> [a = "inner",
|
||||
b = @['o', 'b', 'j']],
|
||||
n = ref 0 --> [a = "inner",
|
||||
b = @['o', 'b', 'j']],
|
||||
o = [Field0 = [a = "inner",
|
||||
b = @['o', 'b', 'j']],
|
||||
Field1 = "tuple!"],
|
||||
p = 0,
|
||||
q = "cstringtest"]
|
||||
""")
|
||||
|
||||
block another:
|
||||
type
|
||||
Size1 = enum
|
||||
s1a, s1b
|
||||
Size2 = enum
|
||||
s2c=0, s2d=20000
|
||||
Size3 = enum
|
||||
s3e=0, s3f=2000000000
|
||||
|
||||
doAssert(repr([s1a, s1b]) == "[s1a, s1b]\n")
|
||||
doAssert(repr([s2c, s2d]) == "[s2c, s2d]\n")
|
||||
doAssert(repr([s3e, s3f]) == "[s3e, s3f]\n")
|
||||
|
||||
block another2:
|
||||
|
||||
type
|
||||
AnEnum = enum
|
||||
en1, en2, en3, en4, en5, en6
|
||||
|
||||
Point {.final.} = object
|
||||
x, y, z: int
|
||||
s: array[0..1, string]
|
||||
e: AnEnum
|
||||
|
||||
var
|
||||
p: Point
|
||||
q: ref Point
|
||||
s: seq[ref Point]
|
||||
|
||||
p.x = 0
|
||||
p.y = 13
|
||||
p.z = 45
|
||||
p.s[0] = "abc"
|
||||
p.s[1] = "xyz"
|
||||
p.e = en6
|
||||
|
||||
new(q)
|
||||
q[] = p
|
||||
|
||||
s = @[q, q, q, q]
|
||||
|
||||
doAssert(repr(p) == """
|
||||
[x = 0,
|
||||
y = 13,
|
||||
z = 45,
|
||||
s = ["abc", "xyz"],
|
||||
e = en6]
|
||||
""")
|
||||
doAssert(repr(q) == """
|
||||
ref 0 --> [x = 0,
|
||||
y = 13,
|
||||
z = 45,
|
||||
s = ["abc", "xyz"],
|
||||
e = en6]
|
||||
""")
|
||||
doAssert(repr(s) == """
|
||||
@[ref 0 --> [x = 0,
|
||||
y = 13,
|
||||
z = 45,
|
||||
s = ["abc", "xyz"],
|
||||
e = en6], ref 1 --> [x = 0,
|
||||
y = 13,
|
||||
z = 45,
|
||||
s = ["abc", "xyz"],
|
||||
e = en6], ref 2 --> [x = 0,
|
||||
y = 13,
|
||||
z = 45,
|
||||
s = ["abc", "xyz"],
|
||||
e = en6], ref 3 --> [x = 0,
|
||||
y = 13,
|
||||
z = 45,
|
||||
s = ["abc", "xyz"],
|
||||
e = en6]]
|
||||
""")
|
||||
doAssert(repr(en4) == "en4")
|
||||
|
||||
doAssert(repr({'a'..'p'}) == "{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'}")
|
||||
@@ -45,11 +45,12 @@ Changes affecting backwards compatibility
|
||||
- If the dispatcher parameter's value used in multi method is ``nil``,
|
||||
a ``NilError`` exception is raised. The old behavior was that the method
|
||||
would be a ``nop`` then.
|
||||
- ``posix.nim``: the family of ``ntohs`` procs now takes unsigned integers
|
||||
instead of signed integers.
|
||||
- In Nim identifiers en-dash (Unicode point U+2013) is not an alias for the
|
||||
underscore anymore. Use underscores and fix your programming font instead.
|
||||
|
||||
|
||||
|
||||
Library Additions
|
||||
-----------------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user