summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/jsgen.nim48
-rw-r--r--compiler/lowerings.nim20
-rw-r--r--compiler/vm.nim12
-rw-r--r--compiler/vmdef.nim2
-rw-r--r--compiler/vmgen.nim7
-rw-r--r--contributing.rst137
-rw-r--r--doc/astspec.txt229
-rw-r--r--doc/tut2.txt12
-rw-r--r--lib/impure/nre.nim8
-rw-r--r--lib/pure/math.nim18
-rw-r--r--lib/system/jssys.nim7
-rw-r--r--tests/stdlib/nre/split.nim1
-rw-r--r--tests/vm/tconsttable2.nim81
-rw-r--r--tests/vm/tswap.nim24
-rw-r--r--web/community.txt7
15 files changed, 496 insertions, 117 deletions
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index d84b0f2f9..ede759426 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -968,7 +968,9 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
       of tyTuple:
         genFieldAddr(p, n.sons[0], r)
       else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
-  else: internalError(n.sons[0].info, "genAddr")
+  of nkObjDownConv:
+    gen(p, n.sons[0], r)
+  else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind)
 
 proc genProcForSymIfNeeded(p: PProc, s: PSym) =
   if not p.g.generatedSyms.containsOrIncl(s.id):
@@ -1096,24 +1098,32 @@ proc putToSeq(s: string, indirect: bool): Rope =
   if indirect: result = "[$1]" % [result]
 
 proc createVar(p: PProc, typ: PType, indirect: bool): Rope
-proc createRecordVarAux(p: PProc, rec: PNode, c: var int): Rope =
-  result = nil
+proc createRecordVarAux(p: PProc, rec: PNode, excludedFieldIDs: IntSet, output: var Rope) =
   case rec.kind
   of nkRecList:
     for i in countup(0, sonsLen(rec) - 1):
-      add(result, createRecordVarAux(p, rec.sons[i], c))
+      createRecordVarAux(p, rec.sons[i], excludedFieldIDs, output)
   of nkRecCase:
-    add(result, createRecordVarAux(p, rec.sons[0], c))
+    createRecordVarAux(p, rec.sons[0], excludedFieldIDs, output)
     for i in countup(1, sonsLen(rec) - 1):
-      add(result, createRecordVarAux(p, lastSon(rec.sons[i]), c))
+      createRecordVarAux(p, lastSon(rec.sons[i]), excludedFieldIDs, output)
   of nkSym:
-    if c > 0: add(result, ", ")
-    add(result, mangleName(rec.sym))
-    add(result, ": ")
-    add(result, createVar(p, rec.sym.typ, false))
-    inc(c)
+    if rec.sym.id notin excludedFieldIDs:
+      if output.len > 0: output.add(", ")
+      output.add(mangleName(rec.sym))
+      output.add(": ")
+      output.add(createVar(p, rec.sym.typ, false))
   else: internalError(rec.info, "createRecordVarAux")
 
+proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: var Rope) =
+  var t = typ
+  if tfFinal notin t.flags or t.sons[0] != nil:
+    if output.len > 0: output.add(", ")
+    addf(output, "m_type: $1" | "m_type = $#", [genTypeInfo(p, t)])
+  while t != nil:
+    createRecordVarAux(p, t.n, excludedFieldIDs, output)
+    t = t.sons[0]
+
 proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
   var t = skipTypes(typ, abstractInst)
   case t.kind
@@ -1154,15 +1164,9 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
     add(result, "}")
     if indirect: result = "[$1]" % [result]
   of tyObject:
-    result = rope("{")
-    var c = 0
-    if tfFinal notin t.flags or t.sons[0] != nil:
-      inc(c)
-      addf(result, "m_type: $1" | "m_type = $#", [genTypeInfo(p, t)])
-    while t != nil:
-      add(result, createRecordVarAux(p, t.n, c))
-      t = t.sons[0]
-    add(result, "}")
+    var initList : Rope
+    createObjInitList(p, t, initIntSet(), initList)
+    result = "{$1}" % [initList]
     if indirect: result = "[$1]" % [result]
   of tyVar, tyPtr, tyRef:
     if mapType(t) == etyBaseIndex:
@@ -1435,6 +1439,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
   r.res = rope("{")
   r.kind = resExpr
+  var fieldIDs = initIntSet()
   for i in countup(1, sonsLen(n) - 1):
     if i > 1: add(r.res, ", ")
     var it = n.sons[i]
@@ -1442,7 +1447,10 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
     gen(p, it.sons[1], a)
     var f = it.sons[0].sym
     if f.loc.r == nil: f.loc.r = mangleName(f)
+    fieldIDs.incl(f.id)
     addf(r.res, "$#: $#" | "$# = $#" , [f.loc.r, a.res])
+  let t = skipTypes(n.typ, abstractInst + skipPtrs)
+  createObjInitList(p, t, fieldIDs, r.res)
   r.res.add("}")
 
 proc genConv(p: PProc, n: PNode, r: var TCompRes) =
diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim
index b6b01d558..b4319b246 100644
--- a/compiler/lowerings.nim
+++ b/compiler/lowerings.nim
@@ -63,6 +63,26 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
     if n.sons[i].kind == nkSym: v.addVar(n.sons[i])
     result.add newAsgnStmt(n.sons[i], newTupleAccess(tempAsNode, i))
 
+proc lowerSwap*(n: PNode; owner: PSym): PNode =
+  result = newNodeI(nkStmtList, n.info)
+  # note: cannot use 'skTemp' here cause we really need the copy for the VM :-(
+  var temp = newSym(skVar, getIdent(genPrefix), owner, n.info)
+  temp.typ = n.sons[1].typ
+  incl(temp.flags, sfFromGeneric)
+
+  var v = newNodeI(nkVarSection, n.info)
+  let tempAsNode = newSymNode(temp)
+
+  var vpart = newNodeI(nkIdentDefs, v.info, 3)
+  vpart.sons[0] = tempAsNode
+  vpart.sons[1] = ast.emptyNode
+  vpart.sons[2] = n[1]
+  addSon(v, vpart)
+
+  result.add(v)
+  result.add newFastAsgnStmt(n[1], n[2])
+  result.add newFastAsgnStmt(n[2], tempAsNode)
+
 proc createObj*(owner: PSym, info: TLineInfo): PType =
   result = newType(tyObject, owner)
   rawAddSon(result, nil)
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 9f0d0bfce..826356c68 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -1051,18 +1051,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
           # set to default value:
           for i in oldLen .. <newLen:
             regs[ra].node.sons[i] = newNodeI(nkEmpty, c.debug[pc])
-    of opcSwap:
-      let rb = instr.regB
-      if regs[ra].kind == regs[rb].kind:
-        case regs[ra].kind
-        of rkNone: discard
-        of rkInt: swap regs[ra].intVal, regs[rb].intVal
-        of rkFloat: swap regs[ra].floatVal, regs[rb].floatVal
-        of rkNode: swap regs[ra].node, regs[rb].node
-        of rkRegisterAddr: swap regs[ra].regAddr, regs[rb].regAddr
-        of rkNodeAddr: swap regs[ra].nodeAddr, regs[rb].nodeAddr
-      else:
-        internalError(c.debug[pc], "cannot swap operands")
     of opcReset:
       internalError(c.debug[pc], "too implement")
     of opcNarrowS:
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index 047009f01..2d0272cd7 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -65,7 +65,7 @@ type
     opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
     opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr,
     opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
-    opcSwap, opcIsNil, opcOf, opcIs,
+    opcIsNil, opcOf, opcIs,
     opcSubStr, opcParseFloat, opcConv, opcCast,
     opcQuit, opcReset,
     opcNarrowS, opcNarrowU,
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index c68282fde..dc3188c66 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -831,12 +831,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     c.freeTemp(tmp)
   of mSwap:
     unused(n, dest)
-    var
-      d1 = c.genx(n.sons[1])
-      d2 = c.genx(n.sons[2])
-    c.gABC(n, opcSwap, d1, d2)
-    c.genAsgnPatch(n.sons[1], d1)
-    c.genAsgnPatch(n.sons[2], d2)
+    c.gen(lowerSwap(n, if c.prc == nil: c.module else: c.prc.sym))
   of mIsNil: genUnaryABC(c, n, dest, opcIsNil)
   of mCopyStr:
     if dest < 0: dest = c.getTemp(n.typ)
