summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/c2nim/cparse.nim226
-rw-r--r--compiler/c2nim/tests/enum.h40
-rw-r--r--compiler/c2nim/tests/struct_anonym.h27
-rw-r--r--compiler/nimrod.ini1
-rw-r--r--lib/pure/asyncdispatch.nim20
-rw-r--r--lib/pure/asynchttpserver.nim39
-rw-r--r--lib/pure/collections/sequtils.nim14
-rw-r--r--tests/seq/tsequtils.nim4
-rw-r--r--web/news.txt1
9 files changed, 299 insertions, 73 deletions
diff --git a/compiler/c2nim/cparse.nim b/compiler/c2nim/cparse.nim
index 52d50ca39..2e31af528 100644
--- a/compiler/c2nim/cparse.nim
+++ b/compiler/c2nim/cparse.nim
@@ -19,7 +19,7 @@
 
 import 
   os, llstream, renderer, clex, idents, strutils, pegs, ast, astalgo, msgs,
-  options, strtabs
+  options, strtabs, hashes, algorithm
 
 type 
   TParserFlag = enum
@@ -63,6 +63,15 @@ type
 
   ERetryParsing = object of ESynch
 
+
+
+proc addTypeDef(section, name, t: PNode)
+proc parseStruct(p: var TParser, stmtList: PNode, isUnion: bool): PNode
+proc parseStructBody(p: var TParser, stmtList: PNode, isUnion: bool,
+                     kind: TNodeKind = nkRecList): PNode
+
+
+
 proc newParserOptions*(): PParserOptions = 
   new(result)
   result.prefixes = @[]
@@ -682,12 +691,75 @@ proc parseField(p: var TParser, kind: TNodeKind): PNode =
     else: result = mangledIdent(p.tok.s, p)
     getTok(p, result)
 
