Merge branch 'devel' into araq

This commit is contained in:
Andreas Rumpf 2017-11-02 10:46:30 +01:00
commit 1eaeccc15d
616 changed files with 73547 additions and 36764 deletions

View file

@ -129,13 +129,6 @@ const
nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
nnkCallStrLit}
proc `[]`*(n: NimNode, i: int): NimNode {.magic: "NChild", noSideEffect.}
## get `n`'s `i`'th child.
proc `[]=`*(n: NimNode, i: int, child: NimNode) {.magic: "NSetChild",
noSideEffect.}
## set `n`'s `i`'th child to `child`.
proc `!`*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect.}
## constructs an identifier from the string `s`
@ -162,6 +155,20 @@ proc sameType*(a, b: NimNode): bool {.magic: "SameNodeType", noSideEffect.} =
proc len*(n: NimNode): int {.magic: "NLen", noSideEffect.}
## returns the number of children of `n`.
proc `[]`*(n: NimNode, i: int): NimNode {.magic: "NChild", noSideEffect.}
## get `n`'s `i`'th child.
proc `[]`*(n: NimNode, i: BackwardsIndex): NimNode = n[n.len - i.int]
## get `n`'s `i`'th child.
proc `[]=`*(n: NimNode, i: int, child: NimNode) {.magic: "NSetChild",
noSideEffect.}
## set `n`'s `i`'th child to `child`.
proc `[]=`*(n: NimNode, i: BackwardsIndex, child: NimNode) =
## set `n`'s `i`'th child to `child`.
n[n.len - i.int] = child
proc add*(father, child: NimNode): NimNode {.magic: "NAdd", discardable,
noSideEffect, locks: 0.}
## Adds the `child` to the `father` node. Returns the
@ -839,7 +846,7 @@ proc newNilLit*(): NimNode {.compileTime.} =
## New nil literal shortcut
result = newNimNode(nnkNilLit)
proc last*(node: NimNode): NimNode {.compileTime.} = node[<node.len]
proc last*(node: NimNode): NimNode {.compileTime.} = node[node.len-1]
## Return the last item in nodes children. Same as `node[^1]`
@ -887,7 +894,7 @@ proc newIfStmt*(branches: varargs[tuple[cond, body: NimNode]]):
proc copyChildrenTo*(src, dest: NimNode) {.compileTime.}=
## Copy all children from `src` to `dest`
for i in 0 .. < src.len:
for i in 0 ..< src.len:
dest.add src[i].copyNimTree
template expectRoutine(node: NimNode) =
@ -986,6 +993,11 @@ iterator items*(n: NimNode): NimNode {.inline.} =
for i in 0 ..< n.len:
yield n[i]
iterator pairs*(n: NimNode): (int, NimNode) {.inline.} =
## Iterates over the children of the NimNode ``n`` and its indices.
for i in 0 ..< n.len:
yield (i, n[i])
iterator children*(n: NimNode): NimNode {.inline.} =
## Iterates over the children of the NimNode ``n``.
for i in 0 ..< n.len:
@ -1099,10 +1111,10 @@ proc eqIdent*(node: NimNode; s: string): bool {.compileTime.} =
else:
result = false
proc hasArgOfName* (params: NimNode; name: string): bool {.compiletime.}=
proc hasArgOfName*(params: NimNode; name: string): bool {.compiletime.}=
## Search nnkFormalParams for an argument.
assert params.kind == nnkFormalParams
for i in 1 .. <params.len:
for i in 1 ..< params.len:
template node: untyped = params[i]
if name.eqIdent( $ node[0]):
return true

View file

@ -18,7 +18,7 @@
## var
## a: ActorPool[int, void]
## createActorPool(a)
## for i in 0 .. < 300:
## for i in 0 ..< 300:
## a.spawn(i, proc (x: int) {.thread.} = echo x)
## a.join()
##
@ -133,7 +133,7 @@ proc createActorPool*[In, Out](a: var ActorPool[In, Out], poolSize = 4) =
newSeq(a.actors, poolSize)
when Out isnot void:
open(a.outputs)
for i in 0 .. < a.actors.len:
for i in 0 ..< a.actors.len:
a.actors[i] = spawn(poolWorker[In, Out])
proc sync*[In, Out](a: var ActorPool[In, Out], polling=50) =
@ -164,8 +164,8 @@ proc terminate*[In, Out](a: var ActorPool[In, Out]) =
## resources attached to `a`.
var t: Task[In, Out]
t.shutdown = true
for i in 0.. <a.actors.len: send(a.actors[i].i, t)
for i in 0.. <a.actors.len: join(a.actors[i])
for i in 0..<a.actors.len: send(a.actors[i].i, t)
for i in 0..<a.actors.len: join(a.actors[i])
when Out isnot void:
close(a.outputs)
a.actors = nil
@ -227,7 +227,7 @@ when not defined(testing) and isMainModule:
var
a: ActorPool[int, void]
createActorPool(a)
for i in 0 .. < 300:
for i in 0 ..< 300:
a.spawn(i, proc (x: int) {.thread.} = echo x)
when false:

View file

@ -98,15 +98,18 @@ proc dbFormat(formatstr: SqlQuery, args: varargs[string]): string =
var a = 0
if args.len > 0 and not string(formatstr).contains("?"):
dbError("""parameter substitution expects "?" """)
for c in items(string(formatstr)):
if c == '?':
if args[a] == nil:
add(result, "NULL")
if args.len == 0:
return string(formatstr)
else:
for c in items(string(formatstr)):
if c == '?':
if args[a] == nil:
add(result, "NULL")
else:
add(result, dbQuote(args[a]))
inc(a)
else:
add(result, dbQuote(args[a]))
inc(a)
else:
add(result, c)
add(result, c)
proc tryExec*(db: DbConn, query: SqlQuery,
args: varargs[string, `$`]): bool {.tags: [ReadDbEffect, WriteDbEffect].} =

View file