diff --git a/contributing.rst b/contributing.rst
new file mode 100644
index 000000000..8e669c614
--- /dev/null
+++ b/contributing.rst
@@ -0,0 +1,137 @@
+The git stuff
+=============
+
+`Guide by github, scroll down a bit <https://guides.github.com/activities/contributing-to-open-source/>`_
+
+Deprecation
+===========
+
+Backward compatibility is important, so if you are renaming a proc or
+a type, you can use
+
+
+.. code-block:: nim
+
+  {.deprecated [oldName: new_name].}
+
+Or you can simply use
+
+.. code-block:: nim
+
+  proc oldProc() {.deprecated.}
+
+to mark a symbol as deprecated. Works for procs/types/vars/consts,
+etc.
+
+`Deprecated pragma in the manual. <http://nim-lang.org/docs/manual.html#pragmas-deprecated-pragma>`_
+
+Writing tests
+=============
+
+Not all the tests follow this scheme, feel free to change the ones
+that don't. Always leave the code cleaner than you found it.
+
+Stdlib
+------
+
+If you change the stdlib (anything under ``lib/``), put a test in the
+file you changed. Add the tests under an ``when isMainModule:``
+condition so they only get executed when the tester is building the
+file. Each test should be in a separate ``block:`` statement, such that
+each has its own scope. Use boolean conditions and ``doAssert`` for the
+testing by itself, don't rely on echo statements or similar.
+
+Sample test:
+
+.. code-block:: nim
+
+  when isMainModule:
+    block: # newSeqWith tests
+      var seq2D = newSeqWith(4, newSeq[bool](2))
+      seq2D[0][0] = true
+      seq2D[1][0] = true
+      seq2D[0][1] = true
+      doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
+
+Compiler
+--------
+
+The tests for the compiler work differently, they are all located in
+``tests/``. Each test has its own file, which is different from the
+stdlib tests. At the beginning of every test is the expected side of
+the test. Possible keys are:
+
+- output: The expected output, most likely via ``echo``
+- exitcode: Exit code of the test (via ``exit(number)``)
+- errormsg: The expected error message
+- file: The file the errormsg
+- line: The line the errormsg was produced at
+
+An example for a test:
+
+.. code-block:: nim
+
+  discard """
+    errormsg: "type mismatch: got (PTest)"
+  """
+
+  type
+    PTest = ref object
+
+  proc test(x: PTest, y: int) = nil
+
+  var buf: PTest
+  buf.test()
+
+Running tests
+=============
+
+You can run the tests with
+
+.. code-block:: bash
+
+  ./koch tests
+
+which will run a good subset of tests. Some tests may fail. If you
+only want to run failing tests, go for
+
+.. code-block:: bash
+
+  ./koch tests --failing all
+
+You can also run only a single category of tests. For a list of
+categories, see ``tests/testament/categories.nim``, at the bottom.
+
+.. code-block:: bash
+
+  ./koch tests c lib
+
+Comparing tests
+===============
+
+Because some tests fail in the current ``devel`` branch, not every fail
+after your change is necessarily caused by your changes.
+
+The tester can compare two test runs. First, you need to create the
+reference test. You'll also need to the commit id, because that's what
+the tester needs to know in order to compare the two.
+
+.. code-block:: bash
+
+  git checkout devel
+  DEVEL_COMMIT=$(git rev-parse HEAD)
+  ./koch tests
+
+Then switch over to your changes and run the tester again.
+
+.. code-block:: bash
+
+  git checkout your-changes
+  ./koch tests
+
+Then you can ask the tester to create a ``testresults.html`` which will
+tell you if any new tests passed/failed.
+
+.. code-block:: bash
+
+  ./koch --print html $DEVEL_COMMIT
diff --git a/doc/astspec.txt b/doc/astspec.txt
index 596d07bab..d3ca7755e 100644
--- a/doc/astspec.txt
+++ b/doc/astspec.txt
@@ -1,5 +1,6 @@
 The AST in Nim
-=================
+==============
+
 This section describes how the AST is modelled with Nim's type system.
 The AST consists of nodes (``NimNode``) with a variable number of
 children. Each node has a field named ``kind`` which describes what the node
@@ -24,9 +25,9 @@ contains:
       of nnkNone, nnkEmpty, nnkNilLit:
         discard                        ## node contains no additional fields
       of nnkCharLit..nnkUInt64Lit:
-        intVal: biggestInt             ## the int literal
+        intVal: BiggestInt             ## the int literal
       of nnkFloatLit..nnkFloat64Lit:
-        floatVal: biggestFloat         ## the float literal
+        floatVal: BiggestFloat         ## the float literal
       of nnkStrLit..nnkTripleStrLit:
         strVal: string                 ## the string literal
       of nnkIdent:
@@ -40,16 +41,16 @@ For the ``NimNode`` type, the ``[]`` operator has been overloaded:
 ``n[i]`` is ``n``'s ``i``-th child.
 
 To specify the AST for the different Nim constructs, the notation
-``nodekind(son1, son2, ...)`` or ``nodekind(value)`` or 
+``nodekind(son1, son2, ...)`` or ``nodekind(value)`` or
 ``nodekind(field=value)`` is used.
 
-Some child may be missing. A missing child is a node of kind ``nnkEmpty``; 
+Some child may be missing. A missing child is a node of kind ``nnkEmpty``;
 a child can never be nil.
 
 
 Leaf nodes/Atoms
 ================
-A leaf of the AST often corresponds to a terminal symbol in the concrete 
+A leaf of the AST often corresponds to a terminal symbol in the concrete
 syntax.
 
 -----------------                ---------------------------------------------
@@ -95,8 +96,8 @@ AST:
 
 .. code-block:: nim
   nnkCommand(
-    nnkIdent(!"echo"), 
-    nnkStrLit("abc"), 
+    nnkIdent(!"echo"),
+    nnkStrLit("abc"),
     nnkStrLit("xyz")
   )
 
@@ -113,8 +114,8 @@ AST:
 
 .. code-block:: nim
   nnkCall(
-    nnkIdent(!"echo"), 
-    nnkStrLit("abc"), 
+    nnkIdent(!"echo"),
+    nnkStrLit("abc"),
     nnkStrLit("xyz")
   )
 
@@ -131,12 +132,12 @@ AST:
 
 .. code-block:: nim
   nnkInfix(
-    nnkIdent(!"&"), 
-    nnkStrLit("abc"), 
+    nnkIdent(!"&"),
+    nnkStrLit("abc"),
     nnkStrLit("xyz")
   )
 
-Note that with multiple infix operators, the command is parsed by operator 
+Note that with multiple infix operators, the command is parsed by operator
 precedence.
 
 Concrete syntax:
