mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-16 08:04:20 +00:00
Merge remote-tracking branch 'origin/devel' into appveyor
This commit is contained in:
@@ -75,7 +75,7 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
""" % [config["doc.googleAnalytics"]]
|
||||
""" % [config.getOrDefault"doc.googleAnalytics"]
|
||||
else:
|
||||
result.analytics = ""
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
|
||||
if s.kind != skEnumField:
|
||||
if s.kind notin ExportableSymKinds:
|
||||
internalError(s.info, "importAllSymbols: " & $s.kind)
|
||||
if exceptSet.empty or s.name.id notin exceptSet:
|
||||
if exceptSet.isNil or s.name.id notin exceptSet:
|
||||
rawImportSymbol(c, s)
|
||||
s = nextIter(i, fromMod.tab)
|
||||
|
||||
@@ -138,7 +138,7 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) =
|
||||
let s = a.sym
|
||||
if s.kind == skModule:
|
||||
importAllSymbolsExcept(c, s, exceptSet)
|
||||
elif exceptSet.empty or s.name.id notin exceptSet:
|
||||
elif exceptSet.isNil or s.name.id notin exceptSet:
|
||||
rawImportSymbol(c, s)
|
||||
of nkExportExceptStmt:
|
||||
localError(n.info, errGenerated, "'export except' not implemented")
|
||||
|
||||
@@ -15,7 +15,7 @@ import
|
||||
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
|
||||
cgen, jsgen, json, nversion,
|
||||
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
|
||||
tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists
|
||||
docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists
|
||||
|
||||
from magicsys import systemModule, resetSysTypes
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ proc addPackage(packages: StringTableRef, p: string) =
|
||||
let name = p.substr(0, x-1)
|
||||
if x < p.len:
|
||||
let version = p.substr(x+1)
|
||||
if packages[name] <. version:
|
||||
if packages.getOrDefault(name) <. version:
|
||||
packages[name] = version
|
||||
else:
|
||||
packages[name] = latest
|
||||
|
||||
@@ -86,7 +86,7 @@ type # please make sure we have under 32 options
|
||||
gcNone, gcBoehm, gcGo, gcMarkAndSweep, gcRefc, gcV2, gcGenerational
|
||||
|
||||
IdeCmd* = enum
|
||||
ideNone, ideSug, ideCon, ideDef, ideUse
|
||||
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus
|
||||
|
||||
var
|
||||
gIdeCmd*: IdeCmd
|
||||
@@ -173,7 +173,7 @@ proc existsConfigVar*(key: string): bool =
|
||||
result = hasKey(gConfigVars, key)
|
||||
|
||||
proc getConfigVar*(key: string): string =
|
||||
result = gConfigVars[key]
|
||||
result = gConfigVars.getOrDefault key
|
||||
|
||||
proc setConfigVar*(key, val: string) =
|
||||
gConfigVars[key] = val
|
||||
@@ -421,6 +421,7 @@ proc parseIdeCmd*(s: string): IdeCmd =
|
||||
of "con": ideCon
|
||||
of "def": ideDef
|
||||
of "use": ideUse
|
||||
of "dus": ideDus
|
||||
else: ideNone
|
||||
|
||||
proc `$`*(c: IdeCmd): string =
|
||||
@@ -429,4 +430,5 @@ proc `$`*(c: IdeCmd): string =
|
||||
of ideCon: "con"
|
||||
of ideDef: "def"
|
||||
of ideUse: "use"
|
||||
of ideDus: "dus"
|
||||
of ideNone: "none"
|
||||
|
||||
@@ -372,7 +372,7 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
|
||||
else:
|
||||
internalError(info, "decodeSym: no ident")
|
||||
#echo "decoding: {", ident.s
|
||||
result = r.syms[id]
|
||||
result = r.syms.getOrDefault(id)
|
||||
if result == nil:
|
||||
new(result)
|
||||
result.id = id
|
||||
@@ -491,7 +491,7 @@ proc processCompilerProcs(r: PRodReader, module: PSym) =
|
||||
inc(r.pos)
|
||||
var key = decodeVInt(r.s, r.pos)
|
||||
inc(r.pos) # #10
|
||||
var s = r.syms[key]
|
||||
var s = r.syms.getOrDefault(key)
|
||||
if s == nil:
|
||||
s = newStub(r, w, key)
|
||||
s.owner = module
|
||||
@@ -737,7 +737,7 @@ proc getReader(moduleId: int): PRodReader =
|
||||
return nil
|
||||
|
||||
proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
|
||||
result = r.syms[id]
|
||||
result = r.syms.getOrDefault(id)
|
||||
if result == nil:
|
||||
# load the symbol:
|
||||
var d = iiTableGet(r.index.tab, id)
|
||||
|
||||
@@ -309,6 +309,10 @@ proc suggestSym*(info: TLineInfo; s: PSym) {.inline.} =
|
||||
findUsages(info, s)
|
||||
elif gIdeCmd == ideDef:
|
||||
findDefinition(info, s)
|
||||
elif gIdeCmd == ideDus and s != nil:
|
||||
if isTracked(info, s.name.s.len):
|
||||
suggestResult(symToSuggest(s, isLocal=false, $ideDef))
|
||||
findUsages(info, s)
|
||||
|
||||
proc markUsed(info: TLineInfo; s: PSym) =
|
||||
incl(s.flags, sfUsed)
|
||||
@@ -366,7 +370,7 @@ proc suggestExpr*(c: PContext, node: PNode) =
|
||||
suggestCall(c, a, n, outputs)
|
||||
|
||||
dec(c.compilesContextId)
|
||||
if outputs > 0 and gIdeCmd != ideUse: suggestQuit()
|
||||
if outputs > 0 and gIdeCmd notin {ideUse, ideDus}: suggestQuit()
|
||||
|
||||
proc suggestStmt*(c: PContext, n: PNode) =
|
||||
suggestExpr(c, n)
|
||||
|
||||
@@ -825,11 +825,13 @@ proc flattenStmts(n: PNode) =
|
||||
var goOn = true
|
||||
while goOn:
|
||||
goOn = false
|
||||
for i in 0..<n.len:
|
||||
var i = 0
|
||||
while i < n.len:
|
||||
let it = n[i]
|
||||
if it.kind in {nkStmtList, nkStmtListExpr}:
|
||||
n.sons[i..i] = it.sons[0..<it.len]
|
||||
goOn = true
|
||||
inc i
|
||||
|
||||
proc liftDeferAux(n: PNode) =
|
||||
if n.kind in {nkStmtList, nkStmtListExpr}:
|
||||
|
||||
@@ -30,6 +30,14 @@ proc setResult*(a: VmArgs; v: string) =
|
||||
s[a.ra].node = newNode(nkStrLit)
|
||||
s[a.ra].node.strVal = v
|
||||
|
||||
proc setResult*(a: VmArgs; n: PNode) =
|
||||
var s: seq[TFullReg]
|
||||
move(s, cast[seq[TFullReg]](a.slots))
|
||||
if s[a.ra].kind != rkNode:
|
||||
myreset(s[a.ra])
|
||||
s[a.ra].kind = rkNode
|
||||
s[a.ra].node = n
|
||||
|
||||
proc setResult*(a: VmArgs; v: seq[string]) =
|
||||
var s: seq[TFullReg]
|
||||
move(s, cast[seq[TFullReg]](a.slots))
|
||||
|
||||
@@ -239,7 +239,7 @@ proc loadAny(p: var JsonParser, t: PType,
|
||||
result = newNode(nkNilLit)
|
||||
next(p)
|
||||
of jsonInt:
|
||||
result = tab[p.getInt]
|
||||
result = tab.getOrDefault(p.getInt)
|
||||
if result.isNil:
|
||||
raiseParseErr(p, "cannot load object with address " & $p.getInt)
|
||||
next(p)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Test high level features
|
||||
|
||||
import strutils
|
||||
import strutils, sequtils
|
||||
|
||||
echo "Give a list of numbers (separated by spaces): "
|
||||
stdin.readLine.split.map(parseInt).max.`$`.echo(" is the maximum!")
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
import
|
||||
pcre, strutils, rtarrays
|
||||
|
||||
{.deprecated.}
|
||||
|
||||
const
|
||||
MaxSubpatterns* = 20
|
||||
## defines the maximum number of subpatterns that can be captured.
|
||||
@@ -46,7 +48,7 @@ type
|
||||
h: ptr Pcre
|
||||
e: ptr ExtraData
|
||||
|
||||
Regex* {.deprecated.} = ref RegexDesc ## a compiled regular expression
|
||||
Regex* = ref RegexDesc ## a compiled regular expression
|
||||
|
||||
RegexError* = object of ValueError
|
||||
## is raised if the pattern is no valid regular expression.
|
||||
|
||||
@@ -139,7 +139,7 @@ proc initRstGenerator*(g: var RstGenerator, target: OutputTarget,
|
||||
g.seenIndexTerms = initTable[string, int]()
|
||||
g.msgHandler = msgHandler
|
||||
|
||||
let s = config["split.item.toc"]
|
||||
let s = config.getOrDefault"split.item.toc"
|
||||
if s != "": g.splitAfter = parseInt(s)
|
||||
for i in low(g.meta)..high(g.meta): g.meta[i] = ""
|
||||
|
||||
@@ -341,10 +341,10 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) =
|
||||
## previously appeared to give a different identifier value for each.
|
||||
let refname = n.rstnodeToRefname
|
||||
if d.seenIndexTerms.hasKey(refname):
|
||||
d.seenIndexTerms[refname] = d.seenIndexTerms[refname] + 1
|
||||
d.seenIndexTerms[refname] = d.seenIndexTerms.getOrDefault(refname) + 1
|
||||
else:
|
||||
d.seenIndexTerms[refname] = 1
|
||||
let id = refname & '_' & $d.seenIndexTerms[refname]
|
||||
let id = refname & '_' & $d.seenIndexTerms.getOrDefault(refname)
|
||||
|
||||
var term = ""
|
||||
renderAux(d, n, term)
|
||||
@@ -518,7 +518,7 @@ proc generateDocumentationIndex(docs: IndexedDocs): string =
|
||||
sort(titles, cmp)
|
||||
|
||||
for title in titles:
|
||||
let tocList = generateDocumentationTOC(docs[title])
|
||||
let tocList = generateDocumentationTOC(docs.getOrDefault(title))
|
||||
result.add("<ul><li><a href=\"" &
|
||||
title.link & "\">" & title.keyword & "</a>\n" & tocList & "</ul>\n")
|
||||
|
||||
@@ -786,7 +786,8 @@ proc renderSmiley(d: PDoc, n: PRstNode, result: var string) =
|
||||
dispA(d.target, result,
|
||||
"""<img src="$1" width="15"
|
||||
height="17" hspace="2" vspace="2" class="smiley" />""",
|
||||
"\\includegraphics{$1}", [d.config["doc.smiley_format"] % n.text])
|
||||
"\\includegraphics{$1}",
|
||||
[d.config.getOrDefault"doc.smiley_format" % n.text])
|
||||
|
||||
proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) =
|
||||
## Parses useful fields which can appear before a code block.
|
||||
@@ -844,8 +845,8 @@ proc buildLinesHTMLTable(d: PDoc; params: CodeBlockParams, code: string):
|
||||
inc d.listingCounter
|
||||
let id = $d.listingCounter
|
||||
if not params.numberLines:
|
||||
result = (d.config["doc.listing_start"] % id,
|
||||
d.config["doc.listing_end"] % id)
|
||||
result = (d.config.getOrDefault"doc.listing_start" % id,
|
||||
d.config.getOrDefault"doc.listing_end" % id)
|
||||
return
|
||||
|
||||
var codeLines = 1 + code.strip.countLines
|
||||
@@ -856,9 +857,11 @@ proc buildLinesHTMLTable(d: PDoc; params: CodeBlockParams, code: string):
|
||||
result.beginTable.add($line & "\n")
|
||||
line.inc
|
||||
codeLines.dec
|
||||
result.beginTable.add("</pre></td><td>" & (d.config["doc.listing_start"] % id))
|
||||
result.endTable = (d.config["doc.listing_end"] % id) &
|
||||
"</td></tr></tbody></table>" & (d.config["doc.listing_button"] % id)
|
||||
result.beginTable.add("</pre></td><td>" & (
|
||||
d.config.getOrDefault"doc.listing_start" % id))
|
||||
result.endTable = (d.config.getOrDefault"doc.listing_end" % id) &
|
||||
"</td></tr></tbody></table>" & (
|
||||
d.config.getOrDefault"doc.listing_button" % id)
|
||||
|
||||
proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
|
||||
## Renders a code block, appending it to `result`.
|
||||
|
||||
@@ -212,7 +212,7 @@ proc processClient(client: AsyncSocket, address: string,
|
||||
if request.reqMethod == "post":
|
||||
# Check for Expect header
|
||||
if request.headers.hasKey("Expect"):
|
||||
if request.headers["Expect"].toLower == "100-continue":
|
||||
if request.headers.getOrDefault("Expect").toLower == "100-continue":
|
||||
await client.sendStatus("100 Continue")
|
||||
else:
|
||||
await client.sendStatus("417 Expectation Failed")
|
||||
@@ -221,7 +221,8 @@ proc processClient(client: AsyncSocket, address: string,
|
||||
# - Check for Content-length header
|
||||
if request.headers.hasKey("Content-Length"):
|
||||
var contentLength = 0
|
||||
if parseInt(request.headers["Content-Length"], contentLength) == 0:
|
||||
if parseInt(request.headers.getOrDefault("Content-Length"),
|
||||
contentLength) == 0:
|
||||
await request.respond(Http400, "Bad Request. Invalid Content-Length.")
|
||||
continue
|
||||
else:
|
||||
@@ -232,16 +233,18 @@ proc processClient(client: AsyncSocket, address: string,
|
||||
continue
|
||||
|
||||
case request.reqMethod
|
||||
of "get", "post", "head", "put", "delete", "trace", "options", "connect", "patch":
|
||||
of "get", "post", "head", "put", "delete", "trace", "options",
|
||||
"connect", "patch":
|
||||
await callback(request)
|
||||
else:
|
||||
await request.respond(Http400, "Invalid request method. Got: " & request.reqMethod)
|
||||
await request.respond(Http400, "Invalid request method. Got: " &
|
||||
request.reqMethod)
|
||||
|
||||
# Persistent connections
|
||||
if (request.protocol == HttpVer11 and
|
||||
request.headers["connection"].normalize != "close") or
|
||||
request.headers.getOrDefault("connection").normalize != "close") or
|
||||
(request.protocol == HttpVer10 and
|
||||
request.headers["connection"].normalize == "keep-alive"):
|
||||
request.headers.getOrDefault("connection").normalize == "keep-alive"):
|
||||
# In HTTP 1.1 we assume that connection is persistent. Unless connection
|
||||
# header states otherwise.
|
||||
# In HTTP 1.0 we assume that the connection should not be persistent.
|
||||
|
||||
@@ -387,7 +387,7 @@ var
|
||||
proc getCookie*(name: string): TaintedString =
|
||||
## Gets a cookie. If no cookie of `name` exists, "" is returned.
|
||||
if gcookies == nil: gcookies = parseCookies(getHttpCookie())
|
||||
result = TaintedString(gcookies[name])
|
||||
result = TaintedString(gcookies.getOrDefault(name))
|
||||
|
||||
proc existsCookie*(name: string): bool =
|
||||
## Checks if a cookie of `name` exists.
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
## container for a set or a mapping of strings. Based on the excellent paper
|
||||
## by Adam Langley.
|
||||
|
||||
include "system/inclrtl"
|
||||
|
||||
type
|
||||
NodeObj[T] = object {.acyclic.}
|
||||
byte: int ## byte index of the difference
|
||||
@@ -140,20 +142,32 @@ proc `[]=`*[T](c: var CritBitTree[T], key: string, val: T) =
|
||||
var n = rawInsert(c, key)
|
||||
n.val = val
|
||||
|
||||
proc `[]`*[T](c: CritBitTree[T], key: string): T {.inline.} =
|
||||
## retrieves the value at ``c[key]``. If `key` is not in `t`,
|
||||
## default empty value for the type `B` is returned
|
||||
## and no exception is raised. One can check with ``hasKey`` whether the key
|
||||
## exists.
|
||||
template get[T](c: CritBitTree[T], key: string): T {.immediate.} =
|
||||
let n = rawGet(c, key)
|
||||
if n != nil: result = n.val
|
||||
else:
|
||||
when compiles($key):
|
||||
raise newException(KeyError, "key not found: " & $key)
|
||||
else:
|
||||
raise newException(KeyError, "key not found")
|
||||
|
||||
proc mget*[T](c: var CritBitTree[T], key: string): var T {.inline.} =
|
||||
proc `[]`*[T](c: CritBitTree[T], key: string): T {.inline, deprecatedGet.} =
|
||||
## retrieves the value at ``c[key]``. If `key` is not in `t`, the
|
||||
## ``KeyError`` exception is raised. One can check with ``hasKey`` whether
|
||||
## the key exists.
|
||||
get(c, key)
|
||||
|
||||
proc `[]`*[T](c: var CritBitTree[T], key: string): var T {.inline,
|
||||
deprecatedGet.} =
|
||||
## retrieves the value at ``c[key]``. The value can be modified.
|
||||
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||
let n = rawGet(c, key)
|
||||
if n != nil: result = n.val
|
||||
else: raise newException(KeyError, "key not found: " & $key)
|
||||
get(c, key)
|
||||
|
||||
proc mget*[T](c: var CritBitTree[T], key: string): var T {.inline, deprecated.} =
|
||||
## retrieves the value at ``c[key]``. The value can be modified.
|
||||
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||
## Use ```[]``` instead.
|
||||
get(c, key)
|
||||
|
||||
proc excl*[T](c: var CritBitTree[T], key: string) =
|
||||
## removes `key` (and its associated value) from the set `c`.
|
||||
|
||||
@@ -138,6 +138,8 @@ proc initIntSet*: IntSet =
|
||||
result.counter = 0
|
||||
result.head = nil
|
||||
|
||||
proc isNil*(x: IntSet): bool {.inline.} = x.head.isNil
|
||||
|
||||
proc assign*(dest: var IntSet, src: IntSet) =
|
||||
## copies `src` to `dest`. `dest` does not need to be initialized by
|
||||
## `initIntSet`.
|
||||
|
||||
@@ -47,7 +47,7 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
|
||||
result[i] = itm
|
||||
inc(i)
|
||||
|
||||
proc repeat*[T](s: seq[T], n: Natural): seq[T] =
|
||||
proc cycle*[T](s: seq[T], n: Natural): seq[T] =
|
||||
## Returns a new sequence with the items of `s` repeated `n` times.
|
||||
##
|
||||
## Example:
|
||||
@@ -56,15 +56,29 @@ proc repeat*[T](s: seq[T], n: Natural): seq[T] =
|
||||
##
|
||||
## let
|
||||
## s = @[1, 2, 3]
|
||||
## total = s.repeat(3)
|
||||
## total = s.cycle(3)
|
||||
## assert total == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
|
||||
result = newSeq[T](n * s.len)
|
||||
var o = 0
|
||||
for x in 1..n:
|
||||
for x in 0..<n:
|
||||
for e in s:
|
||||
result[o] = e
|
||||
inc o
|
||||
|
||||
proc repeat*[T](x: T, n: Natural): seq[T] =
|
||||
## Returns a new sequence with the item `x` repeated `n` times.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block:
|
||||
##
|
||||
## let
|
||||
## total = repeat(5, 3)
|
||||
## assert total == @[5, 5, 5]
|
||||
result = newSeq[T](n)
|
||||
for i in 0..<n:
|
||||
result[i] = x
|
||||
|
||||
proc deduplicate*[T](seq1: seq[T]): seq[T] =
|
||||
## Returns a new sequence without duplicates.
|
||||
##
|
||||
@@ -169,6 +183,77 @@ proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
|
||||
first = last
|
||||
|
||||
|
||||
proc map*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}):
|
||||
seq[S]{.inline.} =
|
||||
## Returns a new sequence with the results of `op` applied to every item in
|
||||
## `data`.
|
||||
##
|
||||
## Since the input is not modified you can use this version of ``map`` to
|
||||
## transform the type of the elements in the input sequence. Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## let
|
||||
## a = @[1, 2, 3, 4]
|
||||
## b = map(a, proc(x: int): string = $x)
|
||||
## assert b == @["1", "2", "3", "4"]
|
||||
newSeq(result, data.len)
|
||||
for i in 0..data.len-1: result[i] = op(data[i])
|
||||
|
||||
proc map*[T](data: var openArray[T], op: proc (x: var T) {.closure.})
|
||||
{.deprecated.} =
|
||||
## Applies `op` to every item in `data` modifying it directly.
|
||||
##
|
||||
## Note that this version of ``map`` requires your input and output types to
|
||||
## be the same, since they are modified in-place. Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## var a = @["1", "2", "3", "4"]
|
||||
## echo repr(a)
|
||||
## # --> ["1", "2", "3", "4"]
|
||||
## map(a, proc(x: var string) = x &= "42")
|
||||
## echo repr(a)
|
||||
## # --> ["142", "242", "342", "442"]
|
||||
## **Deprecated since version 0.12.0:** Use the ``apply`` proc instead.
|
||||
for i in 0..data.len-1: op(data[i])
|
||||
|
||||
proc apply*[T](data: var seq[T], op: proc (x: var T) {.closure.})
|
||||
{.inline.} =
|
||||
## Applies `op` to every item in `data` modifying it directly.
|
||||
##
|
||||
## Note that this requires your input and output types to
|
||||
## be the same, since they are modified in-place.
|
||||
## The parameter function takes a ``var T`` type parameter.
|
||||
## Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## var a = @["1", "2", "3", "4"]
|
||||
## echo repr(a)
|
||||
## # --> ["1", "2", "3", "4"]
|
||||
## map(a, proc(x: var string) = x &= "42")
|
||||
## echo repr(a)
|
||||
## # --> ["142", "242", "342", "442"]
|
||||
##
|
||||
for i in 0..data.len-1: op(data[i])
|
||||
|
||||
proc apply*[T](data: var seq[T], op: proc (x: T): T {.closure.})
|
||||
{.inline.} =
|
||||
## Applies `op` to every item in `data` modifying it directly.
|
||||
##
|
||||
## Note that this requires your input and output types to
|
||||
## be the same, since they are modified in-place.
|
||||
## The parameter function takes and returns a ``T`` type variable.
|
||||
## Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## var a = @["1", "2", "3", "4"]
|
||||
## echo repr(a)
|
||||
## # --> ["1", "2", "3", "4"]
|
||||
## map(a, proc(x: string): string = x & "42")
|
||||
## echo repr(a)
|
||||
## # --> ["142", "242", "342", "442"]
|
||||
##
|
||||
for i in 0..data.len-1: data[i] = op(data[i])
|
||||
|
||||
|
||||
iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T =
|
||||
## Iterates through a sequence and yields every item that fulfills the
|
||||
@@ -181,11 +266,12 @@ iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T =
|
||||
## for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
|
||||
## echo($n)
|
||||
## # echoes 4, 8, 4 in separate lines
|
||||
for i in countup(0, len(seq1)-1):
|
||||
var item = seq1[i]
|
||||
if pred(item): yield seq1[i]
|
||||
for i in 0..<seq1.len:
|
||||
if pred(seq1[i]):
|
||||
yield seq1[i]
|
||||
|
||||
proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T] =
|
||||
proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T]
|
||||
{.inline.} =
|
||||
## Returns a new sequence with all the items that fulfilled the predicate.
|
||||
##
|
||||
## Example:
|
||||
@@ -197,9 +283,13 @@ proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T] =
|
||||
## f2 = filter(colors) do (x: string) -> bool : x.len > 5
|
||||
## assert f1 == @["red", "black"]
|
||||
## assert f2 == @["yellow"]
|
||||
accumulateResult(filter(seq1, pred))
|
||||
result = newSeq[T]()
|
||||
for i in 0..<seq1.len:
|
||||
if pred(seq1[i]):
|
||||
result.add(seq1[i])
|
||||
|
||||
proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.}) =
|
||||
proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.})
|
||||
{.inline.} =
|
||||
## Keeps the items in the passed sequence if they fulfilled the predicate.
|
||||
## Same as the ``filter`` proc, but modifies the sequence directly.
|
||||
##
|
||||
@@ -213,7 +303,7 @@ proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.}) =
|
||||
for i in 0 .. <len(seq1):
|
||||
if pred(seq1[i]):
|
||||
if pos != i:
|
||||
seq1[pos] = seq1[i]
|
||||
shallowCopy(seq1[pos], seq1[i])
|
||||
inc(pos)
|
||||
setLen(seq1, pos)
|
||||
|
||||
@@ -268,7 +358,7 @@ proc insert*[T](dest: var seq[T], src: openArray[T], pos=0) =
|
||||
inc(j)
|
||||
|
||||
|
||||
template filterIt*(seq1, pred: expr): expr {.immediate.} =
|
||||
template filterIt*(seq1, pred: expr): expr =
|
||||
## Returns a new sequence with all the items that fulfilled the predicate.
|
||||
##
|
||||
## Unlike the `proc` version, the predicate needs to be an expression using
|
||||
@@ -282,12 +372,12 @@ template filterIt*(seq1, pred: expr): expr {.immediate.} =
|
||||
## notAcceptable = filterIt(temperatures, it > 50 or it < -10)
|
||||
## assert acceptable == @[-2.0, 24.5, 44.31]
|
||||
## assert notAcceptable == @[-272.15, 99.9, -113.44]
|
||||
var result {.gensym.}: type(seq1) = @[]
|
||||
var result {.gensym.} = newSeq[type(seq1[0])]()
|
||||
for it {.inject.} in items(seq1):
|
||||
if pred: result.add(it)
|
||||
result
|
||||
|
||||
template keepItIf*(varSeq, pred: expr) =
|
||||
template keepItIf*(varSeq: seq, pred: expr) =
|
||||
## Convenience template around the ``keepIf`` proc to reduce typing.
|
||||
##
|
||||
## Unlike the `proc` version, the predicate needs to be an expression using
|
||||
@@ -303,10 +393,71 @@ template keepItIf*(varSeq, pred: expr) =
|
||||
let it {.inject.} = varSeq[i]
|
||||
if pred:
|
||||
if pos != i:
|
||||
varSeq[pos] = varSeq[i]
|
||||
shallowCopy(varSeq[pos], varSeq[i])
|
||||
inc(pos)
|
||||
setLen(varSeq, pos)
|
||||
|
||||
proc all*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): bool =
|
||||
## Iterates through a sequence and checks if every item fulfills the
|
||||
## predicate.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block::
|
||||
## let numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
## assert all(numbers, proc (x: int): bool = return x < 10) == true
|
||||
## assert all(numbers, proc (x: int): bool = return x < 9) == false
|
||||
for i in seq1:
|
||||
if not pred(i):
|
||||
return false
|
||||
return true
|
||||
|
||||
template allIt*(seq1, pred: expr): bool {.immediate.} =
|
||||
## Checks if every item fulfills the predicate.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block::
|
||||
## let numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
## assert allIt(numbers, it < 10) == true
|
||||
## assert allIt(numbers, it < 9) == false
|
||||
var result {.gensym.} = true
|
||||
for it {.inject.} in items(seq1):
|
||||
if not pred:
|
||||
result = false
|
||||
break
|
||||
result
|
||||
|
||||
proc any*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): bool =
|
||||
## Iterates through a sequence and checks if some item fulfills the
|
||||
## predicate.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block::
|
||||
## let numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
## assert any(numbers, proc (x: int): bool = return x > 8) == true
|
||||
## assert any(numbers, proc (x: int): bool = return x > 9) == false
|
||||
for i in seq1:
|
||||
if pred(i):
|
||||
return true
|
||||
return false
|
||||
|
||||
template anyIt*(seq1, pred: expr): bool {.immediate.} =
|
||||
## Checks if some item fulfills the predicate.
|
||||
##
|
||||
## Example:
|
||||
##
|
||||
## .. code-block::
|
||||
## let numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
## assert anyIt(numbers, it > 8) == true
|
||||
## assert anyIt(numbers, it > 9) == false
|
||||
var result {.gensym.} = false
|
||||
for it {.inject.} in items(seq1):
|
||||
if pred:
|
||||
result = true
|
||||
break
|
||||
result
|
||||
|
||||
template toSeq*(iter: expr): expr {.immediate.} =
|
||||
## Transforms any iterator into a sequence.
|
||||
@@ -320,14 +471,19 @@ template toSeq*(iter: expr): expr {.immediate.} =
|
||||
## if x mod 2 == 1:
|
||||
## result = true)
|
||||
## assert odd_numbers == @[1, 3, 5, 7, 9]
|
||||
##
|
||||
## **Note**: Since this is an immediate macro, you cannot always invoke this
|
||||
## as ``x.toSeq``, depending on the ``x``.
|
||||
## See `this <manual.html#limitations-of-the-method-call-syntax>`_
|
||||
## for an explanation.
|
||||
var result {.gensym.}: seq[type(iter)] = @[]
|
||||
for x in iter: add(result, x)
|
||||
result
|
||||
|
||||
when compiles(iter.len):
|
||||
var i = 0
|
||||
var result = newSeq[type(iter)](iter.len)
|
||||
for x in iter:
|
||||
result[i] = x
|
||||
inc i
|
||||
result
|
||||
else:
|
||||
var result: seq[type(iter)] = @[]
|
||||
for x in iter:
|
||||
result.add(x)
|
||||
result
|
||||
|
||||
template foldl*(sequence, operation: expr): expr =
|
||||
## Template to fold a sequence from left to right, returning the accumulation.
|
||||
@@ -358,7 +514,7 @@ template foldl*(sequence, operation: expr): expr =
|
||||
assert sequence.len > 0, "Can't fold empty sequences"
|
||||
var result {.gensym.}: type(sequence[0])
|
||||
result = sequence[0]
|
||||
for i in countup(1, sequence.len - 1):
|
||||
for i in 1..<sequence.len:
|
||||
let
|
||||
a {.inject.} = result
|
||||
b {.inject.} = sequence[i]
|
||||
@@ -401,7 +557,7 @@ template foldr*(sequence, operation: expr): expr =
|
||||
result = operation
|
||||
result
|
||||
|
||||
template mapIt*(seq1, typ, op: expr): expr =
|
||||
template mapIt*(seq1, typ, op: expr): expr {.deprecated.}=
|
||||
## Convenience template around the ``map`` proc to reduce typing.
|
||||
##
|
||||
## The template injects the ``it`` variable which you can use directly in an
|
||||
@@ -414,13 +570,45 @@ template mapIt*(seq1, typ, op: expr): expr =
|
||||
## nums = @[1, 2, 3, 4]
|
||||
## strings = nums.mapIt(string, $(4 * it))
|
||||
## assert strings == @["4", "8", "12", "16"]
|
||||
## **Deprecated since version 0.12.0:** Use the ``mapIt(seq1, op)``
|
||||
## template instead.
|
||||
var result {.gensym.}: seq[typ] = @[]
|
||||
for it {.inject.} in items(seq1):
|
||||
result.add(op)
|
||||
result
|
||||
|
||||
template mapIt*(varSeq, op: expr) =
|
||||
## Convenience template around the mutable ``map`` proc to reduce typing.
|
||||
|
||||
template mapIt*(seq1, op: expr): expr =
|
||||
## Convenience template around the ``map`` proc to reduce typing.
|
||||
##
|
||||
## The template injects the ``it`` variable which you can use directly in an
|
||||
## expression. Example:
|
||||
##
|
||||
## .. code-block::
|
||||
## let
|
||||
## nums = @[1, 2, 3, 4]
|
||||
## strings = nums.mapIt($(4 * it))
|
||||
## assert strings == @["4", "8", "12", "16"]
|
||||
type outType = type((
|
||||
block:
|
||||
var it{.inject.}: type(items(seq1));
|
||||
op))
|
||||
var result: seq[outType]
|
||||
when compiles(seq1.len):
|
||||
let s = seq1
|
||||
var i = 0
|
||||
result = newSeq[outType](s.len)
|
||||
for it {.inject.} in s:
|
||||
result[i] = op
|
||||
i += 1
|
||||
else:
|
||||
result = @[]
|
||||
for it {.inject.} in seq1:
|
||||
result.add(op)
|
||||
result
|
||||
|
||||
template applyIt*(varSeq, op: expr) =
|
||||
## Convenience template around the mutable ``apply`` proc to reduce typing.
|
||||
##
|
||||
## The template injects the ``it`` variable which you can use directly in an
|
||||
## expression. The expression has to return the same type as the sequence you
|
||||
@@ -428,12 +616,14 @@ template mapIt*(varSeq, op: expr) =
|
||||
##
|
||||
## .. code-block::
|
||||
## var nums = @[1, 2, 3, 4]
|
||||
## nums.mapIt(it * 3)
|
||||
## nums.applyIt(it * 3)
|
||||
## assert nums[0] + nums[3] == 15
|
||||
for i in 0 .. <len(varSeq):
|
||||
for i in 0 .. <varSeq.len:
|
||||
let it {.inject.} = varSeq[i]
|
||||
varSeq[i] = op
|
||||
|
||||
|
||||
|
||||
template newSeqWith*(len: int, init: expr): expr =
|
||||
## creates a new sequence, calling `init` to initialize each value. Example:
|
||||
##
|
||||
@@ -513,6 +703,38 @@ when isMainModule:
|
||||
keepItIf(candidates, it.len == 3 and it[0] == 'b')
|
||||
assert candidates == @["bar", "baz"]
|
||||
|
||||
block: # any
|
||||
let
|
||||
numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
len0seq : seq[int] = @[]
|
||||
assert any(numbers, proc (x: int): bool = return x > 8) == true
|
||||
assert any(numbers, proc (x: int): bool = return x > 9) == false
|
||||
assert any(len0seq, proc (x: int): bool = return true) == false
|
||||
|
||||
block: # anyIt
|
||||
let
|
||||
numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
len0seq : seq[int] = @[]
|
||||
assert anyIt(numbers, it > 8) == true
|
||||
assert anyIt(numbers, it > 9) == false
|
||||
assert anyIt(len0seq, true) == false
|
||||
|
||||
block: # all
|
||||
let
|
||||
numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
len0seq : seq[int] = @[]
|
||||
assert all(numbers, proc (x: int): bool = return x < 10) == true
|
||||
assert all(numbers, proc (x: int): bool = return x < 9) == false
|
||||
assert all(len0seq, proc (x: int): bool = return false) == true
|
||||
|
||||
block: # allIt
|
||||
let
|
||||
numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
len0seq : seq[int] = @[]
|
||||
assert allIt(numbers, it < 10) == true
|
||||
assert allIt(numbers, it < 9) == false
|
||||
assert allIt(len0seq, false) == true
|
||||
|
||||
block: # toSeq test
|
||||
let
|
||||
numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
@@ -568,8 +790,8 @@ when isMainModule:
|
||||
block: # mapIt tests
|
||||
var
|
||||
nums = @[1, 2, 3, 4]
|
||||
strings = nums.mapIt(string, $(4 * it))
|
||||
nums.mapIt(it * 3)
|
||||
strings = nums.mapIt($(4 * it))
|
||||
nums.applyIt(it * 3)
|
||||
assert nums[0] + nums[3] == 15
|
||||
|
||||
block: # distribute tests
|
||||
@@ -605,15 +827,19 @@ when isMainModule:
|
||||
seq2D[0][1] = true
|
||||
doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
|
||||
|
||||
block: # repeat tests
|
||||
block: # cycle tests
|
||||
let
|
||||
a = @[1, 2, 3]
|
||||
b: seq[int] = @[]
|
||||
|
||||
doAssert a.repeat(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
|
||||
doAssert a.repeat(0) == @[]
|
||||
#doAssert a.repeat(-1) == @[] # will not compile!
|
||||
doAssert b.repeat(3) == @[]
|
||||
doAssert a.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
|
||||
doAssert a.cycle(0) == @[]
|
||||
#doAssert a.cycle(-1) == @[] # will not compile!
|
||||
doAssert b.cycle(3) == @[]
|
||||
|
||||
block: # repeat tests
|
||||
assert repeat(10, 5) == @[10, 10, 10, 10, 10]
|
||||
assert repeat(@[1,2,3], 2) == @[@[1,2,3], @[1,2,3]]
|
||||
|
||||
when not defined(testing):
|
||||
echo "Finished doc tests"
|
||||
|
||||
@@ -154,9 +154,9 @@ proc rawGetKnownHC[A](s: HashSet[A], key: A, hc: Hash): int {.inline.} =
|
||||
proc rawGet[A](s: HashSet[A], key: A, hc: var Hash): int {.inline.} =
|
||||
rawGetImpl()
|
||||
|
||||
proc mget*[A](s: var HashSet[A], key: A): var A =
|
||||
proc `[]`*[A](s: var HashSet[A], key: A): var A =
|
||||
## returns the element that is actually stored in 's' which has the same
|
||||
## value as 'key' or raises the ``EInvalidKey`` exception. This is useful
|
||||
## value as 'key' or raises the ``KeyError`` exception. This is useful
|
||||
## when one overloaded 'hash' and '==' but still needs reference semantics
|
||||
## for sharing.
|
||||
assert s.isValid, "The set needs to be initialized."
|
||||
@@ -165,6 +165,13 @@ proc mget*[A](s: var HashSet[A], key: A): var A =
|
||||
if index >= 0: result = s.data[index].key
|
||||
else: raise newException(KeyError, "key not found: " & $key)
|
||||
|
||||
proc mget*[A](s: var HashSet[A], key: A): var A {.deprecated.} =
|
||||
## returns the element that is actually stored in 's' which has the same
|
||||
## value as 'key' or raises the ``KeyError`` exception. This is useful
|
||||
## when one overloaded 'hash' and '==' but still needs reference semantics
|
||||
## for sharing. Use ```[]``` instead.
|
||||
s[key]
|
||||
|
||||
proc contains*[A](s: HashSet[A], key: A): bool =
|
||||
## Returns true iff `key` is in `s`.
|
||||
##
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
import
|
||||
hashes, math
|
||||
|
||||
include "system/inclrtl"
|
||||
|
||||
type
|
||||
KeyValuePair[A, B] = tuple[hcode: Hash, key: A, val: B]
|
||||
KeyValuePairSeq[A, B] = seq[KeyValuePair[A, B]]
|
||||
@@ -96,18 +98,10 @@ proc len*[A, B](t: Table[A, B]): int =
|
||||
## returns the number of keys in `t`.
|
||||
result = t.counter
|
||||
|
||||
proc `[]`*[A, B](t: Table[A, B], key: A): B =
|
||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
||||
## default empty value for the type `B` is returned
|
||||
## and no exception is raised. One can check with ``hasKey`` whether the key
|
||||
## exists.
|
||||
var hc: Hash
|
||||
var index = rawGet(t, key, hc)
|
||||
if index >= 0: result = t.data[index].val
|
||||
|
||||
proc mget*[A, B](t: var Table[A, B], key: A): var B =
|
||||
template get(t, key): untyped {.immediate.} =
|
||||
## retrieves the value at ``t[key]``. The value can be modified.
|
||||
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||
mixin rawGet
|
||||
var hc: Hash
|
||||
var index = rawGet(t, key, hc)
|
||||
if index >= 0: result = t.data[index].val
|
||||
@@ -117,6 +111,31 @@ proc mget*[A, B](t: var Table[A, B], key: A): var B =
|
||||
else:
|
||||
raise newException(KeyError, "key not found")
|
||||
|
||||
template getOrDefaultImpl(t, key): untyped {.immediate.} =
|
||||
mixin rawGet
|
||||
var hc: Hash
|
||||
var index = rawGet(t, key, hc)
|
||||
if index >= 0: result = t.data[index].val
|
||||
|
||||
proc `[]`*[A, B](t: Table[A, B], key: A): B {.deprecatedGet.} =
|
||||
## retrieves the value at ``t[key]``. If `key` is not in `t`, the
|
||||
## ``KeyError`` exception is raised. One can check with ``hasKey`` whether
|
||||
## the key exists.
|
||||
get(t, key)
|
||||
|
||||
proc `[]`*[A, B](t: var Table[A, B], key: A): var B {.deprecatedGet.} =
|
||||
## retrieves the value at ``t[key]``. The value can be modified.
|
||||
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||
get(t, key)
|
||||
|
||||
proc mget*[A, B](t: var Table[A, B], key: A): var B {.deprecated.} =
|
||||
## retrieves the value at ``t[key]``. The value can be modified.
|
||||
## If `key` is not in `t`, the ``KeyError`` exception is raised. Use ```[]```
|
||||
## instead.
|
||||
get(t, key)
|
||||
|
||||
proc getOrDefault*[A, B](t: Table[A, B], key: A): B = getOrDefaultImpl(t, key)
|
||||
|
||||
iterator allValues*[A, B](t: Table[A, B]; key: A): B =
|
||||
## iterates over any value in the table `t` that belongs to the given `key`.
|
||||
var h: Hash = hash(key) and high(t.data)
|
||||
@@ -276,17 +295,19 @@ iterator mvalues*[A, B](t: TableRef[A, B]): var B =
|
||||
for h in 0..high(t.data):
|
||||
if isFilled(t.data[h].hcode): yield t.data[h].val
|
||||
|
||||
proc `[]`*[A, B](t: TableRef[A, B], key: A): B =
|
||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
||||
## default empty value for the type `B` is returned
|
||||
## and no exception is raised. One can check with ``hasKey`` whether the key
|
||||
## exists.
|
||||
proc `[]`*[A, B](t: TableRef[A, B], key: A): var B {.deprecatedGet.} =
|
||||
## retrieves the value at ``t[key]``. If `key` is not in `t`, the
|
||||
## ``KeyError`` exception is raised. One can check with ``hasKey`` whether
|
||||
## the key exists.
|
||||
result = t[][key]
|
||||
|
||||
proc mget*[A, B](t: TableRef[A, B], key: A): var B =
|
||||
proc mget*[A, B](t: TableRef[A, B], key: A): var B {.deprecated.} =
|
||||
## retrieves the value at ``t[key]``. The value can be modified.
|
||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
||||
t[].mget(key)
|
||||
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||
## Use ```[]``` instead.
|
||||
t[][key]
|
||||
|
||||
proc getOrDefault*[A, B](t: TableRef[A, B], key: A): B = getOrDefault(t[], key)
|
||||
|
||||
proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B =
|
||||
## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
|
||||
@@ -399,22 +420,26 @@ proc rawGetDeep[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int {.inline
|
||||
proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var Hash): int =
|
||||
rawGetImpl()
|
||||
|
||||
proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B =
|
||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
||||
## default empty value for the type `B` is returned
|
||||
## and no exception is raised. One can check with ``hasKey`` whether the key
|
||||
## exists.
|
||||
var hc: Hash
|
||||
var index = rawGet(t, key, hc)
|
||||
if index >= 0: result = t.data[index].val
|
||||
proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B {.deprecatedGet.} =
|
||||
## retrieves the value at ``t[key]``. If `key` is not in `t`, the
|
||||
## ``KeyError`` exception is raised. One can check with ``hasKey`` whether
|
||||
## the key exists.
|
||||
get(t, key)
|
||||
|
||||
proc mget*[A, B](t: var OrderedTable[A, B], key: A): var B =
|
||||
proc `[]`*[A, B](t: var OrderedTable[A, B], key: A): var B{.deprecatedGet.} =
|
||||
## retrieves the value at ``t[key]``. The value can be modified.
|
||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
||||
var hc: Hash
|
||||
var index = rawGet(t, key, hc)
|
||||
if index >= 0: result = t.data[index].val
|
||||
else: raise newException(KeyError, "key not found: " & $key)
|
||||
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||
get(t, key)
|
||||
|
||||
proc mget*[A, B](t: var OrderedTable[A, B], key: A): var B {.deprecated.} =
|
||||
## retrieves the value at ``t[key]``. The value can be modified.
|
||||
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||
## Use ```[]``` instead.
|
||||
get(t, key)
|
||||
|
||||
proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A): B =
|
||||
getOrDefaultImpl(t, key)
|
||||
|
||||
|
||||
proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
|
||||
## returns true iff `key` is in the table `t`.
|
||||
@@ -572,17 +597,20 @@ iterator mvalues*[A, B](t: OrderedTableRef[A, B]): var B =
|
||||
forAllOrderedPairs:
|
||||
yield t.data[h].val
|
||||
|
||||
proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): B =
|
||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
||||
## default empty value for the type `B` is returned
|
||||
## and no exception is raised. One can check with ``hasKey`` whether the key
|
||||
## exists.
|
||||
proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): var B =
|
||||
## retrieves the value at ``t[key]``. If `key` is not in `t`, the
|
||||
## ``KeyError`` exception is raised. One can check with ``hasKey`` whether
|
||||
## the key exists.
|
||||
result = t[][key]
|
||||
|
||||
proc mget*[A, B](t: OrderedTableRef[A, B], key: A): var B =
|
||||
proc mget*[A, B](t: OrderedTableRef[A, B], key: A): var B {.deprecated.} =
|
||||
## retrieves the value at ``t[key]``. The value can be modified.
|
||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
||||
result = t[].mget(key)
|
||||
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||
## Use ```[]``` instead.
|
||||
result = t[][key]
|
||||
|
||||
proc getOrDefault*[A, B](t: OrderedTableRef[A, B], key: A): B =
|
||||
getOrDefault(t[], key)
|
||||
|
||||
proc mgetOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): var B =
|
||||
## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
|
||||
@@ -683,19 +711,35 @@ proc rawGet[A](t: CountTable[A], key: A): int =
|
||||
h = nextTry(h, high(t.data))
|
||||
result = -1 - h # < 0 => MISSING; insert idx = -1 - result
|
||||
|
||||
proc `[]`*[A](t: CountTable[A], key: A): int =
|
||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
||||
## 0 is returned. One can check with ``hasKey`` whether the key
|
||||
## exists.
|
||||
template ctget(t, key: untyped): untyped {.immediate.} =
|
||||
var index = rawGet(t, key)
|
||||
if index >= 0: result = t.data[index].val
|
||||
else:
|
||||
when compiles($key):
|
||||
raise newException(KeyError, "key not found: " & $key)
|
||||
else:
|
||||
raise newException(KeyError, "key not found")
|
||||
|
||||
proc mget*[A](t: var CountTable[A], key: A): var int =
|
||||
proc `[]`*[A](t: CountTable[A], key: A): int {.deprecatedGet.} =
|
||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
||||
## the ``KeyError`` exception is raised. One can check with ``hasKey``
|
||||
## whether the key exists.
|
||||
ctget(t, key)
|
||||
|
||||
proc `[]`*[A](t: var CountTable[A], key: A): var int {.deprecatedGet.} =
|
||||
## retrieves the value at ``t[key]``. The value can be modified.
|
||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
||||
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||
ctget(t, key)
|
||||
|
||||
proc mget*[A](t: var CountTable[A], key: A): var int {.deprecated.} =
|
||||
## retrieves the value at ``t[key]``. The value can be modified.
|
||||
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||
## Use ```[]``` instead.
|
||||
ctget(t, key)
|
||||
|
||||
proc getOrDefault*[A](t: CountTable[A], key: A): int =
|
||||
var index = rawGet(t, key)
|
||||
if index >= 0: result = t.data[index].val
|
||||
else: raise newException(KeyError, "key not found: " & $key)
|
||||
|
||||
proc hasKey*[A](t: CountTable[A], key: A): bool =
|
||||
## returns true iff `key` is in the table `t`.
|
||||
@@ -831,16 +875,19 @@ iterator mvalues*[A](t: CountTableRef[A]): var int =
|
||||
for h in 0..high(t.data):
|
||||
if t.data[h].val != 0: yield t.data[h].val
|
||||
|
||||
proc `[]`*[A](t: CountTableRef[A], key: A): int =
|
||||
## retrieves the value at ``t[key]``. If `key` is not in `t`,
|
||||
## 0 is returned. One can check with ``hasKey`` whether the key
|
||||
## exists.
|
||||
proc `[]`*[A](t: CountTableRef[A], key: A): var int {.deprecatedGet.} =
|
||||
## retrieves the value at ``t[key]``. The value can be modified.
|
||||
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||
result = t[][key]
|
||||
|
||||
proc mget*[A](t: CountTableRef[A], key: A): var int =
|
||||
proc mget*[A](t: CountTableRef[A], key: A): var int {.deprecated.} =
|
||||
## retrieves the value at ``t[key]``. The value can be modified.
|
||||
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
|
||||
result = t[].mget(key)
|
||||
## If `key` is not in `t`, the ``KeyError`` exception is raised.
|
||||
## Use ```[]``` instead.
|
||||
result = t[][key]
|
||||
|
||||
proc getOrDefault*[A](t: CountTableRef[A], key: A): int =
|
||||
getOrDefaultImpl(t, key)
|
||||
|
||||
proc hasKey*[A](t: CountTableRef[A], key: A): bool =
|
||||
## returns true iff `key` is in the table `t`.
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
#
|
||||
|
||||
## This module implements efficient computations of hash values for diverse
|
||||
## Nim types. All the procs are based on these two building blocks: the `!&
|
||||
## proc <#!&>`_ used to start or mix a hash value, and the `!$ proc <#!$>`_
|
||||
## used to *finish* the hash value. If you want to implement hash procs for
|
||||
## Nim types. All the procs are based on these two building blocks:
|
||||
## - `!& proc <#!&>`_ used to start or mix a hash value, and
|
||||
## - `!$ proc <#!$>`_ used to *finish* the hash value.
|
||||
## If you want to implement hash procs for
|
||||
## your custom types you will end up writing the following kind of skeleton of
|
||||
## code:
|
||||
##
|
||||
@@ -108,7 +109,7 @@ proc hash*(x: int): Hash {.inline.} =
|
||||
result = x
|
||||
|
||||
proc hash*(x: int64): Hash {.inline.} =
|
||||
## efficient hashing of integers
|
||||
## efficient hashing of int64 integers
|
||||
result = toU32(x)
|
||||
|
||||
proc hash*(x: char): Hash {.inline.} =
|
||||
@@ -126,6 +127,16 @@ proc hash*(x: string): Hash =
|
||||
h = h !& ord(x[i])
|
||||
result = !$h
|
||||
|
||||
proc hash*(sBuf: string, sPos, ePos: int): Hash =
|
||||
## efficient hashing of a string buffer, from starting
|
||||
## position `sPos` to ending position `ePos`
|
||||
##
|
||||
## ``hash(myStr, 0, myStr.high)`` is equivalent to ``hash(myStr)``
|
||||
var h: Hash = 0
|
||||
for i in sPos..ePos:
|
||||
h = h !& ord(sBuf[i])
|
||||
result = !$h
|
||||
|
||||
proc hashIgnoreStyle*(x: string): Hash =
|
||||
## efficient hashing of strings; style is ignored
|
||||
var h: Hash = 0
|
||||
@@ -145,6 +156,27 @@ proc hashIgnoreStyle*(x: string): Hash =
|
||||
|
||||
result = !$h
|
||||
|
||||
proc hashIgnoreStyle*(sBuf: string, sPos, ePos: int): Hash =
|
||||
## efficient hashing of a string buffer, from starting
|
||||
## position `sPos` to ending position `ePos`; style is ignored
|
||||
##
|
||||
## ``hashIgnoreStyle(myBuf, 0, myBuf.high)`` is equivalent
|
||||
## to ``hashIgnoreStyle(myBuf)``
|
||||
var h: Hash = 0
|
||||
var i = sPos
|
||||
while i <= ePos:
|
||||
var c = sBuf[i]
|
||||
if c == '_':
|
||||
inc(i)
|
||||
elif isMagicIdentSeparatorRune(cstring(sBuf), i):
|
||||
inc(i, magicIdentSeparatorRuneByteWidth)
|
||||
else:
|
||||
if c in {'A'..'Z'}:
|
||||
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
|
||||
h = h !& ord(c)
|
||||
inc(i)
|
||||
result = !$h
|
||||
|
||||
proc hashIgnoreCase*(x: string): Hash =
|
||||
## efficient hashing of strings; case is ignored
|
||||
var h: Hash = 0
|
||||
@@ -155,7 +187,22 @@ proc hashIgnoreCase*(x: string): Hash =
|
||||
h = h !& ord(c)
|
||||
result = !$h
|
||||
|
||||
proc hashIgnoreCase*(sBuf: string, sPos, ePos: int): Hash =
|
||||
## efficient hashing of a string buffer, from starting
|
||||
## position `sPos` to ending position `ePos`; case is ignored
|
||||
##
|
||||
## ``hashIgnoreCase(myBuf, 0, myBuf.high)`` is equivalent
|
||||
## to ``hashIgnoreCase(myBuf)``
|
||||
var h: Hash = 0
|
||||
for i in sPos..ePos:
|
||||
var c = sBuf[i]
|
||||
if c in {'A'..'Z'}:
|
||||
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
|
||||
h = h !& ord(c)
|
||||
result = !$h
|
||||
|
||||
proc hash*(x: float): Hash {.inline.} =
|
||||
## efficient hashing of floats.
|
||||
var y = x + 1.0
|
||||
result = cast[ptr Hash](addr(y))[]
|
||||
|
||||
@@ -173,10 +220,29 @@ proc hash*[T: tuple](x: T): Hash =
|
||||
result = !$result
|
||||
|
||||
proc hash*[A](x: openArray[A]): Hash =
|
||||
## efficient hashing of arrays and sequences.
|
||||
for it in items(x): result = result !& hash(it)
|
||||
result = !$result
|
||||
|
||||
proc hash*[A](aBuf: openArray[A], sPos, ePos: int): Hash =
|
||||
## efficient hashing of portions of arrays and sequences.
|
||||
##
|
||||
## ``hash(myBuf, 0, myBuf.high)`` is equivalent to ``hash(myBuf)``
|
||||
for i in sPos..ePos:
|
||||
result = result !& hash(aBuf[i])
|
||||
result = !$result
|
||||
|
||||
proc hash*[A](x: set[A]): Hash =
|
||||
## efficient hashing of sets.
|
||||
for it in items(x): result = result !& hash(it)
|
||||
result = !$result
|
||||
|
||||
when isMainModule:
|
||||
doAssert( hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13) )
|
||||
doAssert( hashIgnoreCase("aa bb aaaa1234") == hash("aa bb aaaa1234") )
|
||||
doAssert( hashIgnoreStyle("aa bb aaaa1234") == hashIgnoreCase("aa bb aaaa1234") )
|
||||
let xx = @['H','e','l','l','o']
|
||||
let ss = "Hello"
|
||||
doAssert( hash(xx) == hash(ss) )
|
||||
doAssert( hash(xx) == hash(xx, 0, xx.high) )
|
||||
doAssert( hash(ss) == hash(ss, 0, ss.high) )
|
||||
|
||||
@@ -77,7 +77,7 @@ type
|
||||
## console
|
||||
|
||||
FileLogger* = ref object of Logger ## logger that writes the messages to a file
|
||||
f: File
|
||||
file*: File ## the wrapped file.
|
||||
|
||||
RollingFileLogger* = ref object of FileLogger ## logger that writes the
|
||||
## messages to a file and
|
||||
@@ -92,7 +92,9 @@ type
|
||||
{.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger,
|
||||
PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].}
|
||||
|
||||
proc substituteLog(frmt: string, level: Level, args: varargs[string, `$`]): string =
|
||||
proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): string =
|
||||
## Format a log message using the ``frmt`` format string, ``level`` and varargs.
|
||||
## See the module documentation for the format string syntax.
|
||||
var msgLen = 0
|
||||
for arg in args:
|
||||
msgLen += arg.len
|
||||
@@ -124,7 +126,7 @@ proc substituteLog(frmt: string, level: Level, args: varargs[string, `$`]): stri
|
||||
|
||||
method log*(logger: Logger, level: Level, args: varargs[string, `$`]) {.
|
||||
raises: [Exception],
|
||||
tags: [TimeEffect, WriteIOEffect, ReadIOEffect].} =
|
||||
tags: [TimeEffect, WriteIOEffect, ReadIOEffect], base.} =
|
||||
## Override this method in custom loggers. Default implementation does
|
||||
## nothing.
|
||||
discard
|
||||
@@ -133,15 +135,17 @@ method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) =
|
||||
## Logs to the console using ``logger`` only.
|
||||
if level >= logger.levelThreshold:
|
||||
writeLine(stdout, substituteLog(logger.fmtStr, level, args))
|
||||
if level in {lvlError, lvlFatal}: flushFile(stdout)
|
||||
|
||||
method log*(logger: FileLogger, level: Level, args: varargs[string, `$`]) =
|
||||
## Logs to a file using ``logger`` only.
|
||||
if level >= logger.levelThreshold:
|
||||
writeLine(logger.f, substituteLog(logger.fmtStr, level, args))
|
||||
writeLine(logger.file, substituteLog(logger.fmtStr, level, args))
|
||||
if level in {lvlError, lvlFatal}: flushFile(logger.file)
|
||||
|
||||
proc defaultFilename*(): string =
|
||||
## Returns the default filename for a logger.
|
||||
var (path, name, ext) = splitFile(getAppFilename())
|
||||
var (path, name, _) = splitFile(getAppFilename())
|
||||
result = changeFileExt(path / name, "log")
|
||||
|
||||
proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): ConsoleLogger =
|
||||
@@ -160,14 +164,14 @@ proc newFileLogger*(filename = defaultFilename(),
|
||||
## (-1: use system defaults, 0: unbuffered, >0: fixed buffer size).
|
||||
new(result)
|
||||
result.levelThreshold = levelThreshold
|
||||
result.f = open(filename, mode, bufSize = bufSize)
|
||||
result.file = open(filename, mode, bufSize = bufSize)
|
||||
result.fmtStr = fmtStr
|
||||
|
||||
# ------
|
||||
|
||||
proc countLogLines(logger: RollingFileLogger): int =
|
||||
result = 0
|
||||
for line in logger.f.lines():
|
||||
for line in logger.file.lines():
|
||||
result.inc()
|
||||
|
||||
proc countFiles(filename: string): int =
|
||||
@@ -200,7 +204,7 @@ proc newRollingFileLogger*(filename = defaultFilename(),
|
||||
result.fmtStr = fmtStr
|
||||
result.maxLines = maxLines
|
||||
result.bufSize = bufSize
|
||||
result.f = open(filename, mode, bufSize=result.bufSize)
|
||||
result.file = open(filename, mode, bufSize=result.bufSize)
|
||||
result.curLine = 0
|
||||
result.baseName = filename
|
||||
result.baseMode = mode
|
||||
@@ -222,13 +226,14 @@ method log*(logger: RollingFileLogger, level: Level, args: varargs[string, `$`])
|
||||
## Logs to a file using rolling ``logger`` only.
|
||||
if level >= logger.levelThreshold:
|
||||
if logger.curLine >= logger.maxLines:
|
||||
logger.f.close()
|
||||
logger.file.close()
|
||||
rotate(logger)
|
||||
logger.logFiles.inc
|
||||
logger.curLine = 0
|
||||
logger.f = open(logger.baseName, logger.baseMode, bufSize = logger.bufSize)
|
||||
logger.file = open(logger.baseName, logger.baseMode, bufSize = logger.bufSize)
|
||||
|
||||
writeLine(logger.f, substituteLog(logger.fmtStr, level, args))
|
||||
writeLine(logger.file, substituteLog(logger.fmtStr, level, args))
|
||||
if level in {lvlError, lvlFatal}: flushFile(logger.file)
|
||||
logger.curLine.inc
|
||||
|
||||
# --------
|
||||
|
||||
@@ -176,7 +176,7 @@ proc loadAny(p: var JsonParser, a: Any, t: var Table[BiggestInt, pointer]) =
|
||||
setPointer(a, nil)
|
||||
next(p)
|
||||
of jsonInt:
|
||||
setPointer(a, t[p.getInt])
|
||||
setPointer(a, t.getOrDefault(p.getInt))
|
||||
next(p)
|
||||
of jsonArrayStart:
|
||||
next(p)
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
## Module for computing MD5 checksums.
|
||||
|
||||
import unsigned
|
||||
|
||||
type
|
||||
MD5State = array[0..3, uint32]
|
||||
MD5Block = array[0..15, uint32]
|
||||
|
||||
@@ -499,7 +499,7 @@ proc newMimetypes*(): MimeDB =
|
||||
proc getMimetype*(mimedb: MimeDB, ext: string, default = "text/plain"): string =
|
||||
## Gets mimetype which corresponds to ``ext``. Returns ``default`` if ``ext``
|
||||
## could not be found.
|
||||
result = mimedb.mimes[ext]
|
||||
result = mimedb.mimes.getOrDefault(ext)
|
||||
if result == "":
|
||||
return default
|
||||
|
||||
|
||||
@@ -26,8 +26,10 @@ when not declared(getEnv) or defined(nimscript):
|
||||
## to an environment variable
|
||||
|
||||
ReadDirEffect* = object of ReadIOEffect ## effect that denotes a write
|
||||
## operation to the directory structure
|
||||
WriteDirEffect* = object of WriteIOEffect ## effect that denotes a write operation to
|
||||
## operation to the directory
|
||||
## structure
|
||||
WriteDirEffect* = object of WriteIOEffect ## effect that denotes a write
|
||||
## operation to
|
||||
## the directory structure
|
||||
|
||||
OSErrorCode* = distinct int32 ## Specifies an OS Error Code.
|
||||
@@ -63,13 +65,13 @@ when not declared(getEnv) or defined(nimscript):
|
||||
AltSep* = '/'
|
||||
## An alternative character used by the operating system to separate
|
||||
## pathname components, or the same as `DirSep` if only one separator
|
||||
## character exists. This is set to '/' on Windows systems where `DirSep`
|
||||
## is a backslash.
|
||||
## character exists. This is set to '/' on Windows systems
|
||||
## where `DirSep` is a backslash.
|
||||
|
||||
PathSep* = ':'
|
||||
## The character conventionally used by the operating system to separate
|
||||
## search patch components (as in PATH), such as ':' for POSIX or ';' for
|
||||
## Windows.
|
||||
## search patch components (as in PATH), such as ':' for POSIX
|
||||
## or ';' for Windows.
|
||||
|
||||
FileSystemCaseSensitive* = true
|
||||
## true if the file system is case sensitive, false otherwise. Used by
|
||||
@@ -104,7 +106,8 @@ when not declared(getEnv) or defined(nimscript):
|
||||
# MacOS directory separator is a colon ":" which is the only character not
|
||||
# allowed in filenames.
|
||||
#
|
||||
# A path containing no colon or which begins with a colon is a partial path.
|
||||
# A path containing no colon or which begins with a colon is a partial
|
||||
# path.
|
||||
# E.g. ":kalle:petter" ":kalle" "kalle"
|
||||
#
|
||||
# All other paths are full (absolute) paths. E.g. "HD:kalle:" "HD:"
|
||||
@@ -206,9 +209,9 @@ when not declared(getEnv) or defined(nimscript):
|
||||
|
||||
proc joinPath*(parts: varargs[string]): string {.noSideEffect,
|
||||
rtl, extern: "nos$1OpenArray".} =
|
||||
## The same as `joinPath(head, tail)`, but works with any number of directory
|
||||
## parts. You need to pass at least one element or the proc will assert in
|
||||
## debug builds and crash on release builds.
|
||||
## The same as `joinPath(head, tail)`, but works with any number of
|
||||
## directory parts. You need to pass at least one element or the proc
|
||||
## will assert in debug builds and crash on release builds.
|
||||
result = parts[0]
|
||||
for i in 1..high(parts):
|
||||
result = joinPath(result, parts[i])
|
||||
@@ -316,8 +319,8 @@ when not declared(getEnv) or defined(nimscript):
|
||||
if inclusive: yield path
|
||||
|
||||
proc `/../` * (head, tail: string): string {.noSideEffect.} =
|
||||
## The same as ``parentDir(head) / tail`` unless there is no parent directory.
|
||||
## Then ``head / tail`` is performed instead.
|
||||
## The same as ``parentDir(head) / tail`` unless there is no parent
|
||||
## directory. Then ``head / tail`` is performed instead.
|
||||
let sepPos = parentDirPos(head)
|
||||
if sepPos >= 0:
|
||||
result = substr(head, 0, sepPos-1) / tail
|
||||
@@ -500,7 +503,8 @@ when defined(nimdoc) and not declared(os):
|
||||
proc existsFile(x: string): bool = discard
|
||||
|
||||
when declared(getEnv) or defined(nimscript):
|
||||
proc getHomeDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect].} =
|
||||
proc getHomeDir*(): string {.rtl, extern: "nos$1",
|
||||
tags: [ReadEnvEffect, ReadIOEffect].} =
|
||||
## Returns the home directory of the current user.
|
||||
##
|
||||
## This proc is wrapped by the expandTilde proc for the convenience of
|
||||
@@ -508,18 +512,21 @@ when declared(getEnv) or defined(nimscript):
|
||||
when defined(windows): return string(getEnv("USERPROFILE")) & "\\"
|
||||
else: return string(getEnv("HOME")) & "/"
|
||||
|
||||
proc getConfigDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect, ReadIOEffect].} =
|
||||
proc getConfigDir*(): string {.rtl, extern: "nos$1",
|
||||
tags: [ReadEnvEffect, ReadIOEffect].} =
|
||||
## Returns the config directory of the current user for applications.
|
||||
when defined(windows): return string(getEnv("APPDATA")) & "\\"
|
||||
else: return string(getEnv("HOME")) & "/.config/"
|
||||
|
||||
proc getTempDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect].} =
|
||||
proc getTempDir*(): string {.rtl, extern: "nos$1",
|
||||
tags: [ReadEnvEffect, ReadIOEffect].} =
|
||||
## Returns the temporary directory of the current user for applications to
|
||||
## save temporary files in.
|
||||
when defined(windows): return string(getEnv("TEMP")) & "\\"
|
||||
else: return "/tmp/"
|
||||
|
||||
proc expandTilde*(path: string): string {.tags: [ReadEnvEffect, ReadIOEffect].} =
|
||||
proc expandTilde*(path: string): string {.
|
||||
tags: [ReadEnvEffect, ReadIOEffect].} =
|
||||
## Expands a path starting with ``~/`` to a full path.
|
||||
##
|
||||
## If `path` starts with the tilde character and is followed by `/` or `\\`
|
||||
@@ -527,8 +534,8 @@ when declared(getEnv) or defined(nimscript):
|
||||
## the getHomeDir() proc, otherwise the input path will be returned without
|
||||
## modification.
|
||||
##
|
||||
## The behaviour of this proc is the same on the Windows platform despite not
|
||||
## having this convention. Example:
|
||||
## The behaviour of this proc is the same on the Windows platform despite
|
||||
## not having this convention. Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## let configFile = expandTilde("~" / "appname.cfg")
|
||||
@@ -549,7 +556,8 @@ when declared(getEnv) or defined(nimscript):
|
||||
yield substr(s, first, last-1)
|
||||
inc(last)
|
||||
|
||||
proc findExe*(exe: string): string {.tags: [ReadDirEffect, ReadEnvEffect, ReadIOEffect].} =
|
||||
proc findExe*(exe: string): string {.
|
||||
tags: [ReadDirEffect, ReadEnvEffect, ReadIOEffect].} =
|
||||
## Searches for `exe` in the current working directory and then
|
||||
## in directories listed in the ``PATH`` environment variable.
|
||||
## Returns "" if the `exe` cannot be found. On DOS-like platforms, `exe`
|
||||
|
||||
@@ -145,8 +145,8 @@ proc next*(s: var ScgiState, timeout: int = -1): bool =
|
||||
L = L * 10 + ord(d) - ord('0')
|
||||
recvBuffer(s, L+1)
|
||||
s.headers = parseHeaders(s.input, L)
|
||||
if s.headers["SCGI"] != "1": raiseScgiError("SCGI Version 1 expected")
|
||||
L = parseInt(s.headers["CONTENT_LENGTH"])
|
||||
if s.headers.getOrDefault("SCGI") != "1": raiseScgiError("SCGI Version 1 expected")
|
||||
L = parseInt(s.headers.getOrDefault("CONTENT_LENGTH"))
|
||||
recvBuffer(s, L)
|
||||
return true
|
||||
|
||||
@@ -221,10 +221,10 @@ proc handleClientRead(client: AsyncClient, s: AsyncScgiState) =
|
||||
case ret
|
||||
of ReadFullLine:
|
||||
client.headers = parseHeaders(client.input, client.input.len-1)
|
||||
if client.headers["SCGI"] != "1": raiseScgiError("SCGI Version 1 expected")
|
||||
if client.headers.getOrDefault("SCGI") != "1": raiseScgiError("SCGI Version 1 expected")
|
||||
client.input = "" # For next part
|
||||
|
||||
let contentLen = parseInt(client.headers["CONTENT_LENGTH"])
|
||||
let contentLen = parseInt(client.headers.getOrDefault("CONTENT_LENGTH"))
|
||||
if contentLen > 0:
|
||||
client.mode = ClientReadContent
|
||||
else:
|
||||
@@ -232,7 +232,8 @@ proc handleClientRead(client: AsyncClient, s: AsyncScgiState) =
|
||||
checkCloseSocket(client)
|
||||
of ReadPartialLine, ReadDisconnected, ReadNone: return
|
||||
of ClientReadContent:
|
||||
let L = parseInt(client.headers["CONTENT_LENGTH"])-client.input.len
|
||||
let L = parseInt(client.headers.getOrDefault("CONTENT_LENGTH")) -
|
||||
client.input.len
|
||||
if L > 0:
|
||||
let ret = recvBufferAsync(client, L)
|
||||
case ret
|
||||
|
||||
@@ -101,22 +101,32 @@ proc rawGet(t: StringTableRef, key: string): int =
|
||||
h = nextTry(h, high(t.data))
|
||||
result = - 1
|
||||
|
||||
proc `[]`*(t: StringTableRef, key: string): string {.rtl, extern: "nstGet".} =
|
||||
## retrieves the value at ``t[key]``. If `key` is not in `t`, "" is returned
|
||||
## and no exception is raised. One can check with ``hasKey`` whether the key
|
||||
## exists.
|
||||
template get(t: StringTableRef, key: string): stmt {.immediate.} =
|
||||
var index = rawGet(t, key)
|
||||
if index >= 0: result = t.data[index].val
|
||||
else:
|
||||
when compiles($key):
|
||||
raise newException(KeyError, "key not found: " & $key)
|
||||
else:
|
||||
raise newException(KeyError, "key not found")
|
||||
|
||||
proc `[]`*(t: StringTableRef, key: string): var string {.
|
||||
rtl, extern: "nstTake", deprecatedGet.} =
|
||||
## retrieves the location at ``t[key]``. If `key` is not in `t`, the
|
||||
## ``KeyError`` exception is raised. One can check with ``hasKey`` whether
|
||||
## the key exists.
|
||||
get(t, key)
|
||||
|
||||
proc mget*(t: StringTableRef, key: string): var string {.deprecated.} =
|
||||
## retrieves the location at ``t[key]``. If `key` is not in `t`, the
|
||||
## ``KeyError`` exception is raised. Use ```[]``` instead.
|
||||
get(t, key)
|
||||
|
||||
proc getOrDefault*(t: StringTableRef; key: string): string =
|
||||
var index = rawGet(t, key)
|
||||
if index >= 0: result = t.data[index].val
|
||||
else: result = ""
|
||||
|
||||
proc mget*(t: StringTableRef, key: string): var string {.
|
||||
rtl, extern: "nstTake".} =
|
||||
## retrieves the location at ``t[key]``. If `key` is not in `t`, the
|
||||
## ``KeyError`` exception is raised.
|
||||
var index = rawGet(t, key)
|
||||
if index >= 0: result = t.data[index].val
|
||||
else: raise newException(KeyError, "key does not exist: " & key)
|
||||
|
||||
proc hasKey*(t: StringTableRef, key: string): bool {.rtl, extern: "nst$1".} =
|
||||
## returns true iff `key` is in the table `t`.
|
||||
result = rawGet(t, key) >= 0
|
||||
@@ -152,7 +162,7 @@ proc raiseFormatException(s: string) =
|
||||
raise e
|
||||
|
||||
proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string =
|
||||
if hasKey(t, key): return t[key]
|
||||
if hasKey(t, key): return t.getOrDefault(key)
|
||||
# hm difficult: assume safety in taint mode here. XXX This is dangerous!
|
||||
if useEnvironment in flags: result = os.getEnv(key).string
|
||||
else: result = ""
|
||||
@@ -248,7 +258,7 @@ when isMainModule:
|
||||
assert x["k"] == "v"
|
||||
assert x["11"] == "22"
|
||||
assert x["565"] == "67"
|
||||
x.mget("11") = "23"
|
||||
x["11"] = "23"
|
||||
assert x["11"] == "23"
|
||||
|
||||
x.clear(modeCaseInsensitive)
|
||||
|
||||
@@ -60,6 +60,132 @@ const
|
||||
## doAssert "01234".find(invalid) == -1
|
||||
## doAssert "01A34".find(invalid) == 2
|
||||
|
||||
proc isAlpha*(c: char): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsAlphaChar".}=
|
||||
## Checks whether or not `c` is alphabetical.
|
||||
##
|
||||
## This checks a-z, A-Z ASCII characters only.
|
||||
return c in Letters
|
||||
|
||||
proc isAlphaNumeric*(c: char): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsAlphaNumericChar".}=
|
||||
## Checks whether or not `c` is alphanumeric.
|
||||
##
|
||||
## This checks a-z, A-Z, 0-9 ASCII characters only.
|
||||
return c in Letters or c in Digits
|
||||
|
||||
proc isDigit*(c: char): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsDigitChar".}=
|
||||
## Checks whether or not `c` is a number.
|
||||
##
|
||||
## This checks 0-9 ASCII characters only.
|
||||
return c in Digits
|
||||
|
||||
proc isSpace*(c: char): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsSpaceChar".}=
|
||||
## Checks whether or not `c` is a whitespace character.
|
||||
return c in Whitespace
|
||||
|
||||
proc isLower*(c: char): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsLowerChar".}=
|
||||
## Checks whether or not `c` is a lower case character.
|
||||
##
|
||||
## This checks ASCII characters only.
|
||||
return c in {'a'..'z'}
|
||||
|
||||
proc isUpper*(c: char): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsUpperChar".}=
|
||||
## Checks whether or not `c` is an upper case character.
|
||||
##
|
||||
## This checks ASCII characters only.
|
||||
return c in {'A'..'Z'}
|
||||
|
||||
proc isAlpha*(s: string): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsAlphaStr".}=
|
||||
## Checks whether or not `s` is alphabetical.
|
||||
##
|
||||
## This checks a-z, A-Z ASCII characters only.
|
||||
## Returns true if all characters in `s` are
|
||||
## alphabetic and there is at least one character
|
||||
## in `s`.
|
||||
if s.len() == 0:
|
||||
return false
|
||||
|
||||
result = true
|
||||
for c in s:
|
||||
result = c.isAlpha() and result
|
||||
|
||||
proc isAlphaNumeric*(s: string): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsAlphaNumericStr".}=
|
||||
## Checks whether or not `s` is alphanumeric.
|
||||
##
|
||||
## This checks a-z, A-Z, 0-9 ASCII characters only.
|
||||
## Returns true if all characters in `s` are
|
||||
## alpanumeric and there is at least one character
|
||||
## in `s`.
|
||||
if s.len() == 0:
|
||||
return false
|
||||
|
||||
result = true
|
||||
for c in s:
|
||||
result = c.isAlphaNumeric() and result
|
||||
|
||||
proc isDigit*(s: string): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsDigitStr".}=
|
||||
## Checks whether or not `s` is a numeric value.
|
||||
##
|
||||
## This checks 0-9 ASCII characters only.
|
||||
## Returns true if all characters in `s` are
|
||||
## numeric and there is at least one character
|
||||
## in `s`.
|
||||
if s.len() == 0:
|
||||
return false
|
||||
|
||||
result = true
|
||||
for c in s:
|
||||
result = c.isDigit() and result
|
||||
|
||||
proc isSpace*(s: string): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsSpaceStr".}=
|
||||
## Checks whether or not `s` is completely whitespace.
|
||||
##
|
||||
## Returns true if all characters in `s` are whitespace
|
||||
## characters and there is at least one character in `s`.
|
||||
if s.len() == 0:
|
||||
return false
|
||||
|
||||
result = true
|
||||
for c in s:
|
||||
result = c.isSpace() and result
|
||||
|
||||
proc isLower*(s: string): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsLowerStr".}=
|
||||
## Checks whether or not `s` contains all lower case characters.
|
||||
##
|
||||
## This checks ASCII characters only.
|
||||
## Returns true if all characters in `s` are lower case
|
||||
## and there is at least one character in `s`.
|
||||
if s.len() == 0:
|
||||
return false
|
||||
|
||||
result = true
|
||||
for c in s:
|
||||
result = c.isLower() and result
|
||||
|
||||
proc isUpper*(s: string): bool {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuIsUpperStr".}=
|
||||
## Checks whether or not `s` contains all upper case characters.
|
||||
##
|
||||
## This checks ASCII characters only.
|
||||
## Returns true if all characters in `s` are upper case
|
||||
## and there is at least one character in `s`.
|
||||
if s.len() == 0:
|
||||
return false
|
||||
|
||||
result = true
|
||||
for c in s:
|
||||
result = c.isUpper() and result
|
||||
|
||||
proc toLower*(c: char): char {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuToLowerChar".} =
|
||||
## Converts `c` into lower case.
|
||||
@@ -1526,3 +1652,55 @@ when isMainModule:
|
||||
doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos"
|
||||
|
||||
doAssert " foo\n bar".indent(4, "Q") == "QQQQ foo\nQQQQ bar"
|
||||
|
||||
doAssert isAlpha('r')
|
||||
doAssert isAlpha('A')
|
||||
doAssert(not isAlpha('$'))
|
||||
|
||||
doAssert isAlpha("Rasp")
|
||||
doAssert isAlpha("Args")
|
||||
doAssert(not isAlpha("$Tomato"))
|
||||
|
||||
doAssert isAlphaNumeric('3')
|
||||
doAssert isAlphaNumeric('R')
|
||||
doAssert(not isAlphaNumeric('!'))
|
||||
|
||||
doAssert isAlphaNumeric("34ABc")
|
||||
doAssert isAlphaNumeric("Rad")
|
||||
doAssert isAlphaNumeric("1234")
|
||||
doAssert(not isAlphaNumeric("@nose"))
|
||||
|
||||
doAssert isDigit('3')
|
||||
doAssert(not isDigit('a'))
|
||||
doAssert(not isDigit('%'))
|
||||
|
||||
doAssert isDigit("12533")
|
||||
doAssert(not isDigit("12.33"))
|
||||
doAssert(not isDigit("A45b"))
|
||||
|
||||
doAssert isSpace('\t')
|
||||
doAssert isSpace('\l')
|
||||
doAssert(not isSpace('A'))
|
||||
|
||||
doAssert isSpace("\t\l \v\r\f")
|
||||
doAssert isSpace(" ")
|
||||
doAssert(not isSpace("ABc \td"))
|
||||
|
||||
doAssert isLower('a')
|
||||
doAssert isLower('z')
|
||||
doAssert(not isLower('A'))
|
||||
doAssert(not isLower('5'))
|
||||
doAssert(not isLower('&'))
|
||||
|
||||
doAssert isLower("abcd")
|
||||
doAssert(not isLower("abCD"))
|
||||
doAssert(not isLower("33aa"))
|
||||
|
||||
doAssert isUpper('A')
|
||||
doAssert(not isUpper('b'))
|
||||
doAssert(not isUpper('5'))
|
||||
doAssert(not isUpper('%'))
|
||||
|
||||
doAssert isUpper("ABC")
|
||||
doAssert(not isUpper("AAcc"))
|
||||
doAssert(not isUpper("A#$"))
|
||||
|
||||
@@ -150,6 +150,8 @@ template test*(name: expr, body: stmt): stmt {.immediate, dirty.} =
|
||||
try:
|
||||
when declared(testSetupIMPLFlag): testSetupIMPL()
|
||||
body
|
||||
when declared(testTeardownIMPLFlag):
|
||||
defer: testTeardownIMPL()
|
||||
|
||||
except:
|
||||
when not defined(js):
|
||||
@@ -158,7 +160,6 @@ template test*(name: expr, body: stmt): stmt {.immediate, dirty.} =
|
||||
fail()
|
||||
|
||||
finally:
|
||||
when declared(testTeardownIMPLFlag): testTeardownIMPL()
|
||||
testDone name, testStatusIMPL
|
||||
|
||||
proc checkpoint*(msg: string) =
|
||||
|
||||
@@ -139,11 +139,16 @@ proc delete*(n: XmlNode, i: Natural) {.noSideEffect.} =
|
||||
assert n.k == xnElement
|
||||
n.s.delete(i)
|
||||
|
||||
proc mget* (n: var XmlNode, i: int): var XmlNode {.inline.} =
|
||||
proc `[]`* (n: var XmlNode, i: int): var XmlNode {.inline.} =
|
||||
## returns the `i`'th child of `n` so that it can be modified
|
||||
assert n.k == xnElement
|
||||
result = n.s[i]
|
||||
|
||||
proc mget*(n: var XmlNode, i: int): var XmlNode {.inline, deprecated.} =
|
||||
## returns the `i`'th child of `n` so that it can be modified. Use ```[]```
|
||||
## instead.
|
||||
n[i]
|
||||
|
||||
iterator items*(n: XmlNode): XmlNode {.inline.} =
|
||||
## iterates over any child of `n`.
|
||||
assert n.k == xnElement
|
||||
@@ -152,7 +157,7 @@ iterator items*(n: XmlNode): XmlNode {.inline.} =
|
||||
iterator mitems*(n: var XmlNode): var XmlNode {.inline.} =
|
||||
## iterates over any child of `n`.
|
||||
assert n.k == xnElement
|
||||
for i in 0 .. n.len-1: yield mget(n, i)
|
||||
for i in 0 .. n.len-1: yield n[i]
|
||||
|
||||
proc attrs*(n: XmlNode): XmlAttributes {.inline.} =
|
||||
## gets the attributes belonging to `n`.
|
||||
@@ -337,7 +342,7 @@ proc attr*(n: XmlNode, name: string): string =
|
||||
## Returns "" on failure.
|
||||
assert n.kind == xnElement
|
||||
if n.attrs == nil: return ""
|
||||
return n.attrs[name]
|
||||
return n.attrs.getOrDefault(name)
|
||||
|
||||
proc findAll*(n: XmlNode, tag: string, result: var seq[XmlNode]) =
|
||||
## Iterates over all the children of `n` returning those matching `tag`.
|
||||
|
||||
@@ -1260,6 +1260,15 @@ const
|
||||
hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own
|
||||
taintMode = compileOption("taintmode")
|
||||
|
||||
when defined(boehmgc):
|
||||
when defined(windows):
|
||||
const boehmLib = "boehmgc.dll"
|
||||
elif defined(macosx):
|
||||
const boehmLib = "libgc.dylib"
|
||||
else:
|
||||
const boehmLib = "libgc.so.1"
|
||||
{.pragma: boehmGC, noconv, dynlib: boehmLib.}
|
||||
|
||||
when taintMode:
|
||||
type TaintedString* = distinct string ## a distinct string type that
|
||||
## is `tainted`:idx:. It is an alias for
|
||||
@@ -2160,53 +2169,6 @@ proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} =
|
||||
result = s[L]
|
||||
setLen(s, L)
|
||||
|
||||
proc each*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] {.
|
||||
deprecated.} =
|
||||
## The well-known ``map`` operation from functional programming. Applies
|
||||
## `op` to every item in `data` and returns the result as a sequence.
|
||||
##
|
||||
## **Deprecated since version 0.9:** Use the ``map`` proc instead.
|
||||
newSeq(result, data.len)
|
||||
for i in 0..data.len-1: result[i] = op(data[i])
|
||||
|
||||
proc each*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) {.
|
||||
deprecated.} =
|
||||
## The well-known ``map`` operation from functional programming. Applies
|
||||
## `op` to every item in `data` modifying it directly.
|
||||
##
|
||||
## **Deprecated since version 0.9:** Use the ``map`` proc instead.
|
||||
for i in 0..data.len-1: op(data[i])
|
||||
|
||||
proc map*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] =
|
||||
## Returns a new sequence with the results of `op` applied to every item in
|
||||
## `data`.
|
||||
##
|
||||
## Since the input is not modified you can use this version of ``map`` to
|
||||
## transform the type of the elements in the input sequence. Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## let
|
||||
## a = @[1, 2, 3, 4]
|
||||
## b = map(a, proc(x: int): string = $x)
|
||||
## assert b == @["1", "2", "3", "4"]
|
||||
newSeq(result, data.len)
|
||||
for i in 0..data.len-1: result[i] = op(data[i])
|
||||
|
||||
proc map*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) =
|
||||
## Applies `op` to every item in `data` modifying it directly.
|
||||
##
|
||||
## Note that this version of ``map`` requires your input and output types to
|
||||
## be the same, since they are modified in-place. Example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## var a = @["1", "2", "3", "4"]
|
||||
## echo repr(a)
|
||||
## # --> ["1", "2", "3", "4"]
|
||||
## map(a, proc(x: var string) = x &= "42")
|
||||
## echo repr(a)
|
||||
## # --> ["142", "242", "342", "442"]
|
||||
for i in 0..data.len-1: op(data[i])
|
||||
|
||||
iterator fields*[T: tuple|object](x: T): RootObj {.
|
||||
magic: "Fields", noSideEffect.}
|
||||
## iterates over every field of `x`. Warning: This really transforms
|
||||
|
||||
@@ -51,3 +51,8 @@ when defined(nimlocks):
|
||||
{.pragma: benign, gcsafe, locks: 0.}
|
||||
else:
|
||||
{.pragma: benign, gcsafe.}
|
||||
|
||||
when defined(nimTableGet):
|
||||
{.pragma: deprecatedGet, deprecated.}
|
||||
else:
|
||||
{.pragma: deprecatedGet.}
|
||||
|
||||
@@ -66,41 +66,34 @@ proc raiseOutOfMem() {.noinline.} =
|
||||
quit(1)
|
||||
|
||||
when defined(boehmgc):
|
||||
when defined(windows):
|
||||
const boehmLib = "boehmgc.dll"
|
||||
elif defined(macosx):
|
||||
const boehmLib = "libgc.dylib"
|
||||
else:
|
||||
const boehmLib = "libgc.so.1"
|
||||
|
||||
proc boehmGCinit {.importc: "GC_init", dynlib: boehmLib.}
|
||||
proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.}
|
||||
proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.}
|
||||
proc boehmGCinit {.importc: "GC_init", boehmGC.}
|
||||
proc boehmGC_disable {.importc: "GC_disable", boehmGC.}
|
||||
proc boehmGC_enable {.importc: "GC_enable", boehmGC.}
|
||||
proc boehmGCincremental {.
|
||||
importc: "GC_enable_incremental", dynlib: boehmLib.}
|
||||
proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.}
|
||||
proc boehmAlloc(size: int): pointer {.
|
||||
importc: "GC_malloc", dynlib: boehmLib.}
|
||||
importc: "GC_enable_incremental", boehmGC.}
|
||||
proc boehmGCfullCollect {.importc: "GC_gcollect", boehmGC.}
|
||||
proc boehmAlloc(size: int): pointer {.importc: "GC_malloc", boehmGC.}
|
||||
proc boehmAllocAtomic(size: int): pointer {.
|
||||
importc: "GC_malloc_atomic", dynlib: boehmLib.}
|
||||
importc: "GC_malloc_atomic", boehmGC.}
|
||||
proc boehmRealloc(p: pointer, size: int): pointer {.
|
||||
importc: "GC_realloc", dynlib: boehmLib.}
|
||||
proc boehmDealloc(p: pointer) {.importc: "GC_free", dynlib: boehmLib.}
|
||||
importc: "GC_realloc", boehmGC.}
|
||||
proc boehmDealloc(p: pointer) {.importc: "GC_free", boehmGC.}
|
||||
when hasThreadSupport:
|
||||
proc boehmGC_allow_register_threads {.
|
||||
importc: "GC_allow_register_threads", boehmGC.}
|
||||
|
||||
proc boehmGetHeapSize: int {.importc: "GC_get_heap_size", dynlib: boehmLib.}
|
||||
proc boehmGetHeapSize: int {.importc: "GC_get_heap_size", boehmGC.}
|
||||
## Return the number of bytes in the heap. Excludes collector private
|
||||
## data structures. Includes empty blocks and fragmentation loss.
|
||||
## Includes some pages that were allocated but never written.
|
||||
|
||||
proc boehmGetFreeBytes: int {.importc: "GC_get_free_bytes", dynlib: boehmLib.}
|
||||
proc boehmGetFreeBytes: int {.importc: "GC_get_free_bytes", boehmGC.}
|
||||
## Return a lower bound on the number of free bytes in the heap.
|
||||
|
||||
proc boehmGetBytesSinceGC: int {.importc: "GC_get_bytes_since_gc",
|
||||
dynlib: boehmLib.}
|
||||
proc boehmGetBytesSinceGC: int {.importc: "GC_get_bytes_since_gc", boehmGC.}
|
||||
## Return the number of bytes allocated since the last collection.
|
||||
|
||||
proc boehmGetTotalBytes: int {.importc: "GC_get_total_bytes",
|
||||
dynlib: boehmLib.}
|
||||
proc boehmGetTotalBytes: int {.importc: "GC_get_total_bytes", boehmGC.}
|
||||
## Return the total number of bytes allocated in this process.
|
||||
## Never decreases.
|
||||
|
||||
@@ -157,7 +150,9 @@ when defined(boehmgc):
|
||||
proc setStackBottom(theStackBottom: pointer) = discard
|
||||
|
||||
proc initGC() =
|
||||
when defined(macosx): boehmGCinit()
|
||||
boehmGCinit()
|
||||
when hasThreadSupport:
|
||||
boehmGC_allow_register_threads()
|
||||
|
||||
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
|
||||
if ntfNoRefs in typ.flags: result = allocAtomic(size)
|
||||
@@ -204,9 +199,6 @@ elif defined(gogc):
|
||||
else:
|
||||
const goLib = "libgo.so"
|
||||
|
||||
proc `div`[T: SomeUnsignedInt](x, y: T): T {.magic: "DivU", noSideEffect.}
|
||||
proc `-`[T: SomeUnsignedInt](x, y: T): T {.magic: "SubU", noSideEffect.}
|
||||
|
||||
proc roundup(x, v: int): int {.inline.} =
|
||||
result = (x + (v-1)) and not (v-1)
|
||||
|
||||
|
||||
@@ -304,22 +304,53 @@ type
|
||||
when not defined(boehmgc) and not hasSharedHeap and not defined(gogc):
|
||||
proc deallocOsPages()
|
||||
|
||||
when defined(boehmgc):
|
||||
type GCStackBaseProc = proc(sb: pointer, t: pointer) {.noconv.}
|
||||
proc boehmGC_call_with_stack_base(sbp: GCStackBaseProc, p: pointer)
|
||||
{.importc: "GC_call_with_stack_base", boehmGC.}
|
||||
proc boehmGC_register_my_thread(sb: pointer)
|
||||
{.importc: "GC_register_my_thread", boehmGC.}
|
||||
proc boehmGC_unregister_my_thread()
|
||||
{.importc: "GC_unregister_my_thread", boehmGC.}
|
||||
|
||||
proc threadProcWrapDispatch[TArg](sb: pointer, thrd: pointer) {.noconv.} =
|
||||
boehmGC_register_my_thread(sb)
|
||||
let thrd = cast[ptr Thread[TArg]](thrd)
|
||||
when TArg is void:
|
||||
thrd.dataFn()
|
||||
else:
|
||||
thrd.dataFn(thrd.data)
|
||||
boehmGC_unregister_my_thread()
|
||||
else:
|
||||
proc threadProcWrapDispatch[TArg](thrd: ptr Thread[TArg]) =
|
||||
when TArg is void:
|
||||
thrd.dataFn()
|
||||
else:
|
||||
thrd.dataFn(thrd.data)
|
||||
|
||||
proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) =
|
||||
when defined(boehmgc):
|
||||
boehmGC_call_with_stack_base(threadProcWrapDispatch[TArg], thrd)
|
||||
elif not defined(nogc) and not defined(gogc):
|
||||
var p {.volatile.}: proc(a: ptr Thread[TArg]) {.nimcall.} =
|
||||
threadProcWrapDispatch[TArg]
|
||||
when not hasSharedHeap:
|
||||
# init the GC for refc/markandsweep
|
||||
setStackBottom(addr(p))
|
||||
initGC()
|
||||
when declared(registerThread):
|
||||
thrd.stackBottom = addr(thrd)
|
||||
registerThread(thrd)
|
||||
p(thrd)
|
||||
when declared(registerThread): unregisterThread(thrd)
|
||||
when declared(deallocOsPages): deallocOsPages()
|
||||
else:
|
||||
threadProcWrapDispatch(thrd)
|
||||
|
||||
template threadProcWrapperBody(closure: expr) {.immediate.} =
|
||||
when declared(globalsSlot): threadVarSetValue(globalsSlot, closure)
|
||||
var t = cast[ptr Thread[TArg]](closure)
|
||||
when useStackMaskHack:
|
||||
var tls: ThreadLocalStorage
|
||||
when not defined(boehmgc) and not defined(gogc) and not defined(nogc) and not hasSharedHeap:
|
||||
# init the GC for this thread:
|
||||
setStackBottom(addr(t))
|
||||
initGC()
|
||||
when declared(registerThread):
|
||||
t.stackBottom = addr(t)
|
||||
registerThread(t)
|
||||
when TArg is void: t.dataFn()
|
||||
else: t.dataFn(t.data)
|
||||
when declared(registerThread): unregisterThread(t)
|
||||
when declared(deallocOsPages): deallocOsPages()
|
||||
var thrd = cast[ptr Thread[TArg]](closure)
|
||||
threadProcWrapStackFrame(thrd)
|
||||
# Since an unhandled exception terminates the whole process (!), there is
|
||||
# no need for a ``try finally`` here, nor would it be correct: The current
|
||||
# exception is tried to be re-raised by the code-gen after the ``finally``!
|
||||
@@ -327,7 +358,7 @@ template threadProcWrapperBody(closure: expr) {.immediate.} =
|
||||
# page!
|
||||
|
||||
# mark as not running anymore:
|
||||
t.dataFn = nil
|
||||
thrd.dataFn = nil
|
||||
|
||||
{.push stack_trace:off.}
|
||||
when defined(windows):
|
||||
|
||||
19
readme.md
19
readme.md
@@ -79,22 +79,29 @@ All rights reserved.
|
||||
# Build Status
|
||||
[**Build Waterfall**][waterfall]
|
||||
|
||||
| | Linux | Windows | Mac |
|
||||
| ------ | ----- | ------- | --- |
|
||||
| x86 | ![linux-x86][linux-x86-img] | ![windows-x86][windows-x86-img] | ![mac-x86][mac-x86-img] |
|
||||
| x86_64 | ![linux-x86_64][linux-x86_64-img] | ![windows-x86_64][windows-x86_64-img] | ![mac-x86_64][mac-x86_64-img] |
|
||||
| arm | ![linux-armv5][linux-arm5-img]<br/> ![linux-armv6][linux-arm6-img]<br/> ![linux-armv7][linux-arm7-img] | | |
|
||||
| | Linux | Windows | Mac |
|
||||
| ------ | ----- | ------- | --- |
|
||||
| x86 | [![linux-x86][linux-x86-img]][linux-x86] | [![windows-x86][windows-x86-img]][windows-x86] |
|
||||
| x86_64 | [![linux-x86_64][linux-x86_64-img]][linux-x86_64] | [![windows-x86_64][windows-x86_64-img]][windows-x86_64] | [![mac-x86_64][mac-x86_64-img]][mac-x86_64] |
|
||||
| arm | [![linux-armv5][linux-arm5-img]][linux-arm5]<br/> [![linux-armv6][linux-arm6-img]][linux-arm6]<br/> [![linux-armv7][linux-arm7-img]][linux-arm7]
|
||||
|
||||
[linux-x86]: http://buildbot.nim-lang.org/builders/linux-x32-builder
|
||||
[linux-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x32-builder
|
||||
[linux-x86_64]: http://buildbot.nim-lang.org/builders/linux-x64-builder
|
||||
[linux-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x64-builder
|
||||
[linux-arm5]: http://buildbot.nim-lang.org/builders/linux-arm5-builder
|
||||
[linux-arm5-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm5-builder
|
||||
[linux-arm6]: http://buildbot.nim-lang.org/builders/linux-arm6-builder
|
||||
[linux-arm6-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm6-builder
|
||||
[linux-arm7]: http://buildbot.nim-lang.org/builders/linux-arm7-builder
|
||||
[linux-arm7-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm7-builder
|
||||
|
||||
[windows-x86]: http://buildbot.nim-lang.org/builders/windows-x32-builder
|
||||
[windows-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x32-builder
|
||||
[windows-x86_64]: http://buildbot.nim-lang.org/builders/windows-x64-builder
|
||||
[windows-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x64-builder
|
||||
|
||||
[mac-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x32-builder
|
||||
[mac-x86_64]: http://buildbot.nim-lang.org/builders/mac-x64-builder
|
||||
[mac-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x64-builder
|
||||
|
||||
[waterfall]: http://buildbot.nim-lang.org/waterfall
|
||||
|
||||
@@ -24,4 +24,3 @@ var
|
||||
"D": action4}.toTable
|
||||
|
||||
actionTable["C"]("arg")
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
import json, tables
|
||||
import json, tables, sequtils
|
||||
|
||||
proc run(json_params: TTable) =
|
||||
let json_elems = json_params["files"].elems
|
||||
|
||||
11
tests/collections/tapply.nim
Normal file
11
tests/collections/tapply.nim
Normal file
@@ -0,0 +1,11 @@
|
||||
discard """
|
||||
output: '''true'''
|
||||
"""
|
||||
|
||||
import sequtils
|
||||
|
||||
var x = @[1, 2, 3]
|
||||
x.apply(proc(x: var int) = x = x+10)
|
||||
x.apply(proc(x: int): int = x+100)
|
||||
x.applyIt(it+5000)
|
||||
echo x == @[5111, 5112, 5113]
|
||||
33
tests/collections/tmapit.nim
Normal file
33
tests/collections/tmapit.nim
Normal file
@@ -0,0 +1,33 @@
|
||||
discard """
|
||||
output: '''true
|
||||
true'''
|
||||
"""
|
||||
|
||||
import sequtils
|
||||
|
||||
var x = @[1, 2, 3]
|
||||
# This mapIt call will run with preallocation because ``len`` is available.
|
||||
var y = x.mapIt($(it+10))
|
||||
echo y == @["11", "12", "13"]
|
||||
|
||||
type structureWithoutLen = object
|
||||
a: array[5, int]
|
||||
|
||||
iterator items(s: structureWithoutLen): int {.inline.} =
|
||||
yield s.a[0]
|
||||
yield s.a[1]
|
||||
yield s.a[2]
|
||||
yield s.a[3]
|
||||
yield s.a[4]
|
||||
|
||||
var st: structureWithoutLen
|
||||
st.a[0] = 0
|
||||
st.a[1] = 1
|
||||
st.a[2] = 2
|
||||
st.a[3] = 3
|
||||
st.a[4] = 4
|
||||
|
||||
# this will run without preallocating the result
|
||||
# since ``len`` is not available
|
||||
var r = st.mapIt($(it+10))
|
||||
echo r == @["10", "11", "12", "13", "14"]
|
||||
@@ -60,8 +60,12 @@ block tableTest2:
|
||||
t["123"] = 1.5 # test overwriting
|
||||
|
||||
assert t["123"] == 1.5
|
||||
assert t["111"] == 0.0 # deleted
|
||||
try:
|
||||
echo t["111"] # deleted
|
||||
except KeyError:
|
||||
discard
|
||||
assert(not hasKey(t, "111"))
|
||||
|
||||
assert "123" in t
|
||||
assert("111" notin t)
|
||||
|
||||
|
||||
@@ -60,8 +60,10 @@ block tableTest2:
|
||||
t["123"] = 1.5 # test overwriting
|
||||
|
||||
assert t["123"] == 1.5
|
||||
assert t["111"] == 0.0 # deleted
|
||||
assert "123" in t
|
||||
try:
|
||||
echo t["111"] # deleted
|
||||
except KeyError:
|
||||
discard
|
||||
assert(not hasKey(t, "111"))
|
||||
assert "111" notin t
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ discard """
|
||||
3'''
|
||||
"""
|
||||
|
||||
import sequtils
|
||||
# https://github.com/Araq/Nim/issues/797
|
||||
proc foo[T](s:T):string = $s
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import future
|
||||
import future, sequtils
|
||||
|
||||
let x = map(@[1, 2, 3], x => x+10)
|
||||
assert x == @[11, 12, 13]
|
||||
|
||||
@@ -18,7 +18,7 @@ proc on*(emitter: var EventEmitter, event: string,
|
||||
if not hasKey(emitter.events, event):
|
||||
var list: DoublyLinkedList[proc(e: EventArgs) {.nimcall.}]
|
||||
add(emitter.events, event, list) #if not, add it.
|
||||
append(emitter.events.mget(event), fn)
|
||||
append(emitter.events[event], fn)
|
||||
|
||||
proc initEmitter(emitter: var EventEmitter) =
|
||||
emitter.events = initTable[string,
|
||||
@@ -30,4 +30,3 @@ var
|
||||
initEmitter(ee)
|
||||
ee.on("print", proc(e: EventArgs) = echo("pie"))
|
||||
ee.emit("print", args)
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@ mode = ScriptMode.Whatif
|
||||
|
||||
exec "gcc -v"
|
||||
|
||||
# test that ospaths actually compiles:
|
||||
import ospaths
|
||||
|
||||
--forceBuild
|
||||
|
||||
task listDirs, "lists every subdirectory":
|
||||
|
||||
@@ -5,7 +5,7 @@ yay'''
|
||||
|
||||
# Test overloading of procs when used as function pointers
|
||||
|
||||
import strutils
|
||||
import strutils, sequtils
|
||||
|
||||
proc parseInt(x: float): int {.noSideEffect.} = discard
|
||||
proc parseInt(x: bool): int {.noSideEffect.} = discard
|
||||
|
||||
@@ -5,6 +5,7 @@ discard """
|
||||
77'''
|
||||
"""
|
||||
#import math
|
||||
import sequtils
|
||||
|
||||
proc optarg(x:int, y:int = 0):int = x + 3 * y
|
||||
proc singlearg(x:int):int = 20*x
|
||||
|
||||
141
tests/stdlib/tmget.nim
Normal file
141
tests/stdlib/tmget.nim
Normal file
@@ -0,0 +1,141 @@
|
||||
discard """
|
||||
output: '''Can't access 6
|
||||
10
|
||||
11
|
||||
Can't access 6
|
||||
10
|
||||
11
|
||||
Can't access 6
|
||||
10
|
||||
11
|
||||
Can't access 6
|
||||
10
|
||||
11
|
||||
Can't access 6
|
||||
10
|
||||
11
|
||||
Can't access 6
|
||||
10
|
||||
11
|
||||
Can't access 6
|
||||
5
|
||||
Can't access 6
|
||||
10
|
||||
11
|
||||
Can't access 6
|
||||
10
|
||||
11'''
|
||||
"""
|
||||
|
||||
import tables
|
||||
|
||||
block:
|
||||
var x = initTable[int, int]()
|
||||
x[5] = 10
|
||||
try:
|
||||
echo x[6]
|
||||
except KeyError:
|
||||
echo "Can't access 6"
|
||||
echo x[5]
|
||||
x[5] += 1
|
||||
var c = x[5]
|
||||
echo c
|
||||
|
||||
block:
|
||||
var x = newTable[int, int]()
|
||||
x[5] = 10
|
||||
try:
|
||||
echo x[6]
|
||||
except KeyError:
|
||||
echo "Can't access 6"
|
||||
echo x[5]
|
||||
x[5] += 1
|
||||
var c = x[5]
|
||||
echo c
|
||||
|
||||
block:
|
||||
var x = initOrderedTable[int, int]()
|
||||
x[5] = 10
|
||||
try:
|
||||
echo x[6]
|
||||
except KeyError:
|
||||
echo "Can't access 6"
|
||||
echo x[5]
|
||||
x[5] += 1
|
||||
var c = x[5]
|
||||
echo c
|
||||
|
||||
block:
|
||||
var x = newOrderedTable[int, int]()
|
||||
x[5] = 10
|
||||
try:
|
||||
echo x[6]
|
||||
except KeyError:
|
||||
echo "Can't access 6"
|
||||
echo x[5]
|
||||
x[5] += 1
|
||||
var c = x[5]
|
||||
echo c
|
||||
|
||||
block:
|
||||
var x = initCountTable[int]()
|
||||
x[5] = 10
|
||||
try:
|
||||
echo x[6]
|
||||
except KeyError:
|
||||
echo "Can't access 6"
|
||||
echo x[5]
|
||||
x[5] += 1
|
||||
var c = x[5]
|
||||
echo c
|
||||
|
||||
block:
|
||||
var x = newCountTable[int]()
|
||||
x[5] = 10
|
||||
try:
|
||||
echo x[6]
|
||||
except KeyError:
|
||||
echo "Can't access 6"
|
||||
echo x[5]
|
||||
x[5] += 1
|
||||
var c = x[5]
|
||||
echo c
|
||||
|
||||
import sets
|
||||
|
||||
block:
|
||||
var x = initSet[int]()
|
||||
x.incl 5
|
||||
try:
|
||||
echo x[6]
|
||||
except KeyError:
|
||||
echo "Can't access 6"
|
||||
echo x[5]
|
||||
|
||||
import critbits
|
||||
|
||||
block:
|
||||
var x: CritBitTree[int]
|
||||
x["5"] = 10
|
||||
try:
|
||||
echo x["6"]
|
||||
except KeyError:
|
||||
echo "Can't access 6"
|
||||
echo x["5"]
|
||||
x["5"] += 1
|
||||
var c = x["5"]
|
||||
echo c
|
||||
|
||||
import strtabs
|
||||
|
||||
block:
|
||||
var x = newStringTable()
|
||||
x["5"] = "10"
|
||||
try:
|
||||
echo x["6"]
|
||||
except KeyError:
|
||||
echo "Can't access 6"
|
||||
echo x["5"]
|
||||
x["5"][1] = '1'
|
||||
var c = x["5"]
|
||||
echo c
|
||||
@@ -132,5 +132,5 @@ block:
|
||||
</Students>""")
|
||||
for x in d.mitems:
|
||||
x = <>Student(Name=x.attrs["Name"] & "foo")
|
||||
d.mget(1).attrs["Name"] = "bar"
|
||||
d[1].attrs["Name"] = "bar"
|
||||
echo d
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import unittest
|
||||
import unittest, sequtils
|
||||
|
||||
|
||||
proc doThings(spuds: var int): int =
|
||||
|
||||
@@ -27,6 +27,6 @@ when ATTEMPT == 0:
|
||||
# bug #1543
|
||||
import sequtils
|
||||
|
||||
(var i = @[""];i).mapIt(it)
|
||||
(var i = @[""];i).applyIt(it)
|
||||
# now works:
|
||||
echo "##", i[0], "##"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import strutils, db_sqlite, os, osproc
|
||||
|
||||
var db: TDbConn
|
||||
var db: DbConn
|
||||
|
||||
proc createDb() =
|
||||
db.exec(sql"""
|
||||
@@ -61,7 +61,7 @@ var
|
||||
|
||||
proc `()`(cmd: string{lit}): string = cmd.execProcess.string.strip
|
||||
|
||||
proc getMachine*(db: TDbConn): MachineId =
|
||||
proc getMachine*(db: DbConn): MachineId =
|
||||
var name = "hostname"()
|
||||
if name.len == 0:
|
||||
name = when defined(posix): getenv"HOSTNAME".string
|
||||
@@ -76,7 +76,7 @@ proc getMachine*(db: TDbConn): MachineId =
|
||||
result = db.insertId(sql"insert into Machine(name, os, cpu) values (?,?,?)",
|
||||
name, system.hostOS, system.hostCPU).MachineId
|
||||
|
||||
proc getCommit(db: TDbConn): CommitId =
|
||||
proc getCommit(db: DbConn): CommitId =
|
||||
const commLen = "commit ".len
|
||||
let hash = "git log -n 1"()[commLen..commLen+10]
|
||||
let branch = "git symbolic-ref --short HEAD"()
|
||||
|
||||
@@ -119,12 +119,21 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
|
||||
testSpec r, makeTest("tests/gc" / filename, options &
|
||||
" -d:release -d:useRealtimeGC", cat, actionRun)
|
||||
|
||||
template test(filename: expr): stmt =
|
||||
template testWithoutBoehm(filename: expr): stmt =
|
||||
testWithoutMs filename
|
||||
testSpec r, makeTest("tests/gc" / filename, options &
|
||||
" --gc:markAndSweep", cat, actionRun)
|
||||
testSpec r, makeTest("tests/gc" / filename, options &
|
||||
" -d:release --gc:markAndSweep", cat, actionRun)
|
||||
template test(filename: expr): stmt =
|
||||
testWithoutBoehm filename
|
||||
when not defined(windows):
|
||||
# AR: cannot find any boehm.dll on the net, right now, so disabled
|
||||
# for windows:
|
||||
testSpec r, makeTest("tests/gc" / filename, options &
|
||||
" --gc:boehm", cat, actionRun)
|
||||
testSpec r, makeTest("tests/gc" / filename, options &
|
||||
" -d:release --gc:boehm", cat, actionRun)
|
||||
|
||||
test "gcemscripten"
|
||||
test "growobjcrash"
|
||||
@@ -136,9 +145,9 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
|
||||
test "gcleak4"
|
||||
# Disabled because it works and takes too long to run:
|
||||
#test "gcleak5"
|
||||
test "weakrefs"
|
||||
testWithoutBoehm "weakrefs"
|
||||
test "cycleleak"
|
||||
test "closureleak"
|
||||
testWithoutBoehm "closureleak"
|
||||
testWithoutMs "refarrayleak"
|
||||
|
||||
test "stackrefleak"
|
||||
|
||||
@@ -109,7 +109,7 @@ div.tabContent.hide { display: none; }
|
||||
proc td(s: string): string =
|
||||
result = "<td>" & s.substr(0, 200).xmlEncode & "</td>"
|
||||
|
||||
proc getCommit(db: TDbConn, c: int): string =
|
||||
proc getCommit(db: DbConn, c: int): string =
|
||||
var commit = c
|
||||
for thisCommit in db.rows(sql"select id from [Commit] order by id desc"):
|
||||
if commit == 0: result = thisCommit[0]
|
||||
|
||||
@@ -65,7 +65,7 @@ proc callCompiler(cmdTemplate, filename, options: string,
|
||||
let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target],
|
||||
"options", options, "file", filename.quoteShell])
|
||||
var p = startProcess(command=c[0], args=c[1.. ^1],
|
||||
options={poStdErrToStdOut, poUseShell})
|
||||
options={poStdErrToStdOut, poUsePath})
|
||||
let outp = p.outputStream
|
||||
var suc = ""
|
||||
var err = ""
|
||||
@@ -215,7 +215,7 @@ proc generatedFile(path, name: string, target: TTarget): string =
|
||||
|
||||
proc codegenCheck(test: TTest, check: string, given: var TSpec) =
|
||||
try:
|
||||
let (path, name, ext2) = test.name.splitFile
|
||||
let (path, name, _) = test.name.splitFile
|
||||
let genFile = generatedFile(path, name, test.target)
|
||||
let contents = readFile(genFile).string
|
||||
if check[0] == '\\':
|
||||
@@ -307,7 +307,7 @@ proc testSpec(r: var TResults, test: TTest) =
|
||||
let isJsTarget = test.target == targetJS
|
||||
var exeFile: string
|
||||
if isJsTarget:
|
||||
let (dir, file, ext) = splitFile(tname)
|
||||
let (dir, file, _) = splitFile(tname)
|
||||
exeFile = dir / "nimcache" / file & ".js" # *TODO* hardcoded "nimcache"
|
||||
else:
|
||||
exeFile = changeFileExt(tname, ExeExt)
|
||||
@@ -352,7 +352,7 @@ proc testSpec(r: var TResults, test: TTest) =
|
||||
|
||||
proc testNoSpec(r: var TResults, test: TTest) =
|
||||
# does not extract the spec because the file is not supposed to have any
|
||||
let tname = test.name.addFileExt(".nim")
|
||||
#let tname = test.name.addFileExt(".nim")
|
||||
inc(r.total)
|
||||
let given = callCompiler(cmdTemplate, test.name, test.options, test.target)
|
||||
r.addResult(test, "", given.msg, given.err)
|
||||
@@ -368,7 +368,7 @@ proc testC(r: var TResults, test: TTest) =
|
||||
r.addResult(test, "", given.msg, given.err)
|
||||
elif test.action == actionRun:
|
||||
let exeFile = changeFileExt(test.name, ExeExt)
|
||||
var (buf, exitCode) = execCmdEx(exeFile, options = {poStdErrToStdOut, poUseShell})
|
||||
var (_, exitCode) = execCmdEx(exeFile, options = {poStdErrToStdOut, poUsePath})
|
||||
if exitCode != 0: given.err = reExitCodesDiffer
|
||||
if given.err == reSuccess: inc(r.passed)
|
||||
|
||||
|
||||
24
web/news.txt
24
web/news.txt
@@ -8,7 +8,11 @@ News
|
||||
|
||||
Changes affecting backwards compatibility
|
||||
-----------------------------------------
|
||||
|
||||
- ``tables.[]``, ``strtabs.[]``, ``critbits.[]`` **now raise**
|
||||
the ``KeyError`` **exception when the key does not exist**! Use the
|
||||
new ``getOrDefault`` instead to get the old behaviour. Compile all your
|
||||
code with ``-d:nimTableGet`` to get a listing of where your code
|
||||
uses ``[]``!
|
||||
- The ``rawsockets`` module has been renamed to ``nativesockets`` to avoid
|
||||
confusion with TCP/IP raw sockets, so ``newNativeSocket`` should be used
|
||||
instead of ``newRawSocket``.
|
||||
@@ -68,10 +72,10 @@ News
|
||||
* ``libeay32.dll``: Split into ``libeay32.dll`` and ``libeay64.dll``.
|
||||
|
||||
Compile with ``-d:nimOldDLLs`` to make the stdlib use the old DLL names.
|
||||
- Nim VM now treats objects as nkObjConstr nodes, and not nkPar nodes as it
|
||||
was previously. Macros that generate nkPar nodes when object is expected are
|
||||
likely to break. Macros that expect nkPar nodes to which objects are passed
|
||||
are likely to break as well.
|
||||
- Nim VM now treats objects as ``nkObjConstr`` nodes, and not ``nkPar`` nodes
|
||||
as it was previously. Macros that generate ``nkPar`` nodes when object is
|
||||
expected are likely to break. Macros that expect ``nkPar`` nodes to which
|
||||
objects are passed are likely to break as well.
|
||||
- Base methods now need to be annotated with the ``base`` pragma. This makes
|
||||
multi methods less error-prone to use with the effect system.
|
||||
- Nim's parser directive ``#!`` is now ``#?`` in order to produce no conflicts
|
||||
@@ -86,8 +90,14 @@ News
|
||||
|
||||
echo f(0, "abc")
|
||||
- The ``ftpclient`` module is now deprecated in favour of the
|
||||
``asyncdispatch`` module.
|
||||
|
||||
``asyncftpclient`` module.
|
||||
- In sequtils.nim renamed ``repeat`` function to ``cycle`` (concatenating
|
||||
a sequence by itself the given times), and also introduced ``repeat``,
|
||||
which repeats an element the given times.
|
||||
- The function ``map`` is moved to sequtils.nim. The inplace ``map`` version
|
||||
is renamed to ``apply``.
|
||||
- The template ``mapIt`` now doesn't require the result's type parameter.
|
||||
Also the inplace ``mapIt`` is renamed to ``apply``.
|
||||
|
||||
Library Additions
|
||||
-----------------
|
||||
|
||||
@@ -34,8 +34,8 @@ doc: "tools;niminst;nimgrep;gc;estp;idetools;docgen;koch;backends.txt"
|
||||
doc: "nimfix.txt;nimsuggest.txt;nep1.txt;nims.txt"
|
||||
pdf: "manual.txt;lib;tut1;tut2;nimc;niminst;gc"
|
||||
srcdoc2: "system.nim;system/nimscript;pure/ospaths"
|
||||
srcdoc2: "core/macros;pure/marshal;core/typeinfo;core/unsigned"
|
||||
srcdoc2: "impure/re;pure/sockets;pure/typetraits"
|
||||
srcdoc2: "core/macros;pure/marshal;core/typeinfo"
|
||||
srcdoc2: "impure/re;pure/typetraits"
|
||||
srcdoc2: "pure/concurrency/threadpool.nim;pure/concurrency/cpuinfo.nim"
|
||||
srcdoc: "system/threads.nim;system/channels.nim;js/dom"
|
||||
srcdoc2: "pure/os;pure/strutils;pure/math;pure/matchers;pure/algorithm"
|
||||
@@ -52,12 +52,13 @@ srcdoc2: "pure/json;pure/base64;pure/scgi"
|
||||
srcdoc2: "pure/collections/tables;pure/collections/sets;pure/collections/lists"
|
||||
srcdoc2: "pure/collections/intsets;pure/collections/queues;pure/encodings"
|
||||
srcdoc2: "pure/events;pure/collections/sequtils;pure/cookies"
|
||||
srcdoc2: "pure/ftpclient;pure/memfiles;pure/subexes;pure/collections/critbits"
|
||||
srcdoc2: "pure/asyncio;pure/actors;core/locks;pure/oids;pure/endians;pure/uri"
|
||||
srcdoc2: "pure/memfiles;pure/subexes;pure/collections/critbits"
|
||||
srcdoc2: "deprecated/pure/asyncio;deprecated/pure/actors;core/locks;pure/oids;pure/endians;pure/uri"
|
||||
srcdoc2: "pure/nimprof;pure/unittest;packages/docutils/highlite"
|
||||
srcdoc2: "packages/docutils/rst;packages/docutils/rstast"
|
||||
srcdoc2: "packages/docutils/rstgen;pure/logging;pure/asyncdispatch;pure/asyncnet"
|
||||
srcdoc2: "pure/rawsockets;pure/asynchttpserver;pure/net;pure/selectors;pure/future"
|
||||
srcdoc2: "deprecated/pure/rawsockets;pure/asynchttpserver;pure/net;pure/selectors;pure/future"
|
||||
srcdoc2: "deprecated/pure/ftpclient"
|
||||
srcdoc2: "pure/asyncfile"
|
||||
srcdoc2: "pure/md5;pure/rationals"
|
||||
srcdoc2: "posix/posix"
|
||||
|
||||
Reference in New Issue
Block a user