summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/aliases.nim2
-rwxr-xr-xcompiler/astalgo.nim4
-rw-r--r--compiler/ccgcalls.nim92
-rwxr-xr-xcompiler/ccgexprs.nim5
-rwxr-xr-xcompiler/ccgstmts.nim26
-rwxr-xr-xcompiler/cgen.nim29
-rwxr-xr-xcompiler/pragmas.nim2
-rwxr-xr-xcompiler/semexprs.nim6
-rw-r--r--compiler/semmagic.nim4
-rwxr-xr-xdoc/manual.txt6
-rwxr-xr-xlib/system.nim14
-rwxr-xr-xtests/run/tpegs.nim74
-rwxr-xr-xtodo.txt6
-rwxr-xr-xweb/news.txt11
14 files changed, 167 insertions, 114 deletions
diff --git a/compiler/aliases.nim b/compiler/aliases.nim
index e5f58356e..aa579feee 100644
--- a/compiler/aliases.nim
+++ b/compiler/aliases.nim
@@ -41,7 +41,7 @@ proc isPartOfAux(n: PNode, b: PType, marker: var TIntSet): TAnalysisResult =
   
 proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult = 
   result = arNo
-  if a == nil: return 
+  if a == nil or b == nil: return 
   if ContainsOrIncl(marker, a.id): return 
   if compareTypes(a, b, dcEqIgnoreDistinct): return arYes
   case a.kind
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index d405bd34c..94046a723 100755
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -155,9 +155,7 @@ proc SameValue*(a, b: PNode): bool =
     if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal
   of nkStrLit..nkTripleStrLit: 
     if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal
-  else: 
-    debug a
-    debug b
+  else:
     InternalError(a.info, "SameValue")
 
 proc leValue*(a, b: PNode): bool = 
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 1c57479ae..570c931fb 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -10,16 +10,30 @@
 type
   TAfterCallActions = tuple[p: BProc, actions: PRope]
 
-proc fixupCall(p: BProc, t: PNode, d: var TLoc, pl: PRope) =
+proc leftAppearsOnRightSide(le, ri: PNode): bool =
+  if le != nil:
+    for i in 1 .. <ri.len:
+      if le.isPartOf(ri[i]) != arNo: return true
+
+proc hasNoInit(call: PNode): bool {.inline.} =
+  result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags
+
+proc resetLoc(p: BProc, d: var TLoc) =
+  zeroVar(p, d, containsGarbageCollectedRef(d.t))
+
+proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl: PRope) =
   var pl = pl
-  var typ = t.sons[0].typ # getUniqueType() is too expensive here!
+  var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
   if typ.sons[0] != nil:
     if isInvalidReturnType(typ.sons[0]):
-      if sonsLen(t) > 1: app(pl, ", ")
-      # beware of 'result = p(result)'. We always allocate a temporary:
-      if d.k in {locTemp, locNone}:
-        # We already got a temp. Great, special case it:
+      if sonsLen(ri) > 1: app(pl, ", ")
+      # beware of 'result = p(result)'. We may need to allocate a temporary:
+      if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
+        # Great, we can use 'd':
         if d.k == locNone: getTemp(p, typ.sons[0], d)
+        elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
+          # reset before pass as 'result' var:
+          resetLoc(p, d)
         app(pl, addrLoc(d))
         app(pl, ")")
         app(p.s[cpsStmts], pl)
@@ -117,40 +131,40 @@ proc genArgNoParam(aca: var TAfterCallActions, n: PNode): PRope =
     initLocExpr(aca.p, n, a)
     result = rdLoc(a)
 
-proc genCall(p: BProc, t: PNode, d: var TLoc) =
+proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
   var op: TLoc
   var aca: TAfterCallActions
   aca.p = p
   # this is a hotspot in the compiler
-  initLocExpr(p, t.sons[0], op)
+  initLocExpr(p, ri.sons[0], op)
   var pl = con(op.r, "(")
-  var typ = t.sons[0].typ # getUniqueType() is too expensive here!
+  var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
   assert(typ.kind == tyProc)
