Merge branch 'devel' of https://github.com/Araq/Nimrod into new_spawn
Conflicts: lib/system.nim
This commit is contained in:
commit
85a1d896c2
40 changed files with 385 additions and 114 deletions
|
|
@ -150,6 +150,15 @@ proc sort*[T](a: var openArray[T],
|
|||
## # overload:
|
||||
## sort(myStrArray, system.cmp)
|
||||
##
|
||||
## You can inline adhoc comparison procs with the `do notation
|
||||
## <manual.html#do-notation>`_. Example:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
##
|
||||
## people.sort do (x, y: Person) -> int:
|
||||
## result = cmp(x.surname, y.surname)
|
||||
## if result == 0:
|
||||
## result = cmp(x.name, y.name)
|
||||
var n = a.len
|
||||
var b: seq[T]
|
||||
newSeq(b, n div 2)
|
||||
|
|
|
|||
|
|
@ -27,9 +27,11 @@ export TPort
|
|||
|
||||
|
||||
# TODO: Discarded void PFutures need to checked for exception.
|
||||
# TODO: Exceptions are currently uncatchable due to the limitation that
|
||||
# you cannot have yield in a try stmt. Perhaps I can get the macro to put
|
||||
# a user's try except around ``future.read``.
|
||||
# TODO: ``except`` statement (without `try`) does not work.
|
||||
# TODO: Multiple exception names in a ``except`` don't work.
|
||||
# TODO: The effect system (raises: []) has trouble with my try transformation.
|
||||
# TODO: Can't await in a 'except' body
|
||||
|
||||
|
||||
# -- Futures
|
||||
|
||||
|
|
@ -922,14 +924,17 @@ proc getName(node: PNimrodNode): string {.compileTime.} =
|
|||
return $node[1].ident
|
||||
of nnkIdent:
|
||||
return $node.ident
|
||||
of nnkEmpty:
|
||||
return "anonymous"
|
||||
else:
|
||||
assert false
|
||||
error("Unknown name.")
|
||||
|
||||
macro async*(prc: stmt): stmt {.immediate.} =
|
||||
## Macro which processes async procedures into the appropriate
|
||||
## iterators and yield statements.
|
||||
|
||||
expectKind(prc, nnkProcDef)
|
||||
if prc.kind notin {nnkProcDef, nnkLambda}:
|
||||
error("Cannot transform this node kind into an async proc." &
|
||||
" Proc definition or lambda node expected.")
|
||||
|
||||
hint("Processing " & prc[0].getName & " as an async proc.")
|
||||
|
||||
|
|
@ -941,7 +946,9 @@ macro async*(prc: stmt): stmt {.immediate.} =
|
|||
if $returnType[0] != "PFuture":
|
||||
error("Expected return type of 'PFuture' got '" & $returnType[0] & "'")
|
||||
|
||||
let subtypeIsVoid = returnType.kind == nnkEmpty
|
||||
let subtypeIsVoid = returnType.kind == nnkEmpty or
|
||||
(returnType.kind == nnkBracketExpr and
|
||||
returnType[1].kind == nnkIdent and returnType[1].ident == !"void")
|
||||
|
||||
var outerProcBody = newNimNode(nnkStmtList)
|
||||
|
||||
|
|
@ -990,17 +997,19 @@ macro async*(prc: stmt): stmt {.immediate.} =
|
|||
|
||||
# Remove the 'async' pragma.
|
||||
for i in 0 .. <result[4].len:
|
||||
if result[4][i].ident == !"async":
|
||||
if result[4][i].kind == nnkIdent and result[4][i].ident == !"async":
|
||||
result[4].del(i)
|
||||
if subtypeIsVoid:
|
||||
# Add discardable pragma.
|
||||
result[4].add(newIdentNode("discardable"))
|
||||
if prc.kind == nnkProcDef: # TODO: This is a workaround for #1287
|
||||
result[4].add(newIdentNode("discardable"))
|
||||
if returnType.kind == nnkEmpty:
|
||||
# Add PFuture[void]
|
||||
result[3][0] = parseExpr("PFuture[void]")
|
||||
|
||||
result[6] = outerProcBody
|
||||
|
||||
#echo(treeRepr(result))
|
||||
#echo(toStrLit(result))
|
||||
|
||||
proc recvLine*(socket: TAsyncFD): PFuture[string] {.async.} =
|
||||
|
|
|
|||
|
|
@ -14,12 +14,13 @@
|
|||
import strtabs, asyncnet, asyncdispatch, parseutils, parseurl, strutils
|
||||
type
|
||||
TRequest* = object
|
||||
client: PAsyncSocket # TODO: Separate this into a Response object?
|
||||
client*: PAsyncSocket # TODO: Separate this into a Response object?
|
||||
reqMethod*: string
|
||||
headers*: PStringTable
|
||||
protocol*: tuple[orig: string, major, minor: int]
|
||||
url*: TURL
|
||||
hostname*: string ## The hostname of the client that made the request.
|
||||
body*: string # TODO
|
||||
|
||||
PAsyncHttpServer* = ref object
|
||||
socket: PAsyncSocket
|
||||
|
|
@ -169,6 +170,10 @@ proc serve*(server: PAsyncHttpServer, port: TPort,
|
|||
var fut = await server.socket.acceptAddr()
|
||||
processClient(fut.client, fut.address, callback)
|
||||
|
||||
proc close*(server: PAsyncHttpServer) =
|
||||
## Terminates the async http server instance.
|
||||
server.socket.close()
|
||||
|
||||
when isMainModule:
|
||||
var server = newAsyncHttpServer()
|
||||
proc cb(req: TRequest) {.async.} =
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ proc enqueue*[T](q: var TQueue[T], item: T) =
|
|||
|
||||
proc dequeue*[T](q: var TQueue[T]): T =
|
||||
## removes and returns the first element of the queue `q`.
|
||||
assert q.len > 0
|
||||
assert q.count > 0
|
||||
dec q.count
|
||||
result = q.data[q.rd]
|
||||
q.rd = (q.rd + 1) and q.mask
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@
|
|||
## ## Piggyback on the already available string hash proc.
|
||||
## ##
|
||||
## ## Without this proc nothing works!
|
||||
## result = hash(x.firstName & x.lastName)
|
||||
## result = x.firstName.hash !& x.lastName.hash
|
||||
## result = !$result
|
||||
##
|
||||
## var
|
||||
## salaries = initTable[Person, int]()
|
||||
|
|
@ -145,6 +146,14 @@ proc mget*[A, B](t: var TTable[A, B], key: A): var B =
|
|||
if index >= 0: result = t.data[index].val
|
||||
else: raise newException(EInvalidKey, "key not found: " & $key)
|
||||
|
||||
iterator allValues*[A, B](t: TTable[A, B]; key: A): B =
|
||||
## iterates over any value in the table `t` that belongs to the given `key`.
|
||||
var h: THash = hash(key) and high(t.data)
|
||||
while t.data[h].slot != seEmpty:
|
||||
if t.data[h].key == key and t.data[h].slot == seFilled:
|
||||
yield t.data[h].val
|
||||
h = nextTry(h, high(t.data))
|
||||
|
||||
proc hasKey*[A, B](t: TTable[A, B], key: A): bool =
|
||||
## returns true iff `key` is in the table `t`.
|
||||
result = rawGet(t, key) >= 0
|
||||
|
|
@ -313,8 +322,7 @@ proc newTable*[A, B](initialSize=64): PTable[A, B] =
|
|||
new(result)
|
||||
result[] = initTable[A, B](initialSize)
|
||||
|
||||
proc newTable*[A, B](pairs: openArray[tuple[key: A,
|
||||
val: B]]): PTable[A, B] =
|
||||
proc newTable*[A, B](pairs: openArray[tuple[key: A, val: B]]): PTable[A, B] =
|
||||
## creates a new hash table that contains the given `pairs`.
|
||||
new(result)
|
||||
result[] = toTable[A, B](pairs)
|
||||
|
|
@ -841,7 +849,8 @@ when isMainModule:
|
|||
## Piggyback on the already available string hash proc.
|
||||
##
|
||||
## Without this proc nothing works!
|
||||
result = hash(x.firstName & x.lastName)
|
||||
result = x.firstName.hash !& x.lastName.hash
|
||||
result = !$result
|
||||
|
||||
var
|
||||
salaries = initTable[Person, int]()
|
||||
|
|
|
|||
|
|
@ -119,8 +119,8 @@ proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] =
|
|||
var mev: TMonitorEvent
|
||||
mev.wd = event.wd
|
||||
if event.len.int != 0:
|
||||
mev.name = newString(event.len.int)
|
||||
copyMem(addr(mev.name[0]), addr event.name, event.len.int-1)
|
||||
let cstr = event.name.addr.cstring
|
||||
mev.name = $cstr
|
||||
else:
|
||||
mev.name = ""
|
||||
|
||||
|
|
@ -211,4 +211,4 @@ when isMainModule:
|
|||
|
||||
while true:
|
||||
if not disp.poll(): break
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,34 @@
|
|||
#
|
||||
|
||||
## This module implements efficient computations of hash values for diverse
|
||||
## Nimrod types.
|
||||
## Nimrod types. All the procs are based on these two building blocks: the `!&
|
||||
## proc <#!&>`_ used to start or mix a hash value, and the `!$ proc <#!$>`_
|
||||
## used to *finish* the hash value. If you want to implement hash procs for
|
||||
## your custom types you will end up writing the following kind of skeleton of
|
||||
## code:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## proc hash(x: Something): THash =
|
||||
## ## Computes a THash from `x`.
|
||||
## var h: THash = 0
|
||||
## # Iterate over parts of `x`.
|
||||
## for xAtom in x:
|
||||
## # Mix the atom with the partial hash.
|
||||
## h = h !& xAtom
|
||||
## # Finish the hash.
|
||||
## result = !$h
|
||||
##
|
||||
## If your custom types contain fields for which there already is a hash proc,
|
||||
## like for example objects made up of ``strings``, you can simply hash
|
||||
## together the hash value of the individual fields:
|
||||
##
|
||||
## .. code-block:: nimrod
|
||||
## proc hash(x: Something): THash =
|
||||
## ## Computes a THash from `x`.
|
||||
## var h: THash = 0
|
||||
## h = h &! hash(x.foo)
|
||||
## h = h &! hash(x.bar)
|
||||
## result = !$h
|
||||
|
||||
import
|
||||
strutils
|
||||
|
|
|
|||
|
|
@ -619,6 +619,44 @@ proc `%`*(elements: openArray[PJsonNode]): PJsonNode =
|
|||
newSeq(result.elems, elements.len)
|
||||
for i, p in pairs(elements): result.elems[i] = p
|
||||
|
||||
proc `==`* (a,b: PJsonNode): bool =
|
||||
## Check two nodes for equality
|
||||
if a.kind != b.kind: false
|
||||
else:
|
||||
case a.kind
|
||||
of JString:
|
||||
a.str == b.str
|
||||
of JInt:
|
||||
a.num == b.num
|
||||
of JFloat:
|
||||
a.fnum == b.fnum
|
||||
of JBool:
|
||||
a.bval == b.bval
|
||||
of JNull:
|
||||
true
|
||||
of JArray:
|
||||
a.elems == b.elems
|
||||
of JObject:
|
||||
a.fields == b.fields
|
||||
|
||||
proc hash* (n:PJsonNode): THash =
|
||||
## Compute the hash for a JSON node
|
||||
case n.kind
|
||||
of JArray:
|
||||
result = hash(n.elems)
|
||||
of JObject:
|
||||
result = hash(n.fields)
|
||||
of JInt:
|
||||
result = hash(n.num)
|
||||
of JFloat:
|
||||
result = hash(n.fnum)
|
||||
of JBool:
|
||||
result = hash(n.bval.int)
|
||||
of JString:
|
||||
result = hash(n.str)
|
||||
of JNull:
|
||||
result = hash(0)
|
||||
|
||||
proc len*(n: PJsonNode): int =
|
||||
## If `n` is a `JArray`, it returns the number of elements.
|
||||
## If `n` is a `JObject`, it returns the number of pairs.
|
||||
|
|
@ -631,7 +669,7 @@ proc len*(n: PJsonNode): int =
|
|||
proc `[]`*(node: PJsonNode, name: string): PJsonNode =
|
||||
## Gets a field from a `JObject`, which must not be nil.
|
||||
## If the value at `name` does not exist, returns nil
|
||||
assert(node != nil)
|
||||
assert(not isNil(node))
|
||||
assert(node.kind == JObject)
|
||||
for key, item in items(node.fields):
|
||||
if key == name:
|
||||
|
|
@ -641,8 +679,8 @@ proc `[]`*(node: PJsonNode, name: string): PJsonNode =
|
|||
proc `[]`*(node: PJsonNode, index: int): PJsonNode =
|
||||
## Gets the node at `index` in an Array. Result is undefined if `index`
|
||||
## is out of bounds
|
||||
assert(not isNil(node))
|
||||
assert(node.kind == JArray)
|
||||
assert(node != nil)
|
||||
return node.elems[index]
|
||||
|
||||
proc hasKey*(node: PJsonNode, key: string): bool =
|
||||
|
|
@ -675,14 +713,12 @@ proc `[]=`*(obj: PJsonNode, key: string, val: PJsonNode) =
|
|||
return
|
||||
obj.fields.add((key, val))
|
||||
|
||||
proc `{}`*(node: PJsonNode, names: varargs[string]): PJsonNode =
|
||||
proc `{}`*(node: PJsonNode, key: string): PJsonNode =
|
||||
## Transverses the node and gets the given value. If any of the
|
||||
## names does not exist, returns nil
|
||||
result = node
|
||||
for name in names:
|
||||
result = result[name]
|
||||
if isNil(result):
|
||||
return nil
|
||||
if isNil(node): return nil
|
||||
result = result[key]
|
||||
|
||||
proc `{}=`*(node: PJsonNode, names: varargs[string], value: PJsonNode) =
|
||||
## Transverses the node and tries to set the value at the given location
|
||||
|
|
@ -1021,7 +1057,7 @@ when isMainModule:
|
|||
|
||||
let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd" }"""
|
||||
# nil passthrough
|
||||
assert(testJson{"doesnt_exist", "anything"} == nil)
|
||||
assert(testJson{"doesnt_exist"}{"anything"}.isNil)
|
||||
testJson{["c", "d"]} = %true
|
||||
assert(testJson["c"]["d"].bval)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
{.deadCodeElim: on.}
|
||||
import rawsockets, os, strutils, unsigned, parseutils, times
|
||||
export TPort
|
||||
export TPort, `$`
|
||||
|
||||
const useWinVersion = defined(Windows) or defined(nimdoc)
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ export
|
|||
MSG_PEEK
|
||||
|
||||
type
|
||||
|
||||
TPort* = distinct uint16 ## port type
|
||||
|
||||
TDomain* = enum ## domain, which specifies the protocol family of the
|
||||
|
|
|
|||
|
|
@ -90,6 +90,15 @@ proc defined*(x: expr): bool {.magic: "Defined", noSideEffect.}
|
|||
## when not defined(strutils.toUpper):
|
||||
## # provide our own toUpper proc here, because strutils is
|
||||
## # missing it.
|
||||
##
|
||||
## You can also check external symbols introduced through the compiler's
|
||||
## `-d:x switch <nimrodc.html#compile-time-symbols>`_ to enable build time
|
||||
## conditionals:
|
||||
##
|
||||
## .. code-block:: Nimrod
|
||||
## when not defined(release):
|
||||
## # Do here programmer friendly expensive sanity checks.
|
||||
## # Put here the normal code
|
||||
|
||||
when defined(useNimRtl):
|
||||
{.deadCodeElim: on.}
|
||||
|
|
@ -1769,9 +1778,38 @@ iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[a,b: expr] {
|
|||
## in the loop body.
|
||||
iterator fieldPairs*[T: tuple|object](x: T): TObject {.
|
||||
magic: "FieldPairs", noSideEffect.}
|
||||
## iterates over every field of `x`. Warning: This really transforms
|
||||
## the 'for' and unrolls the loop. The current implementation also has a bug
|
||||
## that affects symbol binding in the loop body.
|
||||
## Iterates over every field of `x` returning their name and value.
|
||||
##
|
||||
## When you iterate over objects with different field types you have to use
|
||||
## the compile time ``when`` instead of a runtime ``if`` to select the code
|
||||
## you want to run for each type. To perform the comparison use the `is
|
||||
## operator <manual.html#is-operator>`_. Example:
|
||||
##
|
||||
## .. code-block:: Nimrod
|
||||
##
|
||||
## type
|
||||
## Custom = object
|
||||
## foo: string
|
||||
## bar: bool
|
||||
##
|
||||
## proc `$`(x: Custom): string =
|
||||
## result = "Custom:"
|
||||
## for name, value in x.fieldPairs:
|
||||
## when value is bool:
|
||||
## result.add("\n\t" & name & " is " & $value)
|
||||
## else:
|
||||
## if value.isNil:
|
||||
## result.add("\n\t" & name & " (nil)")
|
||||
## else:
|
||||
## result.add("\n\t" & name & " '" & value & "'")
|
||||
##
|
||||
## Another way to do the same without ``when`` is to leave the task of
|
||||
## picking the appropriate code to a secondary proc which you overload for
|
||||
## each field type and pass the `value` to.
|
||||
##
|
||||
## Warning: This really transforms the 'for' and unrolls the loop. The
|
||||
## current implementation also has a bug that affects symbol binding in the
|
||||
## loop body.
|
||||
iterator fieldPairs*[S: tuple|object, T: tuple|object](x: S, y: T): tuple[
|
||||
a, b: expr] {.
|
||||
magic: "FieldPairs", noSideEffect.}
|
||||
|
|
@ -2785,10 +2823,15 @@ when true:
|
|||
THide(raiseAssert)(msg)
|
||||
|
||||
template assert*(cond: bool, msg = "") =
|
||||
## provides a means to implement `programming by contracts`:idx: in Nimrod.
|
||||
## Raises ``EAssertionFailure`` with `msg` if `cond` is false.
|
||||
##
|
||||
## Provides a means to implement `programming by contracts`:idx: in Nimrod.
|
||||
## ``assert`` evaluates expression ``cond`` and if ``cond`` is false, it
|
||||
## raises an ``EAssertionFailure`` exception. However, the compiler may
|
||||
## not generate any code at all for ``assert`` if it is advised to do so.
|
||||
## raises an ``EAssertionFailure`` exception. However, the compiler may not
|
||||
## generate any code at all for ``assert`` if it is advised to do so through
|
||||
## the ``-d:release`` or ``--assertions:off`` `command line switches
|
||||
## <nimrodc.html#command-line-switches>`_.
|
||||
##
|
||||
## Use ``assert`` for debugging purposes only.
|
||||
bind instantiationInfo
|
||||
mixin failedAssertImpl
|
||||
|
|
|
|||
|
|
@ -67,6 +67,28 @@ proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} =
|
|||
if a != b:
|
||||
sysFatal(EInvalidObjectAssignment, "invalid object assignment")
|
||||
|
||||
type ObjCheckCache = array[0..1, PNimType]
|
||||
|
||||
proc isObjSlowPath(obj, subclass: PNimType;
|
||||
cache: var ObjCheckCache): bool {.noinline.} =
|
||||
# checks if obj is of type subclass:
|
||||
var x = obj.base
|
||||
while x != subclass:
|
||||
if x == nil:
|
||||
cache[0] = obj
|
||||
return false
|
||||
x = x.base
|
||||
cache[1] = obj
|
||||
return true
|
||||
|
||||
proc isObjWithCache(obj, subclass: PNimType;
|
||||
cache: var ObjCheckCache): bool {.compilerProc, inline.} =
|
||||
if obj == subclass: return true
|
||||
if obj.base == subclass: return true
|
||||
if cache[0] == obj: return false
|
||||
if cache[1] == obj: return true
|
||||
return isObjSlowPath(obj, subclass, cache)
|
||||
|
||||
proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
|
||||
# checks if obj is of type subclass:
|
||||
var x = obj
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue