From b7f20588336760d0968c323d34b0d07d323b8ec8 Mon Sep 17 00:00:00 2001 From: cheatfate Date: Mon, 30 May 2016 13:18:31 +0300 Subject: [PATCH 01/16] Resolve #3059 Make getTimezone() to work properly on FreeBSD and NetBSD. --- lib/pure/times.nim | 107 ++++++++++++++++++++++++++++++++------------- 1 file changed, 76 insertions(+), 31 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index e0ee884a8..6fafb12b3 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -64,8 +64,9 @@ when defined(posix) and not defined(JS): proc posix_gettimeofday(tp: var Timeval, unused: pointer = nil) {. importc: "gettimeofday", header: "".} - var - timezone {.importc, header: "".}: int + when not defined(freebsd) and not defined(netbsd): + var timezone {.importc, header: "".}: int + var tzname {.importc, header: "" .}: array[0..1, cstring] # we also need tzset() to make sure that tzname is initialized proc tzset() {.importc, header: "".} @@ -416,18 +417,32 @@ when not defined(JS): when not defined(JS): # C wrapper: + when defined(freebsd) or defined(netbsd): + type + StructTM {.importc: "struct tm", final.} = object + second {.importc: "tm_sec".}, + minute {.importc: "tm_min".}, + hour {.importc: "tm_hour".}, + monthday {.importc: "tm_mday".}, + month {.importc: "tm_mon".}, + year {.importc: "tm_year".}, + weekday {.importc: "tm_wday".}, + yearday {.importc: "tm_yday".}, + isdst {.importc: "tm_isdst".}: cint + gmtoff {.importc: "tm_gmtoff".}: clong + else: + type + StructTM {.importc: "struct tm", final.} = object + second {.importc: "tm_sec".}, + minute {.importc: "tm_min".}, + hour {.importc: "tm_hour".}, + monthday {.importc: "tm_mday".}, + month {.importc: "tm_mon".}, + year {.importc: "tm_year".}, + weekday {.importc: "tm_wday".}, + yearday {.importc: "tm_yday".}, + isdst {.importc: "tm_isdst".}: cint type - StructTM {.importc: "struct tm", final.} = object - second {.importc: "tm_sec".}, - minute {.importc: "tm_min".}, - hour {.importc: "tm_hour".}, - monthday {.importc: "tm_mday".}, - month {.importc: "tm_mon".}, - year {.importc: "tm_year".}, - weekday {.importc: "tm_wday".}, - yearday {.importc: "tm_yday".}, - isdst {.importc: "tm_isdst".}: cint - TimeInfoPtr = ptr StructTM Clock {.importc: "clock_t".} = distinct int @@ -457,24 +472,47 @@ when not defined(JS): const weekDays: array [0..6, WeekDay] = [ dSun, dMon, dTue, dWed, dThu, dFri, dSat] - TimeInfo(second: int(tm.second), - minute: int(tm.minute), - hour: int(tm.hour), - monthday: int(tm.monthday), - month: Month(tm.month), - year: tm.year + 1900'i32, - weekday: weekDays[int(tm.weekday)], - yearday: int(tm.yearday), - isDST: tm.isdst > 0, - tzname: if local: - if tm.isdst > 0: - getTzname().DST + when defined(freebsd) or defined(netbsd): + TimeInfo(second: int(tm.second), + minute: int(tm.minute), + hour: int(tm.hour), + monthday: int(tm.monthday), + month: Month(tm.month), + year: tm.year + 1900'i32, + weekday: weekDays[int(tm.weekday)], + yearday: int(tm.yearday), + isDST: tm.isdst > 0, + tzname: if local: + if tm.isdst > 0: + getTzname().DST + else: + getTzname().nonDST else: - getTzname().nonDST - else: - "UTC", - timezone: if local: getTimezone() else: 0 - ) + "UTC", + # BSD stores in `gmtoff` offset east of UTC in seconds, + # but posix systems using west of UTC in seconds + timezone: if local: -(tm.gmtoff) else: 0 + ) + else: + TimeInfo(second: int(tm.second), + minute: int(tm.minute), + hour: int(tm.hour), + monthday: int(tm.monthday), + month: Month(tm.month), + year: tm.year + 1900'i32, + weekday: weekDays[int(tm.weekday)], + yearday: int(tm.yearday), + isDST: tm.isdst > 0, + tzname: if local: + if tm.isdst > 0: + getTzname().DST + else: + getTzname().nonDST + else: + "UTC", + timezone: if local: getTimezone() else: 0 + ) + proc timeInfoToTM(t: TimeInfo): StructTM = const @@ -564,7 +602,14 @@ when not defined(JS): return ($tzname[0], $tzname[1]) proc getTimezone(): int = - return timezone + when defined(freebsd) or defined(netbsd): + var a = timec(nil) + let lt = localtime(addr(a)) + # BSD stores in `gmtoff` offset east of UTC in seconds, + # but posix systems using west of UTC in seconds + return -(lt.gmtoff) + else: + return timezone proc fromSeconds(since1970: float): Time = Time(since1970) From 2264bd6097792ea0057b7c45cba28c418dc7f3aa Mon Sep 17 00:00:00 2001 From: cheatfate Date: Mon, 30 May 2016 14:39:29 +0300 Subject: [PATCH 02/16] Adding OpenBSD to defines --- lib/pure/times.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 6fafb12b3..f9d341e32 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -64,7 +64,7 @@ when defined(posix) and not defined(JS): proc posix_gettimeofday(tp: var Timeval, unused: pointer = nil) {. importc: "gettimeofday", header: "".} - when not defined(freebsd) and not defined(netbsd): + when not defined(freebsd) and not defined(netbsd) and not defined(openbsd): var timezone {.importc, header: "".}: int var tzname {.importc, header: "" .}: array[0..1, cstring] @@ -417,7 +417,7 @@ when not defined(JS): when not defined(JS): # C wrapper: - when defined(freebsd) or defined(netbsd): + when defined(freebsd) or defined(netbsd) or defined(openbsd): type StructTM {.importc: "struct tm", final.} = object second {.importc: "tm_sec".}, @@ -472,7 +472,7 @@ when not defined(JS): const weekDays: array [0..6, WeekDay] = [ dSun, dMon, dTue, dWed, dThu, dFri, dSat] - when defined(freebsd) or defined(netbsd): + when defined(freebsd) or defined(netbsd) or defined(openbsd): TimeInfo(second: int(tm.second), minute: int(tm.minute), hour: int(tm.hour), @@ -602,7 +602,7 @@ when not defined(JS): return ($tzname[0], $tzname[1]) proc getTimezone(): int = - when defined(freebsd) or defined(netbsd): + when defined(freebsd) or defined(netbsd) or defined(openbsd): var a = timec(nil) let lt = localtime(addr(a)) # BSD stores in `gmtoff` offset east of UTC in seconds, From 4180f59b27a5a323ee5d35ccf1038647290a12fb Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 May 2016 12:15:34 +0200 Subject: [PATCH 03/16] fixes #1713 --- compiler/ast.nim | 2 +- compiler/renderer.nim | 6 +++++- compiler/semcall.nim | 6 +++++- compiler/semstmts.nim | 17 +++++++++++++---- compiler/vmgen.nim | 12 ++++++++---- 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/compiler/ast.nim b/compiler/ast.nim index acd72479d..7275aceb1 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -938,7 +938,7 @@ const genericParamsPos* = 2 paramsPos* = 3 pragmasPos* = 4 - optimizedCodePos* = 5 # will be used for exception tracking + miscPos* = 5 # used for undocumented and hacky stuff bodyPos* = 6 # position of body; use rodread.getBody() instead! resultPos* = 7 dispatcherPos* = 8 # caution: if method has no 'result' it can be position 7! diff --git a/compiler/renderer.nim b/compiler/renderer.nim index f0ee137e9..e1db327f4 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -712,7 +712,11 @@ proc gproc(g: var TSrcGen, n: PNode) = gpattern(g, n.sons[patternPos]) let oldCheckAnon = g.checkAnon g.checkAnon = true - gsub(g, n.sons[genericParamsPos]) + if renderNoBody in g.flags and n[miscPos].kind != nkEmpty and + n[miscPos][1].kind != nkEmpty: + gsub(g, n[miscPos][1]) + else: + gsub(g, n.sons[genericParamsPos]) g.checkAnon = oldCheckAnon gsub(g, n.sons[paramsPos]) gsub(g, n.sons[pragmasPos]) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 17dd39595..65aa5fd58 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -129,7 +129,11 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = add(result, ')') var candidates = "" for err in errors: - add(candidates, err.getProcHeader(prefer)) + if err.kind in routineKinds and err.ast != nil: + add(candidates, renderTree(err.ast, + {renderNoBody, renderNoComments,renderNoPragmas})) + else: + add(candidates, err.getProcHeader(prefer)) add(candidates, "\n") if candidates != "": add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 20de8e928..fc5eec5c2 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -929,6 +929,17 @@ proc semProcAnnotation(c: PContext, prc: PNode; pragma(c, result[namePos].sym, result[pragmasPos], validPragmas) return +proc setGenericParamsMisc(c: PContext; n: PNode): PNode = + let orig = n.sons[genericParamsPos] + # we keep the original params around for better error messages, see + # issue https://github.com/nim-lang/Nim/issues/1713 + result = semGenericParamList(c, orig) + if n.sons[miscPos].kind == nkEmpty: + n.sons[miscPos] = newTree(nkBracket, ast.emptyNode, orig) + else: + n.sons[miscPos].sons[1] = orig + n.sons[genericParamsPos] = result + proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = # XXX semProcAux should be good enough for this now, we will eventually # remove semLambda @@ -947,8 +958,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = openScope(c) var gp: PNode if n.sons[genericParamsPos].kind != nkEmpty: - n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos]) - gp = n.sons[genericParamsPos] + gp = setGenericParamsMisc(c, n) else: gp = newNodeI(nkGenericParams, n.info) @@ -1170,8 +1180,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, openScope(c) var gp: PNode if n.sons[genericParamsPos].kind != nkEmpty: - n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos]) - gp = n.sons[genericParamsPos] + gp = setGenericParamsMisc(c, n) else: gp = newNodeI(nkGenericParams, n.info) # process parameters: diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 7832aa9b9..675fb2dc2 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1887,8 +1887,8 @@ proc optimizeJumps(c: PCtx; start: int) = else: discard proc genProc(c: PCtx; s: PSym): int = - let x = s.ast.sons[optimizedCodePos] - if x.kind == nkEmpty: + var x = s.ast.sons[miscPos] + if x.kind == nkEmpty or x[0].kind == nkEmpty: #if s.name.s == "outterMacro" or s.name.s == "innerProc": # echo "GENERATING CODE FOR ", s.name.s let last = c.code.len-1 @@ -1899,7 +1899,11 @@ proc genProc(c: PCtx; s: PSym): int = c.debug.setLen(last) #c.removeLastEof result = c.code.len+1 # skip the jump instruction - s.ast.sons[optimizedCodePos] = newIntNode(nkIntLit, result) + if x.kind == nkEmpty: + x = newTree(nkBracket, newIntNode(nkIntLit, result), ast.emptyNode) + else: + x.sons[0] = newIntNode(nkIntLit, result) + s.ast.sons[miscPos] = x # thanks to the jmp we can add top level statements easily and also nest # procs easily: let body = s.getBody @@ -1934,4 +1938,4 @@ proc genProc(c: PCtx; s: PSym): int = c.prc = oldPrc else: c.prc.maxSlots = s.offset - result = x.intVal.int + result = x[0].intVal.int From 5575cfd3ec6124fd0447b00b3edc40c0a25f79da Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 May 2016 14:37:18 +0200 Subject: [PATCH 04/16] added pure Nim random stdlib module --- doc/lib.txt | 3 ++ lib/pure/random.nim | 86 +++++++++++++++++++++++++++++++++++++++++++++ web/website.ini | 2 +- 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 lib/pure/random.nim diff --git a/doc/lib.txt b/doc/lib.txt index e24db97e0..24ba0243e 100644 --- a/doc/lib.txt +++ b/doc/lib.txt @@ -202,6 +202,9 @@ Math libraries * `mersenne `_ Mersenne twister random number generator. +* `random `_ + Fast and tiny random number generator. + * `stats `_ Statistical analysis diff --git a/lib/pure/random.nim b/lib/pure/random.nim new file mode 100644 index 000000000..5a4d45c38 --- /dev/null +++ b/lib/pure/random.nim @@ -0,0 +1,86 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2016 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## | Nim's standard random number generator. Based on +## | http://xoroshiro.di.unimi.it/ +## | http://xoroshiro.di.unimi.it/xoroshiro128plus.c + +include "system/inclrtl" +{.push debugger:off .} # the user does not want to trace a part + # of the standard library! + +# XXX Expose RandomGenState +type + RandomGenState = object + a0, a1: uint64 + +# racy for multi-threading but good enough for now: +var state = RandomGenState( + a0: 0x69B4C98CB8530805u64, + a1: 0xFED1DD3004688D67CAu64) # global for backwards compatibility + +proc rotl(x: uint64, k: uint64): uint64 = + result = (x shl k) or (x shr (64u64 - k)) + +proc next(s: var RandomGenState): uint64 = + let s0 = s.a0 + var s1 = s.a1 + result = s0 + s1 + s1 = s1 xor s0 + s.a0 = rotl(s0, 55) xor s1 xor (s1 shl 14) # a, b + s.a1 = rotl(s1, 36) # c + +proc skipRandomNumbers(s: var RandomGenState) = + ## This is the jump function for the generator. It is equivalent + ## to 2^64 calls to next(); it can be used to generate 2^64 + ## non-overlapping subsequences for parallel computations. + const helper = [0xbeac0467eba5facbu64, 0xd86b048b86aa9922u64] + var + s0 = 0u64 + s1 = 0u64 + for i in 0..high(helper): + for b in 0..< 64: + if (helper[i] and (1u64 shl uint64(b))) != 0: + s0 = s0 xor s.a0 + s1 = s1 xor s.a1 + discard next(s) + s.a0 = s0 + s.a1 = s1 + +proc random*(max: int): int {.benign.} = + ## Returns a random number in the range 0..max-1. The sequence of + ## random number is always the same, unless `randomize` is called + ## which initializes the random number generator with a "random" + ## number, i.e. a tickcount. + result = int(next(state) mod uint64(max)) + +proc random*(max: float): float {.benign.} = + ## Returns a random number in the range 0.. Date: Mon, 30 May 2016 15:07:19 +0200 Subject: [PATCH 05/16] moved random procs from math to its own module (breaking change) --- lib/pure/collections/sequtils.nim | 2 +- lib/pure/concurrency/cpuload.nim | 2 + lib/pure/httpclient.nim | 3 +- lib/pure/math.nim | 110 ---------------------------- lib/pure/random.nim | 23 ++++++ lib/pure/unittest.nim | 2 +- tests/js/tclosures.nim | 2 +- tests/parallel/twrong_refcounts.nim | 2 +- tests/stdlib/tmath.nim | 2 +- tests/stdlib/tunittest.nim | 2 +- tests/threads/ttryrecv.nim | 2 +- web/news.txt | 13 +++- 12 files changed, 43 insertions(+), 122 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 0e3824a81..0817b38a3 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -657,7 +657,7 @@ template newSeqWith*(len: int, init: expr): expr = ## seq2D[1][0] = true ## seq2D[0][1] = true ## - ## import math + ## import random ## var seqRand = newSeqWith(20, random(10)) ## echo seqRand var result {.gensym.} = newSeq[type(init)](len) diff --git a/lib/pure/concurrency/cpuload.nim b/lib/pure/concurrency/cpuload.nim index 22598b5c9..b0fd002ed 100644 --- a/lib/pure/concurrency/cpuload.nim +++ b/lib/pure/concurrency/cpuload.nim @@ -79,6 +79,8 @@ proc advice*(s: var ThreadPoolState): ThreadPoolAdvice = inc s.calls when not defined(testing) and isMainModule: + import random + proc busyLoop() = while true: discard random(80) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 040ce10da..d59b8ecfe 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -79,7 +79,8 @@ ## constructor should be used for this purpose. However, ## currently only basic authentication is supported. -import net, strutils, uri, parseutils, strtabs, base64, os, mimetypes, math +import net, strutils, uri, parseutils, strtabs, base64, os, mimetypes, + math, random import asyncnet, asyncdispatch import nativesockets diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 2feaef097..ce418d72c 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -39,8 +39,6 @@ proc fac*(n: int): int {.noSideEffect.} = when defined(Posix) and not defined(haiku): {.passl: "-lm".} -when not defined(js) and not defined(nimscript): - import times const PI* = 3.1415926535897932384626433 ## the circle constant PI (Ludolph's number) @@ -119,30 +117,6 @@ proc sum*[T](x: openArray[T]): T {.noSideEffect.} = ## If `x` is empty, 0 is returned. for i in items(x): result = result + i -proc random*(max: int): int {.benign.} - ## Returns a random number in the range 0..max-1. The sequence of - ## random number is always the same, unless `randomize` is called - ## which initializes the random number generator with a "random" - ## number, i.e. a tickcount. - -proc random*(max: float): float {.benign.} - ## Returns a random number in the range 0..".} @@ -239,57 +213,6 @@ when not defined(JS): proc tgamma*(x: float64): float64 {.importc: "tgamma", header: "".} ## The gamma function - # C procs: - when defined(vcc) and false: - # The "secure" random, available from Windows XP - # https://msdn.microsoft.com/en-us/library/sxtz2fa8.aspx - # Present in some variants of MinGW but not enough to justify - # `when defined(windows)` yet - proc rand_s(val: var cuint) {.importc: "rand_s", header: "".} - # To behave like the normal version - proc rand(): cuint = rand_s(result) - else: - proc srand(seed: cint) {.importc: "srand", header: "".} - proc rand(): cint {.importc: "rand", header: "".} - - when not defined(windows): - proc srand48(seed: clong) {.importc: "srand48", header: "".} - proc drand48(): float {.importc: "drand48", header: "".} - proc random(max: float): float = - result = drand48() * max - else: - when defined(vcc): # Windows with Visual C - proc random(max: float): float = - # we are hardcoding this because - # importc-ing macros is extremely problematic - # and because the value is publicly documented - # on MSDN and very unlikely to change - # See https://msdn.microsoft.com/en-us/library/296az74e.aspx - const rand_max = 4294967295 # UINT_MAX - result = (float(rand()) / float(rand_max)) * max - proc randomize() = discard - proc randomize(seed: int) = discard - else: # Windows with another compiler - proc random(max: float): float = - # we are hardcoding this because - # importc-ing macros is extremely problematic - # and because the value is publicly documented - # on MSDN and very unlikely to change - const rand_max = 32767 - result = (float(rand()) / float(rand_max)) * max - - when not defined(vcc): # the above code for vcc uses `discard` instead - # this is either not Windows or is Windows without vcc - when not defined(nimscript): - proc randomize() = - randomize(cast[int](epochTime())) - proc randomize(seed: int) = - srand(cint(seed)) # rand_s doesn't use srand - when declared(srand48): srand48(seed) - - proc random(max: int): int = - result = int(rand()) mod max - proc trunc*(x: float32): float32 {.importc: "truncf", header: "".} proc trunc*(x: float64): float64 {.importc: "trunc", header: "".} ## Truncates `x` to the decimal point @@ -319,17 +242,10 @@ when not defined(JS): ## echo fmod(-2.5, 0.3) ## -0.1 else: - proc mathrandom(): float {.importc: "Math.random", nodecl.} proc floor*(x: float32): float32 {.importc: "Math.floor", nodecl.} proc floor*(x: float64): float64 {.importc: "Math.floor", nodecl.} proc ceil*(x: float32): float32 {.importc: "Math.ceil", nodecl.} proc ceil*(x: float64): float64 {.importc: "Math.ceil", nodecl.} - proc random(max: int): int = - result = int(floor(mathrandom() * float(max))) - proc random(max: float): float = - result = float(mathrandom() * float(max)) - proc randomize() = discard - proc randomize(seed: int) = discard proc sqrt*(x: float32): float32 {.importc: "Math.sqrt", nodecl.} proc sqrt*(x: float64): float64 {.importc: "Math.sqrt", nodecl.} @@ -398,14 +314,6 @@ proc `mod`*[T: float32|float64](x, y: T): T = ## echo (4.0 mod -3.1) # -2.2 result = if y == 0.0: x else: x - y * (x/y).floor -proc random*[T](x: Slice[T]): T = - ## For a slice `a .. b` returns a value in the range `a .. b-1`. - result = random(x.b - x.a) + x.a - -proc random*[T](a: openArray[T]): T = - ## returns a random element from the openarray `a`. - result = a[random(a.low..a.len)] - {.pop.} {.pop.} @@ -440,24 +348,6 @@ proc lcm*[T](x, y: T): T = x div gcd(x, y) * y when isMainModule and not defined(JS): - proc gettime(dummy: ptr cint): cint {.importc: "time", header: "".} - - # Verifies random seed initialization. - let seed = gettime(nil) - randomize(seed) - const SIZE = 10 - var buf : array[0..SIZE, int] - # Fill the buffer with random values - for i in 0..SIZE-1: - buf[i] = random(high(int)) - # Check that the second random calls are the same for each position. - randomize(seed) - for i in 0..SIZE-1: - assert buf[i] == random(high(int)), "non deterministic random seeding" - - when not defined(testing): - echo "random values equal after reseeding" - # Check for no side effect annotation proc mySqrt(num: float): float {.noSideEffect.} = return sqrt(num) diff --git a/lib/pure/random.nim b/lib/pure/random.nim index 5a4d45c38..c79f2f77f 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -69,6 +69,14 @@ proc random*(max: float): float {.benign.} = let u = (0x3FFu64 shl 52u64) or (x shr 12u64) result = (cast[float](u) - 1.0) * max +proc random*[T](x: Slice[T]): T = + ## For a slice `a .. b` returns a value in the range `a .. b-1`. + result = random(x.b - x.a) + x.a + +proc random*[T](a: openArray[T]): T = + ## returns a random element from the openarray `a`. + result = a[random(a.low..a.len)] + proc randomize*(seed: int) {.benign.} = ## Initializes the random number generator with a specific seed. state.a0 = uint64(seed shr 16) @@ -84,3 +92,18 @@ when not defined(nimscript): randomize(int times.getTime()) {.pop.} + +when isMainModule: + proc main = + var occur: array[1000, int] + + var x = 8234 + for i in 0..100_000: + x = random(len(occur)) # myrand(x) + inc occur[x] + for i, oc in occur: + if oc < 69: + doAssert false, "too few occurances of " & $i + elif oc > 130: + doAssert false, "too many occurances of " & $i + main() diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index aca9d51e2..b83ec44ca 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -310,7 +310,7 @@ macro expect*(exceptions: varargs[expr], body: stmt): stmt {.immediate.} = ## ## .. code-block:: nim ## - ## import math + ## import math, random ## proc defectiveRobot() = ## randomize() ## case random(1..4) diff --git a/tests/js/tclosures.nim b/tests/js/tclosures.nim index c0d93814c..0ec4f4743 100644 --- a/tests/js/tclosures.nim +++ b/tests/js/tclosures.nim @@ -2,7 +2,7 @@ discard """ action: run """ -import math, strutils +import math, random, strutils const consolePrefix = "jsCallbacks" asm """ diff --git a/tests/parallel/twrong_refcounts.nim b/tests/parallel/twrong_refcounts.nim index db32a96d8..57e0588a0 100644 --- a/tests/parallel/twrong_refcounts.nim +++ b/tests/parallel/twrong_refcounts.nim @@ -2,7 +2,7 @@ discard """ output: "Success" """ -import math, threadPool +import math, random, threadPool # --- diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim index 1ac9c8092..538582ba8 100644 --- a/tests/stdlib/tmath.nim +++ b/tests/stdlib/tmath.nim @@ -1,4 +1,4 @@ -import math +import math, random import unittest import sets diff --git a/tests/stdlib/tunittest.nim b/tests/stdlib/tunittest.nim index 4b210c23b..73113ac68 100644 --- a/tests/stdlib/tunittest.nim +++ b/tests/stdlib/tunittest.nim @@ -26,7 +26,7 @@ test "unittest multiple requires": require(true) -import math +import math, random from strutils import parseInt proc defectiveRobot() = randomize() diff --git a/tests/threads/ttryrecv.nim b/tests/threads/ttryrecv.nim index be79fadae..4a98e6c27 100644 --- a/tests/threads/ttryrecv.nim +++ b/tests/threads/ttryrecv.nim @@ -4,7 +4,7 @@ discard """ # bug #1816 -from math import random +from random import random from os import sleep type PComm = ptr Channel[int] diff --git a/web/news.txt b/web/news.txt index 87896df3f..837f30f40 100644 --- a/web/news.txt +++ b/web/news.txt @@ -2,7 +2,7 @@ News ==== -2016-XX-XX Version 0.13.1 released +2016-XX-XX Version 0.14.0 released ================================== Changes affecting backwards compatibility @@ -39,6 +39,9 @@ Changes affecting backwards compatibility you need that. - The ``json.%`` operator is now overloaded for ``object``, ``ref object`` and ``openarray[T]``. +- The procs related to ``random`` number generation in ``math.nim`` have + been moved to its own ``random`` module and been reimplemented in pure + Nim. Library Additions @@ -64,11 +67,13 @@ Language Additions - Nim now supports a ``.this`` pragma for more notational convenience. - Nim now supports a different ``using`` statement for more convenience. -- Nim now supports ``partial`` object declarations to mitigate the problems - that arise when types are mutually dependent and yet should be kept in - different modules. - ``include`` statements are not restricted to top level statements anymore. +.. + - Nim now supports ``partial`` object declarations to mitigate the problems + that arise when types are mutually dependent and yet should be kept in + different modules. + 2016-01-27 Nim in Action is now available! ========================================== From 5edbc20e13e2c35c35d630e9d3b16f85c2d5df3c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 May 2016 16:24:46 +0200 Subject: [PATCH 06/16] fixes #4238 --- lib/pure/future.nim | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/pure/future.nim b/lib/pure/future.nim index 3793edc8b..4e2c1d893 100644 --- a/lib/pure/future.nim +++ b/lib/pure/future.nim @@ -29,21 +29,17 @@ proc createProcType(p, b: NimNode): NimNode {.compileTime.} = of nnkExprColonExpr: identDefs.add ident[0] identDefs.add ident[1] - of nnkIdent: + else: identDefs.add newIdentNode("i" & $i) identDefs.add(ident) - else: - error("Incorrect type list in proc type declaration.") identDefs.add newEmptyNode() formalParams.add identDefs - of nnkIdent: + else: var identDefs = newNimNode(nnkIdentDefs) identDefs.add newIdentNode("i0") identDefs.add(p) identDefs.add newEmptyNode() formalParams.add identDefs - else: - error("Incorrect type list in proc type declaration.") result.add formalParams result.add newEmptyNode() From b3a3f01d197eaa9d7b0b3000397ad4eed9507df8 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 May 2016 16:28:20 +0200 Subject: [PATCH 07/16] fixes #4221 --- lib/pure/asynchttpserver.nim | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 865b14c75..88c3399b0 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -219,20 +219,20 @@ proc processClient(client: AsyncSocket, address: string, else: await client.sendStatus("417 Expectation Failed") - # Read the body - # - Check for Content-length header - if request.headers.hasKey("Content-Length"): - var contentLength = 0 - if parseInt(request.headers.getOrDefault("Content-Length"), - contentLength) == 0: - await request.respond(Http400, "Bad Request. Invalid Content-Length.") - continue - else: - request.body = await client.recv(contentLength) - assert request.body.len == contentLength - else: - await request.respond(Http400, "Bad Request. No Content-Length.") + # Read the body + # - Check for Content-length header + if request.headers.hasKey("Content-Length"): + var contentLength = 0 + if parseInt(request.headers.getOrDefault("Content-Length"), + contentLength) == 0: + await request.respond(Http400, "Bad Request. Invalid Content-Length.") continue + else: + request.body = await client.recv(contentLength) + assert request.body.len == contentLength + else: + await request.respond(Http400, "Bad Request. No Content-Length.") + continue case request.reqMethod of "get", "post", "head", "put", "delete", "trace", "options", From 3cedf3e887fc4ac40e94ee3ae355c5de7e70d884 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 May 2016 17:40:06 +0200 Subject: [PATCH 08/16] make test green --- lib/pure/random.nim | 58 +++++++++++++++++++++------------ tests/manyloc/nake/nakefile.nim | 4 +-- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/lib/pure/random.nim b/lib/pure/random.nim index c79f2f77f..b5d046f94 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -12,21 +12,30 @@ ## | http://xoroshiro.di.unimi.it/xoroshiro128plus.c include "system/inclrtl" -{.push debugger:off .} # the user does not want to trace a part - # of the standard library! +{.push debugger:off.} # XXX Expose RandomGenState +when defined(JS): + type ui = uint32 +else: + type ui = uint64 + type RandomGenState = object - a0, a1: uint64 + a0, a1: ui -# racy for multi-threading but good enough for now: -var state = RandomGenState( - a0: 0x69B4C98CB8530805u64, - a1: 0xFED1DD3004688D67CAu64) # global for backwards compatibility +when defined(JS): + var state = RandomGenState( + a0: 0x69B4C98Cu32, + a1: 0xFED1DD30u32) # global for backwards compatibility +else: + # racy for multi-threading but good enough for now: + var state = RandomGenState( + a0: 0x69B4C98CB8530805u64, + a1: 0xFED1DD3004688D67CAu64) # global for backwards compatibility -proc rotl(x: uint64, k: uint64): uint64 = - result = (x shl k) or (x shr (64u64 - k)) +proc rotl(x, k: ui): ui = + result = (x shl k) or (x shr (ui(64) - k)) proc next(s: var RandomGenState): uint64 = let s0 = s.a0 @@ -40,13 +49,16 @@ proc skipRandomNumbers(s: var RandomGenState) = ## This is the jump function for the generator. It is equivalent ## to 2^64 calls to next(); it can be used to generate 2^64 ## non-overlapping subsequences for parallel computations. - const helper = [0xbeac0467eba5facbu64, 0xd86b048b86aa9922u64] + when defined(JS): + const helper = [0xbeac0467u32, 0xd86b048bu32] + else: + const helper = [0xbeac0467eba5facbu64, 0xd86b048b86aa9922u64] var - s0 = 0u64 - s1 = 0u64 + s0 = ui 0 + s1 = ui 0 for i in 0..high(helper): for b in 0..< 64: - if (helper[i] and (1u64 shl uint64(b))) != 0: + if (helper[i] and (ui(1) shl ui(b))) != 0: s0 = s0 xor s.a0 s1 = s1 xor s.a1 discard next(s) @@ -66,8 +78,11 @@ proc random*(max: float): float {.benign.} = ## which initializes the random number generator with a "random" ## number, i.e. a tickcount. let x = next(state) - let u = (0x3FFu64 shl 52u64) or (x shr 12u64) - result = (cast[float](u) - 1.0) * max + when defined(JS): + result = (float(x) / float(high(uint32))) * max + else: + let u = (0x3FFu64 shl 52u64) or (x shr 12u64) + result = (cast[float](u) - 1.0) * max proc random*[T](x: Slice[T]): T = ## For a slice `a .. b` returns a value in the range `a .. b-1`. @@ -79,17 +94,20 @@ proc random*[T](a: openArray[T]): T = proc randomize*(seed: int) {.benign.} = ## Initializes the random number generator with a specific seed. - state.a0 = uint64(seed shr 16) - state.a1 = uint64(seed and 0xffff) + state.a0 = ui(seed shr 16) + state.a1 = ui(seed and 0xffff) when not defined(nimscript): import times proc randomize*() {.benign.} = ## Initializes the random number generator with a "random" - ## number, i.e. a tickcount. Note: Does nothing for the JavaScript target, - ## as JavaScript does not support this. Nor does it work for NimScript. - randomize(int times.getTime()) + ## number, i.e. a tickcount. Note: Does not work for NimScript. + when defined(JS): + proc getMil(t: Time): int {.importcpp: "getTime", nodecl.} + randomize(getMil times.getTime()) + else: + randomize(int times.getTime()) {.pop.} diff --git a/tests/manyloc/nake/nakefile.nim b/tests/manyloc/nake/nakefile.nim index e91b86986..2055d7834 100644 --- a/tests/manyloc/nake/nakefile.nim +++ b/tests/manyloc/nake/nakefile.nim @@ -1,5 +1,5 @@ import nake -import httpclient, zip/zipfiles, times, math, sequtils +import httpclient, zip/zipfiles, times, random, sequtils nakeImports randomize() @@ -145,7 +145,7 @@ task "download", "download game assets": echo "Extracted the libs dir. Copy the ones you need to this dir." task "zip-lib", "zip up the libs dir": - var z: TZipArchive + var z: ZipArchive if not z.open("libs-" & getDateStr() & ".zip", fmReadWrite): quit "Could not open zip" for file in walkDirRec("libs", {pcFile, pcDir}): From ca8214a2a25a6ae05a11e2f68c4243e5c2932d7b Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 May 2016 20:26:24 +0200 Subject: [PATCH 09/16] fixes #2640 --- lib/packages/docutils/rst.nim | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index e1d5f902e..ebe6fa19b 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -323,6 +323,11 @@ proc newSharedState(options: RstParseOptions, result.msgHandler = if not isNil(msgHandler): msgHandler else: defaultMsgHandler result.findFile = if not isNil(findFile): findFile else: defaultFindFile +proc findRelativeFile(p: RstParser; filename: string): string = + result = p.filename.splitFile.dir / filename + if not existsFile(result): + result = p.s.findFile(filename) + proc rstMessage(p: RstParser, msgKind: MsgKind, arg: string) = p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line, p.col + p.tok[p.idx].col, msgKind, arg) @@ -1500,7 +1505,7 @@ proc dirInclude(p: var RstParser): PRstNode = result = nil var n = parseDirective(p, {hasArg, argIsFile, hasOptions}, nil) var filename = strip(addNodes(n.sons[0])) - var path = p.s.findFile(filename) + var path = p.findRelativeFile(filename) if path == "": rstMessage(p, meCannotOpenFile, filename) else: @@ -1511,7 +1516,7 @@ proc dirInclude(p: var RstParser): PRstNode = else: var q: RstParser initParser(q, p.s) - q.filename = filename + q.filename = path q.col += getTokens(readFile(path), false, q.tok) # workaround a GCC bug; more like the interior pointer bug? #if find(q.tok[high(q.tok)].symbol, "\0\x01\x02") > 0: @@ -1538,7 +1543,7 @@ proc dirCodeBlock(p: var RstParser, nimExtension = false): PRstNode = result = parseDirective(p, {hasArg, hasOptions}, parseLiteralBlock) var filename = strip(getFieldValue(result, "file")) if filename != "": - var path = p.s.findFile(filename) + var path = p.findRelativeFile(filename) if path == "": rstMessage(p, meCannotOpenFile, filename) var n = newRstNode(rnLiteralBlock) add(n, newRstNode(rnLeaf, readFile(path))) @@ -1590,7 +1595,7 @@ proc dirRawAux(p: var RstParser, result: var PRstNode, kind: RstNodeKind, contentParser: SectionParser) = var filename = getFieldValue(result, "file") if filename.len > 0: - var path = p.s.findFile(filename) + var path = p.findRelativeFile(filename) if path.len == 0: rstMessage(p, meCannotOpenFile, filename) else: From 1a88c01f92b07f0311258ee832863a6d2b7c6991 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 May 2016 20:26:39 +0200 Subject: [PATCH 10/16] documentation build cleaned up --- doc/manual/exceptions.txt | 2 +- doc/manual/lexing.txt | 2 +- doc/manual/syntax.txt | 2 +- doc/manual/types.txt | 2 +- doc/niminst.txt | 4 ++-- lib/core/macros.nim | 2 +- lib/impure/re.nim | 2 +- lib/pure/net.nim | 23 +++++++++++++---------- lib/pure/parsecfg.nim | 26 +++++++++++++------------- lib/pure/parsexml.nim | 4 ++-- lib/pure/pegs.nim | 2 +- lib/pure/random.nim | 8 +++++--- lib/pure/subexes.nim | 2 +- 13 files changed, 43 insertions(+), 38 deletions(-) diff --git a/doc/manual/exceptions.txt b/doc/manual/exceptions.txt index e7af65386..d06c13df4 100644 --- a/doc/manual/exceptions.txt +++ b/doc/manual/exceptions.txt @@ -155,4 +155,4 @@ Exception hierarchy The exception tree is defined in the `system `_ module: -.. include:: exception_hierarchy_fragment.txt +.. include:: ../exception_hierarchy_fragment.txt diff --git a/doc/manual/lexing.txt b/doc/manual/lexing.txt index 4187a60a4..4d03023c3 100644 --- a/doc/manual/lexing.txt +++ b/doc/manual/lexing.txt @@ -116,7 +116,7 @@ operator characters instead. The following keywords are reserved and cannot be used as identifiers: .. code-block:: nim - :file: keywords.txt + :file: ../keywords.txt Some keywords are unused; they are reserved for future developments of the language. diff --git a/doc/manual/syntax.txt b/doc/manual/syntax.txt index ca3b582ca..4f7483be8 100644 --- a/doc/manual/syntax.txt +++ b/doc/manual/syntax.txt @@ -119,6 +119,6 @@ Grammar The grammar's start symbol is ``module``. -.. include:: grammar.txt +.. include:: ../grammar.txt :literal: diff --git a/doc/manual/types.txt b/doc/manual/types.txt index a1596bcea..4c015ffb7 100644 --- a/doc/manual/types.txt +++ b/doc/manual/types.txt @@ -694,7 +694,7 @@ branch switch ``system.reset`` has to be used. Set type -------- -.. include:: sets_fragment.txt +.. include:: ../sets_fragment.txt Reference and pointer types --------------------------- diff --git a/doc/niminst.txt b/doc/niminst.txt index 7bd0f719e..bf5cb0f50 100644 --- a/doc/niminst.txt +++ b/doc/niminst.txt @@ -27,7 +27,7 @@ Configuration file niminst uses the Nim `parsecfg `_ module to parse the configuration file. Here's an example of how the syntax looks like: -.. include:: doc/mytest.cfg +.. include:: mytest.cfg :literal: The value of a key-value pair can reference user-defined variables via @@ -190,6 +190,6 @@ Real world example The installers for the Nim compiler itself are generated by niminst. Have a look at its configuration file: -.. include:: compiler/installer.ini +.. include:: ../compiler/installer.ini :literal: diff --git a/lib/core/macros.nim b/lib/core/macros.nim index bfda6b938..16a954611 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -12,7 +12,7 @@ include "system/inclrtl" ## This module contains the interface to the compiler's abstract syntax ## tree (`AST`:idx:). Macros operate on this tree. -## .. include:: ../doc/astspec.txt +## .. include:: ../../doc/astspec.txt type NimNodeKind* = enum diff --git a/lib/impure/re.nim b/lib/impure/re.nim index 60bb6c77f..d49c6d1c1 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -22,7 +22,7 @@ ## though. ## PRCE's licence follows: ## -## .. include:: ../doc/regexprs.txt +## .. include:: ../../doc/regexprs.txt ## import diff --git a/lib/pure/net.nim b/lib/pure/net.nim index c734fe893..cb8cea720 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -606,28 +606,31 @@ proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) { var valuei = cint(if value: 1 else: 0) setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei) -when defined(posix) or defined(nimdoc): +when defined(posix) and not defined(nimdoc): proc makeUnixAddr(path: string): Sockaddr_un = result.sun_family = AF_UNIX.toInt if path.len >= Sockaddr_un_path_length: raise newException(ValueError, "socket path too long") copyMem(addr result.sun_path, path.cstring, path.len + 1) +when defined(posix): proc connectUnix*(socket: Socket, path: string) = ## Connects to Unix socket on `path`. ## This only works on Unix-style systems: Mac OS X, BSD and Linux - var socketAddr = makeUnixAddr(path) - if socket.fd.connect(cast[ptr SockAddr](addr socketAddr), - sizeof(socketAddr).Socklen) != 0'i32: - raiseOSError(osLastError()) + when not defined(nimdoc): + var socketAddr = makeUnixAddr(path) + if socket.fd.connect(cast[ptr SockAddr](addr socketAddr), + sizeof(socketAddr).Socklen) != 0'i32: + raiseOSError(osLastError()) proc bindUnix*(socket: Socket, path: string) = ## Binds Unix socket to `path`. ## This only works on Unix-style systems: Mac OS X, BSD and Linux - var socketAddr = makeUnixAddr(path) - if socket.fd.bindAddr(cast[ptr SockAddr](addr socketAddr), - sizeof(socketAddr).Socklen) != 0'i32: - raiseOSError(osLastError()) + when not defined(nimdoc): + var socketAddr = makeUnixAddr(path) + if socket.fd.bindAddr(cast[ptr SockAddr](addr socketAddr), + sizeof(socketAddr).Socklen) != 0'i32: + raiseOSError(osLastError()) when defined(ssl): proc handshake*(socket: Socket): bool @@ -1399,7 +1402,7 @@ proc connect*(socket: Socket, address: string, port = Port(0), if selectWrite(s, timeout) != 1: raise newException(TimeoutError, "Call to 'connect' timed out.") else: - when defineSsl: + when defineSsl and not defined(nimdoc): if socket.isSSL: socket.fd.setBlocking(true) {.warning[Deprecated]: off.} diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index bf19d5540..25879d2b7 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -15,21 +15,21 @@ ## This is an example of how a configuration file may look like: ## -## .. include:: doc/mytest.cfg +## .. include:: ../../doc/mytest.cfg ## :literal: ## The file ``examples/parsecfgex.nim`` demonstrates how to use the ## configuration file parser: ## ## .. code-block:: nim -## :file: examples/parsecfgex.nim -## +## :file: ../../examples/parsecfgex.nim +## ## Examples ## -------- ## ## This is an example of a configuration file. -## -## .. include:: config.ini -## +## +## :: +## ## charset = "utf-8" ## [Package] ## name = "hello" @@ -38,11 +38,11 @@ ## name = "lihf8515" ## qq = "10214028" ## email = "lihaifeng@wxm.com" -## +## ## Creating a configuration file. ## ============================== ## .. code-block:: nim -## +## ## import parsecfg ## var dict=newConfig() ## dict.setSectionKey("","charset","utf-8") @@ -52,7 +52,7 @@ ## dict.setSectionKey("Author","qq","10214028") ## dict.setSectionKey("Author","email","lihaifeng@wxm.com") ## dict.writeConfig("config.ini") -## +## ## Reading a configuration file. ## ============================= ## .. code-block:: nim @@ -66,11 +66,11 @@ ## var qq = dict.getSectionValue("Author","qq") ## var email = dict.getSectionValue("Author","email") ## echo pname & "\n" & name & "\n" & qq & "\n" & email -## +## ## Modifying a configuration file. ## =============================== ## .. code-block:: nim -## +## ## import parsecfg ## var dict = loadConfig("config.ini") ## dict.setSectionKey("Author","name","lhf") @@ -79,7 +79,7 @@ ## Deleting a section key in a configuration file. ## =============================================== ## .. code-block:: nim -## +## ## import parsecfg ## var dict = loadConfig("config.ini") ## dict.delSectionKey("Author","email") @@ -434,7 +434,7 @@ proc loadConfig*(filename: string): Config = ## Load the specified configuration file into a new Config instance. var dict = newOrderedTable[string, OrderedTableRef[string, string]]() var curSection = "" ## Current section, - ## the default value of the current section is "", + ## the default value of the current section is "", ## which means that the current section is a common var p: CfgParser var fileStream = newFileStream(filename, fmRead) diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim index f8b2c3d8d..06daa3782 100644 --- a/lib/pure/parsexml.nim +++ b/lib/pure/parsexml.nim @@ -34,7 +34,7 @@ ## document. ## ## .. code-block:: nim -## :file: examples/htmltitle.nim +## :file: ../../examples/htmltitle.nim ## ## ## Example 2: Retrieve all HTML links @@ -45,7 +45,7 @@ ## an HTML document contains. ## ## .. code-block:: nim -## :file: examples/htmlrefs.nim +## :file: ../../examples/htmlrefs.nim ## import diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index eea20a62c..7e1f50266 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -12,7 +12,7 @@ ## Matching performance is hopefully competitive with optimized regular ## expression engines. ## -## .. include:: ../doc/pegdocs.txt +## .. include:: ../../doc/pegdocs.txt ## include "system/inclrtl" diff --git a/lib/pure/random.nim b/lib/pure/random.nim index b5d046f94..c73f403eb 100644 --- a/lib/pure/random.nim +++ b/lib/pure/random.nim @@ -7,9 +7,11 @@ # distribution, for details about the copyright. # -## | Nim's standard random number generator. Based on -## | http://xoroshiro.di.unimi.it/ -## | http://xoroshiro.di.unimi.it/xoroshiro128plus.c +##[Nim's standard random number generator. Based on + +| `http://xoroshiro.di.unimi.it/`_ +| `http://xoroshiro.di.unimi.it/xoroshiro128plus.c`_ +]## include "system/inclrtl" {.push debugger:off.} diff --git a/lib/pure/subexes.nim b/lib/pure/subexes.nim index 22f29b77c..351b3c086 100644 --- a/lib/pure/subexes.nim +++ b/lib/pure/subexes.nim @@ -9,7 +9,7 @@ ## Nim support for `substitution expressions`:idx: (`subex`:idx:). ## -## .. include:: ../doc/subexes.txt +## .. include:: ../../doc/subexes.txt ## {.push debugger:off .} # the user does not want to trace a part From 4ebd7d0744017a02e402f97df1640cf978cdbc0a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 May 2016 20:59:23 +0200 Subject: [PATCH 11/16] fixes #1262 --- compiler/pragmas.nim | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index dc09d8fc4..dc618d9aa 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -393,21 +393,23 @@ type TLinkFeature = enum linkNormal, linkSys -proc processCompile(c: PContext, n: PNode) = +proc relativeFile(c: PContext; n: PNode; ext=""): string = var s = expectStrLit(c, n) - var found = findFile(s) - if found == "": found = s - var trunc = changeFileExt(found, "") - if not isAbsolute(found): - found = parentDir(n.info.toFullPath) / found + if ext.len > 0 and splitFile(s).ext == "": + s = addFileExt(s, ext) + result = parentDir(n.info.toFullPath) / s + if not fileExists(result): + if isAbsolute(s): result = s + else: result = findFile(s) + +proc processCompile(c: PContext, n: PNode) = + let found = relativeFile(c, n) + let trunc = found.changeFileExt("") extccomp.addExternalFileToCompile(found) extccomp.addFileToLink(completeCFilePath(trunc, false)) proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) = - var f = expectStrLit(c, n) - if splitFile(f).ext == "": f = addFileExt(f, CC[cCompiler].objExt) - var found = findFile(f) - if found == "": found = f # use the default + let found = relativeFile(c, n, CC[cCompiler].objExt) case feature of linkNormal: extccomp.addFileToLink(found) of linkSys: From 4886cde781b84f036aebf7021931725665d115b1 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 May 2016 21:05:26 +0200 Subject: [PATCH 12/16] fixes #765 --- compiler/vmdeps.nim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index e7ead17b6..678a765f4 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -7,7 +7,7 @@ # distribution, for details about the copyright. # -import ast, types, msgs, osproc, streams, options, idents, securehash +import ast, types, msgs, os, osproc, streams, options, idents, securehash proc readOutput(p: Process): string = result = "" @@ -51,7 +51,9 @@ proc opGorge*(cmd, input, cache: string): string = proc opSlurp*(file: string, info: TLineInfo, module: PSym): string = try: - let filename = file.findFile + var filename = parentDir(info.toFullPath) / file + if not fileExists(filename): + filename = file.findFile result = readFile(filename) # we produce a fake include statement for every slurped filename, so that # the module dependencies are accurate: From f2d6edd8616b87d8785b73c7d5bc75321fd4de35 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 May 2016 21:18:59 +0200 Subject: [PATCH 13/16] fixes #786 --- compiler/commands.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/commands.nim b/compiler/commands.nim index dc04993a7..e2274f2ad 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -269,6 +269,8 @@ proc processPath(path: string, info: TLineInfo, "config", info.toFullPath().splitFile().dir, "projectname", options.gProjectName, "projectpath", options.gProjectPath]) + if '~' in result: + result = result.replace("~", os.getHomeDir()) except ValueError: localError(info, "invalid path: " & p) result = p From 1e5926458c2d18dec3389d00f41680518fb939c0 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 30 May 2016 21:41:52 +0200 Subject: [PATCH 14/16] fixes #3290 --- koch.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/koch.nim b/koch.nim index f7c0ae204..e8b08c5d2 100644 --- a/koch.nim +++ b/koch.nim @@ -336,10 +336,11 @@ template `|`(a, b): expr = (if a.len > 0: a else: b) proc tests(args: string) = # we compile the tester with taintMode:on to have a basic # taint mode test :-) - exec "nim cc --taintMode:on tests/testament/tester" + let nimexe = findNim() + exec nimexe & " cc --taintMode:on tests/testament/tester" # Since tests take a long time (on my machine), and we want to defy Murhpys # law - lets make sure the compiler really is freshly compiled! - exec "nim c --lib:lib -d:release --opt:speed compiler/nim.nim" + exec nimexe & " c --lib:lib -d:release --opt:speed compiler/nim.nim" let tester = quoteShell(getCurrentDir() / "tests/testament/tester".exe) let success = tryExec tester & " " & (args|"all") if not existsEnv("TRAVIS") and not existsEnv("APPVEYOR"): From 893be3a5a40cbbceb211efe47361632ccdbed227 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 31 May 2016 03:04:36 +0200 Subject: [PATCH 15/16] changed the compiler's path handling; fixes #546 --- compiler/commands.nim | 10 +--------- compiler/importer.nim | 6 +++++- compiler/main.nim | 2 +- compiler/nim.cfg | 2 +- compiler/options.nim | 15 +++++++++++++++ lib/system.nim | 2 +- tests/manyloc/keineschweine/lib/vehicles.nim | 2 +- tests/manyloc/named_argument_bug/main.nim.cfg | 1 + .../named_argument_bug/tri_engine/math/circle.nim | 4 ++-- .../named_argument_bug/tri_engine/math/vec.nim | 2 +- web/news.txt | 3 +++ 11 files changed, 32 insertions(+), 17 deletions(-) diff --git a/compiler/commands.nim b/compiler/commands.nim index e2274f2ad..e9806e6d8 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -262,15 +262,7 @@ proc processPath(path: string, info: TLineInfo, else: options.gProjectPath / path try: - result = unixToNativePath(p % ["nimrod", getPrefixDir(), - "nim", getPrefixDir(), - "lib", libpath, - "home", removeTrailingDirSep(os.getHomeDir()), - "config", info.toFullPath().splitFile().dir, - "projectname", options.gProjectName, - "projectpath", options.gProjectPath]) - if '~' in result: - result = result.replace("~", os.getHomeDir()) + result = pathSubs(p, info.toFullPath().splitFile().dir) except ValueError: localError(info, "invalid path: " & p) result = p diff --git a/compiler/importer.nim b/compiler/importer.nim index 86993358b..5ffe12728 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -22,7 +22,11 @@ proc getModuleName*(n: PNode): string = # The proc won't perform any checks that the path is actually valid case n.kind of nkStrLit, nkRStrLit, nkTripleStrLit: - result = unixToNativePath(n.strVal) + try: + result = pathSubs(n.strVal, n.info.toFullPath().splitFile().dir) + except ValueError: + localError(n.info, "invalid path: " & n.strVal) + result = n.strVal of nkIdent: result = n.ident.s of nkSym: diff --git a/compiler/main.nim b/compiler/main.nim index 4aefbb85a..b1b9006bd 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -242,7 +242,7 @@ proc mainCommand* = clearPasses() gLastCmdTime = epochTime() appendStr(searchPaths, options.libpath) - if gProjectFull.len != 0: + when false: # gProjectFull.len != 0: # current path is always looked first for modules prependStr(searchPaths, gProjectPath) setId(100) diff --git a/compiler/nim.cfg b/compiler/nim.cfg index 4f9962ea8..0ff128ba3 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -7,7 +7,7 @@ path:"$projectPath/.." path:"$lib/packages/docutils" define:booting -import:testability +#import:"$projectpath/testability" @if windows: cincludes: "$lib/wrappers/libffi/common" diff --git a/compiler/options.nim b/compiler/options.nim index 2716a98d3..3ef6c6c46 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -242,6 +242,21 @@ proc getNimcacheDir*: string = result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir / genSubDir + +proc pathSubs*(p, config: string): string = + let home = removeTrailingDirSep(os.getHomeDir()) + result = unixToNativePath(p % [ + "nim", getPrefixDir(), + "lib", libpath, + "home", home, + "config", config, + "projectname", options.gProjectName, + "projectpath", options.gProjectPath, + "projectdir", options.gProjectPath, + "nimcache", getNimcacheDir()]) + if '~' in result: + result = result.replace("~", home) + template newPackageCache(): expr = newStringTable(when FileSystemCaseSensitive: modeCaseInsensitive diff --git a/lib/system.nim b/lib/system.nim index c224535f0..8180f27cd 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2514,7 +2514,7 @@ template newException*(exceptn: typedesc, message: string): expr = e when hostOS == "standalone": - include panicoverride + include "$projectpath/panicoverride" when not declared(sysFatal): when hostOS == "standalone": diff --git a/tests/manyloc/keineschweine/lib/vehicles.nim b/tests/manyloc/keineschweine/lib/vehicles.nim index 94ebf9f57..ddfb43b38 100644 --- a/tests/manyloc/keineschweine/lib/vehicles.nim +++ b/tests/manyloc/keineschweine/lib/vehicles.nim @@ -1,6 +1,6 @@ import sfml, chipmunk, - sg_assets, sfml_stuff, keineschweine + sg_assets, sfml_stuff, "../keineschweine" proc accel*(obj: PVehicle, dt: float) = diff --git a/tests/manyloc/named_argument_bug/main.nim.cfg b/tests/manyloc/named_argument_bug/main.nim.cfg index 27cf8e688..7df7a0e97 100644 --- a/tests/manyloc/named_argument_bug/main.nim.cfg +++ b/tests/manyloc/named_argument_bug/main.nim.cfg @@ -1,2 +1,3 @@ # this file only exists to mark 'main.nim' as the main file +--path:"$projectpath" diff --git a/tests/manyloc/named_argument_bug/tri_engine/math/circle.nim b/tests/manyloc/named_argument_bug/tri_engine/math/circle.nim index 7e7517998..b95cfa379 100644 --- a/tests/manyloc/named_argument_bug/tri_engine/math/circle.nim +++ b/tests/manyloc/named_argument_bug/tri_engine/math/circle.nim @@ -1,6 +1,6 @@ import - tri_engine/config, - tri_engine/math/vec + ../config, + vec type TCircle* = tuple[p: TV2[TR], r: TR] diff --git a/tests/manyloc/named_argument_bug/tri_engine/math/vec.nim b/tests/manyloc/named_argument_bug/tri_engine/math/vec.nim index 3b57acb8e..926958fe4 100644 --- a/tests/manyloc/named_argument_bug/tri_engine/math/vec.nim +++ b/tests/manyloc/named_argument_bug/tri_engine/math/vec.nim @@ -1,6 +1,6 @@ import macros, - tri_engine/config + "../config" type TV2*[T:SomeNumber=TR] = array[0..1, T] diff --git a/web/news.txt b/web/news.txt index 837f30f40..c100c8aee 100644 --- a/web/news.txt +++ b/web/news.txt @@ -42,6 +42,9 @@ Changes affecting backwards compatibility - The procs related to ``random`` number generation in ``math.nim`` have been moved to its own ``random`` module and been reimplemented in pure Nim. +- The path handling changed. The project directory is not added to the + search path automatically anymore. Add this line to your project's + config to get back the old behaviour: ``--path:"$projectdir"``. Library Additions From f3fdad0eda8664f71e265b7ecc41477a7490331c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 31 May 2016 09:59:17 +0200 Subject: [PATCH 16/16] hotfix: --noNimblePath wasn't working when in a config file --- compiler/commands.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/commands.nim b/compiler/commands.nim index e9806e6d8..3bc0b604a 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -316,6 +316,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = of "nonimblepath", "nobabelpath": expectNoArg(switch, arg, pass, info) options.gNoNimblePath = true + options.lazyPaths.head = nil + options.lazyPaths.tail = nil + options.lazyPaths.counter = 0 of "excludepath": expectArg(switch, arg, pass, info) let path = processPath(arg, info)