-  var length = sonsLen(t)
+  var length = sonsLen(ri)
   for i in countup(1, length - 1):
     assert(sonsLen(typ) == sonsLen(typ.n))
     if i < sonsLen(typ):
       assert(typ.n.sons[i].kind == nkSym)
-      app(pl, genArg(aca, t.sons[i], typ.n.sons[i].sym))
+      app(pl, genArg(aca, ri.sons[i], typ.n.sons[i].sym))
     else:
-      app(pl, genArgNoParam(aca, t.sons[i]))
+      app(pl, genArgNoParam(aca, ri.sons[i]))
     if i < length - 1: app(pl, ", ")
-  fixupCall(p, t, d, pl)
+  fixupCall(p, le, ri, d, pl)
   emitAfterCallActions(aca)
 
-proc genInfixCall(p: BProc, t: PNode, d: var TLoc) =
+proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
   var op, a: TLoc
   var aca: TAfterCallActions
   aca.p = p
-  initLocExpr(p, t.sons[0], op)
+  initLocExpr(p, ri.sons[0], op)
   var pl: PRope = nil
-  var typ = t.sons[0].typ # getUniqueType() is too expensive here!
+  var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
   assert(typ.kind == tyProc)
-  var length = sonsLen(t)
+  var length = sonsLen(ri)
   assert(sonsLen(typ) == sonsLen(typ.n))
   
   var param = typ.n.sons[1].sym
-  app(pl, genArg(aca, t.sons[1], param))
+  app(pl, genArg(aca, ri.sons[1], param))
   
   if skipTypes(param.typ, {tyGenericInst}).kind == tyPtr: app(pl, "->")
   else: app(pl, ".")
@@ -160,45 +174,45 @@ proc genInfixCall(p: BProc, t: PNode, d: var TLoc) =
     assert(sonsLen(typ) == sonsLen(typ.n))
     if i < sonsLen(typ):
       assert(typ.n.sons[i].kind == nkSym)
-      app(pl, genArg(aca, t.sons[i], typ.n.sons[i].sym))
+      app(pl, genArg(aca, ri.sons[i], typ.n.sons[i].sym))
     else:
-      app(pl, genArgNoParam(aca, t.sons[i]))
+      app(pl, genArgNoParam(aca, ri.sons[i]))
     if i < length - 1: app(pl, ", ")
-  fixupCall(p, t, d, pl)
+  fixupCall(p, le, ri, d, pl)
   emitAfterCallActions(aca)
 
-proc genNamedParamCall(p: BProc, t: PNode, d: var TLoc) =
+proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
   # generates a crappy ObjC call
   var op, a: TLoc
   var aca: TAfterCallActions
   aca.p = p
-  initLocExpr(p, t.sons[0], op)
+  initLocExpr(p, ri.sons[0], op)
   var pl = toRope"["
-  var typ = t.sons[0].typ # getUniqueType() is too expensive here!
+  var typ = ri.sons[0].typ # getUniqueType() is too expensive here!
   assert(typ.kind == tyProc)
-  var length = sonsLen(t)
+  var length = sonsLen(ri)
   assert(sonsLen(typ) == sonsLen(typ.n))
   
   if length > 1:
-    app(pl, genArg(aca, t.sons[1], typ.n.sons[1].sym))
+    app(pl, genArg(aca, ri.sons[1], typ.n.sons[1].sym))
     app(pl, " ")
   app(pl, op.r)
   if length > 2:
     app(pl, ": ")
-    app(pl, genArg(aca, t.sons[2], typ.n.sons[2].sym))
+    app(pl, genArg(aca, ri.sons[2], typ.n.sons[2].sym))
   for i in countup(3, length-1):
     assert(sonsLen(typ) == sonsLen(typ.n))
     if i >= sonsLen(typ):
-      InternalError(t.info, "varargs for objective C method?")
+      InternalError(ri.info, "varargs for objective C method?")
     assert(typ.n.sons[i].kind == nkSym)
     var param = typ.n.sons[i].sym
     app(pl, " ")
     app(pl, param.name.s)
     app(pl, ": ")