@ -155,7 +155,7 @@ type
## - ``"abc".match(re"(?<letter>\w)").captures["letter"] == "a"``
## - ``"abc".match(re"(\w)\w").captures[-1] == "ab"``
##
## ``captureBounds[]: Option[Slice[int]]``
## ``captureBounds[]: Option[HSlice[int, int]]``
## gets the bounds of the given capture according to the same rules as
## the above. If the capture is not filled, then ``None`` is returned.
## The bounds are both inclusive.
@ -167,7 +167,7 @@ type
## ``match: string``
## the full text of the match.
##
## ``matchBounds: Slice[int]``
## ``matchBounds: HSlice[int, int]``
## the bounds of the match, as in ``captureBounds[]``
##
## ``(captureBounds|captures).toTable``
@ -182,9 +182,9 @@ type
## Not nil.
str*: string ## The string that was matched against.
## Not nil.
pcreMatchBounds: seq[Slice[cint]] ## First item is the bounds of the match
## Other items are the captures
## `a` is inclusive start, `b` is exclusive end
pcreMatchBounds: seq[HSlice[cint, cint]] ## First item is the bounds of the match
## Other items are the captures
## `a` is inclusive start, `b` is exclusive end
Captures* = distinct RegexMatch
CaptureBounds* = distinct RegexMatch
@ -251,13 +251,13 @@ proc captureBounds*(pattern: RegexMatch): CaptureBounds = return CaptureBounds(p
proc captures*(pattern: RegexMatch): Captures = return Captures(pattern)
proc `[]`*(pattern: CaptureBounds, i: int): Option[Slice[int]] =
proc `[]`*(pattern: CaptureBounds, i: int): Option[HSlice[int, int]] =
let pattern = RegexMatch(pattern)
if pattern.pcreMatchBounds[i + 1].a != -1:
let bounds = pattern.pcreMatchBounds[i + 1]
return some(int(bounds.a) .. int(bounds.b-1))
else:
return none(Slice[int])
return none(HSlice[int, int])
proc `[]`*(pattern: Captures, i: int): string =
let pattern = RegexMatch(pattern)
@ -272,10 +272,10 @@ proc `[]`*(pattern: Captures, i: int): string =
proc match*(pattern: RegexMatch): string =
return pattern.captures[-1]
proc matchBounds*(pattern: RegexMatch): Slice[int] =
proc matchBounds*(pattern: RegexMatch): HSlice[int, int] =
return pattern.captureBounds[-1].get
proc `[]`*(pattern: CaptureBounds, name: string): Option[Slice[int]] =
proc `[]`*(pattern: CaptureBounds, name: string): Option[HSlice[int, int]] =
let pattern = RegexMatch(pattern)
return pattern.captureBounds[pattern.pattern.captureNameToId.fget(name)]
@ -295,13 +295,13 @@ proc toTable*(pattern: Captures, default: string = nil): Table[string, string] =
result = initTable[string, string]()
toTableImpl(nextVal == nil)
proc toTable*(pattern: CaptureBounds, default = none(Slice[int])):
Table[string, Option[Slice[int]]] =
result = initTable[string, Option[Slice[int]]]()
proc toTable*(pattern: CaptureBounds, default = none(HSlice[int, int])):
Table[string, Option[HSlice[int, int]]] =
result = initTable[string, Option[HSlice[int, int]]]()
toTableImpl(nextVal.isNone)
template itemsImpl(cond: untyped) {.dirty.} =
for i in 0 .. <RegexMatch(pattern).pattern.captureCount:
for i in 0 ..< RegexMatch(pattern).pattern.captureCount:
let nextVal = pattern[i]
# done in this roundabout way to avoid multiple yields (potential code
# bloat)
@ -309,13 +309,13 @@ template itemsImpl(cond: untyped) {.dirty.} =
yield nextYieldVal
iterator items*(pattern: CaptureBounds, default = none(Slice[int])): Option[Slice[int]] =
iterator items*(pattern: CaptureBounds, default = none(HSlice[int, int])): Option[HSlice[int, int]] =
itemsImpl(nextVal.isNone)
iterator items*(pattern: Captures, default: string = nil): string =
itemsImpl(nextVal == nil)
proc toSeq*(pattern: CaptureBounds, default = none(Slice[int])): seq[Option[Slice[int]]] =
proc toSeq*(pattern: CaptureBounds, default = none(HSlice[int, int])): seq[Option[HSlice[int, int]]] =
accumulateResult(pattern.items(default))
proc toSeq*(pattern: Captures, default: string = nil): seq[string] =
@ -396,8 +396,6 @@ proc extractOptions(pattern: string): tuple[pattern: string, flags: int, study:
# }}}
type UncheckedArray {.unchecked.}[T] = array[0 .. 0, T]
proc destroyRegex(pattern: Regex) =
pcre.free_substring(cast[cstring](pattern.pcreObj))
pattern.pcreObj = nil
@ -412,7 +410,7 @@ proc getNameToNumberTable(pattern: Regex): Table[string, int] =
result = initTable[string, int]()
for i in 0 .. <entryCount:
for i in 0 ..< entryCount:
let pos = i * entrySize
let num = (int(table[pos]) shl 8) or int(table[pos + 1]) - 1
var name = ""
@ -464,7 +462,7 @@ proc matchImpl(str: string, pattern: Regex, start, endpos: int, flags: int): Opt
# 1x capture count as slack space for PCRE
let vecsize = (pattern.captureCount() + 1) * 3
# div 2 because each element is 2 cints long
myResult.pcreMatchBounds = newSeq[Slice[cint]](ceil(vecsize / 2).int)
myResult.pcreMatchBounds = newSeq[HSlice[cint, cint]](ceil(vecsize / 2).int)
myResult.pcreMatchBounds.setLen(vecsize div 3)
let strlen = if endpos == int.high: str.len else: endpos+1

View file

@ -13,10 +13,6 @@
## We had to de-deprecate this module since too much code relies on it
## and many people prefer its API over ``nre``'s.
##
## **Note:** The 're' proc defaults to the **extended regular expression
## syntax** which lets you use whitespace freely to make your regexes readable.
## However, this means matching whitespace requires ``\s`` or something similar.
##
## This module is implemented by providing a wrapper around the
## `PRCE (Perl-Compatible Regular Expressions) <http://www.pcre.org>`_
## C library. This means that your application will depend on the PRCE
@ -78,7 +74,7 @@ proc finalizeRegEx(x: Regex) =
if not isNil(x.e):
pcre.free_substring(cast[cstring](x.e))
proc re*(s: string, flags = {reExtended, reStudy}): Regex =
proc re*(s: string, flags = {reStudy}): Regex =
## Constructor of regular expressions.
##
## Note that Nim's
@ -96,6 +92,13 @@ proc re*(s: string, flags = {reExtended, reStudy}): Regex =
result.e = pcre.study(result.h, options, addr msg)
if not isNil(msg): raiseInvalidRegex($msg)
proc rex*(s: string, flags = {reStudy, reExtended}): Regex =
## Constructor for extended regular expressions.
##
## The extended means that comments starting with `#` and
## whitespace are ignored.
result = re(s, flags)
proc bufSubstr(b: cstring, sPos, ePos: int): string {.inline.} =
## Return a Nim string built from a slice of a cstring buffer.
## Don't assume cstring is '\0' terminated

View file

@ -63,16 +63,16 @@ proc recvLine*(sock: SecureSocket, line: var TaintedString): bool =
setLen(line.string, 0)
while true:
var c: array[0..0, char]
var n = BIO_read(sock.bio, c, c.len.cint)
var n = BIO_read(sock.bio, addr c, c.len.cint)
if n <= 0: return false
if c[0] == '\r':
n = BIO_read(sock.bio, c, c.len.cint)
n = BIO_read(sock.bio, addr c, c.len.cint)
if n > 0 and c[0] == '\L':
return true
elif n <= 0:
return false
elif c[0] == '\L': return true
add(line.string, c)
add(line.string, c[0])
proc send*(sock: SecureSocket, data: string) =

View file

@ -396,15 +396,13 @@ typedef struct TStringDesc* string;
#define GenericSeqSize sizeof(TGenericSeq)
#define paramCount() cmdCount
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__i386__)
# ifndef NAN
static unsigned long nimNaN[2]={0xffffffff, 0x7fffffff};
# define NAN (*(double*) nimNaN)
# endif
#endif
// NAN definition copied from math.h included in the Windows SDK version 10.0.14393.0
#ifndef NAN
# define NAN (0.0 / 0.0)
#ifndef _HUGE_ENUF
#define _HUGE_ENUF 1e+300 // _HUGE_ENUF*_HUGE_ENUF must overflow
#endif
#define NAN_INFINITY ((float)(_HUGE_ENUF * _HUGE_ENUF))
#define NAN ((float)(NAN_INFINITY * 0.0F))
#endif
#ifndef INF

View file

@ -26,3 +26,5 @@ const
proc clone*(fn: pointer; child_stack: pointer; flags: cint;
arg: pointer; ptid: ptr Pid; tls: pointer;
ctid: ptr Pid): cint {.importc, header: "<sched.h>".}
proc pipe2*(a: array[0..1, cint], flags: cint): cint {.importc, header: "<unistd.h>".}

View file

@ -146,7 +146,7 @@ type
Mode* {.importc: "mode_t", header: "<sys/types.h>".} = cint
Nlink* {.importc: "nlink_t", header: "<sys/types.h>".} = int
Off* {.importc: "off_t", header: "<sys/types.h>".} = int64
Pid* {.importc: "pid_t", header: "<sys/types.h>".} = int
Pid* {.importc: "pid_t", header: "<sys/types.h>".} = int32
Pthread_attr* {.importc: "pthread_attr_t", header: "<sys/types.h>".} = int
Pthread_barrier* {.importc: "pthread_barrier_t",
header: "<sys/types.h>".} = int

View file

@ -371,3 +371,126 @@ when isMainModule:
for i in 0 .. high(arr1):
assert arr1.reversed(0, i) == arr1.reversed()[high(arr1) - i .. high(arr1)]
assert arr1.reversed(i, high(arr1)) == arr1.reversed()[0 .. high(arr1) - i]
proc rotateInternal[T](arg: var openarray[T]; first, middle, last: int): int =
## A port of std::rotate from c++. Ported from `this reference <http://www.cplusplus.com/reference/algorithm/rotate/>`_.
result = first + last - middle
if first == middle or middle == last:
return
assert first < middle
assert middle < last
# m prefix for mutable
var
mFirst = first
mMiddle = middle
next = middle
swap(arg[mFirst], arg[next])
mFirst += 1
next += 1
if mFirst == mMiddle:
mMiddle = next
while next != last:
swap(arg[mFirst], arg[next])
mFirst += 1
next += 1
if mFirst == mMiddle:
mMiddle = next
next = mMiddle
while next != last:
swap(arg[mFirst], arg[next])
mFirst += 1
next += 1
if mFirst == mMiddle:
mMiddle = next
elif next == last:
next = mMiddle
proc rotatedInternal[T](arg: openarray[T]; first, middle, last: int): seq[T] =
result = newSeq[T](arg.len)
for i in 0 ..< first:
result[i] = arg[i]
let N = last - middle
let M = middle - first
for i in 0 ..< N:
result[first+i] = arg[middle+i]
for i in 0 ..< M:
result[first+N+i] = arg[first+i]
for i in last ..< arg.len:
result[i] = arg[i]
proc rotateLeft*[T](arg: var openarray[T]; slice: HSlice[int, int]; dist: int): int =
## Performs a left rotation on a range of elements. If you want to rotate right, use a negative ``dist``.
## Specifically, ``rotateLeft`` rotates the elements at ``slice`` by ``dist`` positions.
## The element at index ``slice.a + dist`` will be at index ``slice.a``.
## The element at index ``slice.b`` will be at ``slice.a + dist -1``.
## The element at index ``slice.a`` will be at ``slice.b + 1 - dist``.
## The element at index ``slice.a + dist - 1`` will be at ``slice.b``.
#
## Elements outsize of ``slice`` will be left unchanged.
## The time complexity is linear to ``slice.b - slice.a + 1``.
##
## ``slice``
## the indices of the element range that should be rotated.
##
## ``dist``
## the distance in amount of elements that the data should be rotated. Can be negative, can be any number.
##
## .. code-block:: nim
## var list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
## list.rotateLeft(1 .. 8, 3)
## doAssert list == [0, 4, 5, 6, 7, 8, 1, 2, 3, 9, 10]
let sliceLen = slice.b + 1 - slice.a
let distLeft = ((dist mod sliceLen) + sliceLen) mod sliceLen
arg.rotateInternal(slice.a, slice.a+distLeft, slice.b + 1)
proc rotateLeft*[T](arg: var openarray[T]; dist: int): int =
## default arguments for slice, so that this procedure operates on the entire
## ``arg``, and not just on a part of it.
let arglen = arg.len
let distLeft = ((dist mod arglen) + arglen) mod arglen
arg.rotateInternal(0, distLeft, arglen)
proc rotatedLeft*[T](arg: openarray[T]; slice: HSlice[int, int], dist: int): seq[T] =
## same as ``rotateLeft``, just with the difference that it does
## not modify the argument. It creates a new ``seq`` instead
let sliceLen = slice.b + 1 - slice.a
let distLeft = ((dist mod sliceLen) + sliceLen) mod sliceLen
arg.rotatedInternal(slice.a, slice.a+distLeft, slice.b+1)
proc rotatedLeft*[T](arg: openarray[T]; dist: int): seq[T] =
## same as ``rotateLeft``, just with the difference that it does
## not modify the argument. It creates a new ``seq`` instead
let arglen = arg.len
let distLeft = ((dist mod arglen) + arglen) mod arglen
arg.rotatedInternal(0, distLeft, arg.len)
when isMainModule:
var list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let list2 = list.rotatedLeft(1 ..< 9, 3)
let expected = [0, 4, 5, 6, 7, 8, 1, 2, 3, 9, 10]
doAssert list.rotateLeft(1 ..< 9, 3) == 6
doAssert list == expected
doAssert list2 == @expected
var s0,s1,s2,s3,s4,s5 = "xxxabcdefgxxx"
doAssert s0.rotateLeft(3 ..< 10, 3) == 7
doAssert s0 == "xxxdefgabcxxx"
doAssert s1.rotateLeft(3 ..< 10, 2) == 8
doAssert s1 == "xxxcdefgabxxx"
doAssert s2.rotateLeft(3 ..< 10, 4) == 6
doAssert s2 == "xxxefgabcdxxx"
doAssert s3.rotateLeft(3 ..< 10, -3) == 6
doAssert s3 == "xxxefgabcdxxx"
doAssert s4.rotateLeft(3 ..< 10, -10) == 6
doAssert s4 == "xxxefgabcdxxx"
doAssert s5.rotateLeft(3 ..< 10, 11) == 6
doAssert s5 == "xxxefgabcdxxx"

View file

@ -61,14 +61,14 @@ proc generateExceptionCheck(futSym,
else:
var exceptionChecks: seq[tuple[cond, body: NimNode]] = @[]
let errorNode = newDotExpr(futSym, newIdentNode("error"))
for i in 1 .. <tryStmt.len:
for i in 1 ..< tryStmt.len:
let exceptBranch = tryStmt[i]
if exceptBranch[0].kind == nnkStmtList:
exceptionChecks.add((newIdentNode("true"), exceptBranch[0]))
else:
var exceptIdentCount = 0
var ifCond: NimNode
for i in 0 .. <exceptBranch.len:
for i in 0 ..< exceptBranch.len:
let child = exceptBranch[i]
if child.kind == nnkIdent:
let cond = infix(errorNode, "of", child)
@ -270,7 +270,7 @@ proc processBody(node, retFutureSym: NimNode,
return
else: discard
for i in 0 .. <result.len:
for i in 0 ..< result.len:
result[i] = processBody(result[i], retFutureSym, subTypeIsVoid,
futureVarIdents, nil)
@ -287,7 +287,7 @@ proc getName(node: NimNode): string {.compileTime.} =
proc getFutureVarIdents(params: NimNode): seq[NimNode] {.compileTime.} =
result = @[]
for i in 1 .. <len(params):
for i in 1 ..< len(params):
expectKind(params[i], nnkIdentDefs)
if params[i][1].kind == nnkBracketExpr and
($params[i][1][0].ident).normalize == "futurevar":
@ -466,7 +466,7 @@ proc stripAwait(node: NimNode): NimNode =
node[0][0] = emptyNoopSym
else: discard
for i in 0 .. <result.len:
for i in 0 ..< result.len:
result[i] = stripAwait(result[i])
proc splitParamType(paramType: NimNode, async: bool): NimNode =
@ -512,7 +512,7 @@ proc splitProc(prc: NimNode): (NimNode, NimNode) =
# Retrieve the `T` inside `Future[T]`.
let returnType = stripReturnType(result[0][3][0])
result[0][3][0] = splitParamType(returnType, async=false)
for i in 1 .. <result[0][3].len:
for i in 1 ..< result[0][3].len:
# Sync proc (0) -> FormalParams (3) -> IdentDefs, the parameter (i) ->
# parameter type (1).
result[0][3][i][1] = splitParamType(result[0][3][i][1], async=false)
@ -521,7 +521,7 @@ proc splitProc(prc: NimNode): (NimNode, NimNode) =
result[1] = prc.copyNimTree()
if result[1][3][0].kind == nnkBracketExpr:
result[1][3][0][1] = splitParamType(result[1][3][0][1], async=true)
for i in 1 .. <result[1][3].len:
for i in 1 ..< result[1][3].len:
# Async proc (1) -> FormalParams (3) -> IdentDefs, the parameter (i) ->
# parameter type (1).
result[1][3][i][1] = splitParamType(result[1][3][i][1], async=true)

View file

@ -257,7 +257,7 @@ proc allprefixedAux[T](c: CritBitTree[T], key: string; longestMatch: bool): Node
p = p.child[dir]
if q.byte < key.len: top = p
if not longestMatch:
for i in 0 .. <key.len:
for i in 0 ..< key.len:
if p.key[i] != key[i]: return
result = top

View file

@ -207,9 +207,9 @@ when isMainModule:
assert($deq == "[4, 56, 6, 789]")
assert deq[0] == deq.peekFirst and deq.peekFirst == 4
assert deq[^1] == deq.peekLast and deq.peekLast == 789
#assert deq[^1] == deq.peekLast and deq.peekLast == 789
deq[0] = 42
deq[^1] = 7
deq[deq.len - 1] = 7
assert 6 in deq and 789 notin deq
assert deq.find(6) >= 0

View file

@ -37,6 +37,14 @@ type
DoublyLinkedRing*[T] = object ## a doubly linked ring
head*: DoublyLinkedNode[T]
SomeLinkedList*[T] = SinglyLinkedList[T] | DoublyLinkedList[T]
SomeLinkedRing*[T] = SinglyLinkedRing[T] | DoublyLinkedRing[T]
SomeLinkedCollection*[T] = SomeLinkedList[T] | SomeLinkedRing[T]
SomeLinkedNode*[T] = SinglyLinkedNode[T] | DoublyLinkedNode[T]
{.deprecated: [TDoublyLinkedNode: DoublyLinkedNodeObj,
PDoublyLinkedNode: DoublyLinkedNode,
TSinglyLinkedNode: SinglyLinkedNodeObj,
@ -86,14 +94,34 @@ template itemsRingImpl() {.dirty.} =
it = it.next
if it == L.head: break
template nodesListImpl() {.dirty.} =
iterator items*[T](L: SomeLinkedList[T]): T =
## yields every value of `L`.
itemsListImpl()
iterator items*[T](L: SomeLinkedRing[T]): T =
## yields every value of `L`.
itemsRingImpl()
iterator mitems*[T](L: var SomeLinkedList[T]): var T =
## yields every value of `L` so that you can modify it.
itemsListImpl()
iterator mitems*[T](L: var SomeLinkedRing[T]): var T =
## yields every value of `L` so that you can modify it.
itemsRingImpl()
iterator nodes*[T](L: SomeLinkedList[T]): SomeLinkedNode[T] =
## iterates over every node of `x`. Removing the current node from the
## list during traversal is supported.
var it = L.head
while it != nil:
var nxt = it.next
yield it
it = nxt
template nodesRingImpl() {.dirty.} =
iterator nodes*[T](L: SomeLinkedRing[T]): SomeLinkedNode[T] =
## iterates over every node of `x`. Removing the current node from the
## list during traversal is supported.
var it = L.head
if it != nil:
while true:
@ -102,121 +130,21 @@ template nodesRingImpl() {.dirty.} =
it = nxt
if it == L.head: break
template findImpl() {.dirty.} =
for x in nodes(L):
if x.value == value: return x
iterator items*[T](L: DoublyLinkedList[T]): T =
## yields every value of `L`.
itemsListImpl()
iterator items*[T](L: SinglyLinkedList[T]): T =
## yields every value of `L`.
itemsListImpl()
iterator items*[T](L: SinglyLinkedRing[T]): T =
## yields every value of `L`.
itemsRingImpl()
iterator items*[T](L: DoublyLinkedRing[T]): T =
## yields every value of `L`.
itemsRingImpl()
iterator mitems*[T](L: var DoublyLinkedList[T]): var T =
## yields every value of `L` so that you can modify it.
itemsListImpl()
iterator mitems*[T](L: var SinglyLinkedList[T]): var T =
## yields every value of `L` so that you can modify it.
itemsListImpl()
iterator mitems*[T](L: var SinglyLinkedRing[T]): var T =
## yields every value of `L` so that you can modify it.
itemsRingImpl()
iterator mitems*[T](L: var DoublyLinkedRing[T]): var T =
## yields every value of `L` so that you can modify it.
itemsRingImpl()
iterator nodes*[T](L: SinglyLinkedList[T]): SinglyLinkedNode[T] =
## iterates over every node of `x`. Removing the current node from the
## list during traversal is supported.
nodesListImpl()
iterator nodes*[T](L: DoublyLinkedList[T]): DoublyLinkedNode[T] =
## iterates over every node of `x`. Removing the current node from the
## list during traversal is supported.
nodesListImpl()
iterator nodes*[T](L: SinglyLinkedRing[T]): SinglyLinkedNode[T] =
## iterates over every node of `x`. Removing the current node from the
## list during traversal is supported.
nodesRingImpl()
iterator nodes*[T](L: DoublyLinkedRing[T]): DoublyLinkedNode[T] =
## iterates over every node of `x`. Removing the current node from the
## list during traversal is supported.
nodesRingImpl()
template dollarImpl() {.dirty.} =
proc `$`*[T](L: SomeLinkedCollection[T]): string =
## turns a list into its string representation.
result = "["
for x in nodes(L):
if result.len > 1: result.add(", ")
result.add($x.value)
result.add("]")
proc `$`*[T](L: SinglyLinkedList[T]): string =
## turns a list into its string representation.
dollarImpl()
proc `$`*[T](L: DoublyLinkedList[T]): string =
## turns a list into its string representation.
dollarImpl()
proc `$`*[T](L: SinglyLinkedRing[T]): string =
## turns a list into its string representation.
dollarImpl()
proc `$`*[T](L: DoublyLinkedRing[T]): string =
## turns a list into its string representation.
dollarImpl()
proc find*[T](L: SinglyLinkedList[T], value: T): SinglyLinkedNode[T] =
proc find*[T](L: SomeLinkedCollection[T], value: T): SomeLinkedNode[T] =
## searches in the list for a value. Returns nil if the value does not
## exist.
findImpl()
for x in nodes(L):
if x.value == value: return x
proc find*[T](L: DoublyLinkedList[T], value: T): DoublyLinkedNode[T] =
## searches in the list for a value. Returns nil if the value does not
## exist.
findImpl()
proc find*[T](L: SinglyLinkedRing[T], value: T): SinglyLinkedNode[T] =
## searches in the list for a value. Returns nil if the value does not
## exist.
findImpl()
proc find*[T](L: DoublyLinkedRing[T], value: T): DoublyLinkedNode[T] =
## searches in the list for a value. Returns nil if the value does not
## exist.
findImpl()
proc contains*[T](L: SinglyLinkedList[T], value: T): bool {.inline.} =
## searches in the list for a value. Returns false if the value does not
## exist, true otherwise.
result = find(L, value) != nil
proc contains*[T](L: DoublyLinkedList[T], value: T): bool {.inline.} =
## searches in the list for a value. Returns false if the value does not
## exist, true otherwise.
result = find(L, value) != nil
proc contains*[T](L: SinglyLinkedRing[T], value: T): bool {.inline.} =
## searches in the list for a value. Returns false if the value does not
## exist, true otherwise.
result = find(L, value) != nil
proc contains*[T](L: DoublyLinkedRing[T], value: T): bool {.inline.} =
proc contains*[T](L: SomeLinkedCollection[T], value: T): bool {.inline.} =
## searches in the list for a value. Returns false if the value does not
## exist, true otherwise.
result = find(L, value) != nil
@ -266,7 +194,6 @@ proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) =
if n.next != nil: n.next.prev = n.prev
if n.prev != nil: n.prev.next = n.next
proc append*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) =
## appends a node `n` to `L`. Efficiency: O(1).
if L.head != nil:

View file

@ -198,9 +198,8 @@ when isMainModule:
assert($q == "[4, 56, 6, 789]")
assert q[0] == q.front and q.front == 4
assert q[^1] == q.back and q.back == 789
q[0] = 42
q[^1] = 7
q[q.len - 1] = 7
assert 6 in q and 789 notin q
assert q.find(6) >= 0

View file

@ -13,8 +13,9 @@
## were inspired by functional programming languages.
##
## For functional style programming you may want to pass `anonymous procs
## <manual.html#anonymous-procs>`_ to procs like ``filter`` to reduce typing.
## Anonymous procs can use `the special do notation <manual.html#do-notation>`_
## <manual.html#procedures-anonymous-procs>`_ to procs like ``filter`` to
## reduce typing. Anonymous procs can use `the special do notation
## <manual.html#procedures-do-notation>`_
## which is more convenient in certain situations.
include "system/inclrtl"
@ -43,8 +44,23 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
result[i] = itm
inc(i)
proc cycle*[T](s: seq[T], n: Natural): seq[T] =
## Returns a new sequence with the items of `s` repeated `n` times.
proc count*[T](s: openArray[T], x: T): int =
## Returns the number of occurrences of the item `x` in the container `s`.
##
## Example:
##
## .. code-block::
## let
## s = @[1, 2, 2, 3, 2, 4, 2]
## c = count(s, 2)
## assert c == 4
for itm in items(s):
if itm == x:
inc result
proc cycle*[T](s: openArray[T], n: Natural): seq[T] =
## Returns a new sequence with the items of the container `s` repeated
## `n` times.
##
## Example:
##
@ -56,7 +72,7 @@ proc cycle*[T](s: seq[T], n: Natural): seq[T] =
## assert total == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
result = newSeq[T](n * s.len)
var o = 0
for x in 0..<n:
for x in 0 ..< n:
for e in s:
result[o] = e
inc o
@ -72,12 +88,14 @@ proc repeat*[T](x: T, n: Natural): seq[T] =
## total = repeat(5, 3)
## assert total == @[5, 5, 5]
result = newSeq[T](n)
for i in 0..<n:
for i in 0 ..< n:
result[i] = x
proc deduplicate*[T](seq1: seq[T]): seq[T] =
proc deduplicate*[T](s: openArray[T]): seq[T] =
## Returns a new sequence without duplicates.
##
## Example:
##
## .. code-block::
## let
## dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
@ -87,17 +105,19 @@ proc deduplicate*[T](seq1: seq[T]): seq[T] =
## assert unique1 == @[1, 3, 4, 2, 8]
## assert unique2 == @["a", "c", "d"]
result = @[]
for itm in items(seq1):
for itm in items(s):
if not result.contains(itm): result.add(itm)
{.deprecated: [distnct: deduplicate].}
proc zip*[S, T](seq1: seq[S], seq2: seq[T]): seq[tuple[a: S, b: T]] =
## Returns a new sequence with a combination of the two input sequences.
proc zip*[S, T](s1: openArray[S], s2: openArray[T]): seq[tuple[a: S, b: T]] =
## Returns a new sequence with a combination of the two input containers.
##
## For convenience you can access the returned tuples through the named
## fields `a` and `b`. If one sequence is shorter, the remaining items in the
## longer sequence are discarded. Example:
## fields `a` and `b`. If one container is shorter, the remaining items in
## the longer container are discarded.
##
## Example:
##
## .. code-block::
## let
@ -110,15 +130,16 @@ proc zip*[S, T](seq1: seq[S], seq2: seq[T]): seq[tuple[a: S, b: T]] =
## assert zip2 == @[(1, "one"), (2, "two"), (3, "three")]
## assert zip1[2].b == 4
## assert zip2[2].b == "three"
var m = min(seq1.len, seq2.len)
var m = min(s1.len, s2.len)
newSeq(result, m)
for i in 0 .. m-1: result[i] = (seq1[i], seq2[i])
for i in 0 ..< m:
result[i] = (s1[i], s2[i])
proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
## Splits and distributes a sequence `s` into `num` sub sequences.
##
## Returns a sequence of `num` sequences. For some input values this is the
## inverse of the `concat <#concat>`_ proc. The proc will assert in debug
## inverse of the `concat <#concat>`_ proc. The proc will assert in debug
## builds if `s` is nil or `num` is less than one, and will likely crash on
## release builds. The input sequence `s` can be empty, which will produce
## `num` empty sequences.
@ -159,48 +180,52 @@ proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
# Use an algorithm which overcounts the stride and minimizes reading limits.
if extra > 0: inc(stride)
for i in 0 .. <num:
for i in 0 ..< num:
result[i] = newSeq[T]()
for g in first .. <min(s.len, first + stride):
for g in first ..< min(s.len, first + stride):
result[i].add(s[g])
first += stride
else:
# Use an undercounting algorithm which *adds* the remainder each iteration.
for i in 0 .. <num:
for i in 0 ..< num:
last = first + stride
if extra > 0:
extra -= 1
inc(last)
result[i] = newSeq[T]()
for g in first .. <last:
for g in first ..< last:
result[i].add(s[g])
first = last
proc map*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}):
proc map*[T, S](s: 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`.
## the container `s`.
##
## 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:
## transform the type of the elements in the input container.
##
## 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])
newSeq(result, s.len)
for i in 0 ..< s.len:
result[i] = op(s[i])
proc map*[T](data: var openArray[T], op: proc (x: var T) {.closure.})
proc map*[T](s: var openArray[T], op: proc (x: var T) {.closure.})
{.deprecated.} =
## Applies `op` to every item in `data` modifying it directly.
## Applies `op` to every item in `s` 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:
## be the same, since they are modified in-place.
##
## Example:
##
## .. code-block:: nim
## var a = @["1", "2", "3", "4"]
@ -210,15 +235,16 @@ proc map*[T](data: var openArray[T], op: proc (x: var T) {.closure.})
## 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])
for i in 0 ..< s.len: op(s[i])
proc apply*[T](data: var seq[T], op: proc (x: var T) {.closure.})
proc apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.})
{.inline.} =
## Applies `op` to every item in `data` modifying it directly.
## Applies `op` to every item in `s` 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
@ -229,15 +255,16 @@ proc apply*[T](data: var seq[T], op: proc (x: var T) {.closure.})
## echo repr(a)
## # --> ["142", "242", "342", "442"]
##
for i in 0..data.len-1: op(data[i])
for i in 0 ..< s.len: op(s[i])
proc apply*[T](data: var seq[T], op: proc (x: T): T {.closure.})
proc apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.})
{.inline.} =
## Applies `op` to every item in `data` modifying it directly.
## Applies `op` to every item in `s` 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
@ -248,11 +275,10 @@ proc apply*[T](data: var seq[T], op: proc (x: T): T {.closure.})
## echo repr(a)
## # --> ["142", "242", "342", "442"]
##
for i in 0..data.len-1: data[i] = op(data[i])
for i in 0 ..< s.len: s[i] = op(s[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
iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T =
## Iterates through a container and yields every item that fulfills the
## predicate.
##
## Example:
@ -262,11 +288,11 @@ 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 0..<seq1.len:
if pred(seq1[i]):
yield seq1[i]
for i in 0 ..< s.len:
if pred(s[i]):
yield s[i]
proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T]
proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T]
{.inline.} =
## Returns a new sequence with all the items that fulfilled the predicate.
##
@ -280,11 +306,11 @@ proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T]
## assert f1 == @["red", "black"]
## assert f2 == @["yellow"]
result = newSeq[T]()
for i in 0..<seq1.len:
if pred(seq1[i]):
result.add(seq1[i])
for i in 0 ..< s.len:
if pred(s[i]):
result.add(s[i])
proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.})
proc keepIf*[T](s: var seq[T], pred: proc(x: 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.
@ -296,12 +322,12 @@ proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.})
## keepIf(floats, proc(x: float): bool = x > 10)
## assert floats == @[13.0, 12.5, 10.1]
var pos = 0
for i in 0 .. <len(seq1):
if pred(seq1[i]):
for i in 0 ..< len(s):
if pred(s[i]):
if pos != i:
shallowCopy(seq1[pos], seq1[i])
shallowCopy(s[pos], s[i])
inc(pos)
setLen(seq1, pos)
setLen(s, pos)
proc delete*[T](s: var seq[T]; first, last: Natural) =
## Deletes in `s` the items at position `first` .. `last`. This modifies
@ -354,11 +380,12 @@ proc insert*[T](dest: var seq[T], src: openArray[T], pos=0) =
inc(j)
template filterIt*(seq1, pred: untyped): untyped =
template filterIt*(s, pred: untyped): untyped =
## Returns a new sequence with all the items that fulfilled the predicate.
##
## Unlike the `proc` version, the predicate needs to be an expression using
## the ``it`` variable for testing, like: ``filterIt("abcxyz", it == 'x')``.
##
## Example:
##
## .. code-block::
@ -368,8 +395,8 @@ template filterIt*(seq1, pred: untyped): untyped =
## 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 = newSeq[type(seq1[0])]()
for it {.inject.} in items(seq1):
var result = newSeq[type(s[0])]()
for it {.inject.} in items(s):
if pred: result.add(it)
result
@ -378,6 +405,7 @@ template keepItIf*(varSeq: seq, pred: untyped) =
##
## Unlike the `proc` version, the predicate needs to be an expression using
## the ``it`` variable for testing, like: ``keepItIf("abcxyz", it == 'x')``.
##
## Example:
##
## .. code-block::
@ -385,7 +413,7 @@ template keepItIf*(varSeq: seq, pred: untyped) =
## keepItIf(candidates, it.len == 3 and it[0] == 'b')
## assert candidates == @["bar", "baz"]
var pos = 0
for i in 0 .. <len(varSeq):
for i in 0 ..< len(varSeq):
let it {.inject.} = varSeq[i]
if pred:
if pos != i:
@ -393,8 +421,8 @@ template keepItIf*(varSeq: seq, pred: untyped) =
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
proc all*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool =
## Iterates through a container and checks if every item fulfills the
## predicate.
##
## Example:
@ -403,12 +431,12 @@ proc all*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): bool =
## 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:
for i in s:
if not pred(i):
return false
return true
template allIt*(seq1, pred: untyped): bool =
template allIt*(s, pred: untyped): bool =
## Checks if every item fulfills the predicate.
##
## Example:
@ -418,14 +446,14 @@ template allIt*(seq1, pred: untyped): bool =
## assert allIt(numbers, it < 10) == true
## assert allIt(numbers, it < 9) == false
var result = true
for it {.inject.} in items(seq1):
for it {.inject.} in items(s):
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
proc any*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool =
## Iterates through a container and checks if some item fulfills the
## predicate.
##
## Example:
@ -434,12 +462,12 @@ proc any*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): bool =
## 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:
for i in s:
if pred(i):
return true
return false
template anyIt*(seq1, pred: untyped): bool =
template anyIt*(s, pred: untyped): bool =
## Checks if some item fulfills the predicate.
##
## Example:
@ -449,7 +477,7 @@ template anyIt*(seq1, pred: untyped): bool =
## assert anyIt(numbers, it > 8) == true
## assert anyIt(numbers, it > 9) == false
var result = false
for it {.inject.} in items(seq1):
for it {.inject.} in items(s):
if pred:
result = true
break
@ -493,7 +521,9 @@ template foldl*(sequence, operation: untyped): untyped =
## variables ``a`` and ``b`` for each step of the fold. Since this is a left
## fold, for non associative binary operations like subtraction think that
## the sequence of numbers 1, 2 and 3 will be parenthesized as (((1) - 2) -
## 3). Example:
## 3).
##
## Example:
##
## .. code-block::
## let
@ -527,6 +557,7 @@ template foldl*(sequence, operation, first): untyped =
## The ``operation`` parameter should be an expression which uses the variables
## ``a`` and ``b`` for each step of the fold. The ``first`` parameter is the
## start value (the first ``a``) and therefor defines the type of the result.
##
## Example:
##
## .. code-block::
@ -555,7 +586,9 @@ template foldr*(sequence, operation: untyped): untyped =
## variables ``a`` and ``b`` for each step of the fold. Since this is a right
## fold, for non associative binary operations like subtraction think that
## the sequence of numbers 1, 2 and 3 will be parenthesized as (1 - (2 -
## (3))). Example:
## (3))).
##
## Example:
##
## .. code-block::
## let
@ -580,13 +613,15 @@ template foldr*(sequence, operation: untyped): untyped =
result = operation
result
template mapIt*(seq1, typ, op: untyped): untyped =
template mapIt*(s, typ, op: untyped): untyped =
## Convenience template around the ``map`` proc to reduce typing.
##
## The template injects the ``it`` variable which you can use directly in an
## expression. You also need to pass as `typ` the type of the expression,
## since the new returned sequence can have a different type than the
## original. Example:
## original.
##
## Example:
##
## .. code-block::
## let
@ -596,16 +631,18 @@ template mapIt*(seq1, typ, op: untyped): untyped =
## **Deprecated since version 0.12.0:** Use the ``mapIt(seq1, op)``
## template instead.
var result: seq[typ] = @[]
for it {.inject.} in items(seq1):
for it {.inject.} in items(s):
result.add(op)
result
template mapIt*(seq1, op: untyped): untyped =
template mapIt*(s, op: untyped): untyped =
## Convenience template around the ``map`` proc to reduce typing.
##
## The template injects the ``it`` variable which you can use directly in an
## expression. Example:
## expression.
##
## Example:
##
## .. code-block::
## let
@ -614,19 +651,19 @@ template mapIt*(seq1, op: untyped): untyped =
## assert strings == @["4", "8", "12", "16"]
type outType = type((
block:
var it{.inject.}: type(items(seq1));
var it{.inject.}: type(items(s));
op))
var result: seq[outType]
when compiles(seq1.len):
let s = seq1
when compiles(s.len):
let t = s
var i = 0
result = newSeq[outType](s.len)
for it {.inject.} in s:
for it {.inject.} in t:
result[i] = op
i += 1
else:
result = @[]
for it {.inject.} in seq1:
for it {.inject.} in s:
result.add(op)
result
@ -635,20 +672,23 @@ template applyIt*(varSeq, op: untyped) =
##
## 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
## are mutating. Example:
## are mutating.
##
## Example:
##
## .. code-block::
## var nums = @[1, 2, 3, 4]
## nums.applyIt(it * 3)
## assert nums[0] + nums[3] == 15
for i in 0 .. <varSeq.len:
for i in 0 ..< varSeq.len:
let it {.inject.} = varSeq[i]
varSeq[i] = op
template newSeqWith*(len: int, init: untyped): untyped =
## creates a new sequence, calling `init` to initialize each value. Example:
## creates a new sequence, calling `init` to initialize each value.
##
## Example:
##
## .. code-block::
## var seq2D = newSeqWith(20, newSeq[bool](10))
@ -660,7 +700,7 @@ template newSeqWith*(len: int, init: untyped): untyped =
## var seqRand = newSeqWith(20, random(10))
## echo seqRand
var result = newSeq[type(init)](len)
for i in 0 .. <len:
for i in 0 ..< len:
result[i] = init
result
@ -674,45 +714,178 @@ when isMainModule:
total = concat(s1, s2, s3)
assert total == @[1, 2, 3, 4, 5, 6, 7]
block: # duplicates test
block: # count test
let
s1 = @[1, 2, 3, 2]
s2 = @['a', 'b', 'x', 'a']
a1 = [1, 2, 3, 2]
a2 = ['a', 'b', 'x', 'a']
r0 = count(s1, 0)
r1 = count(s1, 1)
r2 = count(s1, 2)
r3 = count(s2, 'y')
r4 = count(s2, 'x')
r5 = count(s2, 'a')
ar0 = count(a1, 0)
ar1 = count(a1, 1)
ar2 = count(a1, 2)
ar3 = count(a2, 'y')
ar4 = count(a2, 'x')
ar5 = count(a2, 'a')
assert r0 == 0
assert r1 == 1
assert r2 == 2
assert r3 == 0
assert r4 == 1
assert r5 == 2
assert ar0 == 0
assert ar1 == 1
assert ar2 == 2
assert ar3 == 0
assert ar4 == 1
assert ar5 == 2
block: # cycle tests
let
a = @[1, 2, 3]
b: seq[int] = @[]
c = [1, 2, 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) == @[]
doAssert c.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
doAssert c.cycle(0) == @[]
block: # repeat tests
assert repeat(10, 5) == @[10, 10, 10, 10, 10]
assert repeat(@[1,2,3], 2) == @[@[1,2,3], @[1,2,3]]
assert repeat([1,2,3], 2) == @[[1,2,3], [1,2,3]]
block: # deduplicates test
let
dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
dup2 = @["a", "a", "c", "d", "d"]
dup3 = [1, 1, 3, 4, 2, 2, 8, 1, 4]
dup4 = ["a", "a", "c", "d", "d"]
unique1 = deduplicate(dup1)
unique2 = deduplicate(dup2)
unique3 = deduplicate(dup3)
unique4 = deduplicate(dup4)
assert unique1 == @[1, 3, 4, 2, 8]
assert unique2 == @["a", "c", "d"]
assert unique3 == @[1, 3, 4, 2, 8]
assert unique4 == @["a", "c", "d"]
block: # zip test
let
short = @[1, 2, 3]
long = @[6, 5, 4, 3, 2, 1]
words = @["one", "two", "three"]
ashort = [1, 2, 3]
along = [6, 5, 4, 3, 2, 1]
awords = ["one", "two", "three"]
zip1 = zip(short, long)
zip2 = zip(short, words)
zip3 = zip(ashort, along)
zip4 = zip(ashort, awords)
zip5 = zip(ashort, words)
assert zip1 == @[(1, 6), (2, 5), (3, 4)]
assert zip2 == @[(1, "one"), (2, "two"), (3, "three")]
assert zip3 == @[(1, 6), (2, 5), (3, 4)]
assert zip4 == @[(1, "one"), (2, "two"), (3, "three")]
assert zip5 == @[(1, "one"), (2, "two"), (3, "three")]
assert zip1[2].b == 4
assert zip2[2].b == "three"
assert zip3[2].b == 4
assert zip4[2].b == "three"
assert zip5[2].b == "three"
block: # distribute tests
let numbers = @[1, 2, 3, 4, 5, 6, 7]
doAssert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
doAssert numbers.distribute(6)[0] == @[1, 2]
doAssert numbers.distribute(6)[5] == @[7]
let a = @[1, 2, 3, 4, 5, 6, 7]
doAssert a.distribute(1, true) == @[@[1, 2, 3, 4, 5, 6, 7]]
doAssert a.distribute(1, false) == @[@[1, 2, 3, 4, 5, 6, 7]]
doAssert a.distribute(2, true) == @[@[1, 2, 3, 4], @[5, 6, 7]]
doAssert a.distribute(2, false) == @[@[1, 2, 3, 4], @[5, 6, 7]]
doAssert a.distribute(3, true) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
doAssert a.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]]
doAssert a.distribute(4, true) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
doAssert a.distribute(4, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
doAssert a.distribute(5, true) == @[@[1, 2], @[3, 4], @[5], @[6], @[7]]
doAssert a.distribute(5, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7], @[]]
doAssert a.distribute(6, true) == @[@[1, 2], @[3], @[4], @[5], @[6], @[7]]
doAssert a.distribute(6, false) == @[
@[1, 2], @[3, 4], @[5, 6], @[7], @[], @[]]
doAssert a.distribute(8, false) == a.distribute(8, true)
doAssert a.distribute(90, false) == a.distribute(90, true)
var b = @[0]
for f in 1 .. 25: b.add(f)
doAssert b.distribute(5, true)[4].len == 5
doAssert b.distribute(5, false)[4].len == 2
block: # map test
let
numbers = @[1, 4, 5, 8, 9, 7, 4]
anumbers = [1, 4, 5, 8, 9, 7, 4]
m1 = map(numbers, proc(x: int): int = 2*x)
m2 = map(anumbers, proc(x: int): int = 2*x)
assert m1 == @[2, 8, 10, 16, 18, 14, 8]
assert m2 == @[2, 8, 10, 16, 18, 14, 8]
block: # apply test
var a = @["1", "2", "3", "4"]
apply(a, proc(x: var string) = x &= "42")
assert a == @["142", "242", "342", "442"]
block: # filter proc test
let
colors = @["red", "yellow", "black"]
acolors = ["red", "yellow", "black"]
f1 = filter(colors, proc(x: string): bool = x.len < 6)
f2 = filter(colors) do (x: string) -> bool : x.len > 5
f3 = filter(acolors, proc(x: string): bool = x.len < 6)
f4 = filter(acolors) do (x: string) -> bool : x.len > 5
assert f1 == @["red", "black"]
assert f2 == @["yellow"]
assert f3 == @["red", "black"]
assert f4 == @["yellow"]
block: # filter iterator test
let numbers = @[1, 4, 5, 8, 9, 7, 4]
let anumbers = [1, 4, 5, 8, 9, 7, 4]
assert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) ==
@[4, 8, 4]
assert toSeq(filter(anumbers, proc (x: int): bool = x mod 2 == 0)) ==
@[4, 8, 4]
block: # keepIf test
var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
keepIf(floats, proc(x: float): bool = x > 10)
assert floats == @[13.0, 12.5, 10.1]
block: # delete tests
let outcome = @[1,1,1,1,1,1,1,1]
var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
dest.delete(3, 8)
assert outcome == dest, """\
Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1]
is [1,1,1,1,1,1,1,1]"""
block: # insert tests
var dest = @[1,1,1,1,1,1,1,1]
let
src = @[2,2,2,2,2,2]
outcome = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
dest.insert(src, 3)
assert dest == outcome, """\
Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1]
at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]"""
block: # filterIt test
let
temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44]
@ -726,37 +899,49 @@ 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]
anumbers = [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
assert all(anumbers, proc (x: int): bool = return x < 10) == true
assert all(anumbers, proc (x: int): bool = return x < 9) == false
block: # allIt
let
numbers = @[1, 4, 5, 8, 9, 7, 4]
anumbers = [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
assert allIt(anumbers, it < 10) == true
assert allIt(anumbers, it < 9) == false
block: # any
let
numbers = @[1, 4, 5, 8, 9, 7, 4]
anumbers = [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
assert any(anumbers, proc (x: int): bool = return x > 8) == true
assert any(anumbers, proc (x: int): bool = return x > 9) == false
block: # anyIt
let
numbers = @[1, 4, 5, 8, 9, 7, 4]
anumbers = [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
assert anyIt(anumbers, it > 8) == true
assert anyIt(anumbers, it > 9) == false
block: # toSeq test
let
@ -792,56 +977,13 @@ when isMainModule:
assert multiplication == 495, "Multiplication is (5*(9*(11)))"
assert concatenation == "nimiscool"
block: # delete tests
let outcome = @[1,1,1,1,1,1,1,1]
var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
dest.delete(3, 8)
assert outcome == dest, """\
Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1]
is [1,1,1,1,1,1,1,1]"""
block: # insert tests
var dest = @[1,1,1,1,1,1,1,1]
let
src = @[2,2,2,2,2,2]
outcome = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
dest.insert(src, 3)
assert dest == outcome, """\
Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1]
at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]"""
block: # mapIt tests
var
nums = @[1, 2, 3, 4]
strings = nums.mapIt($(4 * it))
nums.applyIt(it * 3)
assert nums[0] + nums[3] == 15
block: # distribute tests
let numbers = @[1, 2, 3, 4, 5, 6, 7]
doAssert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
doAssert numbers.distribute(6)[0] == @[1, 2]
doAssert numbers.distribute(6)[5] == @[7]
let a = @[1, 2, 3, 4, 5, 6, 7]
doAssert a.distribute(1, true) == @[@[1, 2, 3, 4, 5, 6, 7]]
doAssert a.distribute(1, false) == @[@[1, 2, 3, 4, 5, 6, 7]]
doAssert a.distribute(2, true) == @[@[1, 2, 3, 4], @[5, 6, 7]]
doAssert a.distribute(2, false) == @[@[1, 2, 3, 4], @[5, 6, 7]]
doAssert a.distribute(3, true) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
doAssert a.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]]
doAssert a.distribute(4, true) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
doAssert a.distribute(4, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
doAssert a.distribute(5, true) == @[@[1, 2], @[3, 4], @[5], @[6], @[7]]
doAssert a.distribute(5, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7], @[]]
doAssert a.distribute(6, true) == @[@[1, 2], @[3], @[4], @[5], @[6], @[7]]
doAssert a.distribute(6, false) == @[
@[1, 2], @[3, 4], @[5, 6], @[7], @[], @[]]
doAssert a.distribute(8, false) == a.distribute(8, true)
doAssert a.distribute(90, false) == a.distribute(90, true)
var b = @[0]
for f in 1 .. 25: b.add(f)
doAssert b.distribute(5, true)[4].len == 5
doAssert b.distribute(5, false)[4].len == 2
assert strings[2] == "12"
block: # newSeqWith tests
var seq2D = newSeqWith(4, newSeq[bool](2))
@ -850,19 +992,5 @@ when isMainModule:
seq2D[0][1] = true
doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
block: # cycle tests
let
a = @[1, 2, 3]
b: seq[int] = @[]
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"

View file

@ -55,7 +55,7 @@ proc `[]=`*(s: var SharedString; i: Natural; value: char) =
if i < s.len: s.buffer.data[i+s.first] = value
else: raise newException(IndexError, "index out of bounds")
proc `[]`*(s: SharedString; ab: Slice[int]): SharedString =
proc `[]`*(s: SharedString; ab: HSlice[int, int]): SharedString =
#incRef(src.buffer)
if ab.a < s.len:
result.buffer = s.buffer

View file

@ -149,7 +149,7 @@ template delImpl() {.dirty.} =
delImplIdx(t, i)
template clearImpl() {.dirty.} =
for i in 0 .. <t.data.len:
for i in 0 ..< t.data.len:
when compiles(t.data[i].hcode): # CountTable records don't contain a hcode
t.data[i].hcode = 0
t.data[i].key = default(type(t.data[i].key))

View file

@ -45,8 +45,25 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
## returns the numer of the processors/cores the machine has.
## Returns 0 if it cannot be detected.
when defined(windows):
var x = getEnv("NUMBER_OF_PROCESSORS")
if x.len > 0: result = parseInt(x.string)
type
SYSTEM_INFO {.final, pure.} = object
u1: int32
dwPageSize: int32
lpMinimumApplicationAddress: pointer
lpMaximumApplicationAddress: pointer
dwActiveProcessorMask: ptr int32
dwNumberOfProcessors: int32
dwProcessorType: int32
dwAllocationGranularity: int32
wProcessorLevel: int16
wProcessorRevision: int16
proc GetSystemInfo(lpSystemInfo: var SYSTEM_INFO) {.stdcall, dynlib: "kernel32", importc: "GetSystemInfo".}
var
si: SYSTEM_INFO
GetSystemInfo(si)
result = si.dwNumberOfProcessors
elif defined(macosx) or defined(bsd):
var
mib: array[0..3, cint]

View file

@ -149,7 +149,7 @@ proc selectWorker(w: ptr Worker; fn: WorkerProc; data: pointer): bool =
proc cleanFlowVars(w: ptr Worker) =
let q = addr(w.q)
acquire(q.lock)
for i in 0 .. <q.len:
for i in 0 ..< q.len:
GC_unref(cast[RootRef](q.data[i]))
#echo "GC_unref"
q.len = 0
@ -401,7 +401,7 @@ proc setup() =
gCpus = p
currentPoolSize = min(p, MaxThreadPoolSize)
readyWorker = addr(workersData[0])
for i in 0.. <currentPoolSize: activateWorkerThread(i)
for i in 0..<currentPoolSize: activateWorkerThread(i)
proc preferSpawn*(): bool =
## Use this proc to determine quickly if a 'spawn' or a direct call is
@ -446,14 +446,24 @@ proc nimSpawn3(fn: WorkerProc; data: pointer) {.compilerProc.} =
# implementation of 'spawn' that is used by the code generator.
while true:
if selectWorker(readyWorker, fn, data): return
for i in 0.. <currentPoolSize:
for i in 0..<currentPoolSize:
if selectWorker(addr(workersData[i]), fn, data): return
# determine what to do, but keep in mind this is expensive too:
# state.calls < maxPoolSize: warmup phase
# (state.calls and 127) == 0: periodic check
if state.calls < maxPoolSize or (state.calls and 127) == 0:
# ensure the call to 'advice' is atomic:
if tryAcquire(stateLock):
if currentPoolSize < minPoolSize:
if not workersData[currentPoolSize].initialized:
activateWorkerThread(currentPoolSize)
let w = addr(workersData[currentPoolSize])
atomicInc currentPoolSize
if selectWorker(w, fn, data):
release(stateLock)
return
case advice(state)
of doNothing: discard
of doCreateThread:
@ -533,7 +543,7 @@ proc sync*() =
var toRelease = 0
while true:
var allReady = true
for i in 0 .. <currentPoolSize:
for i in 0 ..< currentPoolSize:
if not allReady: break
allReady = allReady and workersData[i].ready
if allReady: break

View file

@ -22,7 +22,7 @@ proc createProcType(p, b: NimNode): NimNode {.compileTime.} =
case p.kind
of nnkPar:
for i in 0 .. <p.len:
for i in 0 ..< p.len:
let ident = p[i]
var identDefs = newNimNode(nnkIdentDefs)
case ident.kind
@ -77,7 +77,7 @@ macro `=>`*(p, b: untyped): untyped =
if c[0].kind == nnkIdent and c[0].ident == !"->":
var procTy = createProcType(c[1], c[2])
params[0] = procTy[0][0]
for i in 1 .. <procTy[0].len:
for i in 1 ..< procTy[0].len:
params.add(procTy[0][i])
else:
error("Expected proc type (->) got (" & $c[0].ident & ").")
@ -96,7 +96,7 @@ macro `=>`*(p, b: untyped): untyped =
if p[0].kind == nnkIdent and p[0].ident == !"->":
var procTy = createProcType(p[1], p[2])
params[0] = procTy[0][0]
for i in 1 .. <procTy[0].len:
for i in 1 ..< procTy[0].len:
params.add(procTy[0][i])
else:
error("Expected proc type (->) got (" & $p[0].ident & ").")

View file

@ -883,7 +883,9 @@ proc recvFull(client: HttpClient | AsyncHttpClient, size: int, timeout: int,
let data = client.socket.recv(sizeToRecv, timeout)
else:
let data = await client.socket.recv(sizeToRecv)
if data == "": break # We've been disconnected.
if data == "":
client.close()
break # We've been disconnected.
readLen.inc(data.len)
if keep:
@ -950,6 +952,7 @@ proc parseBody(client: HttpClient | AsyncHttpClient,
if length > 0:
let recvLen = await client.recvFull(length, client.timeout, true)
if recvLen == 0:
client.close()
httpError("Got disconnected while trying to read body.")
if recvLen != length:
httpError("Received length doesn't match expected length. Wanted " &
@ -962,13 +965,20 @@ proc parseBody(client: HttpClient | AsyncHttpClient,
if headers.getOrDefault"Connection" == "close" or httpVersion == "1.0":
while true:
let recvLen = await client.recvFull(4000, client.timeout, true)
if recvLen == 0: break
if recvLen == 0:
client.close()
break
when client is AsyncHttpClient:
client.bodyStream.complete()
else:
client.bodyStream.setPosition(0)
# If the server will close our connection, then no matter the method of
# reading the body, we need to close our socket.
if headers.getOrDefault"Connection" == "close":
client.close()
proc parseResponse(client: HttpClient | AsyncHttpClient,
getBody: bool): Future[Response | AsyncResponse]
{.multisync.} =
@ -984,7 +994,10 @@ proc parseResponse(client: HttpClient | AsyncHttpClient,
line = await client.socket.recvLine(client.timeout)
else:
line = await client.socket.recvLine()
if line == "": break # We've been disconnected.
if line == "":
# We've been disconnected.
client.close()
break
if line == "\c\L":
fullyRead = true
break
@ -1033,7 +1046,8 @@ proc newConnection(client: HttpClient | AsyncHttpClient,
url: Uri) {.multisync.} =
if client.currentURL.hostname != url.hostname or
client.currentURL.scheme != url.scheme or
client.currentURL.port != url.port:
client.currentURL.port != url.port or
(not client.connected):
let isSsl = url.scheme.toLowerAscii() == "https"
if isSsl and not defined(ssl):

View file

@ -113,6 +113,9 @@ proc newHttpHeaders*(keyValuePairs:
new result
result.table = newTable[string, seq[string]](pairs)
proc `$`*(headers: HttpHeaders): string =
return $headers.table
proc clear*(headers: HttpHeaders) =
headers.table.clear()

View file

@ -94,7 +94,7 @@ proc findEnvVar(key: string): int =
if startsWith(environment[i], temp): return i
return -1
proc getEnv*(key: string): TaintedString {.tags: [ReadEnvEffect].} =
proc getEnv*(key: string, default = ""): TaintedString {.tags: [ReadEnvEffect].} =
## Returns the value of the `environment variable`:idx: named `key`.
##
## If the variable does not exist, "" is returned. To distinguish
@ -108,7 +108,7 @@ proc getEnv*(key: string): TaintedString {.tags: [ReadEnvEffect].} =
return TaintedString(substr(environment[i], find(environment[i], '=')+1))
else:
var env = c_getenv(key)
if env == nil: return TaintedString("")
if env == nil: return TaintedString(default)
result = TaintedString($env)
proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} =

View file

@ -37,15 +37,15 @@
## Retrieving the value of a JSON node can then be achieved using one of the
## helper procedures, which include:
##
## * ``getNum``
## * ``getFNum``
## * ``getInt``
## * ``getFloat``
## * ``getStr``
## * ``getBVal``
## * ``getBool``
##
## To retrieve the value of ``"key"`` you can do the following:
##
## .. code-block:: Nim
## doAssert jsonNode["key"].getFNum() == 3.14
## doAssert jsonNode["key"].getFloat() == 3.14
##
## The ``[]`` operator will raise an exception when the specified field does
## not exist. If you wish to avoid this behaviour you can use the ``{}``
@ -681,14 +681,25 @@ proc getStr*(n: JsonNode, default: string = ""): string =
if n.isNil or n.kind != JString: return default
else: return n.str
proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
proc getInt*(n: JsonNode, default: int = 0): int =
## Retrieves the int value of a `JInt JsonNode`.
##
## Returns ``default`` if ``n`` is not a ``JInt``, or if ``n`` is nil.
if n.isNil or n.kind != JInt: return default
else: return int(n.num)
proc getBiggestInt*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
## Retrieves the BiggestInt value of a `JInt JsonNode`.
##
## Returns ``default`` if ``n`` is not a ``JInt``, or if ``n`` is nil.
if n.isNil or n.kind != JInt: return default
else: return n.num
proc getFNum*(n: JsonNode, default: float = 0.0): float =
proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt {.deprecated.} =
## Deprecated - use getInt or getBiggestInt instead
getBiggestInt(n, default)
proc getFloat*(n: JsonNode, default: float = 0.0): float =
## Retrieves the float value of a `JFloat JsonNode`.
##
## Returns ``default`` if ``n`` is not a ``JFloat`` or ``JInt``, or if ``n`` is nil.
@ -698,13 +709,21 @@ proc getFNum*(n: JsonNode, default: float = 0.0): float =
of JInt: return float(n.num)
else: return default
proc getBVal*(n: JsonNode, default: bool = false): bool =
proc getFNum*(n: JsonNode, default: float = 0.0): float {.deprecated.} =
## Deprecated - use getFloat instead
getFloat(n, default)
proc getBool*(n: JsonNode, default: bool = false): bool =
## Retrieves the bool value of a `JBool JsonNode`.
##
## Returns ``default`` if ``n`` is not a ``JBool``, or if ``n`` is nil.
if n.isNil or n.kind != JBool: return default
else: return n.bval
proc getBVal*(n: JsonNode, default: bool = false): bool {.deprecated.} =
## Deprecated - use getBVal instead
getBool(n, default)
proc getFields*(n: JsonNode,
default = initOrderedTable[string, JsonNode](4)):
OrderedTable[string, JsonNode] =
@ -804,13 +823,13 @@ proc toJson(x: NimNode): NimNode {.compiletime.} =
of nnkBracket: # array
if x.len == 0: return newCall(bindSym"newJArray")
result = newNimNode(nnkBracket)
for i in 0 .. <x.len:
for i in 0 ..< x.len:
result.add(toJson(x[i]))
result = newCall(bindSym"%", result)
of nnkTableConstr: # object
if x.len == 0: return newCall(bindSym"newJObject")
result = newNimNode(nnkTableConstr)
for i in 0 .. <x.len:
for i in 0 ..< x.len:
x[i].expectKind nnkExprColonExpr
result.add newTree(nnkExprColonExpr, x[i][0], toJson(x[i][1]))
result = newCall(bindSym"%", result)
@ -1284,7 +1303,7 @@ else:
case getVarType(x)
of JArray:
result = newJArray()
for i in 0 .. <x.len:
for i in 0 ..< x.len:
result.add(x[i].convertObject())
of JObject:
result = newJObject()
@ -1342,7 +1361,7 @@ proc getEnum(node: JsonNode, ast: string, T: typedesc): T =
# TODO: I shouldn't need this proc.
proc convert[T](x: BiggestInt): T = T(x)
verifyJsonKind(node, {JInt}, ast)
return convert[T](node.getNum())
return convert[T](node.getBiggestInt())
else:
verifyJsonKind(node, {JString}, ast)
return parseEnum[T](node.getStr())
@ -1430,7 +1449,7 @@ proc processElseBranch(recCaseNode, elseBranch, jsonNode, kindType,
# We need to build up a list of conditions from each ``of`` branch so that
# we can then negate it to get ``else``.
var cond = newIdentNode("false")
for i in 1 .. <len(recCaseNode):
for i in 1 ..< len(recCaseNode):
if recCaseNode[i].kind == nnkElse:
break
@ -1492,7 +1511,7 @@ proc processObjField(field, jsonNode: NimNode): seq[NimNode] =
exprColonExpr.add(getEnumCall)
# Iterate through each `of` branch.
for i in 1 .. <field.len:
for i in 1 ..< field.len:
case field[i].kind
of nnkOfBranch:
result.add processOfBranch(field[i], jsonNode, kindType, kindJsonNode)
@ -1621,7 +1640,7 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
(
var list: `typeSym` = @[];
verifyJsonKind(`jsonNode`, {JArray}, astToStr(`jsonNode`));
for `forLoopI` in 0 .. <`jsonNode`.len: list.add(`constructorNode`);
for `forLoopI` in 0 ..< `jsonNode`.len: list.add(`constructorNode`);
list
)
of "array":
@ -1635,7 +1654,7 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
(
var list: `typeSym`;
verifyJsonKind(`jsonNode`, {JArray}, astToStr(`jsonNode`));
for `forLoopI` in 0 .. <`jsonNode`.len: list[`forLoopI`] =`constructorNode`;
for `forLoopI` in 0 ..< `jsonNode`.len: list[`forLoopI`] =`constructorNode`;
list
)
@ -1664,7 +1683,7 @@ proc postProcessValue(value: NimNode): NimNode =
result = postProcess(value)
else:
result = value
for i in 0 .. <len(result):
for i in 0 ..< len(result):
result[i] = postProcessValue(result[i])
proc postProcessExprColonExpr(exprColonExpr, resIdent: NimNode): NimNode =

View file

@ -37,6 +37,7 @@ type
lineNumber*: int ## the current line number
sentinel: int
lineStart: int # index of last line start in buffer
offsetBase*: int # use ``offsetBase + bufpos`` to get the offset
refillChars: set[char]
{.deprecated: [TBaseLexer: BaseLexer].}
@ -107,7 +108,8 @@ proc fillBaseLexer(L: var BaseLexer, pos: int): int =
result = pos + 1 # nothing to do
else:
fillBuffer(L)
L.bufpos = 0 # XXX: is this really correct?
L.offsetBase += pos
L.bufpos = 0
result = 0
proc handleCR*(L: var BaseLexer, pos: int): int =
@ -147,6 +149,7 @@ proc open*(L: var BaseLexer, input: Stream, bufLen: int = 8192;
assert(input != nil)
L.input = input
L.bufpos = 0
L.offsetBase = 0
L.bufLen = bufLen
L.refillChars = refillChars
when defined(js):

View file

@ -283,7 +283,7 @@ proc to*[T](data: string): T =
loadAny(newStringStream(data), toAny(result), tab)
when not defined(testing) and isMainModule:
template testit(x: expr) = echo($$to[type(x)]($$x))
template testit(x: untyped) = echo($$to[type(x)]($$x))
var x: array[0..4, array[0..4, string]] = [
["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],

View file

@ -48,7 +48,7 @@ proc validEmailAddress*(s: string): bool {.noSideEffect,
"aero", "jobs", "museum": return true
else: return false
proc parseInt*(s: string, value: var int, validRange: Slice[int]) {.
proc parseInt*(s: string, value: var int, validRange: HSlice[int, int]) {.
noSideEffect, rtl, extern: "nmatchParseInt".} =
## parses `s` into an integer in the range `validRange`. If successful,
## `value` is modified to contain the result. Otherwise no exception is

View file

@ -184,6 +184,8 @@ when not defined(JS):
proc pow*(x, y: float32): float32 {.importc: "powf", header: "<math.h>".}
proc pow*(x, y: float64): float64 {.importc: "pow", header: "<math.h>".}
## computes x to power raised of y.
##
## To compute power between integers, use `^` e.g. 2 ^ 6
proc erf*(x: float32): float32 {.importc: "erff", header: "<math.h>".}
proc erf*(x: float64): float64 {.importc: "erf", header: "<math.h>".}

View file

@ -496,11 +496,12 @@ proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
addr(namelen)) == -1'i32:
raiseOSError(osLastError())
# Cannot use INET6_ADDRSTRLEN here, because it's a C define.
var buf: array[64, char]
result[0] = newString(64)
if inet_ntop(name.sin6_family.cint,
addr name.sin6_addr, buf.cstring, sizeof(buf).int32).isNil:
addr name.sin6_addr, addr result[0][0], (result[0].len+1).int32).isNil:
raiseOSError(osLastError())
result = ($buf, Port(nativesockets.ntohs(name.sin6_port)))
setLen(result[0], result[0].cstring.len)
result[1] = Port(nativesockets.ntohs(name.sin6_port))
else:
raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr")
@ -532,11 +533,12 @@ proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
addr(namelen)) == -1'i32:
raiseOSError(osLastError())
# Cannot use INET6_ADDRSTRLEN here, because it's a C define.
var buf: array[64, char]
result[0] = newString(64)
if inet_ntop(name.sin6_family.cint,
addr name.sin6_addr, buf.cstring, sizeof(buf).int32).isNil:
addr name.sin6_addr, addr result[0][0], (result[0].len+1).int32).isNil:
raiseOSError(osLastError())
result = ($buf, Port(nativesockets.ntohs(name.sin6_port)))
setLen(result[0], result[0].cstring.len)
result[1] = Port(nativesockets.ntohs(name.sin6_port))
else:
raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr")

View file

@ -857,13 +857,16 @@ proc close*(socket: Socket) =
# shutdown i.e not wait for the peers "close notify" alert with a second
# call to SSLShutdown
let res = SSLShutdown(socket.sslHandle)
SSLFree(socket.sslHandle)
socket.sslHandle = nil
if res == 0:
discard
elif res != 1:
socketError(socket, res)
finally:
when defineSsl:
if socket.isSSL and socket.sslHandle != nil:
SSLFree(socket.sslHandle)
socket.sslHandle = nil
socket.fd.close()
proc toCInt*(opt: SOBool): cint =

View file

@ -153,7 +153,10 @@ proc `==`*(a, b: Option): bool =
(a.has and b.has and a.val == b.val) or (not a.has and not b.has)
proc `$`*[T](self: Option[T]): string =
## Returns the contents of this option or `otherwise` if the option is none.
## Get the string representation of this option. If the option has a value,
## the result will be `Some(x)` where `x` is the string representation of the contained value.
## If the option does not have a value, the result will be `None[T]` where `T` is the name of
## the type contained in the option.
if self.has:
"Some(" & $self.val & ")"
else:

View file

@ -790,7 +790,10 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path:
while true:
var x = readdir(d)
if x == nil: break
var y = $x.d_name
when defined(nimNoArrayToCstringConversion):
var y = $cstring(addr x.d_name)
else:
var y = $x.d_name.cstring
if y != "." and y != "..":
var s: Stat
if not relative:

View file

@ -280,7 +280,7 @@ proc execProcesses*(cmds: openArray[string],
## executes the commands `cmds` in parallel. Creates `n` processes
## that execute in parallel. The highest return value of all processes
## is returned. Runs `beforeRunEvent` before running each command.
when defined(posix):
when false:
# poParentStreams causes problems on Posix, so we simply disable it:
var options = options - {poParentStreams}
@ -617,6 +617,7 @@ when defined(Windows) and not defined(useNimRtl):
var res: int32
discard getExitCodeProcess(p.fProcessHandle, res)
result = res
p.exitStatus = res
discard closeHandle(p.fProcessHandle)
proc peekExitCode(p: Process): int =
@ -625,6 +626,7 @@ when defined(Windows) and not defined(useNimRtl):
else:
var res: int32
discard getExitCodeProcess(p.fProcessHandle, res)
if res == 0: return p.exitStatus
return res
proc inputStream(p: Process): Stream =

View file

@ -72,7 +72,10 @@ proc raiseEInvalidCsv(filename: string, line, col: int,
msg: string) {.noreturn.} =
var e: ref CsvError
new(e)
e.msg = filename & "(" & $line & ", " & $col & ") Error: " & msg
if filename.len == 0:
e.msg = "Error: " & msg
else:
e.msg = filename & "(" & $line & ", " & $col & ") Error: " & msg
raise e
proc error(my: CsvParser, pos: int, msg: string) =

View file

@ -35,7 +35,7 @@ type
cmd: seq[string]
pos: int
remainingShortOptions: string
kind*: CmdLineKind ## the dected command line token
kind*: CmdLineKind ## the detected command line token
key*, val*: TaintedString ## key and value pair; ``key`` is the option
## or the argument, ``value`` is not "" if
## the option was given a value

View file

@ -8,6 +8,8 @@
#
## This module contains helpers for parsing tokens, numbers, identifiers, etc.
##
## To unpack raw bytes look at the `streams <streams.html>`_ module.
{.deadCodeElim: on.}

View file

@ -93,7 +93,7 @@ proc random*(max: float): float {.benign.} =
let u = (0x3FFu64 shl 52u64) or (x shr 12u64)
result = (cast[float](u) - 1.0) * max
proc random*[T](x: Slice[T]): T =
proc random*[T](x: HSlice[T, T]): T =
## For a slice `a .. b` returns a value in the range `a .. b-1`.
result = T(random(x.b - x.a)) + x.a

View file

@ -39,47 +39,13 @@ proc toRational*[T:SomeInteger](x: T): Rational[T] =
result.num = x
result.den = 1
proc toRationalSub(x: float, n: int): Rational[int] =
var
a = 0'i64
b, c, d = 1'i64
result = 0 // 1 # rational 0
while b <= n and d <= n:
let ac = (a+c)
let bd = (b+d)
# scale by 1000 so not overflow for high precision
let mediant = (ac.float/1000) / (bd.float/1000)
if x == mediant:
if bd <= n:
result.num = ac.int
result.den = bd.int
return result
elif d > b:
result.num = c.int
result.den = d.int
return result
else:
result.num = a.int
result.den = b.int
return result
elif x > mediant:
a = ac
b = bd
else:
c = ac
d = bd
if (b > n):
return initRational(c.int, d.int)
return initRational(a.int, b.int)
proc toRational*(x: float, n: int = high(int)): Rational[int] =
## Calculate the best rational numerator and denominator
proc toRational*(x: float, n: int = high(int32)): Rational[int] =
## Calculates the best rational numerator and denominator
## that approximates to `x`, where the denominator is
## smaller than `n` (default is the largest possible
## int to give maximum resolution)
## int to give maximum resolution).
##
## The algorithm is based on the Farey sequence named
## after John Farey
## The algorithm is based on the theory of continued fractions.
##
## .. code-block:: Nim
## import math, rationals
@ -88,13 +54,24 @@ proc toRational*(x: float, n: int = high(int)): Rational[int] =
## let x = toRational(PI, t)
## let newPI = x.num / x.den
## echo x, " ", newPI, " error: ", PI - newPI, " ", t
if x > 1:
result = toRationalSub(1.0/x, n)
swap(result.num, result.den)
elif x == 1.0:
result = 1 // 1
else:
result = toRationalSub(x, n)
# David Eppstein / UC Irvine / 8 Aug 1993
# With corrections from Arno Formella, May 2008
var
m11, m22 = 1
m12, m21 = 0
ai = int(x)
x = x
while m21 * ai + m22 <= n:
swap m12, m11
swap m22, m21
m11 = m12 * ai + m11
m21 = m22 * ai + m21
if x == float(ai): break # division by zero
x = 1/(x - float(ai))
if x > float(high(int32)): break # representation failure
ai = int(x)
result = m11 // m21
proc toFloat*[T](x: Rational[T]): float =
## Convert a rational number `x` to a float.
@ -346,7 +323,14 @@ when isMainModule:
assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7
assert toInt(z) == 0
assert toRational(0.98765432) == 12345679 // 12500000
assert toRational(0.1, 1000000) == 1 // 10
assert toRational(0.9, 1000000) == 9 // 10
#assert toRational(PI) == 80143857 // 25510582
assert toRational(0.98765432) == 2111111029 // 2137499919
assert toRational(PI) == 817696623 // 260280919
assert toRational(0.1) == 1 // 10
assert toRational(0.9) == 9 // 10
assert toRational(0.0) == 0 // 1
assert toRational(-0.25) == 1 // -4
assert toRational(3.2) == 16 // 5
assert toRational(0.33) == 33 // 100
assert toRational(0.22) == 11 // 50
assert toRational(10.0) == 10 // 1

View file

@ -181,7 +181,7 @@ proc `$`*(self: SecureHash): string =
result.add(toHex(int(v), 2))
proc parseSecureHash*(hash: string): SecureHash =
for i in 0.. <Sha1DigestSize:
for i in 0 ..< Sha1DigestSize:
Sha1Digest(result)[i] = uint8(parseHexInt(hash[i*2] & hash[i*2 + 1]))
proc `==`*(a, b: SecureHash): bool =

View file

@ -162,7 +162,7 @@ elif defined(linux):
return @[]
raiseOSError(err)
if evNum == 0: return @[]
for i in 0 .. <evNum:
for i in 0 ..< evNum:
let fd = s.events[i].data.fd.SocketHandle
var evSet: set[Event] = {}
@ -253,7 +253,7 @@ elif defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd):
return @[]
raiseOSError(err)
if evNum == 0: return @[]
for i in 0 .. <evNum:
for i in 0 ..< evNum:
let fd = s.events[i].ident.SocketHandle
var evSet: set[Event] = {}

View file

@ -224,6 +224,38 @@ proc peekInt64*(s: Stream): int64 =
## peeks an int64 from the stream `s`. Raises `EIO` if an error occurred.
peek(s, result)
proc readUint8*(s: Stream): uint8 =
## reads an uint8 from the stream `s`. Raises `EIO` if an error occurred.
read(s, result)
proc peekUint8*(s: Stream): uint8 =
## peeks an uint8 from the stream `s`. Raises `EIO` if an error occurred.
peek(s, result)
proc readUint16*(s: Stream): uint16 =
## reads an uint16 from the stream `s`. Raises `EIO` if an error occurred.
read(s, result)
proc peekUint16*(s: Stream): uint16 =
## peeks an uint16 from the stream `s`. Raises `EIO` if an error occurred.
peek(s, result)
proc readUint32*(s: Stream): uint32 =
## reads an uint32 from the stream `s`. Raises `EIO` if an error occurred.
read(s, result)
proc peekUint32*(s: Stream): uint32 =
## peeks an uint32 from the stream `s`. Raises `EIO` if an error occurred.
peek(s, result)
proc readUint64*(s: Stream): uint64 =
## reads an uint64 from the stream `s`. Raises `EIO` if an error occurred.
read(s, result)
proc peekUint64*(s: Stream): uint64 =
## peeks an uint64 from the stream `s`. Raises `EIO` if an error occurred.
peek(s, result)
proc readFloat32*(s: Stream): float32 =
## reads a float32 from the stream `s`. Raises `EIO` if an error occurred.
read(s, result)

View file

@ -253,7 +253,7 @@ is performed.
for r in collectLinks(body):
echo r
In this example both macros are combined seamlessly in order to maximise
In this example both macros are combined seamlessly in order to maximise
efficiency and perform different checks.
.. code-block:: nim
@ -308,7 +308,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
## See top level documentation of his module of how ``scanf`` works.
template matchBind(parser) {.dirty.} =
var resLen = genSym(nskLet, "resLen")
conds.add newLetStmt(resLen, newCall(bindSym(parser), input, results[i], idx))
conds.add newLetStmt(resLen, newCall(bindSym(parser), inp, results[i], idx))
conds.add resLen.notZero
conds.add resLen
@ -316,7 +316,8 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
var p = 0
var idx = genSym(nskVar, "idx")
var res = genSym(nskVar, "res")
result = newTree(nnkStmtListExpr, newVarStmt(idx, newLit 0), newVarStmt(res, newLit false))
let inp = genSym(nskLet, "inp")
result = newTree(nnkStmtListExpr, newLetStmt(inp, input), newVarStmt(idx, newLit 0), newVarStmt(res, newLit false))
var conds = newTree(nnkStmtList)
var fullMatch = false
while p < pattern.len:
@ -325,7 +326,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
case pattern[p]
of '$':
var resLen = genSym(nskLet, "resLen")
conds.add newLetStmt(resLen, newCall(bindSym"skip", input, newLit($pattern[p]), idx))
conds.add newLetStmt(resLen, newCall(bindSym"skip", inp, newLit($pattern[p]), idx))
conds.add resLen.notZero
conds.add resLen
of 'w':
@ -347,7 +348,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
error("no float var given for $f")
inc i
of 's':
conds.add newCall(bindSym"inc", idx, newCall(bindSym"skipWhitespace", input, idx))
conds.add newCall(bindSym"inc", idx, newCall(bindSym"skipWhitespace", inp, idx))
conds.add newEmptyNode()
conds.add newEmptyNode()
of '.':
@ -364,7 +365,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
token.add pattern[q]
inc q
var resLen = genSym(nskLet, "resLen")
conds.add newLetStmt(resLen, newCall(bindSym"parseUntil", input, results[i], newLit(token), idx))
conds.add newLetStmt(resLen, newCall(bindSym"parseUntil", inp, results[i], newLit(token), idx))
conds.add newCall(bindSym"!=", resLen, newLit min)
conds.add resLen
else:
@ -386,7 +387,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
let expr = pattern.substr(start, p-1)
if i < results.len:
var resLen = genSym(nskLet, "resLen")
conds.add newLetStmt(resLen, buildUserCall(expr, input, results[i], idx))
conds.add newLetStmt(resLen, buildUserCall(expr, inp, results[i], idx))
conds.add newCall(bindSym"!=", resLen, newLit 0)
conds.add resLen
else:
@ -406,7 +407,7 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
else: discard
inc p
let expr = pattern.substr(start, p-1)
conds.add newCall(bindSym"inc", idx, buildUserCall(expr, input, idx))
conds.add newCall(bindSym"inc", idx, buildUserCall(expr, inp, idx))
conds.add newEmptyNode()
conds.add newEmptyNode()
else: error("invalid format string")
@ -417,13 +418,13 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
token.add pattern[p]
inc p
var resLen = genSym(nskLet, "resLen")
conds.add newLetStmt(resLen, newCall(bindSym"skip", input, newLit(token), idx))
conds.add newLetStmt(resLen, newCall(bindSym"skip", inp, newLit(token), idx))
conds.add resLen.notZero
conds.add resLen
result.add conditionsToIfChain(conds, idx, res, 0)
if fullMatch:
result.add newCall(bindSym"and", res,
newCall(bindSym">=", idx, newCall(bindSym"len", input)))
newCall(bindSym">=", idx, newCall(bindSym"len", inp)))
else:
result.add res
@ -684,3 +685,14 @@ when isMainModule:
"NimMain c:/users/anwender/projects/nim/lib/system.nim:2613",
"main c:/users/anwender/projects/nim/lib/system.nim:2620"]
doAssert parseGDB(gdbOut) == result
# bug #6487
var count = 0
proc test(): string =
inc count
result = ",123123"
var a: int
discard scanf(test(), ",$i", a)
doAssert count == 1

View file

@ -138,7 +138,8 @@ proc isAlphaNumeric*(s: string): bool {.noSideEffect, procvar,
result = true
for c in s:
result = c.isAlphaNumeric() and result
if not c.isAlphaNumeric():
return false
proc isDigit*(s: string): bool {.noSideEffect, procvar,
rtl, extern: "nsuIsDigitStr".}=
@ -153,7 +154,8 @@ proc isDigit*(s: string): bool {.noSideEffect, procvar,
result = true
for c in s:
result = c.isDigit() and result
if not c.isDigit():
return false
proc isSpaceAscii*(s: string): bool {.noSideEffect, procvar,
rtl, extern: "nsuIsSpaceAsciiStr".}=
@ -1062,8 +1064,8 @@ proc align*(s: string, count: Natural, padding = ' '): string {.
##
## `padding` characters (by default spaces) are added before `s` resulting in
## right alignment. If ``s.len >= count``, no spaces are added and `s` is
## returned unchanged. If you need to left align a string use the `repeatChar
## proc <#repeatChar>`_. Example:
## returned unchanged. If you need to left align a string use the `alignLeft
## proc <#alignLeft>`_. Example:
##
## .. code-block:: nim
## assert align("abc", 4) == " abc"
@ -1078,6 +1080,28 @@ proc align*(s: string, count: Natural, padding = ' '): string {.
else:
result = s
proc alignLeft*(s: string, count: Natural, padding = ' '): string {.noSideEffect.} =
## Left-Aligns a string `s` with `padding`, so that it is of length `count`.
##
## `padding` characters (by default spaces) are added after `s` resulting in
## left alignment. If ``s.len >= count``, no spaces are added and `s` is
## returned unchanged. If you need to right align a string use the `align
## proc <#align>`_. Example:
##
## .. code-block:: nim
## assert alignLeft("abc", 4) == "abc "
## assert alignLeft("a", 0) == "a"
## assert alignLeft("1232", 6) == "1232 "
## assert alignLeft("1232", 6, '#') == "1232##"
if s.len < count:
result = newString(count)
if s.len > 0:
result[0 .. (s.len - 1)] = s
for i in s.len ..< count:
result[i] = padding
else:
result = s
iterator tokenize*(s: string, seps: set[char] = Whitespace): tuple[
token: string, isSep: bool] =
## Tokenizes the string `s` into substrings.
@ -1175,7 +1199,7 @@ proc unindent*(s: string, count: Natural, padding: string = " "): string
var indentCount = 0
for j in 0..<count.int:
indentCount.inc
if line[j .. j + <padding.len] != padding:
if line[j .. j + padding.len-1] != padding:
indentCount = j
break
result.add(line[indentCount*padding.len .. ^1])
@ -1306,18 +1330,36 @@ proc join*[T: not string](a: openArray[T], sep: string = ""): string {.
add(result, $x)
type
SkipTable = array[char, int]
SkipTable* = array[char, int]
{.push profiler: off.}
proc preprocessSub(sub: string, a: var SkipTable) =
var m = len(sub)
for i in 0..0xff: a[chr(i)] = m+1
for i in 0..m-1: a[sub[i]] = m-i
{.pop.}
proc initSkipTable*(a: var SkipTable, sub: string)
{.noSideEffect, rtl, extern: "nsuInitSkipTable".} =
## Preprocess table `a` for `sub`.
let m = len(sub)
let m1 = m + 1
var i = 0
while i <= 0xff-7:
a[chr(i + 0)] = m1
a[chr(i + 1)] = m1
a[chr(i + 2)] = m1
a[chr(i + 3)] = m1
a[chr(i + 4)] = m1
a[chr(i + 5)] = m1
a[chr(i + 6)] = m1
a[chr(i + 7)] = m1
i += 8
proc findAux(s, sub: string, start, last: int, a: SkipTable): int =
# Fast "quick search" algorithm:
var
for i in 0..m-1:
a[sub[i]] = m-i
proc find*(a: SkipTable, s, sub: string, start: Natural = 0, last: Natural = 0): int
{.noSideEffect, rtl, extern: "nsuFindStrA".} =
## Searches for `sub` in `s` inside range `start`..`last` using preprocessed table `a`.
## If `last` is unspecified, it defaults to `s.high`.
##
## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
let
last = if last==0: s.high else: last
m = len(sub)
n = last + 1
# search:
@ -1337,17 +1379,6 @@ when not (defined(js) or defined(nimdoc) or defined(nimscript)):
else:
const hasCStringBuiltin = false
proc find*(s, sub: string, start: Natural = 0, last: Natural = 0): int {.noSideEffect,
rtl, extern: "nsuFindStr".} =
## Searches for `sub` in `s` inside range `start`..`last`.
## If `last` is unspecified, it defaults to `s.high`.
##
## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
var a {.noinit.}: SkipTable
let last = if last==0: s.high else: last
preprocessSub(sub, a)
result = findAux(s, sub, start, last, a)
proc find*(s: string, sub: char, start: Natural = 0, last: Natural = 0): int {.noSideEffect,
rtl, extern: "nsuFindChar".} =
## Searches for `sub` in `s` inside range `start`..`last`.
@ -1366,9 +1397,24 @@ proc find*(s: string, sub: char, start: Natural = 0, last: Natural = 0): int {.n
else:
for i in start..last:
if sub == s[i]: return i
return -1
proc find*(s, sub: string, start: Natural = 0, last: Natural = 0): int {.noSideEffect,
rtl, extern: "nsuFindStr".} =
## Searches for `sub` in `s` inside range `start`..`last`.
## If `last` is unspecified, it defaults to `s.high`.
##
## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
if sub.len > s.len:
return -1
if sub.len == 1:
return find(s, sub[0], start, last)
var a {.noinit.}: SkipTable
initSkipTable(a, sub)
result = find(a, s, sub, start, last)
proc find*(s: string, chars: set[char], start: Natural = 0, last: Natural = 0): int {.noSideEffect,
rtl, extern: "nsuFindCharSet".} =
## Searches for `chars` in `s` inside range `start`..`last`.
@ -1500,11 +1546,11 @@ proc replace*(s, sub: string, by = ""): string {.noSideEffect,
## Replaces `sub` in `s` by the string `by`.
var a {.noinit.}: SkipTable
result = ""
preprocessSub(sub, a)
initSkipTable(a, sub)
let last = s.high
var i = 0
while true:
var j = findAux(s, sub, i, last, a)
var j = find(a, s, sub, i, last)
if j < 0: break
add result, substr(s, i, j - 1)
add result, by
@ -1534,11 +1580,11 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'}
var a {.noinit.}: SkipTable
result = ""
preprocessSub(sub, a)
initSkipTable(a, sub)
var i = 0
let last = s.high
while true:
var j = findAux(s, sub, i, last, a)
var j = find(a, s, sub, i, last)
if j < 0: break
# word boundary?
if (j == 0 or s[j-1] notin wordChars) and
@ -1890,17 +1936,32 @@ proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault,
frmtstr[3] = '*'
frmtstr[4] = floatFormatToChar[format]
frmtstr[5] = '\0'
L = c_sprintf(buf, frmtstr, precision, f)
when defined(nimNoArrayToCstringConversion):
L = c_sprintf(addr buf, addr frmtstr, precision, f)
else:
L = c_sprintf(buf, frmtstr, precision, f)
else:
frmtstr[1] = floatFormatToChar[format]
frmtstr[2] = '\0'
L = c_sprintf(buf, frmtstr, f)
when defined(nimNoArrayToCstringConversion):
L = c_sprintf(addr buf, addr frmtstr, f)
else:
L = c_sprintf(buf, frmtstr, f)
result = newString(L)
for i in 0 ..< L:
# Depending on the locale either dot or comma is produced,
# but nothing else is possible:
if buf[i] in {'.', ','}: result[i] = decimalsep
else: result[i] = buf[i]
when defined(vcc):
# VS pre 2015 violates the C standard: "The exponent always contains at
# least two digits, and only as many more digits as necessary to
# represent the exponent." [C11 §7.21.6.1]
# The following post-processing fixes this behavior.
if result.len > 4 and result[^4] == '+' and result[^3] == '0':
result[^3] = result[^2]
result[^2] = result[^1]
result.setLen(result.len - 1)
proc formatFloat*(f: float, format: FloatFormatMode = ffDefault,
precision: range[0..32] = 16; decimalSep = '.'): string {.
@ -2169,11 +2230,26 @@ proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.
if idx >% a.high: invalidFormatString()
add s, a[idx]
of '{':
var j = i+1
while formatstr[j] notin {'\0', '}'}: inc(j)
var x = findNormalized(substr(formatstr, i+2, j-1), a)
if x >= 0 and x < high(a): add s, a[x+1]
else: invalidFormatString()
var j = i+2
var k = 0
var negative = formatstr[j] == '-'
if negative: inc j
var isNumber = 0
while formatstr[j] notin {'\0', '}'}:
if formatstr[j] in Digits:
k = k * 10 + ord(formatstr[j]) - ord('0')
if isNumber == 0: isNumber = 1
else:
isNumber = -1
inc(j)
if isNumber == 1:
let idx = if not negative: k-1 else: a.len-k
if idx >% a.high: invalidFormatString()
add s, a[idx]
else:
var x = findNormalized(substr(formatstr, i+2, j-1), a)
if x >= 0 and x < high(a): add s, a[x+1]
else: invalidFormatString()
i = j+1
of 'a'..'z', 'A'..'Z', '\128'..'\255', '_':
var j = i+1
@ -2250,60 +2326,104 @@ proc format*(formatstr: string, a: varargs[string, `$`]): string {.noSideEffect,
proc removeSuffix*(s: var string, chars: set[char] = Newlines) {.
rtl, extern: "nsuRemoveSuffixCharSet".} =
## Removes the first matching character from the string (in-place) given a
## set of characters. If the set of characters is only equal to `Newlines`
## then it will remove both the newline and return feed.
## Removes all characters from `chars` from the end of the string `s`
## (in-place).
##
## .. code-block:: nim
## var
## userInput = "Hello World!\r\n"
## otherInput = "Hello!?!"
## var userInput = "Hello World!*~\r\n"
## userInput.removeSuffix
## userInput == "Hello World!"
## userInput.removeSuffix({'!', '?'})
## userInput == "Hello World"
## doAssert userInput == "Hello World!*~"
## userInput.removeSuffix({'~', '*'})
## doAssert userInput == "Hello World!"
##
## var otherInput = "Hello!?!"
## otherInput.removeSuffix({'!', '?'})
## otherInput == "Hello!?"
## doAssert otherInput == "Hello"
if s.len == 0: return
var last = len(s) - 1
if chars == Newlines:
if s[last] == '\10':
last -= 1
if s[last] == '\13':
last -= 1
else:
if s[last] in chars:
last -= 1
var last = s.high
while last > -1 and s[last] in chars: last -= 1
s.setLen(last + 1)
proc removeSuffix*(s: var string, c: char) {.
rtl, extern: "nsuRemoveSuffixChar".} =
## Removes a single character (in-place) from a string.
## Removes all occurrences of a single character (in-place) from the end
## of a string.
##
## .. code-block:: nim
## var
## table = "users"
## var table = "users"
## table.removeSuffix('s')
## table == "user"
## doAssert table == "user"
##
## var dots = "Trailing dots......."
## dots.removeSuffix('.')
## doAssert dots == "Trailing dots"
removeSuffix(s, chars = {c})
proc removeSuffix*(s: var string, suffix: string) {.
rtl, extern: "nsuRemoveSuffixString".} =
## Remove the first matching suffix (in-place) from a string.
##
## .. code-block:: nim
## var
## answers = "yeses"
## var answers = "yeses"
## answers.removeSuffix("es")
## answers == "yes"
## doAssert answers == "yes"
var newLen = s.len
if s.endsWith(suffix):
newLen -= len(suffix)
s.setLen(newLen)
proc removePrefix*(s: var string, chars: set[char] = Newlines) {.
rtl, extern: "nsuRemovePrefixCharSet".} =
## Removes all characters from `chars` from the start of the string `s`
## (in-place).
##
## .. code-block:: nim
## var userInput = "\r\n*~Hello World!"
## userInput.removePrefix
## doAssert userInput == "*~Hello World!"
## userInput.removePrefix({'~', '*'})
## doAssert userInput == "Hello World!"
##
## var otherInput = "?!?Hello!?!"
## otherInput.removePrefix({'!', '?'})
## doAssert otherInput == "Hello!?!"
var start = 0
while start < s.len and s[start] in chars: start += 1
if start > 0: s.delete(0, start - 1)
proc removePrefix*(s: var string, c: char) {.
rtl, extern: "nsuRemovePrefixChar".} =
## Removes all occurrences of a single character (in-place) from the start
## of a string.
##
## .. code-block:: nim
## var ident = "pControl"
## ident.removePrefix('p')
## doAssert ident == "Control"
removePrefix(s, chars = {c})
proc removePrefix*(s: var string, prefix: string) {.
rtl, extern: "nsuRemovePrefixString".} =
## Remove the first matching prefix (in-place) from a string.
##
## .. code-block:: nim
## var answers = "yesyes"
## answers.removePrefix("yes")
## doAssert answers == "yes"
if s.startsWith(prefix):
s.delete(0, prefix.len - 1)
when isMainModule:
doAssert align("abc", 4) == " abc"
doAssert align("a", 0) == "a"
doAssert align("1232", 6) == " 1232"
doAssert align("1232", 6, '#') == "##1232"
doAssert alignLeft("abc", 4) == "abc "
doAssert alignLeft("a", 0) == "a"
doAssert alignLeft("1232", 6) == "1232 "
doAssert alignLeft("1232", 6, '#') == "1232##"
let
inp = """ this is a long text -- muchlongerthan10chars and here
it goes"""
@ -2313,8 +2433,12 @@ when isMainModule:
doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001"
doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in
["1,0e-11", "1,0e-011"]
# bug #6589
doAssert formatFloat(123.456, ffScientific, precision=0) in
["1.234560e+02", "1.234560e+002"]
doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb"
block: # formatSize tests
doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB"

View file

@ -77,20 +77,17 @@ when defined(posix) and not defined(JS):
when not defined(freebsd) and not defined(netbsd) and not defined(openbsd):
var timezone {.importc, header: "<time.h>".}: int
proc tzset(): void {.importc, header: "<time.h>".}
tzset()
elif defined(windows):
import winlean
when defined(vcc) or defined(bcc) or defined(icl):
# newest version of Visual C++ defines time_t to be of 64 bits
type TimeImpl {.importc: "time_t", header: "<time.h>".} = int64
# visual c's c runtime exposes these under a different name
var
timezone {.importc: "_timezone", header: "<time.h>".}: int
else:
type TimeImpl {.importc: "time_t", header: "<time.h>".} = int
var
timezone {.importc, header: "<time.h>".}: int
# newest version of Visual C++ defines time_t to be of 64 bits
type TimeImpl {.importc: "time_t", header: "<time.h>".} = int64
# visual c's c runtime exposes these under a different name
var
timezone {.importc: "_timezone", header: "<time.h>".}: int
type
Time* = distinct TimeImpl
@ -1028,7 +1025,7 @@ proc countLeapYears*(yearSpan: int): int =
## counts the number of leap years up to January 1st of a given year.
## Keep in mind that if specified year is a leap year, the leap day
## has not happened before January 1st of that year.
(((yearSpan - 1) / 4) - ((yearSpan - 1) / 100) + ((yearSpan - 1) / 400)).int
(yearSpan - 1) div 4 - (yearSpan - 1) div 100 + (yearSpan - 1) div 400
proc countDays*(yearSpan: int): int =
## Returns the number of days spanned by a given number of years.

View file

@ -31,6 +31,10 @@ proc name*(t: typedesc): string {.magic: "TypeTrait".}
## test(@['A','B'])
## # --> type: seq[char], value: @[A, B]
proc `$`*(t: typedesc): string =
## An alias for `name`.
name(t)
proc arity*(t: typedesc): int {.magic: "TypeTrait".}
## Returns the arity of the given type
@ -49,3 +53,15 @@ proc stripGenericParams*(t: typedesc): typedesc {.magic: "TypeTrait".}
## This trait is similar to `genericHead`, but instead of producing
## error for non-generic types, it will just return them unmodified
proc supportsCopyMem*(t: typedesc): bool {.magic: "TypeTrait".}
## This trait returns true iff the type ``t`` is safe to use for
## `copyMem`:idx:. Other languages name a type like these `blob`:idx:.
when isMainModule:
# echo type(42)
import streams
var ss = newStringStream()
ss.write($type(42)) # needs `$`
ss.setPosition(0)
doAssert ss.readAll() == "int"

View file

@ -285,7 +285,7 @@ proc runeReverseOffset*(s: string, rev:Positive): (int, int) =
proc runeSubStr*(s: string, pos:int, len:int = int.high): string =
## Returns the UTF-8 substring starting at codepoint pos
## with len codepoints. If pos or len is negativ they count from
## with len codepoints. If pos or len is negative they count from
## the end of the string. If len is not given it means the longest
## possible string.
##

View file

@ -312,7 +312,7 @@ proc ensureInitialized() =
if not testsToRun.isValid:
testsToRun.init()
when declared(os):
when declared(paramCount):
# Read tests to run from the command line.
for i in 1 .. paramCount():
testsToRun.incl(paramStr(i))

View file

@ -250,7 +250,7 @@ proc combine*(base: Uri, reference: Uri): Uri =
proc combine*(uris: varargs[Uri]): Uri =
## Combines multiple URIs together.
result = uris[0]
for i in 1 .. <uris.len:
for i in 1 ..< uris.len:
result = combine(result, uris[i])
proc isAbsolute*(uri: Uri): bool =
@ -278,7 +278,9 @@ proc `/`*(x: Uri, path: string): Uri =
result = x
if result.path.len == 0:
result.path = path
if path[0] != '/':
result.path = "/"
result.path.add(path)
return
if result.path[result.path.len-1] == '/':
@ -476,6 +478,11 @@ when isMainModule:
let foo = parseUri("http://example.com") / "/baz"
doAssert foo.path == "/baz"
# bug found on stream 13/10/17
block:
let foo = parseUri("http://localhost:9515") / "status"
doAssert $foo == "http://localhost:9515/status"
# isAbsolute tests
block:
doAssert "www.google.com".parseUri().isAbsolute() == false
@ -515,4 +522,6 @@ when isMainModule:
doAssert "https://example.com/about".parseUri().isAbsolute == true
doAssert "https://example.com/about/staff.html".parseUri().isAbsolute == true
doAssert "https://example.com/about/staff.html?".parseUri().isAbsolute == true
doAssert "https://example.com/about/staff.html?parameters".parseUri().isAbsolute == true
doAssert "https://example.com/about/staff.html?parameters".parseUri().isAbsolute == true
echo("All good!")

View file

@ -275,7 +275,7 @@ proc low*[T](x: T): T {.magic: "Low", noSideEffect.}
proc low*[I, T](x: typeDesc[array[I, T]]): I {.magic: "Low", noSideEffect.}
proc low*(x: cstring): int {.magic: "Low", noSideEffect.}
proc low*(x: string): int {.magic: "Low", noSideEffect.}
## returns the lowest possible index of an array, a sequence, a string or
## returns the lowest possible index of an array, a sequence, a string or
## the lowest possible value of an ordinal value `x`. As a special
## semantic rule, `x` may also be a type identifier.
##
@ -285,6 +285,13 @@ proc low*(x: string): int {.magic: "Low", noSideEffect.}
## low(2) #=> -9223372036854775808
## low(int) #=> -9223372036854775808
proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".}
## use this instead of `=` for a `shallow copy`:idx:. The shallow copy
## only changes the semantics for sequences and strings (and types which
## contain those). Be careful with the changed semantics though! There
## is a reason why the default assignment does a deep copy of sequences
## and strings.
when defined(nimArrIdx):
# :array|openarray|string|seq|cstring|tuple
proc `[]`*[I: Ordinal;T](a: T; i: I): T {.
@ -292,15 +299,21 @@ when defined(nimArrIdx):
proc `[]=`*[I: Ordinal;T,S](a: T; i: I;
x: S) {.noSideEffect, magic: "ArrPut".}
proc `=`*[T](dest: var T; src: T) {.noSideEffect, magic: "Asgn".}
when defined(nimNewRuntime):
proc `=destroy`*[T](x: var T) {.inline, magic: "Asgn".} =
## generic `destructor`:idx: implementation that can be overriden.
discard
proc `=sink`*[T](x: var T; y: T) {.inline, magic: "Asgn".} =
## generic `sink`:idx: implementation that can be overriden.
shallowCopy(x, y)
type
Slice*[T] = object ## builtin slice type
a*, b*: T ## the bounds
HSlice*[T, U] = object ## "heterogenous" slice type
a*: T ## the lower bound (inclusive)
b*: U ## the upper bound (inclusive)
Slice*[T] = HSlice[T, T] ## an alias for ``HSlice[T, T]``
when defined(nimalias):
{.deprecated: [TSlice: Slice].}
proc `..`*[T](a, b: T): Slice[T] {.noSideEffect, inline, magic: "DotDot".} =
proc `..`*[T, U](a: T, b: U): HSlice[T, U] {.noSideEffect, inline, magic: "DotDot".} =
## `slice`:idx: operator that constructs an interval ``[a, b]``, both `a`
## and `b` are inclusive. Slices can also be used in the set constructor
## and in ordinal case statements, but then they are special-cased by the
@ -308,7 +321,7 @@ proc `..`*[T](a, b: T): Slice[T] {.noSideEffect, inline, magic: "DotDot".} =
result.a = a
result.b = b
proc `..`*[T](b: T): Slice[T] {.noSideEffect, inline, magic: "DotDot".} =
proc `..`*[T](b: T): HSlice[int, T] {.noSideEffect, inline, magic: "DotDot".} =
## `slice`:idx: operator that constructs an interval ``[default(T), b]``
result.b = b
@ -638,13 +651,17 @@ proc sizeof*[T](x: T): int {.magic: "SizeOf", noSideEffect.}
when defined(nimtypedescfixed):
proc sizeof*(x: typedesc): int {.magic: "SizeOf", noSideEffect.}
proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.}
proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect, deprecated.}
## unary ``<`` that can be used for nice looking excluding ranges:
##
## .. code-block:: nim
## for i in 0 .. <10: echo i #=> 0 1 2 3 4 5 6 7 8 9
##
## Semantically this is the same as ``pred``.
##
## **Deprecated since version 0.18.0**. For the common excluding range
## write ``0 ..< 10`` instead of ``0 .. < 10`` (look at the spacing).
## For ``<x`` write ``pred(x)``.
proc succ*[T](x: Ordinal[T], y = 1): T {.magic: "Succ", noSideEffect.}
## returns the ``y``-th successor of the value ``x``. ``T`` has to be
@ -1150,7 +1167,7 @@ proc contains*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.}
## is achieved by reversing the parameters for ``contains``; ``in`` then
## passes its arguments in reverse order.
proc contains*[T](s: Slice[T], value: T): bool {.noSideEffect, inline.} =
proc contains*[U, V, W](s: HSlice[U, V], value: W): bool {.noSideEffect, inline.} =
## Checks if `value` is within the range of `s`; returns true iff
## `value >= s.a and value <= s.b`
##
@ -1429,7 +1446,8 @@ when defined(nimdoc):
## <#GC_fullCollect>`_.
##
## The proc ``quit(QuitSuccess)`` is called implicitly when your nim
## program finishes without incident. A raised unhandled exception is
## program finishes without incident for platforms where this is the
## expected behavior. A raised unhandled exception is
## equivalent to calling ``quit(QuitFailure)``.
##
## Note that this is a *runtime* call and using ``quit`` inside a macro won't
@ -1444,7 +1462,7 @@ elif defined(genode):
header: "<base/sleep.h>".}
elif defined(nodejs):
proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit",
proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit",
importc: "process.exit", noreturn.}
else:
@ -1480,13 +1498,6 @@ proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
setLen(x, xl + y.len)
for i in 0..high(y): x[xl+i] = y[i]
proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".}
## use this instead of `=` for a `shallow copy`:idx:. The shallow copy
## only changes the semantics for sequences and strings (and types which
## contain those). Be careful with the changed semantics though! There
## is a reason why the default assignment does a deep copy of sequences
## and strings.
proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
## This is an O(1) operation.
@ -1875,7 +1886,7 @@ proc `$` *(x: float): string {.magic: "FloatToStr", noSideEffect.}
proc `$` *(x: bool): string {.magic: "BoolToStr", noSideEffect.}
## The stringify operator for a boolean argument. Returns `x`
## converted to the string "false" or "true".
#
proc `$` *(x: char): string {.magic: "CharToStr", noSideEffect.}
## The stringify operator for a character argument. Returns `x`
## converted to a string.
@ -2065,6 +2076,9 @@ proc max*[T](x, y: T): T =
if y <= x: x else: y
{.pop.}
proc high*(T: typedesc[SomeReal]): T = Inf
proc low*(T: typedesc[SomeReal]): T = NegInf
proc clamp*[T](x, a, b: T): T =
## limits the value ``x`` within the interval [a, b]
##
@ -2075,7 +2089,7 @@ proc clamp*[T](x, a, b: T): T =
if x > b: return b
return x
proc len*[T: Ordinal](x: Slice[T]): int {.noSideEffect, inline.} =
proc len*[U: Ordinal; V: Ordinal](x: HSlice[U, V]): int {.noSideEffect, inline.} =
## length of ordinal slice, when x.b < x.a returns zero length
##
## .. code-block:: Nim
@ -2143,7 +2157,7 @@ iterator items*(E: typedesc[enum]): E =
for v in low(E)..high(E):
yield v
iterator items*[T](s: Slice[T]): T =
iterator items*[T](s: HSlice[T, T]): T =
## iterates over the slice `s`, yielding each value between `s.a` and `s.b`
## (inclusively).
for x in s.a..s.b:
@ -2437,20 +2451,28 @@ proc `$`*[T: tuple|object](x: T): string =
result.add("...")
result.add(")")
proc collectionToString[T: set | seq](x: T, b, e: string): string =
when x is seq:
if x.isNil: return "nil"
result = b
proc collectionToString[T](x: T, prefix, separator, suffix: string): string =
result = prefix
var firstElement = true
for value in items(x):
if not firstElement: result.add(", ")
if firstElement:
firstElement = false
else:
result.add(separator)
when compiles(value.isNil):
if value.isNil: result.add "nil"
else: result.add($value)
# this branch should not be necessary
if value.isNil:
result.add "nil"
else:
result.add($value)
# prevent temporary string allocation
elif compiles(result.add(value)):
result.add(value)
else:
result.add($value)
firstElement = false
result.add(e)
result.add(suffix)
proc `$`*[T](x: set[T]): string =
## generic ``$`` operator for sets that is lifted from the components
@ -2458,7 +2480,7 @@ proc `$`*[T](x: set[T]): string =
##
## .. code-block:: nim
## ${23, 45} == "{23, 45}"
collectionToString(x, "{", "}")
collectionToString(x, "{", ", ", "}")
proc `$`*[T](x: seq[T]): string =
## generic ``$`` operator for seqs that is lifted from the components
@ -2466,13 +2488,10 @@ proc `$`*[T](x: seq[T]): string =
##
## .. code-block:: nim
## $(@[23, 45]) == "@[23, 45]"
collectionToString(x, "@[", "]")
when false:
# causes bootstrapping to fail as we use array of chars and cstring should
# match better ...
proc `$`*[T, IDX](x: array[IDX, T]): string =
collectionToString(x, "[", "]")
if x.isNil:
"nil"
else:
collectionToString(x, "@[", ", ", "]")
# ----------------- GC interface ---------------------------------------------
@ -2816,7 +2835,7 @@ when not defined(JS): #and not defined(nimscript):
fmRead, ## Open the file for read access only.
fmWrite, ## Open the file for write access only.
## If the file does not exist, it will be
## created.
## created. Existing files will be cleared!
fmReadWrite, ## Open the file for read and write access.
## If the file does not exist, it will be
## created. Existing files will be cleared!
@ -2872,7 +2891,7 @@ when not defined(JS): #and not defined(nimscript):
importc: when defined(bcc): "setmode" else: "_setmode",
header: "<io.h>".}
var
O_BINARY {.importc: "O_BINARY", nodecl.}: cint
O_BINARY {.importc: "_O_BINARY", header:"<fcntl.h>".}: cint
# we use binary mode on Windows:
c_setmode(c_fileno(stdin), O_BINARY)
@ -3329,6 +3348,10 @@ elif defined(JS):
include "system/sysio"
proc `$`*[T, IDX](x: array[IDX, T]): string =
## generic ``$`` operator for arrays that is lifted from the components
collectionToString(x, "[", ", ", "]")
proc quit*(errormsg: string, errorcode = QuitFailure) {.noReturn.} =
## a shorthand for ``echo(errormsg); quit(errorcode)``.
echo(errormsg)
@ -3393,6 +3416,29 @@ proc `/`*(x, y: int): float {.inline, noSideEffect.} =
## integer division that results in a float.
result = toFloat(x) / toFloat(y)
type
BackwardsIndex* = distinct int ## type that is constructed by ``^`` for
## reversed array accesses.
template `^`*(x: int): BackwardsIndex = BackwardsIndex(x)
## builtin `roof`:idx: operator that can be used for convenient array access.
## ``a[^x]`` is a shortcut for ``a[a.len-x]``.
template `..^`*(a, b: untyped): untyped =
## a shortcut for '.. ^' to avoid the common gotcha that a space between
## '..' and '^' is required.
a .. ^b
template `..<`*(a, b: untyped): untyped =
## a shortcut for 'a..pred(b)'.
a .. pred(b)
iterator `..<`*[S,T](a: S, b: T): T =
var i = T(a)
while i < b:
yield i
inc i
template spliceImpl(s, a, L, b: untyped): untyped =
# make room for additional elements or cut:
var shift = b.len - max(0,L) # ignore negative slice size
@ -3406,19 +3452,22 @@ template spliceImpl(s, a, L, b: untyped): untyped =
# cut down:
setLen(s, newLen)
# fill the hole:
for i in 0 .. <b.len: s[a+i] = b[i]
for i in 0 ..< b.len: s[a+i] = b[i]
template `^^`(s, i: untyped): untyped =
(when i is BackwardsIndex: s.len - int(i) else: int(i))
when hasAlloc or defined(nimscript):
proc `[]`*(s: string, x: Slice[int]): string {.inline.} =
proc `[]`*[T, U](s: string, x: HSlice[T, U]): string {.inline.} =
## slice operation for strings.
## returns the inclusive range [s[x.a], s[x.b]]:
##
## .. code-block:: nim
## var s = "abcdef"
## assert s[1..3] == "bcd"
result = s.substr(x.a, x.b)
result = s.substr(s ^^ x.a, s ^^ x.b)
proc `[]=`*(s: var string, x: Slice[int], b: string) =
proc `[]=`*[T, U](s: var string, x: HSlice[T, U], b: string) =
## slice assignment for strings. If
## ``b.len`` is not exactly the number of elements that are referred to
## by `x`, a `splice`:idx: is performed:
@ -3427,75 +3476,74 @@ when hasAlloc or defined(nimscript):
## var s = "abcdef"
## s[1 .. ^2] = "xyz"
## assert s == "axyzf"
var a = x.a
var L = x.b - a + 1
var a = s ^^ x.a
var L = (s ^^ x.b) - a + 1
if L == b.len:
for i in 0 .. <L: s[i+a] = b[i]
for i in 0..<L: s[i+a] = b[i]
else:
spliceImpl(s, a, L, b)
proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[int]): seq[T] =
proc `[]`*[Idx, T, U, V](a: array[Idx, T], x: HSlice[U, V]): seq[T] =
## slice operation for arrays.
## returns the inclusive range [a[x.a], a[x.b]]:
##
## .. code-block:: nim
## var a = [1,2,3,4]
## assert a[0..2] == @[1,2,3]
when low(a) < 0:
{.error: "Slicing for arrays with negative indices is unsupported.".}
var L = x.b - x.a + 1
let xa = a ^^ x.a
let L = (a ^^ x.b) - xa + 1
result = newSeq[T](L)
for i in 0.. <L: result[i] = a[i + x.a]
for i in 0..<L: result[i] = a[Idx(i + xa + int low(a))]
proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[int], b: openArray[T]) =
proc `[]=`*[Idx, T, U, V](a: var array[Idx, T], x: HSlice[U, V], b: openArray[T]) =
## slice assignment for arrays.
when low(a) < 0:
{.error: "Slicing for arrays with negative indices is unsupported.".}
var L = x.b - x.a + 1
let xa = a ^^ x.a
let L = (a ^^ x.b) - xa + 1
if L == b.len:
for i in 0 .. <L: a[i+x.a] = b[i]
for i in 0..<L: a[Idx(i + xa + int low(a))] = b[i]
else:
sysFatal(RangeError, "different lengths for slice assignment")
proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[Idx]): seq[T] =
## slice operation for arrays.
var L = ord(x.b) - ord(x.a) + 1
newSeq(result, L)
for i in 0.. <L:
result[i] = a[Idx(ord(x.a) + i)]
proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[Idx], b: openArray[T]) =
## slice assignment for arrays.
var L = ord(x.b) - ord(x.a) + 1
if L == b.len:
for i in 0 .. <L:
a[Idx(ord(x.a) + i)] = b[i]
else:
sysFatal(RangeError, "different lengths for slice assignment")
proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] =
proc `[]`*[T, U, V](s: openArray[T], x: HSlice[U, V]): seq[T] =
## slice operation for sequences.
## returns the inclusive range [s[x.a], s[x.b]]:
##
## .. code-block:: nim
## var s = @[1,2,3,4]
## assert s[0..2] == @[1,2,3]
var a = x.a
var L = x.b - a + 1
let a = s ^^ x.a
let L = (s ^^ x.b) - a + 1
newSeq(result, L)
for i in 0.. <L: result[i] = s[i + a]
for i in 0 ..< L: result[i] = s[i + a]
proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) =
proc `[]=`*[T, U, V](s: var seq[T], x: HSlice[U, V], b: openArray[T]) =
## slice assignment for sequences. If
## ``b.len`` is not exactly the number of elements that are referred to
## by `x`, a `splice`:idx: is performed.
var a = x.a
var L = x.b - a + 1
let a = s ^^ x.a
let L = (s ^^ x.b) - a + 1
if L == b.len:
for i in 0 .. <L: s[i+a] = b[i]
for i in 0 ..< L: s[i+a] = b[i]
else:
spliceImpl(s, a, L, b)
proc `[]`*[T](s: openArray[T]; i: BackwardsIndex): T {.inline.} = s[s.len - int(i)]
proc `[]`*[Idx, T](a: array[Idx, T]; i: BackwardsIndex): T {.inline.} =
a[Idx(a.len - int(i) + int low(a))]
proc `[]`*(s: string; i: BackwardsIndex): char {.inline.} = s[s.len - int(i)]
proc `[]`*[T](s: var openArray[T]; i: BackwardsIndex): var T {.inline.} =
s[s.len - int(i)]
proc `[]`*[Idx, T](a: var array[Idx, T]; i: BackwardsIndex): var T {.inline.} =
a[Idx(a.len - int(i) + int low(a))]
proc `[]=`*[T](s: var openArray[T]; i: BackwardsIndex; x: T) {.inline.} =
s[s.len - int(i)] = x
proc `[]=`*[Idx, T](a: var array[Idx, T]; i: BackwardsIndex; x: T) {.inline.} =
a[Idx(a.len - int(i) + int low(a))] = x
proc `[]=`*(s: var string; i: BackwardsIndex; x: char) {.inline.} =
s[s.len - int(i)] = x
proc slurp*(filename: string): string {.magic: "Slurp".}
## This is an alias for `staticRead <#staticRead>`_.
@ -3836,31 +3884,6 @@ proc procCall*(x: untyped) {.magic: "ProcCall", compileTime.} =
## procCall someMethod(a, b)
discard
proc `^`*[T](x: int; y: openArray[T]): int {.noSideEffect, magic: "Roof".}
proc `^`*(x: int): int {.noSideEffect, magic: "Roof".} =
## builtin `roof`:idx: operator that can be used for convenient array access.
## ``a[^x]`` is rewritten to ``a[a.len-x]``. However currently the ``a``
## expression must not have side effects for this to compile. Note that since
## this is a builtin, it automatically works for all kinds of
## overloaded ``[]`` or ``[]=`` accessors.
discard
template `..^`*(a, b: untyped): untyped =
## a shortcut for '.. ^' to avoid the common gotcha that a space between
## '..' and '^' is required.
a .. ^b
template `..<`*(a, b: untyped): untyped {.dirty.} =
## a shortcut for '.. <' to avoid the common gotcha that a space between
## '..' and '<' is required.
a .. <b
iterator `..<`*[S,T](a: S, b: T): T =
var i = T(a)
while i < b:
yield i
inc i
proc xlen*(x: string): int {.magic: "XLenStr", noSideEffect.} = discard
proc xlen*[T](x: seq[T]): int {.magic: "XLenSeq", noSideEffect.} =
## returns the length of a sequence or a string without testing for 'nil'.

