summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md5
-rw-r--r--compiler/ccgexprs.nim35
-rw-r--r--compiler/ccgliterals.nim91
-rw-r--r--compiler/ccgtypes.nim13
-rw-r--r--compiler/cgen.nim17
-rw-r--r--compiler/cgendata.nim3
-rw-r--r--compiler/pragmas.nim2
-rw-r--r--compiler/renderer.nim35
-rw-r--r--doc/advopt.txt4
-rw-r--r--lib/core/macros.nim44
-rw-r--r--lib/core/seqs.nim6
-rw-r--r--lib/core/strs.nim7
-rw-r--r--lib/pure/algorithm.nim27
-rw-r--r--lib/pure/collections/sets.nim2
-rw-r--r--lib/pure/cookies.nim24
-rw-r--r--lib/pure/json.nim2
-rw-r--r--lib/pure/osproc.nim8
-rw-r--r--lib/system/sysstr.nim4
-rw-r--r--lib/windows/winlean.nim5
-rw-r--r--tests/parser/tpostexprblocks.nim9
-rw-r--r--tests/stdlib/talgorithm.nim11
-rw-r--r--tests/stdlib/tjsonmacro.nim15
-rw-r--r--tests/vm/tnimnode.nim12
23 files changed, 243 insertions, 138 deletions
diff --git a/changelog.md b/changelog.md
index b8d28b633..a1a893237 100644
--- a/changelog.md
+++ b/changelog.md
@@ -7,6 +7,8 @@
 - ``re.split`` for empty regular expressions now yields every character in
   the string which is what other programming languages chose to do.
 
