summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/ccgexprs.nim35
-rwxr-xr-xcompiler/ccgstmts.nim38
-rwxr-xr-xcompiler/cgen.nim26
-rw-r--r--compiler/cgendata.nim7
-rwxr-xr-xdoc/manual.txt54
-rwxr-xr-xdoc/tut2.txt43
-rw-r--r--examples/debugging.nim17
-rwxr-xr-xlib/nimbase.h6
-rwxr-xr-xlib/system/debugger.nim11
-rwxr-xr-xtodo.txt51
-rwxr-xr-xweb/news.txt7
11 files changed, 152 insertions, 143 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index fd70834c2..a99654cbd 100755
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -709,12 +709,12 @@ proc genFieldCheck(p: BProc, e: PNode, obj: PRope, field: PSym) =
               rdLoc(test), strLit)
 
 proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
-  var
-    a: TLoc
-    f, field: PSym
-    ty: PType
-    r: PRope
   if optFieldCheck in p.options:
+    var
+      a: TLoc
+      f, field: PSym
+      ty: PType
+      r: PRope
     ty = genRecordFieldAux(p, e.sons[0], d, a)
     r = rdLoc(a)
     f = e.sons[0].sons[1].sym
@@ -729,31 +729,6 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
     if field.loc.r == nil:
       InternalError(e.info, "genCheckedRecordField") # generate the checks:
     genFieldCheck(p, e, r, field)
-    when false:
-      for i in countup(1, sonsLen(e) - 1):
-        it = e.sons[i]
-        assert(it.kind in nkCallKinds)
-        assert(it.sons[0].kind == nkSym)
-        op = it.sons[0].sym
-        if op.magic == mNot: it = it.sons[1]
-        assert(it.sons[2].kind == nkSym)
-        initLoc(test, locNone, it.typ, OnStack)
-        InitLocExpr(p, it.sons[1], u)
-        initLoc(v, locExpr, it.sons[2].typ, OnUnknown)
-        v.r = ropef("$1.$2", [r, it.sons[2].sym.loc.r])
-        genInExprAux(p, it, u, v, test)
-        id = NodeTableTestOrSet(p.module.dataCache,
-                                newStrNode(nkStrLit, field.name.s), gBackendId)
-        if id == gBackendId: strLit = getStrLit(p.module, field.name.s)
-        else: strLit = con("TMP", toRope(id))
-        if op.magic == mNot:
-          linefmt(p, cpsStmts,
-                  "if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
-                  rdLoc(test), strLit)
-        else:
-          linefmt(p, cpsStmts,
-                  "if (!($1)) #raiseFieldError(((#NimStringDesc*) &$2));$n",
-                  rdLoc(test), strLit)
     app(r, rfmt(nil, ".$1", field.loc.r))
     putIntoDest(p, d, field.typ, r)
   else:
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index dd6d2bfaa..e11678861 100755
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -45,7 +45,7 @@ proc genVarTuple(p: BProc, n: PNode) =
     if t.kind == tyTuple: 
       field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)])
     else: 
