From 35690dc37f74e43149257b8ada0527d4a7949ae0 Mon Sep 17 00:00:00 2001 From: apense Date: Wed, 24 Jun 2015 16:09:18 -0400 Subject: [PATCH 001/674] Rewrote procs for float32/float64 When a proc is `importc`-ed, made explicit. Otherwise, used `[T: float32|float64]` --- lib/pure/math.nim | 214 +++++++++++++++++++++++++++------------------- 1 file changed, 128 insertions(+), 86 deletions(-) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 7a88694b5a..892aa53beb 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -8,7 +8,7 @@ # ## Constructive mathematics is naturally typed. -- Simon Thompson -## +## ## Basic math routines for Nim. ## This module is available for the `JavaScript target ## `_. @@ -34,9 +34,9 @@ const MaxFloat32Precision* = 8 ## maximum number of meaningful digits ## after the decimal point for Nim's ## ``float32`` type. - MaxFloatPrecision* = MaxFloat64Precision ## maximum number of + MaxFloatPrecision* = MaxFloat64Precision ## maximum number of ## meaningful digits - ## after the decimal point + ## after the decimal point ## for Nim's ``float`` type. type @@ -50,10 +50,10 @@ type fcInf, ## value is positive infinity fcNegInf ## value is negative infinity -proc classify*(x: float): FloatClass = +proc classify*(x: float): FloatClass = ## classifies a floating point value. Returns `x`'s class as specified by ## `FloatClass`. - + # JavaScript and most C compilers have no classify: if x == 0.0: if 1.0/x == Inf: @@ -68,15 +68,15 @@ proc classify*(x: float): FloatClass = # XXX: fcSubnormal is not detected! -proc binom*(n, k: int): int {.noSideEffect.} = +proc binom*(n, k: int): int {.noSideEffect.} = ## computes the binomial coefficient if k <= 0: return 1 if 2*k > n: return binom(n, n-k) result = n for i in countup(2, k): result = (result * (n + 1 - i)) div i - -proc fac*(n: int): int {.noSideEffect.} = + +proc fac*(n: int): int {.noSideEffect.} = ## computes the faculty/factorial function. result = 1 for i in countup(2, n): @@ -90,7 +90,7 @@ proc isPowerOfTwo*(x: int): bool {.noSideEffect.} = proc nextPowerOfTwo*(x: int): int {.noSideEffect.} = ## returns `x` rounded up to the nearest power of two. ## Zero and negative numbers get rounded up to 1. - result = x - 1 + result = x - 1 when defined(cpu64): result = result or (result shr 32) when sizeof(int) > 2: @@ -109,8 +109,8 @@ proc countBits32*(n: int32): int {.noSideEffect.} = v = (v and 0x33333333'i32) +% ((v shr 2'i32) and 0x33333333'i32) result = ((v +% (v shr 4'i32) and 0xF0F0F0F'i32) *% 0x1010101'i32) shr 24'i32 -proc sum*[T](x: openArray[T]): T {.noSideEffect.} = - ## computes the sum of the elements in `x`. +proc sum*[T](x: openArray[T]): T {.noSideEffect.} = + ## computes the sum of the elements in `x`. ## If `x` is empty, 0 is returned. for i in items(x): result = result + i @@ -124,7 +124,7 @@ proc mean*[T](x: openArray[T]): float {.noSideEffect.} = result = result / toFloat(len(x)) proc variance*[T](x: openArray[T]): float {.noSideEffect.} = - ## computes the variance of the elements in `x`. + ## computes the variance of the elements in `x`. ## If `x` is empty, NaN is returned. ## ``toFloat(x: T): float`` must be defined. result = 0.0 @@ -151,7 +151,7 @@ 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. - + proc randomize*(seed: int) {.benign.} ## initializes the random number generator with a specific seed. ## Note: Does nothing for the JavaScript target, @@ -159,60 +159,84 @@ proc randomize*(seed: int) {.benign.} {.push noSideEffect.} when not defined(JS): - proc sqrt*(x: float): float {.importc: "sqrt", header: "".} + proc sqrt*(x: float32): float32 {.importc: "sqrt", header: "".} + proc sqrt*(x: float64): float64 {.importc: "sqrt", header: "".} ## computes the square root of `x`. - proc cbrt*(x: float): float {.importc: "cbrt", header: "".} + proc cbrt*(x: float32): float32 {.importc: "cbrt", header: "".} + proc cbrt*(x: float64): float64 {.importc: "cbrt", header: "".} ## computes the cubic root of `x` - - proc ln*(x: float): float {.importc: "log", header: "".} + + proc ln*(x: float32): float32 {.importc: "log", header: "".} + proc ln*(x: float64): float64 {.importc: "log", header: "".} ## computes ln(x). - proc log10*(x: float): float {.importc: "log10", header: "".} - proc log2*(x: float): float = return ln(x) / ln(2.0) - proc exp*(x: float): float {.importc: "exp", header: "".} + proc log10*(x: float32): float32 {.importc: "log10", header: "".} + proc log10*(x: float64): float64 {.importc: "log10", header: "".} + proc log2*[T: float32|float64](x: T): T = return ln(x) / ln(2.0) + proc exp*(x: float32): float32 {.importc: "exp", header: "".} + proc exp*(x: float64): float64 {.importc: "exp", header: "".} ## computes e**x. - - proc frexp*(x: float, exponent: var int): float {. + + proc frexp*(x: float32, exponent: var int): float32 {. + importc: "frexp", header: "".} + proc frexp*(x: float64, exponent: var int): float64 {. importc: "frexp", header: "".} ## Split a number into mantissa and exponent. ## `frexp` calculates the mantissa m (a float greater than or equal to 0.5 ## and less than 1) and the integer value n such that `x` (the original ## float value) equals m * 2**n. frexp stores n in `exponent` and returns ## m. - - proc round*(x: float): int {.importc: "lrint", header: "".} - ## converts a float to an int by rounding. - - proc arccos*(x: float): float {.importc: "acos", header: "".} - proc arcsin*(x: float): float {.importc: "asin", header: "".} - proc arctan*(x: float): float {.importc: "atan", header: "".} - proc arctan2*(y, x: float): float {.importc: "atan2", header: "".} + + proc round*(x: float32): int {.importc: "lrint", header: "".} + proc round*(x: float64): int {.importc: "lrint", header: "".} + ## converts a float to an int by rounding. + + proc arccos*(x: float32): float32 {.importc: "acos", header: "".} + proc arccos*(x: float64): float64 {.importc: "acos", header: "".} + proc arcsin*(x: float32): float32 {.importc: "asin", header: "".} + proc arcsin*(x: float64): float64 {.importc: "asin", header: "".} + proc arctan*(x: float32): float32 {.importc: "atan", header: "".} + proc arctan*(x: float64): float64 {.importc: "atan", header: "".} + proc arctan2*(y, x: float32): float32 {.importc: "atan2", header: "".} + proc arctan2*(y, x: float64): float64 {.importc: "atan2", header: "".} ## Calculate the arc tangent of `y` / `x`. ## `atan2` returns the arc tangent of `y` / `x`; it produces correct ## results even when the resulting angle is near pi/2 or -pi/2 ## (`x` near 0). - - proc cos*(x: float): float {.importc: "cos", header: "".} - proc cosh*(x: float): float {.importc: "cosh", header: "".} - proc hypot*(x, y: float): float {.importc: "hypot", header: "".} + + proc cos*(x: float32): float32 {.importc: "cos", header: "".} + proc cos*(x: float64): float64 {.importc: "cos", header: "".} + proc cosh*(x: float32): float32 {.importc: "cosh", header: "".} + proc cosh*(x: float64): float64 {.importc: "cosh", header: "".} + proc hypot*(x, y: float32): float32 {.importc: "hypot", header: "".} + proc hypot*(x, y: float64): float64 {.importc: "hypot", header: "".} ## same as ``sqrt(x*x + y*y)``. - - proc sinh*(x: float): float {.importc: "sinh", header: "".} - proc sin*(x: float): float {.importc: "sin", header: "".} - proc tan*(x: float): float {.importc: "tan", header: "".} - proc tanh*(x: float): float {.importc: "tanh", header: "".} - proc pow*(x, y: float): float {.importc: "pow", header: "".} + + proc sinh*(x: float32): float32 {.importc: "sinh", header: "".} + proc sinh*(x: float64): float64 {.importc: "sinh", header: "".} + proc sin*(x: float32): float32 {.importc: "sin", header: "".} + proc sin*(x: float64): float64 {.importc: "sin", header: "".} + proc tan*(x: float32): float32 {.importc: "tan", header: "".} + proc tan*(x: float64): float64 {.importc: "tan", header: "".} + proc tanh*(x: float32): float32 {.importc: "tanh", header: "".} + proc tanh*(x: float64): float64 {.importc: "tanh", header: "".} + proc pow*(x, y: float32): float32 {.importc: "pow", header: "".} + proc pow*(x, y: float64): float64 {.importc: "pow", header: "".} ## computes x to power raised of y. - - proc erf*(x: float): float {.importc: "erf", header: "".} + + proc erf*(x: float32): float32 {.importc: "erf", header: "".} + proc erf*(x: float64): float64 {.importc: "erf", header: "".} ## The error function - proc erfc*(x: float): float {.importc: "erfc", header: "".} + proc erfc*(x: float32): float32 {.importc: "erfc", header: "".} + proc erfc*(x: float64): float64 {.importc: "erfc", header: "".} ## The complementary error function - - proc lgamma*(x: float): float {.importc: "lgamma", header: "".} + + proc lgamma*(x: float32): float32 {.importc: "lgamma", header: "".} + proc lgamma*(x: float64): float64 {.importc: "lgamma", header: "".} ## Natural log of the gamma function - proc tgamma*(x: float): float {.importc: "tgamma", header: "".} + proc tgamma*(x: float32): float32 {.importc: "tgamma", header: "".} + proc tgamma*(x: float64): float64 {.importc: "tgamma", header: "".} ## The gamma function - + # C procs: when defined(vcc): # The "secure" random, available from Windows XP @@ -225,7 +249,7 @@ when not defined(JS): 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: "".} @@ -251,7 +275,7 @@ when not defined(JS): # 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 proc randomize() = @@ -259,37 +283,47 @@ when not defined(JS): 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: float): float {.importc: "trunc", header: "".} - proc floor*(x: float): float {.importc: "floor", header: "".} - proc ceil*(x: float): float {.importc: "ceil", header: "".} + proc trunc*(x: float32): float32 {.importc: "trunc", header: "".} + proc trunc*(x: float64): float64 {.importc: "trunc", header: "".} + proc floor*(x: float32): float32 {.importc: "floor", header: "".} + proc floor*(x: float64): float64 {.importc: "floor", header: "".} + proc ceil*(x: float32): float32 {.importc: "ceil", header: "".} + proc ceil*(x: float64): float64 {.importc: "ceil", header: "".} - proc fmod*(x, y: float): float {.importc: "fmod", header: "".} + proc fmod*(x, y: float32): float32 {.importc: "fmod", header: "".} + proc fmod*(x, y: float64): float64 {.importc: "fmod", header: "".} else: proc mathrandom(): float {.importc: "Math.random", nodecl.} - proc floor*(x: float): float {.importc: "Math.floor", nodecl.} - proc ceil*(x: float): float {.importc: "Math.ceil", 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: float): float {.importc: "Math.sqrt", nodecl.} - proc ln*(x: float): float {.importc: "Math.log", nodecl.} - proc log10*(x: float): float = return ln(x) / ln(10.0) - proc log2*(x: float): float = return ln(x) / ln(2.0) - proc exp*(x: float): float {.importc: "Math.exp", nodecl.} + proc sqrt*(x: float32): float32 {.importc: "Math.sqrt", nodecl.} + proc sqrt*(x: float64): float64 {.importc: "Math.sqrt", nodecl.} + proc ln*(x: float32): float32 {.importc: "Math.log", nodecl.} + proc ln*(x: float64): float64 {.importc: "Math.log", nodecl.} + proc log10*[T: float32|float64](x: T): T = return ln(x) / ln(10.0) + proc log2*[T: float32|float64](x: T): T = return ln(x) / ln(2.0) + + proc exp*(x: float32): float32 {.importc: "Math.exp", nodecl.} + proc exp*(x: float64): float64 {.importc: "Math.exp", nodecl.} proc round*(x: float): int {.importc: "Math.round", nodecl.} - proc pow*(x, y: float): float {.importc: "Math.pow", nodecl.} - - proc frexp*(x: float, exponent: var int): float = + proc pow*(x, y: float32): float32 {.importC: "Math.pow", nodecl.} + proc pow*(x, y: float64): float64 {.importc: "Math.pow", nodecl.} + + proc frexp*[T: float32|float64](x: T, exponent: var int): T = if x == 0.0: exponent = 0 result = 0.0 @@ -300,28 +334,36 @@ else: exponent = round(ex) result = x / pow(2.0, ex) - proc arccos*(x: float): float {.importc: "Math.acos", nodecl.} - proc arcsin*(x: float): float {.importc: "Math.asin", nodecl.} - proc arctan*(x: float): float {.importc: "Math.atan", nodecl.} - proc arctan2*(y, x: float): float {.importc: "Math.atan2", nodecl.} - - proc cos*(x: float): float {.importc: "Math.cos", nodecl.} - proc cosh*(x: float): float = return (exp(x)+exp(-x))*0.5 - proc hypot*(x, y: float): float = return sqrt(x*x + y*y) - proc sinh*(x: float): float = return (exp(x)-exp(-x))*0.5 - proc sin*(x: float): float {.importc: "Math.sin", nodecl.} - proc tan*(x: float): float {.importc: "Math.tan", nodecl.} - proc tanh*(x: float): float = + proc arccos*(x: float32): float32 {.importc: "Math.acos", nodecl.} + proc arccos*(x: float64): float64 {.importc: "Math.acos", nodecl.} + proc arcsin*(x: float32): float32 {.importc: "Math.asin", nodecl.} + proc arcsin*(x: float64): float64 {.importc: "Math.asin", nodecl.} + proc arctan*(x: float32): float32 {.importc: "Math.atan", nodecl.} + proc arctan*(x: float64): float64 {.importc: "Math.atan", nodecl.} + proc arctan2*(y, x: float32): float32 {.importC: "Math.atan2", nodecl.} + proc arctan2*(y, x: float64): float64 {.importc: "Math.atan2", nodecl.} + + proc cos*(x: float32): float32 {.importc: "Math.cos", nodecl.} + proc cos*(x: float64): float64 {.importc: "Math.cos", nodecl.} + proc cosh*(x: float32): float32 = return (exp(x)+exp(-x))*0.5 + proc cosh*(x: float64): float64 = return (exp(x)+exp(-x))*0.5 + proc hypot*[T: float32|float64](x, y: T): T = return sqrt(x*x + y*y) + proc sinh*]T: float32|float64](x: T): T = return (exp(x)-exp(-x))*0.5 + proc sin*(x: float32): float32 {.importc: "Math.sin", nodecl.} + proc sin*(x: float64): float64 {.importc: "Math.sin", nodecl.} + proc tan*(x: float32): float32 {.importc: "Math.tan", nodecl.} + proc tan*(x: float64): float64 {.importc: "Math.tan", nodecl.} + proc tanh*[T: float32|float64](x: T): T = var y = exp(2.0*x) return (y-1.0)/(y+1.0) {.pop.} -proc `mod`*(x, y: float): float = +proc `mod`*[T: float32|float64](x, y: T): T = ## Computes the modulo operation for float operators. Equivalent ## to ``x - y * floor(x/y)``. Note that the remainder will always ## have the same sign as the divisor. - ## + ## ## .. code-block:: nim ## echo (4.0 mod -3.1) # -2.2 result = if y == 0.0: x else: x - y * (x/y).floor @@ -342,7 +384,7 @@ type {.deprecated: [TFloatClass: FloatClass, TRunningStat: RunningStat].} -proc push*(s: var RunningStat, x: float) = +proc push*(s: var RunningStat, x: float) = ## pushes a value `x` for processing inc(s.n) # See Knuth TAOCP vol 2, 3rd edition, page 232 @@ -362,17 +404,17 @@ proc push*(s: var RunningStat, x: float) = s.oldM = s.mean s.oldS = s.newS s.sum = s.sum + x - -proc push*(s: var RunningStat, x: int) = + +proc push*(s: var RunningStat, x: int) = ## pushes a value `x` for processing. `x` is simply converted to ``float`` ## and the other push operation is called. push(s, toFloat(x)) - -proc variance*(s: RunningStat): float = + +proc variance*(s: RunningStat): float = ## computes the current variance of `s` if s.n > 1: result = s.newS / (toFloat(s.n - 1)) -proc standardDeviation*(s: RunningStat): float = +proc standardDeviation*(s: RunningStat): float = ## computes the current standard deviation of `s` result = sqrt(variance(s)) @@ -429,7 +471,7 @@ when isMainModule and not defined(JS): # Check for no side effect annotation proc mySqrt(num: float): float {.noSideEffect.} = return sqrt(num) - + # check gamma function assert(tgamma(5.0) == 24.0) # 4! assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0 From 6165e8498ca30043ef013392d5f38d0a3e9f40ec Mon Sep 17 00:00:00 2001 From: apense Date: Wed, 24 Jun 2015 16:12:19 -0400 Subject: [PATCH 002/674] Converted tabs Not sure what was going on before --- lib/pure/math.nim | 78 +++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 892aa53beb..4fae03cc5f 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -160,20 +160,20 @@ proc randomize*(seed: int) {.benign.} {.push noSideEffect.} when not defined(JS): proc sqrt*(x: float32): float32 {.importc: "sqrt", header: "".} - proc sqrt*(x: float64): float64 {.importc: "sqrt", header: "".} + proc sqrt*(x: float64): float64 {.importc: "sqrt", header: "".} ## computes the square root of `x`. proc cbrt*(x: float32): float32 {.importc: "cbrt", header: "".} - proc cbrt*(x: float64): float64 {.importc: "cbrt", header: "".} + proc cbrt*(x: float64): float64 {.importc: "cbrt", header: "".} ## computes the cubic root of `x` proc ln*(x: float32): float32 {.importc: "log", header: "".} - proc ln*(x: float64): float64 {.importc: "log", header: "".} + proc ln*(x: float64): float64 {.importc: "log", header: "".} ## computes ln(x). proc log10*(x: float32): float32 {.importc: "log10", header: "".} - proc log10*(x: float64): float64 {.importc: "log10", header: "".} + proc log10*(x: float64): float64 {.importc: "log10", header: "".} proc log2*[T: float32|float64](x: T): T = return ln(x) / ln(2.0) proc exp*(x: float32): float32 {.importc: "exp", header: "".} - proc exp*(x: float64): float64 {.importc: "exp", header: "".} + proc exp*(x: float64): float64 {.importc: "exp", header: "".} ## computes e**x. proc frexp*(x: float32, exponent: var int): float32 {. @@ -191,11 +191,11 @@ when not defined(JS): ## converts a float to an int by rounding. proc arccos*(x: float32): float32 {.importc: "acos", header: "".} - proc arccos*(x: float64): float64 {.importc: "acos", header: "".} + proc arccos*(x: float64): float64 {.importc: "acos", header: "".} proc arcsin*(x: float32): float32 {.importc: "asin", header: "".} - proc arcsin*(x: float64): float64 {.importc: "asin", header: "".} + proc arcsin*(x: float64): float64 {.importc: "asin", header: "".} proc arctan*(x: float32): float32 {.importc: "atan", header: "".} - proc arctan*(x: float64): float64 {.importc: "atan", header: "".} + proc arctan*(x: float64): float64 {.importc: "atan", header: "".} proc arctan2*(y, x: float32): float32 {.importc: "atan2", header: "".} proc arctan2*(y, x: float64): float64 {.importc: "atan2", header: "".} ## Calculate the arc tangent of `y` / `x`. @@ -204,37 +204,37 @@ when not defined(JS): ## (`x` near 0). proc cos*(x: float32): float32 {.importc: "cos", header: "".} - proc cos*(x: float64): float64 {.importc: "cos", header: "".} + proc cos*(x: float64): float64 {.importc: "cos", header: "".} proc cosh*(x: float32): float32 {.importc: "cosh", header: "".} - proc cosh*(x: float64): float64 {.importc: "cosh", header: "".} + proc cosh*(x: float64): float64 {.importc: "cosh", header: "".} proc hypot*(x, y: float32): float32 {.importc: "hypot", header: "".} proc hypot*(x, y: float64): float64 {.importc: "hypot", header: "".} ## same as ``sqrt(x*x + y*y)``. proc sinh*(x: float32): float32 {.importc: "sinh", header: "".} - proc sinh*(x: float64): float64 {.importc: "sinh", header: "".} + proc sinh*(x: float64): float64 {.importc: "sinh", header: "".} proc sin*(x: float32): float32 {.importc: "sin", header: "".} - proc sin*(x: float64): float64 {.importc: "sin", header: "".} + proc sin*(x: float64): float64 {.importc: "sin", header: "".} proc tan*(x: float32): float32 {.importc: "tan", header: "".} - proc tan*(x: float64): float64 {.importc: "tan", header: "".} + proc tan*(x: float64): float64 {.importc: "tan", header: "".} proc tanh*(x: float32): float32 {.importc: "tanh", header: "".} - proc tanh*(x: float64): float64 {.importc: "tanh", header: "".} + proc tanh*(x: float64): float64 {.importc: "tanh", header: "".} proc pow*(x, y: float32): float32 {.importc: "pow", header: "".} - proc pow*(x, y: float64): float64 {.importc: "pow", header: "".} + proc pow*(x, y: float64): float64 {.importc: "pow", header: "".} ## computes x to power raised of y. proc erf*(x: float32): float32 {.importc: "erf", header: "".} - proc erf*(x: float64): float64 {.importc: "erf", header: "".} + proc erf*(x: float64): float64 {.importc: "erf", header: "".} ## The error function proc erfc*(x: float32): float32 {.importc: "erfc", header: "".} - proc erfc*(x: float64): float64 {.importc: "erfc", header: "".} + proc erfc*(x: float64): float64 {.importc: "erfc", header: "".} ## The complementary error function proc lgamma*(x: float32): float32 {.importc: "lgamma", header: "".} - proc lgamma*(x: float64): float64 {.importc: "lgamma", header: "".} + proc lgamma*(x: float64): float64 {.importc: "lgamma", header: "".} ## Natural log of the gamma function proc tgamma*(x: float32): float32 {.importc: "tgamma", header: "".} - proc tgamma*(x: float64): float64 {.importc: "tgamma", header: "".} + proc tgamma*(x: float64): float64 {.importc: "tgamma", header: "".} ## The gamma function # C procs: @@ -288,21 +288,21 @@ when not defined(JS): result = int(rand()) mod max proc trunc*(x: float32): float32 {.importc: "trunc", header: "".} - proc trunc*(x: float64): float64 {.importc: "trunc", header: "".} + proc trunc*(x: float64): float64 {.importc: "trunc", header: "".} proc floor*(x: float32): float32 {.importc: "floor", header: "".} - proc floor*(x: float64): float64 {.importc: "floor", header: "".} + proc floor*(x: float64): float64 {.importc: "floor", header: "".} proc ceil*(x: float32): float32 {.importc: "ceil", header: "".} - proc ceil*(x: float64): float64 {.importc: "ceil", header: "".} + proc ceil*(x: float64): float64 {.importc: "ceil", header: "".} proc fmod*(x, y: float32): float32 {.importc: "fmod", header: "".} - proc fmod*(x, y: float64): float64 {.importc: "fmod", header: "".} + proc fmod*(x, y: float64): float64 {.importc: "fmod", header: "".} 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 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 ceil*(x: float64): float64 {.importc: "Math.ceil", nodecl.} proc random(max: int): int = result = int(floor(mathrandom() * float(max))) proc random(max: float): float = @@ -311,17 +311,17 @@ else: proc randomize(seed: int) = discard proc sqrt*(x: float32): float32 {.importc: "Math.sqrt", nodecl.} - proc sqrt*(x: float64): float64 {.importc: "Math.sqrt", nodecl.} + proc sqrt*(x: float64): float64 {.importc: "Math.sqrt", nodecl.} proc ln*(x: float32): float32 {.importc: "Math.log", nodecl.} - proc ln*(x: float64): float64 {.importc: "Math.log", nodecl.} + proc ln*(x: float64): float64 {.importc: "Math.log", nodecl.} proc log10*[T: float32|float64](x: T): T = return ln(x) / ln(10.0) - proc log2*[T: float32|float64](x: T): T = return ln(x) / ln(2.0) + proc log2*[T: float32|float64](x: T): T = return ln(x) / ln(2.0) proc exp*(x: float32): float32 {.importc: "Math.exp", nodecl.} - proc exp*(x: float64): float64 {.importc: "Math.exp", nodecl.} + proc exp*(x: float64): float64 {.importc: "Math.exp", nodecl.} proc round*(x: float): int {.importc: "Math.round", nodecl.} proc pow*(x, y: float32): float32 {.importC: "Math.pow", nodecl.} - proc pow*(x, y: float64): float64 {.importc: "Math.pow", nodecl.} + proc pow*(x, y: float64): float64 {.importc: "Math.pow", nodecl.} proc frexp*[T: float32|float64](x: T, exponent: var int): T = if x == 0.0: @@ -335,25 +335,25 @@ else: result = x / pow(2.0, ex) proc arccos*(x: float32): float32 {.importc: "Math.acos", nodecl.} - proc arccos*(x: float64): float64 {.importc: "Math.acos", nodecl.} + proc arccos*(x: float64): float64 {.importc: "Math.acos", nodecl.} proc arcsin*(x: float32): float32 {.importc: "Math.asin", nodecl.} - proc arcsin*(x: float64): float64 {.importc: "Math.asin", nodecl.} + proc arcsin*(x: float64): float64 {.importc: "Math.asin", nodecl.} proc arctan*(x: float32): float32 {.importc: "Math.atan", nodecl.} - proc arctan*(x: float64): float64 {.importc: "Math.atan", nodecl.} + proc arctan*(x: float64): float64 {.importc: "Math.atan", nodecl.} proc arctan2*(y, x: float32): float32 {.importC: "Math.atan2", nodecl.} - proc arctan2*(y, x: float64): float64 {.importc: "Math.atan2", nodecl.} + proc arctan2*(y, x: float64): float64 {.importc: "Math.atan2", nodecl.} proc cos*(x: float32): float32 {.importc: "Math.cos", nodecl.} - proc cos*(x: float64): float64 {.importc: "Math.cos", nodecl.} + proc cos*(x: float64): float64 {.importc: "Math.cos", nodecl.} proc cosh*(x: float32): float32 = return (exp(x)+exp(-x))*0.5 - proc cosh*(x: float64): float64 = return (exp(x)+exp(-x))*0.5 + proc cosh*(x: float64): float64 = return (exp(x)+exp(-x))*0.5 proc hypot*[T: float32|float64](x, y: T): T = return sqrt(x*x + y*y) proc sinh*]T: float32|float64](x: T): T = return (exp(x)-exp(-x))*0.5 proc sin*(x: float32): float32 {.importc: "Math.sin", nodecl.} - proc sin*(x: float64): float64 {.importc: "Math.sin", nodecl.} + proc sin*(x: float64): float64 {.importc: "Math.sin", nodecl.} proc tan*(x: float32): float32 {.importc: "Math.tan", nodecl.} - proc tan*(x: float64): float64 {.importc: "Math.tan", nodecl.} - proc tanh*[T: float32|float64](x: T): T = + proc tan*(x: float64): float64 {.importc: "Math.tan", nodecl.} + proc tanh*[T: float32|float64](x: T): T = var y = exp(2.0*x) return (y-1.0)/(y+1.0) From 6d1532439b43af5e72bf8d94f65c31dfdfb25969 Mon Sep 17 00:00:00 2001 From: apense Date: Wed, 24 Jun 2015 16:17:11 -0400 Subject: [PATCH 003/674] Fixed silly format error Needed other bracket --- lib/pure/math.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 4fae03cc5f..db1f27fc46 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -348,7 +348,7 @@ else: proc cosh*(x: float32): float32 = return (exp(x)+exp(-x))*0.5 proc cosh*(x: float64): float64 = return (exp(x)+exp(-x))*0.5 proc hypot*[T: float32|float64](x, y: T): T = return sqrt(x*x + y*y) - proc sinh*]T: float32|float64](x: T): T = return (exp(x)-exp(-x))*0.5 + proc sinh*[T: float32|float64](x: T): T = return (exp(x)-exp(-x))*0.5 proc sin*(x: float32): float32 {.importc: "Math.sin", nodecl.} proc sin*(x: float64): float64 {.importc: "Math.sin", nodecl.} proc tan*(x: float32): float32 {.importc: "Math.tan", nodecl.} From 739a8ea06095871a92cc3ef9d35a7ca782390195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20J=C3=B6ud?= Date: Wed, 14 Oct 2015 13:44:20 +0200 Subject: [PATCH 004/674] added maxsplit argument to strutils.split --- lib/pure/strutils.nim | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index a78fed4b91..c9b23daf25 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -322,7 +322,7 @@ proc toOctal*(c: char): string {.noSideEffect, rtl, extern: "nsuToOctal".} = result[i] = chr(val mod 8 + ord('0')) val = val div 8 -iterator split*(s: string, seps: set[char] = Whitespace): string = +iterator split*(s: string, seps: set[char] = Whitespace, maxsplit: int = -1): string = ## Splits the string `s` into substrings using a group of separators. ## ## Substrings are separated by a substring containing only `seps`. Note @@ -367,15 +367,20 @@ iterator split*(s: string, seps: set[char] = Whitespace): string = ## "08.398990" ## var last = 0 + var splits = maxsplit assert(not ('\0' in seps)) while last < len(s): while s[last] in seps: inc(last) var first = last while last < len(s) and s[last] notin seps: inc(last) # BUGFIX! if first <= last-1: + if splits == 0: + yield substr(s, first, len(s)-1) + break yield substr(s, first, last-1) + dec(splits) -iterator split*(s: string, sep: char): string = +iterator split*(s: string, sep: char, maxsplit: int = -1): string = ## Splits the string `s` into substrings using a single separator. ## ## Substrings are separated by the character `sep`. @@ -402,26 +407,36 @@ iterator split*(s: string, sep: char): string = ## "" ## var last = 0 + var splits = maxsplit assert('\0' != sep) if len(s) > 0: # `<=` is correct here for the edge cases! while last <= len(s): var first = last while last < len(s) and s[last] != sep: inc(last) + if splits == 0: + yield substr(s, first, len(s)-1) + break yield substr(s, first, last-1) + dec(splits) inc(last) -iterator split*(s: string, sep: string): string = +iterator split*(s: string, sep: string, maxsplit: int = -1): string = ## Splits the string `s` into substrings using a string separator. ## ## Substrings are separated by the string `sep`. var last = 0 + var splits = maxsplit if len(s) > 0: while last <= len(s): var first = last while last < len(s) and s.substr(last, last + `_, but is a ## proc that returns a sequence of substrings. - accumulateResult(split(s, seps)) + accumulateResult(split(s, seps, maxsplit)) -proc split*(s: string, sep: char): seq[string] {.noSideEffect, +proc split*(s: string, sep: char, maxsplit: int = -1): seq[string] {.noSideEffect, rtl, extern: "nsuSplitChar".} = ## The same as the `split iterator <#split.i,string,char>`_, but is a proc ## that returns a sequence of substrings. - accumulateResult(split(s, sep)) + accumulateResult(split(s, sep, maxsplit)) -proc split*(s: string, sep: string): seq[string] {.noSideEffect, +proc split*(s: string, sep: string, maxsplit: int = -1): seq[string] {.noSideEffect, rtl, extern: "nsuSplitString".} = ## Splits the string `s` into substrings using a string separator. ## ## Substrings are separated by the string `sep`. This is a wrapper around the ## `split iterator <#split.i,string,string>`_. - accumulateResult(split(s, sep)) + accumulateResult(split(s, sep, maxsplit)) proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect, rtl, extern: "nsuToHex".} = @@ -1660,7 +1675,7 @@ when isMainModule: doAssert isAlpha("Rasp") doAssert isAlpha("Args") doAssert(not isAlpha("$Tomato")) - + doAssert isAlphaNumeric('3') doAssert isAlphaNumeric('R') doAssert(not isAlphaNumeric('!')) From 4e8e5af934d7c44f5c6fe659b4dcca1e16cf964d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20J=C3=B6ud?= Date: Wed, 14 Oct 2015 14:00:51 +0200 Subject: [PATCH 005/674] added tests for strutils.split --- lib/pure/strutils.nim | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index c9b23daf25..516ca953b8 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1719,3 +1719,9 @@ when isMainModule: doAssert isUpper("ABC") doAssert(not isUpper("AAcc")) doAssert(not isUpper("A#$")) + + let s = " this is an example " + doAssert s.split() == @["this", "is", "an", "example"] + doAssert s.split(maxsplit=4) == @["this", "is", "an", "example"] + doAssert s.split(' ', maxsplit=4) == @["", "this", "", "", "is an example "] + doAssert s.split(" ", maxsplit=4) == @["", "this", "", "", "is an example "] From 755d89e32d39eb08e85a98b421909a7535051c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20J=C3=B6ud?= Date: Wed, 14 Oct 2015 15:29:27 +0200 Subject: [PATCH 006/674] modified strutils.split --- lib/pure/strutils.nim | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 516ca953b8..6eb87d91bd 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -374,10 +374,9 @@ iterator split*(s: string, seps: set[char] = Whitespace, maxsplit: int = -1): st var first = last while last < len(s) and s[last] notin seps: inc(last) # BUGFIX! if first <= last-1: - if splits == 0: - yield substr(s, first, len(s)-1) - break + if splits == 0: last = len(s) yield substr(s, first, last-1) + if splits == 0: break dec(splits) iterator split*(s: string, sep: char, maxsplit: int = -1): string = @@ -414,10 +413,9 @@ iterator split*(s: string, sep: char, maxsplit: int = -1): string = while last <= len(s): var first = last while last < len(s) and s[last] != sep: inc(last) - if splits == 0: - yield substr(s, first, len(s)-1) - break + if splits == 0: last = len(s) yield substr(s, first, last-1) + if splits == 0: break dec(splits) inc(last) @@ -432,10 +430,9 @@ iterator split*(s: string, sep: string, maxsplit: int = -1): string = var first = last while last < len(s) and s.substr(last, last + Date: Thu, 22 Oct 2015 23:51:52 +0200 Subject: [PATCH 007/674] net.nim: support storing arbitrary data inside SSLContext --- examples/ssl/extradata.nim | 14 ++++++++++++++ lib/pure/net.nim | 14 ++++++++++++++ lib/wrappers/openssl.nim | 4 ++++ 3 files changed, 32 insertions(+) create mode 100644 examples/ssl/extradata.nim diff --git a/examples/ssl/extradata.nim b/examples/ssl/extradata.nim new file mode 100644 index 0000000000..f86dc57f26 --- /dev/null +++ b/examples/ssl/extradata.nim @@ -0,0 +1,14 @@ +# Stores extra data inside the SSL context. +import net + +# Our unique index for storing foos +let fooIndex = getSslContextExtraDataIndex() +# And another unique index for storing foos +let barIndex = getSslContextExtraDataIndex() +echo "got indexes ", fooIndex, " ", barIndex + +let ctx = newContext() +assert ctx.getExtraData(fooIndex) == nil +let foo: int = 5 +ctx.setExtraData(fooIndex, cast[pointer](foo)) +assert cast[int](ctx.getExtraData(fooIndex)) == foo diff --git a/lib/pure/net.nim b/lib/pure/net.nim index d1016011e4..5498ebb7dd 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -243,6 +243,20 @@ when defined(ssl): newCTX.loadCertificates(certFile, keyFile) return SSLContext(newCTX) + proc getSslContextExtraDataIndex*(): cint = + ## Retrieves unique index for storing extra data in SSLContext. + return SSL_CTX_get_ex_new_index(0, nil, nil, nil, nil) + + proc setExtraData*(ctx: SSLContext, index: cint, data: pointer) = + ## Stores arbitrary data inside SSLContext. The unique `index` + ## should be retrieved using getSslContextExtraDataIndex. + if SslCtx(ctx).SSL_CTX_set_ex_data(index, data) == -1: + raiseSSLError() + + proc getExtraData*(ctx: SSLContext, index: cint): pointer = + ## Retrieves arbitrary data stored inside SSLContext. + return SslCtx(ctx).SSL_CTX_get_ex_data(index) + proc wrapSocket*(ctx: SSLContext, socket: Socket) = ## Wraps a socket in an SSL context. This function effectively turns ## ``socket`` into an SSL socket. diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 90610eb742..9f24ca58d1 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -216,6 +216,10 @@ proc SSL_CTX_use_PrivateKey_file*(ctx: SslCtx, proc SSL_CTX_check_private_key*(ctx: SslCtx): cInt{.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_CTX_get_ex_new_index*(argl: clong, argp: pointer, new_func: pointer, dup_func: pointer, free_func: pointer): cint {.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_CTX_set_ex_data*(ssl: SslCtx, idx: cint, arg: pointer): cint {.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_CTX_get_ex_data*(ssl: SslCtx, idx: cint): pointer {.cdecl, dynlib: DLLSSLName, importc.} + proc SSL_set_fd*(ssl: SslPtr, fd: SocketHandle): cint{.cdecl, dynlib: DLLSSLName, importc.} proc SSL_shutdown*(ssl: SslPtr): cInt{.cdecl, dynlib: DLLSSLName, importc.} From ba61a8d00a65948fc0b3a1c100a20cca711fdd0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Zieli=C5=84ski?= Date: Sat, 24 Oct 2015 08:53:18 +0200 Subject: [PATCH 008/674] net.nim: support for TLS-PSK ciphersuites --- examples/ssl/pskclient.nim | 15 ++++++ examples/ssl/pskserver.nim | 20 ++++++++ lib/pure/net.nim | 102 ++++++++++++++++++++++++++++++++----- lib/wrappers/openssl.nim | 20 ++++++++ 4 files changed, 144 insertions(+), 13 deletions(-) create mode 100644 examples/ssl/pskclient.nim create mode 100644 examples/ssl/pskserver.nim diff --git a/examples/ssl/pskclient.nim b/examples/ssl/pskclient.nim new file mode 100644 index 0000000000..7c93bbb612 --- /dev/null +++ b/examples/ssl/pskclient.nim @@ -0,0 +1,15 @@ +# Create connection encrypted using preshared key (TLS-PSK). +import net + +static: assert defined(ssl) + +let sock = newSocket() +sock.connect("localhost", Port(8800)) + +proc clientFunc(identityHint: string): tuple[identity: string, psk: string] = + echo "identity hint ", identityHint.repr + return ("foo", "psk-of-foo") + +let context = newContext(cipherList="PSK-AES256-CBC-SHA") +context.clientGetPskFunc = clientFunc +context.wrapConnectedSocket(sock, handshakeAsClient) diff --git a/examples/ssl/pskserver.nim b/examples/ssl/pskserver.nim new file mode 100644 index 0000000000..859eaa875c --- /dev/null +++ b/examples/ssl/pskserver.nim @@ -0,0 +1,20 @@ +# Accept connection encrypted using preshared key (TLS-PSK). +import net + +static: assert defined(ssl) + +let sock = newSocket() +sock.bindAddr(Port(8800)) +sock.listen() + +let context = newContext(cipherList="PSK-AES256-CBC-SHA") +context.pskIdentityHint = "hello" +context.serverGetPskFunc = proc(identity: string): string = "psk-of-" & identity + +while true: + var client = new(Socket) + sock.accept(client) + sock.setSockOpt(OptReuseAddr, true) + echo "accepted connection" + context.wrapConnectedSocket(client, handshakeAsServer) + echo "got connection with identity ", client.getPskIdentity() diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 5498ebb7dd..4bdfede42f 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -38,6 +38,10 @@ when defined(ssl): SslHandshakeType* = enum handshakeAsClient, handshakeAsServer + SslClientGetPskFunc* = proc(hint: string): tuple[identity: string, psk: string] + + SslServerGetPskFunc* = proc(identity: string): string + {.deprecated: [ESSL: SSLError, TSSLCVerifyMode: SSLCVerifyMode, TSSLProtVersion: SSLProtVersion, PSSLContext: SSLContext, TSSLAcceptResult: SSLAcceptResult].} @@ -168,6 +172,10 @@ when defined(ssl): ErrLoadBioStrings() OpenSSL_add_all_algorithms() + type SslContextExtraInternal = ref object + serverGetPskFunc: SslServerGetPskFunc + clientGetPskFunc: SslClientGetPskFunc + proc raiseSSLError*(s = "") = ## Raises a new SSL error. if s != "": @@ -180,6 +188,22 @@ when defined(ssl): var errStr = ErrErrorString(err, nil) raise newException(SSLError, $errStr) + proc getSslContextExtraDataIndex*(): cint = + ## Retrieves unique index for storing extra data in SSLContext. + return SSL_CTX_get_ex_new_index(0, nil, nil, nil, nil) + + proc setExtraData*(ctx: SSLContext, index: cint, data: pointer) = + ## Stores arbitrary data inside SSLContext. The unique `index` + ## should be retrieved using getSslContextExtraDataIndex. + if SslCtx(ctx).SSL_CTX_set_ex_data(index, data) == -1: + raiseSSLError() + + proc getExtraData*(ctx: SSLContext, index: cint): pointer = + ## Retrieves arbitrary data stored inside SSLContext. + return SslCtx(ctx).SSL_CTX_get_ex_data(index) + + let extraInternalIndex = getSslContextExtraDataIndex() + # http://simplestcodings.blogspot.co.uk/2010/08/secure-server-client-using-openssl-in-c.html proc loadCertificates(ctx: SSL_CTX, certFile, keyFile: string) = if certFile != "" and not existsFile(certFile): @@ -202,7 +226,7 @@ when defined(ssl): raiseSSLError("Verification of private key file failed.") proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer, - certFile = "", keyFile = ""): SSLContext = + certFile = "", keyFile = "", cipherList = "ALL"): SSLContext = ## Creates an SSL context. ## ## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1 @@ -229,7 +253,7 @@ when defined(ssl): of protTLSv1: newCTX = SSL_CTX_new(TLSv1_method()) - if newCTX.SSLCTXSetCipherList("ALL") != 1: + if newCTX.SSLCTXSetCipherList(cipherList) != 1: raiseSSLError() case verifyMode of CVerifyPeer: @@ -241,21 +265,73 @@ when defined(ssl): discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY) newCTX.loadCertificates(certFile, keyFile) - return SSLContext(newCTX) - proc getSslContextExtraDataIndex*(): cint = - ## Retrieves unique index for storing extra data in SSLContext. - return SSL_CTX_get_ex_new_index(0, nil, nil, nil, nil) + result = SSLContext(newCTX) + # this is never freed, but SSLContext can't be freed anyway yet + let extraInternal = new(SslContextExtraInternal) + GC_ref(extraInternal) + result.setExtraData(extraInternalIndex, cast[pointer](extraInternal)) - proc setExtraData*(ctx: SSLContext, index: cint, data: pointer) = - ## Stores arbitrary data inside SSLContext. The unique `index` - ## should be retrieved using getSslContextExtraDataIndex. - if SslCtx(ctx).SSL_CTX_set_ex_data(index, data) == -1: + proc getExtraInternal(ctx: SSLContext): SslContextExtraInternal = + return cast[SslContextExtraInternal](ctx.getExtraData(extraInternalIndex)) + + proc `pskIdentityHint=`*(ctx: SSLContext, hint: string) = + ## Sets the identity hint passed to server. + ## + ## Only used in PSK ciphersuites. + if SSLCTX(ctx).SSL_CTX_use_psk_identity_hint(hint) <= 0: raiseSSLError() - proc getExtraData*(ctx: SSLContext, index: cint): pointer = - ## Retrieves arbitrary data stored inside SSLContext. - return SslCtx(ctx).SSL_CTX_get_ex_data(index) + proc clientGetPskFunc*(ctx: SSLContext): SslClientGetPskFunc = + return ctx.getExtraInternal().clientGetPskFunc + + proc pskClientCallback(ssl: SslPtr; hint: cstring; identity: cstring; max_identity_len: cuint; psk: ptr cuchar; + max_psk_len: cuint): cuint {.cdecl.} = + let ctx = SSLContext(ssl.SSL_get_SSL_CTX) + let hintString = if hint == nil: nil else: $hint + let (identityString, pskString) = (ctx.clientGetPskFunc)(hintString) + if psk.len.cuint > max_psk_len: + return 0 + if identityString.len.cuint >= max_identity_len: + return 0 + + copyMem(identity, identityString.cstring, pskString.len + 1) # with the last zero byte + copyMem(psk, pskString.cstring, pskString.len) + + return pskString.len.cuint + + proc `clientGetPskFunc=`*(ctx: SSLContext, fun: SslClientGetPskFunc) = + ## Sets function that returns the client identity and the PSK based on identity + ## hint from the server. + ## + ## Only used in PSK ciphersuites. + ctx.getExtraInternal().clientGetPskFunc = fun + SslCtx(ctx).SSL_CTX_set_psk_client_callback(if fun == nil: nil else: pskClientCallback) + + proc serverGetPskFunc*(ctx: SSLContext): SslServerGetPskFunc = + return ctx.getExtraInternal().serverGetPskFunc + + proc pskServerCallback(ssl: SslCtx; identity: cstring; psk: ptr cuchar; max_psk_len: cint): cuint {.cdecl.} = + let ctx = SSLContext(ssl.SSL_get_SSL_CTX) + let pskString = (ctx.serverGetPskFunc)($identity) + if psk.len.cint > max_psk_len: + return 0 + copyMem(psk, pskString.cstring, pskString.len) + + return pskString.len.cuint + + proc `serverGetPskFunc=`*(ctx: SSLContext, fun: SslServerGetPskFunc) = + ## Sets function that returns PSK based on the client identity. + ## + ## Only used in PSK ciphersuites. + ctx.getExtraInternal().serverGetPskFunc = fun + SslCtx(ctx).SSL_CTX_set_psk_server_callback(if fun == nil: nil + else: pskServerCallback) + + proc getPskIdentity*(socket: Socket): string = + ## Gets the PSK identity provided by the client. + assert socket.isSSL + return $(socket.sslHandle.SSL_get_psk_identity) proc wrapSocket*(ctx: SSLContext, socket: Socket) = ## Wraps a socket in an SSL context. This function effectively turns diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 9f24ca58d1..7ede0f12c9 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -197,6 +197,7 @@ proc TLSv1_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.} proc SSL_new*(context: SslCtx): SslPtr{.cdecl, dynlib: DLLSSLName, importc.} proc SSL_free*(ssl: SslPtr){.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_get_SSL_CTX*(ssl: SslPtr): SslCtx {.cdecl, dynlib: DLLSSLName, importc.} proc SSL_CTX_new*(meth: PSSL_METHOD): SslCtx{.cdecl, dynlib: DLLSSLName, importc.} proc SSL_CTX_load_verify_locations*(ctx: SslCtx, CAfile: cstring, @@ -318,6 +319,25 @@ proc SSL_CTX_set_tlsext_servername_arg*(ctx: SslCtx, arg: pointer): int = ## Set the pointer to be used in the callback registered to ``SSL_CTX_set_tlsext_servername_callback``. result = SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, arg) +type + PskClientCallback* = proc (ssl: SslPtr; + hint: cstring; identity: cstring; max_identity_len: cuint; psk: ptr cuchar; + max_psk_len: cuint): cuint {.cdecl.} + + PskServerCallback* = proc (ssl: SslPtr; + identity: cstring; psk: ptr cuchar; max_psk_len: cint): cuint {.cdecl.} + +proc SSL_CTX_set_psk_client_callback*(ctx: SslCtx; callback: PskClientCallback) {.cdecl, dynlib: DLLSSLName, importc.} + ## Set callback called when OpenSSL needs PSK (for client). + +proc SSL_CTX_set_psk_server_callback*(ctx: SslCtx; callback: PskServerCallback) {.cdecl, dynlib: DLLSSLName, importc.} + ## Set callback called when OpenSSL needs PSK (for server). + +proc SSL_CTX_use_psk_identity_hint*(ctx: SslCtx; hint: cstring): cint {.cdecl, dynlib: DLLSSLName, importc.} + ## Set PSK identity hint to use. + +proc SSL_get_psk_identity*(ssl: SslPtr): cstring {.cdecl, dynlib: DLLSSLName, importc.} + ## Get PSK identity. proc bioNew*(b: PBIO_METHOD): BIO{.cdecl, dynlib: DLLUtilName, importc: "BIO_new".} proc bioFreeAll*(b: BIO){.cdecl, dynlib: DLLUtilName, importc: "BIO_free_all".} From 3ecf33fa6acc87b204ac0240b597d5d91d0a78f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Zieli=C5=84ski?= Date: Sat, 24 Oct 2015 22:48:33 +0200 Subject: [PATCH 009/674] net.nim: destroyContext for destroying SSLContext --- examples/ssl/pskclient.nim | 1 + lib/pure/net.nim | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/ssl/pskclient.nim b/examples/ssl/pskclient.nim index 7c93bbb612..c83f27fbc9 100644 --- a/examples/ssl/pskclient.nim +++ b/examples/ssl/pskclient.nim @@ -13,3 +13,4 @@ proc clientFunc(identityHint: string): tuple[identity: string, psk: string] = let context = newContext(cipherList="PSK-AES256-CBC-SHA") context.clientGetPskFunc = clientFunc context.wrapConnectedSocket(sock, handshakeAsClient) +context.destroyContext() diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 4bdfede42f..368ff6e878 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -267,7 +267,6 @@ when defined(ssl): newCTX.loadCertificates(certFile, keyFile) result = SSLContext(newCTX) - # this is never freed, but SSLContext can't be freed anyway yet let extraInternal = new(SslContextExtraInternal) GC_ref(extraInternal) result.setExtraData(extraInternalIndex, cast[pointer](extraInternal)) @@ -275,6 +274,13 @@ when defined(ssl): proc getExtraInternal(ctx: SSLContext): SslContextExtraInternal = return cast[SslContextExtraInternal](ctx.getExtraData(extraInternalIndex)) + proc destroyContext*(ctx: SSLContext) = + ## Free memory referenced by SSLContext. + let extraInternal = ctx.getExtraInternal() + if extraInternal != nil: + GC_unref(extraInternal) + SSLCTX(ctx).SSL_CTX_free() + proc `pskIdentityHint=`*(ctx: SSLContext, hint: string) = ## Sets the identity hint passed to server. ## From da308be2d7b25683a3073187f699f95f81ac149e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Zieli=C5=84ski?= Date: Wed, 28 Oct 2015 19:55:04 +0100 Subject: [PATCH 010/674] net.nim: add support for Unix sockets --- examples/unix_socket/client.nim | 6 ++++++ examples/unix_socket/server.nim | 14 ++++++++++++++ lib/posix/posix.nim | 13 +++++++++++++ lib/pure/nativesockets.nim | 2 +- lib/pure/net.nim | 24 +++++++++++++++++++++++- 5 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 examples/unix_socket/client.nim create mode 100644 examples/unix_socket/server.nim diff --git a/examples/unix_socket/client.nim b/examples/unix_socket/client.nim new file mode 100644 index 0000000000..f4283d64dd --- /dev/null +++ b/examples/unix_socket/client.nim @@ -0,0 +1,6 @@ +import net + +let sock = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_IP) + +sock.connectUnix("sock") +sock.send("hello\n") diff --git a/examples/unix_socket/server.nim b/examples/unix_socket/server.nim new file mode 100644 index 0000000000..e798bbb48e --- /dev/null +++ b/examples/unix_socket/server.nim @@ -0,0 +1,14 @@ +import net + +let sock = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_IP) +sock.bindUnix("sock") +sock.listen() + +while true: + var client = new(Socket) + sock.accept(client) + var output = "" + output.setLen 32 + client.readLine(output) + echo "got ", output + client.close() diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 5f1dfcfcd5..cae469fe87 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -439,6 +439,14 @@ when hasSpawnH: Tposix_spawn_file_actions* {.importc: "posix_spawn_file_actions_t", header: "", final, pure.} = object +when defined(linux): + # from sys/un.h + const Sockaddr_un_path_length* = 108 +else: + # according to http://pubs.opengroup.org/onlinepubs/009604499/basedefs/sys/un.h.html + # this is >=92 + const Sockaddr_un_path_length* = 92 + type Socklen* {.importc: "socklen_t", header: "".} = cuint TSa_Family* {.importc: "sa_family_t", header: "".} = cint @@ -448,6 +456,11 @@ type sa_family*: TSa_Family ## Address family. sa_data*: array [0..255, char] ## Socket address (variable-length data). + Sockaddr_un* {.importc: "struct sockaddr_un", header: "", + pure, final.} = object ## struct sockaddr_un + sun_family*: TSa_Family ## Address family. + sun_path*: array [0..Sockaddr_un_path_length-1, char] ## Socket path + Sockaddr_storage* {.importc: "struct sockaddr_storage", header: "", pure, final.} = object ## struct sockaddr_storage diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index c9e067a3e7..e75555115f 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -27,7 +27,7 @@ else: import posix export fcntl, F_GETFL, O_NONBLOCK, F_SETFL, EAGAIN, EWOULDBLOCK, MSG_NOSIGNAL, EINTR, EINPROGRESS, ECONNRESET, EPIPE, ENETRESET - export Sockaddr_storage + export Sockaddr_storage, Sockaddr_un, Sockaddr_un_path_length export SocketHandle, Sockaddr_in, Addrinfo, INADDR_ANY, SockAddr, SockLen, Sockaddr_in6, diff --git a/lib/pure/net.nim b/lib/pure/net.nim index d1016011e4..8bc08c4335 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -10,8 +10,9 @@ ## This module implements a high-level cross-platform sockets interface. {.deadCodeElim: on.} -import nativesockets, os, strutils, unsigned, parseutils, times +import nativesockets, os, strutils, parseutils, times export Port, `$`, `==` +export Domain, SockType, Protocol const useWinVersion = defined(Windows) or defined(nimdoc) @@ -582,6 +583,27 @@ proc connect*(socket: Socket, address: string, let ret = SSLConnect(socket.sslHandle) socketError(socket, ret) +when defined(posix): + 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) + + proc connectUnix*(socket: Socket, path: string) = + ## Connects to Unix socket on `path`. + 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`. + 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 {.tags: [ReadIOEffect, WriteIOEffect].} = ## This proc needs to be called on a socket after it connects. This is From 47e45dee7e9157212995c5769b93713f5a4dd14b Mon Sep 17 00:00:00 2001 From: Adam Strzelecki Date: Thu, 29 Oct 2015 22:10:09 +0100 Subject: [PATCH 011/674] fixes #3496 The problem comes from the fact that macroOrTmpl[...] is transformed by semSubscript which is trying to evaluate macroOrTmpl identifier in place. This is okay for non-generic macros or templates, but wrong for generic ones, that do not have a chance to receive their generic arguments explicitly specified in brackets. Solution: 1. macroOrTmpl[...] where macroOrTmpl is non-generic macro or template, then macroOrTmpl is evaluated before applying brackets. (as before) 2. macroOrTmpl[...] where macroOrTmpl is generic macro or template, then if: a. It comes from macroOrTmpl[...](...) call expr (efInCall), then macroOrTmpl is turned into a symbol (efNoEvaluate) rather than evaluating it in place, then whole bracket expr is returned to semIndirectOp which transforms it to proper generic macro or template call with explicit generic arguments. b. macroOrTmpl[...] does not come from call expr, as above macroOrTmpl is transformed to symbol, then it is transformed into proper generic macro or template call with explicit generic arguments and no normal arguments. --- compiler/semdata.nim | 2 +- compiler/semexprs.nim | 60 +++++++++++++++++++++++++++++--- tests/generics/tgenerictmpl2.nim | 31 +++++++++++++++++ 3 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 tests/generics/tgenerictmpl2.nim diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 9b2f2e2ce7..d350f7bea0 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -46,7 +46,7 @@ type efLValue, efWantIterator, efInTypeof, efWantStmt, efAllowStmt, efDetermineType, efAllowDestructor, efWantValue, efOperand, efNoSemCheck, - efNoProcvarCheck + efNoProcvarCheck, efNoEvaluateGeneric, efInCall TExprFlags* = set[TExprFlag] TTypeAttachedOp* = enum diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index f1016595a0..7b3697f8d2 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -102,8 +102,20 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = else: result = newSymNode(s, n.info) else: result = newSymNode(s, n.info) - of skMacro: result = semMacroExpr(c, n, n, s, flags) - of skTemplate: result = semTemplateExpr(c, n, s, flags) + of skMacro: + if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len>0: + markUsed(n.info, s) + styleCheckUse(n.info, s) + result = newSymNode(s, n.info) + else: + result = semMacroExpr(c, n, n, s, flags) + of skTemplate: + if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len>0: + markUsed(n.info, s) + styleCheckUse(n.info, s) + result = newSymNode(s, n.info) + else: + result = semTemplateExpr(c, n, s, flags) of skParam: markUsed(n.info, s) styleCheckUse(n.info, s) @@ -806,10 +818,34 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = for i in countup(1, sonsLen(n) - 1): addSon(result, n.sons[i]) return semExpr(c, result, flags) else: - n.sons[0] = semExpr(c, n.sons[0]) + n.sons[0] = semExpr(c, n.sons[0], {efInCall}) let t = n.sons[0].typ if t != nil and t.kind == tyVar: n.sons[0] = newDeref(n.sons[0]) + elif n.sons[0].kind == nkBracketExpr: + checkMinSonsLen(n.sons[0], 2) + # We received untransformed bracket expression coming from macroOrTmpl[]. + # Transform it to macro or template call, where first come normal + # arguments, next come generic template arguments. + if n.sons[0].sons[0].kind == nkSym: + let s = n.sons[0].sons[0].sym + if s.kind in {skMacro, skTemplate}: + var sons = newSeq[PNode]() + sons.add n.sons[0].sons[0] + # Normal arguments: + for i in 1.. Date: Tue, 15 Dec 2015 23:50:28 +0000 Subject: [PATCH 012/674] Add SO_REUSEPORT support --- lib/posix/posix.nim | 2 ++ lib/pure/asynchttpserver.nim | 6 +++++- lib/pure/nativesockets.nim | 2 +- lib/pure/net.nim | 3 ++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 5f1dfcfcd5..c3d563419c 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -1566,6 +1566,8 @@ var ## Receive timeout. SO_REUSEADDR* {.importc, header: "".}: cint ## Reuse of local addresses is supported. + SO_REUSEPORT* {.importc, header: "".}: cint + ## Multiple binding: load balancing on incoming TCP connections or UDP packets. (Requires Linux kernel > 3.9) SO_SNDBUF* {.importc, header: "".}: cint ## Send buffer size. SO_SNDLOWAT* {.importc, header: "".}: cint diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 590b52c1a2..865b14c751 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -39,6 +39,7 @@ type AsyncHttpServer* = ref object socket: AsyncSocket reuseAddr: bool + reusePort: bool HttpCode* = enum Http100 = "100 Continue", @@ -99,10 +100,11 @@ proc `==`*(protocol: tuple[orig: string, major, minor: int], of HttpVer10: 0 result = protocol.major == major and protocol.minor == minor -proc newAsyncHttpServer*(reuseAddr = true): AsyncHttpServer = +proc newAsyncHttpServer*(reuseAddr = true, reusePort = false): AsyncHttpServer = ## Creates a new ``AsyncHttpServer`` instance. new result result.reuseAddr = reuseAddr + result.reusePort = reusePort proc addHeaders(msg: var string, headers: StringTableRef) = for k, v in headers: @@ -264,6 +266,8 @@ proc serve*(server: AsyncHttpServer, port: Port, server.socket = newAsyncSocket() if server.reuseAddr: server.socket.setSockOpt(OptReuseAddr, true) + if server.reusePort: + server.socket.setSockOpt(OptReusePort, true) server.socket.bindAddr(port, address) server.socket.listen() diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim index 8a77805704..37e3773c5a 100644 --- a/lib/pure/nativesockets.nim +++ b/lib/pure/nativesockets.nim @@ -38,7 +38,7 @@ export SOL_SOCKET, SOMAXCONN, SO_ACCEPTCONN, SO_BROADCAST, SO_DEBUG, SO_DONTROUTE, - SO_KEEPALIVE, SO_OOBINLINE, SO_REUSEADDR, + SO_KEEPALIVE, SO_OOBINLINE, SO_REUSEADDR, SO_REUSEPORT, MSG_PEEK when defined(macosx) and not defined(nimdoc): diff --git a/lib/pure/net.nim b/lib/pure/net.nim index d1016011e4..1243201ab3 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -72,7 +72,7 @@ type SOBool* = enum ## Boolean socket options. OptAcceptConn, OptBroadcast, OptDebug, OptDontRoute, OptKeepAlive, - OptOOBInline, OptReuseAddr + OptOOBInline, OptReuseAddr, OptReusePort ReadLineResult* = enum ## result for readLineAsync ReadFullLine, ReadPartialLine, ReadDisconnected, ReadNone @@ -523,6 +523,7 @@ proc toCInt*(opt: SOBool): cint = of OptKeepAlive: SO_KEEPALIVE of OptOOBInline: SO_OOBINLINE of OptReuseAddr: SO_REUSEADDR + of OptReusePort: SO_REUSEPORT proc getSockOpt*(socket: Socket, opt: SOBool, level = SOL_SOCKET): bool {. tags: [ReadIOEffect].} = From 8a286d3e58a6c292da2be473c758d0ee5b8e989e Mon Sep 17 00:00:00 2001 From: JamesP Date: Sun, 24 Jan 2016 17:32:23 +1000 Subject: [PATCH 013/674] Fix row reading procs to not use SQLRowCount, but SQLFetch until returns SQL_NO_DATA change SqlCheck() and SqlGetDBMS() to sqlCheck() and sqlGetDBMS() (camelCase consistency) --- lib/impure/db_odbc.nim | 103 ++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 54 deletions(-) diff --git a/lib/impure/db_odbc.nim b/lib/impure/db_odbc.nim index 4f0b0469da..1b72c6241d 100644 --- a/lib/impure/db_odbc.nim +++ b/lib/impure/db_odbc.nim @@ -169,11 +169,11 @@ proc dbError*(db: var DbConn) {. properFreeResult(SQL_HANDLE_ENV, db.env) raise e -proc SqlCheck(db: var DbConn, resVal: TSqlSmallInt) {.raises: [DbError]} = - ## Wrapper that checks if ``resVal`` is not SQL_SUCCESS and if so, raises [EDb] - if resVal != SQL_SUCCESS: dbError(db) +proc sqlCheck(db: var DbConn, resVal: TSqlSmallInt) {.raises: [DbError]} = + ## Wrapper that raises [EDb] if ``resVal`` is neither SQL_SUCCESS or SQL_NO_DATA + if resVal notIn [SQL_SUCCESS, SQL_NO_DATA]: dbError(db) -proc SqlGetDBMS(db: var DbConn): string {. +proc sqlGetDBMS(db: var DbConn): string {. tags: [ReadDbEffect, WriteDbEffect], raises: [] .} = ## Returns the ODBC SQL_DBMS_NAME string const @@ -182,7 +182,7 @@ proc SqlGetDBMS(db: var DbConn): string {. sz: TSqlSmallInt = 0 buf[0] = '\0' try: - db.SqlCheck(SQLGetInfo(db.hDb, SQL_DBMS_NAME, cast[SqlPointer](buf.addr), + db.sqlCheck(SQLGetInfo(db.hDb, SQL_DBMS_NAME, cast[SqlPointer](buf.addr), 4095.TSqlSmallInt, sz.addr)) except: discard return $buf.cstring @@ -220,11 +220,11 @@ proc prepareFetch(db: var DbConn, query: SqlQuery, # requires calling # properFreeResult(SQL_HANDLE_STMT, db.stmt) # when finished - db.SqlCheck(SQLAllocHandle(SQL_HANDLE_STMT, db.hDb, db.stmt)) + db.sqlCheck(SQLAllocHandle(SQL_HANDLE_STMT, db.hDb, db.stmt)) var q = dbFormat(query, args) - db.SqlCheck(SQLPrepare(db.stmt, q.PSQLCHAR, q.len.TSqlSmallInt)) - db.SqlCheck(SQLExecute(db.stmt)) - db.SqlCheck(SQLFetch(db.stmt)) + db.sqlCheck(SQLPrepare(db.stmt, q.PSQLCHAR, q.len.TSqlSmallInt)) + db.sqlCheck(SQLExecute(db.stmt)) + db.sqlCheck(SQLFetch(db.stmt)) proc prepareFetchDirect(db: var DbConn, query: SqlQuery, args: varargs[string, `$`]) {. @@ -235,10 +235,10 @@ proc prepareFetchDirect(db: var DbConn, query: SqlQuery, # requires calling # properFreeResult(SQL_HANDLE_STMT, db.stmt) # when finished - db.SqlCheck(SQLAllocHandle(SQL_HANDLE_STMT, db.hDb, db.stmt)) + db.sqlCheck(SQLAllocHandle(SQL_HANDLE_STMT, db.hDb, db.stmt)) var q = dbFormat(query, args) - db.SqlCheck(SQLExecDirect(db.stmt, q.PSQLCHAR, q.len.TSqlSmallInt)) - db.SqlCheck(SQLFetch(db.stmt)) + db.sqlCheck(SQLExecDirect(db.stmt, q.PSQLCHAR, q.len.TSqlSmallInt)) + db.sqlCheck(SQLFetch(db.stmt)) proc tryExec*(db: var DbConn, query: SqlQuery, args: varargs[string, `$`]): bool {. tags: [ReadDbEffect, WriteDbEffect], raises: [].} = @@ -285,20 +285,19 @@ iterator fastRows*(db: var DbConn, query: SqlQuery, rowRes: Row sz: TSqlSmallInt = 0 cCnt: TSqlSmallInt = 0.TSqlSmallInt - rCnt = -1 - + res: TSqlSmallInt = 0.TSqlSmallInt db.prepareFetch(query, args) - db.SqlCheck(SQLNumResultCols(db.stmt, cCnt)) - db.SqlCheck(SQLRowCount(db.stmt, rCnt)) - rowRes = newRow(cCnt) - for rNr in 1..rCnt: + res = SQLNumResultCols(db.stmt, cCnt) + rowRes.setLen(cCnt) + while res == SQL_SUCCESS: for colId in 1..cCnt: buf[0] = '\0' - db.SqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR, + db.sqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR, cast[cstring](buf.addr), 4095.TSqlSmallInt, sz.addr)) rowRes[colId-1] = $buf.cstring - db.SqlCheck(SQLFetchScroll(db.stmt, SQL_FETCH_NEXT, 1)) yield rowRes + res = SQLFetch(db.stmt) + db.sqlCheck(res) properFreeResult(SQL_HANDLE_STMT, db.stmt) iterator instantRows*(db: var DbConn, query: SqlQuery, @@ -307,22 +306,22 @@ iterator instantRows*(db: var DbConn, query: SqlQuery, ## Same as fastRows but returns a handle that can be used to get column text ## on demand using []. Returned handle is valid only within the interator body. var - rowRes: Row + rowRes: Row = @[] sz: TSqlSmallInt = 0 cCnt: TSqlSmallInt = 0.TSqlSmallInt - rCnt = -1 + res: TSqlSmallInt = 0.TSqlSmallInt db.prepareFetch(query, args) - db.SqlCheck(SQLNumResultCols(db.stmt, cCnt)) - db.SqlCheck(SQLRowCount(db.stmt, rCnt)) - rowRes = newRow(cCnt) - for rNr in 1..rCnt: + res = SQLNumResultCols(db.stmt, cCnt) + rowRes.setLen(cCnt) + while res == SQL_SUCCESS: for colId in 1..cCnt: buf[0] = '\0' - db.SqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR, + db.sqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR, cast[cstring](buf.addr), 4095.TSqlSmallInt, sz.addr)) rowRes[colId-1] = $buf.cstring - db.SqlCheck(SQLFetchScroll(db.stmt, SQL_FETCH_NEXT, 1)) yield (row: rowRes, len: cCnt.int) + res = SQLFetch(db.stmt) + db.sqlCheck(res) properFreeResult(SQL_HANDLE_STMT, db.stmt) proc `[]`*(row: InstantRow, col: int): string {.inline.} = @@ -341,17 +340,17 @@ proc getRow*(db: var DbConn, query: SqlQuery, var sz: TSqlSmallInt = 0.TSqlSmallInt cCnt: TSqlSmallInt = 0.TSqlSmallInt - rCnt = -1 - result = @[] + res: TSqlSmallInt = 0.TSqlSmallInt db.prepareFetch(query, args) - db.SqlCheck(SQLNumResultCols(db.stmt, cCnt)) - - db.SqlCheck(SQLRowCount(db.stmt, rCnt)) - for colId in 1..cCnt: - db.SqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR, - cast[cstring](buf.addr), 4095.TSqlSmallInt, sz.addr)) - result.add($buf.cstring) - db.SqlCheck(SQLFetchScroll(db.stmt, SQL_FETCH_NEXT, 1)) + res = SQLNumResultCols(db.stmt, cCnt) + result.setLen(max(cCnt,0)) + if res == SQL_SUCCESS: + for colId in 1..cCnt: + db.sqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR, + cast[cstring](buf.addr), 4095.TSqlSmallInt, sz.addr)) + result[colId-1] = $buf.cstring + res = SQLFetch(db.stmt) + db.sqlCheck(res) properFreeResult(SQL_HANDLE_STMT, db.stmt) proc getAllRows*(db: var DbConn, query: SqlQuery, @@ -362,20 +361,20 @@ proc getAllRows*(db: var DbConn, query: SqlQuery, rowRes: Row sz: TSqlSmallInt = 0 cCnt: TSqlSmallInt = 0.TSqlSmallInt - rCnt = -1 + res: TSqlSmallInt = 0.TSqlSmallInt db.prepareFetch(query, args) - db.SqlCheck(SQLNumResultCols(db.stmt, cCnt)) - db.SqlCheck(SQLRowCount(db.stmt, rCnt)) + res = SQLNumResultCols(db.stmt, cCnt) result = @[] - for rNr in 1..rCnt: - rowRes = @[] + rowRes.setLen(max(cCnt,0)) + while res == SQL_SUCCESS: buf[0] = '\0' for colId in 1..cCnt: - db.SqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR, + db.sqlCheck(SQLGetData(db.stmt, colId.SqlUSmallInt, SQL_C_CHAR, cast[SqlPointer](buf.addr), 4095.TSqlSmallInt, sz.addr)) - rowRes.add($buf.cstring) - db.SqlCheck(SQLFetchScroll(db.stmt, SQL_FETCH_NEXT, 1)) + rowRes[colId-1] = $buf.cstring result.add(rowRes) + res = SQLFetch(db.stmt) + db.sqlCheck(res) properFreeResult(SQL_HANDLE_STMT, db.stmt) iterator rows*(db: var DbConn, query: SqlQuery, @@ -407,10 +406,9 @@ proc tryInsertId*(db: var DbConn, query: SqlQuery, if not tryExec(db, query, args): result = -1'i64 else: - echo "DBMS: ",SqlGetDBMS(db).toLower() result = -1'i64 try: - case SqlGetDBMS(db).toLower(): + case sqlGetDBMS(db).toLower(): of "postgresql": result = getValue(db, sql"SELECT LASTVAL();", []).parseInt of "mysql": @@ -438,15 +436,12 @@ proc execAffectedRows*(db: var DbConn, query: SqlQuery, ## Runs the query (typically "UPDATE") and returns the ## number of affected rows result = -1 - var res = SQLAllocHandle(SQL_HANDLE_STMT, db.hDb, db.stmt.SqlHandle) - if res != SQL_SUCCESS: dbError(db) + db.sqlCheck(SQLAllocHandle(SQL_HANDLE_STMT, db.hDb, db.stmt.SqlHandle)) var q = dbFormat(query, args) - res = SQLPrepare(db.stmt, q.PSQLCHAR, q.len.TSqlSmallInt) - if res != SQL_SUCCESS: dbError(db) + db.sqlCheck(SQLPrepare(db.stmt, q.PSQLCHAR, q.len.TSqlSmallInt)) rawExec(db, query, args) var rCnt = -1 - result = SQLRowCount(db.hDb, rCnt) - if res != SQL_SUCCESS: dbError(db) + db.sqlCheck(SQLRowCount(db.hDb, rCnt)) properFreeResult(SQL_HANDLE_STMT, db.stmt) result = rCnt From b235e5b279c0b0f61deb9c0884716de0485a0439 Mon Sep 17 00:00:00 2001 From: Ruslan Mustakov Date: Thu, 24 Mar 2016 20:54:11 +0600 Subject: [PATCH 014/674] mersenne.nim public procs no longer work with platform-dependent int type --- lib/pure/mersenne.nim | 28 +++++++++++++++------------- web/news.txt | 3 +++ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/lib/pure/mersenne.nim b/lib/pure/mersenne.nim index ae0845714e..afa343086c 100644 --- a/lib/pure/mersenne.nim +++ b/lib/pure/mersenne.nim @@ -5,29 +5,31 @@ type {.deprecated: [TMersenneTwister: MersenneTwister].} -proc newMersenneTwister*(seed: int): MersenneTwister = +proc newMersenneTwister*(seed: uint32): MersenneTwister = result.index = 0 - result.mt[0]= uint32(seed) + result.mt[0] = seed for i in 1..623'u32: - result.mt[i]= (0x6c078965'u32 * (result.mt[i-1] xor (result.mt[i-1] shr 30'u32)) + i) + result.mt[i] = (0x6c078965'u32 * (result.mt[i-1] xor (result.mt[i-1] shr 30'u32)) + i) proc generateNumbers(m: var MersenneTwister) = for i in 0..623: - var y = (m.mt[i] and 0x80000000'u32) + (m.mt[(i+1) mod 624] and 0x7fffffff'u32) + var y = (m.mt[i] and 0x80000000'u32) + + (m.mt[(i+1) mod 624] and 0x7fffffff'u32) m.mt[i] = m.mt[(i+397) mod 624] xor uint32(y shr 1'u32) if (y mod 2'u32) != 0: - m.mt[i] = m.mt[i] xor 0x9908b0df'u32 + m.mt[i] = m.mt[i] xor 0x9908b0df'u32 -proc getNum*(m: var MersenneTwister): int = +proc getNum*(m: var MersenneTwister): uint32 = + ## Returns the next pseudo random number ranging from 0 to high(uint32) if m.index == 0: generateNumbers(m) - var y = m.mt[m.index] - y = y xor (y shr 11'u32) - y = y xor ((7'u32 shl y) and 0x9d2c5680'u32) - y = y xor ((15'u32 shl y) and 0xefc60000'u32) - y = y xor (y shr 18'u32) - m.index = (m.index+1) mod 624 - return int(y) + result = m.mt[m.index] + m.index = (m.index + 1) mod m.mt.len + + result = result xor (result shr 11'u32) + result = result xor ((7'u32 shl result) and 0x9d2c5680'u32) + result = result xor ((15'u32 shl result) and 0xefc60000'u32) + result = result xor (result shr 18'u32) # Test when not defined(testing) and isMainModule: diff --git a/web/news.txt b/web/news.txt index e818ed66e7..82ed4fe44a 100644 --- a/web/news.txt +++ b/web/news.txt @@ -20,6 +20,9 @@ Changes affecting backwards compatibility new experimental ``this`` pragma to achieve a similar effect to what the old ``using`` statement tried to achieve. - Typeless parameters have been removed from the language since it would clash with ``using``. +- Procedures in ``mersenne.nim`` (Mersenne Twister implementation) no longer + accept and produce ``int`` values which have platform-dependent size - + they use ``uint32`` instead. Library Additions From 25f93309285147f8e1ee72a8da09359a197558a5 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Fri, 25 Mar 2016 20:54:01 +0800 Subject: [PATCH 015/674] store block size in when using malloc and nogc this allows for a correct implementation of realloc, which is needed as code using it assumes new values will be zeroed out / nil --- lib/system/mmdisp.nim | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 4b01cf4a87..76c1b476e1 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -389,15 +389,30 @@ elif defined(nogc) and defined(useMalloc): when not defined(useNimRtl): proc alloc(size: Natural): pointer = - result = cmalloc(size) - if result == nil: raiseOutOfMem() + var x = cmalloc(size + sizeof(size)) + if x == nil: raiseOutOfMem() + + cast[ptr int](x)[] = size + result = cast[pointer](cast[int](x) + sizeof(size)) + proc alloc0(size: Natural): pointer = result = alloc(size) zeroMem(result, size) proc realloc(p: pointer, newsize: Natural): pointer = - result = crealloc(p, newsize) - if result == nil: raiseOutOfMem() - proc dealloc(p: pointer) = cfree(p) + var x = cast[pointer](cast[int](p) - sizeof(newsize)) + let oldsize = cast[ptr int](x)[] + + x = crealloc(x, newsize + sizeof(newsize)) + + if x == nil: raiseOutOfMem() + + cast[ptr int](x)[] = newsize + result = cast[pointer](cast[int](x) + sizeof(newsize)) + + if newsize > oldsize: + zeroMem(cast[pointer](cast[int](result) + oldsize), newsize - oldsize) + + proc dealloc(p: pointer) = cfree(cast[pointer](cast[int](p) - sizeof(int))) proc allocShared(size: Natural): pointer = result = cmalloc(size) From f1f1202ea056f4b22d955f8a91fd5f591ff50559 Mon Sep 17 00:00:00 2001 From: Felix Krause Date: Tue, 29 Mar 2016 22:48:34 +0200 Subject: [PATCH 016/674] Added YAML support to doctools/highlite --- lib/packages/docutils/highlite.nim | 298 ++++++++++++++++++++++++++++- 1 file changed, 296 insertions(+), 2 deletions(-) diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim index 1bc0af1b63..488b855450 100644 --- a/lib/packages/docutils/highlite.nim +++ b/lib/packages/docutils/highlite.nim @@ -31,13 +31,14 @@ type state: TokenClass SourceLanguage* = enum - langNone, langNim, langNimrod, langCpp, langCsharp, langC, langJava + langNone, langNim, langNimrod, langCpp, langCsharp, langC, langJava, + langYaml {.deprecated: [TSourceLanguage: SourceLanguage, TTokenClass: TokenClass, TGeneralTokenizer: GeneralTokenizer].} const sourceLanguageToStr*: array[SourceLanguage, string] = ["none", - "Nim", "Nimrod", "C++", "C#", "C", "Java"] + "Nim", "Nimrod", "C++", "C#", "C", "Java", "Yaml"] tokenClassToStr*: array[TokenClass, string] = ["Eof", "None", "Whitespace", "DecNumber", "BinNumber", "HexNumber", "OctNumber", "FloatNumber", "Identifier", "Keyword", "StringLit", "LongStringLit", "CharLit", @@ -578,6 +579,298 @@ proc javaNextToken(g: var GeneralTokenizer) = "try", "void", "volatile", "while"] clikeNextToken(g, keywords, {}) +proc yamlPlainStrLit(g: var GeneralTokenizer, pos: var int) = + g.kind = gtStringLit + while g.buf[pos] notin {'\0', '\x09'..'\x0D', ',', ']', '}'}: + if g.buf[pos] == ':' and + g.buf[pos + 1] in {'\0', '\x09'..'\x0D', ' '}: + break + inc(pos) + +proc yamlPossibleNumber(g: var GeneralTokenizer, pos: var int) = + g.kind = gtNone + if g.buf[pos] == '-': inc(pos) + if g.buf[pos] == '0': + inc(pos) + elif g.buf[pos] in '1'..'9': + inc(pos) + while g.buf[pos] in {'0'..'9'}: inc(pos) + else: yamlPlainStrLit(g, pos) + if g.kind == gtNone: + if g.buf[pos] in {'\0', '\x09'..'\x0D', ' '}: g.kind = gtDecNumber + elif g.buf[pos] == '.': + inc(pos) + if g.buf[pos] notin {'0'..'9'}: yamlPlainStrLit(g, pos) + else: + while g.buf[pos] in {'0'..'9'}: inc(pos) + if g.buf[pos] in {'\0', '\x09'..'\x0D', ' '}: g.kind = gtFloatNumber + if g.kind == gtNone: + if g.buf[pos] in {'e', 'E'}: + inc(pos) + if g.buf[pos] in {'-', '+'}: inc(pos) + if g.buf[pos] notin {'0'..'9'}: yamlPlainStrLit(g, pos) + else: + while g.buf[pos] in {'0'..'9'}: inc(pos) + if g.buf[pos] in {'\0', '\x09'..'\x0D', ' '}: g.kind = gtFloatNumber + else: yamlPlainStrLit(g, pos) + else: yamlPlainStrLit(g, pos) + +proc yamlNextToken(g: var GeneralTokenizer) = + const + hexChars = {'0'..'9', 'A'..'F', 'a'..'f'} + var pos = g.pos + g.start = g.pos + if g.state == gtStringLit: + g.kind = gtStringLit + while true: + case g.buf[pos] + of '\\': + if pos != g.pos: break + g.kind = gtEscapeSequence + inc(pos) + case g.buf[pos] + of 'x': + inc(pos) + for i in 1..2: + {.unroll.} + if g.buf[pos] in hexChars: inc(pos) + break + of 'u': + inc(pos) + for i in 1..4: + {.unroll.} + if g.buf[pos] in hexChars: inc(pos) + break + of 'U': + inc(pos) + for i in 1..8: + {.unroll.} + if g.buf[pos] in hexChars: inc(pos) + break + else: inc(pos) + break + of '\0': + g.state = gtOther + break + of '\"': + inc(pos) + g.state = gtOther + break + else: inc(pos) + elif g.state == gtCharLit: + # abusing gtCharLit as single-quoted string lit + g.kind = gtStringLit + while true: + case g.buf[pos] + of '\'': + inc(pos) + if g.buf[pos] == '\'': + inc(pos) + g.kind = gtEscapeSequence + else: g.state = gtOther + break + else: inc(pos) + elif g.state == gtCommand: + # gtCommand means 'block scalar header' + case g.buf[pos] + of ' ', '\t': + g.kind = gtWhitespace + while g.buf[pos] in {' ', '\t'}: inc(pos) + of '#': + g.kind = gtComment + while g.buf[pos] notin {'\0', '\x0A', '\x0D'}: inc(pos) + of '\x0A', '\x0D': discard + else: + # illegal here. just don't parse a block scalar + g.kind = gtNone + g.state = gtOther + if g.buf[pos] in {'\x0A', '\x0D'} and g.state == gtCommand: + g.state = gtLongStringLit + elif g.state == gtLongStringLit: + # beware, this is the only token where we actually have to parse + # indentation. + + g.kind = gtLongStringLit + # first, we have to find the parent indentation of the block scalar, so that + # we know when to stop + assert g.buf[pos] in {'\x0A', '\x0D'} + var lookbehind = pos - 1 + var headerStart = -1 + while lookbehind >= 0 and g.buf[lookbehind] notin {'\x0A', '\x0D'}: + if headerStart == -1 and g.buf[lookbehind] in {'|', '>'}: + headerStart = lookbehind + dec(lookbehind) + assert headerStart != -1 + var indentation = 1 + while g.buf[lookbehind + indentation] == ' ': inc(indentation) + if g.buf[lookbehind + indentation] in {'|', '>'}: + # when the header is alone in a line, this line does not show the parent's + # indentation, so we must go further. search the first previous line with + # non-whitespace content. + while lookbehind >= 0 and g.buf[lookbehind] in {'\x0A', '\x0D'}: + dec(lookbehind) + while lookbehind >= 0 and + g.buf[lookbehind] in {' ', '\t'}: dec(lookbehind) + # now, find the beginning of the line... + while lookbehind >= 0 and g.buf[lookbehind] notin {'\x0A', '\x0D'}: + dec(lookbehind) + # ... and its indentation + indentation = 1 + while g.buf[lookbehind + indentation] == ' ': inc(indentation) + if lookbehind == -1: indentation = 0 # top level + elif g.buf[lookbehind + 1] == '-' and g.buf[lookbehind + 2] == '-' and + g.buf[lookbehind + 3] == '-' and + g.buf[lookbehind + 4] in {'\x09'..'\x0D', ' '}: + # this is a document start, therefore, we are at top level + indentation = 0 + # because lookbehind was at newline char when calculating indentation, we're + # off by one. fix that. top level's parent will have indentation of -1. + let parentIndentation = indentation - 1 + + # find first content + while g.buf[pos] in {' ', '\x0A', '\x0D'}: + if g.buf[pos] == ' ': inc(indentation) + else: indentation = 0 + inc(pos) + var minIndentation = indentation + + # for stupid edge cases, we must check whether an explicit indentation depth + # is given at the header. + while g.buf[headerStart] in {'>', '|', '+', '-'}: inc(headerStart) + if g.buf[headerStart] in {'0'..'9'}: + minIndentation = min(minIndentation, ord(g.buf[headerStart]) - ord('0')) + + # process content lines + while indentation > parentIndentation and g.buf[pos] != '\0': + if (indentation < minIndentation and g.buf[pos] == '#') or + (indentation == 0 and g.buf[pos] == '.' and g.buf[pos + 1] == '.' and + g.buf[pos + 2] == '.' and + g.buf[pos + 3] in {'\0', '\x09'..'\x0D', ' '}): + # comment after end of block scalar, or end of document + break + minIndentation = min(indentation, minIndentation) + while g.buf[pos] notin {'\0', '\x0A', '\x0D'}: inc(pos) + while g.buf[pos] in {' ', '\x0A', '\x0D'}: + if g.buf[pos] == ' ': inc(indentation) + else: indentation = 0 + inc(pos) + + g.state = gtOther + elif g.state == gtOther: + # gtOther means 'inside YAML document' + case g.buf[pos] + of ' ', '\x09'..'\x0D': + g.kind = gtWhitespace + while g.buf[pos] in {' ', '\x09'..'\x0D'}: inc(pos) + of '#': + g.kind = gtComment + inc(pos) + while g.buf[pos] notin {'\0', '\x0A', '\x0D'}: inc(pos) + of '-': + inc(pos) + if g.buf[pos] in {'\0', ' ', '\x09'..'\x0D'}: + g.kind = gtPunctuation + elif g.buf[pos] == '-' and + (pos == 1 or g.buf[pos - 2] in {'\x0A', '\x0D'}): # start of line + inc(pos) + if g.buf[pos] == '-' and g.buf[pos + 1] in {'\0', '\x09'..'\x0D', ' '}: + inc(pos) + g.kind = gtKeyword + else: yamlPossibleNumber(g, pos) + else: yamlPossibleNumber(g, pos) + of '.': + if pos == 0 or g.buf[pos - 1] in {'\x0A', '\x0D'}: + inc(pos) + for i in 1..2: + {.unroll.} + if g.buf[pos] != '.': break + inc(pos) + if pos == g.start + 3: + g.kind = gtKeyword + g.state = gtNone + else: yamlPlainStrLit(g, pos) + else: yamlPlainStrLit(g, pos) + of '?': + inc(pos) + if g.buf[pos] in {'\0', ' ', '\x09'..'\x0D'}: + g.kind = gtPunctuation + else: yamlPlainStrLit(g, pos) + of ':': + inc(pos) + if g.buf[pos] in {'\0', '\x09'..'\x0D', ' ', '\'', '\"'} or + (pos > 0 and g.buf[pos - 2] in {'}', ']', '\"', '\''}): + g.kind = gtPunctuation + else: yamlPlainStrLit(g, pos) + of '[', ']', '{', '}', ',': + inc(pos) + g.kind = gtPunctuation + of '\"': + inc(pos) + g.state = gtStringLit + g.kind = gtNone + of '\'': + inc(pos) + g.state = gtCharLit + g.kind = gtNone + of '!': + g.kind = gtTagStart + inc(pos) + if g.buf[pos] == '<': + # literal tag (e.g. `!`) + while g.buf[pos] notin {'\0', '>', '\x09'..'\x0D', ' '}: inc(pos) + if g.buf[pos] == '>': inc(pos) + else: + while g.buf[pos] in {'A'..'Z', 'a'..'z', '0'..'9', '-'}: inc(pos) + case g.buf[pos] + of '!': + # prefixed tag (e.g. `!!str`) + inc(pos) + while g.buf[pos] notin + {'\0', '\x09'..'\x0D', ' ', ',', '[', ']', '{', '}'}: inc(pos) + of '\0', '\x09'..'\x0D', ' ': discard + else: + # local tag (e.g. `!nim:system:int`) + while g.buf[pos] notin {'\0', '\x09'..'\x0D', ' '}: inc(pos) + of '&': + g.kind = gtLabel + while g.buf[pos] notin {'\0', '\x09'..'\x0D', ' '}: inc(pos) + of '*': + g.kind = gtReference + while g.buf[pos] notin {'\0', '\x09'..'\x0D', ' '}: inc(pos) + of '|', '>': + # this can lead to incorrect tokenization when | or > appear inside flow + # content. checking whether we're inside flow content is not + # chomsky type-3, so we won't do that here. + g.kind = gtCommand + g.state = gtCommand + inc(pos) + while g.buf[pos] in {'0'..'9', '+', '-'}: inc(pos) + of '0'..'9': yamlPossibleNumber(g, pos) + of '\0': g.kind = gtEOF + else: yamlPlainStrLit(g, pos) + else: + # outside document + case g.buf[pos] + of '%': + if pos == 0 or g.buf[pos - 1] in {'\x0A', '\x0D'}: + g.kind = gtDirective + while g.buf[pos] notin {'\0', '\x0A', '\x0D'}: inc(pos) + else: + g.state = gtOther + yamlPlainStrLit(g, pos) + of ' ', '\x09'..'\x0D': + g.kind = gtWhitespace + while g.buf[pos] in {' ', '\x09'..'\x0D'}: inc(pos) + of '#': + g.kind = gtComment + while g.buf[pos] notin {'\0', '\x0A', '\x0D'}: inc(pos) + of '\0': g.kind = gtEOF + else: + g.kind = gtNone + g.state = gtOther + g.length = pos - g.pos + g.pos = pos + proc getNextToken*(g: var GeneralTokenizer, lang: SourceLanguage) = case lang of langNone: assert false @@ -586,6 +879,7 @@ proc getNextToken*(g: var GeneralTokenizer, lang: SourceLanguage) = of langCsharp: csharpNextToken(g) of langC: cNextToken(g) of langJava: javaNextToken(g) + of langYaml: yamlNextToken(g) when isMainModule: var keywords: seq[string] From 9aa845c6b677dc1a01533dcf02e29acb971a13ee Mon Sep 17 00:00:00 2001 From: Anatoly Galiulin Date: Wed, 30 Mar 2016 17:34:41 +0600 Subject: [PATCH 017/674] Add parseUInt and parseBiggestUInt functions to stdlib (parseutils, strutils) --- lib/pure/parseutils.nim | 51 ++++++++++++++++++++++++++++++++++++ lib/pure/strutils.nim | 18 +++++++++++++ tests/stdlib/tparseuints.nim | 11 ++++++++ 3 files changed, 80 insertions(+) create mode 100644 tests/stdlib/tparseuints.nim diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index 698bde42a5..66bdadb294 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -234,6 +234,57 @@ proc parseInt*(s: string, number: var int, start = 0): int {. elif result != 0: number = int(res) +# overflowChecks doesn't work with uint64 +proc rawParseUInt(s: string, b: var uint64, start = 0): int = + var + res = 0'u64 + prev = 0'u64 + i = start + if s[i] == '+': inc(i) # Allow + if s[i] in {'0'..'9'}: + b = 0 + while s[i] in {'0'..'9'}: + prev = res + res = res * 10 + (ord(s[i]) - ord('0')).uint64 + if prev > res: + return 0 # overflowChecks emulation + inc(i) + while s[i] == '_': inc(i) # underscores are allowed and ignored + b = res + result = i - start + +proc parseBiggestUInt*(s: string, number: var uint64, start = 0): int {. + rtl, extern: "npuParseBiggestUInt", noSideEffect.} = + ## parses an unsigned integer starting at `start` and stores the value into `number`. + ## Result is the number of processed chars or 0 if there is no integer or overflow detected. + var res: uint64 + # use 'res' for exception safety (don't write to 'number' in case of an + # overflow exception): + result = rawParseUInt(s, res, start) + number = res + +# Workaround for high(uint) +proc highUInt(): uint64 = + when sizeof(uint) == 4: + 0xFFFFFFFF'u64 + elif sizeof(uint) == 8: + 0xFFFFFFFFFFFFFFFF'u64 + else: + {.fatal: "Unknoun uint size: " & $sizeof(uint).} + +proc parseUInt*(s: string, number: var uint, start = 0): int {. + rtl, extern: "npuParseUInt", noSideEffect.} = + ## parses an unsigned integer starting at `start` and stores the value into `number`. + ## Result is the number of processed chars or 0 if there is no integer. + ## Result is the number of processed chars or 0 if there is no integer or overflow detected. + var res: uint64 + result = parseBiggestUInt(s, res, start) + if (sizeof(uint) <= 4) and + (res > highUInt()): + raise newException(OverflowError, "overflow") + elif result != 0: + number = uint(res) + proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {. magic: "ParseBiggestFloat", importc: "nimParseBiggestFloat", noSideEffect.} ## parses a float starting at `start` and stores the value into `number`. diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index f2c1e77e18..eebadf4c03 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -560,6 +560,24 @@ proc parseBiggestInt*(s: string): BiggestInt {.noSideEffect, procvar, if L != s.len or L == 0: raise newException(ValueError, "invalid integer: " & s) +proc parseUInt*(s: string): uint {.noSideEffect, procvar, + rtl, extern: "nsuParseUInt".} = + ## Parses a decimal unsigned integer value contained in `s`. + ## + ## If `s` is not a valid integer, `ValueError` is raised. + var L = parseutils.parseUInt(s, result, 0) + if L != s.len or L == 0: + raise newException(ValueError, "invalid unsigned integer: " & s) + +proc parseBiggestUInt*(s: string): uint64 {.noSideEffect, procvar, + rtl, extern: "nsuParseBiggestUInt".} = + ## Parses a decimal unsigned integer value contained in `s`. + ## + ## If `s` is not a valid integer, `ValueError` is raised. + var L = parseutils.parseBiggestUInt(s, result, 0) + if L != s.len or L == 0: + raise newException(ValueError, "invalid unsigned integer: " & s) + proc parseFloat*(s: string): float {.noSideEffect, procvar, rtl, extern: "nsuParseFloat".} = ## Parses a decimal floating point value contained in `s`. If `s` is not diff --git a/tests/stdlib/tparseuints.nim b/tests/stdlib/tparseuints.nim new file mode 100644 index 0000000000..5be3bcbd00 --- /dev/null +++ b/tests/stdlib/tparseuints.nim @@ -0,0 +1,11 @@ +discard """ + action: run +""" +import unittest, strutils + +suite "parseutils": + test "uint": + check: parseBiggestUInt("0") == 0'u64 + check: parseBiggestUInt("18446744073709551615") == 0xFFFF_FFFF_FFFF_FFFF'u64 + expect(ValueError): + discard parseBiggestUInt("18446744073709551616") From 266ea783e8e6502eda5c7d81b9af9a97caa77e95 Mon Sep 17 00:00:00 2001 From: cheatfate Date: Thu, 31 Mar 2016 00:43:56 +0300 Subject: [PATCH 018/674] Make windows locks do not use dyncall --- lib/system/syslocks.nim | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim index 6dcdfff0d9..8afd5d201c 100644 --- a/lib/system/syslocks.nim +++ b/lib/system/syslocks.nim @@ -14,39 +14,41 @@ when defined(Windows): type Handle = int - SysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi + + SysLock {.importc: "CRITICAL_SECTION", + header: "", final, pure.} = object # CRITICAL_SECTION in WinApi DebugInfo: pointer LockCount: int32 RecursionCount: int32 OwningThread: int LockSemaphore: int - Reserved: int32 + SpinCount: int SysCond = Handle {.deprecated: [THandle: Handle, TSysLock: SysLock, TSysCond: SysCond].} - proc initSysLock(L: var SysLock) {.stdcall, noSideEffect, - dynlib: "kernel32", importc: "InitializeCriticalSection".} + proc initSysLock(L: var SysLock) {.importc: "InitializeCriticalSection", + header: "".} ## Initializes the lock `L`. - proc tryAcquireSysAux(L: var SysLock): int32 {.stdcall, noSideEffect, - dynlib: "kernel32", importc: "TryEnterCriticalSection".} + proc tryAcquireSysAux(L: var SysLock): int32 {.importc: "TryEnterCriticalSection", + header: "".} ## Tries to acquire the lock `L`. proc tryAcquireSys(L: var SysLock): bool {.inline.} = result = tryAcquireSysAux(L) != 0'i32 - proc acquireSys(L: var SysLock) {.stdcall, noSideEffect, - dynlib: "kernel32", importc: "EnterCriticalSection".} + proc acquireSys(L: var SysLock) {.importc: "EnterCriticalSection", + header: "".} ## Acquires the lock `L`. - proc releaseSys(L: var SysLock) {.stdcall, noSideEffect, - dynlib: "kernel32", importc: "LeaveCriticalSection".} + proc releaseSys(L: var SysLock) {.importc: "LeaveCriticalSection", + header: "".} ## Releases the lock `L`. - proc deinitSys(L: var SysLock) {.stdcall, noSideEffect, - dynlib: "kernel32", importc: "DeleteCriticalSection".} + proc deinitSys(L: var SysLock) {.importc: "DeleteCriticalSection", + header: "".} proc createEvent(lpEventAttributes: pointer, bManualReset, bInitialState: int32, From 40f4fe997f73176cc2d8bab755c37c90196a046e Mon Sep 17 00:00:00 2001 From: cheatfate Date: Thu, 31 Mar 2016 02:39:53 +0300 Subject: [PATCH 019/674] Replace csprintf() in windows version of nimGetProcAddr to pure nim's implementation, to avoid possible overflow. --- lib/system/dyncalls.nim | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim index 3b3d1f87d9..61777e514e 100644 --- a/lib/system/dyncalls.nim +++ b/lib/system/dyncalls.nim @@ -109,9 +109,30 @@ elif defined(windows) or defined(dos): proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr = result = getProcAddress(cast[THINSTANCE](lib), name) if result != nil: return - var decorated: array[250, char] + const decorated_length = 250 + var decorated: array[decorated_length, char] + decorated[0] = '_' + var m = 1 + while m < (decorated_length - 5): + if name[m - 1] == '\x00': break + decorated[m] = name[m - 1] + inc(m) + decorated[m] = '@' for i in countup(0, 50): - discard csprintf(decorated, "_%s@%ld", name, i*4) + var k = i * 4 + if k div 100 == 0: + if k div 10 == 0: + m = m + 1 + else: + m = m + 2 + else: + m = m + 3 + decorated[m + 1] = '\x00' + while true: + decorated[m] = chr(ord('0') + (k %% 10)) + dec(m) + k = k div 10 + if k == 0: break result = getProcAddress(cast[THINSTANCE](lib), decorated) if result != nil: return procAddrError(name) From f0c19e9e6729a489a2030dffac6409e915b0df6e Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 31 Mar 2016 02:11:22 +0200 Subject: [PATCH 020/674] fixes a critical codegen bug that keeps PR #4017 from working --- compiler/cgen.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index db376821c0..4f27a5a460 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1059,9 +1059,8 @@ proc genModule(m: BModule, cfile: string): Rope = result = getFileHeader(cfile) result.add(genMergeInfo(m)) - generateHeaders(m) - generateThreadLocalStorage(m) + generateHeaders(m) for i in countup(cfsHeaders, cfsProcs): add(result, genSectionStart(i)) add(result, m.s[i]) From c34a68d76f7f552b235592da7634acc333275df9 Mon Sep 17 00:00:00 2001 From: Anatoly Galiulin Date: Thu, 31 Mar 2016 10:51:40 +0600 Subject: [PATCH 021/674] Remove dead code --- lib/pure/parseutils.nim | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index 66bdadb294..3e25eba222 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -263,24 +263,14 @@ proc parseBiggestUInt*(s: string, number: var uint64, start = 0): int {. result = rawParseUInt(s, res, start) number = res -# Workaround for high(uint) -proc highUInt(): uint64 = - when sizeof(uint) == 4: - 0xFFFFFFFF'u64 - elif sizeof(uint) == 8: - 0xFFFFFFFFFFFFFFFF'u64 - else: - {.fatal: "Unknoun uint size: " & $sizeof(uint).} - proc parseUInt*(s: string, number: var uint, start = 0): int {. rtl, extern: "npuParseUInt", noSideEffect.} = ## parses an unsigned integer starting at `start` and stores the value into `number`. - ## Result is the number of processed chars or 0 if there is no integer. ## Result is the number of processed chars or 0 if there is no integer or overflow detected. var res: uint64 result = parseBiggestUInt(s, res, start) if (sizeof(uint) <= 4) and - (res > highUInt()): + (res > 0xFFFF_FFFF'u64): raise newException(OverflowError, "overflow") elif result != 0: number = uint(res) From ebc02f6dc0dd15f0ec34a8c0f22432ca49c71c5b Mon Sep 17 00:00:00 2001 From: Anatoly Galiulin Date: Fri, 25 Mar 2016 16:41:48 +0600 Subject: [PATCH 022/674] Fix ``XDeclaredButNotUsed`` warning when locks or rlocks module is used --- lib/core/locks.nim | 2 +- lib/core/rlocks.nim | 1 + lib/system.nim | 20 ++++++++++---------- lib/system/syslocks.nim | 35 ++++++++++++++++------------------- 4 files changed, 28 insertions(+), 30 deletions(-) diff --git a/lib/core/locks.nim b/lib/core/locks.nim index 66e0ab5208..068e7133ca 100644 --- a/lib/core/locks.nim +++ b/lib/core/locks.nim @@ -63,4 +63,4 @@ template withLock*(a: Lock, body: untyped) = try: body finally: - a.release() \ No newline at end of file + a.release() diff --git a/lib/core/rlocks.nim b/lib/core/rlocks.nim index 14f04592be..4710d6cf13 100644 --- a/lib/core/rlocks.nim +++ b/lib/core/rlocks.nim @@ -9,6 +9,7 @@ ## This module contains Nim's support for reentrant locks. +const insideRLocksModule = true include "system/syslocks" type diff --git a/lib/system.nim b/lib/system.nim index fefabe53f3..03b9e158aa 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2561,6 +2561,16 @@ else: if x < 0: -x else: x {.pop.} +proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect, compileTime.} = + ## Special compile-time procedure that checks whether `x` can be compiled + ## without any semantic error. + ## This can be used to check whether a type supports some operation: + ## + ## .. code-block:: Nim + ## when not compiles(3 + 4): + ## echo "'+' for integers is available" + discard + when not defined(JS): #and not defined(nimscript): {.push stack_trace: off, profiler:off.} @@ -3469,16 +3479,6 @@ when hasAlloc: x[j+i] = item[j] inc(j) -proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect, compileTime.} = - ## Special compile-time procedure that checks whether `x` can be compiled - ## without any semantic error. - ## This can be used to check whether a type supports some operation: - ## - ## .. code-block:: Nim - ## when not compiles(3 + 4): - ## echo "'+' for integers is available" - discard - when declared(initDebugger): initDebugger() diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim index 8afd5d201c..07f6fe1677 100644 --- a/lib/system/syslocks.nim +++ b/lib/system/syslocks.nim @@ -88,17 +88,16 @@ else: #include """.} = object SysLockType = distinct cint - proc SysLockType_Reentrant: SysLockType = - {.emit: "`result` = PTHREAD_MUTEX_RECURSIVE;".} - proc initSysLock(L: var SysLock, attr: ptr SysLockAttr = nil) {. importc: "pthread_mutex_init", header: "", noSideEffect.} - proc initSysLockAttr(a: var SysLockAttr) {. - importc: "pthread_mutexattr_init", header: "", noSideEffect.} - - proc setSysLockType(a: var SysLockAttr, t: SysLockType) {. - importc: "pthread_mutexattr_settype", header: "", noSideEffect.} + when compiles(insideRLocksModule): + proc SysLockType_Reentrant: SysLockType = + {.emit: "`result` = PTHREAD_MUTEX_RECURSIVE;".} + proc initSysLockAttr(a: var SysLockAttr) {. + importc: "pthread_mutexattr_init", header: "", noSideEffect.} + proc setSysLockType(a: var SysLockAttr, t: SysLockType) {. + importc: "pthread_mutexattr_settype", header: "", noSideEffect.} proc acquireSys(L: var SysLock) {.noSideEffect, importc: "pthread_mutex_lock", header: "".} @@ -113,14 +112,12 @@ else: proc deinitSys(L: var SysLock) {.noSideEffect, importc: "pthread_mutex_destroy", header: "".} - proc initSysCond(cond: var SysCond, cond_attr: pointer = nil) {. - importc: "pthread_cond_init", header: "", noSideEffect.} - proc waitSysCond(cond: var SysCond, lock: var SysLock) {. - importc: "pthread_cond_wait", header: "", noSideEffect.} - proc signalSysCond(cond: var SysCond) {. - importc: "pthread_cond_signal", header: "", noSideEffect.} - - proc deinitSysCond(cond: var SysCond) {.noSideEffect, - importc: "pthread_cond_destroy", header: "".} - -{.pop.} + when not compiles(insideRLocksModule): + proc initSysCond(cond: var SysCond, cond_attr: pointer = nil) {. + importc: "pthread_cond_init", header: "", noSideEffect.} + proc waitSysCond(cond: var SysCond, lock: var SysLock) {. + importc: "pthread_cond_wait", header: "", noSideEffect.} + proc signalSysCond(cond: var SysCond) {. + importc: "pthread_cond_signal", header: "", noSideEffect.} + proc deinitSysCond(cond: var SysCond) {.noSideEffect, + importc: "pthread_cond_destroy", header: "".} From 45bbecb0211d18b425c7736f803dde2acef79311 Mon Sep 17 00:00:00 2001 From: Anatoly Galiulin Date: Wed, 30 Mar 2016 08:35:14 +0600 Subject: [PATCH 023/674] Use ``when insideRLocksModule`` instead of ``when compiles`` --- lib/core/locks.nim | 1 + lib/system.nim | 1 + lib/system/syslocks.nim | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/core/locks.nim b/lib/core/locks.nim index 068e7133ca..fbe9c8acfc 100644 --- a/lib/core/locks.nim +++ b/lib/core/locks.nim @@ -9,6 +9,7 @@ ## This module contains Nim's support for locks and condition vars. +const insideRLocksModule = false include "system/syslocks" type diff --git a/lib/system.nim b/lib/system.nim index 03b9e158aa..bcb55fe487 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2884,6 +2884,7 @@ when not defined(JS): #and not defined(nimscript): when declared(initAllocator): initAllocator() when hasThreadSupport: + const insideRLocksModule = false include "system/syslocks" when hostOS != "standalone": include "system/threads" elif not defined(nogc) and not defined(nimscript): diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim index 07f6fe1677..1695deca13 100644 --- a/lib/system/syslocks.nim +++ b/lib/system/syslocks.nim @@ -91,7 +91,7 @@ else: proc initSysLock(L: var SysLock, attr: ptr SysLockAttr = nil) {. importc: "pthread_mutex_init", header: "", noSideEffect.} - when compiles(insideRLocksModule): + when insideRLocksModule: proc SysLockType_Reentrant: SysLockType = {.emit: "`result` = PTHREAD_MUTEX_RECURSIVE;".} proc initSysLockAttr(a: var SysLockAttr) {. @@ -112,7 +112,7 @@ else: proc deinitSys(L: var SysLock) {.noSideEffect, importc: "pthread_mutex_destroy", header: "".} - when not compiles(insideRLocksModule): + when not insideRLocksModule: proc initSysCond(cond: var SysCond, cond_attr: pointer = nil) {. importc: "pthread_cond_init", header: "", noSideEffect.} proc waitSysCond(cond: var SysCond, lock: var SysLock) {. From a9330391c34aa941e895a33a909b2f08ba59f60b Mon Sep 17 00:00:00 2001 From: Anatoly Galiulin Date: Thu, 31 Mar 2016 16:45:54 +0600 Subject: [PATCH 024/674] Move ``compiles`` back --- lib/system.nim | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index bcb55fe487..56210f5dc1 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2561,16 +2561,6 @@ else: if x < 0: -x else: x {.pop.} -proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect, compileTime.} = - ## Special compile-time procedure that checks whether `x` can be compiled - ## without any semantic error. - ## This can be used to check whether a type supports some operation: - ## - ## .. code-block:: Nim - ## when not compiles(3 + 4): - ## echo "'+' for integers is available" - discard - when not defined(JS): #and not defined(nimscript): {.push stack_trace: off, profiler:off.} @@ -3480,6 +3470,16 @@ when hasAlloc: x[j+i] = item[j] inc(j) +proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect, compileTime.} = + ## Special compile-time procedure that checks whether `x` can be compiled + ## without any semantic error. + ## This can be used to check whether a type supports some operation: + ## + ## .. code-block:: Nim + ## when not compiles(3 + 4): + ## echo "'+' for integers is available" + discard + when declared(initDebugger): initDebugger() From a61d5e466beb8dc5efeb4a96511c8162fe16f38c Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 31 Mar 2016 16:49:46 +0200 Subject: [PATCH 025/674] added missing file for --gc:stack --- lib/pure/collections/chains.nim | 44 +++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 lib/pure/collections/chains.nim diff --git a/lib/pure/collections/chains.nim b/lib/pure/collections/chains.nim new file mode 100644 index 0000000000..6b2ecd2722 --- /dev/null +++ b/lib/pure/collections/chains.nim @@ -0,0 +1,44 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2016 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Template based implementation of singly and doubly linked lists. +## The involved types should have 'prev' or 'next' fields and the +## list header should have 'head' or 'tail' fields. + +template prepend*(header, node) = + when compiles(header.head): + when compiles(node.prev): + if header.head != nil: + header.head.prev = node + node.next = header.head + header.head = node + when compiles(header.tail): + if header.tail == nil: + header.tail = node + +template append*(header, node) = + when compiles(header.head): + if header.head == nil: + header.head = node + when compiles(header.tail): + when compiles(node.prev): + node.prev = header.tail + if header.tail != nil: + header.tail.next = node + header.tail = node + +template unlink*(header, node) = + if node.next != nil: + node.next.prev = node.prev + if node.prev != nil: + node.prev.next = node.next + if header.head == node: + header.head = node.prev + if header.tail == node: + header.tail = node.next From 63807a62c6754e58c33b34dfbda84fdc56f0992c Mon Sep 17 00:00:00 2001 From: Joshua Olson <0joshua.olson1@gmail.com> Date: Fri, 1 Apr 2016 01:06:45 -0600 Subject: [PATCH 026/674] triggering yourself -> yourself triggering adverbs --- doc/backends.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/backends.txt b/doc/backends.txt index c7939baec9..343af09ed6 100644 --- a/doc/backends.txt +++ b/doc/backends.txt @@ -420,7 +420,7 @@ function directly will be able to use it since Nim's garbage collector has not had a chance to run *yet*. This gives you enough time to make a copy for the C side of the program, as calling any further Nim procs *might* trigger garbage collection making the previously returned string garbage. Or maybe you -are `triggering yourself the collection `_. +are `yourself triggering the collection `_. Custom data types From 6fe916fc77c717700dd47451c498e5c99928ba63 Mon Sep 17 00:00:00 2001 From: Felix Krause Date: Fri, 1 Apr 2016 21:35:46 +0200 Subject: [PATCH 027/674] Fixes to YAML highlighting support, added tests --- lib/packages/docutils/highlite.nim | 25 ++++-- tests/stdlib/trstgen.nim | 139 +++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+), 7 deletions(-) create mode 100644 tests/stdlib/trstgen.nim diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim index 488b855450..9de25f82b4 100644 --- a/lib/packages/docutils/highlite.nim +++ b/lib/packages/docutils/highlite.nim @@ -590,20 +590,21 @@ proc yamlPlainStrLit(g: var GeneralTokenizer, pos: var int) = proc yamlPossibleNumber(g: var GeneralTokenizer, pos: var int) = g.kind = gtNone if g.buf[pos] == '-': inc(pos) - if g.buf[pos] == '0': - inc(pos) + if g.buf[pos] == '0': inc(pos) elif g.buf[pos] in '1'..'9': inc(pos) while g.buf[pos] in {'0'..'9'}: inc(pos) else: yamlPlainStrLit(g, pos) if g.kind == gtNone: - if g.buf[pos] in {'\0', '\x09'..'\x0D', ' '}: g.kind = gtDecNumber + if g.buf[pos] in {'\0', '\x09'..'\x0D', ' ', ',', ']', '}'}: + g.kind = gtDecNumber elif g.buf[pos] == '.': inc(pos) if g.buf[pos] notin {'0'..'9'}: yamlPlainStrLit(g, pos) else: while g.buf[pos] in {'0'..'9'}: inc(pos) - if g.buf[pos] in {'\0', '\x09'..'\x0D', ' '}: g.kind = gtFloatNumber + if g.buf[pos] in {'\0', '\x09'..'\x0D', ' ', ',', ']', '}'}: + g.kind = gtFloatNumber if g.kind == gtNone: if g.buf[pos] in {'e', 'E'}: inc(pos) @@ -611,9 +612,19 @@ proc yamlPossibleNumber(g: var GeneralTokenizer, pos: var int) = if g.buf[pos] notin {'0'..'9'}: yamlPlainStrLit(g, pos) else: while g.buf[pos] in {'0'..'9'}: inc(pos) - if g.buf[pos] in {'\0', '\x09'..'\x0D', ' '}: g.kind = gtFloatNumber + if g.buf[pos] in {'\0', '\x09'..'\x0D', ' ', ',', ']', '}'}: + g.kind = gtFloatNumber else: yamlPlainStrLit(g, pos) else: yamlPlainStrLit(g, pos) + while g.buf[pos] notin {'\0', ',', ']', '}', '\x0A', '\x0D'}: + inc(pos) + if g.buf[pos] notin {'\x09'..'\x0D', ' ', ',', ']', '}'}: + yamlPlainStrLit(g, pos) + break + # theoretically, we would need to parse indentation (like with block scalars) + # because of possible multiline flow scalars that start with number-like + # content, but that is far too troublesome. I think it is fine that the + # highlighter is sloppy here. proc yamlNextToken(g: var GeneralTokenizer) = const @@ -660,6 +671,7 @@ proc yamlNextToken(g: var GeneralTokenizer) = elif g.state == gtCharLit: # abusing gtCharLit as single-quoted string lit g.kind = gtStringLit + inc(pos) # skip the starting ' while true: case g.buf[pos] of '\'': @@ -807,9 +819,8 @@ proc yamlNextToken(g: var GeneralTokenizer) = of '\"': inc(pos) g.state = gtStringLit - g.kind = gtNone + g.kind = gtStringLit of '\'': - inc(pos) g.state = gtCharLit g.kind = gtNone of '!': diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim new file mode 100644 index 0000000000..c702ccc2a8 --- /dev/null +++ b/tests/stdlib/trstgen.nim @@ -0,0 +1,139 @@ +# tests for rstgen module. + +import ../../lib/packages/docutils/rstgen +import unittest + +suite "YAML syntax highlighting": + test "Basics": + let input = """.. code-block:: yaml + %YAML 1.2 + --- + a string: string + a list: + - item 1 + - item 2 + a map: + ? key + : value + ...""" + let output = rstTohtml(input, {}, defaultConfig()) + assert output == """
%YAML 1.2
+---
+a string: string
+a list:
+  - item 1
+  - item 2
+a map:
+? key
+: value
+...
""" + + test "Block scalars": + let input = """.. code-block:: yaml + a literal block scalar: | + some text + # not a comment + # a comment, since less indented + # another comment + a folded block scalar: >2 + some text + # not a comment since indented as specified + # a comment + another literal block scalar: + |+ # comment after header + allowed, since more indented than parent""" + let output = rstToHtml(input, {}, defaultConfig()) + assert output == """
a literal block scalar: |
+  some text
+  # not a comment
+ # a comment, since less indented
+  # another comment
+a folded block scalar: >2
+   some text
+  # not a comment since indented as specified
+ # a comment
+another literal block scalar:
+  |+ # comment after header
+ allowed, since more indented than parent
""" + + test "Directives": + let input = """.. code-block:: yaml + %YAML 1.2 + --- + %not a directive + ... + %a directive + ... + a string + % not a directive + ... + %TAG ! !foo:""" + let output = rstToHtml(input, {}, defaultConfig()) + assert output == """
%YAML 1.2
+---
+%not a directive
+...
+%a directive
+...
+a string
+% not a directive
+...
+%TAG ! !foo:
""" + + test "Flow Style and Numbers": + let input = """.. code-block:: yaml + { + "quoted string": 42, + 'single quoted string': false, + [ list, "with", 'entries' ]: 73.32e-73, + more numbers: [-783, 11e78], + not numbers: [ 42e, 0023, +32.37, 8 ball] + }""" + let output = rstToHtml(input, {}, defaultConfig()) + assert output == """
{
+  "quoted string": 42,
+  'single quoted string': false,
+  [ list, "with", 'entries' ]: 73.32e-73,
+  more numbers: [-783, 11e78],
+  not numbers: [ 42e, 0023, +32.37, 8 ball]
+}
""" + + test "Anchors, Aliases, Tags": + let input = """.. code-block:: yaml + --- !!map + !!str string: ! 42 + ? &anchor !!seq []: + : !localtag foo + alias: *anchor + """ + let output = rstToHtml(input, {}, defaultConfig()) + assert output == """
--- !!map
+!!str string: !<tag:yaml.org,2002:int> 42
+? &anchor !!seq []:
+: !localtag foo
+alias: *anchor
""" + + test "Edge cases": + let input = """.. code-block:: yaml + ... + %a string: + a:string:not:a:map + ... + not a list: + -2 + -3 + -4 + example.com/not/a#comment: + ?not a map key + """ + let output = rstToHtml(input, {}, defaultConfig()) + assert output == """
...
+ %a string:
+  a:string:not:a:map
+...
+not a list:
+  -2
+  -3
+  -4
+example.com/not/a#comment:
+  ?not a map key
""" \ No newline at end of file From 0a5a593682130d7b74f16c5ee7546b2757e16d7d Mon Sep 17 00:00:00 2001 From: cheatfate Date: Sat, 2 Apr 2016 02:17:32 +0300 Subject: [PATCH 028/674] Patch timer_create and timer_delete to have proper declaration. --- lib/posix/posix.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index 4c7b817cb0..f1344f20d7 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -2309,9 +2309,9 @@ proc strftime*(a1: cstring, a2: int, a3: cstring, a4: var Tm): int {.importc, header: "".} proc strptime*(a1, a2: cstring, a3: var Tm): cstring {.importc, header: "".} proc time*(a1: var Time): Time {.importc, header: "".} -proc timer_create*(a1: var ClockId, a2: var SigEvent, +proc timer_create*(a1: ClockId, a2: var SigEvent, a3: var Timer): cint {.importc, header: "".} -proc timer_delete*(a1: var Timer): cint {.importc, header: "".} +proc timer_delete*(a1: Timer): cint {.importc, header: "".} proc timer_gettime*(a1: Timer, a2: var Itimerspec): cint {. importc, header: "".} proc timer_getoverrun*(a1: Timer): cint {.importc, header: "".} From a2501321c39a89fb0bad52dcb8ef7c974d4ae5d2 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Sat, 2 Apr 2016 21:15:10 +0800 Subject: [PATCH 029/674] document useMalloc changes --- doc/nimc.txt | 4 +++- web/news.txt | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/nimc.txt b/doc/nimc.txt index e7cb570379..48dbaeb219 100644 --- a/doc/nimc.txt +++ b/doc/nimc.txt @@ -243,7 +243,9 @@ Define Effect ``useFork`` Makes ``osproc`` use ``fork`` instead of ``posix_spawn``. ``useNimRtl`` Compile and link against ``nimrtl.dll``. ``useMalloc`` Makes Nim use C's `malloc`:idx: instead of Nim's - own memory manager. This only works with ``gc:none``. + own memory manager, ableit prefixing each allocation with + its size to support clearing memory on reallocation. + This only works with ``gc:none``. ``useRealtimeGC`` Enables support of Nim's GC for *soft* realtime systems. See the documentation of the `gc `_ for further information. diff --git a/web/news.txt b/web/news.txt index e818ed66e7..f0f17448f6 100644 --- a/web/news.txt +++ b/web/news.txt @@ -20,7 +20,11 @@ Changes affecting backwards compatibility new experimental ``this`` pragma to achieve a similar effect to what the old ``using`` statement tried to achieve. - Typeless parameters have been removed from the language since it would clash with ``using``. - +- When using ``useMalloc``, an additional header containing the size of the + allocation will be allocated, to support zeroing memory on realloc as expected + by the language. With this change, ``alloc`` and ``dealloc`` are no longer + aliases for ``malloc`` and ``free`` - use ``c_malloc`` and ``c_free`` if + you need that. Library Additions ----------------- From 0337bdc8218b40f497ea9d7cfbf56d72d1ef3bc3 Mon Sep 17 00:00:00 2001 From: cheatfate Date: Sun, 3 Apr 2016 15:37:45 +0300 Subject: [PATCH 030/674] Add missed library dependencies on Linux and Solaris. --- lib/posix/posix.nim | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index f1344f20d7..e932d2845a 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -35,6 +35,15 @@ const hasSpawnH = not defined(haiku) # should exist for every Posix system nowadays hasAioH = defined(linux) +when defined(linux): + # On Linux: + # timer_{create,delete,settime,gettime}, + # clock_{getcpuclockid, getres, gettime, nanosleep, settime} lives in librt + {.passL: "-lrt".} +when defined(solaris): + # On Solaris hstrerror lives in libresolv + {.passL: "-lresolv".} + when false: const C_IRUSR = 0c000400 ## Read by owner. From c1c3c4c5d1694af27227915884bbfad6ed78fddb Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Sun, 3 Apr 2016 13:07:47 +0100 Subject: [PATCH 031/674] Add nimscript test and run it in Travis CI --- .travis.yml | 1 + tests/test_nimscript.nims | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100755 tests/test_nimscript.nims diff --git a/.travis.yml b/.travis.yml index f68375e939..f8655f9404 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,7 @@ script: - ./koch boot - ./koch boot -d:release - nim e install_nimble.nims + - nim e tests/test_nimscript.nims - nimble update - nimble install zip - nimble install opengl diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims new file mode 100755 index 0000000000..434254f9ab --- /dev/null +++ b/tests/test_nimscript.nims @@ -0,0 +1,25 @@ +# This nimscript is used to test if the following modules can be imported +# http://nim-lang.org/docs/nims.html + +import algorithm +import base64 +import colors +import hashes +import lists +import math +# import marshal +import options +import ospaths +# import parsecfg +# import parseopt +import parseutils +import pegs +import queues +import sequtils +import strutils +import subexes +import tables +import unicode +import uri + +echo "Nimscript imports are successful." From 3035c2c63a226cf97044405eea5107ab01be2a6d Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sun, 3 Apr 2016 15:05:39 +0000 Subject: [PATCH 032/674] net: disable SSLv3 SSLv3 is no longer secure and has been removed from OpenSSL since 1.0.2. Disabling this will enable Nim programs to run against OpenSSL 1.0.2. --- lib/pure/net.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 330682ca90..394bccee31 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -222,9 +222,9 @@ when defined(ssl): of protSSLv23: newCTX = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support. of protSSLv2: - raiseSslError("SSLv2 is no longer secure and has been deprecated, use protSSLv3") + raiseSslError("SSLv2 is no longer secure and has been deprecated, use protSSLv23") of protSSLv3: - newCTX = SSL_CTX_new(SSLv3_method()) + raiseSslError("SSLv3 is no longer secure and has been deprecated, use protSSLv23") of protTLSv1: newCTX = SSL_CTX_new(TLSv1_method()) From 5757ad858cfa86b47a02a0389d3257c3284e1dbb Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 3 Apr 2016 18:12:10 +0200 Subject: [PATCH 033/674] fixes #3995 --- compiler/ccgexprs.nim | 14 ++++++++++---- compiler/lambdalifting.nim | 4 ++++ tests/closure/tflatmap.nim | 24 ++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 tests/closure/tflatmap.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 4fcbeeec2f..d84a7d92ee 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1856,10 +1856,16 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) = initLocExpr(p, n.sons[1], b) if n.sons[0].skipConv.kind == nkClosure: internalError(n.info, "closure to closure created") - getTemp(p, n.typ, tmp) - linefmt(p, cpsStmts, "$1.ClPrc = $2; $1.ClEnv = $3;$n", - tmp.rdLoc, a.rdLoc, b.rdLoc) - putLocIntoDest(p, d, tmp) + # tasyncawait.nim breaks with this optimization: + when false: + if d.k != locNone: + linefmt(p, cpsStmts, "$1.ClPrc = $2; $1.ClEnv = $3;$n", + d.rdLoc, a.rdLoc, b.rdLoc) + else: + getTemp(p, n.typ, tmp) + linefmt(p, cpsStmts, "$1.ClPrc = $2; $1.ClEnv = $3;$n", + tmp.rdLoc, a.rdLoc, b.rdLoc) + putLocIntoDest(p, d, tmp) proc genArrayConstr(p: BProc, n: PNode, d: var TLoc) = var arr: TLoc diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 53fca48631..959632bab8 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -721,6 +721,10 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass; let m = newSymNode(n[namePos].sym) m.typ = n.typ result = liftCapturedVars(m, owner, d, c) + of nkHiddenStdConv: + if n.len == 2: + n.sons[1] = liftCapturedVars(n[1], owner, d, c) + if n[1].kind == nkClosure: result = n[1] else: if owner.isIterator: if n.kind == nkYieldStmt: diff --git a/tests/closure/tflatmap.nim b/tests/closure/tflatmap.nim new file mode 100644 index 0000000000..240756424b --- /dev/null +++ b/tests/closure/tflatmap.nim @@ -0,0 +1,24 @@ + +# bug #3995 + +import future + +type + RNG* = tuple[] + Rand*[A] = (RNG) -> (A, RNG) + +proc nextInt*(r: RNG): (int, RNG) = + (1, ()) + +proc flatMap[A,B](f: Rand[A], g: A -> Rand[B]): Rand[B] = + (rng: RNG) => ( + let (a, rng2) = f(rng); + let g1 = g(a); + g1(rng2) + ) + +proc map[A,B](s: Rand[A], f: A -> B): Rand[B] = + let g: A -> Rand[B] = (a: A) => ((rng: RNG) => (f(a), rng)) + flatMap(s, g) + +let f = nextInt.map(i => i - i mod 2) From 6e53300f83dc7646fbad834c494c34470a393885 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 3 Apr 2016 22:51:22 +0200 Subject: [PATCH 034/674] fixes #3973 --- compiler/vm.nim | 7 +++++-- compiler/vmgen.nim | 2 +- tests/vm/tinheritance.nim | 29 +++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 tests/vm/tinheritance.nim diff --git a/compiler/vm.nim b/compiler/vm.nim index 7220e1b8e7..7be2080894 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -10,7 +10,9 @@ ## This file implements the new evaluation engine for Nim code. ## An instruction is 1-3 int32s in memory, it is a register based VM. -const debugEchoCode = false +const + debugEchoCode = false + traceCode = debugEchoCode import ast except getstr @@ -404,7 +406,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let instr = c.code[pc] let ra = instr.regA #if c.traceActive: - #echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra, " rb ", instr.regB, " rc ", instr.regC + when traceCode: + echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra, " rb ", instr.regB, " rc ", instr.regC # message(c.debug[pc], warnUser, "Trace") case instr.opcode diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 47f16a013d..43c7ca2db6 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1447,12 +1447,12 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode = of tyObject: result = newNodeIT(nkObjConstr, info, t) result.add(newNodeIT(nkEmpty, info, t)) - getNullValueAux(t.n, result) # initialize inherited fields: var base = t.sons[0] while base != nil: getNullValueAux(skipTypes(base, skipPtrs).n, result) base = base.sons[0] + getNullValueAux(t.n, result) of tyArray, tyArrayConstr: result = newNodeIT(nkBracket, info, t) for i in countup(0, int(lengthOrd(t)) - 1): diff --git a/tests/vm/tinheritance.nim b/tests/vm/tinheritance.nim new file mode 100644 index 0000000000..d465e22b95 --- /dev/null +++ b/tests/vm/tinheritance.nim @@ -0,0 +1,29 @@ +discard """ + msg: '''Hello fred , managed by sally +Hello sally , managed by bob''' +""" +# bug #3973 + +type + EmployeeCode = enum + ecCode1, + ecCode2 + + Person* = object of RootObj + name* : string + last_name*: string + + Employee* = object of Person + empl_code* : EmployeeCode + mgr_name* : string + +proc test() = + var + empl1 = Employee(name: "fred", last_name: "smith", mgr_name: "sally", empl_code: ecCode1) + empl2 = Employee(name: "sally", last_name: "jones", mgr_name: "bob", empl_code: ecCode2) + + echo "Hello ", empl1.name, " , managed by ", empl1.mgr_name + echo "Hello ", empl2.name, " , managed by ", empl2.mgr_name + +static: + test() From cb3a38afa2de4401af55fbb7b6050f499b182bf4 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 3 Apr 2016 23:38:29 +0200 Subject: [PATCH 035/674] fixes #1152 --- doc/manual/typedesc.txt | 32 ---------------------- tests/macros/typesafeprintf.nim | 48 +++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 32 deletions(-) create mode 100644 tests/macros/typesafeprintf.nim diff --git a/doc/manual/typedesc.txt b/doc/manual/typedesc.txt index de1d84d7dc..6922d77e40 100644 --- a/doc/manual/typedesc.txt +++ b/doc/manual/typedesc.txt @@ -77,38 +77,6 @@ Once bound, typedesc params can appear in the rest of the proc signature: declareVariableWithType int, 42 -When used with macros and .compileTime. procs on the other hand, the compiler -does not need to instantiate the code multiple times, because types then can be -manipulated using the unified internal symbol representation. In such context -typedesc acts as any other type. One can create variables, store typedesc -values inside containers and so on. For example, here is how one can create -a type-safe wrapper for the unsafe `printf` function from C: - -.. code-block:: nim - macro safePrintF(formatString: string{lit}, args: varargs[expr]): expr = - var i = 0 - for c in formatChars(formatString): - var expectedType = case c - of 'c': char - of 'd', 'i', 'x', 'X': int - of 'f', 'e', 'E', 'g', 'G': float - of 's': string - of 'p': pointer - else: EOutOfRange - - var actualType = args[i].getType - inc i - - if expectedType == EOutOfRange: - error c & " is not a valid format character" - elif expectedType != actualType: - error "type mismatch for argument ", i, ". expected type: ", - expectedType.name, ", actual type: ", actualType.name - - # keep the original callsite, but use cprintf instead - result = callsite() - result[0] = newIdentNode(!"cprintf") - Overload resolution can be further influenced by constraining the set of types that will match the typedesc param: diff --git a/tests/macros/typesafeprintf.nim b/tests/macros/typesafeprintf.nim new file mode 100644 index 0000000000..2f4622f3e1 --- /dev/null +++ b/tests/macros/typesafeprintf.nim @@ -0,0 +1,48 @@ +discard """ + output: '''test 10''' +""" + +# bug #1152 + +import macros, typetraits +proc printfImpl(formatstr: cstring) {.importc: "printf", varargs.} + +iterator tokenize(format: string): char = + var i = 0 + while true: + case format[i] + of '%': + case format[i+1] + of '\0': break + else: yield format[i+1] + i.inc + of '\0': break + else: discard + i.inc + +macro printf(formatString: string{lit}, args: varargs[typed]): untyped = + var i = 0 + let err = getType(bindSym"ValueError") + for c in tokenize(formatString.strVal): + var expectedType = case c + of 'c': getType(bindSym"char") + of 'd', 'i', 'x', 'X': getType(bindSym"int") + of 'f', 'e', 'E', 'g', 'G': getType(bindSym"float") + of 's': getType(bindSym"string") + of 'p': getType(bindSym"pointer") + else: err + + var actualType = getType(args[i]) + inc i + + if sameType(expectedType, err): + error c & " is not a valid format character" + elif not sameType(expectedType, actualType): + error "type mismatch for argument " & $i & ". expected type: " & + $expectedType & ", actual type: " & $actualType + + # keep the original callsite, but use cprintf instead + result = callsite() + result[0] = bindSym"printfImpl" + +printf("test %d\n", 10) From 86e79f5cec118587c7e52f614c245176cf480597 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 4 Apr 2016 01:41:14 +0200 Subject: [PATCH 036/674] fixes #3804 --- compiler/vm.nim | 2 +- compiler/vmgen.nim | 4 ++++ tests/vm/twrong_concat.nim | 28 ++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 tests/vm/twrong_concat.nim diff --git a/compiler/vm.nim b/compiler/vm.nim index 7be2080894..1235a648dc 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -123,7 +123,7 @@ template move(a, b: expr) {.immediate, dirty.} = system.shallowCopy(a, b) # XXX fix minor 'shallowCopy' overloading bug in compiler proc createStrKeepNode(x: var TFullReg; keepNode=true) = - if x.node.isNil: + if x.node.isNil or not keepNode: x.node = newNode(nkStrLit) elif x.node.kind == nkNilLit and keepNode: when defined(useNodeIds): diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 43c7ca2db6..7e506f8a07 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -102,6 +102,10 @@ proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) = let ins = (opc.uint32 or (a.uint32 shl 8'u32) or (b.uint32 shl 16'u32) or (c.uint32 shl 24'u32)).TInstr + when false: + if ctx.code.len == 72: + writeStackTrace() + echo "generating ", opc ctx.code.add(ins) ctx.debug.add(n.info) diff --git a/tests/vm/twrong_concat.nim b/tests/vm/twrong_concat.nim new file mode 100644 index 0000000000..538ea25278 --- /dev/null +++ b/tests/vm/twrong_concat.nim @@ -0,0 +1,28 @@ +discard """ + output: '''success''' +""" + +# bug #3804 + +#import sequtils + +type AnObj = ref object + field: string + +#proc aBug(objs: seq[AnObj]) {.compileTime.} = +# discard objs.mapIt(it.field & " bug") + +proc sameBug(objs: seq[AnObj]) {.compileTime.} = + var strSeq = newSeq[string](objs.len) + strSeq[0] = objs[0].field & " bug" + +static: + var objs: seq[AnObj] = @[] + objs.add(AnObj(field: "hello")) + + sameBug(objs) + # sameBug(objs) + echo objs[0].field + assert(objs[0].field == "hello") # fails, because (objs[0].field == "hello bug") - mutated! + +echo "success" From 0acdaea3342e13317ac9956add08e606208b2986 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 4 Apr 2016 02:45:43 +0200 Subject: [PATCH 037/674] fixes #3561, fixes #2409 --- compiler/vmgen.nim | 10 +++++--- tests/vm/tanonproc.nim | 52 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 tests/vm/tanonproc.nim diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 7e506f8a07..038a07a165 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -708,6 +708,10 @@ proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = c.genNarrow(n, dest) proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) = + if n.typ.kind == arg.typ.kind and arg.typ.kind == tyProc: + # don't do anything for lambda lifting conversions: + gen(c, arg, dest) + return let tmp = c.genx(arg) if dest < 0: dest = c.getTemp(n.typ) c.gABC(n, opc, dest, tmp) @@ -1740,9 +1744,9 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = of declarativeDefs: unused(n, dest) of nkLambdaKinds: - let s = n.sons[namePos].sym - discard genProc(c, s) - genLit(c, n.sons[namePos], dest) + #let s = n.sons[namePos].sym + #discard genProc(c, s) + genLit(c, newSymNode(n.sons[namePos].sym), dest) of nkChckRangeF, nkChckRange64, nkChckRange: let tmp0 = c.genx(n.sons[0]) diff --git a/tests/vm/tanonproc.nim b/tests/vm/tanonproc.nim new file mode 100644 index 0000000000..474b768ca7 --- /dev/null +++ b/tests/vm/tanonproc.nim @@ -0,0 +1,52 @@ +discard """ + output: '''`Test`''' +""" + +# bug #3561 + +import macros, future, strutils + +type + Option[T] = ref object + case valid: bool + of true: + data: T + else: + discard + +proc some[T](v: T): Option[T] = Option[T](valid: true, data: v) +proc none[T](v: T): Option[T] = Option[T](valid: false) +proc none(T: typedesc): Option[T] = Option[T](valid: false) + +proc map[T,U](o: Option[T], f: T -> U): Option[U] = + case o.valid + of true: + f(o.data).some + else: + U.none + +proc notEmpty(o: Option[string]): Option[string] = + case o.valid + of true: + if o.data.strip == "": string.none else: o.data.strip.some + else: + o + +proc getOrElse[T](o: Option[T], def: T): T = + case o.valid + of true: + o.data + else: + def + +proc quoteStr(s: string): Option[string] = + s.some.notEmpty.map(v => "`" & v & "`") + +macro str(s: string): stmt = + let x = s.strVal + let y = quoteStr(x) + let sn = newStrLitNode(y.getOrElse("NONE")) + result = quote do: + echo `sn` + +str"Test" From cbcdf12d2c78de352d3f5149882cca2b0b72522d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 4 Apr 2016 10:16:15 +0200 Subject: [PATCH 038/674] fixes #3731 --- compiler/vm.nim | 2 +- compiler/vmgen.nim | 14 +++++++++++--- tests/vm/tmitems.nim | 15 +++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 tests/vm/tmitems.nim diff --git a/compiler/vm.nim b/compiler/vm.nim index 1235a648dc..f799334d68 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -545,7 +545,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = if regs[rb].node.kind == nkRefTy: regs[ra].node = regs[rb].node.sons[0] else: - stackTrace(c, tos, pc, errGenerated, "limited VM support for 'ref'") + stackTrace(c, tos, pc, errGenerated, "limited VM support for pointers") else: stackTrace(c, tos, pc, errNilAccess) of opcWrDeref: diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 038a07a165..019c79eb34 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -103,7 +103,7 @@ proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) = (b.uint32 shl 16'u32) or (c.uint32 shl 24'u32)).TInstr when false: - if ctx.code.len == 72: + if ctx.code.len == 43: writeStackTrace() echo "generating ", opc ctx.code.add(ins) @@ -126,6 +126,11 @@ proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) = proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) = # Applies `opc` to `bx` and stores it into register `a` # `bx` must be signed and in the range [-32768, 32767] + when false: + if c.code.len == 43: + writeStackTrace() + echo "generating ", opc + if bx >= -32768 and bx <= 32767: let ins = (opc.uint32 or a.uint32 shl 8'u32 or (bx+wordExcess).uint32 shl 16'u32).TInstr @@ -1125,7 +1130,10 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; if isAddr and (let m = canElimAddr(n); m != nil): gen(c, m, dest, flags) return - let newflags = if isAddr: flags+{gfAddrOf} else: flags + + let af = if n[0].kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr}: {gfAddrOf, gfFieldAccess} + else: {gfAddrOf} + let newflags = if isAddr: flags+af else: flags # consider: # proc foo(f: var ref int) = # f = new(int) @@ -1140,7 +1148,7 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; if gfAddrOf notin flags and fitsRegister(n.typ): c.gABC(n, opcNodeToReg, dest, dest) elif isAddr and isGlobal(n.sons[0]): - gen(c, n.sons[0], dest, flags+{gfAddrOf}) + gen(c, n.sons[0], dest, flags+af) else: let tmp = c.genx(n.sons[0], newflags) if dest < 0: dest = c.getTemp(n.typ) diff --git a/tests/vm/tmitems.nim b/tests/vm/tmitems.nim new file mode 100644 index 0000000000..18f5bfa067 --- /dev/null +++ b/tests/vm/tmitems.nim @@ -0,0 +1,15 @@ +discard """ + msg: '''13''' +""" +# bug #3731 +var list {.compileTime.} = newSeq[int]() + +macro calc*(): stmt {.immediate.} = + list.add(1) + for c in list.mitems: + c = 13 + + for c in list: + echo c + +calc() From 6d675814091b20312cbe51b69261453e04e27214 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 4 Apr 2016 10:19:20 +0200 Subject: [PATCH 039/674] fixes #3859 --- tests/vm/tmitems.nim | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/vm/tmitems.nim b/tests/vm/tmitems.nim index 18f5bfa067..4ee225eedc 100644 --- a/tests/vm/tmitems.nim +++ b/tests/vm/tmitems.nim @@ -1,5 +1,8 @@ discard """ msg: '''13''' + output: '''3 +3 +3''' """ # bug #3731 var list {.compileTime.} = newSeq[int]() @@ -13,3 +16,16 @@ macro calc*(): stmt {.immediate.} = echo c calc() + +# bug #3859 +import macros +macro m: stmt = + var s = newseq[NimNode](3) + # var s: array[3,NimNode] # not working either + for i in 0.. Date: Mon, 4 Apr 2016 10:28:18 +0200 Subject: [PATCH 040/674] fixes #4036 --- compiler/parser.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/parser.nim b/compiler/parser.nim index f22177ac1b..1ba59b9386 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -326,6 +326,7 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode = getTok(p) else: parMessage(p, errIdentifierExpected, p.tok) + break eat(p, tkAccent) else: if allowNil and p.tok.tokType == tkNil: From fbedb6c65514e394f163a68dd530d19d310afadf Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 4 Apr 2016 11:16:03 +0200 Subject: [PATCH 041/674] fixes #3646 --- compiler/pragmas.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 2280ef712a..38d17eb62a 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -256,8 +256,9 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode = proc processDynLib(c: PContext, n: PNode, sym: PSym) = if (sym == nil) or (sym.kind == skModule): - POptionEntry(c.optionStack.tail).dynlib = getLib(c, libDynamic, - expectDynlibNode(c, n)) + let lib = getLib(c, libDynamic, expectDynlibNode(c, n)) + if not lib.isOverriden: + POptionEntry(c.optionStack.tail).dynlib = lib else: if n.kind == nkExprColonExpr: var lib = getLib(c, libDynamic, expectDynlibNode(c, n)) From 1d85ca3aa41d8e3d2bf7aaf481fe6a577c33ec48 Mon Sep 17 00:00:00 2001 From: Ruslan Mustakov Date: Mon, 4 Apr 2016 15:50:02 +0600 Subject: [PATCH 042/674] Fixed macros unpackX procedured to return values correctly --- lib/core/macros.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 4522e0fc6b..678982a522 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -796,17 +796,17 @@ proc infix*(a: NimNode; op: string; proc unpackPostfix*(node: NimNode): tuple[node: NimNode; op: string] {. compileTime.} = node.expectKind nnkPostfix - result = (node[0], $node[1]) + result = (node[1], $node[0]) proc unpackPrefix*(node: NimNode): tuple[node: NimNode; op: string] {. compileTime.} = node.expectKind nnkPrefix - result = (node[0], $node[1]) + result = (node[1], $node[0]) proc unpackInfix*(node: NimNode): tuple[left: NimNode; op: string; right: NimNode] {.compileTime.} = assert node.kind == nnkInfix - result = (node[0], $node[1], node[2]) + result = (node[1], $node[0], node[2]) proc copy*(node: NimNode): NimNode {.compileTime.} = ## An alias for copyNimTree(). From a70e6b3fde7c251aff68243de1c7adcebc3c67e3 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 4 Apr 2016 12:06:25 +0100 Subject: [PATCH 043/674] Fixes #3752. --- lib/system.nim | 3 +++ lib/system/sysio.nim | 2 ++ 2 files changed, 5 insertions(+) diff --git a/lib/system.nim b/lib/system.nim index fefabe53f3..d3b18f9e39 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2774,6 +2774,9 @@ when not defined(JS): #and not defined(nimscript): ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns ## the actual number of bytes that have been read which may be less than ## `len` (if not as many bytes are remaining), but not greater. + ## + ## **Warning:** The buffer `a` must be pre-allocated. This can be done + ## using, for example, ``newString``. proc readBuffer*(f: File, buffer: pointer, len: Natural): int {. tags: [ReadIOEffect], benign.} diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index d0bba67758..3c34215acc 100644 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -58,6 +58,8 @@ proc readBytes(f: File, a: var openArray[int8|uint8], start, len: Natural): int result = readBuffer(f, addr(a[start]), len) proc readChars(f: File, a: var openArray[char], start, len: Natural): int = + if (start + len) > len(a): + raiseEIO("buffer overflow: (start+len) > length of openarray buffer") result = readBuffer(f, addr(a[start]), len) proc write(f: File, c: cstring) = fputs(c, f) From 73e48f9c9cfa3d6f2dad1d9e11efec2975eca1e5 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 4 Apr 2016 13:39:42 +0100 Subject: [PATCH 044/674] Fixes #4037 --- lib/pure/strutils.nim | 90 ++++++++++++++++++++++++++++++------------- web/news.txt | 3 ++ 2 files changed, 66 insertions(+), 27 deletions(-) diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index eebadf4c03..a5a4ee5096 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -784,8 +784,7 @@ proc indent*(s: string, count: Natural, padding: string = " "): string {.noSideEffect, rtl, extern: "nsuIndent".} = ## Indents each line in ``s`` by ``count`` amount of ``padding``. ## - ## **Note:** This currently does not preserve the specific new line characters - ## used. + ## **Note:** This does not preserve the new line characters used in ``s``. result = "" var i = 0 for line in s.splitLines(): @@ -796,32 +795,39 @@ proc indent*(s: string, count: Natural, padding: string = " "): string result.add(line) i.inc -proc unindent*(s: string, eatAllIndent = false): string {. - noSideEffect, rtl, extern: "nsuUnindent".} = - ## Unindents `s`. - result = newStringOfCap(s.len) +proc unindent*(s: string, count: Natural, padding: string = " "): string + {.noSideEffect, rtl, extern: "nsuUnindent".} = + ## Unindents each line in ``s`` by ``count`` amount of ``padding``. + ## + ## **Note:** This does not preserve the new line characters used in ``s``. + result = "" var i = 0 - var pattern = true - var indent = 0 - while s[i] == ' ': inc i - var level = if i == 0: -1 else: i - while i < s.len: - if s[i] == ' ': - if i > 0 and s[i-1] in {'\l', '\c'}: - pattern = true - indent = 0 - if pattern: - inc(indent) - if indent > level and not eatAllIndent: - result.add(s[i]) - if level < 0: level = indent - else: - # a space somewhere: do not delete - result.add(s[i]) - else: - pattern = false - result.add(s[i]) - inc i + for line in s.splitLines(): + if i != 0: + result.add("\n") + var indentCount = 0 + for j in 0.. Date: Mon, 4 Apr 2016 14:44:26 +0100 Subject: [PATCH 045/674] Better additionalInfo OSError message, ref #2650. --- lib/pure/os.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 470559e173..1a2c6d537a 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -129,7 +129,7 @@ proc raiseOSError*(errorCode: OSErrorCode; additionalInfo = "") {.noinline.} = if additionalInfo.len == 0: e.msg = osErrorMsg(errorCode) else: - e.msg = additionalInfo & " " & osErrorMsg(errorCode) + e.msg = osErrorMsg(errorCode) & "\nAdditional info: " & additionalInfo if e.msg == "": e.msg = "unknown OS error" raise e From cf5b7cbdefc1da9a5c0c8b54226d52e337855534 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Mon, 4 Apr 2016 21:57:56 +0800 Subject: [PATCH 046/674] fix type used for chckRange node boundaries else you end up with for example an int64-sized value with an int32 type, when checking int32 -> Natural --- compiler/transf.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/transf.nim b/compiler/transf.nim index a4a15ea4ab..0647553c66 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -414,8 +414,8 @@ proc transformConv(c: PTransf, n: PNode): PTransNode = result = newTransNode(nkChckRange, n, 3) dest = skipTypes(n.typ, abstractVar) result[0] = transform(c, n.sons[1]) - result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), source).PTransNode - result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode + result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), dest).PTransNode + result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), dest).PTransNode of tyFloat..tyFloat128: # XXX int64 -> float conversion? if skipTypes(n.typ, abstractVar).kind == tyRange: From af70254c7b508b6658b50ec8b4fb9465a02acb3f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 4 Apr 2016 16:41:35 +0200 Subject: [PATCH 047/674] fixes #2006 --- compiler/sigmatch.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 82f878932a..377743de3f 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -513,7 +513,7 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} = proc matchUserTypeClass*(c: PContext, m: var TCandidate, ff, a: PType): TTypeRelation = var body = ff.skipTypes({tyUserTypeClassInst}) - if c.inTypeClass > 20: + if c.inTypeClass > 4: localError(body.n[3].info, $body.n[3] & " too nested for type matching") return isNone From aa01c346f76716f5d4379cd0eae2d065d676d74a Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 4 Apr 2016 20:15:52 +0100 Subject: [PATCH 048/674] Fixes #3159. --- lib/impure/rdstdin.nim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim index 469bb69c5e..f722a6b39a 100644 --- a/lib/impure/rdstdin.nim +++ b/lib/impure/rdstdin.nim @@ -105,7 +105,8 @@ else: proc readLineFromStdin*(prompt: string): TaintedString {. tags: [ReadIOEffect, WriteIOEffect].} = var buffer = linenoise.readLine(prompt) - if isNil(buffer): quit(0) + if isNil(buffer): + raise newException(IOError, "Linenoise returned nil") result = TaintedString($buffer) if result.string.len > 0: historyAdd(buffer) @@ -114,12 +115,12 @@ else: proc readLineFromStdin*(prompt: string, line: var TaintedString): bool {. tags: [ReadIOEffect, WriteIOEffect].} = var buffer = linenoise.readLine(prompt) - if isNil(buffer): quit(0) + if isNil(buffer): + raise newException(IOError, "Linenoise returned nil") line = TaintedString($buffer) if line.string.len > 0: historyAdd(buffer) linenoise.free(buffer) - # XXX how to determine CTRL+D? result = true proc readPasswordFromStdin*(prompt: string, password: var TaintedString): From 38d6e2c221dcb6f284de1ec7b038385a6212809c Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 4 Apr 2016 20:22:22 +0100 Subject: [PATCH 049/674] Deprecated matchers module. Fixes #2446. --- lib/pure/matchers.nim | 4 ++++ web/news.txt | 2 ++ 2 files changed, 6 insertions(+) diff --git a/lib/pure/matchers.nim b/lib/pure/matchers.nim index 5c28f65a08..7022c21d97 100644 --- a/lib/pure/matchers.nim +++ b/lib/pure/matchers.nim @@ -8,6 +8,10 @@ # ## This module contains various string matchers for email addresses, etc. +## +## **Warning:** This module is deprecated since version 0.14.0. +{.deprecated.} + {.deadCodeElim: on.} {.push debugger:off .} # the user does not want to trace a part diff --git a/web/news.txt b/web/news.txt index 5bb0e19b41..42d2aca99a 100644 --- a/web/news.txt +++ b/web/news.txt @@ -26,6 +26,8 @@ Changes affecting backwards compatibility - The ``strutils.unindent`` procedure has been rewritten. Its parameters now match the parameters of ``strutils.indent``. See issue [#4037](https://github.com/nim-lang/Nim/issues/4037) for more details. +- The ``matchers`` module has been deprecated. See issue [#2446](https://github.com/nim-lang/Nim/issues/2446) + for more details. Library Additions From 8e6f5f20f686110febf7f50e886a51fd821dc44f Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 4 Apr 2016 20:47:47 +0100 Subject: [PATCH 050/674] Improve net and ssl module docs. --- lib/impure/ssl.nim | 3 ++ lib/pure/net.nim | 97 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 80 insertions(+), 20 deletions(-) diff --git a/lib/impure/ssl.nim b/lib/impure/ssl.nim index 721e5ce51c..e3312d792e 100644 --- a/lib/impure/ssl.nim +++ b/lib/impure/ssl.nim @@ -9,6 +9,9 @@ ## This module provides an easy to use sockets-style ## nim interface to the OpenSSL library. +## +## **Warning:** This module is deprecated, use the SSL procedures defined in +## the ``net`` module instead. {.deprecated.} diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 394bccee31..fff72e1d80 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -8,19 +8,76 @@ # ## This module implements a high-level cross-platform sockets interface. +## The procedures implemented in this module are primarily for blocking sockets. +## For asynchronous non-blocking sockets use the ``asyncnet`` module together +## with the ``asyncdispatch`` module. +## +## The first thing you will always need to do in order to start using sockets, +## is to create a new instance of the ``Socket`` type using the ``newSocket`` +## procedure. +## +## SSL +## ==== +## +## In order to use the SSL procedures defined in this module, you will need to +## compile your application with the ``-d:ssl`` flag. +## +## Examples +## ======== +## +## Connecting to a server +## ---------------------- +## +## After you create a socket with the ``newSocket`` procedure, you can easily +## connect it to a server running at a known hostname (or IP address) and port. +## To do so over TCP, use the example below. +## +## .. code-block:: Nim +## var socket = newSocket() +## socket.connect("google.com", Port(80)) +## +## UDP is a connectionless protocol, so UDP sockets don't have to explicitly +## call the ``connect`` procedure. They can simply start sending data +## immediately. +## +## .. code-block:: Nim +## var socket = newSocket() +## socket.sendTo("192.168.0.1", Port(27960), "status\n") +## +## Creating a server +## ----------------- +## +## After you create a socket with the ``newSocket`` procedure, you can create a +## TCP server by calling the ``bindAddr`` and ``listen`` procedures. +## +## .. code-block:: Nim +## var socket = newSocket() +## socket.bindAddr(Port(1234)) +## socket.listen() +## +## You can then begin accepting connections using the ``accept`` procedure. +## +## .. code-block:: Nim +## var client = newSocket() +## var address = "" +## while true: +## socket.acceptAddr(client, address) +## echo("Client connected from: ", address) +## {.deadCodeElim: on.} import nativesockets, os, strutils, parseutils, times export Port, `$`, `==` const useWinVersion = defined(Windows) or defined(nimdoc) +const defineSsl = defined(ssl) or defined(nimdoc) -when defined(ssl): +when defineSsl: import openssl # Note: The enumerations are mapped to Window's constants. -when defined(ssl): +when defineSsl: type SslError* = object of Exception @@ -54,7 +111,7 @@ type currPos: int # current index in buffer bufLen: int # current length of buffer of false: nil - when defined(ssl): + when defineSsl: case isSsl: bool of true: sslHandle: SSLPtr @@ -160,7 +217,7 @@ proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM, raiseOSError(osLastError()) result = newSocket(fd, domain, sockType, protocol, buffered) -when defined(ssl): +when defineSsl: CRYPTO_malloc_init() SslLibraryInit() SslLoadErrorStrings() @@ -301,7 +358,7 @@ proc socketError*(socket: Socket, err: int = -1, async = false, ## error was caused by no data being available to be read. ## ## If ``err`` is not lower than 0 no exception will be raised. - when defined(ssl): + when defineSsl: if socket.isSSL: if err <= 0: var ret = SSLGetError(socket.sslHandle, err.cint) @@ -334,7 +391,7 @@ proc socketError*(socket: Socket, err: int = -1, async = false, raiseSSLError() else: raiseSSLError("Unknown Error") - if err == -1 and not (when defined(ssl): socket.isSSL else: false): + if err == -1 and not (when defineSsl: socket.isSSL else: false): var lastE = if lastError.int == -1: getSocketError(socket) else: lastError if async: when useWinVersion: @@ -414,7 +471,7 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string, client.isBuffered = server.isBuffered # Handle SSL. - when defined(ssl): + when defineSsl: if server.isSSL: # We must wrap the client sock in a ssl context. @@ -425,7 +482,7 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string, # Client socket is set above. address = $inet_ntoa(sockAddress.sin_addr) -when false: #defined(ssl): +when false: #defineSsl: proc acceptAddrSSL*(server: Socket, client: var Socket, address: var string): SSLAcceptResult {. tags: [ReadIOEffect].} = @@ -444,7 +501,7 @@ when false: #defined(ssl): ## ``AcceptNoClient`` will be returned when no client is currently attempting ## to connect. template doHandshake(): stmt = - when defined(ssl): + when defineSsl: if server.isSSL: client.setBlocking(false) # We must wrap the client sock in a ssl context. @@ -495,7 +552,7 @@ proc accept*(server: Socket, client: var Socket, proc close*(socket: Socket) = ## Closes a socket. try: - when defined(ssl): + when defineSsl: if socket.isSSL: ErrClearError() # As we are closing the underlying socket immediately afterwards, @@ -547,7 +604,7 @@ 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(ssl): +when defineSsl: proc handshake*(socket: Socket): bool {.tags: [ReadIOEffect, WriteIOEffect].} = ## This proc needs to be called on a socket after it connects. This is ## only applicable when using ``connectAsync``. @@ -594,7 +651,7 @@ proc hasDataBuffered*(s: Socket): bool = if s.isBuffered: result = s.bufLen > 0 and s.currPos != s.bufLen - when defined(ssl): + when defineSsl: if s.isSSL and not result: result = s.sslHasPeekChar @@ -608,7 +665,7 @@ proc select(readfd: Socket, timeout = 500): int = proc readIntoBuf(socket: Socket, flags: int32): int = result = 0 - when defined(ssl): + when defineSsl: if socket.isSSL: result = SSLRead(socket.sslHandle, addr(socket.buffer), int(socket.buffer.high)) else: @@ -658,7 +715,7 @@ proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ReadIOEffect] result = read else: - when defined(ssl): + when defineSsl: if socket.isSSL: if socket.sslHasPeekChar: copyMem(data, addr(socket.sslPeekChar), 1) @@ -696,7 +753,7 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int, if timeout - int(waited * 1000.0) < 1: raise newException(TimeoutError, "Call to '" & funcName & "' timed out.") - when defined(ssl): + when defineSsl: if socket.isSSL: if socket.hasDataBuffered: # sslPeekChar is present. @@ -764,7 +821,7 @@ proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} = c = socket.buffer[socket.currPos] else: - when defined(ssl): + when defineSsl: if socket.isSSL: if not socket.sslHasPeekChar: result = SSLRead(socket.sslHandle, addr(socket.sslPeekChar), 1) @@ -872,7 +929,7 @@ proc send*(socket: Socket, data: pointer, size: int): int {. ## ## **Note**: This is a low-level version of ``send``. You likely should use ## the version below. - when defined(ssl): + when defineSsl: if socket.isSSL: return SSLWrite(socket.sslHandle, cast[cstring](data), size) @@ -943,7 +1000,7 @@ proc sendTo*(socket: Socket, address: string, port: Port, proc isSsl*(socket: Socket): bool = ## Determines whether ``socket`` is a SSL socket. - when defined(ssl): + when defineSsl: result = socket.isSSL else: result = false @@ -1253,7 +1310,7 @@ proc connect*(socket: Socket, address: string, dealloc(aiList) if not success: raiseOSError(lastError) - when defined(ssl): + when defineSsl: if socket.isSSL: # RFC3546 for SNI specifies that IP addresses are not allowed. if not isIpAddress(address): @@ -1314,7 +1371,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 defined(ssl): + when defineSsl: if socket.isSSL: socket.fd.setBlocking(true) doAssert socket.handshake() From 03be03c6e454f22ef7a70cf8f3300f18407cdc0a Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 4 Apr 2016 21:00:43 +0100 Subject: [PATCH 051/674] Improved asyncnet docs (SSL procs now shown). Deprecated handshake. --- lib/pure/asyncnet.nim | 20 +++++++++++--------- lib/pure/net.nim | 5 ++++- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 6b19a48be0..7161b1c557 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -11,7 +11,7 @@ ## asynchronous dispatcher defined in the ``asyncdispatch`` module. ## ## SSL -## --- +## ---- ## ## SSL can be enabled by compiling with the ``-d:ssl`` flag. ## @@ -62,7 +62,9 @@ import os export SOBool -when defined(ssl): +const defineSsl = defined(ssl) or defined(nimdoc) + +when defineSsl: import openssl type @@ -79,7 +81,7 @@ type of false: nil case isSsl: bool of true: - when defined(ssl): + when defineSsl: sslHandle: SslPtr sslContext: SslContext bioIn: BIO @@ -125,7 +127,7 @@ proc newAsyncSocket*(domain, sockType, protocol: cint, Domain(domain), SockType(sockType), Protocol(protocol), buffered) -when defined(ssl): +when defineSsl: proc getSslError(handle: SslPtr, err: cint): cint = assert err < 0 var ret = SSLGetError(handle, err.cint) @@ -186,7 +188,7 @@ proc connect*(socket: AsyncSocket, address: string, port: Port) {.async.} = ## or an error occurs. await connect(socket.fd.AsyncFD, address, port, socket.domain) if socket.isSsl: - when defined(ssl): + when defineSsl: let flags = {SocketFlag.SafeDisconn} sslSetConnectState(socket.sslHandle) sslLoop(socket, flags, sslDoHandshake(socket.sslHandle)) @@ -197,7 +199,7 @@ template readInto(buf: cstring, size: int, socket: AsyncSocket, ## this is a template and not a proc. var res = 0 if socket.isSsl: - when defined(ssl): + when defineSsl: # SSL mode. sslLoop(socket, flags, sslRead(socket.sslHandle, buf, size.cint)) @@ -274,7 +276,7 @@ proc send*(socket: AsyncSocket, data: string, ## data has been sent. assert socket != nil if socket.isSsl: - when defined(ssl): + when defineSsl: var copy = data sslLoop(socket, flags, sslWrite(socket.sslHandle, addr copy[0], copy.len.cint)) @@ -468,7 +470,7 @@ proc close*(socket: AsyncSocket) = ## Closes the socket. defer: socket.fd.AsyncFD.closeSocket() - when defined(ssl): + when defineSsl: if socket.isSSL: let res = SslShutdown(socket.sslHandle) SSLFree(socket.sslHandle) @@ -478,7 +480,7 @@ proc close*(socket: AsyncSocket) = raiseSslError() socket.closed = true # TODO: Add extra debugging checks for this. -when defined(ssl): +when defineSsl: proc wrapSocket*(ctx: SslContext, socket: AsyncSocket) = ## Wraps a socket in an SSL context. This function effectively turns ## ``socket`` into an SSL socket. diff --git a/lib/pure/net.nim b/lib/pure/net.nim index fff72e1d80..292816fb5f 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -605,7 +605,8 @@ proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) { setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei) when defineSsl: - proc handshake*(socket: Socket): bool {.tags: [ReadIOEffect, WriteIOEffect].} = + proc handshake*(socket: Socket): bool + {.tags: [ReadIOEffect, WriteIOEffect, deprecated].} = ## This proc needs to be called on a socket after it connects. This is ## only applicable when using ``connectAsync``. ## This proc performs the SSL handshake. @@ -614,6 +615,8 @@ when defineSsl: ## ``True`` whenever handshake completed successfully. ## ## A ESSL error is raised on any other errors. + ## + ## **Note:** This procedure is deprecated since version 0.14.0. result = true if socket.isSSL: var ret = SSLConnect(socket.sslHandle) From 3ad103b8ccf70563d67c1839f78bd4429d468496 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 4 Apr 2016 21:20:29 +0100 Subject: [PATCH 052/674] Fixes small mistake in ``net`` module. --- lib/pure/net.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 292816fb5f..6888eb59f4 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -606,7 +606,7 @@ proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) { when defineSsl: proc handshake*(socket: Socket): bool - {.tags: [ReadIOEffect, WriteIOEffect, deprecated].} = + {.tags: [ReadIOEffect, WriteIOEffect], deprecated.} = ## This proc needs to be called on a socket after it connects. This is ## only applicable when using ``connectAsync``. ## This proc performs the SSL handshake. From 8050f43588f21e61a58fcdebb3ed5de231afa751 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 4 Apr 2016 21:28:21 +0100 Subject: [PATCH 053/674] Fixed some warnings in httpclient, net, and openssl. --- lib/pure/asyncnet.nim | 6 ++---- lib/pure/httpclient.nim | 4 ++-- lib/wrappers/openssl.nim | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 7161b1c557..7487785663 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -428,9 +428,6 @@ proc recvLine*(socket: AsyncSocket, ## ## **Warning**: ``recvLine`` on unbuffered sockets assumes that the protocol ## uses ``\r\L`` to delimit a new line. - template addNLIfEmpty(): stmt = - if result.len == 0: - result.add("\c\L") assert SocketFlag.Peek notin flags ## TODO: # TODO: Optimise this @@ -458,7 +455,8 @@ proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {. of AF_INET6: realaddr = "::" of AF_INET: realaddr = "0.0.0.0" else: - raiseOSError("Unknown socket address family and no address specified to bindAddr") + raise newException(ValueError, + "Unknown socket address family and no address specified to bindAddr") var aiList = getAddrInfo(realaddr, port, socket.domain) if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32: diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 603763386a..f473e47d1d 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -335,7 +335,7 @@ proc addFiles*(p: var MultipartData, xs: openarray[tuple[name, file: string]]): var m = newMimetypes() for name, file in xs.items: var contentType: string - let (dir, fName, ext) = splitFile(file) + let (_, fName, ext) = splitFile(file) if ext.len > 0: contentType = m.getMimetype(ext[1..ext.high], nil) p.add(name, readFile(file), fName & ext, contentType) @@ -627,7 +627,7 @@ proc newAsyncHttpClient*(userAgent = defUserAgent, result.userAgent = defUserAgent result.maxRedirects = maxRedirects when defined(ssl): - result.sslContext = net.SslContext(sslContext) + result.sslContext = sslContext proc close*(client: AsyncHttpClient) = ## Closes any connections held by the HTTP client. diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 05843e2d3d..635d52a645 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -260,7 +260,7 @@ proc OpenSSL_add_all_algorithms*(){.cdecl, dynlib: DLLUtilName, importc: "OPENSS proc OPENSSL_config*(configName: cstring){.cdecl, dynlib: DLLSSLName, importc.} -when not useWinVersion: +when not useWinVersion and not defined(macosx): proc CRYPTO_set_mem_functions(a,b,c: pointer){.cdecl, dynlib: DLLUtilName, importc.} @@ -532,7 +532,7 @@ proc md5_File* (file: string): string {.raises: [IOError,Exception].} = result = hexStr(buf) -proc md5_Str* (str:string): string {.raises:[IOError].} = +proc md5_Str*(str:string): string = ##Generate MD5 hash for a string. Result is a 32 character #hex string with lowercase characters var From c90df48293f080833348e8ea9dfcf7ee91736229 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 4 Apr 2016 21:52:10 +0100 Subject: [PATCH 054/674] Fixes JSON module problems. Fixes #3107. --- lib/pure/json.nim | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index b0179cd82b..5df9de5fa4 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -804,7 +804,7 @@ proc `[]`*(node: JsonNode, name: string): JsonNode {.inline.} = ## If the value at `name` does not exist, returns nil assert(not isNil(node)) assert(node.kind == JObject) - result = node.fields.getOrDefault(name) + result = node.fields[name] proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} = ## Gets the node at `index` in an Array. Result is undefined if `index` @@ -838,20 +838,20 @@ proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} = proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode = ## Traverses the node and gets the given value. If any of the - ## keys do not exist, returns nil. Also returns nil if one of the - ## intermediate data structures is not an object + ## keys do not exist, returns ``nil``. Also returns ``nil`` if one of the + ## intermediate data structures is not an object. result = node for key in keys: - if isNil(result) or result.kind!=JObject: + if isNil(result) or result.kind != JObject: return nil - result=result[key] + result = result.fields.getOrDefault(key) proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) = ## Traverses the node and tries to set the value at the given location - ## to `value` If any of the keys are missing, they are added + ## to ``value``. If any of the keys are missing, they are added. var node = node for i in 0..(keys.len-2): - if isNil(node[keys[i]]): + if not node.hasKey(keys[i]): node[keys[i]] = newJObject() node = node[keys[i]] node[keys[keys.len-1]] = value @@ -1217,16 +1217,6 @@ when false: # To get that we shall use, obj["json"] when isMainModule: - when not defined(js): - var parsed = parseFile("tests/testdata/jsontest.json") - - try: - discard parsed["key2"][12123] - doAssert(false) - except IndexError: doAssert(true) - - var parsed2 = parseFile("tests/testdata/jsontest2.json") - doAssert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}") let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd", "c": "\ud83c\udf83", "d": "\u00E6"}""" # nil passthrough @@ -1314,3 +1304,19 @@ when isMainModule: var j4 = %*{"test": nil} doAssert j4 == %{"test": newJNull()} + + echo("99% of tests finished. Going to try loading file.") + + # Test loading of file. + when not defined(js): + var parsed = parseFile("tests/testdata/jsontest.json") + + try: + discard parsed["key2"][12123] + doAssert(false) + except IndexError: doAssert(true) + + var parsed2 = parseFile("tests/testdata/jsontest2.json") + doAssert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}") + + echo("Tests succeeded!") From b22305758dc7c2f1cf7d46173c9f0378a89926f4 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 4 Apr 2016 21:52:49 +0100 Subject: [PATCH 055/674] Fix deprecation warning in net module. --- lib/pure/net.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 6888eb59f4..5de6667ddc 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1377,5 +1377,7 @@ proc connect*(socket: Socket, address: string, port = Port(0), when defineSsl: if socket.isSSL: socket.fd.setBlocking(true) + {.warning[Deprecated]: off.} doAssert socket.handshake() + {.warning[Deprecated]: on.} socket.fd.setBlocking(true) From 1446dc87c301268869223e32e7efdc9c76711bad Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 4 Apr 2016 22:50:31 +0100 Subject: [PATCH 056/674] `await x` where x is Fut var now reads after yield. Fixes #3964. --- lib/pure/asyncdispatch.nim | 30 +++++++++++++++++++++++++----- tests/async/tasyncfile.nim | 2 +- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index cc337452f0..01b53cb12c 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1316,6 +1316,23 @@ proc generateExceptionCheck(futSym, ) result.add elseNode +template useVar(result: var NimNode, futureVarNode: NimNode, valueReceiver, + rootReceiver: expr, fromNode: NimNode) = + ## Params: + ## futureVarNode: The NimNode which is a symbol identifying the Future[T] + ## variable to yield. + ## fromNode: Used for better debug information (to give context). + ## valueReceiver: The node which defines an expression that retrieves the + ## future's value. + ## + ## rootReceiver: ??? TODO + # -> yield future + result.add newNimNode(nnkYieldStmt, fromNode).add(futureVarNode) + # -> future.read + valueReceiver = newDotExpr(futureVarNode, newIdentNode("read")) + result.add generateExceptionCheck(futureVarNode, tryStmt, rootReceiver, + fromNode) + template createVar(result: var NimNode, futSymName: string, asyncProc: NimNode, valueReceiver, rootReceiver: expr, @@ -1323,9 +1340,7 @@ template createVar(result: var NimNode, futSymName: string, result = newNimNode(nnkStmtList, fromNode) var futSym = genSym(nskVar, "future") result.add newVarStmt(futSym, asyncProc) # -> var future = y - result.add newNimNode(nnkYieldStmt, fromNode).add(futSym) # -> yield future - valueReceiver = newDotExpr(futSym, newIdentNode("read")) # -> future.read - result.add generateExceptionCheck(futSym, tryStmt, rootReceiver, fromNode) + useVar(result, futSym, valueReceiver, rootReceiver, fromNode) proc processBody(node, retFutureSym: NimNode, subTypeIsVoid: bool, @@ -1352,7 +1367,11 @@ proc processBody(node, retFutureSym: NimNode, case node[1].kind of nnkIdent, nnkInfix: # await x - result = newNimNode(nnkYieldStmt, node).add(node[1]) # -> yield x + result = newNimNode(nnkStmtList, node) + var futureValue: NimNode + result.useVar(node[1], futureValue, futureValue, node) + # -> yield x + # -> x.read() of nnkCall, nnkCommand: # await foo(p, x) var futureValue: NimNode @@ -1550,6 +1569,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = for i in 0 .. Date: Tue, 5 Apr 2016 19:45:46 +1000 Subject: [PATCH 057/674] Add `import sharedlist` when `hasThreadSupport` Without this change, a user's Nim code won't compile if they're using both threads & the mark-and-sweep GC: lib/system/gc_ms.nim(75, 18) Error: undeclared identifier: 'SharedList' toDispose: SharedList[pointer] ^ This small code block addition was copied from "lib/system/gc.nim" (where it appears directly after a `when defined(memProfiler)` block also). --- lib/system/gc_ms.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index c764571b1b..ec69f6e5fe 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -28,6 +28,9 @@ template mulThreshold(x): expr {.immediate.} = x * 2 when defined(memProfiler): proc nimProfile(requestedSize: int) + +when hasThreadSupport: + import sharedlist type WalkOp = enum From 46ee026e77921b25e6f09ff5a5f7f1e9bd6afefe Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 5 Apr 2016 12:11:37 +0100 Subject: [PATCH 058/674] Many additions to readme. --- readme.md | 104 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 82 insertions(+), 22 deletions(-) diff --git a/readme.md b/readme.md index 27b2273f0c..fbaa5fd320 100644 --- a/readme.md +++ b/readme.md @@ -1,18 +1,9 @@ -# Nim Compiler - -[![Join the Chat at irc.freenode.net#nim](https://img.shields.io/badge/IRC-join_chat_in_%23nim-blue.svg)](https://webchat.freenode.net/?channels=nim) -[![Get help](https://img.shields.io/badge/Forum-get%20help-4eb899.svg)](http://forum.nim-lang.org) -[![Stackoverflow](https://img.shields.io/badge/stackoverflow-use_%23nim_tag-yellow.svg)](http://stackoverflow.com/questions/tagged/nim?sort=newest&pageSize=15) -[![Follow @nim_lang!](https://img.shields.io/twitter/follow/nim_lang.svg?style=social)](https://twitter.com/nim_lang) - -[![Travis](https://img.shields.io/travis/nim-lang/Nim.svg)](https://travis-ci.org/nim-lang/Nim) - -[![Contribute to Nim via Gratipay!](https://img.shields.io/gratipay/team/nim.svg)](https://gratipay.com/nim/) -[![Bountysource](https://img.shields.io/bountysource/team/nim/activity.svg)](https://www.bountysource.com/teams/nim) - +# Nim [![Build Status](https://travis-ci.org/nim-lang/Nim.svg?branch=devel)](https://travis-ci.org/nim-lang/Nim) This repo contains the Nim compiler, Nim's stdlib, tools and -documentation. +documentation. For more information about Nim, including downloads +and documentation for the latest release, check out +[Nim's website](http://nim-lang.org). ## Compiling Compiling the Nim compiler is quite straightforward. Because @@ -48,14 +39,15 @@ $ bin/nim c koch $ ./koch boot -d:release ``` -``koch install [dir]`` may then be used to install Nim, but lots of things -don't work then so don't do that. Add it to your PATH instead. More ``koch`` -related options are documented in [doc/koch.txt](doc/koch.txt). +You should then add the ``bin`` directory to your PATH, to make it easily +executable on your system. The above steps can be performed on Windows in a similar fashion, the ``build.bat`` and ``build64.bat`` (for x86_64 systems) are provided to be used instead of ``build.sh``. +The ``koch`` tool is the Nim build tool, more ``koch`` related options are +documented in [doc/koch.txt](doc/koch.txt). ## Nimble [Nimble](https://github.com/nim-lang/nimble) is Nim's package manager. For the @@ -66,12 +58,80 @@ the easiest way of installing Nimble is via: $ nim e install_nimble.nims ``` -## Getting help -A [forum](http://forum.nim-lang.org/) is available if you have any -questions, and you can also get help in the IRC channel on -[Freenode](irc://irc.freenode.net/nim) in #nim. If you ask questions on -[StackOverflow use the nim -tag](http://stackoverflow.com/questions/tagged/nim). +**Warning:** If you install Nimble this way, you will not be able to use binary +Nimble packages or update Nimble easily. +The [Nimble readme](https://github.com/nim-lang/nimble#installation) +provides thorough instructions on how to install Nimble, so that this isn't a +problem. + +## Community +[![Join the Chat at irc.freenode.net#nim](https://img.shields.io/badge/IRC-join_chat_in_%23nim-blue.svg)](https://webchat.freenode.net/?channels=nim) +[![Get help](https://img.shields.io/badge/Forum-get%20help-4eb899.svg)](http://forum.nim-lang.org) +[![Stackoverflow](https://img.shields.io/badge/stackoverflow-use_%23nim_tag-yellow.svg)](http://stackoverflow.com/questions/tagged/nim?sort=newest&pageSize=15) +[![Follow @nim_lang!](https://img.shields.io/twitter/follow/nim_lang.svg?style=social)](https://twitter.com/nim_lang) + +* The [forum](http://forum.nim-lang.org/) - the best place to ask questions and to discuss Nim. +* [IRC (Freenode#nim)](https://webchat.freenode.net/?channels=nim) - the best place to discuss + Nim in real-time, this is also where most development decision get made! +* [Stackoverflow](http://stackoverflow.com/questions/tagged/nim) + +## Contributing + +[![Contribute to Nim via Gratipay!](https://img.shields.io/gratipay/team/nim.svg)](https://gratipay.com/nim/) +[![Bountysource](https://img.shields.io/bountysource/team/nim/activity.svg)](https://www.bountysource.com/teams/nim) + +We welcome everyone's contributions to Nim. No matter how small or large +the contribution is, anything from small spelling fixes to large modules +intended to be included in the standard library are accepted. Before +you get started, you should know the following about this repositories +structure: + +* ``bin/``, ``build/`` - these directories are empty, but are used when Nim is built. +* ``compiler/`` - the compiler source code, all the Nim source code files in this + directory implement the compiler. This also includes nimfix, and plugins + which live in ``compiler/nimfix`` and ``compiler/plugins`` + respectively. Nimsuggest used to live in the ``compiler`` directory also, + but was moved to https://github.com/nim-lang/nimsuggest. +* ``config/`` - the configuration for the compiler and documentation generator. +* ``doc/`` - the documentation files in reStructuredText format. +* ``lib/`` - where the standard library lives. + * ``pure/`` - modules in the standard library written in pure Nim. + * ``impure/`` - modules in the standard library written in pure Nim which + depend on libraries written in other languages. + * ``wrappers/`` - modules which wrap libraries written in other languages. +* ``tests/`` - contains tests for the compiler and standard library, organised by + category. +* ``tools/`` - the tools including ``niminst`` and ``nimweb``, most of these are invoked + via ``koch``. +* ``web/`` - the Nim website (http://nim-lang.org). +* ``koch.nim`` - tool used to bootstrap Nim, generate C sources, build the website, documentation + and more. + +Most importantly, the ``koch`` tool can be used to run the test suite. To do so compile it first +by executing ``nim c koch``, then execute ``./koch tests``. The test suite takes a while to run, +but you can run specific tests by specifying a category to run, for example ``./koch tests cat async``. + +Make sure that the tests all pass before +[submitting your pull request](https://help.github.com/articles/using-pull-requests/). +If you're short on time, you can +just run the tests specific to your change. Just run the category which corresponds to the change +you've made. When you create your pull request, Travis CI will verify that all the tests pass +anyway. + +If you're looking for things to do, take a look at our +[issue tracker](https://github.com/nim-lang/Nim/issues). There is always plenty of issues +labelled [``Easy``](https://github.com/nim-lang/Nim/labels/Easy), these should be a good +starting point if this is your first contribution to Nim. + +You can also help with the development of Nim by making donations. You can do so +in many ways: + +* [Gratipay](https://gratipay.com/nim/) +* [Bountysource](https://www.bountysource.com/teams/nim) +* Bitcoin - 1BXfuKM2uvoD6mbx4g5xM3eQhLzkCK77tJ + +Finally, if you have any questions feel free to submit a question on the issue tracker, +on the [Nim forum](http://forum.nim-lang.org), or on IRC. ## License The compiler and the standard library are licensed under the MIT license, From 25abb7c2b671d3ea6d28aa871cd3409a0dae8795 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Tue, 5 Apr 2016 20:51:13 +0800 Subject: [PATCH 059/674] tester: allow filtering tests by target --- tests/testament/specs.nim | 9 +++++++++ tests/testament/tester.nim | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/tests/testament/specs.nim b/tests/testament/specs.nim index bab17d2cd1..3f40a53420 100644 --- a/tests/testament/specs.nim +++ b/tests/testament/specs.nim @@ -107,6 +107,15 @@ proc specDefaults*(result: var TSpec) = result.tline = 0 result.tcolumn = 0 +proc parseTargets*(value: string): set[TTarget] = + for v in value.normalize.split: + case v + of "c": result.incl(targetC) + of "cpp", "c++": result.incl(targetCpp) + of "objc": result.incl(targetObjC) + of "js": result.incl(targetJS) + else: echo "target ignored: " & v + proc parseSpec*(filename: string): TSpec = specDefaults(result) result.file = filename diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim index b1e8ac0992..c0b0881249 100644 --- a/tests/testament/tester.nim +++ b/tests/testament/tester.nim @@ -33,6 +33,7 @@ Options: --print also print results to the console --failing only show failing/ignored tests --pedantic return non-zero status code if there are failures + --targets:"c c++ js objc" run tests for specified targets (default: all) """ % resultsFile type @@ -60,6 +61,8 @@ let pegSuccess = peg"'Hint: operation successful'.*" pegOfInterest = pegLineError / pegOtherError +var targets = {low(TTarget)..high(TTarget)} + proc callCompiler(cmdTemplate, filename, options: string, target: TTarget): TSpec = let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target], @@ -275,6 +278,11 @@ proc analyzeAndConsolidateOutput(s: string): string = proc testSpec(r: var TResults, test: TTest) = # major entry point for a single test + if test.target notin targets: + r.addResult(test, "", "", reIgnored) + inc(r.skipped) + return + let tname = test.name.addFileExt(".nim") inc(r.total) var expected: TSpec @@ -394,6 +402,7 @@ proc main() = var optPrintResults = false var optFailing = false var optPedantic = false + var p = initOptParser() p.next() while p.kind == cmdLongoption: @@ -401,6 +410,7 @@ proc main() = of "print", "verbose": optPrintResults = true of "failing": optFailing = true of "pedantic": optPedantic = true + of "targets": targets = parseTargets(p.val) else: quit Usage p.next() if p.kind != cmdArgument: quit Usage From 796f4e917c9164c456d8152fb7d57d566f6148d2 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Wed, 6 Apr 2016 00:01:57 +0800 Subject: [PATCH 060/674] untaint command line option for parsing --- tests/testament/tester.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim index c0b0881249..ad687d3add 100644 --- a/tests/testament/tester.nim +++ b/tests/testament/tester.nim @@ -410,7 +410,7 @@ proc main() = of "print", "verbose": optPrintResults = true of "failing": optFailing = true of "pedantic": optPedantic = true - of "targets": targets = parseTargets(p.val) + of "targets": targets = parseTargets(p.val.string) else: quit Usage p.next() if p.kind != cmdArgument: quit Usage From 3379646c1613c5a29864e5afd350bbf54cdd215c Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 5 Apr 2016 21:26:26 +0100 Subject: [PATCH 061/674] Add -d:nimJsonGet flag for json.[] and news entry. --- lib/pure/json.nim | 18 +++++++++++++++--- web/news.txt | 4 ++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 5df9de5fa4..5be0986640 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -56,6 +56,11 @@ import export tables.`$` +when defined(nimJsonGet): + {.pragma: deprecatedGet, deprecated.} +else: + {.pragma: deprecatedGet.} + type JsonEventKind* = enum ## enumeration of all events that may occur when parsing jsonError, ## an error occurred during parsing @@ -799,16 +804,23 @@ proc len*(n: JsonNode): int = of JObject: result = n.fields.len else: discard -proc `[]`*(node: JsonNode, name: string): JsonNode {.inline.} = +proc `[]`*(node: JsonNode, name: string): JsonNode {.inline, deprecatedGet.} = ## Gets a field from a `JObject`, which must not be nil. - ## If the value at `name` does not exist, returns nil + ## If the value at `name` does not exist, raises KeyError. + ## + ## **Note:** The behaviour of this procedure changed in version 0.14.0. To + ## get a list of usages and to restore the old behaviour of this procedure, + ## compile with the ``-d:nimJsonGet`` flag. assert(not isNil(node)) assert(node.kind == JObject) + when defined(nimJsonGet): + if not node.fields.hasKey(name): return nil result = node.fields[name] proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} = ## Gets the node at `index` in an Array. Result is undefined if `index` - ## is out of bounds + ## is out of bounds, but as long as array bound checks are enabled it will + ## result in an exception. assert(not isNil(node)) assert(node.kind == JArray) return node.elems[index] diff --git a/web/news.txt b/web/news.txt index 42d2aca99a..0a83503c14 100644 --- a/web/news.txt +++ b/web/news.txt @@ -28,6 +28,10 @@ Changes affecting backwards compatibility for more details. - The ``matchers`` module has been deprecated. See issue [#2446](https://github.com/nim-lang/Nim/issues/2446) for more details. +- The ``json.[]`` no longer returns ``nil`` when a key is not found. Instead it + raises a ``KeyError`` exception. You can compile with the ``-d:nimJsonGet`` + flag to get a list of usages of ``[]``, as well as to restore the operator's + previous behaviour. Library Additions From 082ba914bcc18958de9a271dc2fc4dccfe5ed2cf Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 5 Apr 2016 21:45:52 +0100 Subject: [PATCH 062/674] Prevent tester from checking for output diffs for actionRunNoSpec. --- tests/testament/tester.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim index b1e8ac0992..86e9fbc86d 100644 --- a/tests/testament/tester.nim +++ b/tests/testament/tester.nim @@ -336,7 +336,7 @@ proc testSpec(r: var TResults, test: TTest) = reExitCodesDiffer) return - if bufB != expectedOut: + if bufB != expectedOut and expected.action != actionRunNoSpec: if not (expected.substr and expectedOut in bufB): given.err = reOutputsDiffer r.addResult(test, expected.outp, bufB, reOutputsDiffer) From c36421f8e4f85a0a91b490afc1c3bca7da953ad9 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 5 Apr 2016 23:08:51 +0100 Subject: [PATCH 063/674] Fixes subexes tests which were broken in 73e48f9c9. --- lib/pure/subexes.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pure/subexes.nim b/lib/pure/subexes.nim index 5824ace811..22f29b77cd 100644 --- a/lib/pure/subexes.nim +++ b/lib/pure/subexes.nim @@ -390,11 +390,11 @@ when isMainModule: doAssert(("type MyEnum* = enum\n $', '2i'\n '{..}" % ["fieldA", "fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"]).replace(" \n", "\n") == - strutils.unindent """ + strutils.unindent(""" type MyEnum* = enum fieldA, fieldB, FiledClkad, fieldD, - fieldE, longishFieldName""") + fieldE, longishFieldName""", 6)) doAssert subex"$1($', '{2..})" % ["f", "a", "b", "c"] == "f(a, b, c)" @@ -404,8 +404,8 @@ when isMainModule: doAssert((subex("type\n Enum = enum\n $', '40c'\n '{..}") % [ "fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"]).replace(" \n", "\n") == - strutils.unindent """ + strutils.unindent(""" type Enum = enum fieldNameA, fieldNameB, fieldNameC, - fieldNameD""") + fieldNameD""", 6)) From d9ed61fa620a8196724cb51c4b18867cd03df7d9 Mon Sep 17 00:00:00 2001 From: coffeepots Date: Wed, 6 Apr 2016 10:36:17 +0100 Subject: [PATCH 064/674] Deprecate timeToTimeInfo, add str->time procs * depreciate timeToTimeInfo, add str->time procs initTime allows creating times from strings. initTimeFromStr offers a default format string compatible with $Time. timeToTimeInterval changed to work properly. * Spell {.deprecated.} correctly * deprecated timeToTimeInfo, removed initTime procs Is it even worth depreciating timeToTimeInfo rather than just removing it, considering it's just wrong and we have getLocalTime and getGMTime that actually work? Also, if I'm renaming timeToTimeInfo -> toTimeInfo etc, isn't the deprecated tag kind of redundant? * Updated names for toTime and toTimeInterval procs * Added type to toTime template This should allow compilation of os.nim now that toTime is defined in times.nim. * Updated toTime template to use {.gensym.} Local templates default to 'bind' semantics, not 'gensym'. This was causing a failure to 'see' the local toTime template. --- lib/pure/os.nim | 2 +- lib/pure/times.nim | 81 +++++++++++++++++++++++++--------------------- 2 files changed, 45 insertions(+), 38 deletions(-) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 1a2c6d537a..dee227c69d 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1452,7 +1452,7 @@ template rawToFormalFileInfo(rawInfo, formalInfo): expr = ## 'rawInfo' is either a 'TBY_HANDLE_FILE_INFORMATION' structure on Windows, ## or a 'Stat' structure on posix when defined(Windows): - template toTime(e): expr = winTimeToUnixTime(rdFileTime(e)) + template toTime(e: FILETIME): expr {.gensym.} = winTimeToUnixTime(rdFileTime(e)) # local templates default to bind semantics template merge(a, b): expr = a or (b shl 32) formalInfo.id.device = rawInfo.dwVolumeSerialNumber formalInfo.id.file = merge(rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 29ae52d479..6afedefb5d 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -182,7 +182,14 @@ proc getGMTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], benign.} ## converts the calendar time `t` to broken-down time representation, ## expressed in Coordinated Universal Time (UTC). -proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], benign.} +proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], benign, deprecated.} + ## converts a broken-down time structure to + ## calendar time representation. The function ignores the specified + ## contents of the structure members `weekday` and `yearday` and recomputes + ## them from the other information in the broken-down time structure. + ## **Warning:** This procedure is deprecated. Use toTime instead. + +proc toTime*(timeInfo: TimeInfo): Time {.tags: [], benign.} ## converts a broken-down time structure to ## calendar time representation. The function ignores the specified ## contents of the structure members `weekday` and `yearday` and recomputes @@ -356,7 +363,7 @@ proc `+`*(a: TimeInfo, interval: TimeInterval): TimeInfo = ## ## **Note:** This has been only briefly tested and it may not be ## very accurate. - let t = toSeconds(timeInfoToTime(a)) + let t = toSeconds(toTime(a)) let secs = toSeconds(a, interval) result = getLocalTime(fromSeconds(t + secs)) @@ -365,7 +372,7 @@ proc `-`*(a: TimeInfo, interval: TimeInterval): TimeInfo = ## ## **Note:** This has been only briefly tested, it is inaccurate especially ## when you subtract so much that you reach the Julian calendar. - let t = toSeconds(timeInfoToTime(a)) + let t = toSeconds(toTime(a)) var intval: TimeInterval intval.milliseconds = - interval.milliseconds intval.seconds = - interval.seconds @@ -517,6 +524,11 @@ when not defined(JS): # because the header of mktime is broken in my version of libc return mktime(timeInfoToTM(cTimeInfo)) + proc toTime(timeInfo: TimeInfo): Time = + var cTimeInfo = timeInfo # for C++ we have to make a copy, + # because the header of mktime is broken in my version of libc + return mktime(timeInfoToTM(cTimeInfo)) + proc toStringTillNL(p: cstring): string = result = "" var i = 0 @@ -618,7 +630,16 @@ elif defined(JS): result.setFullYear(timeInfo.year) result.setDate(timeInfo.monthday) - proc `$`(timeInfo: TimeInfo): string = return $(timeInfoToTime(timeInfo)) + proc toTime*(timeInfo: TimeInfo): Time = + result = internGetTime() + result.setSeconds(timeInfo.second) + result.setMinutes(timeInfo.minute) + result.setHours(timeInfo.hour) + result.setMonth(ord(timeInfo.month)) + result.setFullYear(timeInfo.year) + result.setDate(timeInfo.monthday) + + proc `$`(timeInfo: TimeInfo): string = return $(toTime(timeInfo)) proc `$`(time: Time): string = return $time.toLocaleString() proc `-` (a, b: Time): int64 = @@ -708,24 +729,24 @@ proc years*(y: int): TimeInterval {.inline.} = proc `+=`*(t: var Time, ti: TimeInterval) = ## modifies `t` by adding the interval `ti` - t = timeInfoToTime(getLocalTime(t) + ti) + t = toTime(getLocalTime(t) + ti) proc `+`*(t: Time, ti: TimeInterval): Time = ## adds the interval `ti` to Time `t` ## by converting to localTime, adding the interval, and converting back ## ## ``echo getTime() + 1.day`` - result = timeInfoToTime(getLocalTime(t) + ti) + result = toTime(getLocalTime(t) + ti) proc `-=`*(t: var Time, ti: TimeInterval) = ## modifies `t` by subtracting the interval `ti` - t = timeInfoToTime(getLocalTime(t) - ti) + t = toTime(getLocalTime(t) - ti) proc `-`*(t: Time, ti: TimeInterval): Time = ## adds the interval `ti` to Time `t` ## ## ``echo getTime() - 1.day`` - result = timeInfoToTime(getLocalTime(t) - ti) + result = toTime(getLocalTime(t) - ti) proc formatToken(info: TimeInfo, token: string, buf: var string) = ## Helper of the format proc to parse individual tokens. @@ -1193,7 +1214,7 @@ proc parse*(value, layout: string): TimeInfo = parseToken(info, token, value, j) token = "" # Reset weekday as it might not have been provided and the default may be wrong - info.weekday = getLocalTime(timeInfoToTime(info)).weekday + info.weekday = getLocalTime(toTime(info)).weekday return info # Leap year calculations are adapted from: @@ -1254,8 +1275,9 @@ proc getDayOfWeekJulian*(day, month, year: int): WeekDay = d = (5 + day + y + (y div 4) + (31*m) div 12) mod 7 result = d.WeekDay -proc timeToTimeInfo*(t: Time): TimeInfo = +proc timeToTimeInfo*(t: Time): TimeInfo {.deprecated.} = ## Converts a Time to TimeInfo. + ## **Warning:** This procedure is deprecated. Use getLocalTime or getGMTime instead. let secs = t.toSeconds().int daysSinceEpoch = secs div secondsInDay @@ -1286,34 +1308,19 @@ proc timeToTimeInfo*(t: Time): TimeInfo = s = daySeconds mod secondsInMin result = TimeInfo(year: y, yearday: yd, month: m, monthday: md, weekday: wd, hour: h, minute: mi, second: s) -proc timeToTimeInterval*(t: Time): TimeInterval = +proc timeToTimeInterval*(t: Time): TimeInterval {.deprecated.} = ## Converts a Time to a TimeInterval. - - let - secs = t.toSeconds().int - daysSinceEpoch = secs div secondsInDay - (yearsSinceEpoch, daysRemaining) = countYearsAndDays(daysSinceEpoch) - daySeconds = secs mod secondsInDay - - result.years = yearsSinceEpoch + epochStartYear - - var - mon = mJan - days = daysRemaining - daysInMonth = getDaysInMonth(mon, result.years) - - # calculate month and day remainder - while days > daysInMonth and mon <= mDec: - days -= daysInMonth - mon.inc - daysInMonth = getDaysInMonth(mon, result.years) - - result.months = mon.int + 1 # month is 1 indexed int - result.days = days - result.hours = daySeconds div secondsInHour + 1 - result.minutes = (daySeconds mod secondsInHour) div secondsInMin - result.seconds = daySeconds mod secondsInMin + ## **Warning:** This procedure is deprecated. Use toTimeInterval instead. # Milliseconds not available from Time + var tInfo = t.getLocalTime() + initInterval(0, tInfo.second, tInfo.minute, tInfo.hour, tInfo.weekday.ord, tInfo.month.ord, tInfo.year) + +proc toTimeInterval*(t: Time): TimeInterval = + ## Converts a Time to a TimeInterval. + # Milliseconds not available from Time + var tInfo = t.getLocalTime() + initInterval(0, tInfo.second, tInfo.minute, tInfo.hour, tInfo.weekday.ord, tInfo.month.ord, tInfo.year) + when isMainModule: # this is testing non-exported function @@ -1328,6 +1335,6 @@ when isMainModule: assert toSeconds(t4L, initInterval(days=1)) == toSeconds(t4, initInterval(days=1)) assert toSeconds(t4L, initInterval(months=1)) == toSeconds(t4, initInterval(months=1)) assert toSeconds(t4L, initInterval(years=1)) == toSeconds(t4, initInterval(years=1)) - + # Further tests are in tests/stdlib/ttime.nim # koch test c stdlib From 9b6fda144a08733aad91b43b043fc3b89b72ed3c Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 6 Apr 2016 10:45:39 +0100 Subject: [PATCH 065/674] Some documentation fixes in times module. --- lib/pure/times.nim | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 6afedefb5d..e0ee884a80 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -187,7 +187,9 @@ proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], benign, deprecated.} ## calendar time representation. The function ignores the specified ## contents of the structure members `weekday` and `yearday` and recomputes ## them from the other information in the broken-down time structure. - ## **Warning:** This procedure is deprecated. Use toTime instead. + ## + ## **Warning:** This procedure is deprecated since version 0.14.0. + ## Use ``toTime`` instead. proc toTime*(timeInfo: TimeInfo): Time {.tags: [], benign.} ## converts a broken-down time structure to @@ -1225,7 +1227,7 @@ proc parse*(value, layout: string): TimeInfo = proc countLeapYears*(yearSpan: int): int = ## Returns the number of leap years spanned by a given number of years. ## - ## Note: for leap years, start date is assumed to be 1 AD. + ## **Note:** For leap years, start date is assumed to be 1 AD. ## counts the number of leap years up to January 1st of a given year. ## Keep in mind that if specified year is a leap year, the leap day ## has not happened before January 1st of that year. @@ -1260,13 +1262,14 @@ proc getDayOfWeek*(day, month, year: int): WeekDay = y = year - a m = month + (12*a) - 2 d = (day + y + (y div 4) - (y div 100) + (y div 400) + (31*m) div 12) mod 7 - # The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc. so we must correct - # for the WeekDay type. + # The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc. + # so we must correct for the WeekDay type. if d == 0: return dSun result = (d-1).WeekDay proc getDayOfWeekJulian*(day, month, year: int): WeekDay = - ## Returns the day of the week enum from day, month and year, according to the Julian calendar. + ## Returns the day of the week enum from day, month and year, + ## according to the Julian calendar. # Day & month start from one. let a = (14 - month) div 12 @@ -1277,7 +1280,9 @@ proc getDayOfWeekJulian*(day, month, year: int): WeekDay = proc timeToTimeInfo*(t: Time): TimeInfo {.deprecated.} = ## Converts a Time to TimeInfo. - ## **Warning:** This procedure is deprecated. Use getLocalTime or getGMTime instead. + ## + ## **Warning:** This procedure is deprecated since version 0.14.0. + ## Use ``getLocalTime`` or ``getGMTime`` instead. let secs = t.toSeconds().int daysSinceEpoch = secs div secondsInDay @@ -1310,7 +1315,9 @@ proc timeToTimeInfo*(t: Time): TimeInfo {.deprecated.} = proc timeToTimeInterval*(t: Time): TimeInterval {.deprecated.} = ## Converts a Time to a TimeInterval. - ## **Warning:** This procedure is deprecated. Use toTimeInterval instead. + ## + ## **Warning:** This procedure is deprecated since version 0.14.0. + ## Use ``toTimeInterval`` instead. # Milliseconds not available from Time var tInfo = t.getLocalTime() initInterval(0, tInfo.second, tInfo.minute, tInfo.hour, tInfo.weekday.ord, tInfo.month.ord, tInfo.year) @@ -1335,6 +1342,6 @@ when isMainModule: assert toSeconds(t4L, initInterval(days=1)) == toSeconds(t4, initInterval(days=1)) assert toSeconds(t4L, initInterval(months=1)) == toSeconds(t4, initInterval(months=1)) assert toSeconds(t4L, initInterval(years=1)) == toSeconds(t4, initInterval(years=1)) - + # Further tests are in tests/stdlib/ttime.nim # koch test c stdlib From 181c834a932ac98bc4451c6f0110cf9816b9808b Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Tue, 5 Apr 2016 22:55:00 +0300 Subject: [PATCH 066/674] Added json.getOrDefault along with {singleKey} tr optimization. --- lib/pure/json.nim | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 5be0986640..b9da8a0dd0 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -858,6 +858,14 @@ proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode = return nil result = result.fields.getOrDefault(key) +proc getOrDefault*(node: JsonNode, key: string): JsonNode = + ## Gets a field from a `node`. If `node` is nil or not an object or + ## value at `key` does not exist, returns nil + if not isNil(node) and node.kind == JObject: + result = node.fields.getOrDefault(key) + +template simpleGetOrDefault*{`{}`(node, [key])}(node: JsonNode, key: string): JsonNode = node.getOrDefault(key) + proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) = ## Traverses the node and tries to set the value at the given location ## to ``value``. If any of the keys are missing, they are added. From b1b14a5e7b3f4f86fc32ab03c5a1666043a9c383 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 6 Apr 2016 22:24:32 +0100 Subject: [PATCH 067/674] Add Bountysource banner to website. --- tools/website.tmpl | 12 +++++++++++- web/assets/style.css | 11 +++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/tools/website.tmpl b/tools/website.tmpl index 50152a0516..6ae9758399 100644 --- a/tools/website.tmpl +++ b/tools/website.tmpl @@ -6,13 +6,23 @@ $c.projectTitle - + #if len(rss) > 0: #end if + +