summary refs log tree commit diff stats
path: root/rod
diff options
context:
space:
mode:
Diffstat (limited to 'rod')
-rwxr-xr-xrod/ast.nim3
-rwxr-xr-xrod/ccgexprs.nim13
-rwxr-xr-xrod/ccgstmts.nim195
-rwxr-xr-xrod/ccgutils.nim96
-rwxr-xr-xrod/cgen.nim19
-rwxr-xr-xrod/main.nim36
-rwxr-xr-xrod/pragmas.nim23
-rwxr-xr-xrod/rst.nim14
-rwxr-xr-xrod/semexprs.nim13
-rwxr-xr-xrod/semtypes.nim3
-rwxr-xr-xrod/transf.nim4
-rwxr-xr-xrod/wordrecg.nim30
12 files changed, 225 insertions, 224 deletions
diff --git a/rod/ast.nim b/rod/ast.nim
index 2b0fc6d38..c7c0fa7d0 100755
--- a/rod/ast.nim
+++ b/rod/ast.nim
@@ -269,7 +269,8 @@ type
     tfNoSideEffect,   # procedure type does not allow side effects
     tfFinal,          # is the object final?
     tfAcyclic,        # type is acyclic (for GC optimization)
-    tfEnumHasWholes   # enum cannot be mapped into a range
+    tfEnumHasWholes,  # enum cannot be mapped into a range
+    tfShallow         # type can be shallow copied on assignment
 
   TTypeFlags* = set[TTypeFlag]
 
diff --git a/rod/ccgexprs.nim b/rod/ccgexprs.nim
index c8404fef6..65cc33fd4 100755
--- a/rod/ccgexprs.nim
+++ b/rod/ccgexprs.nim
@@ -215,20 +215,21 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
            [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
     else:
       appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
-  of tyArray, tyArrayConstr:
+  of tyObject:                
+    # XXX: check for subtyping?
     if needsComplexAssignment(dest.t):
       appcg(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
            [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
     else:
-      appcg(p, cpsStmts,
-           "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n",
-           [rdLoc(dest), rdLoc(src)])
-  of tyObject:                # XXX: check for subtyping?
+      appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
+  of tyArray, tyArrayConstr:
     if needsComplexAssignment(dest.t):
       appcg(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
            [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
     else:
-      appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
+      appcg(p, cpsStmts,
+           "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n",
+           [rdLoc(dest), rdLoc(src)])
   of tyOpenArray:
     # open arrays are always on the stack - really? What if a sequence is
     # passed to an open array?
diff --git a/rod/ccgstmts.nim b/rod/ccgstmts.nim
index 572b60143..e87305065 100755
--- a/rod/ccgstmts.nim
+++ b/rod/ccgstmts.nim
@@ -10,6 +10,10 @@
 const 
   RangeExpandLimit = 256      # do not generate ranges
                               # over 'RangeExpandLimit' elements
+  stringCaseThreshold = 8
+    # above X strings a hash-switch for strings is generated
+    # this version sets it too high to avoid hashing, because this has not
+    # been tested for a long time
 
 proc genLineDir(p: BProc, t: PNode) = 
   var line = toLinenumber(t.info) # BUGFIX
@@ -229,13 +233,6 @@ proc genRaiseStmt(p: BProc, t: PNode) =
     else: 
       appcg(p, cpsStmts, "#reraiseException();" & tnl)
 
-const 
-  stringCaseThreshold = 100000 
-    # above X strings a hash-switch for strings is generated
-    # this version sets it too high to avoid hashing, because this has not
-    # been tested for a long time
-    # XXX test and enable this optimization!
-
 proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, 
                           rangeFormat, eqFormat: TFormatStr, labl: TLabel) = 
   var 
@@ -251,90 +248,68 @@ proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
       initLocExpr(p, b.sons[i], x)
       appcg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl])
 
-proc genCaseSecondPass(p: BProc, t: PNode, labId: int) = 
+proc genCaseSecondPass(p: BProc, t: PNode, labId, until: int): TLabel = 
   var Lend = getLabel(p)
-  for i in countup(1, sonsLen(t) - 1): 
+  for i in 1..until: 
     appf(p.s[cpsStmts], "LA$1: ;$n", [toRope(labId + i)])
-    if t.sons[i].kind == nkOfBranch: # else statement
+    if t.sons[i].kind == nkOfBranch:
       var length = sonsLen(t.sons[i])
       genStmts(p, t.sons[i].sons[length - 1])
       appf(p.s[cpsStmts], "goto $1;$n", [Lend])
     else: 
       genStmts(p, t.sons[i].sons[0])
-  fixLabel(p, Lend)
+  result = Lend
 
-proc genCaseGeneric(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr) = 
+proc genIfForCaseUntil(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr,
+                       until: int, a: TLoc): TLabel = 
   # generate a C-if statement for a Nimrod case statement
-  var a: TLoc
-  initLocExpr(p, t.sons[0], a) # fist pass: generate ifs+goto:
   var labId = p.labels
-  for i in countup(1, sonsLen(t) - 1): 
+  for i in 1..until: 
     inc(p.labels)
     if t.sons[i].kind == nkOfBranch: # else statement
       genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat, 
                            con("LA", toRope(p.labels)))
     else: 
       appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.labels)])