View file

@ -301,13 +301,14 @@ proc pageAddr(p: pointer): PChunk {.inline.} =
result = cast[PChunk](cast[ByteAddress](p) and not PageMask)
#sysAssert(Contains(allocator.chunkStarts, pageIndex(result)))
proc writeFreeList(a: MemRegion) =
var it = a.freeChunksList
c_fprintf(stdout, "freeChunksList: %p\n", it)
while it != nil:
c_fprintf(stdout, "it: %p, next: %p, prev: %p, size: %ld\n",
it, it.next, it.prev, it.size)
it = it.next
when false:
proc writeFreeList(a: MemRegion) =
var it = a.freeChunksList
c_fprintf(stdout, "freeChunksList: %p\n", it)
while it != nil:
c_fprintf(stdout, "it: %p, next: %p, prev: %p, size: %ld\n",
it, it.next, it.prev, it.size)
it = it.next
const nimMaxHeap {.intdefine.} = 0

View file

@ -103,8 +103,12 @@ proc c_sprintf(buf, frmt: cstring): cint {.
importc: "sprintf", header: "<stdio.h>", varargs, noSideEffect.}
# we use it only in a way that cannot lead to security issues
proc c_fileno(f: File): cint {.
importc: "fileno", header: "<fcntl.h>".}
when defined(windows):
proc c_fileno(f: File): cint {.
importc: "_fileno", header: "<stdio.h>".}
else:
proc c_fileno(f: File): cint {.
importc: "fileno", header: "<fcntl.h>".}
proc c_malloc(size: csize): pointer {.
importc: "malloc", header: "<stdlib.h>".}

