diff options
-rw-r--r-- | compiler/cgmeth.nim | 87 | ||||
-rw-r--r-- | compiler/transf.nim | 3 | ||||
-rw-r--r-- | koch.nim | 2 | ||||
-rw-r--r-- | lib/pure/osproc.nim | 32 | ||||
-rw-r--r-- | tests/method/tmproto.nim | 25 | ||||
-rw-r--r-- | tests/method/trecmeth.nim | 22 | ||||
-rw-r--r-- | tests/stdlib/tosprocterminate.nim | 21 |
7 files changed, 158 insertions, 34 deletions
diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 6703b1ba5..6c997b983 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -11,7 +11,7 @@ import intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys, - sempass2 + sempass2, strutils proc genConv(n: PNode, d: PType, downcast: bool): PNode = var dest = skipTypes(d, abstractPtrs) @@ -44,7 +44,8 @@ proc methodCall*(n: PNode): PNode = result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true) # save for incremental compilation: -var gMethods: seq[TSymSeq] = @[] +var + gMethods: seq[tuple[methods: TSymSeq, dispatcher: PSym]] = @[] proc sameMethodBucket(a, b: PSym): bool = result = false @@ -80,31 +81,70 @@ proc attachDispatcher(s: PSym, dispatcher: PNode) = else: s.ast.add(dispatcher) +proc createDispatcher(s: PSym): PSym = + var disp = copySym(s) + incl(disp.flags, sfDispatcher) + excl(disp.flags, sfExported) + disp.typ = copyType(disp.typ, disp.typ.owner, false) + # we can't inline the dispatcher itself (for now): + if disp.typ.callConv == ccInline: disp.typ.callConv = ccDefault + disp.ast = copyTree(s.ast) + disp.ast.sons[bodyPos] = ast.emptyNode + disp.loc.r = nil + if s.typ.sons[0] != nil: + if disp.ast.sonsLen > resultPos: + disp.ast.sons[resultPos].sym = copySym(s.ast.sons[resultPos].sym) + else: + # We've encountered a method prototype without a filled-in + # resultPos slot. We put a placeholder in there that will + # be updated in fixupDispatcher(). + disp.ast.addSon(ast.emptyNode) + attachDispatcher(s, newSymNode(disp)) + # attach to itself to prevent bugs: + attachDispatcher(disp, newSymNode(disp)) + return disp + +proc fixupDispatcher(meth, disp: PSym) = + # We may have constructed the dispatcher from a method prototype + # and need to augment the incomplete dispatcher with information + # from later definitions, particularly the resultPos slot. Also, + # the lock level of the dispatcher needs to be updated/checked + # against that of the method. + if disp.ast.sonsLen > resultPos and meth.ast.sonsLen > resultPos and + disp.ast.sons[resultPos] == ast.emptyNode: + disp.ast.sons[resultPos] = copyTree(meth.ast.sons[resultPos]) + + # The following code works only with lock levels, so we disable + # it when they're not available. + when declared(TLockLevel): + proc `<`(a, b: TLockLevel): bool {.borrow.} + proc `==`(a, b: TLockLevel): bool {.borrow.} + if disp.typ.lockLevel == UnspecifiedLockLevel: + disp.typ.lockLevel = meth.typ.lockLevel + elif meth.typ.lockLevel != UnspecifiedLockLevel and + meth.typ.lockLevel != disp.typ.lockLevel: + message(meth.info, warnLockLevel, + "method has lock level $1, but another method has $2" % + [$meth.typ.lockLevel, $disp.typ.lockLevel]) + # XXX The following code silences a duplicate warning in + # checkMethodeffects() in sempass2.nim for now. + if disp.typ.lockLevel < meth.typ.lockLevel: + disp.typ.lockLevel = meth.typ.lockLevel + proc methodDef*(s: PSym, fromCache: bool) = var L = len(gMethods) for i in countup(0, L - 1): - let disp = gMethods[i][0] + var disp = gMethods[i].dispatcher if sameMethodBucket(disp, s): - add(gMethods[i], s) + add(gMethods[i].methods, s) attachDispatcher(s, lastSon(disp.ast)) + fixupDispatcher(s, disp) when useEffectSystem: checkMethodEffects(disp, s) return - add(gMethods, @[s]) # create a new dispatcher: - if not fromCache: - var disp = copySym(s) - incl(disp.flags, sfDispatcher) - excl(disp.flags, sfExported) - disp.typ = copyType(disp.typ, disp.typ.owner, false) - # we can't inline the dispatcher itself (for now): - if disp.typ.callConv == ccInline: disp.typ.callConv = ccDefault - disp.ast = copyTree(s.ast) - disp.ast.sons[bodyPos] = ast.emptyNode - if s.typ.sons[0] != nil: - disp.ast.sons[resultPos].sym = copySym(s.ast.sons[resultPos].sym) - attachDispatcher(s, newSymNode(disp)) - # attach to itself to prevent bugs: - attachDispatcher(disp, newSymNode(disp)) + add(gMethods, (methods: @[s], dispatcher: createDispatcher(s))) + if fromCache: + internalError(s.info, "no method dispatcher found") proc relevantCol(methods: TSymSeq, col: int): bool = # returns true iff the position is relevant @@ -194,8 +234,9 @@ proc generateMethodDispatchers*(): PNode = result = newNode(nkStmtList) for bucket in countup(0, len(gMethods) - 1): var relevantCols = initIntSet() - for col in countup(1, sonsLen(gMethods[bucket][0].typ) - 1): - if relevantCol(gMethods[bucket], col): incl(relevantCols, col) - sortBucket(gMethods[bucket], relevantCols) - addSon(result, newSymNode(genDispatcher(gMethods[bucket], relevantCols))) + for col in countup(1, sonsLen(gMethods[bucket].methods[0].typ) - 1): + if relevantCol(gMethods[bucket].methods, col): incl(relevantCols, col) + sortBucket(gMethods[bucket].methods, relevantCols) + addSon(result, + newSymNode(genDispatcher(gMethods[bucket].methods, relevantCols))) diff --git a/compiler/transf.nim b/compiler/transf.nim index bab719ba1..6196512ba 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -624,6 +624,9 @@ proc transformCall(c: PTransf, n: PNode): PTransNode = # bugfix: check after 'transformSons' if it's still a method call: # use the dispatcher for the call: if s.sons[0].kind == nkSym and s.sons[0].sym.kind == skMethod: + let t = lastSon(s.sons[0].sym.ast) + if t.kind != nkSym or sfDispatcher notin t.sym.flags: + methodDef(s.sons[0].sym, false) result = methodCall(s).PTransNode else: result = s.PTransNode diff --git a/koch.nim b/koch.nim index cbc22b2a3..2de93bdea 100644 --- a/koch.nim +++ b/koch.nim @@ -92,7 +92,7 @@ const compileNimInst = "-d:useLibzipSrc tools/niminst/niminst" proc csource(args: string) = - exec("$4 cc $1 -r $3 --var:version=$2 csource compiler/nim.ini $1" % + exec("$4 cc $1 -r $3 --var:version=$2 --var:mingw=mingw32 csource compiler/nim.ini $1" % [args, VersionAsString, compileNimInst, findNim()]) proc zip(args: string) = diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 500ec7fb7..3963497fd 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -167,8 +167,14 @@ proc resume*(p: Process) {.rtl, extern: "nosp$1", tags: [].} ## Resumes the process `p`. proc terminate*(p: Process) {.rtl, extern: "nosp$1", tags: [].} - ## Terminates the process `p`. - + ## Stop the process `p`. On Posix OSes the procedure sends ``SIGTERM`` + ## to the process. On Windows the Win32 API function ``TerminateProcess()`` + ## is called to stop the process. + +proc kill*(p: Process) {.rtl, extern: "nosp$1", tags: [].} + ## Kill the process `p`. On Posix OSes the procedure sends ``SIGKILL`` to + ## the process. On Windows ``kill()`` is simply an alias for ``terminate()``. + proc running*(p: Process): bool {.rtl, extern: "nosp$1", tags: [].} ## Returns true iff the process `p` is still running. Returns immediately. @@ -489,7 +495,10 @@ when defined(Windows) and not defined(useNimRtl): if running(p): discard terminateProcess(p.fProcessHandle, 0) - proc waitForExit(p: Process, timeout: int = -1): int = + proc kill(p: PProcess) = + terminate(p) + + proc waitForExit(p: PProcess, timeout: int = -1): int = discard waitForSingleObject(p.fProcessHandle, timeout.int32) var res: int32 @@ -829,10 +838,10 @@ elif not defined(useNimRtl): discard close(p.errHandle) proc suspend(p: Process) = - if kill(-p.id, SIGSTOP) != 0'i32: raiseOSError(osLastError()) + if kill(p.id, SIGSTOP) != 0'i32: raiseOsError(osLastError()) proc resume(p: Process) = - if kill(-p.id, SIGCONT) != 0'i32: raiseOSError(osLastError()) + if kill(p.id, SIGCONT) != 0'i32: raiseOsError(osLastError()) proc running(p: Process): bool = var ret = waitpid(p.id, p.exitCode, WNOHANG) @@ -840,11 +849,13 @@ elif not defined(useNimRtl): result = ret == int(p.id) proc terminate(p: Process) = - if kill(-p.id, SIGTERM) == 0'i32: - if p.running(): - if kill(-p.id, SIGKILL) != 0'i32: raiseOSError(osLastError()) - else: raiseOSError(osLastError()) + if kill(p.id, SIGTERM) != 0'i32: + raiseOsError(osLastError()) + proc kill(p: Process) = + if kill(p.id, SIGKILL) != 0'i32: + raiseOsError(osLastError()) + proc waitForExit(p: Process, timeout: int = -1): int = #if waitPid(p.id, p.exitCode, 0) == int(p.id): # ``waitPid`` fails if the process is not running anymore. But then @@ -885,7 +896,8 @@ elif not defined(useNimRtl): createStream(p.errStream, p.errHandle, fmRead) return p.errStream - proc csystem(cmd: cstring): cint {.nodecl, importc: "system", header: "<stdlib.h>".} + proc csystem(cmd: cstring): cint {.nodecl, importc: "system", + header: "<stdlib.h>".} proc execCmd(command: string): int = when defined(linux): diff --git a/tests/method/tmproto.nim b/tests/method/tmproto.nim new file mode 100644 index 000000000..5d75cff1a --- /dev/null +++ b/tests/method/tmproto.nim @@ -0,0 +1,25 @@ +type + Obj1 = ref object {.inheritable.} + Obj2 = ref object of Obj1 + +method beta(x: Obj1): int + +proc delta(x: Obj2): int = + beta(x) + +method beta(x: Obj2): int + +proc alpha(x: Obj1): int = + beta(x) + +method beta(x: Obj1): int = 1 +method beta(x: Obj2): int = 2 + +proc gamma(x: Obj1): int = + beta(x) + +doAssert alpha(Obj1()) == 1 +doAssert gamma(Obj1()) == 1 +doAssert alpha(Obj2()) == 2 +doAssert gamma(Obj2()) == 2 +doAssert delta(Obj2()) == 2 diff --git a/tests/method/trecmeth.nim b/tests/method/trecmeth.nim new file mode 100644 index 000000000..32f620f15 --- /dev/null +++ b/tests/method/trecmeth.nim @@ -0,0 +1,22 @@ +# Note: We only compile this to verify that code generation +# for recursive methods works, no code is being executed + +type + Obj = ref object of TObject + +# Mutual recursion + +method alpha(x: Obj) +method beta(x: Obj) + +method alpha(x: Obj) = + beta(x) + +method beta(x: Obj) = + alpha(x) + +# Simple recursion + +method gamma(x: Obj) = + gamma(x) + diff --git a/tests/stdlib/tosprocterminate.nim b/tests/stdlib/tosprocterminate.nim new file mode 100644 index 000000000..fd044414c --- /dev/null +++ b/tests/stdlib/tosprocterminate.nim @@ -0,0 +1,21 @@ +import os, osproc + +when defined(Windows): + const ProgramWhichDoesNotEnd = "notepad" +else: + const ProgramWhichDoesNotEnd = "/bin/sh" + +echo("starting " & ProgramWhichDoesNotEnd) +var process = startProcess(ProgramWhichDoesNotEnd) +sleep(500) +echo("stopping process") +process.terminate() +var TimeToWait = 5000 +while process.running() and TimeToWait > 0: + sleep(100) + TimeToWait = TimeToWait - 100 + +if process.running(): + echo("FAILED") +else: + echo("SUCCESS") |