-  genCaseSecondPass(p, t, labId)
-
-proc hashString(s: string): biggestInt = 
-  var 
-    a: int32
-    b: int64
-  if CPU[targetCPU].bit == 64: 
-    # we have to use the same bitwidth
-    # as the target CPU
-    b = 0
-    for i in countup(0, len(s) - 1): 
-      b = b +% Ord(s[i])
-      b = b +% `shl`(b, 10)
-      b = b xor `shr`(b, 6)
-    b = b +% `shl`(b, 3)
-    b = b xor `shr`(b, 11)
-    b = b +% `shl`(b, 15)
-    result = b
-  else: 
-    a = 0
-    for i in countup(0, len(s) - 1): 
-      a = a +% int32(Ord(s[i]))
-      a = a +% `shl`(a, int32(10))
-      a = a xor `shr`(a, int32(6))
-    a = a +% `shl`(a, int32(3))
-    a = a xor `shr`(a, int32(11))
-    a = a +% `shl`(a, int32(15))
-    result = a
+  if until < t.len-1: 
+    inc(p.labels)
+    var gotoTarget = p.labels
+    appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(gotoTarget)])
+    result = genCaseSecondPass(p, t, labId, until)
+    appf(p.s[cpsStmts], "LA$1: ;$n", [toRope(gotoTarget)])
+  else:
+    result = genCaseSecondPass(p, t, labId, until)
 
-type 
-  TRopeSeq = seq[PRope]
+proc genCaseGeneric(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr) = 
+  var a: TLoc
+  initLocExpr(p, t.sons[0], a)
+  var Lend = genIfForCaseUntil(p, t, rangeFormat, eqFormat, sonsLen(t)-1, a)
+  fixLabel(p, Lend)
 
 proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel, 
-                         branches: var TRopeSeq) = 
-  var 
-    length, j: int
-    x: TLoc
-  length = sonsLen(b)
+                         branches: var openArray[PRope]) = 
+  var x: TLoc
+  var length = sonsLen(b)
   for i in countup(0, length - 2): 
     assert(b.sons[i].kind != nkRange)
     initLocExpr(p, b.sons[i], x)
     assert(b.sons[i].kind in {nkStrLit..nkTripleStrLit})
-    j = int(hashString(b.sons[i].strVal) and high(branches))
+    var j = int(hashString(b.sons[i].strVal) and high(branches))
     appcg(p.module, branches[j], "if (#eqStrings($1, $2)) goto $3;$n", 
          [rdLoc(e), rdLoc(x), labl])
 
 proc genStringCase(p: BProc, t: PNode) = 
-  var 
-    strings, bitMask, labId: int
-    a: TLoc
-    branches: TRopeSeq
   # count how many constant strings there are in the case:
-  strings = 0
+  var strings = 0
   for i in countup(1, sonsLen(t) - 1): 
     if t.sons[i].kind == nkOfBranch: inc(strings, sonsLen(t.sons[i]) - 1)
   if strings > stringCaseThreshold: 
-    bitMask = math.nextPowerOfTwo(strings) - 1
+    var bitMask = math.nextPowerOfTwo(strings) - 1
+    var branches: seq[PRope]
     newSeq(branches, bitMask + 1)
+    var a: TLoc
     initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto:
-    labId = p.labels
+    var labId = p.labels
     for i in countup(1, sonsLen(t) - 1): 
       inc(p.labels)
       if t.sons[i].kind == nkOfBranch: 
@@ -353,67 +328,72 @@ proc genStringCase(p: BProc, t: PNode) =
     if t.sons[sonsLen(t) - 1].kind != nkOfBranch: 
       appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.labels)]) 
     # third pass: generate statements
-    genCaseSecondPass(p, t, labId)
+    var Lend = genCaseSecondPass(p, t, labId, sonsLen(t)-1)
+    fixLabel(p, Lend)
   else: 
     genCaseGeneric(p, t, "", "if (#eqStrings($1, $2)) goto $3;$n")
   
 proc branchHasTooBigRange(b: PNode): bool = 