View file

@ -61,13 +61,17 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
unsureAsgnRef(x, s2)
return
sysAssert(dest != nil, "genericAssignAux 3")
unsureAsgnRef(x, newSeq(mt, seq.len))
var dst = cast[ByteAddress](cast[PPointer](dest)[])
if ntfNoRefs in mt.base.flags:
var ss = nimNewSeqOfCap(mt, seq.len)
cast[PGenericSeq](ss).len = seq.len
unsureAsgnRef(x, ss)
var dst = cast[ByteAddress](cast[PPointer](dest)[])
copyMem(cast[pointer](dst +% GenericSeqSize),
cast[pointer](cast[ByteAddress](s2) +% GenericSeqSize),
seq.len * mt.base.size)
else:
unsureAsgnRef(x, newSeq(mt, seq.len))
var dst = cast[ByteAddress](cast[PPointer](dest)[])
for i in 0..seq.len-1:
genericAssignAux(
cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),

View file

@ -127,7 +127,7 @@ proc fileMatches(c, bp: cstring): bool =
proc canonFilename*(filename: cstring): cstring =
## returns 'nil' if the filename cannot be found.
for i in 0 .. <dbgFilenameLen:
for i in 0 .. dbgFilenameLen-1:
result = dbgFilenames[i]
if fileMatches(result, filename): return result
result = nil
@ -261,7 +261,7 @@ proc genericHash(dest: pointer, mt: PNimType): int =
proc dbgRegisterWatchpoint(address: pointer, name: cstring,
typ: PNimType) {.compilerproc.} =
let L = watchPointsLen
for i in 0.. <L:
for i in 0 .. pred(L):
if watchPoints[i].name == name:
# address may have changed:
watchPoints[i].address = address
@ -288,7 +288,7 @@ var
proc checkWatchpoints =
let L = watchPointsLen
for i in 0.. <L:
for i in 0 .. pred(L):
let newHash = genericHash(watchPoints[i].address, watchPoints[i].typ)
if newHash != watchPoints[i].oldValue:
dbgWatchpointHook(watchPoints[i].name)