+- ``cookies.setCookie` no longer assumes UTC for the expiration date.
+
 #### Breaking changes in the compiler
 
 ### Library additions
@@ -18,6 +20,9 @@
 
 ### Library changes
 
+- ``macros.astGenRepr``, ``macros.lispRepr`` and ``macros.treeRepr``
+  now escapes the content of string literals consistently.
+
 ### Language additions
 
 ### Language changes
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index dc06c8482..6ee7d698e 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -30,12 +30,6 @@ proc intLiteral(i: BiggestInt): Rope =
   else:
     result = ~"(IL64(-9223372036854775807) - IL64(1))"
 
-proc getStrLit(m: BModule, s: string): Rope =
-  discard cgsym(m, "TGenericSeq")
-  result = getTempName(m)
-  addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
-       [result, makeCString(s), rope(len(s))])
-
 proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
   if ty == nil: internalError(n.info, "genLiteral: ty is nil")
   case n.kind
@@ -65,19 +59,14 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
     else:
       result = rope("NIM_NIL")
   of nkStrLit..nkTripleStrLit:
-    if n.strVal.isNil:
-      result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", [])
-    elif skipTypes(ty, abstractVarRange).kind == tyString:
-      let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
-      if id == p.module.labels:
-        # string literal not found in the cache:
-        result = ropecg(p.module, "((#NimStringDesc*) &$1)",
-                        [getStrLit(p.module, n.strVal)])
-      else:
-        result = ropecg(p.module, "((#NimStringDesc*) &$1$2)",
-                        [p.module.tmpBase, rope(id)])
+    case skipTypes(ty, abstractVarRange).kind
+    of tyNil:
+      result = genNilStringLiteral(p.module, n.info)
+    of tyString:
+      result = genStringLiteral(p.module, n)
     else:
-      result = makeCString(n.strVal)
+      if n.strVal.isNil: result = rope("NIM_NIL")
+      else: result = makeCString(n.strVal)
   of nkFloatLit, nkFloat64Lit:
     result = rope(n.floatVal.toStrMaxPrecision)
   of nkFloat32Lit:
@@ -818,16 +807,16 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
     genInExprAux(p, it, u, v, test)
     let id = nodeTableTestOrSet(p.module.dataCache,
                                newStrNode(nkStrLit, field.name.s), p.module.labels)
-    let strLit = if id == p.module.labels: getStrLit(p.module, field.name.s)
+    let strLit = if id == p.module.labels: genStringLiteralDataOnly(p.module, field.name.s, e.info)
                  else: p.module.tmpBase & rope(id)
     if op.magic == mNot:
       linefmt(p, cpsStmts,
-              "if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
-              rdLoc(test), strLit)
+              "if ($1) #raiseFieldError($2);$n",
+              rdLoc(test), genStringLiteralFromData(p.module, strLit, e.info))
     else:
       linefmt(p, cpsStmts,
-              "if (!($1)) #raiseFieldError(((#NimStringDesc*) &$2));$n",
-              rdLoc(test), strLit)
+              "if (!($1)) #raiseFieldError($2);$n",
+              rdLoc(test), genStringLiteralFromData(p.module, strLit, e.info))
 
 proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
   if optFieldCheck in p.options:
diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim
new file mode 100644
index 000000000..b17a5eedd
--- /dev/null
+++ b/compiler/ccgliterals.nim
@@ -0,0 +1,91 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2018 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This include file contains the logic to produce constant string
+## and seq literals. The code here is responsible that
+## ``const x = ["a", "b"]`` works without hidden runtime creation code.
+## The price is that seqs and strings are not purely a library
+## implementation.
+
+template detectVersion(field, corename) =
+  if m.g.field == 0:
+    let core = getCompilerProc(corename)
+    if core == nil or core.kind != skConst:
+      m.g.field = 1
+    else:
+      m.g.field = int ast.getInt(core.ast)
+  result = m.g.field
+
+proc detectStrVersion(m: BModule): int =
+  detectVersion(strVersion, "nimStrVersion")
+
+proc detectSeqVersion(m: BModule): int =
+  detectVersion(seqVersion, "nimSeqVersion")
+
+# ----- Version 1: GC'ed strings and seqs --------------------------------
+
+proc genStringLiteralDataOnlyV1(m: BModule, s: string): Rope =
+  discard cgsym(m, "TGenericSeq")
+  result = getTempName(m)
+  addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
+       [result, makeCString(s), rope(len(s))])
+
+proc genStringLiteralV1(m: BModule; n: PNode): Rope =
+  if s.isNil:
+    result = ropecg(m, "((#NimStringDesc*) NIM_NIL)", [])
+  else:
+    let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
+    if id == m.labels:
+      # string literal not found in the cache:
+      result = ropecg(m, "((#NimStringDesc*) &$1)",
+                      [genStringLiteralDataOnlyV1(m, n.strVal)])
+    else:
+      result = ropecg(m, "((#NimStringDesc*) &$1$2)",
+                      [m.tmpBase, rope(id)])
+
+# ------ Version 2: destructor based strings and seqs -----------------------
+
+proc genStringLiteralDataOnlyV2(m: BModule, s: string): Rope =
+  result = getTempName(m)
+  addf(m.s[cfsData], " static const NIM_CHAR $1[$2] = $3;$n",
+       [result, rope(len(s)+1), makeCString(s)])
+
+proc genStringLiteralV2(m: BModule; n: PNode): Rope =
+  let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
+  if id == m.labels:
+    # string literal not found in the cache:
+    let pureLit = genStringLiteralDataOnlyV2(m, n.strVal)
+    result = getTempName(m)
+    addf(m.s[cfsData], "static const #NimStringV2 $1 = {$2, $2, $3};$n",
+        [result, rope(len(n.strVal)+1), pureLit])
+  else:
+    result = m.tmpBase & rope(id)
+
+# ------ Version selector ---------------------------------------------------
+
+proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo): Rope =
+  case detectStrVersion(m)
+  of 0, 1: result = genStringLiteralDataOnlyV1(m, s)
+  of 2: result = genStringLiteralDataOnlyV2(m, s)
+  else:
+    localError(info, "cannot determine how to produce code for string literal")
+
+proc genStringLiteralFromData(m: BModule; data: Rope; info: TLineInfo): Rope =
+  result = ropecg(m, "((#NimStringDesc*) &$1)",
+                [data])
+
+proc genNilStringLiteral(m: BModule; info: TLineInfo): Rope =
+  result = ropecg(m, "((#NimStringDesc*) NIM_NIL)", [])
+
+proc genStringLiteral(m: BModule; n: PNode): Rope =
+  case detectStrVersion(m)
+  of 0, 1: result = genStringLiteralV1(m, n)
+  of 2: result = genStringLiteralV2(m, n)
+  else:
+    localError(n.info, "cannot determine how to produce code for string literal")
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index ed44c577d..2a4a10555 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -267,10 +267,6 @@ proc addAbiCheck(m: BModule, t: PType, name: Rope) =
   if isDefined("checkabi"):
     addf(m.s[cfsTypeInfo], "NIM_CHECK_SIZE($1, $2);$n", [name, rope(getSize(t))])
 
-proc getTempName(m: BModule): Rope =
-  result = m.tmpBase & rope(m.labels)
-  inc m.labels
-
 proc ccgIntroducedPtr(s: PSym): bool =
   var pt = skipTypes(s.typ, typedescInst)
   assert skResult != s.kind
@@ -316,8 +312,13 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
   of tyPointer:
     result = typeNameOrLiteral(m, typ, "void*")
   of tyString:
-    discard cgsym(m, "NimStringDesc")
-    result = typeNameOrLiteral(m, typ, "NimStringDesc*")
+    case detectStrVersion(m)
+    of 2:
+      discard cgsym(m, "string")
+      result = typeNameOrLiteral(m, typ, "NimStringV2")
+    else:
+      discard cgsym(m, "NimStringDesc")
+      result = typeNameOrLiteral(m, typ, "NimStringDesc*")
   of tyCString: result = typeNameOrLiteral(m, typ, "NCSTRING")
   of tyBool: result = typeNameOrLiteral(m, typ, "NIM_BOOL")
   of tyChar: result = typeNameOrLiteral(m, typ, "NIM_CHAR")
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 01610010b..05f222520 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -238,7 +238,12 @@ proc genProc(m: BModule, prc: PSym)
 template compileToCpp(m: BModule): untyped =
   gCmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags
 
-include "ccgtypes.nim"
+proc getTempName(m: BModule): Rope =
+  result = m.tmpBase & rope(m.labels)
+  inc m.labels
+
+include ccgliterals
+include ccgtypes
 
 # ------------------------------ Manager of temporaries ------------------
 
@@ -551,11 +556,13 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
       for i in countup(0, high(s)):
         inc(m.labels)
         if i > 0: add(loadlib, "||")
-        appcg(m, loadlib, "($1 = #nimLoadLibrary((#NimStringDesc*) &$2))$n",
-              [tmp, getStrLit(m, s[i])])
+        let n = newStrNode(nkStrLit, s[i])
+        n.info = lib.path.info
+        appcg(m, loadlib, "($1 = #nimLoadLibrary($2))$n",
+              [tmp, genStringLiteral(m, n)])
       appcg(m, m.s[cfsDynLibInit],
-            "if (!($1)) #nimLoadLibraryError((#NimStringDesc*) &$2);$n",
-            [loadlib, getStrLit(m, lib.path.strVal)])
+            "if (!($1)) #nimLoadLibraryError($2);$n",
+            [loadlib, genStringLiteral(m, lib.path)])
     else:
       var p = newProc(nil, m)
       p.options = p.options - {optStackTrace, optEndb}
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index efa346934..f8167acdc 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -70,7 +70,7 @@ type
     threadVarAccessed*: bool  # true if the proc already accessed some threadvar
     lastLineInfo*: TLineInfo  # to avoid generating excessive 'nimln' statements
     currLineInfo*: TLineInfo  # AST codegen will make this superfluous
-    nestedTryStmts*: seq[tuple[n: PNode, inExcept: bool]]  
+    nestedTryStmts*: seq[tuple[n: PNode, inExcept: bool]]
                               # in how many nested try statements we are
                               # (the vars must be volatile then)
                               # bool is true when are in the except part of a try block
@@ -116,6 +116,7 @@ type
     breakpoints*: Rope # later the breakpoints are inserted into the main proc
     typeInfoMarker*: TypeCache
     config*: ConfigRef
+    strVersion*, seqVersion*: int # version of the string/seq implementation to use
 
   TCGen = object of TPassContext # represents a C source file
     s*: TCFileSections        # sections of the C file
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 1295ee18d..78ded578f 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -65,7 +65,7 @@ const
     wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims, wUsed}
   constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
     wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims,
-    wIntDefine, wStrDefine, wUsed}
+    wIntDefine, wStrDefine, wUsed, wCompilerProc, wCore}
   letPragmas* = varPragmas
   procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
                       wThread, wRaises, wLocks, wTags, wGcSafe}
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index fa93c968a..0b1b0479f 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -173,25 +173,30 @@ proc put(g: var TSrcGen, kind: TTokType, s: string) =
   else:
     g.pendingWhitespace = s.len
 
-proc toNimChar(c: char): string =
+proc addNimChar(dst: var string; c: char): void =
   case c
-  of '\0': result = "\\x00" # not "\\0" to avoid ambiguous cases like "\\012".
-  of '\a': result = "\\a" # \x07
-  of '\b': result = "\\b" # \x08
-  of '\t': result = "\\t" # \x09
-  of '\L': result = "\\L" # \x0A
-  of '\v': result = "\\v" # \x0B
-  of '\f': result = "\\f" # \x0C
-  of '\c': result = "\\c" # \x0D
-  of '\e': result = "\\e" # \x1B
+  of '\0': dst.add "\\x00" # not "\\0" to avoid ambiguous cases like "\\012".
+  of '\a': dst.add "\\a" # \x07
+  of '\b': dst.add "\\b" # \x08
+  of '\t': dst.add "\\t" # \x09
+  of '\L': dst.add "\\L" # \x0A
+  of '\v': dst.add "\\v" # \x0B
+  of '\f': dst.add "\\f" # \x0C
+  of '\c': dst.add "\\c" # \x0D
+  of '\e': dst.add "\\e" # \x1B
   of '\x01'..'\x06', '\x0E'..'\x1A', '\x1C'..'\x1F', '\x80'..'\xFF':
-    result = "\\x" & strutils.toHex(ord(c), 2)
-  of '\'', '\"', '\\': result = '\\' & c
-  else: result = c & ""
+    dst.add "\\x"
+    dst.add strutils.toHex(ord(c), 2)
+  of '\'', '\"', '\\':
+    dst.add '\\'
+    dst.add c
+  else:
+    dst.add c
 
 proc makeNimString(s: string): string =
   result = "\""
-  for i in countup(0, len(s)-1): add(result, toNimChar(s[i]))
+  for c in s:
+    result.addNimChar c
   add(result, '\"')
 
 proc putComment(g: var TSrcGen, s: string) =
@@ -364,7 +369,7 @@ proc atom(g: TSrcGen; n: PNode): string =
   of nkStrLit: result = makeNimString(n.strVal)
   of nkRStrLit: result = "r\"" & replace(n.strVal, "\"", "\"\"")  & '\"'
   of nkTripleStrLit: result = "\"\"\"" & n.strVal & "\"\"\""
-  of nkCharLit: result = '\'' & toNimChar(chr(int(n.intVal))) & '\''
+  of nkCharLit: result = "\'"; result.addNimChar chr(int(n.intVal)); result.add '\''
   of nkIntLit: result = litAux(g, n, n.intVal, 4)
   of nkInt8Lit: result = litAux(g, n, n.intVal, 1) & "\'i8"
   of nkInt16Lit: result = litAux(g, n, n.intVal, 2) & "\'i16"
diff --git a/doc/advopt.txt b/doc/advopt.txt
index 77531f5de..ac309c222 100644
--- a/doc/advopt.txt
+++ b/doc/advopt.txt
@@ -31,8 +31,8 @@ Advanced options:
   --nimcache:PATH           set the path used for generated files
   --header:FILE             the compiler should produce a .h file (FILE
                             is optional)
-  -c, --compileOnly         compile only; do not assemble or link
-  --noLinking               compile but do not link
+  -c, --compileOnly         compile Nim files only; do not assemble or link
+  --noLinking               compile Nim and generated files but do not link
   --noMain                  do not generate a main procedure
   --genScript               generate a compile script (in the 'nimcache'
                             subdirectory named 'compile_$project$scriptext')
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index d09f5f933..5a4c4c1e9 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -620,7 +620,7 @@ proc treeRepr*(n: NimNode): string {.compileTime, benign.} =
     of nnkNilLit: res.add(" nil")
     of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
     of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
-    of nnkStrLit..nnkTripleStrLit: res.add(" " & $n.strVal)
+    of nnkStrLit..nnkTripleStrLit: res.add(" " & $n.strVal.newLit.repr)
     of nnkIdent: res.add(" ident\"" & $n.ident & '"')
     of nnkSym: res.add(" \"" & $n.symbol & '"')
     of nnkNone: assert false
@@ -645,7 +645,7 @@ proc lispRepr*(n: NimNode): string {.compileTime, benign.} =
   of nnkNilLit: add(result, "nil")
   of nnkCharLit..nnkInt64Lit: add(result, $n.intVal)
   of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
-  of nnkStrLit..nnkTripleStrLit: add(result, $n.strVal)
+  of nnkStrLit..nnkTripleStrLit, nnkCommentStmt: add(result, n.strVal.newLit.repr)
   of nnkIdent: add(result, "ident\"" & $n.ident & '"')
   of nnkSym: add(result, $n.symbol)
   of nnkNone: assert false
@@ -681,33 +681,6 @@ proc astGenRepr*(n: NimNode): string {.compileTime, benign.} =
     NodeKinds = {nnkEmpty, nnkNilLit, nnkIdent, nnkSym, nnkNone, nnkCommentStmt}
     LitKinds = {nnkCharLit..nnkInt64Lit, nnkFloatLit..nnkFloat64Lit, nnkStrLit..nnkTripleStrLit}
 
-  proc escape(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect.} =
-    ## Functions copied from strutils
-    proc toHex(x: BiggestInt, len: Positive): string {.noSideEffect, rtl.} =
-      const
-        HexChars = "0123456789ABCDEF"
-      var
-        t = x
-      result = newString(len)
-      for j in countdown(len-1, 0):
-        result[j] = HexChars[int(t and 0xF)]
-        t = t shr 4
-        # handle negative overflow
-        if t == 0 and x < 0: t = -1
-
-    result = newStringOfCap(s.len + s.len shr 2)
-    result.add(prefix)
-    for c in items(s):
-      case c
-      of '\0'..'\31', '\128'..'\255':
-        add(result, "\\x")
-        add(result, toHex(ord(c), 2))
-      of '\\': add(result, "\\\\")
-      of '\'': add(result, "\\'")
-      of '\"': add(result, "\\\"")
-      else: add(result, c)
-    add(result, suffix)
-
   proc traverse(res: var string, level: int, n: NimNode) {.benign.} =
     for i in 0..level-1: res.add "  "
     if n.kind in NodeKinds:
@@ -723,9 +696,9 @@ proc astGenRepr*(n: NimNode): string {.compileTime, benign.} =
     of nnkCharLit: res.add("'" & $chr(n.intVal) & "'")
     of nnkIntLit..nnkInt64Lit: res.add($n.intVal)
     of nnkFloatLit..nnkFloat64Lit: res.add($n.floatVal)
-    of nnkStrLit..nnkTripleStrLit, nnkCommentStmt: res.add($n.strVal.escape())
-    of nnkIdent: res.add(($n.ident).escape())
-    of nnkSym: res.add(($n.symbol).escape())
+    of nnkStrLit..nnkTripleStrLit, nnkCommentStmt: res.add($n.strVal.newLit.repr)
+    of nnkIdent: res.add(($n.ident).newLit.repr())
+    of nnkSym: res.add(($n.symbol).newLit.repr())
     of nnkNone: assert false
     else:
       res.add(".newTree(")
@@ -774,7 +747,6 @@ macro dumpTreeImm*(s: untyped): untyped {.deprecated.} = echo s.treeRepr
 macro dumpLispImm*(s: untyped): untyped {.deprecated.} = echo s.lispRepr
   ## Deprecated.
 
-
 proc newEmptyNode*(): NimNode {.compileTime, noSideEffect.} =
   ## Create a new empty node
   result = newNimNode(nnkEmpty)
@@ -1227,7 +1199,7 @@ proc customPragmaNode(n: NimNode): NimNode =
     let recList = typDef[2][2]
     for identDefs in recList:
       for i in 0 .. identDefs.len - 3:
-        if identDefs[i].kind == nnkPragmaExpr and 
+        if identDefs[i].kind == nnkPragmaExpr and
            identDefs[i][0].kind == nnkIdent and $identDefs[i][0] == $n[1]:
           return identDefs[i][1]
 
@@ -1237,7 +1209,7 @@ macro hasCustomPragma*(n: typed, cp: typed{nkSym}): untyped =
   ##
   ## .. code-block:: nim
   ##   template myAttr() {.pragma.}
-  ##   type 
+  ##   type
   ##     MyObj = object
   ##       myField {.myAttr.}: int
   ##   var o: MyObj
@@ -1255,7 +1227,7 @@ macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped =
   ##
   ## .. code-block:: nim
   ##   template serializationKey(key: string) {.pragma.}
-  ##   type 
+  ##   type
   ##     MyObj = object
   ##       myField {.serializationKey: "mf".}: int
   ##   var o: MyObj
diff --git a/lib/core/seqs.nim b/lib/core/seqs.nim
index c32cf3690..02c192851 100644
--- a/lib/core/seqs.nim
+++ b/lib/core/seqs.nim
@@ -15,11 +15,11 @@ type
     len, cap: int
     data: ptr UncheckedArray[T]
 
+const nimSeqVersion {.core.} = 2
+
 template frees(s) = dealloc(s.data, s.cap * sizeof(T))
 
 # XXX make code memory safe for overflows in '*'
-proc nimSeqLiteral[T](x: openArray[T]): seq[T] {.core.} =
-  seq[T](len: x.len, cap: x.len, data: x)
 
 when defined(nimHasTrace):
   proc `=trace`[T](s: seq[T]; a: Allocator) =
@@ -120,7 +120,7 @@ proc `$`*[T](x: seq[T]): string =
   result = "@["
   var firstElement = true
   for i in 0..<x.len:
-    let 
+    let
       value = x.data[i]
     if firstElement:
       firstElement = false
diff --git a/lib/core/strs.nim b/lib/core/strs.nim
index 1958f4974..ff38aef1d 100644
--- a/lib/core/strs.nim
+++ b/lib/core/strs.nim
@@ -12,12 +12,11 @@
 import allocators
 
 type
-  string {.core.} = object
+  string {.core, exportc: "NimStringV2".} = object
     len, cap: int
     data: ptr UncheckedArray[char]
 
-proc nimStringLiteral(x: cstring; len: int): string {.core.} =
-  string(len: len, cap: len, data: x)
+const nimStrVersion {.core.} = 2
 
 template frees(s) = dealloc(s.data, s.cap + 1)
 
@@ -80,7 +79,7 @@ proc newString*(len: int): string =
   if len > 0:
     result.data = alloc0(len+1)
 
-converter toCString(x: string): cstring {.core.} =
+converter toCString(x: string): cstring {.core, inline.} =
   if x.len == 0: cstring"" else: cast[cstring](x.data)
 
 proc newStringOfCap*(cap: int): string =
diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim
index 2f7b44b31..45e031574 100644
--- a/lib/pure/algorithm.nim
+++ b/lib/pure/algorithm.nim
@@ -24,16 +24,20 @@ 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`.
+template fillImpl[T](a: var openArray[T], first, last: int, value: T) =
   var x = first
   while x <= last:
     a[x] = value
     inc(x)
 
