diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/core/macros.nim | 6 | ||||
-rw-r--r-- | lib/impure/re.nim | 4 | ||||
-rw-r--r-- | lib/pure/algorithm.nim | 19 | ||||
-rw-r--r-- | lib/pure/asyncdispatch.nim | 4 | ||||
-rw-r--r-- | lib/pure/collections/tables.nim | 24 | ||||
-rw-r--r-- | lib/pure/concurrency/threadpool.nim | 2 | ||||
-rw-r--r-- | lib/pure/hashes.nim | 66 | ||||
-rw-r--r-- | lib/pure/httpclient.nim | 16 | ||||
-rw-r--r-- | lib/pure/json.nim | 65 | ||||
-rw-r--r-- | lib/pure/math.nim | 22 | ||||
-rw-r--r-- | lib/pure/net.nim | 10 | ||||
-rw-r--r-- | lib/pure/os.nim | 4 | ||||
-rw-r--r-- | lib/pure/osproc.nim | 26 | ||||
-rw-r--r-- | lib/pure/rawsockets.nim | 4 | ||||
-rw-r--r-- | lib/pure/scgi.nim | 2 | ||||
-rw-r--r-- | lib/pure/sexp.nim | 697 | ||||
-rw-r--r-- | lib/pure/sockets.nim | 18 | ||||
-rw-r--r-- | lib/pure/streams.nim | 99 | ||||
-rw-r--r-- | lib/pure/strutils.nim | 20 | ||||
-rw-r--r-- | lib/pure/times.nim | 21 | ||||
-rw-r--r-- | lib/system.nim | 19 | ||||
-rw-r--r-- | lib/system/arithm.nim | 8 | ||||
-rw-r--r-- | lib/system/chcks.nim | 6 | ||||
-rw-r--r-- | lib/windows/windows.nim | 79 |
24 files changed, 1094 insertions, 147 deletions
diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 35f0f61c1..7e6e4ccc9 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -177,6 +177,12 @@ proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.} ## resolve recursive types, you have to call 'getType' again. To see what ## kind of type it is, call `typeKind` on getType's result. +proc getType*(n: typedesc): NimNode {.magic: "NGetType", noSideEffect.} + ## Returns the Nim type node for given type. This can be used to turn macro + ## typedesc parameter into proper NimNode representing type, since typedesc + ## are an exception in macro calls - they are not mapped implicitly to + ## NimNode like any other arguments. + proc typeKind*(n: NimNode): NimTypeKind {.magic: "NGetType", noSideEffect.} ## Returns the type kind of the node 'n' that should represent a type, that ## means the node should have been obtained via `getType`. diff --git a/lib/impure/re.nim b/lib/impure/re.nim index fb95610f6..279f8aadd 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -146,8 +146,8 @@ proc findBounds*(s: string, pattern: Regex, proc findBounds*(s: string, pattern: Regex, start = 0): tuple[first, last: int] = - ## returns the starting position of `pattern` in `s`. If it does not - ## match, ``(-1,0)`` is returned. + ## returns the starting position and end position of ``pattern`` in ``s``. + ## If it does not match, ``(-1,0)`` is returned. var rtarray = initRtArray[cint](3) rawMatches = rtarray.getRawData diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index f7ccb9234..0eafb316a 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -24,6 +24,17 @@ proc `*`*(x: int, order: SortOrder): int {.inline.} = var y = order.ord - 1 result = (x xor y) - y +proc fill*[T](a: var openArray[T], first, last: Natural, value: T) = + ## fills the array ``a[first..last]`` with `value`. + var x = first + while x <= last: + a[x] = value + inc(x) + +proc fill*[T](a: var openArray[T], value: T) = + ## fills the array `a` with `value`. + fill(a, 0, a.high, value) + proc reverse*[T](a: var openArray[T], first, last: Natural) = ## reverses the array ``a[first..last]``. var x = first @@ -210,8 +221,7 @@ template sortedByIt*(seq1, op: expr): expr = ## p2: Person = (name: "p2", age: 20) ## p3: Person = (name: "p3", age: 30) ## p4: Person = (name: "p4", age: 30) - ## - ## people = @[p1,p2,p4,p3] + ## people = @[p1,p2,p4,p3] ## ## echo people.sortedByIt(it.name) ## @@ -233,7 +243,7 @@ template sortedByIt*(seq1, op: expr): expr = proc product*[T](x: openArray[seq[T]]): seq[seq[T]] = ## produces the Cartesian product of the array. Warning: complexity ## may explode. - result = @[] + result = newSeq[seq[T]]() if x.len == 0: return if x.len == 1: @@ -243,8 +253,7 @@ proc product*[T](x: openArray[seq[T]]): seq[seq[T]] = indexes = newSeq[int](x.len) initial = newSeq[int](x.len) index = 0 - # replace with newSeq as soon as #853 is fixed - var next: seq[T] = @[] + var next = newSeq[T]() next.setLen(x.len) for i in 0..(x.len-1): if len(x[i]) == 0: return diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index a4d7a1632..8010e9ebc 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1154,7 +1154,7 @@ else: proc sleepAsync*(ms: int): Future[void] = ## Suspends the execution of the current async procedure for the next - ## ``ms`` miliseconds. + ## ``ms`` milliseconds. var retFuture = newFuture[void]("sleepAsync") let p = getGlobalDispatcher() p.timers.add((epochTime() + (ms / 1000), retFuture)) @@ -1328,7 +1328,7 @@ proc processBody(node, retFutureSym: NimNode, else: discard of nnkDiscardStmt: # discard await x - if node[0].kind != nnkEmpty and node[0][0].kind == nnkIdent and + if node[0].kind == nnkCommand and node[0][0].kind == nnkIdent and node[0][0].ident == !"await": var newDiscard = node result.createVar("futureDiscard_" & $toStrLit(node[0][1]), node[0][1], diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index a9357ce67..9496fa2fe 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -215,6 +215,10 @@ proc hasKey*[A, B](t: Table[A, B], key: A): bool = var hc: THash result = rawGet(t, key, hc) >= 0 +proc contains*[A, B](t: Table[A, B], key: A): bool = + ## alias of `hasKey` for use with the `in` operator. + return hasKey[A, B](t, key) + proc rawInsert[A, B](t: var Table[A, B], data: var KeyValuePairSeq[A, B], key: A, val: B, hc: THash, h: THash) = rawInsertImpl() @@ -411,6 +415,10 @@ proc hasKey*[A, B](t: TableRef[A, B], key: A): bool = ## returns true iff `key` is in the table `t`. result = t[].hasKey(key) +proc contains*[A, B](t: TableRef[A, B], key: A): bool = + ## alias of `hasKey` for use with the `in` operator. + return hasKey[A, B](t, key) + proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: B) = ## puts a (key, value)-pair into `t`. t[][key] = val @@ -532,6 +540,10 @@ proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool = var hc: THash result = rawGet(t, key, hc) >= 0 +proc contains*[A, B](t: OrderedTable[A, B], key: A): bool = + ## alias of `hasKey` for use with the `in` operator. + return hasKey[A, B](t, key) + proc rawInsert[A, B](t: var OrderedTable[A, B], data: var OrderedKeyValuePairSeq[A, B], key: A, val: B, hc: THash, h: THash) = @@ -704,6 +716,10 @@ proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool = ## returns true iff `key` is in the table `t`. result = t[].hasKey(key) +proc contains*[A, B](t: OrderedTableRef[A, B], key: A): bool = + ## alias of `hasKey` for use with the `in` operator. + return hasKey[A, B](t, key) + proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: B) = ## puts a (key, value)-pair into `t`. t[][key] = val @@ -804,6 +820,10 @@ proc hasKey*[A](t: CountTable[A], key: A): bool = ## returns true iff `key` is in the table `t`. result = rawGet(t, key) >= 0 +proc contains*[A](t: CountTable[A], key: A): bool = + ## alias of `hasKey` for use with the `in` operator. + return hasKey[A](t, key) + proc rawInsert[A](t: CountTable[A], data: var seq[tuple[key: A, val: int]], key: A, val: int) = var h: THash = hash(key) and high(data) @@ -945,6 +965,10 @@ proc hasKey*[A](t: CountTableRef[A], key: A): bool = ## returns true iff `key` is in the table `t`. result = t[].hasKey(key) +proc contains*[A](t: CountTableRef[A], key: A): bool = + ## alias of `hasKey` for use with the `in` operator. + return hasKey[A](t, key) + proc `[]=`*[A](t: CountTableRef[A], key: A, val: int) = ## puts a (key, value)-pair into `t`. `val` has to be positive. assert val > 0 diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index 9f1e53fb8..a431691ad 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -300,7 +300,7 @@ proc setMinPoolSize*(size: range[1..MaxThreadPoolSize]) = minPoolSize = size proc setMaxPoolSize*(size: range[1..MaxThreadPoolSize]) = - ## sets the minimal thread pool size. The default value of this + ## sets the maximal thread pool size. The default value of this ## is ``MaxThreadPoolSize``. maxPoolSize = size if currentPoolSize > maxPoolSize: diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index a16342d44..2ce8ac796 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -37,29 +37,29 @@ ## h = h !& hash(x.bar) ## result = !$h -import +import strutils -type - THash* = int ## a hash value; hash tables using these values should +type + THash* = int ## a hash value; hash tables using these values should ## always have a size of a power of two and can use the ``and`` ## operator instead of ``mod`` for truncation of the hash value. -proc `!&`*(h: THash, val: int): THash {.inline.} = +proc `!&`*(h: THash, val: int): THash {.inline.} = ## mixes a hash value `h` with `val` to produce a new hash value. This is ## only needed if you need to implement a hash proc for a new datatype. result = h +% val result = result +% result shl 10 result = result xor (result shr 6) -proc `!$`*(h: THash): THash {.inline.} = +proc `!$`*(h: THash): THash {.inline.} = ## finishes the computation of the hash value. This is ## only needed if you need to implement a hash proc for a new datatype. result = h +% h shl 3 result = result xor (result shr 11) result = result +% result shl 15 -proc hashData*(data: pointer, size: int): THash = +proc hashData*(data: pointer, size: int): THash = ## hashes an array of bytes of size `size` var h: THash = 0 when defined(js): @@ -69,7 +69,7 @@ proc hashData*(data: pointer, size: int): THash = var p = cast[cstring](data) var i = 0 var s = size - while s > 0: + while s > 0: h = h !& ord(p[i]) inc(i) dec(s) @@ -78,7 +78,7 @@ proc hashData*(data: pointer, size: int): THash = when defined(js): var objectID = 0 -proc hash*(x: pointer): THash {.inline.} = +proc hash*(x: pointer): THash {.inline.} = ## efficient hashing of pointers when defined(js): asm """ @@ -93,7 +93,7 @@ proc hash*(x: pointer): THash {.inline.} = """ else: result = (cast[THash](x)) shr 3 # skip the alignment - + when not defined(booting): proc hash*[T: proc](x: T): THash {.inline.} = ## efficient hashing of proc vars; closures are supported too. @@ -101,58 +101,65 @@ when not defined(booting): result = hash(rawProc(x)) !& hash(rawEnv(x)) else: result = hash(pointer(x)) - -proc hash*(x: int): THash {.inline.} = + +proc hash*(x: int): THash {.inline.} = ## efficient hashing of integers result = x -proc hash*(x: int64): THash {.inline.} = +proc hash*(x: int64): THash {.inline.} = ## efficient hashing of integers result = toU32(x) -proc hash*(x: char): THash {.inline.} = +proc hash*(x: char): THash {.inline.} = ## efficient hashing of characters result = ord(x) -proc hash*(x: string): THash = +proc hash*(x: string): THash = ## efficient hashing of strings var h: THash = 0 - for i in 0..x.len-1: + for i in 0..x.len-1: h = h !& ord(x[i]) result = !$h - -proc hashIgnoreStyle*(x: string): THash = + +proc hashIgnoreStyle*(x: string): THash = ## efficient hashing of strings; style is ignored var h: THash = 0 - for i in 0..x.len-1: + for i in 0..x.len-1: var c = x[i] - if c == '_': + if c == '_': continue # skip _ - if c in {'A'..'Z'}: + if c in {'A'..'Z'}: c = chr(ord(c) + (ord('a') - ord('A'))) # toLower() h = h !& ord(c) result = !$h -proc hashIgnoreCase*(x: string): THash = +proc hashIgnoreCase*(x: string): THash = ## efficient hashing of strings; case is ignored var h: THash = 0 - for i in 0..x.len-1: + for i in 0..x.len-1: var c = x[i] - if c in {'A'..'Z'}: + if c in {'A'..'Z'}: c = chr(ord(c) + (ord('a') - ord('A'))) # toLower() h = h !& ord(c) result = !$h - -proc hash*[T: tuple](x: T): THash = - ## efficient hashing of tuples. - for f in fields(x): - result = result !& hash(f) - result = !$result proc hash*(x: float): THash {.inline.} = var y = x + 1.0 result = cast[ptr THash](addr(y))[] + +# Forward declarations before methods that hash containers. This allows +# containers to contain other containers +proc hash*[A](x: openArray[A]): THash +proc hash*[A](x: set[A]): THash + + +proc hash*[T: tuple](x: T): THash = + ## efficient hashing of tuples. + for f in fields(x): + result = result !& hash(f) + result = !$result + proc hash*[A](x: openArray[A]): THash = for it in items(x): result = result !& hash(it) result = !$result @@ -160,3 +167,4 @@ proc hash*[A](x: openArray[A]): THash = proc hash*[A](x: set[A]): THash = for it in items(x): result = result !& hash(it) result = !$result + diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 9c27ecdab..e083d44ea 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -64,7 +64,7 @@ ## ======== ## Currently all functions support an optional timeout, by default the timeout is set to ## `-1` which means that the function will never time out. The timeout is -## measured in miliseconds, once it is set any call on a socket which may +## measured in milliseconds, once it is set any call on a socket which may ## block will be susceptible to this timeout, however please remember that the ## function as a whole can take longer than the specified timeout, only ## individual internal calls on the socket are affected. In practice this means @@ -386,7 +386,7 @@ proc request*(url: string, httpMethod: string, extraHeaders = "", ## | Requests ``url`` with the custom method string specified by the ## | ``httpMethod`` parameter. ## | Extra headers can be specified and must be separated by ``\c\L`` - ## | An optional timeout can be specified in miliseconds, if reading from the + ## | An optional timeout can be specified in milliseconds, if reading from the ## server takes longer than specified an ETimeout exception will be raised. var r = if proxy == nil: parseUri(url) else: proxy.url var headers = substr(httpMethod, len("http")) @@ -440,7 +440,7 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "", userAgent = defUserAgent, proxy: Proxy = nil): Response = ## | Requests ``url`` with the specified ``httpMethod``. ## | Extra headers can be specified and must be separated by ``\c\L`` - ## | An optional timeout can be specified in miliseconds, if reading from the + ## | An optional timeout can be specified in milliseconds, if reading from the ## server takes longer than specified an ETimeout exception will be raised. result = request(url, $httpMethod, extraHeaders, body, sslContext, timeout, userAgent, proxy) @@ -467,7 +467,7 @@ proc get*(url: string, extraHeaders = "", maxRedirects = 5, ## | GETs the ``url`` and returns a ``Response`` object ## | This proc also handles redirection ## | Extra headers can be specified and must be separated by ``\c\L``. - ## | An optional timeout can be specified in miliseconds, if reading from the + ## | An optional timeout can be specified in milliseconds, if reading from the ## server takes longer than specified an ETimeout exception will be raised. result = request(url, httpGET, extraHeaders, "", sslContext, timeout, userAgent, proxy) @@ -486,7 +486,7 @@ proc getContent*(url: string, extraHeaders = "", maxRedirects = 5, ## | GETs the body and returns it as a string. ## | Raises exceptions for the status codes ``4xx`` and ``5xx`` ## | Extra headers can be specified and must be separated by ``\c\L``. - ## | An optional timeout can be specified in miliseconds, if reading from the + ## | An optional timeout can be specified in milliseconds, if reading from the ## server takes longer than specified an ETimeout exception will be raised. var r = get(url, extraHeaders, maxRedirects, sslContext, timeout, userAgent, proxy) @@ -505,7 +505,7 @@ proc post*(url: string, extraHeaders = "", body = "", ## | This proc adds the necessary Content-Length header. ## | This proc also handles redirection. ## | Extra headers can be specified and must be separated by ``\c\L``. - ## | An optional timeout can be specified in miliseconds, if reading from the + ## | An optional timeout can be specified in milliseconds, if reading from the ## server takes longer than specified an ETimeout exception will be raised. ## | The optional ``multipart`` parameter can be used to create ## ``multipart/form-data`` POSTs comfortably. @@ -542,7 +542,7 @@ proc postContent*(url: string, extraHeaders = "", body = "", ## | POSTs ``body`` to ``url`` and returns the response's body as a string ## | Raises exceptions for the status codes ``4xx`` and ``5xx`` ## | Extra headers can be specified and must be separated by ``\c\L``. - ## | An optional timeout can be specified in miliseconds, if reading from the + ## | An optional timeout can be specified in milliseconds, if reading from the ## server takes longer than specified an ETimeout exception will be raised. ## | The optional ``multipart`` parameter can be used to create ## ``multipart/form-data`` POSTs comfortably. @@ -558,7 +558,7 @@ proc downloadFile*(url: string, outputFilename: string, timeout = -1, userAgent = defUserAgent, proxy: Proxy = nil) = ## | Downloads ``url`` and saves it to ``outputFilename`` - ## | An optional timeout can be specified in miliseconds, if reading from the + ## | An optional timeout can be specified in milliseconds, if reading from the ## server takes longer than specified an ETimeout exception will be raised. var f: File if open(f, outputFilename, fmWrite): diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 5d824d6f8..518572be3 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -761,7 +761,7 @@ proc len*(n: JsonNode): int = of JObject: result = n.fields.len else: discard -proc `[]`*(node: JsonNode, name: string): JsonNode = +proc `[]`*(node: JsonNode, name: string): JsonNode {.inline.} = ## Gets a field from a `JObject`, which must not be nil. ## If the value at `name` does not exist, returns nil assert(not isNil(node)) @@ -771,7 +771,7 @@ proc `[]`*(node: JsonNode, name: string): JsonNode = return item return nil -proc `[]`*(node: JsonNode, index: int): JsonNode = +proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} = ## Gets the node at `index` in an Array. Result is undefined if `index` ## is out of bounds assert(not isNil(node)) @@ -799,7 +799,7 @@ proc add*(obj: JsonNode, key: string, val: JsonNode) = assert obj.kind == JObject obj.fields.add((key, val)) -proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) = +proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} = ## Sets a field from a `JObject`. Performs a check for duplicate keys. assert(obj.kind == JObject) for i in 0..obj.fields.len-1: @@ -815,7 +815,7 @@ proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode = result = node for key in keys: if isNil(result) or result.kind!=JObject: - return nil + return nil result=result[key] proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) = @@ -949,10 +949,46 @@ proc pretty*(node: JsonNode, indent = 2): string = result = "" toPretty(result, node, indent) +proc toUgly*(result: var string, node: JsonNode) = + ## Converts `node` to its JSON Representation, without + ## regard for human readability. Meant to improve ``$`` string + ## conversion performance. + ## + ## This provides higher efficiency than the ``toPretty`` procedure as it + ## does **not** attempt to format the resulting JSON to make it human readable. + var comma = false + case node.kind: + of JArray: + result.add "[" + for child in node.elems: + if comma: result.add "," + else: comma = true + result.toUgly child + result.add "]" + of JObject: + result.add "{" + for key, value in items(node.fields): + if comma: result.add "," + else: comma = true + result.add key.escapeJson() + result.add ":" + result.toUgly value + result.add "}" + of JString: + result.add node.str.escapeJson() + of JInt: + result.add($node.num) + of JFloat: + result.add($node.fnum) + of JBool: + result.add(if node.bval: "true" else: "false") + of JNull: + result.add "null" + proc `$`*(node: JsonNode): string = ## Converts `node` to its JSON Representation on one line. - result = "" - toPretty(result, node, 0, false) + result = newStringOfCap(node.len shl 1) + toUgly(result, node) iterator items*(node: JsonNode): JsonNode = ## Iterator for the items of `node`. `node` has to be a JArray. @@ -1153,7 +1189,7 @@ when false: when isMainModule: #var node = parse("{ \"test\": null }") #echo(node.existsKey("test56")) - + var parsed = parseFile("tests/testdata/jsontest.json") var parsed2 = parseFile("tests/testdata/jsontest2.json") @@ -1176,6 +1212,11 @@ when isMainModule: testJson{["c", "d"]} = %true assert(testJson["c"]["d"].bval) + # test `$` + let stringified = $testJson + let parsedAgain = parseJson(stringified) + assert(parsedAgain["b"].str == "asd") + # Bounds checking try: let a = testJson["a"][9] @@ -1192,17 +1233,17 @@ when isMainModule: except: assert(false, "EInvalidIndex thrown for valid index") - assert(testJson{"b"}.str=="asd", "Couldn't fetch a singly nested key with {}") - assert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil") + assert(testJson{"b"}.str=="asd", "Couldn't fetch a singly nested key with {}") + assert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil") assert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}") assert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil") assert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil") assert(testJson{"a"}==parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found") assert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil") - + # Generator: var j = %* [{"name": "John", "age": 30}, {"name": "Susan", "age": 31}] - assert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}] + assert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}] var j2 = %* [ @@ -1230,7 +1271,7 @@ when isMainModule: } ] assert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}] - + when not defined(testing): discard """ while true: diff --git a/lib/pure/math.nim b/lib/pure/math.nim index daa108460..a9e9010f6 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -85,7 +85,7 @@ proc fac*(n: int): int {.noSideEffect.} = proc isPowerOfTwo*(x: int): bool {.noSideEffect.} = ## returns true, if `x` is a power of two, false otherwise. ## Zero and negative numbers are not a power of two. - return (x != 0) and ((x and (x - 1)) == 0) + return (x > 0) and ((x and (x - 1)) == 0) proc nextPowerOfTwo*(x: int): int {.noSideEffect.} = ## returns `x` rounded up to the nearest power of two. @@ -114,18 +114,23 @@ proc sum*[T](x: openArray[T]): T {.noSideEffect.} = ## If `x` is empty, 0 is returned. for i in items(x): result = result + i -proc mean*(x: openArray[float]): float {.noSideEffect.} = - ## computes the mean of the elements in `x`. +template toFloat(f: float): float = f + +proc mean*[T](x: openArray[T]): float {.noSideEffect.} = + ## computes the mean of the elements in `x`, which are first converted to floats. ## If `x` is empty, NaN is returned. - result = sum(x) / toFloat(len(x)) + ## ``toFloat(x: T): float`` must be defined. + for i in items(x): result = result + toFloat(i) + result = result / toFloat(len(x)) -proc variance*(x: openArray[float]): float {.noSideEffect.} = +proc variance*[T](x: openArray[T]): float {.noSideEffect.} = ## computes the variance of the elements in `x`. ## If `x` is empty, NaN is returned. + ## ``toFloat(x: T): float`` must be defined. result = 0.0 var m = mean(x) - for i in 0 .. high(x): - var diff = x[i] - m + for i in items(x): + var diff = toFloat(i) - m result = result + diff*diff result = result / toFloat(len(x)) @@ -347,6 +352,9 @@ proc `^`*[T](x, y: T): T = proc gcd*[T](x, y: T): T = ## Computes the greatest common divisor of ``x`` and ``y``. + ## Note that for floats, the result cannot always be interpreted as + ## "greatest decimal `z` such that ``z*N == x and z*M == y`` + ## where N and M are positive integers." var (x,y) = (x,y) while y != 0: x = x mod y diff --git a/lib/pure/net.nim b/lib/pure/net.nim index ffbc6e320..cf37c271e 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -704,7 +704,7 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int, proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {. tags: [ReadIOEffect, TimeEffect].} = - ## overload with a ``timeout`` parameter in miliseconds. + ## overload with a ``timeout`` parameter in milliseconds. var waited = 0.0 # number of seconds already waited var read = 0 @@ -729,7 +729,7 @@ proc recv*(socket: Socket, data: var string, size: int, timeout = -1, ## This function will throw an EOS exception when an error occurs. A value ## lower than 0 is never returned. ## - ## A timeout may be specified in miliseconds, if enough data is not received + ## A timeout may be specified in milliseconds, if enough data is not received ## within the time specified an ETimeout exception will be raised. ## ## **Note**: ``data`` must be initialised. @@ -777,7 +777,7 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1, ## ## An EOS exception will be raised in the case of a socket error. ## - ## A timeout can be specified in miliseconds, if data is not received within + ## A timeout can be specified in milliseconds, if data is not received within ## the specified time an ETimeout exception will be raised. ## ## **Warning**: Only the ``SafeDisconn`` flag is currently supported. @@ -844,7 +844,7 @@ proc recvFrom*(socket: Socket, data: var string, length: int, proc skip*(socket: Socket, size: int, timeout = -1) = ## Skips ``size`` amount of bytes. ## - ## An optional timeout can be specified in miliseconds, if skipping the + ## An optional timeout can be specified in milliseconds, if skipping the ## bytes takes longer than specified an ETimeout exception will be raised. ## ## Returns the number of skipped bytes. @@ -967,7 +967,7 @@ proc connect*(socket: Socket, address: string, port = Port(0), timeout: int, af: Domain = AF_INET) {.tags: [ReadIOEffect, WriteIOEffect].} = ## Connects to server as specified by ``address`` on port specified by ``port``. ## - ## The ``timeout`` paremeter specifies the time in miliseconds to allow for + ## The ``timeout`` paremeter specifies the time in milliseconds to allow for ## the connection to the server to be made. socket.fd.setBlocking(false) diff --git a/lib/pure/os.nim b/lib/pure/os.nim index f53abe81d..3a5bcbfa1 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -2033,10 +2033,10 @@ proc getFileInfo*(path: string, followSymlink = true): FileInfo = else: var rawInfo: TStat if followSymlink: - if lstat(path, rawInfo) < 0'i32: + if stat(path, rawInfo) < 0'i32: raiseOSError(osLastError()) else: - if stat(path, rawInfo) < 0'i32: + if lstat(path, rawInfo) < 0'i32: raiseOSError(osLastError()) rawToFormalFileInfo(rawInfo, result) diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index dce0673ba..dc6f21174 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -195,43 +195,43 @@ proc peekExitCode*(p: Process): int {.tags: [].} proc inputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## returns ``p``'s input stream for writing to. ## - ## **Warning**: The returned `PStream` should not be closed manually as it - ## is closed when closing the PProcess ``p``. + ## **Warning**: The returned `Stream` should not be closed manually as it + ## is closed when closing the Process ``p``. proc outputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## returns ``p``'s output stream for reading from. ## - ## **Warning**: The returned `PStream` should not be closed manually as it - ## is closed when closing the PProcess ``p``. + ## **Warning**: The returned `Stream` should not be closed manually as it + ## is closed when closing the Process ``p``. proc errorStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## returns ``p``'s error stream for reading from. ## - ## **Warning**: The returned `PStream` should not be closed manually as it - ## is closed when closing the PProcess ``p``. + ## **Warning**: The returned `Stream` should not be closed manually as it + ## is closed when closing the Process ``p``. proc inputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", tags: [].} = ## returns ``p``'s input file handle for writing to. ## - ## **Warning**: The returned `TFileHandle` should not be closed manually as - ## it is closed when closing the PProcess ``p``. + ## **Warning**: The returned `FileHandle` should not be closed manually as + ## it is closed when closing the Process ``p``. result = p.inHandle proc outputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", tags: [].} = ## returns ``p``'s output file handle for reading from. ## - ## **Warning**: The returned `TFileHandle` should not be closed manually as - ## it is closed when closing the PProcess ``p``. + ## **Warning**: The returned `FileHandle` should not be closed manually as + ## it is closed when closing the Process ``p``. result = p.outHandle proc errorHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", tags: [].} = ## returns ``p``'s error file handle for reading from. ## - ## **Warning**: The returned `TFileHandle` should not be closed manually as - ## it is closed when closing the PProcess ``p``. + ## **Warning**: The returned `FileHandle` should not be closed manually as + ## it is closed when closing the Process ``p``. result = p.errHandle proc countProcessors*(): int {.rtl, extern: "nosp$1".} = @@ -303,7 +303,7 @@ proc execProcesses*(cmds: openArray[string], close(p) proc select*(readfds: var seq[Process], timeout = 500): int - ## `select` with a sensible Nim interface. `timeout` is in miliseconds. + ## `select` with a sensible Nim interface. `timeout` is in milliseconds. ## Specify -1 for no timeout. Returns the number of processes that are ## ready to read from. The processes that are ready to be read from are ## removed from `readfds`. diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim index a30c23ada..d08c5b769 100644 --- a/lib/pure/rawsockets.nim +++ b/lib/pure/rawsockets.nim @@ -392,7 +392,7 @@ proc select*(readfds: var seq[SocketHandle], timeout = 500): int = ## Traditional select function. This function will return the number of ## sockets that are ready to be read from, written to, or which have errors. ## If there are none; 0 is returned. - ## ``Timeout`` is in miliseconds and -1 can be specified for no timeout. + ## ``Timeout`` is in milliseconds and -1 can be specified for no timeout. ## ## A socket is removed from the specific ``seq`` when it has data waiting to ## be read/written to or has errors (``exceptfds``). @@ -416,7 +416,7 @@ proc selectWrite*(writefds: var seq[SocketHandle], ## written to. The sockets which can be written to will also be removed ## from ``writefds``. ## - ## ``timeout`` is specified in miliseconds and ``-1`` can be specified for + ## ``timeout`` is specified in milliseconds and ``-1`` can be specified for ## an unlimited time. var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout) diff --git a/lib/pure/scgi.nim b/lib/pure/scgi.nim index f3e2b583c..3de422c87 100644 --- a/lib/pure/scgi.nim +++ b/lib/pure/scgi.nim @@ -126,7 +126,7 @@ proc close*(s: var ScgiState) = s.server.close() proc next*(s: var ScgiState, timeout: int = -1): bool = - ## proceed to the first/next request. Waits ``timeout`` miliseconds for a + ## proceed to the first/next request. Waits ``timeout`` milliseconds for a ## request, if ``timeout`` is `-1` then this function will never time out. ## Returns `true` if a new request has been processed. var rsocks = @[s.server] diff --git a/lib/pure/sexp.nim b/lib/pure/sexp.nim new file mode 100644 index 000000000..3c9fbc150 --- /dev/null +++ b/lib/pure/sexp.nim @@ -0,0 +1,697 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2015 Andreas Rumpf, Dominik Picheta +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +import + hashes, strutils, lexbase, streams, unicode, macros + +type + SexpEventKind* = enum ## enumeration of all events that may occur when parsing + sexpError, ## an error occurred during parsing + sexpEof, ## end of file reached + sexpString, ## a string literal + sexpSymbol, ## a symbol + sexpInt, ## an integer literal + sexpFloat, ## a float literal + sexpNil, ## the value ``nil`` + sexpDot, ## the dot to separate car/cdr + sexpListStart, ## start of a list: the ``(`` token + sexpListEnd, ## end of a list: the ``)`` token + + TTokKind = enum # must be synchronized with SexpEventKind! + tkError, + tkEof, + tkString, + tkSymbol, + tkInt, + tkFloat, + tkNil, + tkDot, + tkParensLe, + tkParensRi + tkSpace + + SexpError* = enum ## enumeration that lists all errors that can occur + errNone, ## no error + errInvalidToken, ## invalid token + errParensRiExpected, ## ``)`` expected + errQuoteExpected, ## ``"`` expected + errEofExpected, ## EOF expected + + SexpParser* = object of BaseLexer ## the parser object. + a: string + tok: TTokKind + kind: SexpEventKind + err: SexpError + +const + errorMessages: array [SexpError, string] = [ + "no error", + "invalid token", + "')' expected", + "'\"' or \"'\" expected", + "EOF expected", + ] + tokToStr: array [TTokKind, string] = [ + "invalid token", + "EOF", + "string literal", + "symbol", + "int literal", + "float literal", + "nil", + ".", + "(", ")", "space" + ] + +proc close*(my: var SexpParser) {.inline.} = + ## closes the parser `my` and its associated input stream. + lexbase.close(my) + +proc str*(my: SexpParser): string {.inline.} = + ## returns the character data for the events: ``sexpInt``, ``sexpFloat``, + ## ``sexpString`` + assert(my.kind in {sexpInt, sexpFloat, sexpString}) + result = my.a + +proc getInt*(my: SexpParser): BiggestInt {.inline.} = + ## returns the number for the event: ``sexpInt`` + assert(my.kind == sexpInt) + result = parseBiggestInt(my.a) + +proc getFloat*(my: SexpParser): float {.inline.} = + ## returns the number for the event: ``sexpFloat`` + assert(my.kind == sexpFloat) + result = parseFloat(my.a) + +proc kind*(my: SexpParser): SexpEventKind {.inline.} = + ## returns the current event type for the SEXP parser + result = my.kind + +proc getColumn*(my: SexpParser): int {.inline.} = + ## get the current column the parser has arrived at. + result = getColNumber(my, my.bufpos) + +proc getLine*(my: SexpParser): int {.inline.} = + ## get the current line the parser has arrived at. + result = my.lineNumber + +proc errorMsg*(my: SexpParser): string = + ## returns a helpful error message for the event ``sexpError`` + assert(my.kind == sexpError) + result = "($1, $2) Error: $3" % [$getLine(my), $getColumn(my), errorMessages[my.err]] + +proc errorMsgExpected*(my: SexpParser, e: string): string = + ## returns an error message "`e` expected" in the same format as the + ## other error messages + result = "($1, $2) Error: $3" % [$getLine(my), $getColumn(my), e & " expected"] + +proc handleHexChar(c: char, x: var int): bool = + result = true # Success + case c + of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) + of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10) + of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) + else: result = false # error + +proc parseString(my: var SexpParser): TTokKind = + result = tkString + var pos = my.bufpos + 1 + var buf = my.buf + while true: + case buf[pos] + of '\0': + my.err = errQuoteExpected + result = tkError + break + of '"': + inc(pos) + break + of '\\': + case buf[pos+1] + of '\\', '"', '\'', '/': + add(my.a, buf[pos+1]) + inc(pos, 2) + of 'b': + add(my.a, '\b') + inc(pos, 2) + of 'f': + add(my.a, '\f') + inc(pos, 2) + of 'n': + add(my.a, '\L') + inc(pos, 2) + of 'r': + add(my.a, '\C') + inc(pos, 2) + of 't': + add(my.a, '\t') + inc(pos, 2) + of 'u': + inc(pos, 2) + var r: int + if handleHexChar(buf[pos], r): inc(pos) + if handleHexChar(buf[pos], r): inc(pos) + if handleHexChar(buf[pos], r): inc(pos) + if handleHexChar(buf[pos], r): inc(pos) + add(my.a, toUTF8(Rune(r))) + else: + # don't bother with the error + add(my.a, buf[pos]) + inc(pos) + of '\c': + pos = lexbase.handleCR(my, pos) + buf = my.buf + add(my.a, '\c') + of '\L': + pos = lexbase.handleLF(my, pos) + buf = my.buf + add(my.a, '\L') + else: + add(my.a, buf[pos]) + inc(pos) + my.bufpos = pos # store back + +proc parseNumber(my: var SexpParser) = + var pos = my.bufpos + var buf = my.buf + if buf[pos] == '-': + add(my.a, '-') + inc(pos) + if buf[pos] == '.': + add(my.a, "0.") + inc(pos) + else: + while buf[pos] in Digits: + add(my.a, buf[pos]) + inc(pos) + if buf[pos] == '.': + add(my.a, '.') + inc(pos) + # digits after the dot: + while buf[pos] in Digits: + add(my.a, buf[pos]) + inc(pos) + if buf[pos] in {'E', 'e'}: + add(my.a, buf[pos]) + inc(pos) + if buf[pos] in {'+', '-'}: + add(my.a, buf[pos]) + inc(pos) + while buf[pos] in Digits: + add(my.a, buf[pos]) + inc(pos) + my.bufpos = pos + +proc parseSymbol(my: var SexpParser) = + var pos = my.bufpos + var buf = my.buf + if buf[pos] in IdentStartChars: + while buf[pos] in IdentChars: + add(my.a, buf[pos]) + inc(pos) + my.bufpos = pos + +proc getTok(my: var SexpParser): TTokKind = + setLen(my.a, 0) + case my.buf[my.bufpos] + of '-', '0'..'9': # numbers that start with a . are not parsed + # correctly. + parseNumber(my) + if {'.', 'e', 'E'} in my.a: + result = tkFloat + else: + result = tkInt + of '"': #" # gotta fix nim-mode + result = parseString(my) + of '(': + inc(my.bufpos) + result = tkParensLe + of ')': + inc(my.bufpos) + result = tkParensRi + of '\0': + result = tkEof + of 'a'..'z', 'A'..'Z', '_': + parseSymbol(my) + if my.a == "nil": + result = tkNil + else: + result = tkSymbol + of ' ': + result = tkSpace + inc(my.bufpos) + of '.': + result = tkDot + inc(my.bufpos) + else: + inc(my.bufpos) + result = tkError + my.tok = result + +# ------------- higher level interface --------------------------------------- + +type + SexpNodeKind* = enum ## possible SEXP node types + SNil, + SInt, + SFloat, + SString, + SSymbol, + SList, + SCons + + SexpNode* = ref SexpNodeObj ## SEXP node + SexpNodeObj* {.acyclic.} = object + case kind*: SexpNodeKind + of SString: + str*: string + of SSymbol: + symbol*: string + of SInt: + num*: BiggestInt + of SFloat: + fnum*: float + of SList: + elems*: seq[SexpNode] + of SCons: + car: SexpNode + cdr: SexpNode + of SNil: + discard + + Cons = tuple[car: SexpNode, cdr: SexpNode] + + SexpParsingError* = object of ValueError ## is raised for a SEXP error + +proc raiseParseErr*(p: SexpParser, msg: string) {.noinline, noreturn.} = + ## raises an `ESexpParsingError` exception. + raise newException(SexpParsingError, errorMsgExpected(p, msg)) + +proc newSString*(s: string): SexpNode {.procvar.}= + ## Creates a new `SString SexpNode`. + new(result) + result.kind = SString + result.str = s + +proc newSStringMove(s: string): SexpNode = + new(result) + result.kind = SString + shallowCopy(result.str, s) + +proc newSInt*(n: BiggestInt): SexpNode {.procvar.} = + ## Creates a new `SInt SexpNode`. + new(result) + result.kind = SInt + result.num = n + +proc newSFloat*(n: float): SexpNode {.procvar.} = + ## Creates a new `SFloat SexpNode`. + new(result) + result.kind = SFloat + result.fnum = n + +proc newSNil*(): SexpNode {.procvar.} = + ## Creates a new `SNil SexpNode`. + new(result) + +proc newSCons*(car, cdr: SexpNode): SexpNode {.procvar.} = + ## Creates a new `SCons SexpNode` + new(result) + result.kind = SCons + result.car = car + result.cdr = cdr + +proc newSList*(): SexpNode {.procvar.} = + ## Creates a new `SList SexpNode` + new(result) + result.kind = SList + result.elems = @[] + +proc newSSymbol*(s: string): SexpNode {.procvar.} = + new(result) + result.kind = SSymbol + result.symbol = s + +proc newSSymbolMove(s: string): SexpNode = + new(result) + result.kind = SSymbol + shallowCopy(result.symbol, s) + +proc getStr*(n: SexpNode, default: string = ""): string = + ## Retrieves the string value of a `SString SexpNode`. + ## + ## Returns ``default`` if ``n`` is not a ``SString``. + if n.kind != SString: return default + else: return n.str + +proc getNum*(n: SexpNode, default: BiggestInt = 0): BiggestInt = + ## Retrieves the int value of a `SInt SexpNode`. + ## + ## Returns ``default`` if ``n`` is not a ``SInt``. + if n.kind != SInt: return default + else: return n.num + +proc getFNum*(n: SexpNode, default: float = 0.0): float = + ## Retrieves the float value of a `SFloat SexpNode`. + ## + ## Returns ``default`` if ``n`` is not a ``SFloat``. + if n.kind != SFloat: return default + else: return n.fnum + +proc getSymbol*(n: SexpNode, default: string = ""): string = + ## Retrieves the int value of a `SList SexpNode`. + ## + ## Returns ``default`` if ``n`` is not a ``SList``. + if n.kind != SSymbol: return default + else: return n.symbol + +proc getElems*(n: SexpNode, default: seq[SexpNode] = @[]): seq[SexpNode] = + ## Retrieves the int value of a `SList SexpNode`. + ## + ## Returns ``default`` if ``n`` is not a ``SList``. + if n.kind == SNil: return @[] + elif n.kind != SList: return default + else: return n.elems + +proc getCons*(n: SexpNode, defaults: Cons = (newSNil(), newSNil())): Cons = + ## Retrieves the cons value of a `SList SexpNode`. + ## + ## Returns ``default`` if ``n`` is not a ``SList``. + if n.kind == SCons: return (n.car, n.cdr) + elif n.kind == SList: return (n.elems[0], n.elems[1]) + else: return defaults + +proc sexp*(s: string): SexpNode = + ## Generic constructor for SEXP data. Creates a new `SString SexpNode`. + new(result) + result.kind = SString + result.str = s + +proc sexp*(n: BiggestInt): SexpNode = + ## Generic constructor for SEXP data. Creates a new `SInt SexpNode`. + new(result) + result.kind = SInt + result.num = n + +proc sexp*(n: float): SexpNode = + ## Generic constructor for SEXP data. Creates a new `SFloat SexpNode`. + new(result) + result.kind = SFloat + result.fnum = n + +proc sexp*(b: bool): SexpNode = + ## Generic constructor for SEXP data. Creates a new `SSymbol + ## SexpNode` with value t or `SNil SexpNode`. + new(result) + if b: + result.kind = SSymbol + result.symbol = "t" + else: + result.kind = SNil + +proc sexp*(elements: openArray[SexpNode]): SexpNode = + ## Generic constructor for SEXP data. Creates a new `SList SexpNode` + new(result) + result.kind = SList + newSeq(result.elems, elements.len) + for i, p in pairs(elements): result.elems[i] = p + +proc sexp*(s: SexpNode): SexpNode = + result = s + +proc toSexp(x: NimNode): NimNode {.compiletime.} = + case x.kind + of nnkBracket: + result = newNimNode(nnkBracket) + for i in 0 .. <x.len: + result.add(toSexp(x[i])) + + else: + result = x + + result = prefix(result, "sexp") + +macro convertSexp*(x: expr): expr = + ## Convert an expression to a SexpNode directly, without having to specify + ## `%` for every element. + result = toSexp(x) + +proc `==`* (a,b: SexpNode): bool = + ## Check two nodes for equality + if a.isNil: + if b.isNil: return true + return false + elif b.isNil or a.kind != b.kind: + return false + else: + return case a.kind + of SString: + a.str == b.str + of SInt: + a.num == b.num + of SFloat: + a.fnum == b.fnum + of SNil: + true + of SList: + a.elems == b.elems + of SSymbol: + a.symbol == b.symbol + of SCons: + a.car == b.car and a.cdr == b.cdr + +proc hash* (n:SexpNode): THash = + ## Compute the hash for a SEXP node + case n.kind + of SList: + result = hash(n.elems) + of SInt: + result = hash(n.num) + of SFloat: + result = hash(n.fnum) + of SString: + result = hash(n.str) + of SNil: + result = hash(0) + of SSymbol: + result = hash(n.symbol) + of SCons: + result = hash(n.car) !& hash(n.cdr) + +proc len*(n: SexpNode): int = + ## If `n` is a `SList`, it returns the number of elements. + ## If `n` is a `JObject`, it returns the number of pairs. + ## Else it returns 0. + case n.kind + of SList: result = n.elems.len + else: discard + +proc `[]`*(node: SexpNode, index: int): SexpNode = + ## Gets the node at `index` in a List. Result is undefined if `index` + ## is out of bounds + assert(not isNil(node)) + assert(node.kind == SList) + return node.elems[index] + +proc add*(father, child: SexpNode) = + ## Adds `child` to a SList node `father`. + assert father.kind == SList + father.elems.add(child) + +# ------------- pretty printing ---------------------------------------------- + +proc indent(s: var string, i: int) = + s.add(spaces(i)) + +proc newIndent(curr, indent: int, ml: bool): int = + if ml: return curr + indent + else: return indent + +proc nl(s: var string, ml: bool) = + if ml: s.add("\n") + +proc escapeJson*(s: string): string = + ## Converts a string `s` to its JSON representation. + result = newStringOfCap(s.len + s.len shr 3) + result.add("\"") + for x in runes(s): + var r = int(x) + if r >= 32 and r <= 127: + var c = chr(r) + case c + of '"': result.add("\\\"") #" # gotta fix nim-mode + of '\\': result.add("\\\\") + else: result.add(c) + else: + result.add("\\u") + result.add(toHex(r, 4)) + result.add("\"") + +proc copy*(p: SexpNode): SexpNode = + ## Performs a deep copy of `a`. + case p.kind + of SString: + result = newSString(p.str) + of SInt: + result = newSInt(p.num) + of SFloat: + result = newSFloat(p.fnum) + of SNil: + result = newSNil() + of SSymbol: + result = newSSymbol(p.symbol) + of SList: + result = newSList() + for i in items(p.elems): + result.elems.add(copy(i)) + of SCons: + result = newSCons(copy(p.car), copy(p.cdr)) + +proc toPretty(result: var string, node: SexpNode, indent = 2, ml = true, + lstArr = false, currIndent = 0) = + case node.kind + of SString: + if lstArr: result.indent(currIndent) + result.add(escapeJson(node.str)) + of SInt: + if lstArr: result.indent(currIndent) + result.add($node.num) + of SFloat: + if lstArr: result.indent(currIndent) + result.add($node.fnum) + of SNil: + if lstArr: result.indent(currIndent) + result.add("nil") + of SSymbol: + if lstArr: result.indent(currIndent) + result.add($node.symbol) + of SList: + if lstArr: result.indent(currIndent) + if len(node.elems) != 0: + result.add("(") + result.nl(ml) + for i in 0..len(node.elems)-1: + if i > 0: + result.add(" ") + result.nl(ml) # New Line + toPretty(result, node.elems[i], indent, ml, + true, newIndent(currIndent, indent, ml)) + result.nl(ml) + result.indent(currIndent) + result.add(")") + else: result.add("nil") + of SCons: + if lstArr: result.indent(currIndent) + result.add("(") + toPretty(result, node.car, indent, ml, + true, newIndent(currIndent, indent, ml)) + result.add(" . ") + toPretty(result, node.cdr, indent, ml, + true, newIndent(currIndent, indent, ml)) + result.add(")") + +proc pretty*(node: SexpNode, indent = 2): string = + ## Converts `node` to its Sexp Representation, with indentation and + ## on multiple lines. + result = "" + toPretty(result, node, indent) + +proc `$`*(node: SexpNode): string = + ## Converts `node` to its SEXP Representation on one line. + result = "" + toPretty(result, node, 0, false) + +iterator items*(node: SexpNode): SexpNode = + ## Iterator for the items of `node`. `node` has to be a SList. + assert node.kind == SList + for i in items(node.elems): + yield i + +iterator mitems*(node: var SexpNode): var SexpNode = + ## Iterator for the items of `node`. `node` has to be a SList. Items can be + ## modified. + assert node.kind == SList + for i in mitems(node.elems): + yield i + +proc eat(p: var SexpParser, tok: TTokKind) = + if p.tok == tok: discard getTok(p) + else: raiseParseErr(p, tokToStr[tok]) + +proc parseSexp(p: var SexpParser): SexpNode = + ## Parses SEXP from a SEXP Parser `p`. + case p.tok + of tkString: + # we capture 'p.a' here, so we need to give it a fresh buffer afterwards: + result = newSStringMove(p.a) + p.a = "" + discard getTok(p) + of tkInt: + result = newSInt(parseBiggestInt(p.a)) + discard getTok(p) + of tkFloat: + result = newSFloat(parseFloat(p.a)) + discard getTok(p) + of tkNil: + result = newSNil() + discard getTok(p) + of tkSymbol: + result = newSSymbolMove(p.a) + p.a = "" + discard getTok(p) + of tkParensLe: + result = newSList() + discard getTok(p) + while p.tok notin {tkParensRi, tkDot}: + result.add(parseSexp(p)) + if p.tok != tkSpace: break + discard getTok(p) + if p.tok == tkDot: + eat(p, tkDot) + eat(p, tkSpace) + result.add(parseSexp(p)) + result = newSCons(result[0], result[1]) + eat(p, tkParensRi) + of tkSpace, tkDot, tkError, tkParensRi, tkEof: + raiseParseErr(p, "(") + +proc open*(my: var SexpParser, input: Stream) = + ## initializes the parser with an input stream. + lexbase.open(my, input) + my.kind = sexpError + my.a = "" + +proc parseSexp*(s: Stream): SexpNode = + ## Parses from a buffer `s` into a `SexpNode`. + var p: SexpParser + p.open(s) + discard getTok(p) # read first token + result = p.parseSexp() + p.close() + +proc parseSexp*(buffer: string): SexpNode = + ## Parses Sexp from `buffer`. + result = parseSexp(newStringStream(buffer)) + +when isMainModule: + let testSexp = parseSexp("""(1 (98 2) nil (2) foobar "foo" 9.234)""") + assert(testSexp[0].getNum == 1) + assert(testSexp[1][0].getNum == 98) + assert(testSexp[2].getElems == @[]) + assert(testSexp[4].getSymbol == "foobar") + assert(testSexp[5].getStr == "foo") + + let alist = parseSexp("""((1 . 2) (2 . "foo"))""") + assert(alist[0].getCons.car.getNum == 1) + assert(alist[0].getCons.cdr.getNum == 2) + assert(alist[1].getCons.cdr.getStr == "foo") + + # Generator: + var j = convertSexp([true, false, "foobar", [1, 2, "baz"]]) + assert($j == """(t nil "foobar" (1 2 "baz"))""") diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim index 3afb545c8..64e2cdcd3 100644 --- a/lib/pure/sockets.nim +++ b/lib/pure/sockets.nim @@ -986,7 +986,7 @@ proc select*(readfds, writefds, exceptfds: var seq[Socket], ## Traditional select function. This function will return the number of ## sockets that are ready to be read from, written to, or which have errors. ## If there are none; 0 is returned. - ## ``Timeout`` is in miliseconds and -1 can be specified for no timeout. + ## ``Timeout`` is in milliseconds and -1 can be specified for no timeout. ## ## Sockets which are **not** ready for reading, writing or which don't have ## errors waiting on them are removed from the ``readfds``, ``writefds``, @@ -1040,7 +1040,7 @@ proc selectWrite*(writefds: var seq[Socket], ## written to. The sockets which **cannot** be written to will also be removed ## from ``writefds``. ## - ## ``timeout`` is specified in miliseconds and ``-1`` can be specified for + ## ``timeout`` is specified in milliseconds and ``-1`` can be specified for ## an unlimited time. var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout) @@ -1174,7 +1174,7 @@ proc waitFor(socket: Socket, waited: var float, timeout, size: int, proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {. tags: [ReadIOEffect, TimeEffect].} = - ## overload with a ``timeout`` parameter in miliseconds. + ## overload with a ``timeout`` parameter in milliseconds. var waited = 0.0 # number of seconds already waited var read = 0 @@ -1197,7 +1197,7 @@ proc recv*(socket: Socket, data: var string, size: int, timeout = -1): int = ## This function will throw an EOS exception when an error occurs. A value ## lower than 0 is never returned. ## - ## A timeout may be specified in miliseconds, if enough data is not received + ## A timeout may be specified in milliseconds, if enough data is not received ## within the time specified an ETimeout exception will be raised. ## ## **Note**: ``data`` must be initialised. @@ -1258,7 +1258,7 @@ proc recvLine*(socket: Socket, line: var TaintedString, timeout = -1): bool {. ## If the socket is disconnected, ``line`` will be set to ``""`` and ``True`` ## will be returned. ## - ## A timeout can be specified in miliseconds, if data is not received within + ## A timeout can be specified in milliseconds, if data is not received within ## the specified time an ETimeout exception will be raised. ## ## **Deprecated since version 0.9.2**: This function has been deprecated in @@ -1302,7 +1302,7 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1) {. ## ## An EOS exception will be raised in the case of a socket error. ## - ## A timeout can be specified in miliseconds, if data is not received within + ## A timeout can be specified in milliseconds, if data is not received within ## the specified time an ETimeout exception will be raised. template addNLIfEmpty(): stmt = @@ -1433,7 +1433,7 @@ proc recv*(socket: Socket): TaintedString {.tags: [ReadIOEffect], deprecated.} = proc recvTimeout*(socket: Socket, timeout: int): TaintedString {. tags: [ReadIOEffect], deprecated.} = ## overloaded variant to support a ``timeout`` parameter, the ``timeout`` - ## parameter specifies the amount of miliseconds to wait for data on the + ## parameter specifies the amount of milliseconds to wait for data on the ## socket. ## ## **Deprecated since version 0.9.2**: This function is not safe for use. @@ -1554,7 +1554,7 @@ proc skip*(socket: Socket) {.tags: [ReadIOEffect], deprecated.} = proc skip*(socket: Socket, size: int, timeout = -1) = ## Skips ``size`` amount of bytes. ## - ## An optional timeout can be specified in miliseconds, if skipping the + ## An optional timeout can be specified in milliseconds, if skipping the ## bytes takes longer than specified an ETimeout exception will be raised. ## ## Returns the number of skipped bytes. @@ -1708,7 +1708,7 @@ proc connect*(socket: Socket, address: string, port = Port(0), timeout: int, af: Domain = AF_INET) {.tags: [ReadIOEffect, WriteIOEffect].} = ## Connects to server as specified by ``address`` on port specified by ``port``. ## - ## The ``timeout`` paremeter specifies the time in miliseconds to allow for + ## The ``timeout`` paremeter specifies the time in milliseconds to allow for ## the connection to the server to be made. let originalStatus = not socket.nonblocking socket.setBlocking(false) diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index e706f2016..77698d329 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -1,7 +1,7 @@ # # # Nim's Runtime Library -# (c) Copyright 2012 Andreas Rumpf +# (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -31,6 +31,8 @@ type getPositionImpl*: proc (s: Stream): int {.nimcall, tags: [], gcsafe.} readDataImpl*: proc (s: Stream, buffer: pointer, bufLen: int): int {.nimcall, tags: [ReadIOEffect], gcsafe.} + peekDataImpl*: proc (s: Stream, buffer: pointer, + bufLen: int): int {.nimcall, tags: [ReadIOEffect], gcsafe.} writeDataImpl*: proc (s: Stream, buffer: pointer, bufLen: int) {.nimcall, tags: [WriteIOEffect], gcsafe.} flushImpl*: proc (s: Stream) {.nimcall, tags: [WriteIOEffect], gcsafe.} @@ -84,6 +86,11 @@ proc readData*(s, unused: Stream, buffer: pointer, ## low level proc that reads data into an untyped `buffer` of `bufLen` size. result = s.readDataImpl(s, buffer, bufLen) +proc peekData*(s: Stream, buffer: pointer, bufLen: int): int = + ## low level proc that reads data into an untyped `buffer` of `bufLen` size + ## without moving stream position + result = s.peekDataImpl(s, buffer, bufLen) + proc writeData*(s: Stream, buffer: pointer, bufLen: int) = ## low level proc that writes an untyped `buffer` of `bufLen` size ## to the stream `s`. @@ -121,39 +128,77 @@ proc read[T](s: Stream, result: var T) = if readData(s, addr(result), sizeof(T)) != sizeof(T): raise newEIO("cannot read from stream") +proc peek[T](s: Stream, result: var T) = + ## generic peek procedure. Peeks `result` from the stream `s`. + if peekData(s, addr(result), sizeof(T)) != sizeof(T): + raise newEIO("cannot read from stream") + proc readChar*(s: Stream): char = ## reads a char from the stream `s`. Raises `EIO` if an error occurred. ## Returns '\0' as an EOF marker. if readData(s, addr(result), sizeof(result)) != 1: result = '\0' +proc peekChar*(s: Stream): char = + ## peeks a char from the stream `s`. Raises `EIO` if an error occurred. + ## Returns '\0' as an EOF marker. + if peekData(s, addr(result), sizeof(result)) != 1: result = '\0' + proc readBool*(s: Stream): bool = ## reads a bool from the stream `s`. Raises `EIO` if an error occurred. read(s, result) +proc peekBool*(s: Stream): bool = + ## peeks a bool from the stream `s`. Raises `EIO` if an error occured. + peek(s, result) + proc readInt8*(s: Stream): int8 = ## reads an int8 from the stream `s`. Raises `EIO` if an error occurred. read(s, result) +proc peekInt8*(s: Stream): int8 = + ## peeks an int8 from the stream `s`. Raises `EIO` if an error occurred. + peek(s, result) + proc readInt16*(s: Stream): int16 = ## reads an int16 from the stream `s`. Raises `EIO` if an error occurred. read(s, result) +proc peekInt16*(s: Stream): int16 = + ## peeks an int16 from the stream `s`. Raises `EIO` if an error occurred. + peek(s, result) + proc readInt32*(s: Stream): int32 = ## reads an int32 from the stream `s`. Raises `EIO` if an error occurred. read(s, result) +proc peekInt32*(s: Stream): int32 = + ## peeks an int32 from the stream `s`. Raises `EIO` if an error occurred. + peek(s, result) + proc readInt64*(s: Stream): int64 = ## reads an int64 from the stream `s`. Raises `EIO` if an error occurred. read(s, result) +proc peekInt64*(s: Stream): int64 = + ## peeks an int64 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) +proc peekFloat32*(s: Stream): float32 = + ## peeks a float32 from the stream `s`. Raises `EIO` if an error occurred. + peek(s, result) + proc readFloat64*(s: Stream): float64 = ## reads a float64 from the stream `s`. Raises `EIO` if an error occurred. read(s, result) +proc peekFloat64*(s: Stream): float64 = + ## peeks a float64 from the stream `s`. Raises `EIO` if an error occurred. + peek(s, result) + proc readStr*(s: Stream, length: int): TaintedString = ## reads a string of length `length` from the stream `s`. Raises `EIO` if ## an error occurred. @@ -161,6 +206,13 @@ proc readStr*(s: Stream, length: int): TaintedString = var L = readData(s, addr(string(result)[0]), length) if L != length: setLen(result.string, L) +proc peekStr*(s: Stream, length: int): TaintedString = + ## peeks a string of length `length` from the stream `s`. Raises `EIO` if + ## an error occurred. + result = newString(length).TaintedString + var L = peekData(s, addr(string(result)[0]), length) + if L != length: setLen(result.string, L) + proc readLine*(s: Stream, line: var TaintedString): bool = ## reads a line of text from the stream `s` into `line`. `line` must not be ## ``nil``! May throw an IO exception. @@ -181,6 +233,17 @@ proc readLine*(s: Stream, line: var TaintedString): bool = line.string.add(c) result = true +proc peekLine*(s: Stream, line: var TaintedString): bool = + ## peeks a line of text from the stream `s` into `line`. `line` must not be + ## ``nil``! May throw an IO exception. + ## A line of text may be delimited by ``CR``, ``LF`` or + ## ``CRLF``. The newline character(s) are not part of the returned string. + ## Returns ``false`` if the end of the file has been reached, ``true`` + ## otherwise. If ``false`` is returned `line` contains no new data. + let pos = getPosition(s) + defer: setPosition(s, pos) + readLine(s, line) + proc readLine*(s: Stream): TaintedString = ## Reads a line from a stream `s`. Note: This is not very efficient. Raises ## `EIO` if an error occurred. @@ -195,6 +258,13 @@ proc readLine*(s: Stream): TaintedString = else: result.string.add(c) +proc peekLine*(s: Stream): TaintedString = + ## Peeks a line from a stream `s`. Note: This is not very efficient. Raises + ## `EIO` if an error occurred. + let pos = getPosition(s) + defer: setPosition(s, pos) + readLine(s) + type StringStream* = ref StringStreamObj ## a stream that encapsulates a string StringStreamObj* = object of StreamObj @@ -222,6 +292,12 @@ proc ssReadData(s: Stream, buffer: pointer, bufLen: int): int = copyMem(buffer, addr(s.data[s.pos]), result) inc(s.pos, result) +proc ssPeekData(s: Stream, buffer: pointer, bufLen: int): int = + var s = StringStream(s) + result = min(bufLen, s.data.len - s.pos) + if result > 0: + copyMem(buffer, addr(s.data[s.pos]), result) + proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) = var s = StringStream(s) if bufLen <= 0: @@ -245,6 +321,7 @@ proc newStringStream*(s: string = ""): StringStream = result.setPositionImpl = ssSetPosition result.getPositionImpl = ssGetPosition result.readDataImpl = ssReadData + result.peekDataImpl = ssPeekData result.writeDataImpl = ssWriteData when not defined(js): @@ -266,6 +343,11 @@ when not defined(js): proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int = result = readBuffer(FileStream(s).f, buffer, bufLen) + + proc fsPeekData(s: Stream, buffer: pointer, bufLen: int): int = + let pos = fsGetPosition(s) + defer: fsSetPosition(s, pos) + result = readBuffer(FileStream(s).f, buffer, bufLen) proc fsWriteData(s: Stream, buffer: pointer, bufLen: int) = if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen: @@ -280,6 +362,7 @@ when not defined(js): result.setPositionImpl = fsSetPosition result.getPositionImpl = fsGetPosition result.readDataImpl = fsReadData + result.peekDataImpl = fsPeekData result.writeDataImpl = fsWriteData result.flushImpl = fsFlush @@ -329,6 +412,9 @@ else: proc hsReadData(s: FileHandleStream, buffer: pointer, bufLen: int): int = result = posix.read(s.handle, buffer, bufLen) inc(s.pos, result) + + proc hsPeekData(s: FileHandleStream, buffer: pointer, bufLen: int): int = + result = posix.read(s.handle, buffer, bufLen) proc hsWriteData(s: FileHandleStream, buffer: pointer, bufLen: int) = if posix.write(s.handle, buffer, bufLen) != bufLen: @@ -344,6 +430,7 @@ else: result.setPosition = hsSetPosition result.getPosition = hsGetPosition result.readData = hsReadData + result.peekData = hsPeekData result.writeData = hsWriteData proc newFileHandleStream*(filename: string, @@ -361,3 +448,13 @@ else: var handle = open(filename, flags) if handle < 0: raise newEOS("posix.open() call failed") result = newFileHandleStream(handle) + +when defined(testing): + var ss = newStringStream("The quick brown fox jumped over the lazy dog.\nThe lazy dog ran") + assert(ss.getPosition == 0) + assert(ss.peekStr(5) == "The q") + assert(ss.getPosition == 0) # haven't moved + assert(ss.readStr(5) == "The q") + assert(ss.getPosition == 5) # did move + assert(ss.peekLine() == "uick brown fox jumped over the lazy dog.") + assert(ss.getPosition == 5) # haven't moved diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 59cebf7fa..eb4be719a 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -169,14 +169,12 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect, {.pop.} -proc strip*(s: string, leading = true, trailing = true): string {.noSideEffect, - rtl, extern: "nsuStrip".} = - ## Strips whitespace from `s` and returns the resulting string. +proc strip*(s: string, leading = true, trailing = true, chars: set[char] = Whitespace): string + {.noSideEffect, rtl, extern: "nsuStrip".} = + ## Strips `chars` from `s` and returns the resulting string. ## - ## If `leading` is true, leading whitespace is stripped. - ## If `trailing` is true, trailing whitespace is stripped. - const - chars: set[char] = Whitespace + ## If `leading` is true, leading `chars` are stripped. + ## If `trailing` is true, trailing `chars` are stripped. var first = 0 last = len(s)-1 @@ -1433,3 +1431,11 @@ when isMainModule: doAssert count("foofoofoo", "foofoo", overlapping = true) == 2 doAssert count("foofoofoo", 'f') == 3 doAssert count("foofoofoobar", {'f','b'}) == 4 + + doAssert strip(" foofoofoo ") == "foofoofoo" + doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo" + doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo" + doAssert strip("stripme but don't strip this stripme", + chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) == " but don't strip this " + doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo" + doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos" diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 5f8835c6a..b8836c15b 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -119,7 +119,7 @@ type ## in the range 0 to 23. monthday*: range[1..31] ## The day of the month, in the range 1 to 31. month*: Month ## The current month. - year*: range[-10_000..10_000] ## The current year. + year*: int ## The current year. weekday*: WeekDay ## The current day of the week. yearday*: range[0..365] ## The number of days since January 1, ## in the range 0 to 365. @@ -134,7 +134,7 @@ type ## everything should be positive or everything negative. Zero is ## fine too. Mixed signs will lead to unexpected results. TimeInterval* = object ## a time interval - miliseconds*: int ## The number of miliseconds + milliseconds*: int ## The number of milliseconds seconds*: int ## The number of seconds minutes*: int ## The number of minutes hours*: int ## The number of hours @@ -145,6 +145,11 @@ type {.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time, TTimeInterval: TimeInterval, TTimeInfo: TimeInfo].} +proc miliseconds*(t: TimeInterval): int {.deprecated.} = t.milliseconds + +proc `miliseconds=`*(t:var TimeInterval, milliseconds: int) {.deprecated.} = + t.milliseconds = milliseconds + proc getTime*(): Time {.tags: [TimeEffect], benign.} ## gets the current calendar time as a UNIX epoch value (number of seconds ## elapsed since 1970) with integer precission. Use epochTime for higher @@ -208,13 +213,13 @@ proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign.} ## returns the offset of the local (non-DST) timezone in seconds west of UTC. proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], benign.} - ## get the miliseconds from the start of the program. **Deprecated since + ## get the milliseconds from the start of the program. **Deprecated since ## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead. -proc initInterval*(miliseconds, seconds, minutes, hours, days, months, +proc initInterval*(milliseconds, seconds, minutes, hours, days, months, years: int = 0): TimeInterval = ## creates a new ``TimeInterval``. - result.miliseconds = miliseconds + result.milliseconds = milliseconds result.seconds = seconds result.minutes = minutes result.hours = hours @@ -264,7 +269,7 @@ proc toSeconds(a: TimeInfo, interval: TimeInterval): float = result += float(newinterv.hours * 60 * 60) result += float(newinterv.minutes * 60) result += float(newinterv.seconds) - result += newinterv.miliseconds / 1000 + result += newinterv.milliseconds / 1000 proc `+`*(a: TimeInfo, interval: TimeInterval): TimeInfo = ## adds ``interval`` time. @@ -379,7 +384,7 @@ when not defined(JS): result.hour = t.hour result.monthday = t.monthday result.month = ord(t.month) - result.year = t.year - 1900 + result.year = cint(t.year - 1900) result.weekday = weekDays[t.weekday] result.yearday = t.yearday result.isdst = if t.isDST: 1 else: 0 @@ -530,7 +535,7 @@ elif defined(JS): startMilsecs = getTime() proc getStartMilsecs(): int = - ## get the miliseconds from the start of the program + ## get the milliseconds from the start of the program return int(getTime() - startMilsecs) proc valueOf(time: Time): float {.importcpp: "getTime", tags:[]} diff --git a/lib/system.nim b/lib/system.nim index ca4c81411..1e6f76f3d 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1110,7 +1110,7 @@ var programResult* {.exportc: "nim_program_result".}: int ## prematurely using ``quit``, this value is ignored. proc quit*(errorcode: int = QuitSuccess) {. - magic: "Exit", importc: "exit", header: "<stdlib.h>", noReturn.} + magic: "Exit", importc: "exit", header: "<stdlib.h>", noreturn.} ## Stops the program immediately with an exit code. ## ## Before stopping the program the "quit procedures" are called in the @@ -2270,20 +2270,21 @@ when hostOS == "standalone": include panicoverride when not declared(sysFatal): - template sysFatal(exceptn: typedesc, message: string) = - when hostOS == "standalone": + when hostOS == "standalone": + proc sysFatal(exceptn: typedesc, message: string) {.inline.} = panic(message) - else: + + proc sysFatal(exceptn: typedesc, message, arg: string) {.inline.} = + rawoutput(message) + panic(arg) + else: + proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} = var e: ref exceptn new(e) e.msg = message raise e - template sysFatal(exceptn: typedesc, message, arg: string) = - when hostOS == "standalone": - rawoutput(message) - panic(arg) - else: + proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noReturn.} = var e: ref exceptn new(e) e.msg = message & arg diff --git a/lib/system/arithm.nim b/lib/system/arithm.nim index f68e2dcd9..ef153417c 100644 --- a/lib/system/arithm.nim +++ b/lib/system/arithm.nim @@ -10,11 +10,11 @@ # simple integer arithmetic with overflow checking -proc raiseOverflow {.compilerproc, noinline, noreturn.} = +proc raiseOverflow {.compilerproc, noinline.} = # a single proc to reduce code size to a minimum sysFatal(OverflowError, "over- or underflow") -proc raiseDivByZero {.compilerproc, noinline, noreturn.} = +proc raiseDivByZero {.compilerproc, noinline.} = sysFatal(DivByZeroError, "division by zero") proc addInt64(a, b: int64): int64 {.compilerProc, inline.} = @@ -327,13 +327,13 @@ when not declared(mulInt): # We avoid setting the FPU control word here for compatibility with libraries # written in other languages. -proc raiseFloatInvalidOp {.noinline, noreturn.} = +proc raiseFloatInvalidOp {.noinline.} = sysFatal(FloatInvalidOpError, "FPU operation caused a NaN result") proc nanCheck(x: float64) {.compilerProc, inline.} = if x != x: raiseFloatInvalidOp() -proc raiseFloatOverflow(x: float64) {.noinline, noreturn.} = +proc raiseFloatOverflow(x: float64) {.noinline.} = if x > 0.0: sysFatal(FloatOverflowError, "FPU operation caused an overflow") else: diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim index 2f6d25a12..6caf99d27 100644 --- a/lib/system/chcks.nim +++ b/lib/system/chcks.nim @@ -9,16 +9,16 @@ # Implementation of some runtime checks. -proc raiseRangeError(val: BiggestInt) {.compilerproc, noreturn, noinline.} = +proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} = when hostOS == "standalone": sysFatal(RangeError, "value out of range") else: sysFatal(RangeError, "value out of range: ", $val) -proc raiseIndexError() {.compilerproc, noreturn, noinline.} = +proc raiseIndexError() {.compilerproc, noinline.} = sysFatal(IndexError, "index out of bounds") -proc raiseFieldError(f: string) {.compilerproc, noreturn, noinline.} = +proc raiseFieldError(f: string) {.compilerproc, noinline.} = sysFatal(FieldError, f, " is not accessible") proc chckIndx(i, a, b: int): int = diff --git a/lib/windows/windows.nim b/lib/windows/windows.nim index b76dea6c5..02c87132a 100644 --- a/lib/windows/windows.nim +++ b/lib/windows/windows.nim @@ -18513,11 +18513,15 @@ proc DisableThreadLibraryCalls*(hLibModule: HMODULE): WINBOOL{.stdcall, proc GetProcAddress*(hModule: HINST, lpProcName: LPCSTR): FARPROC{.stdcall, dynlib: "kernel32", importc: "GetProcAddress".} proc GetVersion*(): DWORD{.stdcall, dynlib: "kernel32", importc: "GetVersion".} -proc GlobalAlloc*(uFlags: int32, dwBytes: DWORD): HGLOBAL{.stdcall, +proc GlobalAlloc*(uFlags: int32, dwBytes: SIZE_T): HGLOBAL{.stdcall, dynlib: "kernel32", importc: "GlobalAlloc".} -proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: DWORD, uFlags: int32): HGLOBAL{. +proc GlobalAlloc*(uFlags: int32, dwBytes: DWORD): HGLOBAL{.stdcall, + dynlib: "kernel32", importc: "GlobalAlloc", deprecated.} +proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: SIZE_T, uFlags: int32): HGLOBAL{. stdcall, dynlib: "kernel32", importc: "GlobalReAlloc".} -proc GlobalSize*(hMem: HGLOBAL): DWORD{.stdcall, dynlib: "kernel32", +proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: DWORD, uFlags: int32): HGLOBAL{. + stdcall, dynlib: "kernel32", importc: "GlobalReAlloc", deprecated.} +proc GlobalSize*(hMem: HGLOBAL): SIZE_T{.stdcall, dynlib: "kernel32", importc: "GlobalSize".} proc GlobalFlags*(hMem: HGLOBAL): WINUINT{.stdcall, dynlib: "kernel32", importc: "GlobalFlags".} @@ -18541,10 +18545,14 @@ proc GlobalUnWire*(hMem: HGLOBAL): WINBOOL{.stdcall, dynlib: "kernel32", importc: "GlobalUnWire".} proc GlobalMemoryStatus*(lpBuffer: LPMEMORYSTATUS){.stdcall, dynlib: "kernel32", importc: "GlobalMemoryStatus".} -proc LocalAlloc*(uFlags: WINUINT, uBytes: WINUINT): HLOCAL{.stdcall, +proc LocalAlloc*(uFlags: WINUINT, uBytes: SIZE_T): HLOCAL{.stdcall, dynlib: "kernel32", importc: "LocalAlloc".} -proc LocalReAlloc*(hMem: HLOCAL, uBytes: WINUINT, uFlags: WINUINT): HLOCAL{.stdcall, +proc LocalAlloc*(uFlags: WINUINT, uBytes: DWORD): HLOCAL{.stdcall, + dynlib: "kernel32", importc: "LocalAlloc", deprecated.} +proc LocalReAlloc*(hMem: HLOCAL, uBytes: SIZE_T, uFlags: WINUINT): HLOCAL{.stdcall, dynlib: "kernel32", importc: "LocalReAlloc".} +proc LocalReAlloc*(hMem: HLOCAL, uBytes: DWORD, uFlags: WINUINT): HLOCAL{.stdcall, + dynlib: "kernel32", importc: "LocalReAlloc", deprecated.} proc LocalLock*(hMem: HLOCAL): LPVOID{.stdcall, dynlib: "kernel32", importc: "LocalLock".} proc LocalHandle*(pMem: LPCVOID): HLOCAL{.stdcall, dynlib: "kernel32", @@ -18564,38 +18572,71 @@ proc LocalCompact*(uMinFree: WINUINT): WINUINT{.stdcall, dynlib: "kernel32", proc FlushInstructionCache*(hProcess: HANDLE, lpBaseAddress: LPCVOID, dwSize: DWORD): WINBOOL{.stdcall, dynlib: "kernel32", importc: "FlushInstructionCache".} -proc VirtualAlloc*(lpAddress: LPVOID, dwSize: DWORD, flAllocationType: DWORD, +proc VirtualAlloc*(lpAddress: LPVOID, dwSize: SIZE_T, flAllocationType: DWORD, flProtect: DWORD): LPVOID{.stdcall, dynlib: "kernel32", importc: "VirtualAlloc".} -proc VirtualFree*(lpAddress: LPVOID, dwSize: DWORD, dwFreeType: DWORD): WINBOOL{. +proc VirtualAlloc*(lpAddress: LPVOID, dwSize: DWORD, flAllocationType: DWORD, + flProtect: DWORD): LPVOID{.stdcall, dynlib: "kernel32", + importc: "VirtualAlloc", deprecated.} +proc VirtualAllocEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: SIZE_T, + flAllocationType: DWORD, flProtect: DWORD): LPVOID + {.stdcall, dynlib: "kernel32", importc: "VirtualAllocEx".} +proc VirtualAllocEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD, + flAllocationType: DWORD, flProtect: DWORD): LPVOID + {.stdcall, dynlib: "kernel32", importc: "VirtualAllocEx", + deprecated.} +proc VirtualFree*(lpAddress: LPVOID, dwSize: SIZE_T, dwFreeType: DWORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "VirtualFree".} -proc VirtualProtect*(lpAddress: LPVOID, dwSize: DWORD, flNewProtect: DWORD, +proc VirtualFree*(lpAddress: LPVOID, dwSize: DWORD, dwFreeType: DWORD): WINBOOL{. + stdcall, dynlib: "kernel32", importc: "VirtualFree", deprecated.} +proc VirtualFreeEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: SIZE_T, + dwFreeType: DWORD): WINBOOL + {.stdcall, dynlib: "kernel32", importc: "VirtualFree".} +proc VirtualFreeEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD, + dwFreeType: DWORD): WINBOOL + {.stdcall, dynlib: "kernel32", importc: "VirtualFree".} +proc VirtualProtect*(lpAddress: LPVOID, dwSize: SIZE_T, flNewProtect: DWORD, lpflOldProtect: PDWORD): WINBOOL{.stdcall, dynlib: "kernel32", importc: "VirtualProtect".} +proc VirtualProtect*(lpAddress: LPVOID, dwSize: DWORD, flNewProtect: DWORD, + lpflOldProtect: PDWORD): WINBOOL{.stdcall, + dynlib: "kernel32", importc: "VirtualProtect", deprecated.} proc VirtualQuery*(lpAddress: LPCVOID, lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: DWORD): DWORD{.stdcall, dynlib: "kernel32", importc: "VirtualQuery".} -proc VirtualProtectEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD, +proc VirtualProtectEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: SIZE_T, flNewProtect: DWORD, lpflOldProtect: PDWORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "VirtualProtectEx".} +proc VirtualProtectEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD, + flNewProtect: DWORD, lpflOldProtect: PDWORD): WINBOOL{. + stdcall, dynlib: "kernel32", importc: "VirtualProtectEx", deprecated.} proc VirtualQueryEx*(hProcess: HANDLE, lpAddress: LPCVOID, - lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: DWORD): DWORD{. + lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: SIZE_T): DWORD{. stdcall, dynlib: "kernel32", importc: "VirtualQueryEx".} -proc HeapCreate*(flOptions: DWORD, dwInitialSize: DWORD, dwMaximumSize: DWORD): HANDLE{. +proc VirtualQueryEx*(hProcess: HANDLE, lpAddress: LPCVOID, + lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: DWORD): DWORD{. + stdcall, dynlib: "kernel32", importc: "VirtualQueryEx", deprecated.} +proc HeapCreate*(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T): HANDLE{. stdcall, dynlib: "kernel32", importc: "HeapCreate".} +proc HeapCreate*(flOptions: DWORD, dwInitialSize: DWORD, dwMaximumSize: DWORD): HANDLE{. + stdcall, dynlib: "kernel32", importc: "HeapCreate", deprecated.} proc HeapDestroy*(hHeap: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32", importc: "HeapDestroy".} -proc HeapAlloc*(hHeap: HANDLE, dwFlags: DWORD, dwBytes: DWORD): LPVOID{.stdcall, +proc HeapAlloc*(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T): LPVOID{.stdcall, dynlib: "kernel32", importc: "HeapAlloc".} -proc HeapReAlloc*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: DWORD): LPVOID{. +proc HeapAlloc*(hHeap: HANDLE, dwFlags: DWORD, dwBytes: DWORD): LPVOID{.stdcall, + dynlib: "kernel32", importc: "HeapAlloc", deprecated.} +proc HeapReAlloc*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T): LPVOID{. stdcall, dynlib: "kernel32", importc: "HeapReAlloc".} +proc HeapReAlloc*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: DWORD): LPVOID{. + stdcall, dynlib: "kernel32", importc: "HeapReAlloc", deprecated.} proc HeapFree*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID): WINBOOL{.stdcall, dynlib: "kernel32", importc: "HeapFree".} -proc HeapSize*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPCVOID): DWORD{.stdcall, +proc HeapSize*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPCVOID): SIZE_T{.stdcall, dynlib: "kernel32", importc: "HeapSize".} proc HeapValidate*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPCVOID): WINBOOL{. stdcall, dynlib: "kernel32", importc: "HeapValidate".} -proc HeapCompact*(hHeap: HANDLE, dwFlags: DWORD): WINUINT{.stdcall, +proc HeapCompact*(hHeap: HANDLE, dwFlags: DWORD): SIZE_T{.stdcall, dynlib: "kernel32", importc: "HeapCompact".} proc GetProcessHeap*(): HANDLE{.stdcall, dynlib: "kernel32", importc: "GetProcessHeap".} @@ -19221,10 +19262,14 @@ proc FindNextChangeNotification*(hChangeHandle: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32", importc: "FindNextChangeNotification".} proc FindCloseChangeNotification*(hChangeHandle: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32", importc: "FindCloseChangeNotification".} -proc VirtualLock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall, +proc VirtualLock*(lpAddress: LPVOID, dwSize: SIZE_T): WINBOOL{.stdcall, dynlib: "kernel32", importc: "VirtualLock".} -proc VirtualUnlock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall, +proc VirtualLock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall, + dynlib: "kernel32", importc: "VirtualLock", deprecated.} +proc VirtualUnlock*(lpAddress: LPVOID, dwSize: SIZE_T): WINBOOL{.stdcall, dynlib: "kernel32", importc: "VirtualUnlock".} +proc VirtualUnlock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall, + dynlib: "kernel32", importc: "VirtualUnlock", deprecated.} proc MapViewOfFileEx*(hFileMappingObject: HANDLE, dwDesiredAccess: DWORD, dwFileOffsetHigh: DWORD, dwFileOffsetLow: DWORD, dwNumberOfBytesToMap: DWORD, lpBaseAddress: LPVOID): LPVOID{. |