@@ -148,18 +149,18 @@ AST:
 
 .. code-block:: nim
   nnkInfix(
-    nnkIdent(!"+"), 
+    nnkIdent(!"+"),
     nnkIntLit(5),
     nnkInfix(
-      nnkIdent(!"*"), 
-      nnkIntLit(3), 
+      nnkIdent(!"*"),
+      nnkIntLit(3),
       nnkIntLit(4)
     )
   )
 
-As a side note, if you choose to use infix operators in a prefix form, the AST 
-behaves as a 
-[parenthetical function call](./macros.html#calls-expressions-call-with) with 
+As a side note, if you choose to use infix operators in a prefix form, the AST
+behaves as a
+[parenthetical function call](./macros.html#calls-expressions-call-with) with
 ``nnkAccQuoted``, as follows:
 
 Concrete syntax:
@@ -173,8 +174,8 @@ AST:
   nnkCall(
     nnkAccQuoted(
       nnkIdent(!"+")
-    ), 
-    nnkIntLit(3), 
+    ),
+    nnkIntLit(3),
     nnkIntLit(4)
   )
 
@@ -190,7 +191,7 @@ AST:
 
 .. code-block:: nim
   nnkPrefix(
-    nnkIdent(!"?"), 
+    nnkIdent(!"?"),
     nnkStrLit("abc")
   )
 
@@ -198,7 +199,7 @@ AST:
 Postfix operator call
 ---------------------
 
-**Note:** There are no postfix operators in Nim. However, the 
+**Note:** There are no postfix operators in Nim. However, the
 ``nnkPostfix`` node is used for the *asterisk export marker* ``*``:
 
 Concrete syntax:
@@ -210,7 +211,7 @@ AST:
 
 .. code-block:: nim
   nnkPostfix(
-    nnkIdent(!"*"), 
+    nnkIdent(!"*"),
     nnkIdent(!"identifier")
   )
 
@@ -227,11 +228,11 @@ AST:
 
 .. code-block:: nim
   nnkCall(
-    nnkIdent(!"writeln"), 
+    nnkIdent(!"writeln"),
     nnkExprEqExpr(
-      nnkIdent(!"file"), 
+      nnkIdent(!"file"),
       nnkIdent(!"stdout")
-    ), 
+    ),
     nnkStrLit("hallo")
   )
 
@@ -310,7 +311,7 @@ AST:
 .. code-block:: nim
   nnkDotExpr(nnkIdent(!"x"), nnkIdent(!"y"))
 
-If you use Nim's flexible calling syntax (as in ``x.len()``), the result is the 
+If you use Nim's flexible calling syntax (as in ``x.len()``), the result is the
 same as above but wrapped in an ``nnkCall``.
 
 
@@ -331,7 +332,7 @@ AST:
 Parentheses
 -----------
 
-Parentheses for affecting operator precedence or tuple construction 
+Parentheses for affecting operator precedence or tuple construction
 are built with the ``nnkPar`` node.
 
 Concrete syntax:
@@ -343,12 +344,12 @@ AST:
 
 .. code-block:: nim
   nnkPar(nnkIntLit(1), nnkIntLit(2), nnkPar(nnkIntLit(3)))
-  
-  
+
+
 Curly braces
 ------------
 
-Curly braces are used as the set constructor. 
+Curly braces are used as the set constructor.
 
 Concrete syntax:
 
@@ -360,7 +361,7 @@ AST:
 .. code-block:: nim
   nnkCurly(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3))
 
-When used as a table constructor, the syntax (and result) is different.
+When used as a table constructor, the syntax is different.
 
 Concrete syntax:
 
@@ -379,7 +380,7 @@ AST:
 Brackets
 --------
 
-Brackets are used as the array constructor.  
+Brackets are used as the array constructor.
 
 Concrete syntax:
 
@@ -411,7 +412,7 @@ AST:
 If expression
 -------------
 
-The representation of the if expression is subtle, but easy to traverse.
+The representation of the ``if`` expression is subtle, but easy to traverse.
 
 Concrete syntax:
 
@@ -430,8 +431,8 @@ AST:
 Documentation Comments
 ----------------------
 