-    app(pl, genArg(aca, t.sons[i], param))
+    app(pl, genArg(aca, ri.sons[i], param))
   if typ.sons[0] != nil:
     if isInvalidReturnType(typ.sons[0]):
-      if sonsLen(t) > 1: app(pl, " ")
+      if sonsLen(ri) > 1: app(pl, " ")
       # beware of 'result = p(result)'. We always allocate a temporary:
       if d.k in {locTemp, locNone}:
         # We already got a temp. Great, special case it:
@@ -230,3 +244,21 @@ proc genNamedParamCall(p: BProc, t: PNode, d: var TLoc) =
     appf(p.s[cpsStmts], ";$n")
   emitAfterCallActions(aca)
 
+proc genCall(p: BProc, e: PNode, d: var TLoc) =
+  if e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags and
+      e.len >= 2:
+    genInfixCall(p, nil, e, d)
+  elif e.sons[0].kind == nkSym and sfNamedParamCall in e.sons[0].sym.flags:
+    genNamedParamCall(p, e, d)
+  else:
+    genPrefixCall(p, nil, e, d)
+
+proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
+  if ri.sons[0].kind == nkSym and sfInfixCall in ri.sons[0].sym.flags and
+      ri.len >= 2:
+    genInfixCall(p, le, ri, d)
+  elif ri.sons[0].kind == nkSym and sfNamedParamCall in ri.sons[0].sym.flags:
+    genNamedParamCall(p, ri, d)
+  else:
+    genPrefixCall(p, le, ri, d)
+
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 3a2c5965b..ddd272fba 100755
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1628,11 +1628,6 @@ proc expr(p: BProc, e: PNode, d: var TLoc) =
      nkCallStrLit:
     if e.sons[0].kind == nkSym and e.sons[0].sym.magic != mNone:
       genMagicExpr(p, e, d, e.sons[0].sym.magic)
-    elif e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags and
-        e.len >= 2:
-      genInfixCall(p, e, d)
-    elif e.sons[0].kind == nkSym and sfNamedParamCall in e.sons[0].sym.flags:
-      genNamedParamCall(p, e, d)
     else:
       genCall(p, e, d)
   of nkCurly:
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index a994f27f3..108d7f071 100755
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -18,16 +18,16 @@ proc genVarTuple(p: BProc, n: PNode) =
   if n.kind != nkVarTuple: InternalError(n.info, "genVarTuple")
   var L = sonsLen(n)
   genLineDir(p, n)
-  initLocExpr(p, n.sons[L - 1], tup)
+  initLocExpr(p, n.sons[L-1], tup)
   var t = tup.t
-  for i in countup(0, L - 3): 
+  for i in countup(0, L-3): 
     var v = n.sons[i].sym
     if sfGlobal in v.flags: 
       assignGlobalVar(p, v)
       genObjectInit(p, cpsInit, v.typ, v.loc, true)
-    else: 
+    else:
       assignLocalVar(p, v)
-      initVariable(p, v)
+      initLocalVar(p, v, immediateAsgn=true)
     initLoc(field, locExpr, t.sons[i], tup.s)
     if t.n == nil: 
       field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
