summary refs log tree commit diff stats
path: root/lib/pure
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pure')
-rw-r--r--lib/pure/math.nim74
-rw-r--r--lib/pure/os.nim4
-rw-r--r--lib/pure/parseutils.nim32
-rw-r--r--lib/pure/terminal.nim35
4 files changed, 105 insertions, 40 deletions
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index a9e9010f6..494dfc4c8 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -161,6 +161,8 @@ proc randomize*(seed: int) {.benign.}
 when not defined(JS):
   proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".}
     ## computes the square root of `x`.
+  proc cbrt*(x: float): float {.importc: "cbrt", header: "<math.h>".}
+    ## computes the cubic root of `x`
   
   proc ln*(x: float): float {.importc: "log", header: "<math.h>".}
     ## computes ln(x).
@@ -200,30 +202,64 @@ when not defined(JS):
   proc tanh*(x: float): float {.importc: "tanh", header: "<math.h>".}
   proc pow*(x, y: float): float {.importc: "pow", header: "<math.h>".}
     ## computes x to power raised of y.
+  
+  proc erf*(x: float): float {.importc: "erf", header: "<math.h>".}
+    ## The error function
+  proc erfc*(x: float): float {.importc: "erfc", header: "<math.h>".}
+    ## The complementary error function
+  
+  proc lgamma*(x: float): float {.importc: "lgamma", header: "<math.h>".}
+    ## Natural log of the gamma function
+  proc tgamma*(x: float): float {.importc: "tgamma", header: "<math.h>".}
+    ## The gamma function
     
   # C procs:
-  proc srand(seed: cint) {.importc: "srand", header: "<stdlib.h>".}
-  proc rand(): cint {.importc: "rand", header: "<stdlib.h>".}
+  when defined(vcc):
+    # The "secure" random, available from Windows XP
+    # https://msdn.microsoft.com/en-us/library/sxtz2fa8.aspx
+    # Present in some variants of MinGW but not enough to justify
+    # `when defined(windows)` yet
+    proc rand_s(val: var cuint) {.importc: "rand_s", header: "<stdlib.h>".}
+    # To behave like the normal version
+    proc rand(): cuint = rand_s(result)
+  else:
+    proc srand(seed: cint) {.importc: "srand", header: "<stdlib.h>".}
+    proc rand(): cint {.importc: "rand", header: "<stdlib.h>".}
   
   when not defined(windows):
     proc srand48(seed: clong) {.importc: "srand48", header: "<stdlib.h>".}
     proc drand48(): float {.importc: "drand48", header: "<stdlib.h>".}
     proc random(max: float): float =
       result = drand48() * max
-  when defined(windows):
-    proc random(max: float): float =
-      # we are hardcodeing this because
-      # importcing macros is extremely problematic
-      # and because the value is publicly documented
-      # on MSDN and very unlikely to change
-      const rand_max = 32767
-      result = (float(rand()) / float(rand_max)) * max
-  proc randomize() =
-    randomize(cast[int](epochTime()))
-
-  proc randomize(seed: int) =
-    srand(cint(seed))
-    when declared(srand48): srand48(seed)
+  else:
+    when defined(vcc): # Windows with Visual C
+      proc random(max: float): float =
+        # we are hardcoding this because
+        # importc-ing macros is extremely problematic
+        # and because the value is publicly documented
+        # on MSDN and very unlikely to change
+        # See https://msdn.microsoft.com/en-us/library/296az74e.aspx
+        const rand_max = 4294967295 # UINT_MAX
+        result = (float(rand()) / float(rand_max)) * max
+      proc randomize() = discard
+      proc randomize(seed: int) = discard
+    else: # Windows with another compiler
+      proc random(max: float): float =
+        # we are hardcoding this because
+        # importc-ing macros is extremely problematic
+        # and because the value is publicly documented
+        # on MSDN and very unlikely to change
+        const rand_max = 32767
+        result = (float(rand()) / float(rand_max)) * max
+  
+  when not defined(vcc): # the above code for vcc uses `discard` instead
+    # this is either not Windows or is Windows without vcc
+    proc randomize() =
+      randomize(cast[int](epochTime()))
+    proc randomize(seed: int) =
+      srand(cint(seed)) # rand_s doesn't use srand
+      when declared(srand48): srand48(seed)
+    
   proc random(max: int): int =
     result = int(rand()) mod max
 