-  for i in countup(0, sonsLen(b) - 2): 
+  for i in countup(0, sonsLen(b)-2): 
     # last son is block
     if (b.sons[i].Kind == nkRange) and
         b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit: 
       return true
-  result = false
 
-proc genOrdinalCase(p: BProc, t: PNode) = 
-  # We analyse if we have a too big switch range. If this is the case,
-  # we generate an ordinary if statement and rely on the C compiler
-  # to produce good code.
-  var 
-    canGenerateSwitch, hasDefault: bool
-    length: int
-    a: TLoc
-    v: PNode
-  canGenerateSwitch = true
-  if not (hasSwitchRange in CC[ccompiler].props): 
-    for i in countup(1, sonsLen(t) - 1): 
-      if (t.sons[i].kind == nkOfBranch) and branchHasTooBigRange(t.sons[i]): 
-        canGenerateSwitch = false
-        break 
-  if canGenerateSwitch: 
-    initLocExpr(p, t.sons[0], a)
+proc IfSwitchSplitPoint(p: BProc, n: PNode): int =
+  for i in 1..n.len-1:
+    var branch = n[i]
+    var stmtBlock = lastSon(branch)
+    if stmtBlock.stmtsContainPragma(wLinearScanEnd):
+      result = i
+    elif hasSwitchRange notin CC[ccompiler].props: 
+      if branch.kind == nkOfBranch and branchHasTooBigRange(branch): 
+        result = i
+
+proc genOrdinalCase(p: BProc, n: PNode) = 
+  # analyse 'case' statement:
+  var splitPoint = IfSwitchSplitPoint(p, n)
+  
+  # generate if part (might be empty):
+  var a: TLoc
+  initLocExpr(p, n.sons[0], a)
+  var Lend = if splitPoint > 0: genIfForCaseUntil(p, n, 
+                    rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n",
+                    eqFormat = "if ($1 == $2) goto $3;$n", 
+                    splitPoint, a) else: nil
+  
+  # generate switch part (might be empty):
+  if splitPoint+1 < n.len:
     appf(p.s[cpsStmts], "switch ($1) {$n", [rdCharLoc(a)])
-    hasDefault = false
-    for i in countup(1, sonsLen(t) - 1): 
-      if t.sons[i].kind == nkOfBranch: 
-        length = sonsLen(t.sons[i])
-        for j in countup(0, length - 2): 
-          if t.sons[i].sons[j].kind == nkRange: 
-            # a range
+    var hasDefault = false
+    for i in splitPoint+1 .. < n.len: 
+      var branch = n[i]
+      if branch.kind == nkOfBranch: 
+        var length = branch.len
+        for j in 0 .. length-2: 
+          if branch[j].kind == nkRange: 
             if hasSwitchRange in CC[ccompiler].props: 
               appf(p.s[cpsStmts], "case $1 ... $2:$n", [
-                  genLiteral(p, t.sons[i].sons[j].sons[0]), 
-                  genLiteral(p, t.sons[i].sons[j].sons[1])])
+                  genLiteral(p, branch[j][0]), 
+                  genLiteral(p, branch[j][1])])
             else: 
-              v = copyNode(t.sons[i].sons[j].sons[0])
-              while (v.intVal <= t.sons[i].sons[j].sons[1].intVal): 
+              var v = copyNode(branch[j][0])
+              while v.intVal <= branch[j][1].intVal: 
                 appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, v)])
                 Inc(v.intVal)
           else: 
-            appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, t.sons[i].sons[j])])
-        genStmts(p, t.sons[i].sons[length - 1])
+            appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, branch[j])])
+        genStmts(p, branch[length-1])
       else: 
         # else part of case statement:
         app(p.s[cpsStmts], "default:" & tnl)
-        genStmts(p, t.sons[i].sons[0])
+        genStmts(p, branch[0])
         hasDefault = true
       app(p.s[cpsStmts], "break;" & tnl)
     if (hasAssume in CC[ccompiler].props) and not hasDefault: 
       app(p.s[cpsStmts], "default: __assume(0);" & tnl)
     app(p.s[cpsStmts], '}' & tnl)
-  else: 
-    genCaseGeneric(p, t, "if ($1 >= $2 && $1 <= $3) goto $4;$n", 
-                   "if ($1 == $2) goto $3;$n")
+  if Lend != nil: fixLabel(p, Lend)
   
 proc genCaseStmt(p: BProc, t: PNode) = 
   genLineDir(p, t)