@@ -37,17 +37,25 @@ proc genVarTuple(p: BProc, n: PNode) =
                       [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
     putLocIntoDest(p, v.loc, field)
 
+proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
+  if ri.kind in nkCallKinds and (ri.sons[0].kind != nkSym or
+                                 ri.sons[0].sym.magic == mNone):
+    genAsgnCall(p, le, ri, a)
+  else:
+    expr(p, ri, a)
+
 proc genSingleVar(p: BProc, a: PNode) =
   var v = a.sons[0].sym
+  var immediateAsgn = a.sons[2].kind != nkEmpty
   if sfGlobal in v.flags: 
     assignGlobalVar(p, v)
     genObjectInit(p, cpsInit, v.typ, v.loc, true)
-  else: 
+  else:
     assignLocalVar(p, v)
-    initVariable(p, v)
-  if a.sons[2].kind != nkEmpty: 
+    initLocalVar(p, v, immediateAsgn)
+  if immediateAsgn:
     genLineDir(p, a)
-    expr(p, a.sons[2], v.loc)
+    loadInto(p, a.sons[0], a.sons[2], v.loc)
 
 proc genVarStmt(p: BProc, n: PNode) = 
   for i in countup(0, sonsLen(n) - 1): 
@@ -658,7 +666,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
     InitLocExpr(p, e.sons[0], a)
     if fastAsgn: incl(a.flags, lfNoDeepCopy)
     assert(a.t != nil)
-    expr(p, e.sons[1], a)
+    loadInto(p, e.sons[0], e.sons[1], a)
   else:
     asgnFieldDiscriminant(p, e)
 
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 2018d7e6d..aa07f40aa 100755
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -14,7 +14,7 @@ import
   options, intsets,
   nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
   times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
-  rodutils, renderer, idgen, cgendata, ccgmerge, semfold
+  rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases
 
 when options.hasTinyCBackend:
   import tccgen
@@ -235,16 +235,17 @@ proc zeroVar(p: BProc, loc: TLoc, containsGCref: bool) =
       genRefAssign(p, loc, nilLoc, {afSrcIsNil})
     else:
       appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(loc)])
-  else: 
+  else:
     if containsGcref and p.WithInLoop > 0:
       appf(p.s[cpsInit], "memset((void*)$1, 0, sizeof($2));$n", 
            [addrLoc(loc), rdLoc(loc)])
+      genObjectInit(p, cpsInit, loc.t, loc, true)
       appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", 
            [addrLoc(loc), genTypeInfo(p.module, loc.t)])
     else:
       appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n", 
            [addrLoc(loc), rdLoc(loc)])
-    genObjectInit(p, cpsInit, loc.t, loc, true)
+      genObjectInit(p, cpsStmts, loc.t, loc, true)
 
 proc zeroTemp(p: BProc, loc: TLoc) = 
   if skipTypes(loc.t, abstractVarRange).Kind notin
@@ -259,15 +260,22 @@ proc zeroTemp(p: BProc, loc: TLoc) =
   else: 
     appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n", 
          [addrLoc(loc), rdLoc(loc)])
+    # XXX no object init necessary for temporaries?
     when false:
       appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", 
            [addrLoc(loc), genTypeInfo(p.module, loc.t)])
 
-proc initVariable(p: BProc, v: PSym) =
+proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
   if sfNoInit notin v.flags:
-    var b = containsGarbageCollectedRef(v.typ)
-    if b or v.ast == nil:
-      zeroVar(p, v.loc, b)
+    # we know it is a local variable and thus on the stack!
+    # If ``not immediateAsgn`` it is not initialized in a binding like
+    # ``var v = X`` and thus we need to init it. 
+    # If ``v`` contains a GC-ref we may pass it to ``unsureAsgnRef`` somehow
+    # which requires initialization. However this can really only happen if
+    # ``var v = X()`` gets transformed into ``X(&v)``. 
+    # Nowadays the logic in ccgcalls deals with this case however.
+    if not immediateAsgn:
+      zeroVar(p, v.loc, containsGarbageCollectedRef(v.typ))
     
 proc initTemp(p: BProc, tmp: var TLoc) = 
   if containsGarbageCollectedRef(tmp.t) or isInvalidReturnType(tmp.t):
@@ -534,13 +542,14 @@ proc genProcAux(m: BModule, prc: PSym) =
   assert(prc.ast != nil)
   if sfPure notin prc.flags and prc.typ.sons[0] != nil:
     var res = prc.ast.sons[resultPos].sym # get result symbol
-    if not isInvalidReturnType(prc.typ.sons[0]): 
+    if not isInvalidReturnType(prc.typ.sons[0]):
+      if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
       # declare the result symbol:
       assignLocalVar(p, res)
       assert(res.loc.r != nil)
       returnStmt = ropeff("return $1;$n", "ret $1$n", [rdLoc(res.loc)])
-      initVariable(p, res)
-    else: 
+      initLocalVar(p, res, immediateAsgn=false)
+    else:
       fillResult(res)
       assignParam(p, res)
       if skipTypes(res.typ, abstractInst).kind == tyArray: 
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index d4ea3226d..a291d4741 100755
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -23,7 +23,7 @@ const
     wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, 
     wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge, 
     wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