@@ -387,3 +423,9 @@ 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
+  assert(erf(6.0) > erf(5.0))
+  assert(erfc(6.0) < erfc(5.0))
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 4deb79f86..f29505590 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -1304,7 +1304,9 @@ iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {.
           when defined(linux) or defined(macosx) or defined(bsd):
             if x.d_type != DT_UNKNOWN:
               if x.d_type == DT_DIR: k = pcDir
-              if x.d_type == DT_LNK: k = succ(k)
+              if x.d_type == DT_LNK:
+                if dirExists(y): k = pcLinkToDir
+                else: k = succ(k)
               yield (k, y)
               continue
 
diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim
index c07b713de..b3708838a 100644
--- a/lib/pure/parseutils.nim
+++ b/lib/pure/parseutils.nim
@@ -26,7 +26,7 @@ proc toLower(c: char): char {.inline.} =
   result = if c in {'A'..'Z'}: chr(ord(c)-ord('A')+ord('a')) else: c
 
 proc parseHex*(s: string, number: var int, start = 0): int {.
-  rtl, extern: "npuParseHex", noSideEffect.}  = 
+  rtl, extern: "npuParseHex", noSideEffect.}  =
   ## Parses a hexadecimal number and stores its value in ``number``.
   ##
   ## Returns the number of the parsed characters or 0 in case of an error. This
@@ -49,7 +49,7 @@ proc parseHex*(s: string, number: var int, start = 0): int {.
   var foundDigit = false
   if s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2)
   elif s[i] == '#': inc(i)
-  while true: 
+  while true:
     case s[i]
     of '_': discard
     of '0'..'9':
@@ -66,13 +66,13 @@ proc parseHex*(s: string, number: var int, start = 0): int {.
   if foundDigit: result = i-start
 
 proc parseOct*(s: string, number: var int, start = 0): int  {.
-  rtl, extern: "npuParseOct", noSideEffect.} = 
+  rtl, extern: "npuParseOct", noSideEffect.} =
   ## parses an octal number and stores its value in ``number``. Returns
   ## the number of the parsed characters or 0 in case of an error.
   var i = start
   var foundDigit = false
   if s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2)
-  while true: 
+  while true:
     case s[i]
     of '_': discard
     of '0'..'7':
@@ -93,7 +93,7 @@ proc parseIdent*(s: string, ident: var string, start = 0): int =
     result = i-start
 
 proc parseIdent*(s: string, start = 0): string =
-  ## parses an identifier and stores it in ``ident``. 
+  ## parses an identifier and stores it in ``ident``.
   ## Returns the parsed identifier or an empty string in case of an error.
   result = ""
   var i = start
@@ -101,14 +101,14 @@ proc parseIdent*(s: string, start = 0): string =
   if s[i] in IdentStartChars:
     inc(i)
     while s[i] in IdentChars: inc(i)
-    
+
     result = substr(s, start, i-1)
 
 proc parseToken*(s: string, token: var string, validChars: set[char],
                  start = 0): int {.inline, deprecated.} =
   ## parses a token and stores it in ``token``. Returns
   ## the number of the parsed characters or 0 in case of an error. A token
-  ## consists of the characters in `validChars`. 
+  ## consists of the characters in `validChars`.
   ##
   ## **Deprecated since version 0.8.12**: Use ``parseWhile`` instead.
   var i = start
@@ -126,13 +126,13 @@ proc skip*(s, token: string, start = 0): int {.inline.} =
   ## or 0 if there was no `token` at ``s[start]``.
   while result < token.len and s[result+start] == token[result]: inc(result)
   if result != token.len: result = 0
-  
+
 proc skipIgnoreCase*(s, token: string, start = 0): int =
   ## same as `skip` but case is ignored for token matching.
   while result < token.len and
       toLower(s[result+start]) == toLower(token[result]): inc(result)
   if result != token.len: result = 0
-  
+
 proc skipUntil*(s: string, until: set[char], start = 0): int {.inline.} =
   ## Skips all characters until one char from the set `until` is found
   ## or the end is reached.
@@ -154,7 +154,7 @@ proc parseUntil*(s: string, token: var string, until: set[char],
                  start = 0): int {.inline.} =
   ## parses a token and stores it in ``token``. Returns
   ## the number of the parsed characters or 0 in case of an error. A token