@@ -424,7 +404,6 @@ proc genCaseStmt(p: BProc, t: PNode) =
     genCaseGeneric(p, t, "if ($1 >= $2 && $1 <= $3) goto $4;$n", 
                    "if ($1 == $2) goto $3;$n") 
   else: 
-    # ordinal type: generate a switch statement
     genOrdinalCase(p, t)
   
 proc hasGeneralExceptSection(t: PNode): bool = 
@@ -629,19 +608,17 @@ proc genBreakPoint(p: BProc, t: PNode) =
 proc genPragma(p: BProc, n: PNode) = 
   for i in countup(0, sonsLen(n) - 1): 
     var it = n.sons[i]
-    var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
-    if key.kind == nkIdent: 
-      case whichKeyword(key.ident)
-      of wEmit:
-        genEmit(p, it)
-      of wBreakpoint: 
-        genBreakPoint(p, it)
-      of wDeadCodeElim: 
-        if not (optDeadCodeElim in gGlobalOptions): 
-          # we need to keep track of ``deadCodeElim`` pragma
-          if (sfDeadCodeElim in p.module.module.flags): 
-            addPendingModule(p.module)
-      else: nil
+    case whichPragma(it)
+    of wEmit:
+      genEmit(p, it)
+    of wBreakpoint: 
+      genBreakPoint(p, it)
+    of wDeadCodeElim: 
+      if not (optDeadCodeElim in gGlobalOptions): 
+        # we need to keep track of ``deadCodeElim`` pragma
+        if (sfDeadCodeElim in p.module.module.flags): 
+          addPendingModule(p.module)
+    else: nil
   
 proc genAsgn(p: BProc, e: PNode) = 
   var a: TLoc
diff --git a/rod/ccgutils.nim b/rod/ccgutils.nim
index c7733c5ff..f1d66ca94 100755
--- a/rod/ccgutils.nim
+++ b/rod/ccgutils.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nimrod Compiler
-#        (c) Copyright 2009 Andreas Rumpf
+#        (c) Copyright 2011 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -10,21 +10,58 @@
 # This module declares some helpers for the C code generator.
 
 import 
-  ast, astalgo, ropes, lists, nhashes, strutils, types, msgs
+  ast, astalgo, ropes, lists, nhashes, strutils, types, msgs, wordrecg, 
+  platform
 