-    wNoStackFrame, wError, wDiscardable}
+    wNoStackFrame, wError, wDiscardable, wNoInit}
   converterPragmas* = procPragmas
   methodPragmas* = procPragmas
   macroPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, 
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index a08e9c875..a5093f567 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -983,12 +983,6 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
     else:
       result = semDirectOp(c, n, flags)
   of mExpandToAst: result = semExpandToAst(c, n, s, flags)
-  of mAstToStr:
-    if sonsLen(n) == 2:
-      result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
-      result.typ = getSysType(tyString)
-    else:
-      result = semDirectOp(c, n, flags)
   else: result = semDirectOp(c, n, flags)
 
 proc semIfExpr(c: PContext, n: PNode): PNode = 
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index da1101729..696988fd3 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -31,6 +31,8 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
   case n[0].sym.magic
   of mSlurp: result = semSlurp(c, n, flags)
   of mIsPartOf: result = semIsPartOf(c, n, flags)
+  of mAstToStr:
+    result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
+    result.typ = getSysType(tyString)
   else: result = n
-  
 
diff --git a/doc/manual.txt b/doc/manual.txt
index 164410a68..97af7fe2a 100755
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -1584,6 +1584,11 @@ The implicit initialization can be avoided for optimization reasons with the
   var

     a {.noInit.}: array [0..1023, char] 

 

+If a proc is annotated with the ``noinit`` pragma this refers to its implicit

+``result`` variable:

+

+.. code-block:: nimrod

+  proc returnUndefinedValue: int {.noinit.} = nil

 

 

 let statement

@@ -2849,6 +2854,7 @@ exported.
 The algorithm for compiling modules is:

 

 - compile the whole module as usual, following import statements recursively

+

 - if there is a cycle only import the already parsed symbols (that are

   exported); if an unknown identifier occurs then abort

 

diff --git a/lib/system.nim b/lib/system.nim
index c7e26230a..8a99781cc 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -2071,14 +2071,24 @@ proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.}
   ## converts the AST of `x` into a string representation. This is very useful
   ## for debugging.
   
+proc raiseAssert(msg: string) {.noinline.} =
+  raise newException(EAssertionFailed, msg)
+  
 template assert*(cond: expr, msg = "") =
   ## provides a means to implement `programming by contracts`:idx: in Nimrod.
   ## ``assert`` evaluates expression ``cond`` and if ``cond`` is false, it
   ## raises an ``EAssertionFailure`` exception. However, the compiler may
   ## not generate any code at all for ``assert`` if it is advised to do so.
   ## Use ``assert`` for debugging purposes only.
+  bind raiseAssert
   when compileOption("assertions"):
     if not cond:
-      raise newException(EAssertionFailed, astToStr(cond) & ' ' & msg)
-
+      raiseAssert(astToStr(cond) & ' ' & msg)
+
+template doAssert*(cond: expr, msg = "") =
+  ## same as `assert' but is always turned on and not affected by the
+  ## ``--assertions`` command line switch.
+  bind raiseAssert
+  if not cond:
+    raiseAssert(astToStr(cond) & ' ' & msg)
 
diff --git a/tests/run/tpegs.nim b/tests/run/tpegs.nim
index 64c547b24..8fe302073 100755
--- a/tests/run/tpegs.nim
+++ b/tests/run/tpegs.nim
@@ -1669,25 +1669,25 @@ proc escapePeg*(s: string): string =
   if inQuote: result.add('\'')
 
 when isMainModule:
-  assert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27"
-  #assert match("(a b c)", peg"'(' @ ')'")
-  assert match("W_HI_Le", peg"\y 'while'")
-  assert(not match("W_HI_L", peg"\y 'while'"))
-  assert(not match("W_HI_Le", peg"\y v'while'"))
-  assert match("W_HI_Le", peg"y'while'")
+  doAssert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27"
+  #doAssert match("(a b c)", peg"'(' @ ')'")
+  doAssert match("W_HI_Le", peg"\y 'while'")
+  doAssert(not match("W_HI_L", peg"\y 'while'"))
+  doAssert(not match("W_HI_Le", peg"\y v'while'"))
+  doAssert match("W_HI_Le", peg"y'while'")
   