-  ## consists of the characters notin `until`. 
+  ## consists of the characters notin `until`.
   var i = start
   while i < s.len and s[i] notin until: inc(i)
   result = i-start
@@ -174,7 +174,7 @@ proc parseWhile*(s: string, token: var string, validChars: set[char],
                  start = 0): int {.inline.} =
   ## parses a token and stores it in ``token``. Returns
   ## the number of the parsed characters or 0 in case of an error. A token
-  ## consists of the characters in `validChars`. 
+  ## consists of the characters in `validChars`.
   var i = start
   while s[i] in validChars: inc(i)
   result = i-start
@@ -214,7 +214,7 @@ proc parseBiggestInt*(s: string, number: var BiggestInt, start = 0): int {.
   ## `EOverflow` is raised if an overflow occurs.
   var res: BiggestInt
   # use 'res' for exception safety (don't write to 'number' in case of an
-  # overflow exception:
+  # overflow exception):
   result = rawParseInt(s, res, start)
   number = res
 
@@ -246,7 +246,7 @@ proc parseFloat*(s: string, number: var float, start = 0): int {.
   result = parseBiggestFloat(s, bf, start)
   if result != 0:
     number = bf
-  
+
 type
   InterpolatedKind* = enum   ## describes for `interpolatedFragments`
                              ## which part of the interpolated string is
@@ -289,12 +289,12 @@ iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
           case s[j]
           of '{': inc nesting
           of '}':
-            if nesting == 0: 
+            if nesting == 0:
               inc j
               break
             dec nesting
           of '\0':
-            raise newException(ValueError, 
+            raise newException(ValueError,
               "Expected closing '}': " & substr(s, i, s.high))
           else: discard
           inc j
@@ -310,7 +310,7 @@ iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
         inc i # skip $
         kind = ikDollar
       else:
-        raise newException(ValueError, 
+        raise newException(ValueError,
           "Unable to parse a varible name at " & substr(s, i, s.high))
     else:
       while j < s.len and s[j] != '$': inc j
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
index 15e2eefec..2efdf72d5 100644
--- a/lib/pure/terminal.nim
+++ b/lib/pure/terminal.nim
@@ -406,22 +406,43 @@ proc isatty*(f: File): bool =
 
   result = isatty(getFileHandle(f)) != 0'i32
 
-proc styledEchoProcessArg(s: string) = write stdout, s
-proc styledEchoProcessArg(style: Style) = setStyle({style})
-proc styledEchoProcessArg(style: set[Style]) = setStyle style
-proc styledEchoProcessArg(color: ForegroundColor) = setForegroundColor color
-proc styledEchoProcessArg(color: BackgroundColor) = setBackgroundColor color
+type
+  TerminalCmd* = enum  ## commands that can be expressed as arguments
+    resetStyle         ## reset attributes
+
+template styledEchoProcessArg(s: string) = write stdout, s
+template styledEchoProcessArg(style: Style) = setStyle({style})
+template styledEchoProcessArg(style: set[Style]) = setStyle style
+template styledEchoProcessArg(color: ForegroundColor) = setForegroundColor color
+template styledEchoProcessArg(color: BackgroundColor) = setBackgroundColor color
+template styledEchoProcessArg(cmd: TerminalCmd) =
+  when cmd == resetStyle:
+    resetAttributes()
 
 macro styledEcho*(m: varargs[expr]): stmt =
   ## to be documented.
   let m = callsite()
+  var reset = false
   result = newNimNode(nnkStmtList)
 
   for i in countup(1, m.len - 1):
-    result.add(newCall(bindSym"styledEchoProcessArg", m[i]))
+    let item = m[i]
+    case item.kind
+    of nnkStrLit..nnkTripleStrLit:
+      if i == m.len - 1:
+        # optimize if string literal is last, just call writeln
+        result.add(newCall(bindSym"writeln", bindSym"stdout", item))
+        if reset: result.add(newCall(bindSym"resetAttributes"))
+        return
+      else:
+        # if it is string literal just call write, do not enable reset
+        result.add(newCall(bindSym"write", bindSym"stdout", item))
+    else:
+      result.add(newCall(bindSym"styledEchoProcessArg", item))
+      reset = true
 
   result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n")))
-  result.add(newCall(bindSym"resetAttributes"))
+  if reset: result.add(newCall(bindSym"resetAttributes"))
 
 when defined(nimdoc):
   proc getch*(): char =