summary refs log tree commit diff stats
path: root/nim
diff options
context:
space:
mode:
Diffstat (limited to 'nim')
-rw-r--r--nim/ast.pas110
-rw-r--r--nim/ccgexprs.pas29
-rw-r--r--nim/docgen.pas18
-rw-r--r--nim/evals.pas132
-rw-r--r--nim/importer.pas4
-rw-r--r--nim/lookups.pas48
-rw-r--r--nim/msgs.pas62
-rw-r--r--nim/nimsets.pas5
-rw-r--r--nim/pasparse.pas13
-rw-r--r--nim/pnimsyn.pas23
-rw-r--r--nim/pragmas.pas13
-rw-r--r--nim/rnimsyn.pas23
-rw-r--r--nim/ropes.pas5
-rw-r--r--nim/scanner.pas16
-rw-r--r--nim/sem.pas11
-rw-r--r--nim/semdata.pas4
-rw-r--r--nim/semexprs.pas162
-rw-r--r--nim/semstmts.pas41
-rw-r--r--nim/semtempl.pas57
-rw-r--r--nim/sigmatch.pas72
-rw-r--r--nim/strutils.pas11
-rw-r--r--nim/transf.pas22
-rw-r--r--nim/types.pas10
-rw-r--r--nim/wordrecg.pas20
24 files changed, 544 insertions, 367 deletions
diff --git a/nim/ast.pas b/nim/ast.pas
index 681bf72d5..4836a860e 100644
--- a/nim/ast.pas
+++ b/nim/ast.pas
@@ -78,27 +78,27 @@ type
     nkCurly, nkBracket, nkBracketExpr, nkPragmaExpr, 
     nkRange, nkDotExpr, nkCheckedFieldExpr, nkDerefExpr, 
     nkIfExpr, nkElifExpr, nkElseExpr, nkLambda, 
-    nkAccQuoted, nkHeaderQuoted, nkTableConstr, nkQualified, 
-    nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv, nkConv, 
-    nkCast, nkAddr, nkHiddenAddr, nkHiddenDeref, 
-    nkObjDownConv, nkObjUpConv, nkChckRangeF, nkChckRange64, 
-    nkChckRange, nkStringToCString, nkCStringToString, nkPassAsOpenArray, 
-    nkAsgn, nkFastAsgn, nkDefaultTypeParam, nkGenericParams, 
-    nkFormalParams, nkOfInherit, nkModule, nkProcDef, 
-    nkConverterDef, nkMacroDef, nkTemplateDef, nkIteratorDef, 
-    nkOfBranch, nkElifBranch, nkExceptBranch, nkElse, 
-    nkMacroStmt, nkAsmStmt, nkPragma, nkIfStmt, 
-    nkWhenStmt, nkForStmt, nkWhileStmt, nkCaseStmt, 
-    nkVarSection, nkConstSection, nkConstDef, nkTypeSection, 
-    nkTypeDef, nkYieldStmt, nkTryStmt, nkFinally, 
-    nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt, 
-    nkBlockStmt, nkDiscardStmt, nkStmtList, nkImportStmt, 
-    nkFromStmt, nkImportAs, nkIncludeStmt, nkCommentStmt, 
-    nkStmtListExpr, nkBlockExpr, nkStmtListType, nkBlockType, 
-    nkVm, nkTypeOfExpr, nkObjectTy, nkTupleTy, 
-    nkRecList, nkRecCase, nkRecWhen, nkRefTy, 
-    nkPtrTy, nkVarTy, nkAbstractTy, nkProcTy, 
-    nkEnumTy, nkEnumFieldDef, nkReturnToken);
+    nkAccQuoted, nkTableConstr, nkQualified, nkBind, 
+    nkSymChoice, nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv, 
+    nkConv, nkCast, nkAddr, nkHiddenAddr, 
+    nkHiddenDeref, nkObjDownConv, nkObjUpConv, nkChckRangeF, 
+    nkChckRange64, nkChckRange, nkStringToCString, nkCStringToString, 
+    nkPassAsOpenArray, nkAsgn, nkFastAsgn, nkDefaultTypeParam, 
+    nkGenericParams, nkFormalParams, nkOfInherit, nkModule, 
+    nkProcDef, nkConverterDef, nkMacroDef, nkTemplateDef, 
+    nkIteratorDef, nkOfBranch, nkElifBranch, nkExceptBranch, 
+    nkElse, nkMacroStmt, nkAsmStmt, nkPragma, 
+    nkIfStmt, nkWhenStmt, nkForStmt, nkWhileStmt, 
+    nkCaseStmt, nkVarSection, nkConstSection, nkConstDef, 
+    nkTypeSection, nkTypeDef, nkYieldStmt, nkTryStmt, 
+    nkFinally, nkRaiseStmt, nkReturnStmt, nkBreakStmt, 
+    nkContinueStmt, nkBlockStmt, nkDiscardStmt, nkStmtList, 
+    nkImportStmt, nkFromStmt, nkImportAs, nkIncludeStmt, 
+    nkCommentStmt, nkStmtListExpr, nkBlockExpr, nkStmtListType, 
+    nkBlockType, nkVm, nkTypeOfExpr, nkObjectTy, 
+    nkTupleTy, nkRecList, nkRecCase, nkRecWhen, 
+    nkRefTy, nkPtrTy, nkVarTy, nkAbstractTy, 
+    nkProcTy, nkEnumTy, nkEnumFieldDef, nkReturnToken);
   TNodeKinds = set of TNodeKind;
 const
   NodeKindToStr: array [TNodeKind] of string = (
@@ -113,48 +113,48 @@ const
     'nkCurly', 'nkBracket', 'nkBracketExpr', 'nkPragmaExpr', 
     'nkRange', 'nkDotExpr', 'nkCheckedFieldExpr', 'nkDerefExpr', 
     'nkIfExpr', 'nkElifExpr', 'nkElseExpr', 'nkLambda', 
-    'nkAccQuoted', 'nkHeaderQuoted', 'nkTableConstr', 'nkQualified', 
-    'nkHiddenStdConv', 'nkHiddenSubConv', 'nkHiddenCallConv', 'nkConv', 
-    'nkCast', 'nkAddr', 'nkHiddenAddr', 'nkHiddenDeref', 
-    'nkObjDownConv', 'nkObjUpConv', 'nkChckRangeF', 'nkChckRange64', 
-    'nkChckRange', 'nkStringToCString', 'nkCStringToString', 'nkPassAsOpenArray', 
-    'nkAsgn', 'nkFastAsgn', 'nkDefaultTypeParam', 'nkGenericParams', 
-    'nkFormalParams', 'nkOfInherit', 'nkModule', 'nkProcDef', 
-    'nkConverterDef', 'nkMacroDef', 'nkTemplateDef', 'nkIteratorDef', 
-    'nkOfBranch', 'nkElifBranch', 'nkExceptBranch', 'nkElse', 
-    'nkMacroStmt', 'nkAsmStmt', 'nkPragma', 'nkIfStmt', 
-    'nkWhenStmt', 'nkForStmt', 'nkWhileStmt', 'nkCaseStmt', 
-    'nkVarSection', 'nkConstSection', 'nkConstDef', 'nkTypeSection', 
-    'nkTypeDef', 'nkYieldStmt', 'nkTryStmt', 'nkFinally', 
-    'nkRaiseStmt', 'nkReturnStmt', 'nkBreakStmt', 'nkContinueStmt', 
-    'nkBlockStmt', 'nkDiscardStmt', 'nkStmtList', 'nkImportStmt', 
-    'nkFromStmt', 'nkImportAs', 'nkIncludeStmt', 'nkCommentStmt', 
-    'nkStmtListExpr', 'nkBlockExpr', 'nkStmtListType', 'nkBlockType', 
-    'nkVm', 'nkTypeOfExpr', 'nkObjectTy', 'nkTupleTy', 
-    'nkRecList', 'nkRecCase', 'nkRecWhen', 'nkRefTy', 
-    'nkPtrTy', 'nkVarTy', 'nkAbstractTy', 'nkProcTy', 
-    'nkEnumTy', 'nkEnumFieldDef', 'nkReturnToken');
+    'nkAccQuoted', 'nkTableConstr', 'nkQualified', 'nkBind', 
+    'nkSymChoice', 'nkHiddenStdConv', 'nkHiddenSubConv', 'nkHiddenCallConv', 
+    'nkConv', 'nkCast', 'nkAddr', 'nkHiddenAddr', 
+    'nkHiddenDeref', 'nkObjDownConv', 'nkObjUpConv', 'nkChckRangeF', 
+    'nkChckRange64', 'nkChckRange', 'nkStringToCString', 'nkCStringToString', 
+    'nkPassAsOpenArray', 'nkAsgn', 'nkFastAsgn', 'nkDefaultTypeParam', 
+    'nkGenericParams', 'nkFormalParams', 'nkOfInherit', 'nkModule', 
+    'nkProcDef', 'nkConverterDef', 'nkMacroDef', 'nkTemplateDef', 
+    'nkIteratorDef', 'nkOfBranch', 'nkElifBranch', 'nkExceptBranch', 
+    'nkElse', 'nkMacroStmt', 'nkAsmStmt', 'nkPragma', 
+    'nkIfStmt', 'nkWhenStmt', 'nkForStmt', 'nkWhileStmt', 
+    'nkCaseStmt', 'nkVarSection', 'nkConstSection', 'nkConstDef', 
+    'nkTypeSection', 'nkTypeDef', 'nkYieldStmt', 'nkTryStmt', 
+    'nkFinally', 'nkRaiseStmt', 'nkReturnStmt', 'nkBreakStmt', 
+    'nkContinueStmt', 'nkBlockStmt', 'nkDiscardStmt', 'nkStmtList', 
+    'nkImportStmt', 'nkFromStmt', 'nkImportAs', 'nkIncludeStmt', 
+    'nkCommentStmt', 'nkStmtListExpr', 'nkBlockExpr', 'nkStmtListType', 
+    'nkBlockType', 'nkVm', 'nkTypeOfExpr', 'nkObjectTy', 
+    'nkTupleTy', 'nkRecList', 'nkRecCase', 'nkRecWhen', 
+    'nkRefTy', 'nkPtrTy', 'nkVarTy', 'nkAbstractTy', 
+    'nkProcTy', 'nkEnumTy', 'nkEnumFieldDef', 'nkReturnToken');
 type
   TSymFlag = (
     sfUsed, sfStar, sfMinus, sfInInterface, 
     sfFromGeneric, sfGlobal, sfForward, sfImportc, 
     sfExportc, sfVolatile, sfRegister, sfPure, 
-    sfResult, sfNoSideEffect, sfMainModule, sfSystemModule, 
-    sfNoReturn, sfAddrTaken, sfCompilerProc, sfCppMethod, 
-    sfDiscriminant, sfDeprecated, sfInClosure, sfTypeCheck, 
-    sfCompileTime, sfThreadVar, sfMerge, sfDeadCodeElim, 
-    sfBorrow);
+    sfResult, sfNoSideEffect, sfSideEffect, sfMainModule, 
+    sfSystemModule, sfNoReturn, sfAddrTaken, sfCompilerProc, 
+    sfCppMethod, sfDiscriminant, sfDeprecated, sfInClosure, 
+    sfTypeCheck, sfCompileTime, sfThreadVar, sfMerge, 
+    sfDeadCodeElim, sfBorrow);
   TSymFlags = set of TSymFlag;
 const
   SymFlagToStr: array [TSymFlag] of string = (
     'sfUsed', 'sfStar', 'sfMinus', 'sfInInterface', 
     'sfFromGeneric', 'sfGlobal', 'sfForward', 'sfImportc', 
     'sfExportc', 'sfVolatile', 'sfRegister', 'sfPure', 
-    'sfResult', 'sfNoSideEffect', 'sfMainModule', 'sfSystemModule', 
-    'sfNoReturn', 'sfAddrTaken', 'sfCompilerProc', 'sfCppMethod', 
-    'sfDiscriminant', 'sfDeprecated', 'sfInClosure', 'sfTypeCheck', 
-    'sfCompileTime', 'sfThreadVar', 'sfMerge', 'sfDeadCodeElim', 
-    'sfBorrow');
+    'sfResult', 'sfNoSideEffect', 'sfSideEffect', 'sfMainModule', 
+    'sfSystemModule', 'sfNoReturn', 'sfAddrTaken', 'sfCompilerProc', 
+    'sfCppMethod', 'sfDiscriminant', 'sfDeprecated', 'sfInClosure', 
+    'sfTypeCheck', 'sfCompileTime', 'sfThreadVar', 'sfMerge', 
+    'sfDeadCodeElim', 'sfBorrow');
 type
   TTypeKind = (
     tyNone, tyBool, tyChar, tyEmpty, 
@@ -189,11 +189,13 @@ const
     'nfAllConst', 'nfTransf', 'nfSem');
 type
   TTypeFlag = (
-    tfVarargs, tfFinal, tfAcyclic, tfEnumHasWholes);
+    tfVarargs, tfNoSideEffect, tfFinal, tfAcyclic, 
+    tfEnumHasWholes);
   TTypeFlags = set of TTypeFlag;
 const
   TypeFlagToStr: array [TTypeFlag] of string = (
-    'tfVarargs', 'tfFinal', 'tfAcyclic', 'tfEnumHasWholes');
+    'tfVarargs', 'tfNoSideEffect', 'tfFinal', 'tfAcyclic', 
+    'tfEnumHasWholes');
 type
   TSymKind = (
     skUnknownSym, skConditional, skDynLib, skParam, 
diff --git a/nim/ccgexprs.pas b/nim/ccgexprs.pas
index bf03365cd..212017d14 100644
--- a/nim/ccgexprs.pas
+++ b/nim/ccgexprs.pas
@@ -220,8 +220,7 @@ end;
 function addrLoc(const a: TLoc): PRope;
 begin
   result := a.r;
-  if not (lfIndirect in a.flags) then
-    result := con('&'+'', result)
+  if not (lfIndirect in a.flags) then result := con('&'+'', result)
 end;
 
 function rdCharLoc(const a: TLoc): PRope;
@@ -2257,32 +2256,6 @@ begin
 end;
 
 // ---------------------- generation of complex constants ---------------------
-(*
-function transformRecordExpr(n: PNode): PNode;
-var
-  i: int;
-  t: PType;
-  field: PSym;
-begin
-  result := copyNode(n);
-  newSons(result, sonsLen(n));
-  t := getUniqueType(skipTypes(n.Typ, abstractVarRange));
-  if t.n = nil then
-    InternalError(n.info, 'transformRecordExpr: invalid type');
-  for i := 0 to sonsLen(n)-1 do begin
-    assert(n.sons[i].kind = nkExprColonExpr);
-    assert(n.sons[i].sons[0].kind = nkSym);
-    field := n.sons[i].sons[0].sym;
-    field := lookupInRecord(t.n, field.name);
-    if field = nil then
-      InternalError(n.sons[i].info, 'transformRecordExpr: unknown field');
-    if result.sons[field.position] <> nil then begin
-      InternalError(n.sons[i].info, 'transformRecordExpr: value twice: ' +
-                    renderTree(n.sons[i]));
-    end;
-    result.sons[field.position] := copyTree(n.sons[i].sons[1]);
-  end;
-end; *)
 
 function genNamedConstExpr(p: BProc; n: PNode): PRope;
 begin
diff --git a/nim/docgen.pas b/nim/docgen.pas
index 5e8ecf7a3..a72f64908 100644
--- a/nim/docgen.pas
+++ b/nim/docgen.pas
@@ -139,16 +139,22 @@ function ropeFormatNamedVars(const frmt: TFormatStr;
                              const varnames: array of string;
                              const varvalues: array of PRope): PRope;
 var
-  i, j, L, start, idx: int;
+  i, j, L, start, idx, num: int;
   id: string;
 begin
   i := strStart;
   L := length(frmt);
   result := nil;
+  num := 0;
   while i <= L + StrStart - 1 do begin
     if frmt[i] = '$' then begin
       inc(i);                 // skip '$'
       case frmt[i] of
+        '#': begin
+          app(result, varvalues[num]);
+          inc(num);
+          inc(i);
+        end;
         '$': begin
           app(result, '$'+'');
           inc(i)
@@ -162,6 +168,7 @@ begin
           end;
           if j > high(varvalues) + 1 then
             internalError('ropeFormatNamedVars');
+          num := j;
           app(result, varvalues[j - 1])
         end;
         'A'..'Z', 'a'..'z', #128..#255: begin
@@ -515,17 +522,17 @@ begin
       result := renderRstSons(d, n);
       L := ropeLen(result);
       result := ropef('$n$1$2$n$1$3', [ind, result,
-                           toRope(repeatChar(L, lvlToChar[n.level]))]);
+                      toRope(repeatChar(L, lvlToChar[n.level]))]);
     end;
     rnOverline: begin
       result := renderRstSons(d, n);
       L := ropeLen(result);
       result := ropef('$n$1$3$n$1$2$n$1$3', [ind, result,
-                           toRope(repeatChar(L, lvlToChar[n.level]))]);
+                      toRope(repeatChar(L, lvlToChar[n.level]))]);
     end;
     rnTransition:
       result := ropef('$n$n$1$2$n$n',
-                          [ind, toRope(repeatChar(78-d.indent, '-'))]);
+                     [ind, toRope(repeatChar(78-d.indent, '-'))]);
     rnParagraph: begin
       result := renderRstSons(d, n);
       result := ropef('$n$n$1$2', [ind, result]);