+proc fill*[T](a: var openArray[T], first, last: Natural, value: T) =
+  ## fills the array ``a[first..last]`` with `value`.
+  fillImpl(a, first, last, value)
+
 proc fill*[T](a: var openArray[T], value: T) =
   ## fills the array `a` with `value`.
-  fill(a, 0, a.high, value)
+  fillImpl(a, 0, a.high, value)
+
 
 proc reverse*[T](a: var openArray[T], first, last: Natural) =
   ## reverses the array ``a[first..last]``.
@@ -494,3 +498,20 @@ when isMainModule:
   doAssert s4 == "xxxefgabcdxxx"
   doAssert s5.rotateLeft(3 ..< 10, 11) == 6
   doAssert s5 == "xxxefgabcdxxx"
+
+  block product:
+    doAssert product(newSeq[seq[int]]()) == newSeq[seq[int]](), "empty input"
+    doAssert product(@[newSeq[int](), @[], @[]]) == newSeq[seq[int]](), "bit more empty input"
+    doAssert product(@[@[1,2]]) == @[@[1,2]], "a simple case of one element"
+    doAssert product(@[@[1,2], @[3,4]]) == @[@[2,4],@[1,4],@[2,3],@[1,3]], "two elements"
+    doAssert product(@[@[1,2], @[3,4], @[5,6]]) == @[@[2,4,6],@[1,4,6],@[2,3,6],@[1,3,6], @[2,4,5],@[1,4,5],@[2,3,5],@[1,3,5]], "three elements"
+    doAssert product(@[@[1,2], @[]]) == newSeq[seq[int]](), "two elements, but one empty"
+
+  block lowerBound:
+    doAssert lowerBound([1,2,4], 3, system.cmp[int]) == 2
+    doAssert lowerBound([1,2,2,3], 4, system.cmp[int]) == 4
+    doAssert lowerBound([1,2,3,10], 11) == 4
+
+  block fillEmptySeq:
+    var s = newSeq[int]()
+    s.fill(0)
\ No newline at end of file
diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim
index 9e9152fc8..32b6387ad 100644
--- a/lib/pure/collections/sets.nim
+++ b/lib/pure/collections/sets.nim
@@ -11,7 +11,7 @@
 ## ordered hash set.
 ##
 ## Hash sets are different from the `built in set type