-  assert($ +digits == $peg"\d+")
-  assert "0158787".match(peg"\d+")
-  assert "ABC 0232".match(peg"\w+\s+\d+")
-  assert "ABC".match(peg"\d+ / \w+")
+  doAssert($ +digits == $peg"\d+")
+  doAssert "0158787".match(peg"\d+")
+  doAssert "ABC 0232".match(peg"\w+\s+\d+")
+  doAssert "ABC".match(peg"\d+ / \w+")
 
   for word in split("00232this02939is39an22example111", peg"\d+"):
     writeln(stdout, word)
 
-  assert matchLen("key", ident) == 3
+  doAssert matchLen("key", ident) == 3
 
   var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident)
-  assert matchLen("key1=  cal9", pattern) == 11
+  doAssert matchLen("key1=  cal9", pattern) == 11
   
   var ws = newNonTerminal("ws", 1, 1)
   ws.rule = *whitespace
@@ -1698,24 +1698,24 @@ when isMainModule:
   
   var c: TCaptures
   var s = "a+b +  c +d+e+f"
-  assert rawMatch(s, expr.rule, 0, c) == len(s)
+  doAssert rawMatch(s, expr.rule, 0, c) == len(s)
   var a = ""
   for i in 0..c.ml-1:
     a.add(substr(s, c.matches[i][0], c.matches[i][1]))
-  assert a == "abcdef"
+  doAssert a == "abcdef"
   #echo expr.rule
 
   #const filename = "lib/devel/peg/grammar.txt"
   #var grammar = parsePeg(newFileStream(filename, fmRead), filename)
   #echo "a <- [abc]*?".match(grammar)
-  assert find("_____abc_______", term("abc"), 2) == 5
-  assert match("_______ana", peg"A <- 'ana' / . A")
-  assert match("abcs%%%", peg"A <- ..A / .A / '%'")
+  doAssert find("_____abc_______", term("abc"), 2) == 5
+  doAssert match("_______ana", peg"A <- 'ana' / . A")
+  doAssert match("abcs%%%", peg"A <- ..A / .A / '%'")
 
   if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}":
-    assert matches[0] == "abc"
+    doAssert matches[0] == "abc"
   else:
-    assert false
+    doAssert false
   
   var g2 = peg"""S <- A B / C D
                  A <- 'a'+
@@ -1723,44 +1723,44 @@ when isMainModule:
                  C <- 'c'+
                  D <- 'd'+
               """
-  assert($g2 == "((A B) / (C D))")
-  assert match("cccccdddddd", g2)
-  assert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
+  doAssert($g2 == "((A B) / (C D))")
+  doAssert match("cccccdddddd", g2)
+  doAssert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
          "var1<-keykey; var2<-key2key2")
-  assert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}")
+  doAssert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}")
 
   if "aaaaaa" =~ peg"'aa' !. / ({'a'})+":
-    assert matches[0] == "a"
+    doAssert matches[0] == "a"
   else:
-    assert false
+    doAssert false
     
   var matches: array[0..5, string]
   if match("abcdefg", peg"c {d} ef {g}", matches, 2): 
-    assert matches[0] == "d"
-    assert matches[1] == "g"
+    doAssert matches[0] == "d"
+    doAssert matches[1] == "g"
   else:
-    assert false
+    doAssert false
 
   for x in findAll("abcdef", peg"{.}", 3):
     echo x
     
   if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')":
-    assert matches[0] == "f"
-    assert matches[1] == "a, b"
+    doAssert matches[0] == "f"
+    doAssert matches[1] == "a, b"
   else:
-    assert false
+    doAssert false
   
-  assert match("eine übersicht und außerdem", peg"(\letter \white*)+")
+  doAssert match("eine übersicht und außerdem", peg"(\letter \white*)+")
   # ß is not a lower cased letter?!