-      if (t.n.sons[i].kind != nkSym): InternalError(n.info, "genVarTuple")
+      if t.n.sons[i].kind != nkSym: InternalError(n.info, "genVarTuple")
       field.r = ropef("$1.$2", 
                       [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
     putLocIntoDest(p, v.loc, field)
@@ -64,19 +64,23 @@ proc startBlock(p: BProc, start: TFormatStr = "{$n",
   result = len(p.blocks)
   setlen(p.blocks, result + 1)
   p.blocks[result].id = p.labels
-  p.blocks[result].nestedTryStmts = p.nestedTryStmts.len
+  p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16
 
 proc assignLabel(b: var TBlock): PRope {.inline.} =
   b.label = con("LA", b.id.toRope)
   result = b.label
 
-proc blockBody(b: var TBlock): PRope {.inline.} =
-  return b.sections[cpsLocals].con(b.sections[cpsInit]).con(b.sections[cpsStmts])
+proc blockBody(b: var TBlock): PRope =
+  result = b.sections[cpsLocals]
+  if b.frameLen > 0:
+    result.appf("F.len+=$1;$n", b.frameLen.toRope)
+  result.app(b.sections[cpsInit])
+  result.app(b.sections[cpsStmts])
 
 proc endBlock(p: BProc, blockEnd: PRope) =
-  let topBlock = p.blocks.len - 1
+  let topBlock = p.blocks.len-1
   # the block is merged into the parent block
-  app(p.blocks[topBlock - 1].sections[cpsStmts], p.blocks[topBlock].blockBody)
+  app(p.blocks[topBlock-1].sections[cpsStmts], p.blocks[topBlock].blockBody)
   setlen(p.blocks, topBlock)
   # this is done after the block is popped so $n is
   # properly indented when pretty printing is enabled
@@ -84,10 +88,13 @@ proc endBlock(p: BProc, blockEnd: PRope) =
 
 proc endBlock(p: BProc) =
   let topBlock = p.blocks.len - 1  
-  let blockEnd = if p.blocks[topBlock].label != nil:
+  var blockEnd = if p.blocks[topBlock].label != nil:
       rfmt(nil, "} $1: ;$n", p.blocks[topBlock].label)
     else:
       ~"}$n"
+  let frameLen = p.blocks[topBlock].frameLen
+  if frameLen > 0:
+    blockEnd.appf("F.len-=$1;$n", frameLen.toRope)
   endBlock(p, blockEnd)
 
 proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} =
@@ -774,7 +781,7 @@ var
 
 proc genBreakPoint(p: BProc, t: PNode) = 
   var name: string
-  if optEndb in p.Options: 
+  if optEndb in p.Options:
     if t.kind == nkExprColonExpr: 
       assert(t.sons[1].kind in {nkStrLit..nkTripleStrLit})
       name = normalize(t.sons[1].strVal)
@@ -784,7 +791,7 @@ proc genBreakPoint(p: BProc, t: PNode) =
     genLineDir(p, t)          # BUGFIX
     appcg(p.module, gBreakpoints, 
          "#dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n", [
-        toRope(toLinenumber(t.info)), makeCString(toFilename(t.info)), 
+        toRope(toLinenumber(t.info)), makeCString(toFilename(t.info)),
         makeCString(name)])
 
 proc genWatchpoint(p: BProc, n: PNode) =
@@ -796,16 +803,13 @@ proc genWatchpoint(p: BProc, n: PNode) =
         [a.addrLoc, makeCString(renderTree(n.sons[1])),
         genTypeInfo(p.module, typ)])
 
-proc genPragma(p: BProc, n: PNode) = 
-  for i in countup(0, sonsLen(n) - 1): 
+proc genPragma(p: BProc, n: PNode) =
+  for i in countup(0, sonsLen(n) - 1):
     var it = n.sons[i]
     case whichPragma(it)
-    of wEmit:
-      genEmit(p, it)
-    of wBreakpoint: 
-      genBreakPoint(p, it)
-    of wWatchpoint:
-      genWatchpoint(p, it)
+    of wEmit: genEmit(p, it)
+    of wBreakpoint: genBreakPoint(p, it)
+    of wWatchpoint: genWatchpoint(p, it)
     else: nil
 
 proc FieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool = 
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 399785c82..d06a6cb6f 100755
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nimrod Compiler
-#        (c) Copyright 2012 Andreas Rumpf
+#        (c) Copyright 2013 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -269,18 +269,18 @@ proc genCLineDir(r: var PRope, filename: string, line: int) =
 proc genCLineDir(r: var PRope, info: TLineInfo) = 
   genCLineDir(r, info.toFullPath, info.safeLineNm)
 
-proc genLineDir(p: BProc, t: PNode) = 
+proc genLineDir(p: BProc, t: PNode) =
   var line = t.info.safeLineNm
   if optEmbedOrigSrc in gGlobalOptions:
     app(p.s(cpsStmts), con(~"//", t.info.sourceLine, rnl))
   genCLineDir(p.s(cpsStmts), t.info.toFullPath, line)
   if ({optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb}) and
-      (p.prc == nil or sfPure notin p.prc.flags): 
-    linefmt(p, cpsStmts, "#endb($1);$n", toRope(line))
+      (p.prc == nil or sfPure notin p.prc.flags):
+    linefmt(p, cpsStmts, "#endb($1, $2);$n",
+            line.toRope, makeCString(toFilename(t.info)))
   elif ({optLineTrace, optStackTrace} * p.Options ==
       {optLineTrace, optStackTrace}) and
       (p.prc == nil or sfPure notin p.prc.flags):
-   
     linefmt(p, cpsStmts, "nimln($1, $2);$n",
             line.toRope, t.info.quotedFilename)
 
@@ -470,12 +470,13 @@ proc localDebugInfo(p: BProc, s: PSym) =
   # XXX work around a bug: No type information for open arrays possible:
   if skipTypes(s.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: return
   var a = con("&", s.loc.r)
-  if (s.kind == skParam) and ccgIntroducedPtr(s): a = s.loc.r
+  if s.kind == skParam and ccgIntroducedPtr(s): a = s.loc.r
   lineF(p, cpsInit,
        "F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n",
-       [toRope(p.frameLen), makeCString(normalize(s.name.s)), a, 
+       [p.maxFrameLen.toRope, makeCString(normalize(s.name.s)), a,
         genTypeInfo(p.module, s.loc.t)])
-  inc(p.frameLen)
+  inc(p.maxFrameLen)
+  inc p.blocks[p.blocks.len-1].frameLen
 
 proc assignLocalVar(p: BProc, s: PSym) = 
   #assert(s.loc.k == locNone) // not yet assigned
@@ -488,7 +489,7 @@ proc assignLocalVar(p: BProc, s: PSym) =
   if sfRegister in s.flags: app(decl, " register")
   #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
   #  app(decl, " GC_GUARD")
-  if (sfVolatile in s.flags) or (p.nestedTryStmts.len > 0): 
+  if sfVolatile in s.flags or p.nestedTryStmts.len > 0: 
     app(decl, " volatile")
   appf(decl, " $1;$n", [s.loc.r])
   line(p, cpsLocals, decl)
@@ -693,10 +694,11 @@ proc retIsNotVoid(s: PSym): bool =
 
 proc initFrame(p: BProc, procname, filename: PRope): PRope =
   discard cgsym(p.module, "pushFrame")
-  if p.frameLen > 0:
+  if p.maxFrameLen > 0:
     discard cgsym(p.module, "TVarSlot")
-    result = rfmt(nil, "\tnimfrs($1, $2, $3)$N",
-                  procname, filename, p.frameLen.toRope)
+    result = rfmt(nil, "\tnimfrs($1, $2, $3, $4)$N",
+                  procname, filename, p.maxFrameLen.toRope,
+                  p.blocks[0].frameLen.toRope)
   else:
     result = rfmt(nil, "\tnimfr($1, $2)$N", procname, filename)
 
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index 32e9fb4ce..ad17194df 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -54,9 +54,10 @@ type
     id*: int                  # the ID of the label; positive means that it
     label*: PRope             # generated text for the label
                               # nil if label is not used
-    nestedTryStmts*: int      # how many try statements is it nested into
     sections*: TCProcSections # the code beloging
     isLoop*: bool             # whether block is a loop
+    nestedTryStmts*: int16    # how many try statements is it nested into
+    frameLen*: int16
   
   TCProc{.final.} = object    # represents C proc that is currently generated
     prc*: PSym                # the Nimrod proc that this C proc belongs to
@@ -74,9 +75,7 @@ type
     options*: TOptions        # options that should be used for code
                               # generation; this is the same as prc.options
                               # unless prc == nil
-    frameLen*: int            # current length of frame descriptor
-    sendClosure*: PType       # closure record type that we pass
-    receiveClosure*: PType    # closure record type that we get
+    maxFrameLen*: int         # max length of frame descriptor
     module*: BModule          # used to prevent excessive parameter passing
     withinLoop*: int          # > 0 if we are within a loop
     gcFrameId*: natural       # for the GC stack marking
diff --git a/doc/manual.txt b/doc/manual.txt
index b70dbdebc..3c2d7534b 100755
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -984,7 +984,7 @@ in future versions of the compiler.
 .. code-block:: nimrod
 
   type
-    TPerson = tuple[name: string, age: int] # type representing a person
+    TPerson = tuple[name: string, age: int] # type representing a person:
                                             # a person consists of a name
                                             # and an age
   var
@@ -1000,7 +1000,6 @@ For consistency  with ``object`` declarations, tuples in a ``type`` section
 can also be defined with indentation instead of ``[]``:
 
 .. code-block:: nimrod
-
   type
     TPerson = tuple   # type representing a person
       name: string    # a person consists of a name
@@ -1011,7 +1010,6 @@ and information hiding. Objects have access to their type at runtime, so that
 the ``of`` operator can be used to determine the object's type.
 
 .. code-block:: nimrod
-
   type
     TPerson {.inheritable.} = object
       name*: string   # the * means that `name` is accessible from other modules
@@ -1032,6 +1030,19 @@ and thus have no hidden type field. One can use the ``inheritable`` pragma to
 introduce new object roots apart from ``system.TObject``.
 
 
+Object construction
+-------------------
+
+Objects can also be created with an `object construction expression`:idx: that
+has the syntax ``T(fieldA: valueA, fieldB: valueB, ...)`` where ``T`` is 
+an ``object`` type or a ``ref object`` type:
+
+.. code-block:: nimrod
+  var student = TStudent(name: "Anton", age: 5, id: 3)
+
+For a ``ref object`` type ``new`` is invoked implicitly.
+
+
 Object variants
 ---------------
 Often an object hierarchy is overkill in certain situations where simple
@@ -1061,15 +1072,22 @@ An example:
       of nkIf:
         condition, thenPart, elsePart: PNode
 
-  var
-    n: PNode
-  new(n)  # creates a new node
-  n.kind = nkFloat
-  n.floatVal = 0.0 # valid, because ``n.kind==nkFloat``, so that it fits
+  # create a new case object:
+  var n = PNode(kind: nkIf, condition: nil)
+  # accessing n.thenPart is valid because the ``nkIf`` branch is active:
+  n.thenPart = PNode(kind: nkFloat, floatVal: 2.0)
 
   # the following statement raises an `EInvalidField` exception, because
-  # n.kind's value does not fit:
+  # n.kind's value does not fit and the ``nkString`` branch is not active:
   n.strVal = ""
+  
+  # invalid: would change the active object branch:
+  n.kind = nkInt
+  
+  var x = PNode(kind: nkAdd, leftOp: PNode(kind: nkInt, intVal: 4),
+                             rightOp: PNode(kind: nkInt, intVal: 2))
+  # valid: does not change the active object branch:
+  x.kind = nkSub
 
 As can been seen from the example, an advantage to an object hierarchy is that
 no casting between different object types is needed. Yet, access to invalid
@@ -1078,6 +1096,11 @@ object fields raises an exception.
 The syntax of ``case`` in an object declaration follows closely the syntax of
 the ``case`` statement: The branches in a ``case`` section may be indented too.
 
+In the example the ``kind`` field is called the `discriminator`:idx:\: For
+safety its address cannot be taken and assignments to it are restricted: The
+new value must not lead to a change of the active object branch. For an object
+branch switch ``system.reset`` has to be used.
+
 
 Set type
 --------
@@ -2387,6 +2410,7 @@ the proc's name.
 Procs as expressions can appear both as nested procs and inside top level 
 executable code.
 
+
 Do notation
 -----------
 
@@ -2410,7 +2434,7 @@ Again, let's see the equivalent of the previous example:
   sort(cities) do (x,y: string) -> int:
     cmp(x.len, y.len)
 
-Finally, more than one ``do`` blocks can appear in a single call:
+Finally, more than one ``do`` block can appear in a single call:
 
 .. code-block:: nimrod
   proc performWithUndo(task: proc(), undo: proc()) = ...
@@ -2426,6 +2450,7 @@ omitted if the supplied proc doesn't have any parameters and return value.
 The compatibility works in the other direction too as the ``do`` syntax can be
 used with macros and templates expecting ``stmt`` blocks.
 
+
 Nonoverloadable builtins
 ------------------------
 
@@ -2987,8 +3012,7 @@ possibly raised exceptions; the algorithm operates on ``p``'s call graph:
    raise ``system.E_Base`` unless ``q`` has an explicit ``raises`` list.
 3. Every call to a method ``m`` is assumed to 
    raise ``system.E_Base`` unless ``m`` has an explicit ``raises`` list.
-4. For every other call the analysis can determine an 
-   exact ``raises`` list.
+4. For every other call the analysis can determine an exact ``raises`` list.
 5. For determining a ``raises`` list, the ``raise`` and ``try`` statements 
    of ``p`` are taken into consideration.
 
@@ -3259,7 +3283,7 @@ Symbol lookup in generics
 
 The symbol binding rules in generics are slightly subtle: There are "open" and
 "closed" symbols. A "closed" symbol cannot be re-bound in the instantiation
-context, an "open" symbol can be. Per default overloaded symbols are open
+context, an "open" symbol can. Per default overloaded symbols are open
 and every other symbol is closed.
 
 Open symbols are looked up in two different contexts: Both the context
@@ -4106,8 +4130,8 @@ implemented with term rewriting:
   proc p(x, y: int; cond: bool): int =
     result = if cond: x + y else: x - y
 
-  template optP{p(x, y, true)}(x, y: expr): expr = x + y
-  template optP{p(x, y, false)}(x, y: expr): expr = x - y
+  template optP1{p(x, y, true)}(x, y: expr): expr = x + y
+  template optP2{p(x, y, false)}(x, y: expr): expr = x - y
 
 
 Example: hoisting
diff --git a/doc/tut2.txt b/doc/tut2.txt
index c080d1339..e1e36bfc4 100755
--- a/doc/tut2.txt
+++ b/doc/tut2.txt
@@ -46,8 +46,7 @@ Objects
 Like tuples, objects are a means to pack different values together in a
 structured way. However, objects provide many features that tuples do not:
 They provide inheritance and information hiding. Because objects encapsulate
-data, the ``()`` tuple constructor cannot be used to construct objects. So
-the order of the object's fields is not as important as it is for tuples. The
+data, the ``T()`` object constructor should only be used internally and the
 programmer should provide a proc to initialize the object (this is called
 a *constructor*).
 
@@ -55,7 +54,6 @@ Objects have access to their type at runtime. There is an
 ``of`` operator that can be used to check the object's type:
 
 .. code-block:: nimrod
-
   type
     TPerson = object of TObject
       name*: string  # the * means that `name` is accessible from other modules
@@ -68,6 +66,8 @@ Objects have access to their type at runtime. There is an
     student: TStudent
     person: TPerson
   assert(student of TStudent) # is true
+  # object construction:
+  student = TStudent(name: "Anton", age: 5, id: 2)
 
 Object fields that should be visible from outside the defining module have to
 be marked by ``*``. In contrast to tuples, different object types are
@@ -161,12 +161,7 @@ An example:
       of nkIf:
         condition, thenPart, elsePart: PNode
 
-  var
-    n: PNode
-  new(n)  # creates a new node
-  n.kind = nkFloat
-  n.floatVal = 0.0 # valid, because ``n.kind==nkFloat``
-
+  var n = PNode(kind: nkFloat, floatVal: 1.0)
   # the following statement raises an `EInvalidField` exception, because
   # n.kind's value does not fit:
   n.strVal = ""
@@ -288,30 +283,22 @@ Procedures always use static dispatch. For dynamic dispatch replace the
 
 .. code-block:: nimrod
   type
-    TExpr = object of TObject ## abstract base class for an expression
-    TLiteral = object of TExpr
+    PExpr = ref object of TObject ## abstract base class for an expression
+    PLiteral = ref object of PExpr
       x: int
-    TPlusExpr = object of TExpr
-      a, b: ref TExpr
-      
-  method eval(e: ref TExpr): int =
+    PPlusExpr = ref object of PExpr
+      a, b: PExpr
+
+  # watch out: 'eval' relies on dynamic binding
+  method eval(e: PExpr): int =
     # override this base method
     quit "to override!"
   
-  method eval(e: ref TLiteral): int = return e.x
-
-  method eval(e: ref TPlusExpr): int =
-    # watch out: relies on dynamic binding
-    return eval(e.a) + eval(e.b)
+  method eval(e: PLiteral): int = e.x
+  method eval(e: PPlusExpr): int = eval(e.a) + eval(e.b)
   
-  proc newLit(x: int): ref TLiteral =
-    new(result)
-    result.x = x
-    
-  proc newPlus(a, b: ref TExpr): ref TPlusExpr =
-    new(result)
-    result.a = a
-    result.b = b
+  proc newLit(x: int): PLiteral = PLiteral(x: x)
+  proc newPlus(a, b: PExpr): PPlusExpr = PPlusExpr(a: a, b: b)
   
   echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
   
diff --git a/examples/debugging.nim b/examples/debugging.nim
new file mode 100644
index 000000000..89cdd3b2a
--- /dev/null
+++ b/examples/debugging.nim
@@ -0,0 +1,17 @@
+# Simple program to test the debugger
+# compile with --debugger:on
+
+proc someComp(x, y: int): int =
+  let a = x+y
+  if a > 7:
+    let b = a*90
+    {.breakpoint.}
+    result = b
+  {.breakpoint.}
+
+proc pp() =
+  var aa = 45
+  var bb = "abcdef"
+  echo someComp(23, 45)
+
+pp()
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 4735cbb4f..fcbf80fc3 100755
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -1,7 +1,7 @@
 /*
 
             Nimrod's Runtime Library
-        (c) Copyright 2012 Andreas Rumpf
+        (c) Copyright 2013 Andreas Rumpf
 
     See the file "copying.txt", included in this
     distribution, for details about the copyright.
@@ -440,9 +440,9 @@ struct TFrame {
   volatile TFrame F; \
   F.procname = proc; F.filename = file; F.line = 0; F.len = 0; nimFrame(&F);
 
-#define nimfrs(proc, file, slots) \
+#define nimfrs(proc, file, slots, length) \
   volatile struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; TVarSlot s[slots];} F; \
-  F.procname = proc; F.filename = file; F.line = 0; F.len = slots; nimFrame((TFrame*)&F);
+  F.procname = proc; F.filename = file; F.line = 0; F.len = length; nimFrame((TFrame*)&F);
 
 #define nimln(n, file) \
   F.line = n; F.filename = file;
diff --git a/lib/system/debugger.nim b/lib/system/debugger.nim
index f234c9daf..101b3c599 100755
--- a/lib/system/debugger.nim
+++ b/lib/system/debugger.nim
@@ -207,9 +207,8 @@ proc fileMatches(c, bp: cstring): bool =
     return false
   var i = 0
   while i < blen:
-    var x, y: char
-    x = bp[i]
-    y = c[i+clen-blen]
+    var x = bp[i]
+    var y = c[i+clen-blen]
     when FileSystemCaseInsensitive:
       if x >= 'A' and x <= 'Z': x = chr(ord(x) - ord('A') + ord('a'))
       if y >= 'A' and y <= 'Z': y = chr(ord(y) - ord('A') + ord('a'))
@@ -742,7 +741,7 @@ proc checkWatchpoints =
         debugOut(Watchpoints[i].name)
       Watchpoints[i].oldValue = newHash
 
-proc endb(line: int) {.compilerproc.} =
+proc endb(line: int, file: cstring) {.compilerproc.} =
   # This proc is called before every Nimrod code line!
   # Thus, it must have as few parameters as possible to keep the
   # code size small!
@@ -753,6 +752,7 @@ proc endb(line: int) {.compilerproc.} =
   #if oldState != dbOff: 
   checkWatchpoints()
   framePtr.line = line # this is done here for smaller code size!
+  framePtr.filename = file
   if dbgLineHook != nil: dbgLineHook()
   case oldState
   of dbStepInto:
@@ -765,7 +765,8 @@ proc endb(line: int) {.compilerproc.} =
       CommandPrompt()
     else: # breakpoints are wanted though (I guess)
       checkForBreakpoint()
-  of dbBreakpoints: # debugger is only interested in breakpoints
+  of dbBreakpoints:
+    # debugger is only interested in breakpoints
     checkForBreakpoint()
   else: nil
 
diff --git a/todo.txt b/todo.txt
index c914e0155..bb838e24d 100755
--- a/todo.txt
+++ b/todo.txt
@@ -1,6 +1,9 @@
 version 0.9.2
 =============
 
+- fix destructors; don't work yet when used as expression; alternative for 
+  version 1: disallow expressions yielding a type with a destructor that are
+  not in a 'let/var' context  (p(a.openFile, b.openFile) makes no sense anyway)
 - lazy overloading resolution:
   * get rid of ``expr[typ]``, use perhaps ``static[typ]`` instead
   * special case ``tyStmt``
@@ -8,16 +11,24 @@ version 0.9.2
   * test libffi on windows
   * test: times.format with the FFI
 - acyclic vs prunable; introduce GC hints
-- implement constructors
-  - more checks
-  - document them
 - CGEN: ``restrict`` pragma + backend support; computed goto support
-- fix:
-  - 'result' is not properly cleaned for NRVO
 - document NimMain and check whether it works for threading
-- fix destructors; don't work yet when used as expression; alternative for 
-  version 1: disallow expressions yielding a type with a destructor that are
-  not in a 'let/var' context  (p(a.openFile, b.openFile) makes no sense anyway)
+
+
+Bugs
+====
+
+- 'result' is not properly cleaned for NRVO
+- instantiated generics are listed in error messages
+- sneaking with qualifiedLookup() is really broken!
+- aporia.nim(968, 5) Error: ambiguous identifier: 'DELETE' -- 
+  use a qualifier
+- blocks can "export" an identifier but the CCG generates {} for them ...
+- JS gen: fix exception handling
+- osproc execProcesses can deadlock if all processes fail (as experienced
+  in c++ mode)
+- bootstrapping does not work in C++ mode
+- case statement exhaustiveness checking is still wrong
 
 
 version 0.9.4
@@ -40,7 +51,7 @@ version 0.9.X
 - test&finish first class iterators:
   * nested iterators
 - implement the missing features wrt inheritance
-- better support for *hard* realtime systems
+- object pooling support for *hard* realtime systems
 - improve the compiler as a service
 - better support for macros that rewrite procs
 - macros need access to types and symbols (partially implemented)
@@ -71,8 +82,9 @@ version 0.9.XX
 ==============
 
 - object branch transitions can't work with the current 'reset'; add a 'reset'
-  with an additional parameter --> re-evaluate this issue after constructors
-  have been added
+  with an additional parameter --> simple:
+  provide a 'reset(x, TObj(k: nkValue))' instead? why bother? '=' does the
+  same.
 - document nimdoc properly finally
 - make 'clamp' a magic for the range stuff
 - better type syntax for functions and tuples: tuple(int, int); (int,int)->int
@@ -103,6 +115,8 @@ Not essential for 1.0.0
   * first version: mark black in write barrier
   * second version: introduce fake roots instead of marking black
   * third version: find some clever heuristic which is preferable
+- object constructors: static check for fields if discriminator is known at 
+  compile time
 
 
 GC
@@ -122,18 +136,3 @@ Optimizations
   even further write barrier specialization
 - inlining of first class functions
 - proc specialization in the code gen for write barrier specialization
-
-
-Bugs
-====
-
-- instantiated generics are listed in error messages
-- sneaking with qualifiedLookup() is really broken!
-- aporia.nim(968, 5) Error: ambiguous identifier: 'DELETE' -- 
-  use a qualifier
-- blocks can "export" an identifier but the CCG generates {} for them ...
-- JS gen: fix exception handling
-- the better scoping for locals is the wrong default for endb
-- osproc execProcesses can deadlock if all processes fail (as experienced
-  in c++ mode)
-- case statement exhaustiveness checking is still wrong
diff --git a/web/news.txt b/web/news.txt
index a0728e812..7bd0e4f4f 100755
--- a/web/news.txt
+++ b/web/news.txt
@@ -15,17 +15,17 @@ Bugfixes
   with ``GC_disableMarkAndSweep`` and run it explicitly at an appropriate time 
   or not at all. There is also a new GC you can activate 
   with ``--gc:markAndSweep`` which does not have this problem but is slower in
-  general.
+  general and has no realtime guarantees.
 
 
 Library Additions
 -----------------
 
+- There is a new experimental mark&sweep GC which can be faster (or much 
+  slower) than the default GC. Enable with ``--gc:markAndSweep``.
 - Added ``system.onRaise`` to support a condition system.
 - Added ``macros.quote`` for AST quasi-quoting.
 - Added ``system.unsafeNew`` to support hacky variable length objects.
-- There is a new experimental mark&sweep GC which can be faster (or much 
-  slower) than the default GC. Enable with ``--gc:markAndSweep``.
 - ``system.fields`` and ``system.fieldPairs`` support ``object`` too; they
   used to only support tuples.
 
@@ -68,6 +68,7 @@ Language Additions
   dependencies explicitly.
 - Overloading based on ASTs has been implemented.
 - Generics are now supported for multi methods.
+- Objects can be initialized via an *object constructor expression*.
 
 
 2012-09-23 Version 0.9.0 released