-proc toCChar*(c: Char): string
-proc makeCString*(s: string): PRope
-proc makeLLVMString*(s: string): PRope
-proc TableGetType*(tab: TIdTable, key: PType): PObject
-proc GetUniqueType*(key: PType): PType
-# implementation
+proc whichPragma*(n: PNode): TSpecialWord = 
+  var key = if n.kind == nkExprColonExpr: n.sons[0] else: n
+  if key.kind == nkIdent: result = whichKeyword(key.ident)
+
+proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
+  case n.kind
+  of nkStmtList: 
+    for i in 0 .. < n.len: 
+      result = getPragmaStmt(n[i], w)
+      if result != nil: break
+  of nkPragma:
+    for i in 0 .. < n.len: 
+      if whichPragma(n[i]) == w: return n[i]
+  else: nil
+
+proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
+  result = getPragmaStmt(n, w) != nil
+
+proc hashString*(s: string): biggestInt = 
+  # has to be the same algorithm as system.hashString!
+  if CPU[targetCPU].bit == 64: 
+    # we have to use the same bitwidth
+    # as the target CPU
+    var b = 0'i64
+    for i in countup(0, len(s) - 1): 
+      b = b +% Ord(s[i])
+      b = b +% `shl`(b, 10)
+      b = b xor `shr`(b, 6)
+    b = b +% `shl`(b, 3)
+    b = b xor `shr`(b, 11)
+    b = b +% `shl`(b, 15)
+    result = b
+  else: 
+    var a = 0'i32
+    for i in countup(0, len(s) - 1): 
+      a = a +% Ord(s[i]).int32
+      a = a +% `shl`(a, 10'i32)
+      a = a xor `shr`(a, 6'i32)
+    a = a +% `shl`(a, 3'i32)
+    a = a xor `shr`(a, 11'i32)
+    a = a +% `shl`(a, 15'i32)
+    result = a
 
 var gTypeTable: array[TTypeKind, TIdTable]
 
 proc initTypeTables() = 
   for i in countup(low(TTypeKind), high(TTypeKind)): InitIdTable(gTypeTable[i])
   
-proc GetUniqueType(key: PType): PType = 
+proc GetUniqueType*(key: PType): PType = 
   var 
     t: PType
     k: TTypeKind
@@ -32,33 +69,7 @@ proc GetUniqueType(key: PType): PType =
   result = key
   if key == nil: return 
   k = key.kind
-  case k #
-         #  case key.Kind of
-         #    tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString, 
-         #    tyInt..tyFloat128, tyProc, tyAnyEnum: begin end;
-         #    tyNone, tyForward: 
-         #      InternalError('GetUniqueType: ' + typeToString(key));
-         #    tyGenericParam, tyGeneric, tyAbstract, tySequence,
-         #    tyOpenArray, tySet, tyVar, tyRef, tyPtr, tyArrayConstr,
-         #    tyArray, tyTuple, tyRange: begin
-         #      // we have to do a slow linear search because types may need
-         #      // to be compared by their structure:
-         #      if IdTableHasObjectAsKey(gTypeTable, key) then exit;
-         #      for h := 0 to high(gTypeTable.data) do begin
-         #        t := PType(gTypeTable.data[h].key);
-         #        if (t <> nil) and sameType(t, key) then begin result := t; exit end
-         #      end;
-         #      IdTablePut(gTypeTable, key, key);
-         #    end;
-         #    tyObject, tyEnum: begin
-         #      result := PType(IdTableGet(gTypeTable, key));
-         #      if result = nil then begin
-         #        IdTablePut(gTypeTable, key, key);
-         #        result := key;
-         #      end
-         #    end;
-         #    tyGenericInst, tyAbstract: result := GetUniqueType(lastSon(key));
-         #  end; 
+  case k 
   of tyObject, tyEnum: 
     result = PType(IdTableGet(gTypeTable[k], key))
     if result == nil: 
@@ -78,7 +89,7 @@ proc GetUniqueType(key: PType): PType =
         return t
     IdTablePut(gTypeTable[k], key, key)
 
-proc TableGetType(tab: TIdTable, key: PType): PObject = 
+proc TableGetType*(tab: TIdTable, key: PType): PObject = 
   var t: PType
   # returns nil if we need to declare this type
   result = IdTableGet(tab, key)
@@ -91,13 +102,13 @@ proc TableGetType(tab: TIdTable, key: PType): PObject =
         if sameType(t, key): 
           return tab.data[h].val
 
-proc toCChar(c: Char): string = 
+proc toCChar*(c: Char): string = 
   case c
   of '\0'..'\x1F', '\x80'..'\xFF': result = '\\' & toOctal(c)
   of '\'', '\"', '\\': result = '\\' & c
   else: result = $(c)
   
-proc makeCString(s: string): PRope = 
+proc makeCString*(s: string): PRope = 
   # BUGFIX: We have to split long strings into many ropes. Otherwise
   # this could trigger an InternalError(). See the ropes module for
   # further information.
@@ -117,9 +128,8 @@ proc makeCString(s: string): PRope =
   add(res, '\"')
   app(result, toRope(res))
 
-proc makeLLVMString(s: string): PRope = 
-  const 
-    MaxLineLength = 64
+proc makeLLVMString*(s: string): PRope = 
+  const MaxLineLength = 64
   var res: string
   result = nil
   res = "c\""
@@ -135,4 +145,4 @@ proc makeLLVMString(s: string): PRope =
   add(res, "\\00\"")
   app(result, toRope(res))
 
-InitTypeTables()
\ No newline at end of file
+InitTypeTables()
diff --git a/rod/cgen.nim b/rod/cgen.nim
index 503cb8586..7df9f3d11 100755
--- a/rod/cgen.nim
+++ b/rod/cgen.nim
@@ -308,14 +308,19 @@ proc zeroVar(p: BProc, loc: TLoc, containsGCref: bool) =
 proc zeroTemp(p: BProc, loc: TLoc) = 
   if skipTypes(loc.t, abstractVarRange).Kind notin
       {tyArray, tyArrayConstr, tySet, tyTuple, tyObject}: 
-    var nilLoc: TLoc
-    initLoc(nilLoc, locTemp, loc.t, onStack)
-    nilLoc.r = toRope("NIM_NIL")
-    # puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``:
-    genRefAssign(p, loc, nilLoc, {afSrcIsNil})
+    appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(loc)])
+    when false:
+      var nilLoc: TLoc
+      initLoc(nilLoc, locTemp, loc.t, onStack)
+      nilLoc.r = toRope("NIM_NIL")
+      # puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``:
+      genRefAssign(p, loc, nilLoc, {afSrcIsNil})
   else: 
-    appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", 
-         [addrLoc(loc), genTypeInfo(p.module, loc.t)])
+    appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n", 
+         [addrLoc(loc), rdLoc(loc)])
+    when false:
+      appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", 
+           [addrLoc(loc), genTypeInfo(p.module, loc.t)])
 
 proc initVariable(p: BProc, v: PSym) = 
   var b = containsGarbageCollectedRef(v.typ)