@@ -1003,7 +1010,4 @@ begin
   generateIndex(d);
 end;
 
-// #FFD700
-// #9f9b75
-
 end.
diff --git a/nim/evals.pas b/nim/evals.pas
index 7c443bad6..d522dfaf0 100644
--- a/nim/evals.pas
+++ b/nim/evals.pas
@@ -35,8 +35,9 @@ type
   
   TEvalContext = object(passes.TPassContext)
     module: PSym;
-    tos: PStackFrame; // top of a tos tos
+    tos: PStackFrame; // top of stack
     lastException: PNode;
+    optEval: bool; // evaluation done for optimization purposes
   end;
   PEvalContext = ^TEvalContext;
 
@@ -44,12 +45,15 @@ function newStackFrame(): PStackFrame;
 procedure pushStackFrame(c: PEvalContext; t: PStackFrame);
 procedure popStackFrame(c: PEvalContext);
 
-function newEvalContext(module: PSym; const filename: string): PEvalContext;
+function newEvalContext(module: PSym; const filename: string;
+                        optEval: bool): PEvalContext;
 
 function eval(c: PEvalContext; n: PNode): PNode; 
 // eval never returns nil! This simplifies the code a lot and
 // makes it faster too.
 
+function evalConstExpr(module: PSym; e: PNode): PNode;
+
 function evalPass(): TPass;
 
 implementation
@@ -71,13 +75,15 @@ begin
 {@emit result.params := @[];}
 end;
 
-function newEvalContext(module: PSym; const filename: string): PEvalContext;
+function newEvalContext(module: PSym; const filename: string;
+                        optEval: bool): PEvalContext;
 begin
   new(result);
 {@ignore}
   fillChar(result^, sizeof(result^), 0);
 {@emit}
   result.module := module;
+  result.optEval := optEval;
 end;
 
 procedure pushStackFrame(c: PEvalContext; t: PStackFrame);
@@ -228,32 +234,35 @@ begin
   case result.kind of
     nkBreakStmt, nkReturnToken: begin end;
     nkExceptBranch: begin
-      // exception token!
-      exc := result;
-      i := 1;
-      len := sonsLen(n);
-      while (i < len) and (n.sons[i].kind = nkExceptBranch) do begin
-        blen := sonsLen(n.sons[i]);
-        if blen = 1 then begin
-          // general except section:
-          result := evalAux(c, n.sons[i].sons[0]);
-          exc := result;
-          break
-        end
-        else begin
-          for j := 0 to blen-2 do begin
-            assert(n.sons[i].sons[j].kind = nkType);
-            if exc.typ.id = n.sons[i].sons[j].typ.id then begin
-              result := evalAux(c, n.sons[i].sons[blen-1]);
-              exc := result;
-              break
-            end
+      if sonsLen(result) >= 1 then begin
+        // creating a nkExceptBranch without sons means that it could not be
+        // evaluated
+        exc := result;
+        i := 1;
+        len := sonsLen(n);
+        while (i < len) and (n.sons[i].kind = nkExceptBranch) do begin
+          blen := sonsLen(n.sons[i]);
+          if blen = 1 then begin
+            // general except section:
+            result := evalAux(c, n.sons[i].sons[0]);
+            exc := result;
+            break
           end
+          else begin
+            for j := 0 to blen-2 do begin
+              assert(n.sons[i].sons[j].kind = nkType);
+              if exc.typ.id = n.sons[i].sons[j].typ.id then begin
+                result := evalAux(c, n.sons[i].sons[blen-1]);
+                exc := result;
+                break
+              end
+            end
+          end;
+          inc(i);
         end;
-        inc(i);
-      end;
-      result := evalFinally(c, n, exc);
-    end;
+        result := evalFinally(c, n, exc);
+      end
+    end
     else
       result := evalFinally(c, n, emptyNode);
   end
@@ -339,6 +348,7 @@ begin
   if n.typ <> nil then d.params[0] := getNullValue(n.typ, n.info);
   pushStackFrame(c, d);
   result := evalAux(c, prc);
+  if result.kind = nkExceptBranch then exit;
   if n.typ <> nil then result := d.params[0];
   popStackFrame(c);
 end;