-  assert match("eine übersicht und auerdem", peg"(\lower \white*)+")
-  assert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+")
-  assert(not match("456678", peg"(\letter)+"))
+  doAssert match("eine übersicht und auerdem", peg"(\lower \white*)+")
+  doAssert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+")
+  doAssert(not match("456678", peg"(\letter)+"))
 
-  assert("var1 = key; var2 = key2".replacef(
+  doAssert("var1 = key; var2 = key2".replacef(
     peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") ==
          "var1<-keykey;var2<-key2key2")
 
-  assert match("prefix/start", peg"^start$", 7)
+  doAssert match("prefix/start", peg"^start$", 7)
   
   # tricky test to check for false aliasing:
   block:
diff --git a/todo.txt b/todo.txt
index ba7fed751..33dc52bf9 100755
--- a/todo.txt
+++ b/todo.txt
@@ -1,7 +1,8 @@
 version 0.8.14
 ==============
 
-- find a proper bugfix for C compilers optimizing away stack roots
+- implement a proper bugfix for C compilers optimizing away stack roots
+
 - cleanup file path handling in the compiler
 - warning for implicit openArray -> varargs convention
 - implement explicit varargs; **but** ``len(varargs)`` problem remains! 
@@ -37,9 +38,6 @@ version 0.9.0
 Bugs
 ----
 - bug: generic assign still buggy
-  - Optimization: If we use a temporary for the result anyway the code gen
-    should make use of this fact to generate better code...
-  - bug: memset() without type field initialization?
   - special case the generic assign that needs to care about case objects
 
 - bug: returning a tyVar does not mean it is save to return it:
diff --git a/web/news.txt b/web/news.txt
index b4c76cdc3..22e0377c5 100755
--- a/web/news.txt
+++ b/web/news.txt
@@ -29,7 +29,7 @@ Changes affecting backwards compatibility
   ``os.iterOverEnvironment``, ``os.pcDirectory``, ``os.pcLinkToDirectory``,
   ``os.SplitPath``, ``os.extractDir``, ``os.SplitFilename``, 
   ``os.extractFileTrunk``, ``os.extractFileExt``, ``osproc.executeProcess``,
-  ``osproc.executeCommand``. 
+  ``osproc.executeCommand``.
 - Removed deprecated ``parseopt.init``, ``parseopt.getRestOfCommandLine``.
 - Moved ``strutils.validEmailAddress`` to ``matchers.validEmailAddress``.
 - The pointer dereference operator ``^`` has been removed, so that ``^``
@@ -53,8 +53,8 @@ Changes affecting backwards compatibility
   because they should not be used directly anymore. 
   Wrapper procs have been created that should be used instead.
 - ``export`` is now a keyword.
-- ``assert`` is now implemented in pure Nimrod; it's easy to implement your
-  own assertion schemes now.
+- ``assert`` is now implemented in pure Nimrod as a template; it's easy 
+  to implement your own assertion templates with ``system.astToStr``.
 
 
 Language Additions
@@ -112,6 +112,7 @@ Compiler Additions
 - Added ``--import:file`` and ``--include:file`` configuration options
   for specifying modules that will be automatically imported/incluced.
 - ``nimrod i`` can now optionally be given a module to execute.
+- The compiler now performs a simple aliases analysis to generate better code.
 
 
 Library Additions
@@ -128,7 +129,7 @@ Library Additions
 - Added ``system.program_result``.
 - Added ``xmltree.innerText``.
 - Added ``os.isAbsolute``, ``os.dynLibFormat``, ``os.isRootDir``,
-   ``os.parentDirs``.
+  ``os.parentDirs``.
 - Added ``parseutils.interpolatedFragments``.
 - Added ``macros.treeRepr``, ``macros.lispRepr``, ``macros.dumpTree``, 
   ``macros.dumpLisp``, ``macros.parseExpr``, ``macros.parseStmt``, 
@@ -142,7 +143,7 @@ Library Additions
   and ``exec`` on Posix systems. Define the symbol ``useFork`` to revert to
   the old implementation.
 - Added ``intsets.assign``.
-- Added ``system.astToStr`` and ``system.rand``.
+- Added ``system.astToStr`` and ``system.rand``, ``system.doAssert``.
 
 
 2011-07-10 Version 0.8.12 released