diff --git a/compiler/cgen.nim b/compiler/cgen.nim index fd15d07934..b27d9cbce6 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1315,8 +1315,11 @@ proc shouldRecompile(code: Rope, cfile: Cfile): bool = if optForceFullMake notin gGlobalOptions: if not equalsFile(code, cfile.cname): if isDefined("nimdiff"): - copyFile(cfile.cname, cfile.cname & ".backup") - echo "diff ", cfile.cname, ".backup ", cfile.cname + if fileExists(cfile.cname): + copyFile(cfile.cname, cfile.cname & ".backup") + echo "diff ", cfile.cname, ".backup ", cfile.cname + else: + echo "new file ", cfile.cname writeRope(code, cfile.cname) return if existsFile(cfile.obj) and os.fileNewer(cfile.obj, cfile.cname): diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 0016a8492b..ad988d1b08 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -434,22 +434,23 @@ proc binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) = proc unsignedTrimmerJS(size: BiggestInt): Rope = case size - of 1: rope"& 0xff" - of 2: rope"& 0xffff" - of 4: rope">>> 0" - else: rope"" + of 1: rope"& 0xff" + of 2: rope"& 0xffff" + of 4: rope">>> 0" + else: rope"" proc unsignedTrimmerPHP(size: BiggestInt): Rope = case size - of 1: rope"& 0xff" - of 2: rope"& 0xffff" - of 4: rope"& 0xffffffff" - else: rope"" + of 1: rope"& 0xff" + of 2: rope"& 0xffff" + of 4: rope"& 0xffffffff" + else: rope"" template unsignedTrimmer(size: BiggestInt): Rope = size.unsignedTrimmerJS | size.unsignedTrimmerPHP -proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string, reassign: bool = false) = +proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string, + reassign = false) = var x, y: TCompRes gen(p, n.sons[1], x) gen(p, n.sons[2], y) @@ -1633,11 +1634,11 @@ proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = gen(p, n.sons[1], a) if magic == "reprAny": - # the pointer argument in reprAny is expandend to + # 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") + add(r.res, ", null") else: add(r.res, "$1, $2" % [a.address, a.res]) else: @@ -1670,7 +1671,7 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) = genReprAux(p, n, r, "reprSet", genTypeInfo(p, t)) of tyEmpty, tyVoid: localError(n.info, "'repr' doesn't support 'void' type") - of tyPointer: + of tyPointer: genReprAux(p, n, r, "reprPointer") of tyOpenArray, tyVarargs: genReprAux(p, n, r, "reprJSONStringify") @@ -2128,6 +2129,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = else: r.res = rope(f.toStrMaxPrecision) r.kind = resExpr of nkCallKinds: + if isEmptyType(n.typ): genLineDir(p, n) if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone): genMagic(p, n, r) elif n.sons[0].kind == nkSym and sfInfixCall in n.sons[0].sym.flags and diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 01635cf48d..4bd54603d8 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -74,7 +74,7 @@ proc lowerTupleUnpackingForAsgn*(n: PNode; owner: PSym): PNode = let value = n.lastSon result = newNodeI(nkStmtList, n.info) - var temp = newSym(skLet, getIdent(genPrefix), owner, value.info) + var temp = newSym(skLet, getIdent("_"), owner, value.info) var v = newNodeI(nkLetSection, value.info) let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info) diff --git a/koch.nim b/koch.nim index e24367dd50..da99ea264e 100644 --- a/koch.nim +++ b/koch.nim @@ -178,7 +178,7 @@ proc bundleNimbleExe() = bundleNimbleSrc() # now compile Nimble and copy it to $nim/bin for the installer.ini # to pick it up: - nimexec("c dist/nimble/src/nimble.nim") + nimexec("c -d:release dist/nimble/src/nimble.nim") copyExe("dist/nimble/src/nimble".exe, "bin/nimble".exe) proc buildNimble(latest: bool) = @@ -205,7 +205,7 @@ proc buildNimble(latest: bool) = else: exec("git checkout -f stable") exec("git pull") - nimexec("c --noNimblePath -p:compiler " & installDir / "src/nimble.nim") + nimexec("c --noNimblePath -p:compiler -d:release " & installDir / "src/nimble.nim") copyExe(installDir / "src/nimble".exe, "bin/nimble".exe) proc bundleNimsuggest(buildExe: bool) = diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index ab608efc6a..02312a4d52 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -97,15 +97,6 @@ when not defined(macosx): ## Second-granularity time of last status change. result = s.st_ctim.tv_sec -proc WIFCONTINUED*(s:cint) : bool {.importc, header: "".} - ## True if child has been continued. -proc WIFEXITED*(s:cint) : bool {.importc, header: "".} - ## True if child exited normally. -proc WIFSIGNALED*(s:cint) : bool {.importc, header: "".} - ## True if child exited due to uncaught signal. -proc WIFSTOPPED*(s:cint) : bool {.importc, header: "".} - ## True if child is currently stopped. - when hasAioH: proc aio_cancel*(a1: cint, a2: ptr Taiocb): cint {.importc, header: "".} proc aio_error*(a1: ptr Taiocb): cint {.importc, header: "".} diff --git a/lib/posix/posix_linux_amd64.nim b/lib/posix/posix_linux_amd64.nim index 4948642c1a..70f7e710f5 100644 --- a/lib/posix/posix_linux_amd64.nim +++ b/lib/posix/posix_linux_amd64.nim @@ -602,3 +602,12 @@ var include posix_linux_amd64_consts const POSIX_SPAWN_USEVFORK* = cint(0x40) # needs _GNU_SOURCE! + +# +proc WEXITSTATUS*(s: cint): cint = (s and 0xff00) shr 8 +proc WTERMSIG*(s:cint): cint = s and 0x7f +proc WSTOPSIG*(s:cint): cint = WEXITSTATUS(s) +proc WIFEXITED*(s:cint) : bool = WTERMSIG(s) == 0 +proc WIFSIGNALED*(s:cint) : bool = (cast[int8]((s and 0x7f) + 1) shr 1) > 0 +proc WIFSTOPPED*(s:cint) : bool = (s and 0xff) == 0x7f +proc WIFCONTINUED*(s:cint) : bool = s == W_CONTINUED diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim index 6e1c336056..b1cc244b78 100644 --- a/lib/posix/posix_other.nim +++ b/lib/posix/posix_other.nim @@ -611,3 +611,18 @@ when hasSpawnH: # OR'ing of flags: const POSIX_SPAWN_USEVFORK* = cint(0) +# +proc WEXITSTATUS*(s: cint): cint {.importc, header: "".} + ## Exit code, iff WIFEXITED(s) +proc WTERMSIG*(s: cint): cint {.importc, header: "".} + ## Termination signal, iff WIFSIGNALED(s) +proc WSTOPSIG*(s: cint): cint {.importc, header: "".} + ## Stop signal, iff WIFSTOPPED(s) +proc WIFEXITED*(s: cint): bool {.importc, header: "".} + ## True if child exited normally. +proc WIFSIGNALED*(s: cint): bool {.importc, header: "".} + ## True if child exited due to uncaught signal. +proc WIFSTOPPED*(s: cint): bool {.importc, header: "".} + ## True if child is currently stopped. +proc WIFCONTINUED*(s: cint): bool {.importc, header: "".} + ## True if child has been continued. diff --git a/lib/pure/json.nim b/lib/pure/json.nim index a6659638de..564f952d38 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1213,22 +1213,22 @@ when not defined(js): proc parseJson*(s: Stream, filename: string): JsonNode = ## Parses from a stream `s` into a `JsonNode`. `filename` is only needed ## for nice error messages. - ## If `s` contains extra data, it will raising `JsonParsingError`. + ## If `s` contains extra data, it will raise `JsonParsingError`. var p: JsonParser p.open(s, filename) defer: p.close() discard getTok(p) # read first token result = p.parseJson() - eat(p, tkEof) # check there are no exstra data + eat(p, tkEof) # check if there is no extra data proc parseJson*(buffer: string): JsonNode = ## Parses JSON from `buffer`. - ## If `buffer` contains extra data, it will raising `JsonParsingError`. + ## If `buffer` contains extra data, it will raise `JsonParsingError`. result = parseJson(newStringStream(buffer), "input") proc parseFile*(filename: string): JsonNode = ## Parses `file` into a `JsonNode`. - ## If `file` contains extra data, it will raising `JsonParsingError`. + ## If `file` contains extra data, it will raise `JsonParsingError`. var stream = newFileStream(filename, fmRead) if stream == nil: raise newException(IOError, "cannot read from file: " & filename) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 0f37f8fe01..82a0c0c659 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -209,9 +209,16 @@ proc waitForExit*(p: Process, timeout: int = -1): int {.rtl, ## ## **Warning**: Be careful when using waitForExit for processes created without ## poParentStreams because they may fill output buffers, causing deadlock. + ## + ## On posix, if the process has exited because of a signal, 128 + signal + ## number will be returned. + proc peekExitCode*(p: Process): int {.tags: [].} ## return -1 if the process is still running. Otherwise the process' exit code + ## + ## On posix, if the process has exited because of a signal, 128 + signal + ## number will be returned. proc inputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## returns ``p``'s input stream for writing to. @@ -679,6 +686,16 @@ elif not defined(useNimRtl): readIdx = 0 writeIdx = 1 + proc isExitStatus(status: cint): bool = + WIFEXITED(status) or WIFSIGNALED(status) + + proc exitStatus(status: cint): cint = + if WIFSIGNALED(status): + # like the shell! + 128 + WTERMSIG(status) + else: + WEXITSTATUS(status) + proc envToCStringArray(t: StringTableRef): cstringArray = result = cast[cstringArray](alloc0((t.len + 1) * sizeof(cstring))) var i = 0 @@ -967,7 +984,7 @@ elif not defined(useNimRtl): var status : cint = 1 ret = waitpid(p.id, status, WNOHANG) if ret == int(p.id): - if WIFEXITED(status): + if isExitStatus(status): p.exitStatus = status return false else: @@ -990,7 +1007,9 @@ elif not defined(useNimRtl): import kqueue, times proc waitForExit(p: Process, timeout: int = -1): int = - if p.exitStatus != -3: return((p.exitStatus and 0xFF00) shr 8) + if p.exitStatus != -3: + return exitStatus(p.exitStatus) + if timeout == -1: var status : cint = 1 if waitpid(p.id, status, 0) < 0: @@ -1041,7 +1060,7 @@ elif not defined(useNimRtl): finally: discard posix.close(kqFD) - result = ((p.exitStatus and 0xFF00) shr 8) + result = exitStatus(p.exitStatus) else: import times @@ -1077,7 +1096,9 @@ elif not defined(useNimRtl): # ``waitPid`` fails if the process is not running anymore. But then # ``running`` probably set ``p.exitStatus`` for us. Since ``p.exitStatus`` is # initialized with -3, wrong success exit codes are prevented. - if p.exitStatus != -3: return((p.exitStatus and 0xFF00) shr 8) + if p.exitStatus != -3: + return exitStatus(p.exitStatus) + if timeout == -1: var status : cint = 1 if waitpid(p.id, status, 0) < 0: @@ -1151,17 +1172,19 @@ elif not defined(useNimRtl): if sigprocmask(SIG_UNBLOCK, nmask, omask) == -1: raiseOSError(osLastError()) - result = ((p.exitStatus and 0xFF00) shr 8) + result = exitStatus(p.exitStatus) proc peekExitCode(p: Process): int = var status = cint(0) result = -1 - if p.exitStatus != -3: return((p.exitStatus and 0xFF00) shr 8) + if p.exitStatus != -3: + return exitStatus(p.exitStatus) + var ret = waitpid(p.id, status, WNOHANG) if ret > 0: - if WIFEXITED(status): + if isExitStatus(status): p.exitStatus = status - result = (status and 0xFF00) shr 8 + result = exitStatus(status) proc createStream(stream: var Stream, handle: var FileHandle, fileMode: FileMode) = @@ -1189,7 +1212,8 @@ elif not defined(useNimRtl): proc execCmd(command: string): int = when defined(linux): - result = csystem(command) shr 8 + let tmp = csystem(command) + result = if tmp == -1: tmp else: exitStatus(tmp) else: result = csystem(command) diff --git a/lib/system.nim b/lib/system.nim index 82d3bb7f7d..9b41253cca 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2016,6 +2016,12 @@ proc min*(x, y: float): float {.magic: "MinF64", noSideEffect.} = if x <= y: x else: y proc max*(x, y: float): float {.magic: "MaxF64", noSideEffect.} = if y <= x: x else: y + +proc min*[T](x, y: T): T = + if x <= y: x else: y + +proc max*[T](x, y: T): T = + if y <= x: x else: y {.pop.} proc clamp*[T](x, a, b: T): T = diff --git a/tests/osproc/texitsignal.nim b/tests/osproc/texitsignal.nim new file mode 100644 index 0000000000..c0bed70ee6 --- /dev/null +++ b/tests/osproc/texitsignal.nim @@ -0,0 +1,36 @@ +discard """ + output: '''true +true''' + targets: "c" +""" + +import os, osproc +when not defined(windows): + import posix + +# Checks that the environment is passed correctly in startProcess +# To do that launches a copy of itself with a new environment. + +if paramCount() == 0: + # Parent process + + let p = startProcess( + getAppFilename(), + args = @["child"], + options = {poStdErrToStdOut, poUsePath, poParentStreams} + ) + + echo p.running() + + p.kill() + + when defined(windows): + # windows kill happens using TerminateProcess(h, 0), so we should get a + # 0 here + echo p.waitForExit() == 0 + else: + # on posix (non-windows), kill sends SIGKILL + echo p.waitForExit() == 128 + SIGKILL + +else: + sleep(5000) # should get killed before this \ No newline at end of file diff --git a/tests/tuples/tunpack_asgn.nim b/tests/tuples/tunpack_asgn.nim index a48fcff5da..1dc7ff0749 100644 --- a/tests/tuples/tunpack_asgn.nim +++ b/tests/tuples/tunpack_asgn.nim @@ -21,6 +21,8 @@ proc pg[T](x, y: var T) = # test as a top level statement: var x, y, a, b: int +# test for regression: +(x, y) = (1, 2) (x, y) = fooBar() echo x, " ", y diff --git a/web/news/e031_version_0_16_2.rst b/web/news/e031_version_0_16_2.rst index fd12bb822e..b38f0c159c 100644 --- a/web/news/e031_version_0_16_2.rst +++ b/web/news/e031_version_0_16_2.rst @@ -13,6 +13,9 @@ Changelog Changes affecting backwards compatibility ----------------------------------------- +- There are now two different HTTP response types, ``Response`` and + ``AsyncResponse``. ``AsyncResponse``'s ``body`` accessor returns a + ``Future[string]``! - ``httpclient.request`` now respects ``maxRedirects`` option. Previously redirects were handled only by ``get`` and ``post`` procs. - The IO routines now raise ``EOFError`` for the "end of file" condition. @@ -56,6 +59,8 @@ Changes affecting backwards compatibility checks. When fields within case objects are initialiazed, the compiler will now demand that the respective discriminator field has a matching known compile-time value. +- On posix, the results of `waitForExit`, `peekExitCode`, `execCmd` will return + 128 + signal number if the application terminates via signal. Library Additions -----------------