-Double-hash (``##``) comments in the code actually have their own format, 
-but the comments do not yet show up in the AST, which will only show that 
+Double-hash (``##``) comments in the code actually have their own format,
+but the comments do not yet show up in the AST, which will only show that
 a comment exists, not what it contains. Single-hash (``#``) comments are ignored.
 
 Concrete syntax:
@@ -447,14 +448,14 @@ AST:
 .. code-block:: nim
   nnkCommentStmt() # only appears once for the first two lines!
   stmt1
-  nnkCommentStmt() # another nnkCommentStmt because there is another comment 
+  nnkCommentStmt() # another nnkCommentStmt because there is another comment
                    # (separate from the first)
 
 Pragmas
 -------
 
 One of Nim's cool features is pragmas, which allow fine-tuning of various
-aspects of the language. They come in all types, such as adorning procs and 
+aspects of the language. They come in all types, such as adorning procs and
 objects, but the standalone ``emit`` pragma shows the basics with the AST.
 
 Concrete syntax:
@@ -472,7 +473,7 @@ AST:
     )
   )
 
-As many ``nnkIdent``s appear as there are pragmas between ``{..}``. Note that
+As many ``nnkIdent`` appear as there are pragmas between ``{..}``. Note that
 the declaration of new pragmas is essentially the same:
 
 Concrete syntax:
@@ -503,7 +504,7 @@ there is no ``else`` branch, no ``nnkElse`` child exists.
 Concrete syntax:
 
 .. code-block:: nim
-  if cond1: 
+  if cond1:
     stmt1
   elif cond2:
     stmt2
@@ -560,7 +561,7 @@ AST:
 .. code-block:: nim
   nnkStmtList(stmt1, stmt2, stmt3)
 
-  
+
 Case statement
 --------------
 
@@ -568,7 +569,7 @@ Concrete syntax:
 
 .. code-block:: nim
   case expr1
-  of expr2, expr3..expr4: 
+  of expr2, expr3..expr4:
     stmt1
   of expr5:
     stmt2
@@ -629,11 +630,11 @@ Concrete syntax:
 .. code-block:: nim
   try:
     stmt1
-  except e1, e2: 
+  except e1, e2:
     stmt2
   except e3:
     stmt3
-  except: 
+  except:
     stmt4
   finally:
     stmt5
@@ -642,9 +643,9 @@ AST:
 
 .. code-block:: nim
   nnkTryStmt(
-    stmt1, 
-    nnkExceptBranch(e1, e2, stmt2), 
-    nnkExceptBranch(e3, stmt3), 
+    stmt1,
+    nnkExceptBranch(e1, e2, stmt2),
+    nnkExceptBranch(e3, stmt3),
     nnkExceptBranch(stmt4),
     nnkFinally(stmt5)
   )
@@ -824,10 +825,23 @@ AST:
 .. code-block:: nim
   nnkExportStmt(nnkIdent(!"unsigned"))
 
+Similar to the ``import`` statement, the AST is different for
+``export ... except``.
+
+Concrete syntax:
+
+.. code-block:: nim
+  export math except pow # we're going to implement our own exponentiation
+
+AST:
+
+.. code-block:: nim
+  nnkExportExceptStmt(nnkIdent(!"math"),nnkIdent(!"pow"))
+
 Include statement
 -----------------
 
-Like a plain ``import`` statement.
+Like a plain ``import`` statement but with ``nnkIncludeStmt``.
 
 Concrete syntax:
 
@@ -862,8 +876,8 @@ Note that either the second or third (or both) parameters above must exist,
 as the compiler needs to know the type somehow (which it can infer from
 the given assignment).
 
-This is not the same AST for all uses of ``var``. See 
-[Procedure declaration](http://nim-lang.org/docs/macros.html#statements-procedure-declaration) 
+This is not the same AST for all uses of ``var``. See
+[Procedure declaration](http://nim-lang.org/docs/macros.html#statements-procedure-declaration)
 for details.
 
 Let section
@@ -872,6 +886,20 @@ Let section
 This is equivalent to ``var``, but with ``nnkLetSection`` rather than
 ``nnkVarSection``.
 
+Concrete syntax:
+
+.. code-block:: nim
+  let v = 3
+
+AST:
+
+.. code-block:: nim
+  nnkLetSection(
+    nnkIdentDefs(!"v"),
+    nnkEmpty(), # for the type
+    nnkIntLit(3)
+  )
+
 Const section
 -------------
 
@@ -894,7 +922,7 @@ AST:
 Type section
 ------------
 
-Starting with the simplest case, a ``type`` section appears much like ``var`` 
+Starting with the simplest case, a ``type`` section appears much like ``var``
 and ``const``.
 
 Concrete syntax:
@@ -949,7 +977,7 @@ AST:
       nnkGenericParams(
         nnkIdentDefs(
           nnkIdent(!"T"),
-          nnkEmpty(), # if the type is declared with options, like 
+          nnkEmpty(), # if the type is declared with options, like
                       # ``[T: SomeInteger]``, they are given here
           nnkEmpty(),
         )
@@ -983,6 +1011,73 @@ AST:
     )
   )
 
+Nim's object syntax is rich. Let's take a look at an involved example in
+its entirety to see some of the complexities.
+
+Concrete syntax:
+
+.. code-block:: nim
+  type Obj[T] = object {.inheritable.}
+    name: string
+    case isFat: bool
+    of true:
+      m: array[100_000, T]
+    of false:
+      m: array[10, T]
+
+AST:
+
+.. code-block:: nim
+  # ...
+  nnkObjectTy(
+    nnkPragma(
+      nnkIdent(!"inheritable")
+    ),
+    nnkEmpty(),
+    nnkRecList( # list of object parameters
+      nnkIdentDefs(
+        nnkIdent(!"name"),
+        nnkIdent(!"string"),
+        nnkEmpty()
+      ),
+      nnkRecCase( # case statement within object (not nnkCaseStmt)
+        nnkIdentDefs(
+          nnkIdent(!"isFat"),
+          nnkIdent(!"bool"),
+          nnkEmpty()
+        ),
+        nnkOfBranch(
+          nnkIdent(!"true"),
+          nnkRecList( # again, a list of object parameters
+            nnkIdentDefs(
+              nnkIdent(!"m"),
+              nnkBracketExpr(
+                nnkIdent(!"array"),
+                nnkIntLit(100000),
+                nnkIdent(!"T")
+              ),
+              nnkEmpty()
+          )
+        ),
+        nnkOfBranch(
+          nnkIdent(!"false"),
+          nnkRecList(
+            nnkIdentDefs(
+              nnkIdent(!"m"),
+              nnkBracketExpr(
+                nnkIdent(!"array"),
+                nnkIntLit(10),
+                nnkIdent(!"T")
+              ),
+              nnkEmpty()
+            )
+          )
+        )
+      )
+    )
+  )
+
+
 Using an ``enum`` is similar to using an ``object``.
 
 Concrete syntax:
@@ -1019,7 +1114,7 @@ AST:
     # ...
   )
 
-Static types, like ``static[int]``, use ``nnkIdent`` wrapped in 
+Static types, like ``static[int]``, use ``nnkIdent`` wrapped in
 ``nnkStaticTy``.
 
 Concrete syntax:
@@ -1041,7 +1136,7 @@ AST:
   # ...
 
 In general, declaring types mirrors this syntax (i.e., ``nnkStaticTy`` for
-``static``, etc.). Examples follow (exceptions marked by ``*``:
+``static``, etc.). Examples follow (exceptions marked by ``*``):
 
 -------------                ---------------------------------------------
 Nim type                     Corresponding AST
@@ -1059,7 +1154,7 @@ Nim type                     Corresponding AST
 ``iterator``                 ``nnkIteratorTy``
 ``object``                   ``nnkObjectTy``
 
-Take special care when declaring types as ``proc``s. The behavior is similar
+Take special care when declaring types as ``proc``. The behavior is similar
 to ``Procedure declaration``, below, but does not treat ``nnkGenericParams``.
 Generic parameters are treated in the type, not the ``proc`` itself.
 
@@ -1084,8 +1179,8 @@ AST:
     )
   )
 