@@ -572,13 +582,24 @@ begin
   if result.intVal <> 0 then result := evalAux(c, n.sons[2])
 end;
 
+function evalNoOpt(c: PEvalContext; n: PNode): PNode;
+begin
+  result := newNodeI(nkExceptBranch, n.info);
+  // creating a nkExceptBranch without sons means that it could not be
+  // evaluated
+end;
+
 function evalNew(c: PEvalContext; n: PNode): PNode;
 var
   t: PType;
 begin
-  t := skipTypes(n.sons[1].typ, abstractVar);
-  result := newNodeIT(nkRefTy, n.info, t);
-  addSon(result, getNullValue(t.sons[0], n.info));
+  if c.optEval then 
+    result := evalNoOpt(c, n)
+  else begin
+    t := skipTypes(n.sons[1].typ, abstractVar);
+    result := newNodeIT(nkRefTy, n.info, t);
+    addSon(result, getNullValue(t.sons[0], n.info));
+  end
 end;
 
 function evalDeref(c: PEvalContext; n: PNode): PNode;
@@ -740,6 +761,7 @@ end;
 function evalSetLengthStr(c: PEvalContext; n: PNode): PNode;
 var
   a, b: PNode;
+  oldLen, newLen: int;
 begin
   result := evalAux(c, n.sons[1]);
   if result.kind = nkExceptBranch then exit;
@@ -748,7 +770,16 @@ begin
   if result.kind = nkExceptBranch then exit;
   b := result;
   case a.kind of
-    nkStrLit..nkTripleStrLit: setLength(a.strVal, int(getOrdValue(b)));
+    nkStrLit..nkTripleStrLit: begin
+    {@ignore}
+      oldLen := length(a.strVal);
+    {@emit}
+      newLen := int(getOrdValue(b));
+      setLength(a.strVal, newLen);
+    {@ignore}
+      FillChar(a.strVal[oldLen+1], newLen-oldLen, 0);
+    {@emit}
+    end
     else InternalError(n.info, 'evalSetLengthStr')
   end;
   result := emptyNode
@@ -1241,6 +1272,7 @@ end;
 function evalAux(c: PEvalContext; n: PNode): PNode;
 var
   i: int;
+  a: PNode;
 begin
   result := emptyNode;
   dec(gNestedEvals);
@@ -1254,13 +1286,22 @@ begin
     nkCall, nkHiddenCallConv, nkMacroStmt, nkCommand: 
       result := evalMagicOrCall(c, n);
     nkCurly, nkBracket, nkRange: begin
-      result := copyNode(n);
-      for i := 0 to sonsLen(n)-1 do addSon(result, evalAux(c, n.sons[i]));
+      a := copyNode(n);
+      for i := 0 to sonsLen(n)-1 do begin
+        result := evalAux(c, n.sons[i]);
+        if result.kind = nkExceptBranch then exit;        
+        addSon(a, result);
+      end;
+      result := a
     end;
     nkPar: begin
-      result := copyTree(n);
-      for i := 0 to sonsLen(n)-1 do
-        result.sons[i].sons[1] := evalAux(c, n.sons[i].sons[1]);
+      a := copyTree(n);
+      for i := 0 to sonsLen(n)-1 do begin
+        result := evalAux(c, n.sons[i].sons[1]);
+        if result.kind = nkExceptBranch then exit;
+        a.sons[i].sons[1] := result;
+      end;
+      result := a
     end;
     nkBracketExpr: result := evalArrayAccess(c, n);
     nkDotExpr: result := evalFieldAccess(c, n);
@@ -1313,15 +1354,30 @@ begin
   gWhileCounter := evalMaxIterations;
   gNestedEvals := evalMaxRecDepth;
   result := evalAux(c, n);
-  if result.kind = nkExceptBranch then
+  if (result.kind = nkExceptBranch) and (sonsLen(result) >= 1) then
     stackTrace(c, n, errUnhandledExceptionX, typeToString(result.typ));
 end;
 
+function evalConstExpr(module: PSym; e: PNode): PNode;
+var
+  p: PEvalContext;
+  s: PStackFrame;
+begin
+  p := newEvalContext(module, '', true);
+  s := newStackFrame();
+  s.call := e;
+  pushStackFrame(p, s);
+  result := eval(p, e);
+  if (result <> nil) and (result.kind = nkExceptBranch) then 
+    result := nil;
+  popStackFrame(p);
+end;
+
 function myOpen(module: PSym; const filename: string): PPassContext;
 var
   c: PEvalContext;
 begin
-  c := newEvalContext(module, filename);
+  c := newEvalContext(module, filename, false);
   pushStackFrame(c, newStackFrame());
   result := c;
 end;
diff --git a/nim/importer.pas b/nim/importer.pas
index 5c49259c2..fdb72fd4b 100644
--- a/nim/importer.pas
+++ b/nim/importer.pas
@@ -68,8 +68,8 @@ begin
   if (check <> nil) and (check.id <> copy.id) then begin
     if not (s.kind in OverloadableSyms) then begin
       // s and check need to be qualified:
-      IntSetIncl(c.AmbigiousSymbols, copy.id);
-      IntSetIncl(c.AmbigiousSymbols, check.id);
+      IntSetIncl(c.AmbiguousSymbols, copy.id);
+      IntSetIncl(c.AmbiguousSymbols, check.id);
     end
   end;
   StrTableAdd(c.tab.stack[importTablePos], copy);
diff --git a/nim/lookups.pas b/nim/lookups.pas
index a9a4a783b..d106ef302 100644
--- a/nim/lookups.pas
+++ b/nim/lookups.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -19,7 +19,8 @@ uses
 {$include 'config.inc'}
 
 type
-  TOverloadIterMode = (oimNoQualifier, oimSelfModule, oimOtherModule);
+  TOverloadIterMode = (oimDone, oimNoQualifier, oimSelfModule, oimOtherModule,
+                       oimSymChoice);
   TOverloadIter = record
     stackPtr: int;
     it: TIdentIter;
@@ -43,7 +44,7 @@ procedure addInterfaceOverloadableSymAt(c: PContext; sym: PSym; at: int);
 function lookUp(c: PContext; n: PNode): PSym;
 // Looks up a symbol. Generates an error in case of nil.
 
-function QualifiedLookUp(c: PContext; n: PNode; ambigiousCheck: bool): PSym;
+function QualifiedLookUp(c: PContext; n: PNode; ambiguousCheck: bool): PSym;
 
 function InitOverloadIter(out o: TOverloadIter; c: PContext; n: PNode): PSym;
 function nextOverloadIter(var o: TOverloadIter; c: PContext; n: PNode): PSym;
@@ -139,22 +140,22 @@ begin
       result := SymtabGet(c.Tab, n.sym.name);
       if result = nil then
         liMessage(n.info, errUndeclaredIdentifier, n.sym.name.s);
-      include(result.flags, sfUsed);
+      //include(result.flags, sfUsed);
     end;
     nkIdent: begin
       result := SymtabGet(c.Tab, n.ident);
       if result = nil then
         liMessage(n.info, errUndeclaredIdentifier, n.ident.s);
-      include(result.flags, sfUsed);
+      //include(result.flags, sfUsed);
     end
     else InternalError(n.info, 'lookUp');
   end;
-  if IntSetContains(c.AmbigiousSymbols, result.id) then
+  if IntSetContains(c.AmbiguousSymbols, result.id) then
     liMessage(n.info, errUseQualifier, result.name.s);
   if result.kind = skStub then loadStub(result);
 end;
 
-function QualifiedLookUp(c: PContext; n: PNode; ambigiousCheck: bool): PSym;
+function QualifiedLookUp(c: PContext; n: PNode; ambiguousCheck: bool): PSym;
 var
   m: PSym;
   ident: PIdent;
@@ -164,16 +165,16 @@ begin
       result := SymtabGet(c.Tab, n.ident);
       if result = nil then
         liMessage(n.info, errUndeclaredIdentifier, n.ident.s)
-      else if ambigiousCheck
-          and IntSetContains(c.AmbigiousSymbols, result.id) then
+      else if ambiguousCheck
+          and IntSetContains(c.AmbiguousSymbols, result.id) then
         liMessage(n.info, errUseQualifier, n.ident.s)
     end;
     nkSym: begin
       result := SymtabGet(c.Tab, n.sym.name);
       if result = nil then
         liMessage(n.info, errUndeclaredIdentifier, n.sym.name.s)
-      else if ambigiousCheck
-          and IntSetContains(c.AmbigiousSymbols, result.id) then
+      else if ambiguousCheck
+          and IntSetContains(c.AmbiguousSymbols, result.id) then
         liMessage(n.info, errUseQualifier, n.sym.name.s)
     end;
     nkDotExpr, nkQualified: begin
@@ -200,7 +201,7 @@ begin
                     renderTree(n.sons[1]));
       end
     end;
-    nkAccQuoted: result := QualifiedLookup(c, n.sons[0], ambigiousCheck);
+    nkAccQuoted: result := QualifiedLookup(c, n.sons[0], ambiguousCheck);
     else begin
       result := nil;
       //liMessage(n.info, errIdentifierExpected, '')
@@ -224,15 +225,18 @@ begin
         result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.ident);
       end;
     end;
-    nkSym: begin
+    nkSym: begin 
+      result := n.sym;
+      o.mode := oimDone;
+    (*
       o.stackPtr := c.tab.tos;
       o.mode := oimNoQualifier;
       while (result = nil) do begin
         dec(o.stackPtr);
         if o.stackPtr < 0 then break;
         result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.sym.name);
-      end;
-    end;
+      end; *)
+    end; 
     nkDotExpr, nkQualified: begin
       o.mode := oimOtherModule;
       o.m := qualifiedLookUp(c, n.sons[0], false);
@@ -258,6 +262,11 @@ begin
       end
     end;
     nkAccQuoted: result := InitOverloadIter(o, c, n.sons[0]);
+    nkSymChoice: begin
+      o.mode := oimSymChoice;
+      result := n.sons[0].sym;
+      o.stackPtr := 1
+    end;
     else begin end
   end;
   if (result <> nil) and (result.kind = skStub) then loadStub(result);
@@ -266,6 +275,7 @@ end;
 function nextOverloadIter(var o: TOverloadIter; c: PContext; n: PNode): PSym;
 begin
   case o.mode of
+    oimDone: result := nil;
     oimNoQualifier: begin
       if n.kind = nkAccQuoted then 
         result := nextOverloadIter(o, c, n.sons[0]) // BUGFIX
@@ -282,6 +292,14 @@ begin
     end;
     oimSelfModule:  result := nextIdentIter(o.it, c.tab.stack[ModuleTablePos]);
     oimOtherModule: result := nextIdentIter(o.it, o.m.tab);