diff --git a/rod/main.nim b/rod/main.nim
index 977a4ff1b..79059a874 100755
--- a/rod/main.nim
+++ b/rod/main.nim
@@ -193,23 +193,23 @@ proc MainCommand(cmd, filename: string) =
   setID(100)
   passes.gIncludeFile = syntaxes.parseFile
   passes.gImportModule = importModule
-  case whichKeyword(cmd)
-  of wCompile, wCompileToC, wC, wCC: 
+  case cmd.normalize
+  of "c", "cc", "compile", "compiletoc": 
     # compile means compileToC currently
     gCmd = cmdCompileToC
     wantFile(filename)
     CommandCompileToC(filename)
-  of wCompileToCpp: 
+  of "compiletocpp": 
     extccomp.cExt = ".cpp"
     gCmd = cmdCompileToCpp
     wantFile(filename)
     CommandCompileToC(filename)
-  of wCompileToOC, wOC:
+  of "oc", "compiletooc":
     extccomp.cExt = ".m"
     gCmd = cmdCompileToOC
     wantFile(filename)
     CommandCompileToC(filename)
-  of wRun:
+  of "run":
     gCmd = cmdRun
     wantFile(filename)
     when hasTinyCBackend:
@@ -217,61 +217,61 @@ proc MainCommand(cmd, filename: string) =
       CommandCompileToC(filename)
     else: 
       rawMessage(errInvalidCommandX, cmd)
-  of wCompileToEcmaScript, wJs: 
+  of "js", "compiletoecmascript": 
     gCmd = cmdCompileToEcmaScript
     wantFile(filename)
     CommandCompileToEcmaScript(filename)
-  of wCompileToLLVM: 
+  of "compiletollvm": 
     gCmd = cmdCompileToLLVM
     wantFile(filename)
     when has_LLVM_Backend:
       CommandCompileToLLVM(filename)
     else:
       rawMessage(errInvalidCommandX, cmd)
-  of wPretty: 
+  of "pretty": 
     gCmd = cmdPretty
     wantFile(filename)        #CommandExportSymbols(filename);
     CommandPretty(filename)
-  of wDoc: 
+  of "doc": 
     gCmd = cmdDoc
     LoadSpecialConfig(DocConfig)
     wantFile(filename)
     CommandDoc(filename)
-  of wRst2html: 
+  of "rst2html": 
     gCmd = cmdRst2html
     LoadSpecialConfig(DocConfig)
     wantFile(filename)
     CommandRst2Html(filename)
-  of wRst2tex: 
+  of "rst2tex": 
     gCmd = cmdRst2tex
     LoadSpecialConfig(DocTexConfig)
     wantFile(filename)
     CommandRst2TeX(filename)
-  of wGenDepend: 
+  of "gendepend": 
     gCmd = cmdGenDepend
     wantFile(filename)
     CommandGenDepend(filename)
-  of wDump: 
+  of "dump": 
     gCmd = cmdDump
     condsyms.ListSymbols()
     for it in iterSearchPath(): MsgWriteln(it)
-  of wCheck: 
+  of "check": 
     gCmd = cmdCheck
     wantFile(filename)
     CommandCheck(filename)
-  of wParse: 
+  of "parse": 
     gCmd = cmdParse
     wantFile(filename)
     discard parseFile(addFileExt(filename, nimExt))
-  of wScan: 
+  of "scan": 
     gCmd = cmdScan
     wantFile(filename)
     CommandScan(filename)
     MsgWriteln("Beware: Indentation tokens depend on the parser\'s state!")
-  of wI: 
+  of "i": 
     gCmd = cmdInteractive
     CommandInteractive()
-  of wIdeTools:
+  of "idetools":
     gCmd = cmdIdeTools
     wantFile(filename)
     CommandSuggest(filename)
diff --git a/rod/pragmas.nim b/rod/pragmas.nim
index 45543eb74..d7bda4099 100755
--- a/rod/pragmas.nim
+++ b/rod/pragmas.nim
@@ -34,12 +34,12 @@ const
     wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, wFatal, 
     wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop, wBreakpoint, 
     wCheckpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated, wFloatChecks,
-    wInfChecks, wNanChecks, wPragma, wEmit}
+    wInfChecks, wNanChecks, wPragma, wEmit, wUnroll, wLinearScanEnd}
   lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, 
     wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wPure, 
     wDeprecated, wExtern}
   typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl, 
