Merge branch 'devel' into bigbreak

Conflicts:
	lib/pure/osproc.nim
This commit is contained in:
Araq 2014-11-03 22:50:55 +01:00
commit a53e97fc89
7 changed files with 157 additions and 33 deletions

View file

@ -11,7 +11,7 @@
import import
intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys, intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys,
sempass2 sempass2, strutils
proc genConv(n: PNode, d: PType, downcast: bool): PNode = proc genConv(n: PNode, d: PType, downcast: bool): PNode =
var dest = skipTypes(d, abstractPtrs) 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) result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true)
# save for incremental compilation: # save for incremental compilation:
var gMethods: seq[TSymSeq] = @[] var
gMethods: seq[tuple[methods: TSymSeq, dispatcher: PSym]] = @[]
proc sameMethodBucket(a, b: PSym): bool = proc sameMethodBucket(a, b: PSym): bool =
result = false result = false
@ -80,18 +81,7 @@ proc attachDispatcher(s: PSym, dispatcher: PNode) =
else: else:
s.ast.add(dispatcher) s.ast.add(dispatcher)
proc methodDef*(s: PSym, fromCache: bool) = proc createDispatcher(s: PSym): PSym =
var L = len(gMethods)
for i in countup(0, L - 1):
let disp = gMethods[i][0]
if sameMethodBucket(disp, s):
add(gMethods[i], s)
attachDispatcher(s, lastSon(disp.ast))
when useEffectSystem: checkMethodEffects(disp, s)
return
add(gMethods, @[s])
# create a new dispatcher:
if not fromCache:
var disp = copySym(s) var disp = copySym(s)
incl(disp.flags, sfDispatcher) incl(disp.flags, sfDispatcher)
excl(disp.flags, sfExported) excl(disp.flags, sfExported)
@ -100,11 +90,61 @@ proc methodDef*(s: PSym, fromCache: bool) =
if disp.typ.callConv == ccInline: disp.typ.callConv = ccDefault if disp.typ.callConv == ccInline: disp.typ.callConv = ccDefault
disp.ast = copyTree(s.ast) disp.ast = copyTree(s.ast)
disp.ast.sons[bodyPos] = ast.emptyNode disp.ast.sons[bodyPos] = ast.emptyNode
disp.loc.r = nil
if s.typ.sons[0] != nil: if s.typ.sons[0] != nil:
if disp.ast.sonsLen > resultPos:
disp.ast.sons[resultPos].sym = copySym(s.ast.sons[resultPos].sym) 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)) attachDispatcher(s, newSymNode(disp))
# attach to itself to prevent bugs: # attach to itself to prevent bugs:
attachDispatcher(disp, newSymNode(disp)) 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):
var disp = gMethods[i].dispatcher
if sameMethodBucket(disp, s):
add(gMethods[i].methods, s)
attachDispatcher(s, lastSon(disp.ast))
fixupDispatcher(s, disp)
when useEffectSystem: checkMethodEffects(disp, s)
return
# create a new dispatcher:
add(gMethods, (methods: @[s], dispatcher: createDispatcher(s)))
if fromCache:
internalError(s.info, "no method dispatcher found")
proc relevantCol(methods: TSymSeq, col: int): bool = proc relevantCol(methods: TSymSeq, col: int): bool =
# returns true iff the position is relevant # returns true iff the position is relevant
@ -194,8 +234,9 @@ proc generateMethodDispatchers*(): PNode =
result = newNode(nkStmtList) result = newNode(nkStmtList)
for bucket in countup(0, len(gMethods) - 1): for bucket in countup(0, len(gMethods) - 1):
var relevantCols = initIntSet() var relevantCols = initIntSet()
for col in countup(1, sonsLen(gMethods[bucket][0].typ) - 1): for col in countup(1, sonsLen(gMethods[bucket].methods[0].typ) - 1):
if relevantCol(gMethods[bucket], col): incl(relevantCols, col) if relevantCol(gMethods[bucket].methods, col): incl(relevantCols, col)
sortBucket(gMethods[bucket], relevantCols) sortBucket(gMethods[bucket].methods, relevantCols)
addSon(result, newSymNode(genDispatcher(gMethods[bucket], relevantCols))) addSon(result,
newSymNode(genDispatcher(gMethods[bucket].methods, relevantCols)))

View file

@ -624,6 +624,9 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
# bugfix: check after 'transformSons' if it's still a method call: # bugfix: check after 'transformSons' if it's still a method call:
# use the dispatcher for the call: # use the dispatcher for the call:
if s.sons[0].kind == nkSym and s.sons[0].sym.kind == skMethod: 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 result = methodCall(s).PTransNode
else: else:
result = s.PTransNode result = s.PTransNode

View file

@ -92,7 +92,7 @@ const
compileNimInst = "-d:useLibzipSrc tools/niminst/niminst" compileNimInst = "-d:useLibzipSrc tools/niminst/niminst"
proc csource(args: string) = 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()]) [args, VersionAsString, compileNimInst, findNim()])
proc zip(args: string) = proc zip(args: string) =

View file

@ -167,7 +167,13 @@ proc resume*(p: Process) {.rtl, extern: "nosp$1", tags: [].}
## Resumes the process `p`. ## Resumes the process `p`.
proc terminate*(p: Process) {.rtl, extern: "nosp$1", tags: [].} 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: [].} proc running*(p: Process): bool {.rtl, extern: "nosp$1", tags: [].}
## Returns true iff the process `p` is still running. Returns immediately. ## 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): if running(p):
discard terminateProcess(p.fProcessHandle, 0) 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) discard waitForSingleObject(p.fProcessHandle, timeout.int32)
var res: int32 var res: int32
@ -829,10 +838,10 @@ elif not defined(useNimRtl):
discard close(p.errHandle) discard close(p.errHandle)
proc suspend(p: Process) = 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) = 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 = proc running(p: Process): bool =
var ret = waitpid(p.id, p.exitCode, WNOHANG) var ret = waitpid(p.id, p.exitCode, WNOHANG)
@ -840,10 +849,12 @@ elif not defined(useNimRtl):
result = ret == int(p.id) result = ret == int(p.id)
proc terminate(p: Process) = proc terminate(p: Process) =
if kill(-p.id, SIGTERM) == 0'i32: if kill(p.id, SIGTERM) != 0'i32:
if p.running(): raiseOsError(osLastError())
if kill(-p.id, SIGKILL) != 0'i32: raiseOSError(osLastError())
else: raiseOSError(osLastError()) proc kill(p: Process) =
if kill(p.id, SIGKILL) != 0'i32:
raiseOsError(osLastError())
proc waitForExit(p: Process, timeout: int = -1): int = proc waitForExit(p: Process, timeout: int = -1): int =
#if waitPid(p.id, p.exitCode, 0) == int(p.id): #if waitPid(p.id, p.exitCode, 0) == int(p.id):
@ -885,7 +896,8 @@ elif not defined(useNimRtl):
createStream(p.errStream, p.errHandle, fmRead) createStream(p.errStream, p.errHandle, fmRead)
return p.errStream 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 = proc execCmd(command: string): int =
when defined(linux): when defined(linux):

25
tests/method/tmproto.nim Normal file
View file

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

22
tests/method/trecmeth.nim Normal file
View file

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

View file

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