+    oimSymChoice: begin
+      if o.stackPtr < sonsLen(n) then begin
+        result := n.sons[o.stackPtr].sym;
+        inc(o.stackPtr);
+      end
+      else
+        result := nil
+    end;
   end;
   if (result <> nil) and (result.kind = skStub) then loadStub(result);
 end;
diff --git a/nim/msgs.pas b/nim/msgs.pas
index 48ffc9ee5..0f47695af 100644
--- a/nim/msgs.pas
+++ b/nim/msgs.pas
@@ -1,7 +1,7 @@
 //

 //

 //           The Nimrod Compiler

-//        (c) Copyright 2008 Andreas Rumpf

+//        (c) Copyright 2009 Andreas Rumpf

 //

 //    See the file "copying.txt", included in this

 //    distribution, for details about the copyright.

@@ -79,19 +79,15 @@ type
     errNoneSpeedOrSizeExpected,
     errInvalidPragma,
     errUnknownPragma,
-    errPragmaXHereNotAllowed,
     errUnknownDirective,
     errInvalidDirective,
     errAtPopWithoutPush,
     errEmptyAsm,
-    errAsgnInvalidInExpr,
     errInvalidIndentation,
     errExceptionExpected,
     errExceptionAlreadyHandled,
-    errReturnNotAllowedHere,
     errYieldNotAllowedHere,
     errInvalidNumberOfYieldExpr,
-    errReturnInvalidInIterator,
     errCannotReturnExpr,
     errAttemptToRedefine,
     errStmtInvalidAfterReturn,
@@ -116,7 +112,6 @@ type
     errExprExpected,
     errUndeclaredIdentifier,
     errUseQualifier,
-    errTwiceForwarded,
     errTypeExpected,
     errSystemNeeds,
     errExecutionOfProgramFailed,
@@ -126,8 +121,7 @@ type
     errXExpectsTypeOrValue,
     errXExpectsArrayType,
     errIteratorCannotBeInstantiated,
-    errExprWithNoTypeCannotBeConverted,
-    errExprWithNoTypeCannotBeCasted,
+    errExprXAmbiguous,
     errConstantDivisionByZero,
     errOrdinalTypeExpected,
     errOrdinalOrFloatTypeExpected,
@@ -145,21 +139,17 @@ type
     errValueOutOfSetBounds,
     errFieldInitTwice,
     errFieldNotInit,
-    errExprCannotBeCalled,
+    errExprXCannotBeCalled,
     errExprHasNoType,
     errExprXHasNoType,
     errCastNotInSafeMode,
     errExprCannotBeCastedToX,
-    errUndefinedPrefixOpr,
     errCommaOrParRiExpected,
     errCurlyLeOrParLeExpected,
     errSectionExpected,
-    errImplemenationExpected,
     errRangeExpected,
-    errInvalidTypeDescription,
     errAttemptToRedefineX,
     errMagicOnlyInSystem,
-    errUnknownOperatorX,
     errPowerOfTwoExpected,
     errStringMayNotBeEmpty,
     errCallConvExpected,
@@ -193,9 +183,8 @@ type
     errTypeMismatch,
     errButExpected,
     errButExpectedX,
-    errAmbigiousCallXYZ,
+    errAmbiguousCallXYZ,
     errWrongNumberOfTypeParams,
-    errOutParamNoDefaultValue,
     errInlineProcHasNoAddress,
     errXCannotBeInParamDecl,
     errPragmaOnlyInHeaderOfProc,
@@ -204,21 +193,15 @@ type
     errNoSymbolToBorrowFromFound,
     errDiscardValue,
     errInvalidDiscard,
-    errUnknownPrecedence,
     errIllegalConvFromXtoY,
-    errTypeMismatchExpectedXGotY,
     errCannotBindXTwice,
     errInvalidOrderInEnumX,
     errEnumXHasWholes,
     errExceptExpected,
     errInvalidTry,
-    errEofExpectedButXFound,
     errOptionExpected,
-    errCannotEvaluateForwardConst,
     errXisNoLabel,
-    errXNeedsConcreteType,
     errNotAllCasesCovered,
-    errStringRange,
     errUnkownSubstitionVar,
     errComplexStmtRequiresInd,
     errXisNotCallable,
@@ -279,6 +262,7 @@ type
     errUnhandledExceptionX,
     errCyclicTree,
     errXisNoMacroOrTemplate,
+    errXhasSideEffects,
     errUser,
     warnCannotOpenFile,
     warnOctalEscape,
@@ -338,19 +322,15 @@ const
     '''none'', ''speed'' or ''size'' expected',
     'invalid pragma',
     'unknown pragma: ''$1''',
-    'pragma ''$1'' here not allowed',
     'unknown directive: ''$1''',
     'invalid directive',
     '''pop'' without a ''push'' pragma',
     'empty asm statement makes no sense',
-    '''='' invalid in an expression; probably ''=='' meant',
     'invalid indentation',
     'exception expected',
     'exception already handled',
-    '''return'' only allowed in routine',
     '''yield'' only allowed in a loop of an iterator',
     'invalid number of ''yield'' expresions',
-    '''return'' not allowed in iterator',
     'current routine cannot return an expression',
     'attempt to redefine ''$1''',
     'statement not allowed after ''return'', ''break'' or ''raise''',
@@ -374,19 +354,17 @@ const
     ''':'' or ''='' expected, but found ''$1''',
     'expression expected, but found ''$1''',
     'undeclared identifier: ''$1''',
-    'ambigious identifier: ''$1'' -- use a qualifier',
-    '''$1'' is forwarded twice',
+    'ambiguous identifier: ''$1'' -- use a qualifier',
     'type expected',
     'system module needs ''$1''',
     'execution of an external program failed',
-    'overloaded ''$1'' leads to ambigious calls',
+    'overloaded ''$1'' leads to ambiguous calls',
     'invalid argument for ''$1''',
     'statement has no effect',
     '''$1'' expects a type or value',
     '''$1'' expects an array type',
     '''$1'' cannot be instantiated because its body has not been compiled yet',
-    'expression with no type cannot be converted',
-    'expression with no type cannot be casted',
+    'expression ''$1'' ambiguous in this context',
     'constant division by zero',
     'ordinal type expected',
     'ordinal or float type expected',
@@ -404,21 +382,17 @@ const
     'value out of set bounds',
     'field initialized twice: ''$1''',
     'field ''$1'' not initialized',
-    'expression cannot be called',
+    'expression ''$1'' cannot be called',
     'expression has no type',
-    'expression ''$1'' has no type',
+    'expression ''$1'' has no type (or is ambiguous)',
     '''cast'' not allowed in safe mode',
     'expression cannot be casted to $1',
-    'undefined prefix operator: $1',
     ''','' or '')'' expected',
     '''{'' or ''('' expected',
     'section (''type'', ''proc'', etc.) expected',
-    '''implementation'' or end of file expected',
     'range expected',
-    'invalid type description',
     'attempt to redefine ''$1''',
     '''magic'' only allowed in system module',
-    'unkown operator: ''$1''',
     'power of two expected',
     'string literal may not be empty',
     'calling convention expected',
@@ -452,9 +426,8 @@ const
     'type mismatch: got (',
     'but expected one of: ',
     'but expected ''$1''',
-    'ambigious call; both $1 and $2 match for: $3',
+    'ambiguous call; both $1 and $2 match for: $3',
     'wrong number of type parameters',
-    'out parameters cannot have default values',
     'an inline proc has no address',
     '$1 cannot be declared in parameter declaration',
     'pragmas are only in the header of a proc allowed',
@@ -463,21 +436,15 @@ const
     'no symbol to borrow from found',
     'value returned by statement has to be discarded',
     'statement returns no value that can be discarded',
-    'unknown precedence for operator; use ''infix: prec'' pragma',
     'conversion from $1 to $2 is invalid',
-    'type mismatch: expected ''$1'', but got ''$2''',
     'cannot bind parameter ''$1'' twice',
     'invalid order in enum ''$1''',
     'enum ''$1'' has wholes',
     '''except'' or ''finally'' expected',
     'after catch all ''except'' or ''finally'' no section may follow',
-    'end of file expected, but found token ''$1''',
     'option expected, but found ''$1''',
-    'cannot evaluate forwarded constant',
     '''$1'' is not a label',
-    '''$1'' needs to be of a non-generic type',
     'not all cases are covered',
-    'string range in case statement not allowed',
     'unknown substitution variable: ''$1''',
     'complex statement requires indentation',
     '''$1'' is not callable',
@@ -489,7 +456,7 @@ const
     'no return type for $1 allowed',
     'a type conversion needs exactly one argument',
     'invalid pragma: $1',
-    '$1 here not allowed',
+    '$1 not allowed here',
     'invalid control flow: $1',
     'a type has no value',
     'invalid type: ''$1''',
@@ -499,11 +466,11 @@ const
     'invalid expression: ''$1''',
     'enum has no value ''$1''',
     'named expression expected',
-    'named expression here not allowed',
+    'named expression not allowed here',
     '''$1'' expects one type parameter',
     'array expects two type parameters',
     'invalid invisibility: ''$1''',
-    'initialization here not allowed',
+    'initialization not allowed here',
     '''$1'' cannot be assigned to',
     'iterators can only be defined at the module''s top level',
     'iterator needs an implementation',
@@ -538,6 +505,7 @@ const
     'unhandled exception: $1',
     'macro returned a cyclic abstract syntax tree',
     '''$1'' is no macro or template',