-    wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern}
+    wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow}
   fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern}
   varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, 
     wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib, wExtern}
@@ -357,6 +357,19 @@ proc PragmaEmit(c: PContext, n: PNode) =
 proc noVal(n: PNode) = 
   if n.kind == nkExprColonExpr: invalidPragma(n)
 
+proc PragmaUnroll(c: PContext, n: PNode) = 
+  if c.p.nestedLoopCounter <= 0: 
+    invalidPragma(n)
+  elif n.kind == nkExprColonExpr:
+    var unrollFactor = expectIntLit(c, n)
+    if unrollFactor <% 32: 
+      n.sons[1] = newIntNode(nkIntLit, unrollFactor)
+    else: 
+      invalidPragma(n)
+
+proc PragmaLinearScanEnd(c: PContext, n: PNode) =
+  noVal(n)
+
 proc processPragma(c: PContext, n: PNode, i: int) = 
   var it = n.sons[i]
   if it.kind != nkExprColonExpr: invalidPragma(n)
@@ -475,6 +488,10 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
             noVal(it)
             if sym.typ == nil: invalidPragma(it)
             incl(sym.typ.flags, tfAcyclic)
+          of wShallow:
+            noVal(it)
+            if sym.typ == nil: invalidPragma(it)
+            incl(sym.typ.flags, tfShallow)
           of wTypeCheck: 
             noVal(it)
             incl(sym.flags, sfTypeCheck)
@@ -509,6 +526,8 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
             if sym.typ == nil: invalidPragma(it)
             sym.typ.callConv = wordToCallConv(k)
           of wEmit: PragmaEmit(c, it)
+          of wUnroll: PragmaUnroll(c, it)
+          of wLinearScanEnd: PragmaLinearScanEnd(c, it)
           else: invalidPragma(it)
         else: invalidPragma(it)
     else: processNote(c, it)
diff --git a/rod/rst.nim b/rod/rst.nim
index efda9bd9a..dace43a44 100755
--- a/rod/rst.nim
+++ b/rod/rst.nim
@@ -188,7 +188,7 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
   of '\x0D', '\x0A': 
     getIndent(L, tok)
   of '!', '\"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', 
-     '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', 
+     '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{',
      '|', '}', '~': 
     getAdornment(L, tok)
     if len(tok.symbol) <= 3: tok.kind = tkPunct
@@ -257,16 +257,16 @@ type
     value*: PRstNode
 
   TSharedState{.final.} = object 
-    uLevel*, oLevel*: int     # counters for the section levels
-    subs*: seq[TSubstitution] # substitutions
-    refs*: seq[TSubstitution] # references
+    uLevel*, oLevel*: int        # counters for the section levels
+    subs*: seq[TSubstitution]    # substitutions
+    refs*: seq[TSubstitution]    # references
     underlineToLevel*: TLevelMap # Saves for each possible title adornment
                                  # character its level in the
                                  # current document. 
                                  # This is for single underline adornments.
-    overlineToLevel*: TLevelMap # Saves for each possible title adornment 
-                                # character its level in the current document. 
-                                # This is for over-underline adornments.
+    overlineToLevel*: TLevelMap  # Saves for each possible title adornment 
+                                 # character its level in the current document. 
+                                 # This is for over-underline adornments.
   
   PSharedState = ref TSharedState
   TRstParser = object of TObject
diff --git a/rod/semexprs.nim b/rod/semexprs.nim
index 1d20e5253..7a14b931a 100755
--- a/rod/semexprs.nim
+++ b/rod/semexprs.nim
@@ -410,10 +410,13 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
   
 proc semDirectCallAnalyseEffects(c: PContext, n: PNode,
                                  flags: TExprFlags): PNode = 
-  if not (efWantIterator in flags): 
-    result = semDirectCall(c, n, {skProc, skMethod, skConverter})
-  else: 
-    result = semDirectCall(c, n, {skIterator})
+  var symflags = {skProc, skMethod, skConverter}
+  if efWantIterator in flags:
+    symflags = {skIterator}
+  elif efAllowType in flags: 
+    # for ``type countup(1,3)``, see ``tests/ttoseq``.
+    symflags.incl(skIterator)
+  result = semDirectCall(c, n, symflags)
   if result != nil: 
     if result.sons[0].kind != nkSym: 
       InternalError("semDirectCallAnalyseEffects")
@@ -1037,7 +1040,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     of paNone: result = nil
     of paTuplePositions: result = semTuplePositionsConstr(c, n)
     of paTupleFields: result = semTupleFieldsConstr(c, n)