-proc parseStructBody(p: var TParser, isUnion: bool,
+proc structPragmas(p: TParser, name: PNode, origName: string): PNode = 
+  assert name.kind == nkIdent
+  result = newNodeP(nkPragmaExpr, p)
+  addSon(result, exportSym(p, name, origName))
+  var pragmas = newNodeP(nkPragma, p)
+  #addSon(pragmas, newIdentNodeP("pure", p), newIdentNodeP("final", p))
+  if p.options.header.len > 0:
+    addSon(pragmas, newIdentStrLitPair("importc", origName, p),
+                    newIdentStrLitPair("header", p.options.header, p))
+  if pragmas.len > 0: addSon(result, pragmas)
+  else: addSon(result, ast.emptyNode)
+
+proc hashPosition(p: TParser): string =
+  let lineInfo = parLineInfo(p)
+  let fileInfo = fileInfos[lineInfo.fileIndex]
+  result = $hash(fileInfo.shortName & "_" & $lineInfo.line & "_" & $lineInfo.col).uint
+
+proc parseInnerStruct(p: var TParser, stmtList: PNode, isUnion: bool): PNode =
+  getTok(p, nil)
+  if p.tok.xkind != pxCurlyLe:
+    parMessage(p, errUser, "Expected '{' but found '" & $(p.tok[]) & "'")
+  
+  let structName =  if isUnion: "INNER_C_UNION_" & p.hashPosition
+                    else: "INNER_C_STRUCT_" & p.hashPosition
+  let typeSection = newNodeP(nkTypeSection, p)
+  let newStruct = newNodeP(nkObjectTy, p)
+  var pragmas = ast.emptyNode
+  if isUnion:
+    pragmas = newNodeP(nkPragma, p)
+    addSon(pragmas, newIdentNodeP("union", p))
+  addSon(newStruct, pragmas, ast.emptyNode) # no inheritance 
+  result = newNodeP(nkIdent, p)
+  result.ident = getIdent(structName)
+  let struct = parseStructBody(p, stmtList, isUnion)
+  let defName = newNodeP(nkIdent, p)
+  defName.ident = getIdent(structName)
+  addSon(newStruct, struct)
+  addTypeDef(typeSection, structPragmas(p, defName, "no_name"), newStruct)
+  addSon(stmtList, typeSection)
+
+proc parseStructBody(p: var TParser, stmtList: PNode, isUnion: bool,
                      kind: TNodeKind = nkRecList): PNode =
   result = newNodeP(kind, p)
   eat(p, pxCurlyLe, result)
   while p.tok.xkind notin {pxEof, pxCurlyRi}:
-    var baseTyp = typeAtom(p)
+    skipConst(p)
+    var baseTyp: PNode
+    if p.tok.xkind == pxSymbol and (p.tok.s == "struct" or p.tok.s == "union"):
+      let gotUnion = if p.tok.s == "union": true   else: false
+      saveContext(p)
+      getTok(p, nil)
+      if p.tok.xkind == pxSymbol:
+        backtrackContext(p)
+        baseTyp = typeAtom(p)
+      else:
+        backtrackContext(p)
+        baseTyp = parseInnerStruct(p, stmtList, gotUnion)
+        if p.tok.xkind == pxSemiColon:
+          let def = newNodeP(nkIdentDefs, p)
+          var t = pointer(p, baseTyp)
+          let i = fieldIdent("ano_" & p.hashPosition, p)
+          t = parseTypeSuffix(p, t)
+          addSon(def, i, t, ast.emptyNode)
+          addSon(result, def)
+          getTok(p, nil)
+          continue
+    else:
+      baseTyp = typeAtom(p)
+    
     while true:
       var def = newNodeP(nkIdentDefs, p)
       var t = pointer(p, baseTyp)
@@ -700,18 +772,6 @@ proc parseStructBody(p: var TParser, isUnion: bool,
     eat(p, pxSemicolon, lastSon(result))
   eat(p, pxCurlyRi, result)
 
-proc structPragmas(p: TParser, name: PNode, origName: string): PNode = 
-  assert name.kind == nkIdent
-  result = newNodeP(nkPragmaExpr, p)
-  addSon(result, exportSym(p, name, origName))
-  var pragmas = newNodeP(nkPragma, p)
-  #addSon(pragmas, newIdentNodeP("pure", p), newIdentNodeP("final", p))
-  if p.options.header.len > 0:
-    addSon(pragmas, newIdentStrLitPair("importc", origName, p),
-                    newIdentStrLitPair("header", p.options.header, p))
-  if pragmas.len > 0: addSon(result, pragmas)
-  else: addSon(result, ast.emptyNode)
-
 proc enumPragmas(p: TParser, name: PNode): PNode =
   result = newNodeP(nkPragmaExpr, p)
   addSon(result, name)
@@ -722,7 +782,7 @@ proc enumPragmas(p: TParser, name: PNode): PNode =
   addSon(pragmas, e)
   addSon(result, pragmas)
 
-proc parseStruct(p: var TParser, isUnion: bool): PNode =
+proc parseStruct(p: var TParser, stmtList: PNode, isUnion: bool): PNode =
   result = newNodeP(nkObjectTy, p)
   var pragmas = ast.emptyNode
   if isUnion:
@@ -730,7 +790,7 @@ proc parseStruct(p: var TParser, isUnion: bool): PNode =
     addSon(pragmas, newIdentNodeP("union", p))
   addSon(result, pragmas, ast.emptyNode) # no inheritance 
   if p.tok.xkind == pxCurlyLe:
-    addSon(result, parseStructBody(p, isUnion))
+    addSon(result, parseStructBody(p, stmtList, isUnion))
   else: 
     addSon(result, newNodeP(nkRecList, p))
 
@@ -855,9 +915,28 @@ proc parseTrailingDefinedTypes(p: var TParser, section, typ: PNode) =
     newTyp = parseTypeSuffix(p, newTyp)
     addTypeDef(section, newName, newTyp)
 
-proc enumFields(p: var TParser): PNode = 
+proc createConst(name, typ, val: PNode, p: TParser): PNode =
+  result = newNodeP(nkConstDef, p)
+  addSon(result, name, typ, val)
+
+proc exprToNumber(n: PNode not nil): tuple[succ: bool, val: BiggestInt] =
+  result = (false, 0.BiggestInt)
+  case n.kind:
+  of nkPrefix:
+    # Check for negative/positive numbers  -3  or  +6
+    if n.sons.len == 2 and n.sons[0].kind == nkIdent and n.sons[1].kind == nkIntLit:
+      let pre = n.sons[0]
+      let num = n.sons[1]
+      if pre.ident.s == "-": result = (true, - num.intVal)
+      elif pre.ident.s == "+": result = (true, num.intVal)
+  else: discard
+
+proc enumFields(p: var TParser, constList: PNode): PNode = 
   result = newNodeP(nkEnumTy, p)
   addSon(result, ast.emptyNode) # enum does not inherit from anything
+  var i: BiggestInt = 0
+  var field: tuple[id: BiggestInt, isNumber: bool, node: PNode]
+  var fields = newSeq[type(field)]()
   while true:
     var e = skipIdent(p)
     if p.tok.xkind == pxAsgn: 
@@ -867,17 +946,59 @@ proc enumFields(p: var TParser): PNode =
       e = newNodeP(nkEnumFieldDef, p)
       addSon(e, a, c)
       skipCom(p, e)
-    
-    addSon(result, e)
+      if c.kind == nkIntLit:
+        i = c.intVal
+        field.isNumber = true
+      else:
+        var (success, number) = exprToNumber(c)
+        if success:
+          i = number
+          field.isNumber = true
+        else:
+          field.isNumber = false
+    else:
+      inc(i)
+      field.isNumber = true
+    field.id = i
+    field.node = e
+    fields.add(field)
     if p.tok.xkind != pxComma: break
     getTok(p, e)
     # allow trailing comma:
     if p.tok.xkind == pxCurlyRi: break
-
-proc parseTypedefStruct(p: var TParser, result: PNode, isUnion: bool) = 
+  fields.sort do (x, y: type(field)) -> int:
+    cmp(x.id, y.id)
+  var lastId: BiggestInt
+  var lastIdent: PNode
+  for count, f in fields:
+    if not f.isNumber:
+      addSon(result, f.node)
+    elif f.id == lastId and count > 0:
+      var currentIdent: PNode
+      case f.node.kind:
+      of nkEnumFieldDef:
+        if f.node.sons.len > 0 and f.node.sons[0].kind == nkIdent:
+          currentIdent = f.node.sons[0]
+        else: parMessage(p, errGenerated, "Warning: When sorting enum fields an expected nkIdent was not found. Check the fields!")
+      of nkIdent: currentIdent = f.node
+      else: parMessage(p, errGenerated, "Warning: When sorting enum fields an expected nkIdent was not found. Check the fields!")
+      var constant = createConst( currentIdent, ast.emptyNode, lastIdent, p)
+      constList.addSon(constant)
+    else:
+      addSon(result, f.node)
+      lastId = f.id
+      case f.node.kind:
+      of nkEnumFieldDef:
+        if f.node.sons.len > 0 and f.node.sons[0].kind == nkIdent:
+          lastIdent = f.node.sons[0]
+        else: parMessage(p, errGenerated, "Warning: When sorting enum fields an expected nkIdent was not found. Check the fields!")
+      of nkIdent: lastIdent = f.node
+      else: parMessage(p, errGenerated, "Warning: When sorting enum fields an expected nkIdent was not found. Check the fields!")
+
+proc parseTypedefStruct(p: var TParser, result: PNode, stmtList: PNode, isUnion: bool) = 
   getTok(p, result)
   if p.tok.xkind == pxCurlyLe:
-    var t = parseStruct(p, isUnion)
+    var t = parseStruct(p, stmtList, isUnion)
     var origName = p.tok.s
     markTypeIdent(p, nil)
     var name = skipIdent(p)
@@ -890,7 +1011,7 @@ proc parseTypedefStruct(p: var TParser, result: PNode, isUnion: bool) =
     var nameOrType = skipIdent(p)
     case p.tok.xkind 
     of pxCurlyLe:
-      var t = parseStruct(p, isUnion)
+      var t = parseStruct(p, stmtList, isUnion)
       if p.tok.xkind == pxSymbol: 
         # typedef struct tagABC {} abc, *pabc;
         # --> abc is a better type name than tagABC!
@@ -914,11 +1035,11 @@ proc parseTypedefStruct(p: var TParser, result: PNode, isUnion: bool) =
   else:
     expectIdent(p)
 
-proc parseTypedefEnum(p: var TParser, result: PNode) = 
+proc parseTypedefEnum(p: var TParser, result, constSection: PNode) = 
   getTok(p, result)
   if p.tok.xkind == pxCurlyLe:
     getTok(p, result)
-    var t = enumFields(p)
+    var t = enumFields(p, constSection)
     eat(p, pxCurlyRi, t)
     var origName = p.tok.s
     markTypeIdent(p, nil)
@@ -933,7 +1054,7 @@ proc parseTypedefEnum(p: var TParser, result: PNode) =
     case p.tok.xkind 
     of pxCurlyLe:
       getTok(p, result)
-      var t = enumFields(p)
+      var t = enumFields(p, constSection)
       eat(p, pxCurlyRi, t)
       if p.tok.xkind == pxSymbol: 
         # typedef enum tagABC {} abc, *pabc;
@@ -960,27 +1081,36 @@ proc parseTypedefEnum(p: var TParser, result: PNode) =
     expectIdent(p)
 
 proc parseTypeDef(p: var TParser): PNode =  
-  result = newNodeP(nkTypeSection, p)
+  result = newNodeP(nkStmtList, p)
+  var typeSection = newNodeP(nkTypeSection, p)
+  var afterStatements = newNodeP(nkStmtList, p)
   while p.tok.xkind == pxSymbol and p.tok.s == "typedef":
-    getTok(p, result)
+    getTok(p, typeSection)
     inc(p.inTypeDef)
     expectIdent(p)
     case p.tok.s
-    of "struct": parseTypedefStruct(p, result, isUnion=false)
-    of "union": parseTypedefStruct(p, result, isUnion=true)
-    of "enum": parseTypedefEnum(p, result)
+    of "struct": parseTypedefStruct(p, typeSection, result, isUnion=false)
+    of "union": parseTypedefStruct(p, typeSection, result, isUnion=true)
+    of "enum":
+      var constSection = newNodeP(nkConstSection, p)
+      parseTypedefEnum(p, typeSection, constSection)
+      addSon(afterStatements, constSection)
     of "class":
       if pfCpp in p.options.flags:
-        parseTypedefStruct(p, result, isUnion=false)
+        parseTypedefStruct(p, typeSection, result, isUnion=false)
       else:
         var t = typeAtom(p)
-        otherTypeDef(p, result, t)
+        otherTypeDef(p, typeSection, t)
     else: 
       var t = typeAtom(p)
-      otherTypeDef(p, result, t)
+      otherTypeDef(p, typeSection, t)
     eat(p, pxSemicolon)
     dec(p.inTypeDef)
-    
+  
+  addSon(result, typeSection)
+  for s in afterStatements:
+    addSon(result, s)
+  
 proc skipDeclarationSpecifiers(p: var TParser) =
   while p.tok.xkind == pxSymbol:
     case p.tok.s
@@ -1092,10 +1222,6 @@ proc declaration(p: var TParser): PNode =
     result = parseVarDecl(p, baseTyp, rettyp, origName)
   assert result != nil
 
-proc createConst(name, typ, val: PNode, p: TParser): PNode =
-  result = newNodeP(nkConstDef, p)
-  addSon(result, name, typ, val)
-
 proc enumSpecifier(p: var TParser): PNode =  
   saveContext(p)
   getTok(p, nil) # skip "enum"
@@ -1141,12 +1267,16 @@ proc enumSpecifier(p: var TParser): PNode =
       closeContext(p)
       var name = result
       # create a type section containing the enum
-      result = newNodeP(nkTypeSection, p)
+      result = newNodeP(nkStmtList, p)
+      var tSection = newNodeP(nkTypeSection, p)
       var t = newNodeP(nkTypeDef, p)
       getTok(p, t)
-      var e = enumFields(p)
+      var constSection = newNodeP(nkConstSection, p)
+      var e = enumFields(p, constSection)
       addSon(t, exportSym(p, name, origName), ast.emptyNode, e)
-      addSon(result, t)
+      addSon(tSection, t)
+      addSon(result, tSection)
+      addSon(result, constSection)
       eat(p, pxCurlyRi, result)
       eat(p, pxSemicolon)
     of pxSemicolon:
@@ -1608,8 +1738,8 @@ proc declarationOrStatement(p: var TParser): PNode =
       result = expressionStatement(p)
   assert result != nil
 
-proc parseTuple(p: var TParser, isUnion: bool): PNode = 
-  result = parseStructBody(p, isUnion, nkTupleTy)
+proc parseTuple(p: var TParser, statements: PNode, isUnion: bool): PNode = 
+  parseStructBody(p, statements, isUnion, nkTupleTy)
 
 proc parseTrailingDefinedIdents(p: var TParser, result, baseTyp: PNode) =
   var varSection = newNodeP(nkVarSection, p)
@@ -1640,13 +1770,13 @@ proc parseStandaloneStruct(p: var TParser, isUnion: bool): PNode =
   if p.tok.xkind in {pxCurlyLe, pxSemiColon}:
     if origName.len > 0: 
       var name = mangledIdent(origName, p)
-      var t = parseStruct(p, isUnion)
+      var t = parseStruct(p, result, isUnion)
       var typeSection = newNodeP(nkTypeSection, p)
       addTypeDef(typeSection, structPragmas(p, name, origName), t)
       addSon(result, typeSection)
       parseTrailingDefinedIdents(p, result, name)
     else:
-      var t = parseTuple(p, isUnion)
+      var t = parseTuple(p, result, isUnion)
       parseTrailingDefinedIdents(p, result, t)
   else:
     backtrackContext(p)
@@ -2034,7 +2164,7 @@ proc parseStandaloneClass(p: var TParser, isStruct: bool): PNode =
       addTypeDef(typeSection, structPragmas(p, name, origName), t)
       parseTrailingDefinedIdents(p, result, name)
     else:
-      var t = parseTuple(p, isUnion=false)
+      var t = parseTuple(p, result, isUnion=false)
       parseTrailingDefinedIdents(p, result, t)
   else:
     backtrackContext(p)
diff --git a/compiler/c2nim/tests/enum.h b/compiler/c2nim/tests/enum.h
new file mode 100644
index 000000000..16bc59058
--- /dev/null
+++ b/compiler/c2nim/tests/enum.h
@@ -0,0 +1,40 @@
+
+enum vehicles
+{
+	car = 0x10,
+	truck,
+	boat = 0x01,
+	ship = 1,
+	speedboat = 1,
+	bicycle = 4,
+	bobycar
+};
+
+enum
+{
+	red = 4,
+	green = 2,
+	blue
+};
+
+typedef enum food
+{
+	bread = 4,
+	toast = 4,
+	bun = 0x04,
+	cucumber = 2,
+	chocolate = 6
+};
+
+typedef enum numbers
+{
+	one = 1,
+	two,
+	nten = - 10,
+	nnine,
+	four = 4,
+	three = + 3,
+	positivenine = + 9,
+	nfour = - 4,
+	negativeten = -10
+};
\ No newline at end of file
diff --git a/compiler/c2nim/tests/struct_anonym.h b/compiler/c2nim/tests/struct_anonym.h
new file mode 100644
index 000000000..859bfc206
--- /dev/null
+++ b/compiler/c2nim/tests/struct_anonym.h
@@ -0,0 +1,27 @@
+
+struct normal{
+	int a;
+	int b;
+};
+
+typedef struct outerStruct {
+	struct normal a_nomal_one;
+	
+	int a;
+	
+	struct {
+		union {
+			int b;
+		} a_union_in_the_struct;
+		
+		int c;
+	};
+	
+	union {
+		int d;
+		
+		struct {
+			int e;
+		} a_struct_in_the_union;
+	} a_union;
+};
\ No newline at end of file
diff --git a/compiler/nimrod.ini b/compiler/nimrod.ini
index 8b2353aab..44e16cec8 100644
--- a/compiler/nimrod.ini
+++ b/compiler/nimrod.ini
@@ -79,6 +79,7 @@ Files: "lib/system/*.nim"
 Files: "lib/core/*.nim"
 Files: "lib/pure/*.nim"
 Files: "lib/pure/collections/*.nim"
+Files: "lib/pure/concurrency/*.nim"
 Files: "lib/impure/*.nim"
 Files: "lib/wrappers/*.nim"
 
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 6d9e605f1..12329951c 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -26,12 +26,12 @@ export TPort
 ## **Note:** This module is still largely experimental.
 
 
-# TODO: Discarded void PFutures need to checked for exception.
+# TODO: Discarded void PFutures need to be checked for exception.
 # 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
-
+# TODO: getCurrentException(Msg) don't work
 
 # -- Futures
 
@@ -77,7 +77,8 @@ proc fail*[T](future: PFuture[T], error: ref EBase) =
     # This is to prevent exceptions from being silently ignored when a future
     # is discarded.
     # TODO: This may turn out to be a bad idea.
-    raise error
+    # Turns out this is a bad idea.
+    #raise error
 
 proc `callback=`*(future: PFutureBase, cb: proc () {.closure,gcsafe.}) =
   ## Sets the callback proc to be called when the future completes.
@@ -775,20 +776,23 @@ proc accept*(socket: TAsyncFD): PFuture[TAsyncFD] =
 
 # -- Await Macro
 
-template createCb*(retFutureSym, iteratorNameSym: expr): stmt {.immediate.} =
+template createCb*(retFutureSym, iteratorNameSym,
+                   name: expr): stmt {.immediate.} =
   var nameIterVar = iteratorNameSym
+  #{.push stackTrace: off.}
   proc cb {.closure,gcsafe.} =
     try:
       if not nameIterVar.finished:
         var next = nameIterVar()
         if next == nil:
-          assert retFutureSym.finished, "Async procedure's return Future was not finished."
+          assert retFutureSym.finished, "Async procedure's (" &
+                 name & ") return Future was not finished."
         else:
           next.callback = cb
     except:
       retFutureSym.fail(getCurrentException())
   cb()
-
+  #{.pop.}
 proc generateExceptionCheck(futSym,
     exceptBranch, rootReceiver: PNimrodNode): PNimrodNode {.compileTime.} =
   if exceptBranch == nil:
@@ -987,7 +991,8 @@ macro async*(prc: stmt): stmt {.immediate.} =
 
   # -> createCb(retFuture)
   var cbName = newIdentNode("cb")
-  var procCb = newCall("createCb", retFutureSym, iteratorNameSym)
+  var procCb = newCall("createCb", retFutureSym, iteratorNameSym,
+                       newStrLitNode(prc[0].getName))
   outerProcBody.add procCb
 
   # -> return retFuture
@@ -1010,6 +1015,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
   result[6] = outerProcBody
 
   #echo(treeRepr(result))
+  #if prc[0].getName == "routeReq":
   #echo(toStrLit(result))
 
 proc recvLine*(socket: TAsyncFD): PFuture[string] {.async.} =
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
index 005c56ebc..1b47cf5f1 100644
--- a/lib/pure/asynchttpserver.nim
+++ b/lib/pure/asynchttpserver.nim
@@ -20,7 +20,7 @@ type
     protocol*: tuple[orig: string, major, minor: int]
     url*: TURL
     hostname*: string ## The hostname of the client that made the request.
-    body*: string # TODO
+    body*: string
 
   PAsyncHttpServer* = ref object
     socket: PAsyncSocket
@@ -78,7 +78,7 @@ proc parseHeader(line: string): tuple[key, value: string] =
   i += line.skipWhiteSpace(i)
   i += line.parseUntil(result.value, {'\c', '\L'}, i)
 
-proc parseProtocol(protocol: string):  tuple[orig: string, major, minor: int] =
+proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
   var i = protocol.skipIgnoreCase("HTTP/")
   if i != 5:
     raise newException(EInvalidValue, "Invalid request protocol. Got: " &
@@ -88,6 +88,9 @@ proc parseProtocol(protocol: string):  tuple[orig: string, major, minor: int] =
   i.inc # Skip .
   i.inc protocol.parseInt(result.minor, i)
 
+proc sendStatus(client: PAsyncSocket, status: string): PFuture[void] =
+  client.send("HTTP/1.1 " & status & "\c\L")
+
 proc processClient(client: PAsyncSocket, address: string,
                  callback: proc (request: TRequest): PFuture[void]) {.async.} =
   # GET /path HTTP/1.1
@@ -97,6 +100,7 @@ proc processClient(client: PAsyncSocket, address: string,
   request.hostname = address
   assert client != nil
   request.client = client
+  var runCallback = true
 
   # First line - GET /path HTTP/1.1
   let line = await client.recvLine() # TODO: Timeouts.
@@ -106,8 +110,7 @@ proc processClient(client: PAsyncSocket, address: string,
   let lineParts = line.split(' ')
   if lineParts.len != 3:
     request.respond(Http400, "Invalid request. Got: " & line)
-    client.close()
-    return
+    runCallback = false
 
   let reqMethod = lineParts[0]
   let path = lineParts[1]
@@ -132,13 +135,35 @@ proc processClient(client: PAsyncSocket, address: string,
     request.protocol = protocol.parseProtocol()
   except EInvalidValue:
     request.respond(Http400, "Invalid request protocol. Got: " & protocol)
-    return
+    runCallback = false
+
+  if reqMethod.normalize == "post":
+    # Check for Expect header
+    if request.headers.hasKey("Expect"):
+      if request.headers["Expect"].toLower == "100-continue":
+        await client.sendStatus("100 Continue")
+      else:
+        await client.sendStatus("417 Expectation Failed")
   
+    # Read the body
+    # - Check for Content-length header
+    if request.headers.hasKey("Content-Length"):
+      var contentLength = 0
+      if parseInt(request.headers["Content-Length"], contentLength) == 0:
+        await request.respond(Http400, "Bad Request. Invalid Content-Length.")
+      else:
+        request.body = await client.recv(contentLength)
+        assert request.body.len == contentLength
+    else:
+      await request.respond(Http400, "Bad Request. No Content-Length.")
+      runCallback = false
+
   case reqMethod.normalize
   of "get", "post", "head", "put", "delete", "trace", "options", "connect", "patch":
-    await callback(request)
+    if runCallback:
+      await callback(request)
   else:
-    request.respond(Http400, "Invalid request method. Got: " & reqMethod)
+    await request.respond(Http400, "Invalid request method. Got: " & reqMethod)
 
   # Persistent connections
   if (request.protocol == HttpVer11 and
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index f5db9d3fa..15bb2a154 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -47,19 +47,15 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
       result[i] = itm
       inc(i)
 
-proc distnct*[T](seq1: seq[T]): seq[T] =
+proc deduplicate*[T](seq1: seq[T]): seq[T] =
   ## Returns a new sequence without duplicates.
   ##
-  ## This proc is `misspelled` on purpose to avoid a clash with the keyword
-  ## ``distinct`` used to `define a derived type incompatible with its base
-  ## type <manual.html#distinct-type>`_. Example:
-  ##
   ## .. code-block:: nimrod
   ##   let
   ##     dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
   ##     dup2 = @["a", "a", "c", "d", "d"]
-  ##     unique1 = distnct(dup1)
-  ##     unique2 = distnct(dup2)
+  ##     unique1 = deduplicate(dup1)
+  ##     unique2 = deduplicate(dup2)
   ##   assert unique1 == @[1, 3, 4, 2, 8]
   ##   assert unique2 == @["a", "c", "d"]
   result = @[]
@@ -387,8 +383,8 @@ when isMainModule:
     let
       dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
       dup2 = @["a", "a", "c", "d", "d"]
-      unique1 = distnct(dup1)
-      unique2 = distnct(dup2)
+      unique1 = deduplicate(dup1)
+      unique2 = deduplicate(dup2)
     assert unique1 == @[1, 3, 4, 2, 8]
     assert unique2 == @["a", "c", "d"]
 
diff --git a/tests/seq/tsequtils.nim b/tests/seq/tsequtils.nim
index 7bc15ef9c..3a7eeeffa 100644
--- a/tests/seq/tsequtils.nim
+++ b/tests/seq/tsequtils.nim
@@ -50,6 +50,6 @@ var concatseq = concat(seq1,seq2)
 echo "Concat: ", $$(concatseq)
 
 var seq3 = @[1,2,3,4,5,5,5,7]
-var discntseq = distnct(seq3)
-echo "Distnct: ", $$(discntseq)
+var dedupseq = deduplicate(seq3)
+echo "Deduplicate: ", $$(dedupseq)
 
diff --git a/web/news.txt b/web/news.txt
index b7403a3c7..eef71a2f7 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -19,6 +19,7 @@ News
 
   - Added module ``cpuinfo``.
   - Added module ``threadpool``.
+  - ``sequtils.distnct`` has been renamed to ``sequtils.deduplicate``.
 
 
 2014-04-21 Version 0.9.4 released