+    '''$1'' can have side effects',
     '$1',
     'cannot open ''$1'' [CannotOpenFile]',
     'octal escape sequences do not exist; leading zero is ignored [OctalEscape]',
diff --git a/nim/nimsets.pas b/nim/nimsets.pas
index 7fa3dbc12..9795817b8 100644
--- a/nim/nimsets.pas
+++ b/nim/nimsets.pas
@@ -1,15 +1,14 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
 //
 unit nimsets;
 
-// this unit handles Morpork sets; it implements symbolic sets
-// the code here should be reused in the Morpork standard library
+// this unit handles Nimrod sets; it implements symbolic sets
 
 interface
 
diff --git a/nim/pasparse.pas b/nim/pasparse.pas
index d0353fc86..73280aeca 100644
--- a/nim/pasparse.pas
+++ b/nim/pasparse.pas
@@ -40,12 +40,11 @@ const
   ImportBlackList: array [1..3] of string = (
     'nsystem', 'sysutils', 'charsets'
   );
-  stdReplacements: array [1..20] of TReplaceTuple = (
+  stdReplacements: array [1..19] of TReplaceTuple = (
     ('include',      'incl'),
     ('exclude',      'excl'),
     ('pchar',        'cstring'),
-    ('close',        'closeFile'),
-    ('assignfile',   'openFile'),
+    ('assignfile',   'open'),
     ('integer',      'int'),
     ('longword',     'int32'),
     ('cardinal',     'int'),
@@ -62,10 +61,12 @@ const
     ('len',          'length'),
     ('setlength',    'setlen')
   );
-  nimReplacements: array [1..30] of TReplaceTuple = (
+  nimReplacements: array [1..32] of TReplaceTuple = (
     ('nimread',      'read'),
     ('nimwrite',     'write'),
-    ('nimclosefile', 'closeFile'),
+    ('nimclosefile', 'close'),
+    ('closefile',    'close'),
+    ('openfile',     'open'),
     ('nsystem', 'system'),
     ('ntime', 'times'),
     ('nos', 'os'),
@@ -1972,7 +1973,7 @@ begin
         if isHandledDirective(p) then
           addSon(result, parseDirective(p))
         else
-          parMessage(p, errPragmaXHereNotAllowed, p.tok.ident.s)
+          parMessage(p, errXNotAllowedHere, p.tok.ident.s)
       end
       else addSon(result, parseStmt(p))
     end;
diff --git a/nim/pnimsyn.pas b/nim/pnimsyn.pas
index 51c0cd4f5..2ca411770 100644
--- a/nim/pnimsyn.pas
+++ b/nim/pnimsyn.pas
@@ -313,9 +313,8 @@ end;
 function accExpr(var p: TParser): PNode;
 var
   x, y: PNode;
-  info: TLineInfo;
 begin
-  info := parLineInfo(p);
+  result := newNodeP(nkAccQuoted, p);
   getTok(p); // skip `
   x := nil;
   y := nil;
@@ -343,16 +342,7 @@ begin
       end
     end;
   end;
-  if (p.tok.tokType = tkParLe) or (p.tok.tokType = tkColon) then begin
-    result := newNodeP(nkHeaderQuoted, p);
-    addSon(result, x);
-    addSon(result, parseParamList(p));
-  end
-  else begin
-    result := newNodeP(nkAccQuoted, p);
-    addSon(result, x);
-  end;
-  result.info := info;
+  addSon(result, x);
   eat(p, tkAccent);
 end;
 
@@ -665,6 +655,13 @@ begin
     optInd(p, a);
     addSon(result, primary(p));
     exit
+  end
+  else if p.tok.tokType = tkBind then begin
+    result := newNodeP(nkBind, p);
+    getTok(p);
+    optInd(p, result);
+    addSon(result, primary(p));
+    exit
   end;
   result := identOrLiteral(p);
   while true do begin
@@ -798,7 +795,7 @@ end;
 function isExprStart(const p: TParser): bool;
 begin
   case p.tok.tokType of
-    tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkLambda,
+    tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf, tkLambda, tkBind,
     tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit: result := true;
     else result := false;
   end;
diff --git a/nim/pragmas.pas b/nim/pragmas.pas
index 9f4a543c5..f81cdd6e2 100644
--- a/nim/pragmas.pas
+++ b/nim/pragmas.pas
@@ -499,7 +499,11 @@ begin
             // otherwise header would not make sense
             if sym.loc.r = nil then sym.loc.r := toRope(sym.name.s)
           end;
-          wNosideeffect: begin noVal(it); Include(sym.flags, sfNoSideEffect); end;
+          wNosideeffect: begin 
+            noVal(it); Include(sym.flags, sfNoSideEffect); 
+            if sym.typ <> nil then include(sym.typ.flags, tfNoSideEffect);
+          end;
+          wSideEffect: begin noVal(it); Include(sym.flags, sfSideEffect); end;
           wNoReturn: begin noVal(it); Include(sym.flags, sfNoReturn); end;
           wDynLib: processDynLib(c, it, sym);
           wCompilerProc: begin
@@ -597,7 +601,7 @@ end;
 procedure pragmaProc(c: PContext; s: PSym; n: PNode);
 begin
   pragma(c, s, n, {@set}[FirstCallConv..LastCallConv,
-    wImportc, wExportc, wNodecl, wMagic, wNosideEffect,
+    wImportc, wExportc, wNodecl, wMagic, wNosideEffect, wSideEffect,
     wNoreturn, wDynLib, wHeader, wCompilerProc, wPure,
     wCppMethod, wDeprecated, wVarargs, wCompileTime, wMerge,
     wBorrow]);
@@ -612,7 +616,8 @@ end;
 
 procedure pragmaIterator(c: PContext; s: PSym; n: PNode);
 begin
-  pragma(c, s, n, {@set}[FirstCallConv..LastCallConv,
+  pragma(c, s, n, {@set}[FirstCallConv..LastCallConv, 
+         wNosideEffect, wSideEffect,
          wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow]);
 end;
 
@@ -630,7 +635,7 @@ end;
 procedure pragmaLambda(c: PContext; s: PSym; n: PNode);
 begin
   pragma(c, s, n, {@set}[FirstCallConv..LastCallConv,
-    wImportc, wExportc, wNodecl, wNosideEffect,
+    wImportc, wExportc, wNodecl, wNosideEffect, wSideEffect, 
     wNoreturn, wDynLib, wHeader, wPure, wDeprecated]);
 end;
 
diff --git a/nim/rnimsyn.pas b/nim/rnimsyn.pas
index 5be10a0f3..0ed3cfcd7 100644
--- a/nim/rnimsyn.pas
+++ b/nim/rnimsyn.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -498,8 +498,10 @@ begin
     nkCommand: result := lsub(n.sons[0])+lcomma(n, 1)+1;
     nkExprEqExpr, nkDefaultTypeParam, nkAsgn, nkFastAsgn: result := lsons(n)+3;
     nkPar, nkCurly, nkBracket: result := lcomma(n)+2;
+    nkSymChoice: result := lsons(n) + length('()') + sonsLen(n)-1;
     nkTupleTy: result := lcomma(n)+length('tuple[]');
     nkQualified, nkDotExpr: result := lsons(n)+1;
+    nkBind: result := lsons(n)+length('bind_');
     nkCheckedFieldExpr: result := lsub(n.sons[0]);
     nkLambda: result := lsons(n)+length('lambda__=_');
     nkConstDef, nkIdentDefs: begin
@@ -531,7 +533,6 @@ begin
     nkDerefExpr:      result := lsub(n.sons[0])+2;
     nkImportAs:       result := lsons(n) + length('_as_');
     nkAccQuoted:      result := lsub(n.sons[0]) + 2;
-    nkHeaderQuoted:   result := lsub(n.sons[0]) + lsub(n.sons[1]) + 2;
 
     nkIfExpr:         result := lsub(n.sons[0].sons[0])+lsub(n.sons[0].sons[1])
                               + lsons(n, 1) + length('if_:_');
@@ -1023,6 +1024,14 @@ begin
       gcomma(g, n, 1);
       put(g, tkParRi, ')'+'');
     end;
+    nkSymChoice: begin
+      put(g, tkParLe, '('+'');
+      for i := 0 to sonsLen(n)-1 do begin
+        if i > 0 then put(g, tkOpr, '|'+'');
+        gsub(g, n.sons[i], c);
+      end;
+      put(g, tkParRi, ')'+'');      
+    end;
     nkPar: begin
       put(g, tkParLe, '('+'');
       gcomma(g, n, c);
@@ -1043,6 +1052,10 @@ begin
       put(g, tkDot, '.'+'');
       gsub(g, n.sons[1]);
     end;
+    nkBind: begin
+      putWithSpace(g, tkBind, 'bind');
+      gsub(g, n.sons[0]);
+    end;
     nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref: gsub(g, n.sons[0]);
     nkLambda: begin
       assert(n.sons[genericParamsPos] = nil);
@@ -1119,12 +1132,6 @@ begin
       gsub(g, n.sons[0]);
       put(g, tkAccent, '`'+'');
     end;
-    nkHeaderQuoted: begin
-      put(g, tkAccent, '`'+'');
-      gsub(g, n.sons[0]);
-      gsub(g, n.sons[1]);
-      put(g, tkAccent, '`'+'');
-    end;
     nkIfExpr: begin
       putWithSpace(g, tkIf, 'if');
       gsub(g, n.sons[0].sons[0]);
diff --git a/nim/ropes.pas b/nim/ropes.pas
index 6b6540c24..286f1b9e6 100644
--- a/nim/ropes.pas
+++ b/nim/ropes.pas
@@ -488,22 +488,25 @@ end;
 
 function ropef(const frmt: TFormatStr; const args: array of PRope): PRope;
 var
-  i, j, len, start: int;
+  i, j, len, start, num: int;
 begin
   i := strStart;
   len := length(frmt);
   result := nil;
+  num := 0;
   while i <= len + StrStart - 1 do begin
     if frmt[i] = '$' then begin
       inc(i); // skip '$'
       case frmt[i] of
         '$': begin app(result, '$'+''); inc(i); end;
+        '#': begin inc(i); app(result, args[num]); inc(num); end;
         '0'..'9': begin
           j := 0;
           repeat
             j := (j*10) + Ord(frmt[i]) - ord('0');
             inc(i);
           until (i > len + StrStart - 1) or not (frmt[i] in ['0'..'9']);
+          num := j;
           if j > high(args)+1 then
             internalError('ropes: invalid format string $' + toString(j));
           app(result, args[j-1]);
diff --git a/nim/scanner.pas b/nim/scanner.pas
index d1f32135c..edc9ca24a 100644
--- a/nim/scanner.pas
+++ b/nim/scanner.pas
@@ -53,10 +53,10 @@ type
     //cog.out(idents)
     //]]]
     tkAbstract, tkAddr, tkAnd, tkAs, 
-    tkAsm, tkBlock, tkBreak, tkCase, 
-    tkCast, tkConst, tkContinue, tkConverter, 
-    tkDiscard, tkDiv, tkElif, tkElse, 
-    tkEnd, tkEnum, tkExcept, tkException, 
+    tkAsm, tkBind, tkBlock, tkBreak, 
+    tkCase, tkCast, tkConst, tkContinue, 
+    tkConverter, tkDiscard, tkDiv, tkElif, 
+    tkElse, tkEnd, tkEnum, tkExcept, 
     tkFinally, tkFor, tkFrom, tkGeneric, 
     tkIf, tkImplies, tkImport, tkIn, 
     tkInclude, tkIs, tkIsnot, tkIterator, 
@@ -97,10 +97,10 @@ const
     //cog.out(strings)
     //]]]
     'abstract', 'addr', 'and', 'as', 
-    'asm', 'block', 'break', 'case', 
-    'cast', 'const', 'continue', 'converter', 
-    'discard', 'div', 'elif', 'else', 
-    'end', 'enum', 'except', 'exception', 
+    'asm', 'bind', 'block', 'break', 
+    'case', 'cast', 'const', 'continue', 
+    'converter', 'discard', 'div', 'elif', 
+    'else', 'end', 'enum', 'except', 
     'finally', 'for', 'from', 'generic', 
     'if', 'implies', 'import', 'in', 
     'include', 'is', 'isnot', 'iterator', 
diff --git a/nim/sem.pas b/nim/sem.pas
index c0826bdbe..1fd141f5a 100644
--- a/nim/sem.pas
+++ b/nim/sem.pas
@@ -90,8 +90,6 @@ end;
 function semAndEvalConstExpr(c: PContext; n: PNode): PNode;
 var
   e: PNode;
-  p: PEvalContext;
-  s: PStackFrame;
 begin
   e := semExprWithType(c, n);
   if e = nil then begin
@@ -101,12 +99,7 @@ begin
   result := getConstExpr(c.module, e);
   if result = nil then begin
     //writeln(output, renderTree(n));
-    p := newEvalContext(c.module, '');
-    s := newStackFrame();
-    s.call := e;
-    pushStackFrame(p, s);
-    result := eval(p, e);
-    popStackFrame(p);
+    result := evalConstExpr(c.module, e);
     if (result = nil) or (result.kind = nkEmpty) then
       liMessage(n.info, errConstExprExpected);
   end
@@ -135,7 +128,7 @@ var
   s: PStackFrame;
 begin
   include(sym.flags, sfUsed);
-  p := newEvalContext(c.module, '');
+  p := newEvalContext(c.module, '', false);
   s := newStackFrame();
   s.call := n;
   setLength(s.params, 2);
diff --git a/nim/semdata.pas b/nim/semdata.pas
index acca48376..acaffd3bf 100644
--- a/nim/semdata.pas
+++ b/nim/semdata.pas
@@ -45,7 +45,7 @@ type
     module: PSym;            // the module sym belonging to the context
     filename: string;        // the module's filename
     tab: TSymTab;            // each module has its own symbol table
-    AmbigiousSymbols: TIntSet; // contains ids of all ambigious symbols (cannot
+    AmbiguousSymbols: TIntSet; // contains ids of all ambiguous symbols (cannot
                                // store this info in the syms themselves!)
     generics: PNode;         // a list of the things to compile; list of
                              // nkExprEqExpr nodes which contain the generic
@@ -156,7 +156,7 @@ begin
   fillChar(result^, sizeof(result^), 0);
 {@emit}
   InitSymTab(result.tab);
-  IntSetInit(result.AmbigiousSymbols);
+  IntSetInit(result.AmbiguousSymbols);
   initLinkedList(result.optionStack);
   initLinkedList(result.libs);
   append(result.optionStack, newOptionEntry());
diff --git a/nim/semexprs.pas b/nim/semexprs.pas
index 74cd44b3d..de37295b7 100644
--- a/nim/semexprs.pas
+++ b/nim/semexprs.pas
@@ -1,6 +1,6 @@
 //
 //
-//           The Ethexor Morpork Compiler
+//           The Nimrod Compiler
 //        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
@@ -110,18 +110,33 @@ begin
 end;
 
 function semConv(c: PContext; n: PNode; s: PSym): PNode;
+var
+  op: PNode;
+  i: int;
 begin
   if sonsLen(n) <> 2 then liMessage(n.info, errConvNeedsOneArg);
   result := newNodeI(nkConv, n.info);
   result.typ := semTypeNode(c, n.sons[0], nil);
   addSon(result, copyTree(n.sons[0]));
   addSon(result, semExprWithType(c, n.sons[1]));
-  checkConvertible(result.info, result.typ, result.sons[1].typ);
+  op := result.sons[1];
+  if op.kind <> nkSymChoice then 
+    checkConvertible(result.info, result.typ, op.typ)
+  else begin
+    for i := 0 to sonsLen(op)-1 do begin
+      if sameType(result.typ, op.sons[i].typ) then begin
+        include(op.sons[i].sym.flags, sfUsed);
+        result := op.sons[i]; exit
+      end
+    end;
+    liMessage(n.info, errUseQualifier, op.sons[0].sym.name.s);
+  end
 end;
 
 function semCast(c: PContext; n: PNode): PNode;
 begin
   if optSafeCode in gGlobalOptions then liMessage(n.info, errCastNotInSafeMode);
+  include(c.p.owner.flags, sfSideEffect);
   checkSonsLen(n, 2);
   result := newNodeI(nkCast, n.info);
   result.typ := semTypeNode(c, n.sons[0], nil);
@@ -354,7 +369,7 @@ function isAssignable(n: PNode): bool;
 begin
   result := false;
   case n.kind of
-    nkSym: result := n.sym.kind in [skVar, skTemp];
+    nkSym: result := (n.sym.kind in [skVar, skTemp]);
     nkDotExpr, nkQualified, nkBracketExpr: begin
       checkMinSonsLen(n, 1);
       if skipTypes(n.sons[0].typ, abstractInst).kind in [tyVar, tyPtr, tyRef] then
@@ -373,7 +388,7 @@ begin
     nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
       result := isAssignable(n.sons[0]);
     else begin end
-  end
+  end;
 end;
 
 function newHiddenAddrTaken(c: PContext; n: PNode): PNode;
@@ -442,13 +457,31 @@ begin
       n.sons[i] := analyseIfAddressTaken(c, n.sons[i]);
 end;
 
+function semDirectCallAnalyseEffects(c: PContext; n: PNode): PNode;
+var
+  callee: PSym;
+begin
+  result := semDirectCall(c, n);
+  if result <> nil then begin
+    if result.sons[0].kind <> nkSym then 
+      InternalError('semDirectCallAnalyseEffects');
+    callee := result.sons[0].sym;
+    if not (sfNoSideEffect in callee.flags) then 
+      if (sfForward in callee.flags) 
+      or ([sfImportc, sfSideEffect] * callee.flags <> []) then 
+        include(c.p.owner.flags, sfSideEffect);
+  end
+end;
+
 function semIndirectOp(c: PContext; n: PNode): PNode;
 var
   m: TCandidate;
   msg: string;
   i: int;
+  prc: PNode;
 begin
   result := nil;
+  prc := n.sons[0];
   checkMinSonsLen(n, 1);
   case n.sons[0].kind of
     nkDotExpr, nkQualified: begin
@@ -457,8 +490,7 @@ begin
       if n.sons[0].kind = nkDotCall then begin // it is a static call!
         result := n.sons[0];
         result.kind := nkCall;
-        for i := 1 to sonsLen(n)-1 do
-          addSon(result, n.sons[i]);
+        for i := 1 to sonsLen(n)-1 do addSon(result, n.sons[i]);
         result := semExpr(c, result);
         exit
       end
@@ -475,8 +507,8 @@ begin
     if m.state <> csMatch then begin
       msg := msgKindToString(errTypeMismatch);
       for i := 1 to sonsLen(n)-1 do begin
+        if i > 1 then add(msg, ', ');
         add(msg, typeToString(n.sons[i].typ));
-        if i <> sonsLen(n)-1 then add(msg, ', ');
       end;
       add(msg, ')' +{&} nl +{&} msgKindToString(errButExpected) +{&}
              nl +{&} typeToString(n.sons[0].typ));
@@ -485,11 +517,21 @@ begin
     end
     else
       result := m.call;
+    // we assume that a procedure that calls something indirectly 
+    // has side-effects:
+    include(c.p.owner.flags, sfSideEffect);
   end
   else begin
     result := overloadedCallOpr(c, n);
-    if result = nil then result := semDirectCall(c, n);
-    if result = nil then liMessage(n.info, errExprCannotBeCalled);
+    // Now that nkSym does not imply an iteration over the proc/iterator space,
+    // the old ``prc`` (which is likely an nkIdent) has to be restored:
+    if result = nil then begin
+      n.sons[0] := prc;
+      result := semDirectCallAnalyseEffects(c, n);
+    end;
+    if result = nil then 
+      liMessage(n.info, errExprXCannotBeCalled, 
+                renderTree(n, {@set}[renderNoComments]));
   end;
   fixAbstractType(c, result);
   analyseIfAddressTakenInCall(c, result);
@@ -499,7 +541,7 @@ function semDirectOp(c: PContext; n: PNode): PNode;
 begin
   // this seems to be a hotspot in the compiler!
   semOpAux(c, n);
-  result := semDirectCall(c, n);
+  result := semDirectCallAnalyseEffects(c, n);
   if result = nil then begin
     result := overloadedCallOpr(c, n);
     if result = nil then
@@ -508,45 +550,6 @@ begin
   fixAbstractType(c, result);
   analyseIfAddressTakenInCall(c, result);
 end;
-(*
-function semIncSucc(c: PContext; n: PNode; const opr: string): PNode;
-// handles Inc, Dec, Succ and Pred
-var
-  a: PNode;
-  typ: PType;
-begin
-  checkMinSonsLen(n, 2);
-  n.sons[1] := semExprWithType(c, n.sons[1]);
-  typ := skipTypes(n.sons[1].Typ, {@set}[tyGenericInst, tyVar]);
-  if not isOrdinalType(typ) or enumHasWholes(typ) then
-    liMessage(n.sons[1].Info, errOrdinalTypeExpected);
-  if sonsLen(n) = 3 then begin
-    n.sons[2] := semExprWithType(c, n.sons[2]);
-    a := IndexTypesMatch(c, getSysType(tyInt), n.sons[2].typ, n.sons[2]);
-    if a = nil then
-      typeMismatch(n.sons[2], getSysType(tyInt), n.sons[2].typ);
-    n.sons[2] := a;
-  end
-  else if sonsLen(n) = 2 then begin // default value of 1
-    a := newIntNode(nkIntLit, 1);
-    a.info := n.info;
-    a.typ := getSysType(tyInt);
-    addSon(n, a)
-  end
-  else
-    liMessage(n.info, errInvalidArgForX, opr);
-  result := n;
-end;
-
-function semOrd(c: PContext; n: PNode): PNode;
-begin
-  checkSonsLen(n, 2);
-  n.sons[1] := semExprWithType(c, n.sons[1]);
-  if not isOrdinalType(skipTypes(n.sons[1].Typ, {@set}[tyGenericInst, tyVar])) then
-    liMessage(n.Info, errOrdinalTypeExpected);
-  n.typ := getSysType(tyInt);
-  result := n
-end; *)
 
 function semEcho(c: PContext; n: PNode): PNode;
 var
@@ -632,18 +635,6 @@ begin
     mSizeOf:  result := semSizeof(c, setMs(n, s));
     mIs:      result := semIs(c, setMs(n, s));
     mEcho:    result := semEcho(c, setMs(n, s)); 
-    (*
-    mSucc:    begin
-      result := semIncSucc(c, setMs(n, s), 'succ');
-      result.typ := n.sons[1].typ;
-    end;
-    mPred:    begin
-      result := semIncSucc(c, setMs(n, s), 'pred');
-      result.typ := n.sons[1].typ;
-    end;
-    mInc:     result := semIncSucc(c, setMs(n, s), 'inc');
-    ast.mDec: result := semIncSucc(c, setMs(n, s), 'dec');
-    mOrd:     result := semOrd(c, setMs(n, s)); *)
     else      result := semDirectOp(c, n);
   end;
 end;
@@ -655,16 +646,14 @@ end;
 
 function semSym(c: PContext; n: PNode; s: PSym; flags: TExprFlags): PNode;
 begin
-  result := newSymNode(s);
-  result.info := n.info;
-  result.typ := s.typ;
-  include(s.flags, sfUsed);
   if (s.kind = skType) and not (efAllowType in flags) then
     liMessage(n.info, errATypeHasNoValue);
   case s.kind of
-    skProc, skIterator, skConverter:
+    skProc, skIterator, skConverter: begin
       if (s.magic <> mNone) then
         liMessage(n.info, errInvalidContextForBuiltinX, s.name.s);
+      result := symChoice(c, n, s);
+    end;
     skConst: begin
       (*
         Consider::
@@ -678,20 +667,40 @@ begin
         copy `x`'s AST into each context, so that the type fixup phase can
         deal with two different ``[]``.
       *)
+      include(s.flags, sfUsed);
       if s.typ.kind in ConstAbstractTypes then begin
         result := copyTree(s.ast);
         result.info := n.info;
         result.typ := s.typ;
       end
+      else begin
+        result := newSymNode(s);
+        result.info := n.info;      
+      end
+    end;
+    skMacro: begin
+      include(s.flags, sfUsed);
+      result := semMacroExpr(c, n, s);
     end;
-    skMacro: result := semMacroExpr(c, n, s);
     skTemplate: begin
+      include(s.flags, sfUsed);
       // Templates and macros can be invoked without ``()``
       pushInfoContext(n.info);
       result := evalTemplate(c, n, s);
       popInfoContext();
     end;
-    else begin end
+    skVar: begin
+      include(s.flags, sfUsed);
+      // if a proc accesses a global variable, it is not side effect free
+      if sfGlobal in s.flags then include(c.p.owner.flags, sfSideEffect);
+      result := newSymNode(s);
+      result.info := n.info;  
+    end;
+    else begin
+      include(s.flags, sfUsed);
+      result := newSymNode(s);
+      result.info := n.info;
+    end
   end;
   checkDeprecated(n, s);
 end;
@@ -1266,6 +1275,7 @@ begin
         result := semExpr(c, result, flags)
       end;
     end;
+    nkBind: result := semExpr(c, n.sons[0], flags);
     nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand: begin
       // check if it is an expression macro:
       checkMinSonsLen(n, 1);
@@ -1326,11 +1336,7 @@ begin
     end;
     nkCurly: result := semSetConstr(c, n);
     nkBracket: result := semArrayConstr(c, n);
-    nkLambda: result := semLambda(c, n); // handled in semstmts
-    nkExprColonExpr: begin
-      internalError(n.info, 'semExpr() to implement');
-      // XXX: to implement for array constructors!
-    end;
+    nkLambda: result := semLambda(c, n);
     nkDerefExpr: begin
       checkSonsLen(n, 1);
       n.sons[0] := semExprWithType(c, n.sons[0]);
@@ -1357,11 +1363,6 @@ begin
       checkSonsLen(n, 1);
       result := semExpr(c, n.sons[0]);
     end;
-    nkHeaderQuoted: begin
-      // look up the proc:
-      internalError(n.info, 'semExpr() to implement');
-      // XXX: to implement
-    end;
     nkIfExpr: result := semIfExpr(c, n);
     nkStmtListExpr: result := semStmtListExpr(c, n);
     nkBlockExpr: result := semBlockExpr(c, n);
@@ -1374,6 +1375,11 @@ begin
       checkSonsLen(n, 3);
     nkCheckedFieldExpr:
       checkMinSonsLen(n, 2);
+    nkSymChoice: begin
+      liMessage(n.info, errExprXAmbiguous,
+                renderTree(n, {@set}[renderNoComments]));
+      result := nil
+    end
     else begin
       //InternalError(n.info, nodeKindToStr[n.kind]);
       liMessage(n.info, errInvalidExpressionX,
diff --git a/nim/semstmts.pas b/nim/semstmts.pas
index c8b942df8..686ff775d 100644
--- a/nim/semstmts.pas
+++ b/nim/semstmts.pas
@@ -257,7 +257,7 @@ begin
       addSon(result, newIdentNode(getIdent(id.s+'='), n.info));
       addSon(result, semExpr(c, a.sons[0]));
       addSon(result, semExpr(c, n.sons[1]));
-      result := semDirectCall(c, result);
+      result := semDirectCallAnalyseEffects(c, result);
       if result <> nil then begin
         fixAbstractType(c, result);
         analyseIfAddressTakenInCall(c, result);
@@ -277,7 +277,7 @@ begin
         addSonIfNotNil(result, semExpr(c, a.sons[1].sons[0]));
         addSonIfNotNil(result, semExpr(c, a.sons[1].sons[1]));
         addSon(result, semExpr(c, n.sons[1]));
-        result := semDirectCall(c, result);
+        result := semDirectCallAnalyseEffects(c, result);
         if result <> nil then begin
           fixAbstractType(c, result);
           analyseIfAddressTakenInCall(c, result);
@@ -289,7 +289,7 @@ begin
         addSon(result, semExpr(c, a.sons[0]));
         addSon(result, semExpr(c, a.sons[1]));
         addSon(result, semExpr(c, n.sons[1]));
-        result := semDirectCall(c, result);
+        result := semDirectCallAnalyseEffects(c, result);
         if result <> nil then begin
           fixAbstractType(c, result);
           analyseIfAddressTakenInCall(c, result);
@@ -322,7 +322,7 @@ begin
   result := n;
   checkSonsLen(n, 1);
   if not (c.p.owner.kind in [skConverter, skProc, skMacro]) then
-    liMessage(n.info, errReturnNotAllowedHere);
+    liMessage(n.info, errXNotAllowedHere, '''return''');
   if (n.sons[0] <> nil) then begin
     n.sons[0] := SemExprWithType(c, n.sons[0]);
     // check for type compatibility:
@@ -624,9 +624,28 @@ begin
   end
 end;
 
-function resolveGenericParams(c: PContext; n: PNode): PNode;
+function resolveGenericParams(c: PContext; n: PNode; 
+                              withinBind: bool = false): PNode;
+var
+  i: int;
+  s: PSym;
 begin
-  result := n;
+  if n = nil then begin result := nil; exit end;
+  case n.kind of
+    nkIdent: begin
+      if not withinBind then 
+        result := n
+      else
+        result := symChoice(c, n, lookup(c, n))
+    end;
+    nkSym..nkNilLit: result := n;
+    nkBind: result := resolveGenericParams(c, n.sons[0], true);
+    else begin
+      result := n;
+      for i := 0 to sonsLen(n)-1 do
+        result.sons[i] := resolveGenericParams(c, n.sons[i], withinBind);
+    end
+  end
 end;
 
 function SemTypeSection(c: PContext; n: PNode): PNode;
@@ -682,7 +701,7 @@ begin
       addSon(s.typ, nil);
       // process the type body for symbol lookup of generic params
       // we can use the same algorithm as for template parameters:
-      a.sons[2] := resolveTemplateParams(c, a.sons[2]);
+      a.sons[2] := resolveTemplateParams(c, a.sons[2], false);
       s.ast := a;
       if s.typ.containerID <> 0 then
         InternalError(a.info, 'semTypeSection: containerID');
@@ -754,6 +773,13 @@ begin
   n.sons[codePos] := newSymNode(b);
 end;
 
+procedure sideEffectsCheck(c: PContext; s: PSym);
+begin
+  if [sfNoSideEffect, sfSideEffect] * s.flags = 
+     [sfNoSideEffect, sfSideEffect] then 
+    liMessage(s.info, errXhasSideEffects, s.name.s);
+end;
+
 function semIterator(c: PContext; n: PNode): PNode;
 var
   s: PSym;
@@ -972,6 +998,7 @@ begin
     else if sfBorrow in s.flags then 
       semBorrow(c, n, s);
   end;
+  sideEffectsCheck(c, s);
   closeScope(c.tab); // close scope for parameters
   popOwner();
   c.p := oldP; // restore
diff --git a/nim/semtempl.pas b/nim/semtempl.pas
index ebc5e1ebb..b8107095f 100644
--- a/nim/semtempl.pas
+++ b/nim/semtempl.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -90,7 +90,37 @@ begin
   dec(evalTemplateCounter);
 end;
 
-function resolveTemplateParams(c: PContext; n: PNode): PNode;
+function symChoice(c: PContext; n: PNode; s: PSym): PNode;
+var
+  a: PSym;
+  o: TOverloadIter;
+  i: int;
+begin
+  i := 0;
+  a := initOverloadIter(o, c, n);
+  while a <> nil do begin
+    a := nextOverloadIter(o, c, n);
+    inc(i);
+  end;
+  if i <= 1 then begin
+    result := newSymNode(s);
+    result.info := n.info;
+    include(s.flags, sfUsed);
+  end
+  else begin
+    // semantic checking requires a type; ``fitNode`` deal with it
+    // appropriately
+    result := newNodeIT(nkSymChoice, n.info, newTypeS(tyNone, c));
+    a := initOverloadIter(o, c, n);
+    while a <> nil do begin
+      addSon(result, newSymNode(a));
+      a := nextOverloadIter(o, c, n);
+    end
+  end
+end;
+
+function resolveTemplateParams(c: PContext; n: PNode; 
+                               withinBind: bool): PNode;
 var
   i: int;
   s: PSym;
@@ -98,20 +128,27 @@ begin
   if n = nil then begin result := nil; exit end;
   case n.kind of
     nkIdent: begin
-      s := SymTabLocalGet(c.Tab, n.ident);
-      if (s <> nil) then begin
-        result := newSymNode(s);
-        result.info := n.info
+      if not withinBind then begin
+        s := SymTabLocalGet(c.Tab, n.ident);
+        if (s <> nil) then begin
+          result := newSymNode(s);
+          result.info := n.info
+        end
+        else
+          result := n
+      end
+      else begin
+        result := symChoice(c, n, lookup(c, n))
       end
-      else
-        result := n
     end;
     nkSym..nkNilLit: // atom
       result := n;
+    nkBind: 
+      result := resolveTemplateParams(c, n.sons[0], true);
     else begin
       result := n;
       for i := 0 to sonsLen(n)-1 do
-        result.sons[i] := resolveTemplateParams(c, n.sons[i]);
+        result.sons[i] := resolveTemplateParams(c, n.sons[i], withinBind);
     end
   end
 end;
@@ -200,7 +237,7 @@ begin
   if n.sons[genericParamsPos] <> nil then
     liMessage(n.info, errNoGenericParamsAllowedForX, 'template');
   // resolve parameters:
-  n.sons[codePos] := resolveTemplateParams(c, n.sons[codePos]);
+  n.sons[codePos] := resolveTemplateParams(c, n.sons[codePos], false);
   if params.sons[0].ident.id = ord(wExpr) then
     n.sons[codePos] := transformToExpr(n.sons[codePos]);
 
diff --git a/nim/sigmatch.pas b/nim/sigmatch.pas
index d95745e0c..ccd05d413 100644
--- a/nim/sigmatch.pas
+++ b/nim/sigmatch.pas
@@ -46,6 +46,21 @@ begin
   assert(c.callee <> nil);
 end;
 
+procedure copyCandidate(var a: TCandidate; const b: TCandidate);
+begin
+  a.exactMatches := b.exactMatches;
+  a.subtypeMatches := b.subtypeMatches;
+  a.convMatches := b.convMatches;
+  a.intConvMatches := b.intConvMatches;
+  a.genericMatches := b.genericMatches;
+  a.state := b.state;
+  a.callee := b.callee;
+  a.calleeSym := b.calleeSym;
+  a.call := copyTree(b.call);
+  a.baseTypeMatch := b.baseTypeMatch;
+  copyIdTable(a.bindings, b.bindings);
+end;
+
 function cmpCandidates(const a, b: TCandidate): int;
 begin
   result := a.exactMatches - b.exactMatches;
@@ -552,8 +567,8 @@ begin
   end
 end;
 
-function ParamTypesMatch(c: PContext; var m: TCandidate; f, a: PType;
-                         arg: PNode): PNode;
+function ParamTypesMatchAux(c: PContext; var m: TCandidate; f, a: PType;
+                            arg: PNode): PNode;
 var
   r: TTypeRelation;
 begin
@@ -608,6 +623,57 @@ begin
   end
 end;
 
+function ParamTypesMatch(c: PContext; var m: TCandidate; f, a: PType;
+                         arg: PNode): PNode;
+var
+  i, cmp, best: int;
+  x, y, z: TCandidate;
+  r: TTypeRelation;
+begin
+  if (arg = nil) or (arg.kind <> nkSymChoice) then
+    result := ParamTypesMatchAux(c, m, f, a, arg)
+  else begin
+    // CAUTION: The order depends on the used hashing scheme. Thus it is
+    // incorrect to simply use the first fitting match. However, to implement
+    // this correctly is inefficient. We have to copy `m` here to be able to
+    // roll back the side effects of the unification algorithm.
+    initCandidate(x, m.callee);
+    initCandidate(y, m.callee);
+    initCandidate(z, m.callee);
+    x.calleeSym := m.calleeSym;
+    y.calleeSym := m.calleeSym;
+    z.calleeSym := m.calleeSym;
+    best := -1;
+    for i := 0 to sonsLen(arg)-1 do begin
+      copyCandidate(z, m);
+      r := typeRel(z.bindings, f, arg.sons[i].typ);
+      if r <> isNone then begin
+        case x.state of
+          csEmpty, csNoMatch: begin x := z; best := i; x.state := csMatch; end;
+          csMatch: begin
+            cmp := cmpCandidates(x, z);
+            if cmp < 0 then begin best := i; x := z end // z is better than x
+            else if cmp = 0 then y := z // z is as good as x
+            else begin end // z is worse than x
+          end
+        end
+      end
+    end;
+    if x.state = csEmpty then 
+      result := nil
+    else if (y.state = csMatch) and (cmpCandidates(x, y) = 0) then begin
+      if x.state <> csMatch then InternalError(arg.info, 'x.state is not csMatch');
+      // ambiguous: more than one symbol fits
+      result := nil
+    end
+    else begin
+      // only one valid interpretation found:
+      include(arg.sons[best].sym.flags, sfUsed);
+      result := ParamTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best]);
+    end
+  end
+end;
+
 function IndexTypesMatch(c: PContext; f, a: PType; arg: PNode): PNode;
 var
   m: TCandidate;
@@ -796,7 +862,7 @@ begin
     //writeMatches(x);
     //writeMatches(y);
     liMessage(n.Info, errGenerated,
-      format(msgKindToString(errAmbigiousCallXYZ),
+      format(msgKindToString(errAmbiguousCallXYZ),
         [getProcHeader(x.calleeSym),
         getProcHeader(y.calleeSym), x.calleeSym.Name.s]))
   end
diff --git a/nim/strutils.pas b/nim/strutils.pas
index 377d3abc6..f34379fcb 100644
--- a/nim/strutils.pas
+++ b/nim/strutils.pas
@@ -502,18 +502,25 @@ procedure addf(var result: string; const f: string; args: array of string);
 const
   PatternChars = ['a'..'z', 'A'..'Z', '0'..'9', '_', #128..#255];
 var
-  i, j, x: int;
+  i, j, x, num: int;
 begin
   i := 1;
+  num := 0;
   while i <= length(f) do
     if f[i] = '$' then begin
       case f[i+1] of
+        '#': begin
+          inc(i, 2);
+          add(result, args[num]);
+          inc(num);
+        end;
         '$': begin
           addChar(result, '$');
           inc(i, 2);
         end;
         '1'..'9': begin
-          add(result, args[ord(f[i+1]) - ord('0') - 1]);
+          num := ord(f[i+1]) - ord('0');
+          add(result, args[num - 1]);
           inc(i, 2);
         end;
         '{': begin
diff --git a/nim/transf.pas b/nim/transf.pas
index b1812d52c..3e3b2a611 100644
--- a/nim/transf.pas
+++ b/nim/transf.pas
@@ -15,6 +15,7 @@ unit transf;
 // * inlines constants
 // * performes contant folding
 // * introduces nkHiddenDeref, nkHiddenSubConv, etc.
+// * aggressive compile-time evaluation based on the side-effect analysis
 
 interface
 
@@ -22,7 +23,7 @@ interface
 
 uses
   sysutils, nsystem, charsets, strutils,
-  lists, options, ast, astalgo, trees, treetab, 
+  lists, options, ast, astalgo, trees, treetab, evals,
   msgs, nos, idents, rnimsyn, types, passes, semfold, magicsys;
 
 const
@@ -822,7 +823,24 @@ begin
     end;
     if sonsLen(result) = 2 then
       result := result.sons[1];
-  end;
+  end
+  (*
+  else if result.sons[0].kind = nkSym then begin
+    // optimization still too aggressive
+    op := result.sons[0].sym;
+    if (op.magic = mNone) and (op.kind = skProc) 
+    and ([sfSideEffect, sfForward, sfNoReturn, sfImportc] * op.flags = [])
+    then begin
+      for i := 1 to sonsLen(result)-1 do
+        if not isConstExpr(result.sons[i]) then exit;
+      // compile-time evaluation:
+      a := evalConstExpr(c.module, result);
+      if (a <> nil) and (a.kind <> nkEmpty) then begin
+        messageout('evaluated at compile time: ' + rendertree(result));
+        result := a
+      end
+    end
+  end *)
 end;
 
 function transform(c: PTransf; n: PNode): PNode;
diff --git a/nim/types.pas b/nim/types.pas
index b4558fe82..d2aee2413 100644
--- a/nim/types.pas
+++ b/nim/types.pas
@@ -65,16 +65,6 @@ function equalParams(a, b: PNode): TParamsEquality;
 function isOrdinalType(t: PType): Boolean;
 function enumHasWholes(t: PType): Boolean;
 
-(*
-function skipRange(t: PType): PType;
-function skipGeneric(t: PType): PType;
-function skipGenericRange(t: PType): PType;
-function skipVar(t: PType): PType;
-function skipVarGeneric(t: PType): PType;
-function skipVarGenericRange(t: PType): PType;
-function skipPtrsGeneric(t: PType): PType;
-*)
-
 const
   abstractPtrs = {@set}[tyVar, tyPtr, tyRef, tyGenericInst, tyAbstract, tyOrdinal];
   abstractVar = {@set}[tyVar, tyGenericInst, tyAbstract, tyOrdinal];
diff --git a/nim/wordrecg.pas b/nim/wordrecg.pas
index cd31a64e4..1f4513ed5 100644
--- a/nim/wordrecg.pas
+++ b/nim/wordrecg.pas
@@ -40,10 +40,10 @@ type
     //cog.out(idents)
     //]]]
     wAbstract, wAddr, wAnd, wAs, 
-    wAsm, wBlock, wBreak, wCase, 
-    wCast, wConst, wContinue, wConverter, 
-    wDiscard, wDiv, wElif, wElse, 
-    wEnd, wEnum, wExcept, wException, 
+    wAsm, wBind, wBlock, wBreak, 
+    wCase, wCast, wConst, wContinue, 
+    wConverter, wDiscard, wDiv, wElif, 
+    wElse, wEnd, wEnum, wExcept, 
     wFinally, wFor, wFrom, wGeneric, 
     wIf, wImplies, wImport, wIn, 
     wInclude, wIs, wIsnot, wIterator, 
@@ -62,7 +62,7 @@ type
     // pragmas and command line options:
     wMagic, wTypeCheck, wFinal, wProfiler,
     wObjChecks, wImportc, wExportc, wAlign, wNodecl, wPure,
-    wVolatile, wRegister, wNostatic, wHeader, wNosideeffect, wNoreturn,
+    wVolatile, wRegister, wSideeffect, wHeader, wNosideeffect, wNoreturn,
     wMerge, wLib, wDynlib, wCompilerproc, wCppmethod, wFatal,
     wError, wWarning, wHint, wLine, wPush, wPop,
     wDefine, wUndef, wLinedir, wStacktrace, wLinetrace, wPragma,
@@ -114,10 +114,10 @@ const
     //cog.out(strings)
     //]]]
     'abstract', 'addr', 'and', 'as', 
-    'asm', 'block', 'break', 'case', 
-    'cast', 'const', 'continue', 'converter', 
-    'discard', 'div', 'elif', 'else', 
-    'end', 'enum', 'except', 'exception', 
+    'asm', 'bind', 'block', 'break', 
+    'case', 'cast', 'const', 'continue', 
+    'converter', 'discard', 'div', 'elif', 
+    'else', 'end', 'enum', 'except', 
     'finally', 'for', 'from', 'generic', 
     'if', 'implies', 'import', 'in', 
     'include', 'is', 'isnot', 'iterator', 
@@ -136,7 +136,7 @@ const
     // pragmas and command line options:
     'magic', 'typecheck', 'final', 'profiler',
     'objchecks', 'importc', 'exportc', 'align', 'nodecl', 'pure',
-    'volatile', 'register', 'nostatic', 'header', 'nosideeffect', 'noreturn',
+    'volatile', 'register', 'sideeffect', 'header', 'nosideeffect', 'noreturn',
     'merge', 'lib', 'dynlib', 'compilerproc', 'cppmethod', 'fatal',
     'error', 'warning', 'hint', 'line', 'push', 'pop',
     'define', 'undef', 'linedir', 'stacktrace', 'linetrace', 'pragma',