View file

@ -142,7 +142,10 @@ elif defined(windows) or defined(dos):
dec(m)
k = k div 10
if k == 0: break
result = getProcAddress(cast[THINSTANCE](lib), decorated)
when defined(nimNoArrayToCstringConversion):
result = getProcAddress(cast[THINSTANCE](lib), addr decorated)
else:
result = getProcAddress(cast[THINSTANCE](lib), decorated)
if result != nil: return
procAddrError(name)

View file

@ -76,10 +76,10 @@ proc `==`(a, b: StaticStr): bool =
return true
proc `==`(a: StaticStr, b: cstring): bool =
result = c_strcmp(a.data, b) == 0
result = c_strcmp(unsafeAddr a.data, b) == 0
proc write(f: File, s: StaticStr) =
write(f, cstring(s.data))
write(f, cstring(unsafeAddr s.data))
proc listBreakPoints() =
write(stdout, EndbBeg)
@ -260,8 +260,8 @@ proc parseBreakpoint(s: cstring, start: int): Breakpoint =
if result.high == 0: result.high = result.low
i = scanFilename(s, dbgTemp, i)
if dbgTemp.len != 0:
if not hasExt(dbgTemp.data): add(dbgTemp, ".nim")
result.filename = canonFilename(dbgTemp.data.cstring)
if not hasExt(addr dbgTemp.data): add(dbgTemp, ".nim")
result.filename = canonFilename(addr dbgTemp.data)
if result.filename.isNil:
debugOut("[Warning] no breakpoint could be set; unknown filename ")
return
@ -292,12 +292,12 @@ proc dbgEvaluate(stream: File, s: cstring, start: int, f: PFrame) =
i = scanAndAppendWord(s, dbgTemp, i)
for i in 0 .. getGlobalLen()-1:
let v = getGlobal(i)
if c_strcmp(v.name, dbgTemp.data) == 0:
if c_strcmp(v.name, addr dbgTemp.data) == 0:
writeVariable(stream, v)
else:
for i in 0 .. f.len-1:
let v = getLocal(f, i)
if c_strcmp(v.name, dbgTemp.data) == 0:
if c_strcmp(v.name, addr dbgTemp.data) == 0:
writeVariable(stream, v)
proc dbgOut(s: cstring, start: int, currFrame: PFrame) =
@ -306,7 +306,7 @@ proc dbgOut(s: cstring, start: int, currFrame: PFrame) =
if dbgTemp.len == 0:
invalidCommand()
return
var stream = openAppend(dbgTemp.data)
var stream = openAppend(addr dbgTemp.data)
if stream == nil:
debugOut("[Warning] could not open or create file ")
return
@ -320,7 +320,7 @@ proc dbgStackFrame(s: cstring, start: int, currFrame: PFrame) =
# just write it to stdout:
listFrame(stdout, currFrame)
else:
var stream = openAppend(dbgTemp.data)
var stream = openAppend(addr dbgTemp.data)
if stream == nil:
debugOut("[Warning] could not open or create file ")
return
@ -369,7 +369,7 @@ proc commandPrompt() =
if not readLine(stdin, dbgUser): break
if dbgUser.len == 0: dbgUser.len = oldLen
# now look what we have to do:
var i = scanWord(dbgUser.data, dbgTemp, 0)
var i = scanWord(addr dbgUser.data, dbgTemp, 0)
template `?`(x: expr): expr = dbgTemp == cstring(x)
if ?"s" or ?"step":
dbgState = dbStepInto
@ -400,13 +400,13 @@ proc commandPrompt() =
prevState = dbgState
prevSkipFrame = dbgSkipToFrame
dbgState = dbSkipCurrent
dbgEvaluate(stdout, dbgUser.data, i, dbgFramePtr)
dbgEvaluate(stdout, addr dbgUser.data, i, dbgFramePtr)
dbgState = prevState
dbgSkipToFrame = prevSkipFrame
elif ?"o" or ?"out":
dbgOut(dbgUser.data, i, dbgFramePtr)
dbgOut(addr dbgUser.data, i, dbgFramePtr)
elif ?"stackframe":
dbgStackFrame(dbgUser.data, i, dbgFramePtr)
dbgStackFrame(addr dbgUser.data, i, dbgFramePtr)
elif ?"w" or ?"where":
dbgShowExecutionPoint()
elif ?"l" or ?"locals":
@ -444,16 +444,16 @@ proc commandPrompt() =
elif ?"bt" or ?"backtrace":
dbgWriteStackTrace(framePtr)
elif ?"b" or ?"break":
createBreakPoint(dbgUser.data, i)
createBreakPoint(addr dbgUser.data, i)
elif ?"breakpoints":
listBreakPoints()
elif ?"toggle":
breakpointToggle(dbgUser.data, i)
breakpointToggle(addr dbgUser.data, i)
elif ?"filenames":
listFilenames()
elif ?"maxdisplay":
var parsed: int
i = scanNumber(dbgUser.data, parsed, i)
i = scanNumber(addr dbgUser.data, parsed, i)
if dbgUser.data[i-1] in {'0'..'9'}:
if parsed == 0: maxDisplayRecDepth = -1
else: maxDisplayRecDepth = parsed