-    of paSingle: result = semExpr(c, n.sons[0])
+    of paSingle: result = semExpr(c, n.sons[0], flags)
   of nkCurly: result = semSetConstr(c, n)
   of nkBracket: result = semArrayConstr(c, n)
   of nkLambda: result = semLambda(c, n)
diff --git a/rod/semtypes.nim b/rod/semtypes.nim
index 4a676e00a..8dae5c27b 100755
--- a/rod/semtypes.nim
+++ b/rod/semtypes.nim
@@ -574,7 +574,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   case n.kind
   of nkEmpty: nil
   of nkTypeOfExpr: 
-    result = semExprWithType(c, n, {efAllowType}).typ
+    checkSonsLen(n, 1)
+    result = semExprWithType(c, n.sons[0], {efAllowType}).typ
   of nkPar: 
     if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
     else: GlobalError(n.info, errTypeExpected)
diff --git a/rod/transf.nim b/rod/transf.nim
index 5b62c7f16..c7c4e3db8 100755
--- a/rod/transf.nim
+++ b/rod/transf.nim
@@ -340,10 +340,6 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
       #result = newTransNode(n.sons[0])
       #result[1] = transform(c, m.sons[0])
       
-      #if skipTypes(n.sons[0].typ, abstractVar).kind == tyOpenArray:
-      #  debug(result.pnode)
-      #  liMessage(n.info, warnUser, 
-      #    "nkPassAsOpenArray introduced here " & renderTree(n))
     else:
       result = transformSons(c, n)
   else: 
diff --git a/rod/wordrecg.nim b/rod/wordrecg.nim
index f9ea37158..8376fa01b 100755
--- a/rod/wordrecg.nim
+++ b/rod/wordrecg.nim
@@ -53,12 +53,8 @@ type
     wGenerate, wG, wC, wCpp, wBorrow, wRun, wR, wVerbosity, wV, wHelp, wH, 
     wSymbolFiles, wFieldChecks, wX, wVersion, wAdvanced, wSkipcfg, wSkipProjCfg, 
     wCc, wGenscript, wCheckPoint, wCheckPoints, wNoMain, wSubsChar, 
-    wAcyclic, wIndex, 
-    wCompileToC, wCompileToCpp, wCompileToEcmaScript, wCompileToLLVM, 
-    wCompileToOC,
-    wPretty, 
-    wDoc, wGenDepend, wDump, wCheck, wParse, wScan, wJs, wOC, 
-    wRst2html, wRst2tex, wI,
+    wAcyclic, wShallow, wUnroll, wLinearScanEnd,
+    wIndex, 
     wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wThreads,
     wRecursivePath, 
     wStdout,
@@ -105,33 +101,25 @@ const
     "cpu", "generate", "g", "c", "cpp", "borrow", "run", "r", "verbosity", "v", 
     "help", "h", "symbolfiles", "fieldchecks", "x", "version", "advanced", 
     "skipcfg", "skipprojcfg", "cc", "genscript", "checkpoint", "checkpoints", 
-    "nomain", "subschar", "acyclic", "index", 
-    "compiletoc", "compiletocpp", "compiletoecmascript", "compiletollvm", 
-    "compiletooc",
-    "pretty", "doc", "gendepend", "dump", "check", "parse", "scan", 
-    "js", "oc", "rst2html", "rst2tex", "i", 
+    "nomain", "subschar", "acyclic", "shallow", "unroll", "linearscanend",
+    "index", 
     "write", "putenv", "prependenv", "appendenv", "threadvar", "emit",
     "threads", "recursivepath", 
     "stdout",
     "idetools", "suggest", "track", "def", "context"]
 
-proc whichKeyword*(id: PIdent): TSpecialWord
-proc whichKeyword*(id: String): TSpecialWord
-proc findStr*(a: openarray[string], s: string): int
-# implementation
-
-proc findStr(a: openarray[string], s: string): int = 
+proc findStr*(a: openarray[string], s: string): int = 
   for i in countup(low(a), high(a)): 
     if cmpIgnoreStyle(a[i], s) == 0: 
       return i
   result = - 1
 
-proc whichKeyword(id: String): TSpecialWord = 
-  result = whichKeyword(getIdent(id))
-
-proc whichKeyword(id: PIdent): TSpecialWord = 
+proc whichKeyword*(id: PIdent): TSpecialWord = 
   if id.id < 0: result = wInvalid
   else: result = TSpecialWord(id.id)
+
+proc whichKeyword*(id: String): TSpecialWord = 
+  result = whichKeyword(getIdent(id))
   
 proc initSpecials() = 
   # initialize the keywords: