diff options
Diffstat (limited to 'lib/pure')
-rw-r--r-- | lib/pure/math.nim | 74 | ||||
-rw-r--r-- | lib/pure/os.nim | 4 | ||||
-rw-r--r-- | lib/pure/parseutils.nim | 32 | ||||
-rw-r--r-- | lib/pure/terminal.nim | 35 |
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 = |