View file

@ -306,8 +306,12 @@ proc raiseExceptionAux(e: ref Exception) =
add(buf, " [")
xadd(buf, e.name, e.name.len)
add(buf, "]\n")
unhandled(buf):
showErrorMessage(buf)
when defined(nimNoArrayToCstringConversion):
template tbuf(): untyped = addr buf
else:
template tbuf(): untyped = buf
unhandled(tbuf()):
showErrorMessage(tbuf())
quitOrDebug()
proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =

View file

@ -155,14 +155,15 @@ template setColor(c, col) =
else:
c.refcount = c.refcount and not colorMask or col
proc writeCell(msg: cstring, c: PCell) =
var kind = -1
var typName: cstring = "nil"
if c.typ != nil:
kind = ord(c.typ.kind)
when defined(nimTypeNames):
if not c.typ.name.isNil:
typName = c.typ.name
when defined(logGC):
proc writeCell(msg: cstring, c: PCell) =
var kind = -1
var typName: cstring = "nil"
if c.typ != nil:
kind = ord(c.typ.kind)
when defined(nimTypeNames):
if not c.typ.name.isNil:
typName = c.typ.name
when leakDetector:
c_fprintf(stdout, "[GC] %s: %p %d %s rc=%ld from %s(%ld)\n",
@ -642,9 +643,9 @@ when useMarkForDebug or useBackupGc:
forAllChildren(d, waMarkPrecise)
proc markGlobals(gch: var GcHeap) =
for i in 0 .. < globalMarkersLen: globalMarkers[i]()
for i in 0 .. globalMarkersLen-1: globalMarkers[i]()
let d = gch.additionalRoots.d
for i in 0 .. < gch.additionalRoots.len: markS(gch, d[i])
for i in 0 .. gch.additionalRoots.len-1: markS(gch, d[i])
when logGC:
var
@ -652,7 +653,7 @@ when logGC:
cycleCheckALen = 0
proc alreadySeen(c: PCell): bool =
for i in 0 .. <cycleCheckALen:
for i in 0 .. cycleCheckALen-1:
if cycleCheckA[i] == c: return true
if cycleCheckALen == len(cycleCheckA):
gcAssert(false, "cycle detection overflow")

View file

@ -487,12 +487,12 @@ proc GC_dumpHeap*(file: File) =
var spaceIter: ObjectSpaceIter
when false:
var d = gch.decStack.d
for i in 0 .. < gch.decStack.len:
for i in 0 .. gch.decStack.len-1:
if isAllocatedPtr(gch.region, d[i]):
c_fprintf(file, "onstack %p\n", d[i])
else:
c_fprintf(file, "onstack_invalid %p\n", d[i])
for i in 0 .. < globalMarkersLen: globalMarkers[i]()
for i in 0 .. globalMarkersLen-1: globalMarkers[i]()
while true:
let x = allObjectsAsProc(gch.region, addr spaceIter)
if spaceIter.state < 0: break
@ -579,7 +579,7 @@ proc markIncremental(gch: var GcHeap): bool =
result = true
proc markGlobals(gch: var GcHeap) =
for i in 0 .. < globalMarkersLen: globalMarkers[i]()
for i in 0 .. globalMarkersLen-1: globalMarkers[i]()
proc doOperation(p: pointer, op: WalkOp) =
if p == nil: return

View file

@ -450,9 +450,9 @@ when false:
quit 1
proc markGlobals(gch: var GcHeap) =
for i in 0 .. < globalMarkersLen: globalMarkers[i]()
for i in 0 .. globalMarkersLen-1: globalMarkers[i]()
let d = gch.additionalRoots.d
for i in 0 .. < gch.additionalRoots.len: mark(gch, d[i])
for i in 0 .. gch.additionalRoots.len-1: mark(gch, d[i])
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
# the addresses are not as cells on the stack, so turn them to cells:

View file

@ -106,7 +106,7 @@ proc cmpic*(a, b: string): int =
## Compares `a` and `b` ignoring case.
cmpIgnoreCase(a, b)
proc getEnv*(key: string): string {.tags: [ReadIOEffect].} =
proc getEnv*(key: string; default = ""): string {.tags: [ReadIOEffect].} =
## Retrieves the environment variable of name `key`.
builtin

View file

@ -16,34 +16,39 @@ proc reprInt(x: int64): string {.compilerproc.} = return $x
proc reprFloat(x: float): string {.compilerproc.} = return $x
proc reprPointer(x: pointer): string {.compilerproc.} =
var buf: array[0..59, char]
discard c_sprintf(buf, "%p", x)
return $buf
when defined(nimNoArrayToCstringConversion):
result = newString(60)
let n = c_sprintf(addr result[0], "%p", x)
setLen(result, n)
else:
var buf: array[0..59, char]
discard c_sprintf(buf, "%p", x)
return $buf
proc `$`(x: uint64): string =
if x == 0:
result = "0"
else:
var buf: array[60, char]
result = newString(60)
var i = 0
var n = x
while n != 0:
let nn = n div 10'u64
buf[i] = char(n - 10'u64 * nn + ord('0'))
result[i] = char(n - 10'u64 * nn + ord('0'))
inc i
n = nn
result.setLen i
let half = i div 2
# Reverse
for t in 0 .. < half: swap(buf[t], buf[i-t-1])
result = $buf
for t in 0 .. half-1: swap(result[t], result[i-t-1])
proc reprStrAux(result: var string, s: cstring; len: int) =
if cast[pointer](s) == nil:
add result, "nil"
return
add result, reprPointer(cast[pointer](s)) & "\""
for i in 0.. <len:
for i in 0 .. pred(len):
let c = s[i]
case c
of '"': add result, "\\\""

View file

@ -9,13 +9,13 @@
# The generic ``repr`` procedure for the javascript backend.
proc reprInt(x: int64): string {.compilerproc.} = return $x
proc reprFloat(x: float): string {.compilerproc.} =
proc reprFloat(x: float): string {.compilerproc.} =
# Js toString doesn't differentiate between 1.0 and 1,
# but we do.
if $x == $(x.int): $x & ".0"
else: $x
proc reprPointer(p: pointer): string {.compilerproc.} =
proc reprPointer(p: pointer): string {.compilerproc.} =
# Do we need to generate the full 8bytes ? In js a pointer is an int anyway
var tmp: int
{. emit: """
@ -38,7 +38,7 @@ proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
result = $typ.node.sons[e].name
else:
result = $e & " (invalid data!)"
proc reprChar(x: char): string {.compilerRtl.} =
result = "\'"
case x
@ -50,7 +50,7 @@ proc reprChar(x: char): string {.compilerRtl.} =
proc reprStrAux(result: var string, s: cstring, len: int) =
add(result, "\"")
for i in 0 .. <len:
for i in 0 .. len-1:
let c = s[i]
case c
of '"': add(result, "\\\"")
@ -67,7 +67,7 @@ proc reprStr(s: string): string {.compilerRtl.} =
if cast[pointer](s).isNil:
# Handle nil strings here because they don't have a length field in js
# TODO: check for null/undefined before generating call to length in js?
# Also: c backend repr of a nil string is <pointer>"", but repr of an
# Also: c backend repr of a nil string is <pointer>"", but repr of an
# array of string that is not initialized is [nil, nil, ...] ??
add(result, "nil")
else:
@ -86,7 +86,7 @@ proc addSetElem(result: var string, elem: int, typ: PNimType) =
iterator setKeys(s: int): int {.inline.} =
# The type of s is a lie, but it's expected to be a set.
# Iterate over the JS object representing a set
# Iterate over the JS object representing a set
# and returns the keys as int.
var len: int
var yieldRes: int
@ -124,16 +124,16 @@ proc initReprClosure(cl: var ReprClosure) =
cl.recDepth = -1 # default is to display everything!
cl.indent = 0
proc reprAux(result: var string, p: pointer, typ: PNimType, cl: var ReprClosure)
proc reprAux(result: var string, p: pointer, typ: PNimType, cl: var ReprClosure)
proc reprArray(a: pointer, typ: PNimType,
proc reprArray(a: pointer, typ: PNimType,
cl: var ReprClosure): string {.compilerRtl.} =
var isNilArrayOrSeq: bool
# isnil is not enough here as it would try to deref `a` without knowing what's inside
{. emit: """
if (`a` == null) {
if (`a` == null) {
`isNilArrayOrSeq` = true;
} else if (`a`[0] == null) {
} else if (`a`[0] == null) {
`isNilArrayOrSeq` = true;
} else {
`isNilArrayOrSeq` = false;
@ -146,19 +146,19 @@ proc reprArray(a: pointer, typ: PNimType,
result = if typ.kind == tySequence: "@[" else: "["
var len: int = 0
var i: int = 0
{. emit: "`len` = `a`.length;\n" .}
var dereffed: pointer = a
for i in 0 .. < len:
for i in 0 .. len-1:
if i > 0 :
add(result, ", ")
# advance pointer and point to element at index
{. emit: """
`dereffed`_Idx = `i`;
`dereffed`_Idx = `i`;
`dereffed` = `a`[`dereffed`_Idx];
""" .}
reprAux(result, dereffed, typ.base, cl)
add(result, "]")
proc isPointedToNil(p: pointer): bool {.inline.}=
@ -181,7 +181,7 @@ proc reprRef(result: var string, p: pointer, typ: PNimType,
proc reprRecordAux(result: var string, o: pointer, typ: PNimType, cl: var ReprClosure) =
add(result, "[")
var first: bool = true
var val: pointer = o
if typ.node.len == 0:
@ -192,7 +192,7 @@ proc reprRecordAux(result: var string, o: pointer, typ: PNimType, cl: var ReprCl
reprAux(result, val, typ.node.typ, cl)
else:
# if the object has more than one field, sons is not nil and contains the fields.
for i in 0 .. <typ.node.len:
for i in 0 .. typ.node.len-1:
if first: first = false
else: add(result, ",\n")
@ -214,11 +214,11 @@ proc reprJSONStringify(p: int): string {.compilerRtl.} =
{. emit: "`tmp` = JSON.stringify(`p`);\n" .}
result = $tmp
proc reprAux(result: var string, p: pointer, typ: PNimType,
proc reprAux(result: var string, p: pointer, typ: PNimType,
cl: var ReprClosure) =
if cl.recDepth == 0:
add(result, "...")
return
return
dec(cl.recDepth)
case typ.kind
of tyInt..tyInt64, tyUInt..tyUInt64:

View file

@ -15,9 +15,12 @@
{.push debugger:off .} # the user does not want to trace a part
# of the standard library!
proc c_fdopen(filehandle: cint, mode: cstring): File {.
importc: "fdopen", header: "<stdio.h>".}
when defined(windows):
proc c_fdopen(filehandle: cint, mode: cstring): File {.
importc: "_fdopen", header: "<stdio.h>".}
else:
proc c_fdopen(filehandle: cint, mode: cstring): File {.
importc: "fdopen", header: "<stdio.h>".}
proc c_fputs(c: cstring, f: File): cint {.
importc: "fputs", header: "<stdio.h>", tags: [WriteIOEffect].}
proc c_fgets(c: cstring, n: cint, f: File): cstring {.
@ -401,4 +404,18 @@ proc setStdIoUnbuffered() =
when declared(stdin):
discard c_setvbuf(stdin, nil, IONBF, 0)
when declared(stdout):
proc echoBinSafe(args: openArray[string]) {.compilerProc.} =
when not defined(windows):
proc flockfile(f: File) {.importc, noDecl.}
proc funlockfile(f: File) {.importc, noDecl.}
flockfile(stdout)
for s in args:
discard c_fwrite(s.cstring, s.len, 1, stdout)
const linefeed = "\n" # can be 1 or more chars
discard c_fwrite(linefeed.cstring, linefeed.len, 1, stdout)
discard c_fflush(stdout)
when not defined(windows):
funlockfile(stdout)
{.pop.}

View file

@ -142,7 +142,7 @@ var
workersData: array[NumThreads, Worker]
proc setup() =
for i in 0.. <NumThreads:
for i in 0 ..< NumThreads:
workersData[i].taskArrived = createCondVar()
workersData[i].taskStarted = createFastCondVar()
createThread(workers[i], slave, addr(workersData[i]))

View file

@ -24,7 +24,10 @@ proc cmpStrings(a, b: NimString): int {.inline, compilerProc.} =
if a == b: return 0
if a == nil: return -1
if b == nil: return 1
return c_strcmp(a.data, b.data)
when defined(nimNoArrayToCstringConversion):
return c_strcmp(addr a.data, addr b.data)
else:
return c_strcmp(a.data, b.data)
proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
if a == b: return true
@ -275,7 +278,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
GenericSeqSize +% (i*%elemSize)),
extGetCellType(result).base, waPush)
let len1 = gch.tempStack.len
for i in len0 .. <len1:
for i in len0 ..< len1:
doDecRef(gch.tempStack.d[i], LocalHeap, MaybeCyclic)
gch.tempStack.len = len0
else:
@ -320,7 +323,10 @@ proc nimIntToStr(x: int): string {.compilerRtl.} =
proc add*(result: var string; x: float) =
var buf: array[0..64, char]
var n: int = c_sprintf(buf, "%.16g", x)
when defined(nimNoArrayToCstringConversion):
var n: int = c_sprintf(addr buf, "%.16g", x)
else:
var n: int = c_sprintf(buf, "%.16g", x)
var hasDot = false
for i in 0..n-1:
if buf[i] == ',':
@ -332,9 +338,10 @@ proc add*(result: var string; x: float) =
buf[n] = '.'
buf[n+1] = '0'
buf[n+2] = '\0'
# On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' are produced.
# On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN'
# of '-1.#IND' are produced.
# We want to get rid of these here:
if buf[n-1] in {'n', 'N'}:
if buf[n-1] in {'n', 'N', 'D', 'd'}:
result.add "nan"
elif buf[n-1] == 'F':
if buf[0] == '-':
@ -342,7 +349,10 @@ proc add*(result: var string; x: float) =
else:
result.add "inf"
else:
result.add buf
var i = 0
while buf[i] != '\0':
result.add buf[i]
inc i
proc nimFloatToStr(f: float): string {.compilerproc.} =
result = newStringOfCap(8)
@ -353,9 +363,9 @@ proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {.
const
IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
powtens = [ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
1e20, 1e21, 1e22]
powtens = [1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
1e20, 1e21, 1e22]
proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
start = 0): int {.compilerProc.} =
@ -507,7 +517,10 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
t[ti-2] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10
t[ti-3] = ('0'.ord + abs_exponent mod 10).char
number = c_strtod(t, nil)
when defined(nimNoArrayToCstringConversion):
number = c_strtod(addr t, nil)
else:
number = c_strtod(t, nil)
proc nimInt64ToStr(x: int64): string {.compilerRtl.} =
result = newStringOfCap(sizeof(x)*4)

View file

@ -398,7 +398,7 @@ template afterThreadRuns() =
threadDestructionHandlers[i]()
when not defined(boehmgc) and not hasSharedHeap and not defined(gogc) and not defined(gcRegions):
proc deallocOsPages()
proc deallocOsPages() {.rtl.}
when defined(boehmgc):
type GCStackBaseProc = proc(sb: pointer, t: pointer) {.noconv.}

View file

@ -14,8 +14,8 @@
import dynlib
when defined(vcc):
{.passC: "-DWIN32_LEAN_AND_MEAN".}
{.passC: "-DWIN32_LEAN_AND_MEAN".}
const
useWinUnicode* = not defined(useWinAnsi)

View file

@ -590,13 +590,13 @@ proc md5_Transform*(c: var MD5_CTX; b: ptr cuchar){.importc: "MD5_Transform".}
from strutils import toHex, toLowerAscii
proc hexStr (buf:cstring): string =
proc hexStr(buf: cstring): string =
# turn md5s output into a nice hex str
result = newStringOfCap(32)
for i in 0 .. <16:
for i in 0 ..< 16:
result.add toHex(buf[i].ord, 2).toLowerAscii
proc md5_File* (file: string): string {.raises: [IOError,Exception].} =
proc md5_File*(file: string): string {.raises: [IOError,Exception].} =
## Generate MD5 hash for a file. Result is a 32 character
# hex string with lowercase characters (like the output
# of `md5sum`
@ -611,14 +611,14 @@ proc md5_File* (file: string): string {.raises: [IOError,Exception].} =
while(let bytes = f.readChars(buf, 0, sz); bytes > 0):
discard md5_update(ctx, buf[0].addr, bytes)
discard md5_final( buf[0].addr, ctx )
discard md5_final(buf[0].addr, ctx)
f.close
result = hexStr(buf)
result = hexStr(addr buf)
proc md5_Str*(str:string): string =
##Generate MD5 hash for a string. Result is a 32 character
#hex string with lowercase characters
proc md5_Str*(str: string): string =
## Generate MD5 hash for a string. Result is a 32 character
## hex string with lowercase characters
var
ctx: MD5_CTX
res: array[MD5_DIGEST_LENGTH,char]
@ -631,5 +631,5 @@ proc md5_Str*(str:string): string =
discard md5_update(ctx, input[i].addr, L)
i += L
discard md5_final(res,ctx)
result = hexStr(res)
discard md5_final(addr res, ctx)
result = hexStr(addr res)

File diff suppressed because it is too large Load diff

View file

@ -20,16 +20,12 @@ proc openCCState*(): PccState {.importc: "tcc_new", cdecl.}
proc closeCCState*(s: PccState) {.importc: "tcc_delete", cdecl.}
## free a TCC compilation context
proc enableDebug*(s: PccState) {.importc: "tcc_enable_debug", cdecl.}
## add debug information in the generated code
proc setErrorFunc*(s: PccState, errorOpaque: pointer, errorFun: ErrorFunc) {.
cdecl, importc: "tcc_set_error_func".}
## set error/warning display callback
proc setWarning*(s: PccState, warningName: cstring, value: int) {.cdecl,
importc: "tcc_set_warning".}
## set/reset a warning
proc setOptions*(s: PccState, options: cstring) {.cdecl, importc: "tcc_set_options".}
## set a options
# preprocessor
@ -41,7 +37,6 @@ proc addSysincludePath*(s: PccState, pathname: cstring) {.cdecl,
importc: "tcc_add_sysinclude_path".}
## add in system include path
proc defineSymbol*(s: PccState, sym, value: cstring) {.cdecl,
importc: "tcc_define_symbol".}
## define preprocessor symbol 'sym'. Can put optional value
@ -65,16 +60,12 @@ proc compileString*(s: PccState, buf: cstring): cint {.cdecl,
const
OutputMemory*: cint = 0 ## output will be ran in memory (no
OutputMemory*: cint = 1 ## output will be ran in memory (no
## output file) (default)
OutputExe*: cint = 1 ## executable file
OutputDll*: cint = 2 ## dynamic library
OutputObj*: cint = 3 ## object file
OutputPreprocess*: cint = 4 ## preprocessed file (used internally)
OutputFormatElf*: cint = 0 ## default output format: ELF
OutputFormatBinary*: cint = 1 ## binary image output
OutputFormatCoff*: cint = 2 ## COFF
OutputExe*: cint = 2 ## executable file
OutputDll*: cint = 3 ## dynamic library
OutputObj*: cint = 4 ## object file
OutputPreprocess*: cint = 5 ## preprocessed file (used internally)
proc setOutputType*(s: PCCState, outputType: cint): cint {.cdecl,
importc: "tcc_set_output_type".}