-## <manual.html#set-type>`_. Sets allow you to store any value that can be
+## <manual.html#types-set-type>`_. Sets allow you to store any value that can be
 ## `hashed <hashes.html>`_ and they don't contain duplicate entries.
 ##
 ## **Note**: The data types declared here have *value semantics*: This means
diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim
index 8f16717ac..aca0ac2b4 100644
--- a/lib/pure/cookies.nim
+++ b/lib/pure/cookies.nim
@@ -51,26 +51,26 @@ proc setCookie*(key, value: string, domain = "", path = "",
   if secure: result.add("; Secure")
   if httpOnly: result.add("; HttpOnly")
 
-proc setCookie*(key, value: string, expires: DateTime,
+proc setCookie*(key, value: string, expires: DateTime|Time,
                 domain = "", path = "", noName = false,
                 secure = false, httpOnly = false): string =
   ## Creates a command in the format of
   ## ``Set-Cookie: key=value; Domain=...; ...``
-  ##
-  ## **Note:** UTC is assumed as the timezone for ``expires``.
   return setCookie(key, value, domain, path,
-                   format(expires, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'"),
+                   format(expires.utc, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'"),
                    noname, secure, httpOnly)
 
 when isMainModule:
-  var tim = fromUnix(getTime().toUnix + 76 * (60 * 60 * 24))
+  let expire = fromUnix(0) + 1.seconds
 
-  let cookie = setCookie("test", "value", tim.utc)
-  when not defined(testing):
-    echo cookie
-  let start = "Set-Cookie: test=value; Expires="
-  assert cookie[0..start.high] == start
+  let cookies = [
+    setCookie("test", "value", expire),
+    setCookie("test", "value", expire.local),
+    setCookie("test", "value", expire.utc)
+  ]
+  let expected = "Set-Cookie: test=value; Expires=Thu, 01 Jan 1970 00:00:01 GMT"
+  doAssert cookies == [expected, expected, expected]
 
   let table = parseCookies("uid=1; kp=2")
-  assert table["uid"] == "1"
-  assert table["kp"] == "2"
+  doAssert table["uid"] == "1"
+  doAssert table["kp"] == "2"
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 912cd6837..da1b66188 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -1697,7 +1697,7 @@ proc createConstructor(typeSym, jsonNode: NimNode): NimNode =
 
       result = quote do:
         (
-          if `lenientJsonNode`.isNil: `workaround`[`optionGeneric`]() else: some[`optionGeneric`](`value`)
+          if `lenientJsonNode`.isNil or `jsonNode`.kind == JNull: `workaround`[`optionGeneric`]() else: some[`optionGeneric`](`value`)
         )
     of "table", "orderedtable":
       let tableKeyType = typeSym[1]
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index c1c727fc6..555626514 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -494,7 +494,7 @@ when defined(Windows) and not defined(useNimRtl):
     sa.nLength = sizeof(SECURITY_ATTRIBUTES).cint
     sa.lpSecurityDescriptor = nil
     sa.bInheritHandle = 1
-    if createPipe(rdHandle, wrHandle, sa, 1024) == 0'i32:
+    if createPipe(rdHandle, wrHandle, sa, 0) == 0'i32:
       raiseOSError(osLastError())
 
   proc fileClose(h: Handle) {.inline.} =
@@ -524,6 +524,12 @@ when defined(Windows) and not defined(useNimRtl):
           he = ho
         else:
           createPipeHandles(he, si.hStdError)
+          if setHandleInformation(he, DWORD(1), DWORD(0)) == 0'i32:
+            raiseOsError(osLastError())
+        if setHandleInformation(hi, DWORD(1), DWORD(0)) == 0'i32:
+          raiseOsError(osLastError())  
+        if setHandleInformation(ho, DWORD(1), DWORD(0)) == 0'i32:
+          raiseOsError(osLastError())
       else:
         createAllPipeHandles(si, hi, ho, he, cast[int](result))
       result.inHandle = FileHandle(hi)
diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim
index 5bf90c895..ea0273340 100644
--- a/lib/system/sysstr.nim
+++ b/lib/system/sysstr.nim
@@ -293,7 +293,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
 
     # XXX: zeroing out the memory can still result in crashes if a wiped-out
     # cell is aliased by another pointer (ie proc parameter or a let variable).
-    # This is a tought problem, because even if we don't zeroMem here, in the
+    # This is a tough problem, because even if we don't zeroMem here, in the
     # presence of user defined destructors, the user will expect the cell to be
     # "destroyed" thus creating the same problem. We can destoy the cell in the
     # finalizer of the sequence, but this makes destruction non-deterministic.
@@ -420,7 +420,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
     return 0
 
   if s[i] in {'0'..'9'}:
-      first_digit = (s[i].ord - '0'.ord)
+    first_digit = (s[i].ord - '0'.ord)
   # Integer part?
   while s[i] in {'0'..'9'}:
     inc(kdigits)
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index a0c784637..f40344396 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -704,6 +704,11 @@ proc duplicateHandle*(hSourceProcessHandle: HANDLE, hSourceHandle: HANDLE,
                       dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,
                       dwOptions: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",
     importc: "DuplicateHandle".}
+
+proc setHandleInformation*(hObject: HANDLE, dwMask: DWORD,
+                           dwFlags: DWORD): WINBOOL {.stdcall,
+    dynlib: "kernel32", importc: "SetHandleInformation".}
+
 proc getCurrentProcess*(): HANDLE{.stdcall, dynlib: "kernel32",
                                    importc: "GetCurrentProcess".}
 
diff --git a/tests/parser/tpostexprblocks.nim b/tests/parser/tpostexprblocks.nim
index 3b9c956c2..e97b9c7ee 100644
--- a/tests/parser/tpostexprblocks.nim
+++ b/tests/parser/tpostexprblocks.nim
@@ -22,26 +22,26 @@ StmtList
         Empty
   Call
     Ident ident"foo070"
-    StrLit test
+    StrLit "test"
     StmtList
       DiscardStmt
         Empty
   Call
     Ident ident"foo080"
-    StrLit test
+    StrLit "test"
     StmtList
       DiscardStmt
         Empty
   Command
     Ident ident"foo090"
-    StrLit test
+    StrLit "test"
     StmtList
       DiscardStmt
         Empty
   Command
     Ident ident"foo100"
     Call
-      StrLit test
+      StrLit "test"
       StmtList
         DiscardStmt
           Empty
@@ -540,4 +540,3 @@ dumpTree:
   foo380.add((quote do:
     discard
   )[0])
-
diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim
deleted file mode 100644
index f200e54c5..000000000
--- a/tests/stdlib/talgorithm.nim
+++ /dev/null
@@ -1,11 +0,0 @@
-import algorithm
-
-doAssert product[int](newSeq[seq[int]]()) == newSeq[seq[int]](), "empty input"
-doAssert product[int](@[newSeq[int](), @[], @[]]) == newSeq[seq[int]](), "bit more empty input"
-doAssert product(@[@[1,2]]) == @[@[1,2]], "a simple case of one element"
-doAssert product(@[@[1,2], @[3,4]]) == @[@[2,4],@[1,4],@[2,3],@[1,3]], "two elements"
-doAssert product(@[@[1,2], @[3,4], @[5,6]]) == @[@[2,4,6],@[1,4,6],@[2,3,6],@[1,3,6], @[2,4,5],@[1,4,5],@[2,3,5],@[1,3,5]], "three elements"
-doAssert product(@[@[1,2], @[]]) == newSeq[seq[int]](), "two elements, but one empty"
-doAssert lowerBound([1,2,4], 3, system.cmp[int]) == 2
-doAssert lowerBound([1,2,2,3], 4, system.cmp[int]) == 4
-doAssert lowerBound([1,2,3,10], 11) == 4
diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim
index e8740c591..f13d2e5cb 100644
--- a/tests/stdlib/tjsonmacro.nim
+++ b/tests/stdlib/tjsonmacro.nim
@@ -330,6 +330,21 @@ when isMainModule:
     doAssert jDeser[0].n2.get() == "ABC"
     doAssert jDeser[1].n2.isNone()
 
+    # Issue #6902
+    type
+      Obj = object
+        n1: int
+        n2: Option[int]
+        n3: Option[string]
+        n4: Option[bool]
+        
+    var j0 = parseJson("""{"n1": 1, "n2": null, "n3": null, "n4": null}""")
+    let j0Deser = j0.to(Obj)
+    doAssert j0Deser.n1 == 1
+    doAssert j0Deser.n2.isNone()
+    doAssert j0Deser.n3.isNone()
+    doAssert j0Deser.n4.isNone()
+
   # Table[T, Y] support.
   block:
     type
diff --git a/tests/vm/tnimnode.nim b/tests/vm/tnimnode.nim
index 0614b9807..2727df290 100644
--- a/tests/vm/tnimnode.nim
+++ b/tests/vm/tnimnode.nim
@@ -26,12 +26,12 @@ proc checkNode(arg: NimNode; name: string): void {. compileTime .} =
   seqAppend.add(arg)   # bit this creates a copy
   arg.add newCall(ident"echo", newLit("Hello World"))
 
-  assertEq arg.lispRepr          , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit(Hello World)))"""
-  assertEq node.lispRepr         , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit(Hello World)))"""
-  assertEq nodeArray[0].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit(Hello World)))"""
-  assertEq nodeSeq[0].lispRepr   , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit(Hello World)))"""
-  assertEq seqAppend[0].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit(Hello World)))"""
-  assertEq seqAppend[1].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit(Hello World)))"""
+  assertEq arg.lispRepr          , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit("Hello World")))"""
+  assertEq node.lispRepr         , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit("Hello World")))"""
+  assertEq nodeArray[0].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit("Hello World")))"""
+  assertEq nodeSeq[0].lispRepr   , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit("Hello World")))"""
+  assertEq seqAppend[0].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit("Hello World")))"""
+  assertEq seqAppend[1].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit("Hello World")))"""
 
   echo "OK"