-The same syntax applies to ``iterator``s (with ``nnkIteratorTy``), but
-*does not* apply to ``converter``s or ``template``s. 
+The same syntax applies to ``iterator`` (with ``nnkIteratorTy``), but
+*does not* apply to ``converter`` or ``template``.
 
 Mixin statement
 ---------------
@@ -1138,13 +1233,13 @@ AST:
     nnkFormalParams(
       nnkIdent(!"int"), # the first FormalParam is the return type. nnkEmpty() if there is none
       nnkIdentDefs(
-        nnkIdent(!"x"), 
+        nnkIdent(!"x"),
         nnkIdent(!"int"), # type type (required for procs, not for templates)
         nnkIntLit(3) # a default value
       ),
       nnkIdentDefs(
-        nnkIdent(!"y"), 
-        nnkIdent(!"float32"), 
+        nnkIdent(!"y"),
+        nnkIdent(!"float32"),
         nnkEmpty()
       )
       nnkPragma(nnkIdent(!"inline")),
@@ -1177,7 +1272,7 @@ AST:
   ),
   # ...
 
-When a procedure uses the special ``var`` type return variable, the result 
+When a procedure uses the special ``var`` type return variable, the result
 is different from that of a var section.
 
 Concrete syntax:
@@ -1198,7 +1293,7 @@ AST:
 Iterator declaration
 --------------------
 
-The syntax for iterators is similar to procs, but with ``nnkIteratorDef`` 
+The syntax for iterators is similar to procs, but with ``nnkIteratorDef``
 replacing ``nnkProcDef``.
 
 Concrete syntax:
@@ -1239,7 +1334,7 @@ Template declaration
 Templates (as well as macros, as we'll see) have a slightly expanded AST when
 compared to procs and iterators. The reason for this is [term-rewriting
 macros](http://nim-lang.org/docs/manual.html#term-rewriting-macros). Notice
-the ``nnkEmpty()`` as the second argument to ``nnkProcDef`` and 
+the ``nnkEmpty()`` as the second argument to ``nnkProcDef`` and
 ``nnkIteratorDef`` above? That's where the term-rewriting macros go.
 
 Concrete syntax:
@@ -1264,16 +1359,16 @@ inside ``nnkFormalParams`` just becomes ``nnkEmpty``.
 Macro declaration
 -----------------
 
-Macros behave like templates, but ``nnkTemplateDef`` is replaced with 
+Macros behave like templates, but ``nnkTemplateDef`` is replaced with
 ``nnkMacroDef``.
 
 
 Special node kinds
 ==================
 
-There are several node kinds that are used for semantic checking or code 
+There are several node kinds that are used for semantic checking or code
 generation. These are accessible from this module, but should not be used.
 Other node kinds are especially designed to make AST manipulations easier.
-These are explained here. 
+These are explained here.
 
 To be written.
diff --git a/doc/tut2.txt b/doc/tut2.txt
index e1ac20074..966423844 100644
--- a/doc/tut2.txt
+++ b/doc/tut2.txt
@@ -233,17 +233,15 @@ is needed:
 
   type
     Socket* = ref object of RootObj
-      FHost: int # cannot be accessed from the outside of the module
-                 # the `F` prefix is a convention to avoid clashes since
-                 # the accessors are named `host`
+      host: int # cannot be accessed from the outside of the module due to missing star
 
   proc `host=`*(s: var Socket, value: int) {.inline.} =
-    ## setter of hostAddr
-    s.FHost = value
+    ## setter of host address
+    s.host = value
 
   proc host*(s: Socket): int {.inline.} =
-    ## getter of hostAddr
-    s.FHost
+    ## getter of host address
+    s.host
 
   var s: Socket
   new s
diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim
index 6f92b0d71..973f1f2ee 100644
--- a/lib/impure/nre.nim
+++ b/lib/impure/nre.nim
@@ -586,9 +586,12 @@ proc split*(str: string, pattern: Regex, maxSplit = -1, start = 0): seq[string]
   result = @[]
   var lastIdx = start
   var splits = 0
-  var bounds = 0 .. 0
+  var bounds = 0 .. -1
+  var never_ran = true
 
   for match in str.findIter(pattern, start = start):
+    never_ran = false
+
     # bounds are inclusive:
     #
     # 0123456
@@ -615,7 +618,8 @@ proc split*(str: string, pattern: Regex, maxSplit = -1, start = 0): seq[string]
   # "12".split("\b") would be @["1", "2", ""], but
   # if we skip an empty last match, it's the correct
   # @["1", "2"]
-  if bounds.a <= bounds.b or bounds.b < str.high:
+  # If matches were never found, then the input string is the result
+  if bounds.a <= bounds.b or bounds.b < str.high or never_ran:
     # last match: Each match takes the previous substring,
     # but "1 2".split(/ /) needs to return @["1", "2"].
     # This handles "2"
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index b91c7f0d8..494dfc4c8 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -161,6 +161,8 @@ proc randomize*(seed: int) {.benign.}
 when not defined(JS):
   proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".}
     ## computes the square root of `x`.
+  proc cbrt*(x: float): float {.importc: "cbrt", header: "<math.h>".}
+    ## computes the cubic root of `x`
   
   proc ln*(x: float): float {.importc: "log", header: "<math.h>".}
     ## computes ln(x).
@@ -200,6 +202,16 @@ when not defined(JS):
   proc tanh*(x: float): float {.importc: "tanh", header: "<math.h>".}
   proc pow*(x, y: float): float {.importc: "pow", header: "<math.h>".}
     ## computes x to power raised of y.
+  
+  proc erf*(x: float): float {.importc: "erf", header: "<math.h>".}
+    ## The error function
+  proc erfc*(x: float): float {.importc: "erfc", header: "<math.h>".}
+    ## The complementary error function
+  
+  proc lgamma*(x: float): float {.importc: "lgamma", header: "<math.h>".}
+    ## Natural log of the gamma function
+  proc tgamma*(x: float): float {.importc: "tgamma", header: "<math.h>".}
+    ## The gamma function
     
   # C procs:
   when defined(vcc):
@@ -411,3 +423,9 @@ when isMainModule and not defined(JS):
   # Check for no side effect annotation
   proc mySqrt(num: float): float {.noSideEffect.} =
     return sqrt(num)
+  
+  # check gamma function
+  assert(tgamma(5.0) == 24.0) # 4!
+  assert(lgamma(1.0) == 0.0) # ln(1.0) == 0.0
+  assert(erf(6.0) > erf(5.0))
+  assert(erfc(6.0) < erfc(5.0))
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index 82cf18299..242f42c16 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -178,15 +178,18 @@ proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
     var asciiPart = new Array(len);
     var fcc = String.fromCharCode;
     var nonAsciiPart = null;
+    var nonAsciiOffset = 0;
     for (var i = 0; i < len; ++i) {
       if (nonAsciiPart !== null) {
-        nonAsciiPart[i * 2] = "%";
-        nonAsciiPart[i * 2 + 1] = `s`[i].toString(16);
+        var offset = (i - nonAsciiOffset) * 2;
+        nonAsciiPart[offset] = "%";
+        nonAsciiPart[offset + 1] = `s`[i].toString(16);
       }
       else if (`s`[i] < 128)
         asciiPart[i] = fcc(`s`[i]);
       else {
         asciiPart.length = i;
+        nonAsciiOffset = i;
         nonAsciiPart = new Array((len - i) * 2);
         --i;
       }
diff --git a/tests/stdlib/nre/split.nim b/tests/stdlib/nre/split.nim
index 8064e40b7..9d57ea7d8 100644
--- a/tests/stdlib/nre/split.nim
+++ b/tests/stdlib/nre/split.nim
@@ -8,6 +8,7 @@ suite "string splitting":
     check("1 2".split(re(" ")) == @["1", "2"])
     check("foo".split(re("foo")) == @["", ""])
     check("".split(re"foo") == @[""])
+    check("9".split(re"\son\s") == @["9"])
 
   test "captured patterns":
     check("12".split(re"(\d)") == @["", "1", "", "2", ""])
diff --git a/tests/vm/tconsttable2.nim b/tests/vm/tconsttable2.nim
new file mode 100644
index 000000000..e07734eb5
--- /dev/null
+++ b/tests/vm/tconsttable2.nim
@@ -0,0 +1,81 @@
+discard """
+  msg: '''61'''
+"""
+
+# bug #2297
+
+import tables
+
+proc html5tags*(): TableRef[string, string] =
+  var html5tagsCache: Table[string,string]
+  if true:
+    new(result)
+    html5tagsCache = initTable[string, string]()
+    html5tagsCache["a"] = "a"
+    html5tagsCache["abbr"] = "abbr"
+    html5tagsCache["b"] = "b"
+    html5tagsCache["element"] = "element"
+    html5tagsCache["embed"] = "embed"
+    html5tagsCache["fieldset"] = "fieldset"
+    html5tagsCache["figcaption"] = "figcaption"
+    html5tagsCache["figure"] = "figure"
+    html5tagsCache["footer"] = "footer"
+    html5tagsCache["header"] = "header"
+    html5tagsCache["form"] = "form"
+    html5tagsCache["head"] = "head"
+    html5tagsCache["hr"] = "hr"
+    html5tagsCache["html"] = "html"
+    html5tagsCache["iframe"] = "iframe"
+    html5tagsCache["img"] = "img"
+    html5tagsCache["input"] = "input"
+    html5tagsCache["keygen"] = "keygen"
+    html5tagsCache["label"] = "label"
+    html5tagsCache["legend"] = "legend"
+    html5tagsCache["li"] = "li"
+    html5tagsCache["link"] = "link"
+    html5tagsCache["main"] = "main"
+    html5tagsCache["map"] = "map"
+    html5tagsCache["menu"] = "menu"
+    html5tagsCache["menuitem"] = "menuitem"
+    html5tagsCache["meta"] = "meta"
+    html5tagsCache["meter"] = "master"
+    html5tagsCache["noscript"] = "noscript"
+    html5tagsCache["object"] = "object"
+    html5tagsCache["ol"] = "ol"
+    html5tagsCache["optgroup"] = "optgroup"
+    html5tagsCache["option"] = "option"
+    html5tagsCache["output"] = "output"
+    html5tagsCache["p"] = "p"
+    html5tagsCache["pre"] = "pre"
+    html5tagsCache["param"] = "param"
+    html5tagsCache["progress"] = "progress"
+    html5tagsCache["q"] = "q"
+    html5tagsCache["rp"] = "rp"
+    html5tagsCache["rt"] = "rt"
+    html5tagsCache["ruby"] = "ruby"
+    html5tagsCache["s"] = "s"
+    html5tagsCache["script"] = "script"
+    html5tagsCache["select"] = "select"
+    html5tagsCache["source"] = "source"
+    html5tagsCache["style"] = "style"
+    html5tagsCache["summary"] = "summary"
+    html5tagsCache["table"] = "table"
+    html5tagsCache["tbody"] = "tbody"
+    html5tagsCache["thead"] = "thead"
+    html5tagsCache["td"] = "td"
+    html5tagsCache["th"] = "th"
+    html5tagsCache["template"] = "template"
+    html5tagsCache["textarea"] = "textarea"
+    html5tagsCache["time"] = "time"
+    html5tagsCache["title"] = "title"
+    html5tagsCache["tr"] = "tr"
+    html5tagsCache["track"] = "track"
+    html5tagsCache["ul"] = "ul"
+    html5tagsCache["video"] = "video"
+  result[] = html5tagsCache
+
+static:
+  var i = 0
+  for key, value in html5tags().pairs():
+    inc i
+  echo i
diff --git a/tests/vm/tswap.nim b/tests/vm/tswap.nim
new file mode 100644
index 000000000..2219be9ca
--- /dev/null
+++ b/tests/vm/tswap.nim
@@ -0,0 +1,24 @@
+discard """
+msg: '''
+x.data = @[10]
+y = @[11]
+x.data = @[11]
+y = @[10]'''
+"""
+
+# bug #2946
+
+proc testSwap(): int {.compiletime.} =
+  type T = object
+    data: seq[int]
+  var x: T
+  x.data = @[10]
+  var y = @[11]
+  echo "x.data = ", x.data
+  echo "y = ", y
+  swap(y, x.data)
+  echo "x.data = ", x.data
+  echo "y = ", y
+  result = 99
+
+const something = testSwap()
diff --git a/web/community.txt b/web/community.txt
index 12d024871..1348f7bec 100644
--- a/web/community.txt
+++ b/web/community.txt
@@ -78,6 +78,13 @@ Nim's Community
   When asking a question relating to Nim, be sure to use the
   `Nim <http://stackoverflow.com/questions/tagged/nim>`_ tag in your
   question.
+  
+.. container:: standout
+
+  Google+
+  -------
+
+  The `G+ Nim community <https://plus.google.com/u/0/communities/106921341535068810587>`_ is another place where discussions related to the language happen. Read and follow various articles, posts and interesting links about Nim.
 
 .. container:: standout