summary refs log tree commit diff stats
path: root/nim
diff options
context:
space:
mode:
authorAndreas Rumpf <andreasrumpf@noname>2009-09-15 23:22:22 +0200
committerAndreas Rumpf <andreasrumpf@noname>2009-09-15 23:22:22 +0200
commit66a7e3d37c0303997a6b1a3b7ec263dfb8c07748 (patch)
tree40ae1ab8aeb9086b7310ea73ab8a2ed6b597f88b /nim
parent300430fbba28b408f7ac86ca46b03d9d50839399 (diff)
downloadNim-66a7e3d37c0303997a6b1a3b7ec263dfb8c07748.tar.gz
added tools and web dirs
Diffstat (limited to 'nim')
-rwxr-xr-x[-rw-r--r--]nim/ast.pas174
-rwxr-xr-x[-rw-r--r--]nim/astalgo.pas37
-rwxr-xr-x[-rw-r--r--]nim/bitsets.pas0
-rwxr-xr-x[-rw-r--r--]nim/ccgexprs.pas49
-rwxr-xr-x[-rw-r--r--]nim/ccgstmts.pas80
-rwxr-xr-x[-rw-r--r--]nim/ccgtypes.pas4
-rwxr-xr-x[-rw-r--r--]nim/ccgutils.pas2
-rwxr-xr-x[-rw-r--r--]nim/cgen.pas121
-rwxr-xr-x[-rw-r--r--]nim/charsets.pas0
-rwxr-xr-x[-rw-r--r--]nim/commands.pas10
-rwxr-xr-x[-rw-r--r--]nim/condsyms.pas0
-rwxr-xr-x[-rw-r--r--]nim/config.inc0
-rwxr-xr-x[-rw-r--r--]nim/crc.pas0
-rwxr-xr-x[-rw-r--r--]nim/depends.pas0
-rwxr-xr-x[-rw-r--r--]nim/docgen.pas556
-rwxr-xr-x[-rw-r--r--]nim/ecmasgen.pas21
-rwxr-xr-x[-rw-r--r--]nim/evals.pas6
-rwxr-xr-x[-rw-r--r--]nim/extccomp.pas5
-rwxr-xr-x[-rw-r--r--]nim/hashtest.pas0
-rwxr-xr-x[-rw-r--r--]nim/highlite.pas7
-rwxr-xr-x[-rw-r--r--]nim/idents.pas0
-rwxr-xr-x[-rw-r--r--]nim/importer.pas0
-rwxr-xr-x[-rw-r--r--]nim/interact.pas0
-rwxr-xr-x[-rw-r--r--]nim/lexbase.pas0
-rwxr-xr-x[-rw-r--r--]nim/lists.pas0
-rwxr-xr-x[-rw-r--r--]nim/llstream.pas0
-rwxr-xr-x[-rw-r--r--]nim/llvmdyn.pas2
-rwxr-xr-x[-rw-r--r--]nim/llvmstat.pas0
-rwxr-xr-x[-rw-r--r--]nim/lookups.pas18
-rwxr-xr-x[-rw-r--r--]nim/magicsys.pas2
-rwxr-xr-x[-rw-r--r--]nim/main.pas6
-rwxr-xr-x[-rw-r--r--]nim/msgs.pas789
-rwxr-xr-x[-rw-r--r--]nim/nhashes.pas0
-rwxr-xr-x[-rw-r--r--]nim/nimconf.pas2
-rwxr-xr-x[-rw-r--r--]nim/nimrod.pas0
-rwxr-xr-x[-rw-r--r--]nim/nimsets.pas0
-rwxr-xr-x[-rw-r--r--]nim/nmath.pas0
-rwxr-xr-x[-rw-r--r--]nim/nos.pas4
-rwxr-xr-x[-rw-r--r--]nim/nstrtabs.pas0
-rwxr-xr-x[-rw-r--r--]nim/nsystem.pas7
-rwxr-xr-x[-rw-r--r--]nim/ntime.pas0
-rwxr-xr-x[-rw-r--r--]nim/nversion.pas6
-rwxr-xr-x[-rw-r--r--]nim/options.pas8
-rwxr-xr-x[-rw-r--r--]nim/osproc.pas0
-rwxr-xr-x[-rw-r--r--]nim/parsecfg.pas0
-rwxr-xr-x[-rw-r--r--]nim/parseopt.pas0
-rwxr-xr-x[-rw-r--r--]nim/paslex.pas0
-rwxr-xr-x[-rw-r--r--]nim/pasparse.pas4
-rwxr-xr-x[-rw-r--r--]nim/passaux.pas0
-rwxr-xr-x[-rw-r--r--]nim/passes.pas0
-rwxr-xr-x[-rw-r--r--]nim/platform.pas0
-rwxr-xr-x[-rw-r--r--]nim/pnimsyn.pas86
-rwxr-xr-x[-rw-r--r--]nim/pragmas.pas122
-rwxr-xr-x[-rw-r--r--]nim/procfind.pas10
-rwxr-xr-x[-rw-r--r--]nim/ptmplsyn.pas0
-rwxr-xr-x[-rw-r--r--]nim/readme.txt0
-rwxr-xr-x[-rw-r--r--]nim/rnimsyn.pas38
-rwxr-xr-x[-rw-r--r--]nim/rodread.pas8
-rwxr-xr-x[-rw-r--r--]nim/rodwrite.pas0
-rwxr-xr-x[-rw-r--r--]nim/ropes.pas0
-rwxr-xr-x[-rw-r--r--]nim/rst.pas15
-rwxr-xr-x[-rw-r--r--]nim/scanner.pas33
-rwxr-xr-x[-rw-r--r--]nim/sem.pas60
-rwxr-xr-x[-rw-r--r--]nim/semdata.pas34
-rwxr-xr-x[-rw-r--r--]nim/semexprs.pas254
-rwxr-xr-x[-rw-r--r--]nim/semfold.pas2
-rwxr-xr-x[-rw-r--r--]nim/seminst.pas369
-rwxr-xr-x[-rw-r--r--]nim/semstmts.pas344
-rwxr-xr-x[-rw-r--r--]nim/semtempl.pas109
-rwxr-xr-x[-rw-r--r--]nim/semtypes.pas180
-rwxr-xr-x[-rw-r--r--]nim/sigmatch.pas125
-rwxr-xr-x[-rw-r--r--]nim/strutils.pas10
-rwxr-xr-x[-rw-r--r--]nim/syntaxes.pas0
-rwxr-xr-x[-rw-r--r--]nim/tigen.pas0
-rwxr-xr-x[-rw-r--r--]nim/transf.pas47
-rwxr-xr-x[-rw-r--r--]nim/transtmp.pas2
-rwxr-xr-x[-rw-r--r--]nim/trees.pas13
-rwxr-xr-x[-rw-r--r--]nim/treetab.pas0
-rwxr-xr-x[-rw-r--r--]nim/types.pas144
-rwxr-xr-x[-rw-r--r--]nim/wordrecg.pas31
80 files changed, 2195 insertions, 1761 deletions
diff --git a/nim/ast.pas b/nim/ast.pas
index 4836a860e..aec165585 100644..100755
--- a/nim/ast.pas
+++ b/nim/ast.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.
@@ -72,32 +72,31 @@ type
     nkInt16Lit, nkInt32Lit, nkInt64Lit, nkFloatLit, 
     nkFloat32Lit, nkFloat64Lit, nkStrLit, nkRStrLit, 
     nkTripleStrLit, nkMetaNode, nkNilLit, nkDotCall, 
-    nkCommand, nkCall, nkGenericCall, nkExplicitTypeListCall, 
-    nkExprEqExpr, nkExprColonExpr, nkIdentDefs, nkVarTuple, 
-    nkInfix, nkPrefix, nkPostfix, nkPar, 
-    nkCurly, nkBracket, nkBracketExpr, nkPragmaExpr, 
-    nkRange, nkDotExpr, nkCheckedFieldExpr, nkDerefExpr, 
-    nkIfExpr, nkElifExpr, nkElseExpr, nkLambda, 
-    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, 
+    nkCommand, nkCall, nkCallStrLit, nkExprEqExpr, 
+    nkExprColonExpr, nkIdentDefs, nkVarTuple, nkInfix, 
+    nkPrefix, nkPostfix, nkPar, nkCurly, 
+    nkBracket, nkBracketExpr, nkPragmaExpr, nkRange, 
+    nkDotExpr, nkCheckedFieldExpr, nkDerefExpr, nkIfExpr, 
+    nkElifExpr, nkElseExpr, nkLambda, nkAccQuoted, 
+    nkTableConstr, nkQualified, nkBind, nkSymChoice, 
+    nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv, nkConv, 
+    nkCast, nkAddr, nkHiddenAddr, nkHiddenDeref, 
+    nkObjDownConv, nkObjUpConv, nkChckRangeF, nkChckRange64, 
+    nkChckRange, nkStringToCString, nkCStringToString, nkPassAsOpenArray, 
+    nkAsgn, nkFastAsgn, 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, 
+    nkIncludeStmt, nkCommentStmt, nkStmtListExpr, nkBlockExpr, 
+    nkStmtListType, nkBlockType, nkTypeOfExpr, nkObjectTy, 
     nkTupleTy, nkRecList, nkRecCase, nkRecWhen, 
-    nkRefTy, nkPtrTy, nkVarTy, nkAbstractTy, 
+    nkRefTy, nkPtrTy, nkVarTy, nkDistinctTy, 
     nkProcTy, nkEnumTy, nkEnumFieldDef, nkReturnToken);
   TNodeKinds = set of TNodeKind;
 const
@@ -107,32 +106,31 @@ const
     'nkInt16Lit', 'nkInt32Lit', 'nkInt64Lit', 'nkFloatLit', 
     'nkFloat32Lit', 'nkFloat64Lit', 'nkStrLit', 'nkRStrLit', 
     'nkTripleStrLit', 'nkMetaNode', 'nkNilLit', 'nkDotCall', 
-    'nkCommand', 'nkCall', 'nkGenericCall', 'nkExplicitTypeListCall', 
-    'nkExprEqExpr', 'nkExprColonExpr', 'nkIdentDefs', 'nkVarTuple', 
-    'nkInfix', 'nkPrefix', 'nkPostfix', 'nkPar', 
-    'nkCurly', 'nkBracket', 'nkBracketExpr', 'nkPragmaExpr', 
-    'nkRange', 'nkDotExpr', 'nkCheckedFieldExpr', 'nkDerefExpr', 
-    'nkIfExpr', 'nkElifExpr', 'nkElseExpr', 'nkLambda', 
-    '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', 
+    'nkCommand', 'nkCall', 'nkCallStrLit', 'nkExprEqExpr', 
+    'nkExprColonExpr', 'nkIdentDefs', 'nkVarTuple', 'nkInfix', 
+    'nkPrefix', 'nkPostfix', 'nkPar', 'nkCurly', 
+    'nkBracket', 'nkBracketExpr', 'nkPragmaExpr', 'nkRange', 
+    'nkDotExpr', 'nkCheckedFieldExpr', 'nkDerefExpr', 'nkIfExpr', 
+    'nkElifExpr', 'nkElseExpr', 'nkLambda', 'nkAccQuoted', 
+    'nkTableConstr', 'nkQualified', 'nkBind', 'nkSymChoice', 
+    'nkHiddenStdConv', 'nkHiddenSubConv', 'nkHiddenCallConv', 'nkConv', 
+    'nkCast', 'nkAddr', 'nkHiddenAddr', 'nkHiddenDeref', 
+    'nkObjDownConv', 'nkObjUpConv', 'nkChckRangeF', 'nkChckRange64', 
+    'nkChckRange', 'nkStringToCString', 'nkCStringToString', 'nkPassAsOpenArray', 
+    'nkAsgn', 'nkFastAsgn', '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', 
+    'nkIncludeStmt', 'nkCommentStmt', 'nkStmtListExpr', 'nkBlockExpr', 
+    'nkStmtListType', 'nkBlockType', 'nkTypeOfExpr', 'nkObjectTy', 
     'nkTupleTy', 'nkRecList', 'nkRecCase', 'nkRecWhen', 
-    'nkRefTy', 'nkPtrTy', 'nkVarTy', 'nkAbstractTy', 
+    'nkRefTy', 'nkPtrTy', 'nkVarTy', 'nkDistinctTy', 
     'nkProcTy', 'nkEnumTy', 'nkEnumFieldDef', 'nkReturnToken');
 type
   TSymFlag = (
@@ -158,8 +156,9 @@ const
 type
   TTypeKind = (
     tyNone, tyBool, tyChar, tyEmpty, 
-    tyArrayConstr, tyNil, tyGeneric, tyGenericInst, 
-    tyGenericParam, tyAbstract, tyEnum, tyOrdinal, 
+    tyArrayConstr, tyNil, tyExpr, tyStmt, 
+    tyTypeDesc, tyGenericInvokation, tyGenericBody, tyGenericInst, 
+    tyGenericParam, tyDistinct, tyEnum, tyOrdinal, 
     tyArray, tyObject, tyTuple, tySet, 
     tyRange, tyPtr, tyRef, tyVar, 
     tySequence, tyProc, tyPointer, tyOpenArray, 
@@ -170,8 +169,9 @@ type
 const
   TypeKindToStr: array [TTypeKind] of string = (
     'tyNone', 'tyBool', 'tyChar', 'tyEmpty', 
-    'tyArrayConstr', 'tyNil', 'tyGeneric', 'tyGenericInst', 
-    'tyGenericParam', 'tyAbstract', 'tyEnum', 'tyOrdinal', 
+    'tyArrayConstr', 'tyNil', 'tyExpr', 'tyStmt', 
+    'tyTypeDesc', 'tyGenericInvokation', 'tyGenericBody', 'tyGenericInst', 
+    'tyGenericParam', 'tyDistinct', 'tyEnum', 'tyOrdinal', 
     'tyArray', 'tyObject', 'tyTuple', 'tySet', 
     'tyRange', 'tyPtr', 'tyRef', 'tyVar', 
     'tySequence', 'tyProc', 'tyPointer', 'tyOpenArray', 
@@ -198,16 +198,16 @@ const
     'tfEnumHasWholes');
 type
   TSymKind = (
-    skUnknownSym, skConditional, skDynLib, skParam, 
-    skTypeParam, skTemp, skType, skConst, 
+    skUnknown, skConditional, skDynLib, skParam, 
+    skGenericParam, skTemp, skType, skConst, 
     skVar, skProc, skIterator, skConverter, 
     skMacro, skTemplate, skField, skEnumField, 
     skForVar, skModule, skLabel, skStub);
   TSymKinds = set of TSymKind;
 const
   SymKindToStr: array [TSymKind] of string = (
-    'skUnknownSym', 'skConditional', 'skDynLib', 'skParam', 
-    'skTypeParam', 'skTemp', 'skType', 'skConst', 
+    'skUnknown', 'skConditional', 'skDynLib', 'skParam', 
+    'skGenericParam', 'skTemp', 'skType', 'skConst', 
     'skVar', 'skProc', 'skIterator', 'skConverter', 
     'skMacro', 'skTemplate', 'skField', 'skEnumField', 
     'skForVar', 'skModule', 'skLabel', 'skStub');
@@ -253,14 +253,15 @@ type
     mNewString, mArray, mOpenArray, mRange, mSet, mSeq, 
     mOrdinal, mInt, mInt8, mInt16, mInt32, mInt64, 
     mFloat, mFloat32, mFloat64, mBool, mChar, mString, 
-    mCstring, mPointer, mEmptySet, mIntSetBaseType, mNil, mIsMainModule, 
-    mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor, mNimrodMinor, mNimrodPatch, 
-    mCpuEndian, mHostOS, mHostCPU, mNaN, mInf, mNegInf, 
-    mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, 
-    mNKind, mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, 
-    mNStrVal, mNSetIntVal, mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, 
-    mNSetStrVal, mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr, 
-    mEqIdent, mNHint, mNWarning, mNError
+    mCstring, mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, 
+    mStmt, mTypeDesc, mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, 
+    mNimrodMajor, mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, 
+    mNaN, mInf, mNegInf, mNLen, mNChild, mNSetChild, 
+    mNAdd, mNAddMultiple, mNDel, mNKind, mNIntVal, mNFloatVal, 
+    mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal, mNSetFloatVal, 
+    mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNNewNimNode, mNCopyNimNode, 
+    mNCopyNimTree, mStrToIdent, mIdentToStr, mEqIdent, mNHint, mNWarning, 
+    mNError
     //[[[end]]]
   );
 
@@ -418,7 +419,6 @@ type
     loc: TLoc;
   end;
 
-  // these are not part of the syntax tree, but nevertherless inherit from TNode
   TPair = record
     key, val: PObject;
   end;
@@ -512,19 +512,24 @@ const // "MagicToStr" array:
     'NewString', 'Array', 'OpenArray', 'Range', 'Set', 'Seq', 
     'Ordinal', 'Int', 'Int8', 'Int16', 'Int32', 'Int64', 
     'Float', 'Float32', 'Float64', 'Bool', 'Char', 'String', 
-    'Cstring', 'Pointer', 'EmptySet', 'IntSetBaseType', 'Nil', 'IsMainModule', 
-    'CompileDate', 'CompileTime', 'NimrodVersion', 'NimrodMajor', 'NimrodMinor', 'NimrodPatch', 
-    'CpuEndian', 'HostOS', 'HostCPU', 'NaN', 'Inf', 'NegInf', 
-    'NLen', 'NChild', 'NSetChild', 'NAdd', 'NAddMultiple', 'NDel', 
-    'NKind', 'NIntVal', 'NFloatVal', 'NSymbol', 'NIdent', 'NGetType', 
-    'NStrVal', 'NSetIntVal', 'NSetFloatVal', 'NSetSymbol', 'NSetIdent', 'NSetType', 
-    'NSetStrVal', 'NNewNimNode', 'NCopyNimNode', 'NCopyNimTree', 'StrToIdent', 'IdentToStr', 
-    'EqIdent', 'NHint', 'NWarning', 'NError'
+    'Cstring', 'Pointer', 'EmptySet', 'IntSetBaseType', 'Nil', 'Expr', 
+    'Stmt', 'TypeDesc', 'IsMainModule', 'CompileDate', 'CompileTime', 'NimrodVersion', 
+    'NimrodMajor', 'NimrodMinor', 'NimrodPatch', 'CpuEndian', 'HostOS', 'HostCPU', 
+    'NaN', 'Inf', 'NegInf', 'NLen', 'NChild', 'NSetChild', 
+    'NAdd', 'NAddMultiple', 'NDel', 'NKind', 'NIntVal', 'NFloatVal', 
+    'NSymbol', 'NIdent', 'NGetType', 'NStrVal', 'NSetIntVal', 'NSetFloatVal', 
+    'NSetSymbol', 'NSetIdent', 'NSetType', 'NSetStrVal', 'NNewNimNode', 'NCopyNimNode', 
+    'NCopyNimTree', 'StrToIdent', 'IdentToStr', 'EqIdent', 'NHint', 'NWarning', 
+    'NError'
     //[[[end]]]
   );
 
 const
-  GenericTypes: TTypeKinds = {@set}[tyGeneric, tyGenericParam];
+  GenericTypes: TTypeKinds = {@set}[
+    tyGenericInvokation, 
+    tyGenericBody, 
+    tyGenericParam
+  ];
 
   StructuralEquivTypes: TTypeKinds = {@set}[
     tyArrayConstr, tyNil, tyTuple,
@@ -669,6 +674,7 @@ type
 
 function IntSetContains(const s: TIntSet; key: int): bool;
 procedure IntSetIncl(var s: TIntSet; key: int);
+procedure IntSetExcl(var s: TIntSet; key: int);
 procedure IntSetInit(var s: TIntSet);
 
 function IntSetContainsOrIncl(var s: TIntSet; key: int): bool;
@@ -1069,6 +1075,7 @@ begin
 {@emit
   if isNil(father.sons) then father.sons := @[]; }
 {@emit add(father.sons, son); }
+  assert((father.kind <> tyGenericInvokation) or (son.kind <> tyGenericInst));
 end;
 
 function sonsLen(n: PNode): int;
@@ -1371,6 +1378,19 @@ begin
                             or shlu(1, u and IntMask);
 end;
 
+procedure IntSetExcl(var s: TIntSet; key: int);
+var
+  u: TBitScalar;
+  t: PTrunk;
+begin
+  t := IntSetGet(s, shru(key, TrunkShift));
+  if t <> nil then begin
+    u := key and TrunkMask;
+    t.bits[shru(u, IntShift)] := t.bits[shru(u, IntShift)]
+                               and not shlu(1, u and IntMask);
+  end
+end;
+
 function IntSetContainsOrIncl(var s: TIntSet; key: int): bool;
 var
   u: TBitScalar;
diff --git a/nim/astalgo.pas b/nim/astalgo.pas
index e5475ddd1..7c1f3ec0b 100644..100755
--- a/nim/astalgo.pas
+++ b/nim/astalgo.pas
@@ -419,6 +419,8 @@ end;
 
 function typeToYamlAux(n: PType; var marker: TIntSet;
                        indent: int; maxRecDepth: int): PRope;
+var
+  i: int;
 begin
   if n = nil then
     result := toRope('null')
@@ -427,6 +429,18 @@ begin
       toRope(typeKindToStr[n.kind]),
       toRope(strutils.toHex({@cast}TAddress(n), sizeof(n)*2))])
   else begin
+    if sonsLen(n) > 0 then begin
+      result := toRope('['+'');
+      for i := 0 to sonsLen(n)-1 do begin
+        if i > 0 then app(result, ','+'');
+        appf(result, '$n$1$2',
+          [spaces(indent+4),
+           typeToYamlAux(n.sons[i], marker, indent + 4, maxRecDepth-1)]);
+      end;
+      appf(result, '$n$1]', [spaces(indent+2)]);
+    end
+    else
+      result := toRope('null');
     result := ropeConstr(indent, [
       toRope('kind'), makeYamlString(typeKindToStr[n.kind]),
       toRope('sym'), symToYamlAux(n.sym, marker, indent+2, maxRecDepth-1),
@@ -434,7 +448,8 @@ begin
       toRope('flags'), typeFlagsToStr(n.flags),
       toRope('callconv'), makeYamlString(CallingConvToStr[n.callConv]),
       toRope('size'), toRope(n.size),
-      toRope('align'), toRope(n.align)
+      toRope('align'), toRope(n.align),
+      toRope('sons'), result
     ]);
   end
 end;
@@ -525,14 +540,20 @@ begin
     result := toRope('null')
   else begin
     result := toRope(typeKindToStr[n.kind]);
-    app(result, '('+'');
-    for i := 0 to sonsLen(n)-1 do begin
-      if i > 0 then app(result, ', ');
-      if n.sons[i] = nil then app(result, 'null')
-      else app(result, debugType(n.sons[i]));
-       //  app(result, typeKindToStr[n.sons[i].kind]);
+    if n.sym <> nil then begin
+      app(result, ' '+'');
+      app(result, n.sym.name.s);
     end;
-    app(result, ')'+'');
+    if (n.kind <> tyString) and (sonsLen(n) > 0) then begin
+      app(result, '('+'');
+      for i := 0 to sonsLen(n)-1 do begin
+        if i > 0 then app(result, ', ');
+        if n.sons[i] = nil then app(result, 'null')
+        else app(result, debugType(n.sons[i]));
+         //  app(result, typeKindToStr[n.sons[i].kind]);
+      end;
+      app(result, ')'+'');
+    end
   end
 end;
 
diff --git a/nim/bitsets.pas b/nim/bitsets.pas
index 78c6d1f36..78c6d1f36 100644..100755
--- a/nim/bitsets.pas
+++ b/nim/bitsets.pas
diff --git a/nim/ccgexprs.pas b/nim/ccgexprs.pas
index 212017d14..97a24caeb 100644..100755
--- a/nim/ccgexprs.pas
+++ b/nim/ccgexprs.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.
@@ -213,8 +213,7 @@ end;
 function rdLoc(const a: TLoc): PRope; // 'read' location (deref if indirect)
 begin
   result := a.r;
-  if lfIndirect in a.flags then
-    result := ropef('(*$1 /*rdLoc*/)', [result])
+  if lfIndirect in a.flags then result := ropef('(*$1)', [result])
 end;
 
 function addrLoc(const a: TLoc): PRope;
@@ -760,7 +759,8 @@ begin
   f := e.sons[1].sym;
   field := nil;
   while ty <> nil do begin
-    assert(ty.kind in [tyTuple, tyObject]);
+    if not (ty.kind in [tyTuple, tyObject]) then
+      InternalError(e.info, 'genRecordField');
     field := lookupInRecord(ty.n, f.name);
     if field <> nil then break;
     if gCmd <> cmdCompileToCpp then app(r, '.Sup');
@@ -1643,8 +1643,8 @@ begin
       case op of
         mIncl: binaryStmtInExcl(p, e, d, '$1[$2/8] |=(1<<($2%8));$n');
         mExcl: binaryStmtInExcl(p, e, d, '$1[$2/8] &= ~(1<<($2%8));$n');
-        mCard: unaryExprChar(p, e, d, 'countBitsVar',
-                                  'countBitsVar($1, ' + ToString(size) + ')');
+        mCard: unaryExprChar(p, e, d, 'cardSet',
+                                  'cardSet($1, ' + ToString(size) + ')');
         mLtSet, mLeSet: begin
           getTemp(p, getSysType(tyInt), i); // our counter
           initLocExpr(p, e.sons[1], a);
@@ -1847,7 +1847,6 @@ end;
 
 procedure genMagicExpr(p: BProc; e: PNode; var d: TLoc; op: TMagic);
 var
-  a: TLoc;
   line, filen: PRope;
 begin
   case op of
@@ -1870,6 +1869,22 @@ begin
       else
         binaryExpr(p, e, d, 'addInt', 'addInt($1, $2)')
     end;
+    mInc: begin
+      if not (optOverflowCheck in p.Options) then
+        binaryStmt(p, e, d, '', '$1 += $2;$n')
+      else if skipTypes(e.sons[1].typ, abstractVar).kind = tyInt64 then
+        binaryStmt(p, e, d, 'addInt64', '$1 = addInt64($1, $2);$n')
+      else
+        binaryStmt(p, e, d, 'addInt', '$1 = addInt($1, $2);$n')
+    end;
+    ast.mDec: begin
+      if not (optOverflowCheck in p.Options) then
+        binaryStmt(p, e, d, '', '$1 -= $2;$n')
+      else if skipTypes(e.sons[1].typ, abstractVar).kind = tyInt64 then
+        binaryStmt(p, e, d, 'subInt64', '$1 = subInt64($1, $2);$n')
+      else
+        binaryStmt(p, e, d, 'subInt', '$1 = subInt($1, $2);$n')
+    end;
     mConStrStr: genStrConcat(p, e, d);
     mAppendStrCh: binaryStmt(p, e, d, 'addChar', '$1 = addChar($1, $2);$n');
     mAppendStrStr: genStrAppend(p, e, d);
@@ -1907,22 +1922,6 @@ begin
     mOrd: genOrd(p, e, d);
     mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray:
       genArrayLen(p, e, d, op);
-    mInc: begin
-      if not (optOverflowCheck in p.Options) then
-        binaryStmt(p, e, d, '', '$1 += $2;$n')
-      else if skipTypes(e.sons[1].typ, abstractVar).kind = tyInt64 then
-        binaryStmt(p, e, d, 'addInt64', '$1 = addInt64($1, $2);$n')
-      else
-        binaryStmt(p, e, d, 'addInt', '$1 = addInt($1, $2);$n')
-    end;
-    ast.mDec: begin
-      if not (optOverflowCheck in p.Options) then
-        binaryStmt(p, e, d, '', '$1 -= $2;$n')
-      else if skipTypes(e.sons[1].typ, abstractVar).kind = tyInt64 then
-        binaryStmt(p, e, d, 'subInt64', '$1 = subInt64($1, $2);$n')
-      else
-        binaryStmt(p, e, d, 'subInt', '$1 = subInt($1, $2);$n')
-    end;
     mGCref: unaryStmt(p, e, d, 'nimGCref', 'nimGCref($1);$n');
     mGCunref: unaryStmt(p, e, d, 'nimGCunref', 'nimGCunref($1);$n');
     mSetLengthStr: genSetLengthStr(p, e, d);
@@ -2203,7 +2202,8 @@ begin
     nkFloatLit..nkFloat64Lit, nkNilLit, nkCharLit: begin
       putIntoDest(p, d, e.typ, genLiteral(p, e));
     end;
-    nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand: begin
+    nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand,
+    nkCallStrLit: begin
       if (e.sons[0].kind = nkSym) and
          (e.sons[0].sym.magic <> mNone) then
         genMagicExpr(p, e, d, e.sons[0].sym.magic)
@@ -2279,7 +2279,6 @@ end;
 
 function genConstExpr(p: BProc; n: PNode): PRope;
 var
-  trans: PNode;
   cs: TBitSet;
   d: TLoc;
 begin
diff --git a/nim/ccgstmts.pas b/nim/ccgstmts.pas
index 90e5c1c77..03d6edb01 100644..100755
--- a/nim/ccgstmts.pas
+++ b/nim/ccgstmts.pas
@@ -94,31 +94,70 @@ begin
    end
 end;
 
-procedure genVarStmt(p: BProc; n: PNode);
+procedure genVarTuple(p: BProc; n: PNode);
 var
-  i: int;
+  i, L: int;
   v: PSym;
-  a: PNode;
+  tup, field: TLoc;
+  t: PType;
 begin
-  for i := 0 to sonsLen(n)-1 do begin
-    a := n.sons[i];
-    if a.kind = nkCommentStmt then continue;
-    assert(a.kind = nkIdentDefs);
-    assert(a.sons[0].kind = nkSym);
-    v := a.sons[0].sym;
+  if n.kind <> nkVarTuple then InternalError(n.info, 'genVarTuple');
+  L := sonsLen(n);
+  genLineDir(p, n);
+  initLocExpr(p, n.sons[L-1], tup);
+  t := tup.t;
+  for i := 0 to L-3 do begin
+    v := n.sons[i].sym;
     if sfGlobal in v.flags then
       assignGlobalVar(p, v)
     else begin
       assignLocalVar(p, v);
-      initVariable(p, v) // XXX: this is not required if a.sons[2] != nil,
-                         // unless it is a GC'ed pointer
+      initVariable(p, v)
     end;
     // generate assignment:
-    if a.sons[2] <> nil then begin
-      genLineDir(p, a);
-      expr(p, a.sons[2], v.loc);
+    initLoc(field, locExpr, t.sons[i], tup.s);
+    if t.n = nil then begin
+      field.r := ropef('$1.Field$2', [rdLoc(tup), toRope(i)]);
+    end
+    else begin
+      if (t.n.sons[i].kind <> nkSym) then
+        InternalError(n.info, 'genVarTuple');
+      field.r := ropef('$1.$2', [rdLoc(tup), 
+        mangleRecFieldName(t.n.sons[i].sym, t)]);
     end;
-    genObjectInit(p, v.typ, v.loc, true); // correct position
+    putLocIntoDest(p, v.loc, field);
+    genObjectInit(p, v.typ, v.loc, true);
+  end
+end;
+
+procedure genVarStmt(p: BProc; n: PNode);
+var
+  i: int;
+  v: PSym;
+  a: PNode;
+begin
+  for i := 0 to sonsLen(n)-1 do begin
+    a := n.sons[i];
+    if a.kind = nkCommentStmt then continue;
+    if a.kind = nkIdentDefs then begin
+      assert(a.sons[0].kind = nkSym);
+      v := a.sons[0].sym;
+      if sfGlobal in v.flags then
+        assignGlobalVar(p, v)
+      else begin
+        assignLocalVar(p, v);
+        initVariable(p, v) // XXX: this is not required if a.sons[2] != nil,
+                           // unless it is a GC'ed pointer
+      end;
+      // generate assignment:
+      if a.sons[2] <> nil then begin
+        genLineDir(p, a);
+        expr(p, a.sons[2], v.loc);
+      end;
+      genObjectInit(p, v.typ, v.loc, true); // correct position
+    end
+    else
+      genVarTuple(p, a);
   end
 end;
 
@@ -294,7 +333,7 @@ begin
         else begin
           r := sym.loc.r;
           if r = nil then begin // if no name has already been given,
-                       // it doesn't matter much:
+                                // it doesn't matter much:
             r := mangleName(sym);
             sym.loc.r := r; // but be consequent!
           end;
@@ -561,7 +600,7 @@ procedure genOrdinalCase(p: BProc; t: PNode);
 // we generate an ordinary if statement and rely on the C compiler
 // to produce good code.
 var
-  canGenerateSwitch: bool;
+  canGenerateSwitch, hasDefault: bool;
   i, j, len: int;
   a: TLoc;
   v: PNode;
@@ -578,6 +617,7 @@ begin
   if canGenerateSwitch then begin
     initLocExpr(p, t.sons[0], a);
     appf(p.s[cpsStmts], 'switch ($1) {$n', [rdCharLoc(a)]);
+    hasDefault := false;
     for i := 1 to sonsLen(t)-1 do begin
       if t.sons[i].kind = nkOfBranch then begin
         len := sonsLen(t.sons[i]);
@@ -604,9 +644,12 @@ begin
       else begin // else part of case statement:
         app(p.s[cpsStmts], 'default:' + tnl);
         genStmts(p, t.sons[i].sons[0]);
+        hasDefault := true;
       end;
       app(p.s[cpsStmts], 'break;' + tnl);
     end;
+    if (hasAssume in CC[ccompiler].props) and not hasDefault then 
+      app(p.s[cpsStmts], 'default: __assume(0);' + tnl);      
     app(p.s[cpsStmts], '}' + tnl);
   end
   else
@@ -902,7 +945,8 @@ begin
     nkCaseStmt:    genCaseStmt(p, t);
     nkReturnStmt:  genReturnStmt(p, t);
     nkBreakStmt:   genBreakStmt(p, t);
-    nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand: begin
+    nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand,
+    nkCallStrLit: begin
       genLineDir(p, t);
       initLocExpr(p, t, a);
     end;
diff --git a/nim/ccgtypes.pas b/nim/ccgtypes.pas
index f9b3a36c1..8c17514ff 100644..100755
--- a/nim/ccgtypes.pas
+++ b/nim/ccgtypes.pas
@@ -116,7 +116,7 @@ begin
     end;
     tyOpenArray, tyArrayConstr, tyArray: result := ctArray;
     tyObject, tyTuple: result := ctStruct;
-    tyGeneric, tyGenericInst, tyGenericParam, tyAbstract, tyOrdinal: 
+    tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal: 
       result := mapType(lastSon(typ));
     tyEnum: begin
       if firstOrd(typ) < 0 then
@@ -664,7 +664,7 @@ begin
         end
       end
     end;
-    tyGenericInst, tyAbstract, tyOrdinal: 
+    tyGenericInst, tyDistinct, tyOrdinal: 
       result := getTypeDescAux(m, lastSon(t), check);
     else begin
       InternalError('getTypeDescAux(' + typeKindToStr[t.kind] + ')');
diff --git a/nim/ccgutils.pas b/nim/ccgutils.pas
index de5cac13c..da6b8774f 100644..100755
--- a/nim/ccgutils.pas
+++ b/nim/ccgutils.pas
@@ -56,7 +56,7 @@ begin
         result := key;
       end
     end;
-    tyGenericInst, tyAbstract, tyOrdinal: 
+    tyGenericInst, tyDistinct, tyOrdinal: 
       result := GetUniqueType(lastSon(key));
     tyProc: begin end;
     else begin
diff --git a/nim/cgen.pas b/nim/cgen.pas
index fdae6feb6..04c19d444 100644..100755
--- a/nim/cgen.pas
+++ b/nim/cgen.pas
@@ -463,7 +463,7 @@ begin
   if (le >= strStart) and (ri > le) then begin
     prefix := ncopy(s, strStart, le-1);
     suffix := ncopy(s, ri+1);
-    temp := splitSeq(ncopy(s, le+1, ri-1), {@set}['|']);
+    temp := split(ncopy(s, le+1, ri-1), {@set}['|']);
     for i := 0 to high(temp) do 
       libCandidates(prefix +{&} temp[i] +{&} suffix, dest);
   end
@@ -850,7 +850,7 @@ begin
       '; Generated by the Nimrod Compiler v$1$n' +
       ';   (c) 2009 Andreas Rumpf$n' +
       '; Compiled for: $2, $3, $4$n' +
-      '; Command for C compiler:$n   $5$n',
+      '; Command for LLVM compiler:$n   $5$n',
       [toRope(versionAsString), toRope(platform.OS[targetOS].name),
       toRope(platform.CPU[targetCPU].name),
       toRope(extccomp.CC[extccomp.ccompiler].name),
@@ -884,84 +884,119 @@ const
     '  call void systemInit()$n' +
     '$1' +
     '$2';    
-  PosixMain =
+  PosixNimMain =
     'int cmdCount;$n' +
     'char** cmdLine;$n' +
     'char** gEnv;$n' +
+    'N_CDECL(void, NimMain)(void) {$n' +
+    '  int dummy[8];$n' +{&}
+    CommonMainBody +{&}
+    '}$n';
+  PosixCMain = 
     'int main(int argc, char** args, char** env) {$n' +
-    '  int dummy[8];$n' +
     '  cmdLine = args;$n' +
     '  cmdCount = argc;$n' +
-    '  gEnv = env;$n' +{&}
-    CommonMainBody +{&}
+    '  gEnv = env;$n' +
+    '  NimMain();$n' +
     '  return 0;$n' +
     '}$n';
-  PosixMainLLVM =
+  PosixNimMainLLVM =
     '@cmdCount = linkonce i32$n' +
     '@cmdLine = linkonce i8**$n' +
     '@gEnv = linkonce i8**$n' +
+    'define void @NimMain(void) {$n' +
+    '  %dummy = alloca [8 x %NI]$n' +{&}
+    CommonMainBodyLLVM +{&}
+    '}$n';
+  PosixCMainLLVM = 
     'define i32 @main(i32 %argc, i8** %args, i8** %env) {$n' +
-    '  %dummy = alloca [8 x %NI]$n' +
     '  store i8** %args, i8*** @cmdLine$n' +
     '  store i32 %argc, i32* @cmdCount$n' +
-    '  store i8** %env, i8*** @gEnv$n' +{&}
-    CommonMainBodyLLVM +{&}
+    '  store i8** %env, i8*** @gEnv$n' +
+    '  call void @NimMain()$n' +
     '  ret i32 0$n' +
+    '}$n';    
+  WinNimMain = 
+    'N_CDECL(void, NimMain)(void) {$n' +
+    '  int dummy[8];$n' +{&}
+    CommonMainBody +{&}
     '}$n';
-  WinMain =
+  WinCMain =
     'N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $n' +
     '                        HINSTANCE hPrevInstance, $n' +
     '                        LPSTR lpCmdLine, int nCmdShow) {$n' +
-    '  int dummy[8];$n' +{&}
-    CommonMainBody +{&}
+    '  NimMain();$n' +
     '  return 0;$n' +
     '}$n';
-  WinMainLLVM =
+  WinNimMainLLVM = 
+    'define void @NimMain(void) {$n' +
+    '  %dummy = alloca [8 x %NI]$n' +{&}
+    CommonMainBodyLLVM +{&}
+    '}$n';
+  WinCMainLLVM =
     'define stdcall i32 @WinMain(i32 %hCurInstance, $n' +
     '                            i32 %hPrevInstance, $n' +
     '                            i8* %lpCmdLine, i32 %nCmdShow) {$n' +
-    '  %dummy = alloca [8 x %NI]$n' +{&}
-    CommonMainBodyLLVM +{&}
+    '  call void @NimMain()$n' +
     '  ret i32 0$n' +
     '}$n';
-  WinDllMain =
+  WinNimDllMain = WinNimMain;
+  WinCDllMain =
     'BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $n' +
     '                    LPVOID lpvReserved) {$n' +
-    '  int dummy[8];$n' +{&}
-    CommonMainBody +{&}
+    '  NimMain();$n' +
     '  return 1;$n' +
     '}$n';
-  WinDllMainLLVM =
+  WinNimDllMainLLVM = WinNimMainLLVM;
+  WinCDllMainLLVM =
     'define stdcall i32 @DllMain(i32 %hinstDLL, i32 %fwdreason, $n' +
     '                            i8* %lpvReserved) {$n' +
-    '  %dummy = alloca [8 x %NI]$n' +{&}
-    CommonMainBodyLLVM +{&}
+    '  call void @NimMain()$n' +
     '  ret i32 1$n' +
     '}$n';
 var
-  frmt: TFormatStr;
+  nimMain, otherMain: TFormatStr;
 begin
   useMagic(m, 'setStackBottom');
   if (platform.targetOS = osWindows) and
       (gGlobalOptions * [optGenGuiApp, optGenDynLib] <> []) then begin
-    if optGenGuiApp in gGlobalOptions then
-      if gCmd = cmdCompileToLLVM then frmt := WinMainLLVM else frmt := WinMain
-    else
-      if gCmd = cmdCompileToLLVM then 
-        frmt := WinDllMainLLVM 
-      else 
-        frmt := WinDllMain;
+    if optGenGuiApp in gGlobalOptions then begin
+      if gCmd = cmdCompileToLLVM then begin
+        nimMain := WinNimMainLLVM; 
+        otherMain := WinCMainLLVM
+      end
+      else begin
+        nimMain := WinNimMain;
+        otherMain := WinCMain;
+      end
+    end
+    else begin
+      if gCmd = cmdCompileToLLVM then begin
+        nimMain := WinNimDllMainLLVM;
+        otherMain := WinCDllMainLLVM;
+      end
+      else begin
+        nimMain := WinNimDllMain;
+        otherMain := WinCDllMain;
+      end
+    end;
     {@discard} lists.IncludeStr(m.headerFiles, '<windows.h>')
   end
-  else 
-    if gCmd = cmdCompileToLLVM then 
-      frmt := PosixMainLLVM 
-    else 
-      frmt := PosixMain;
-  if gBreakpoints <> nil then
-    useMagic(m, 'dbgRegisterBreakpoint');
+  else begin 
+    if gCmd = cmdCompileToLLVM then begin 
+      nimMain := PosixNimMainLLVM;
+      otherMain := PosixCMainLLVM;
+    end
+    else begin
+      nimMain := PosixNimMain;
+      otherMain := PosixCMain;
+    end
+  end;
+  if gBreakpoints <> nil then useMagic(m, 'dbgRegisterBreakpoint');
   inc(m.labels);
-  appf(m.s[cfsProcs], frmt, [gBreakpoints, mainModInit, toRope(m.labels)])
+  appf(m.s[cfsProcs], nimMain, [gBreakpoints, mainModInit, toRope(m.labels)]);
+  if not (optNoMain in gGlobalOptions) then 
+    appf(m.s[cfsProcs], otherMain, []);
 end;
 
 function getInitName(m: PSym): PRope;
@@ -1101,13 +1136,6 @@ begin
   //MessageOut('cgen.myOpenCached has been called ' + filename);
   cfile := changeFileExt(completeCFilePath(filename), cExt);
   cfilenoext := changeFileExt(cfile, '');
-  (*
-  objFile := toObjFile(cfilenoext);
-  if ExistsFile(objFile) and nos.FileNewer(objFile, cfile) then begin
-  end
-  else begin
-    addFileToCompile(cfilenoext); // is to compile
-  end; *)
   addFileToLink(cfilenoext);
   registerModuleToMain(module);
   // XXX: this cannot be right here, initalization has to be appended during
@@ -1208,11 +1236,12 @@ begin
         finishModule(gPendingModules[i]);
     for i := 0 to high(gPendingModules) do writeModule(gPendingModules[i]);
     setLength(gPendingModules, 0);
-    writeMapping(gMapping);
   end;
   if not (optDeadCodeElim in gGlobalOptions) and 
       not (sfDeadCodeElim in m.module.flags) then
     writeModule(m);
+  if sfMainModule in m.module.flags then 
+    writeMapping(gMapping);  
 end;
 
 function cgenPass(): TPass;
diff --git a/nim/charsets.pas b/nim/charsets.pas
index a5f14450f..a5f14450f 100644..100755
--- a/nim/charsets.pas
+++ b/nim/charsets.pas
diff --git a/nim/commands.pas b/nim/commands.pas
index df6ab9da7..b281552c9 100644..100755
--- a/nim/commands.pas
+++ b/nim/commands.pas
@@ -63,6 +63,7 @@ const
 +{&} '  compile_to_c, cc          compile project with C code generator' +{&} nl
 +{&} '  doc                       generate the documentation for inputfile' +{&} nl
 +{&} '  rst2html                  converts a reStructuredText file to HTML' +{&} nl
++{&} '  rst2tex                   converts a reStructuredText file to TeX' +{&} nl
 +{&} 'Arguments:' +{&} nl
 +{&} '  arguments are passed to the program being run (if --run option is selected)' +{&} nl
 +{&} 'Options:' +{&} nl
@@ -112,6 +113,7 @@ const
 +{&} '  --lib:PATH                set the system library path' +{&} nl
 +{&} '  -c, --compile_only        compile only; do not assemble or link' +{&} nl
 +{&} '  --no_linking              compile but do not link' +{&} nl
++{&} '  --no_main                 do not generate a main procedure' +{&} nl
 +{&} '  --gen_script              generate a compile script (in the ''nimcache''' +{&} nl
 +{&} '                            subdirectory named ''compile_$project$scriptext'')' +{&} nl
 +{&} '  --os:SYMBOL               set the target operating system (cross-compilation)' +{&} nl
@@ -360,6 +362,10 @@ begin
     wNoLinking: begin

       expectNoArg(switch, arg, pass, info);

       include(gGlobalOptions, optNoLinking);

+    end;
+    wNoMain: begin
+      expectNoArg(switch, arg, pass, info);

+      include(gGlobalOptions, optNoMain);    
     end;

     wForceBuild, wF: begin

       expectNoArg(switch, arg, pass, info);

@@ -555,10 +561,6 @@ begin
       expectArg(switch, arg, pass, info);

       setCC(arg)

     end;

-    wMaxErr: begin

-      expectArg(switch, arg, pass, info);

-      gErrorMax := parseInt(arg);

-    end;

     else if strutils.find(switch, '.') >= strStart then

       options.setConfigVar(switch, arg)

     else

diff --git a/nim/condsyms.pas b/nim/condsyms.pas
index 465bc045e..465bc045e 100644..100755
--- a/nim/condsyms.pas
+++ b/nim/condsyms.pas
diff --git a/nim/config.inc b/nim/config.inc
index f73444a71..f73444a71 100644..100755
--- a/nim/config.inc
+++ b/nim/config.inc
diff --git a/nim/crc.pas b/nim/crc.pas
index e14716605..e14716605 100644..100755
--- a/nim/crc.pas
+++ b/nim/crc.pas
diff --git a/nim/depends.pas b/nim/depends.pas
index d8b978142..d8b978142 100644..100755
--- a/nim/depends.pas
+++ b/nim/depends.pas
diff --git a/nim/docgen.pas b/nim/docgen.pas
index a72f64908..39a9069c7 100644..100755
--- a/nim/docgen.pas
+++ b/nim/docgen.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.
@@ -24,6 +24,7 @@ uses
 
 procedure CommandDoc(const filename: string);
 procedure CommandRst2Html(const filename: string);
+procedure CommandRst2TeX(const filename: string);
 
 implementation
 
@@ -33,7 +34,7 @@ type
     refname, header: PRope;
   end;
   TSections = array [TSymKind] of PRope;
-  TMetaEnum = (metaNone, metaTitle, metaSubtitle);
+  TMetaEnum = (metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion);
   TDocumentor = record  // contains a module's documentation
     filename: string;   // filename of the source file; without extension
     basedir: string;    // base directory (where to put the documentation)
@@ -51,6 +52,9 @@ type
   end;
   PDoc = ^TDocumentor;
 
+var
+  splitter: string = '<wbr />';
+
 function findIndexNode(n: PRstNode): PRstNode;
 var
   i: int;
@@ -213,6 +217,8 @@ begin
   end
 end;
 
+// -------------------- dispatcher -------------------------------------------
+
 procedure addXmlChar(var dest: string; c: Char);
 begin
   case c of
@@ -224,6 +230,43 @@ begin
   end
 end;
 
+procedure addRtfChar(var dest: string; c: Char);
+begin
+  case c of
+    '{': add(dest, '\{');
+    '}': add(dest, '\}');
+    '\': add(dest, '\\');
+    else addChar(dest, c)
+  end
+end;
+
+procedure addTexChar(var dest: string; c: Char);
+begin
+  case c of
+    '_': add(dest, '\_');
+    '{': add(dest, '\symbol{123}');
+    '}': add(dest, '\symbol{125}');
+    '[': add(dest, '\symbol{91}');
+    ']': add(dest, '\symbol{93}');
+    '\': add(dest, '\symbol{92}');
+    '$': add(dest, '\$');
+    '&': add(dest, '\&');
+    '#': add(dest, '\#');
+    '%': add(dest, '\%');
+    '~': add(dest, '\symbol{126}');
+    '@': add(dest, '\symbol{64}');
+    '^': add(dest, '\symbol{94}');
+    '`': add(dest, '\symbol{96}');
+    else addChar(dest, c)
+  end
+end;
+
+procedure escChar(var dest: string; c: Char);
+begin
+  if gCmd <> cmdRst2Tex then addXmlChar(dest, c)
+  else addTexChar(dest, c);
+end;
+
 function nextSplitPoint(const s: string; start: int): int;
 begin
   result := start;
@@ -241,9 +284,7 @@ begin
   dec(result); // last valid index
 end;
 
-function toXml(const s: string; splitAfter: int = -1): string;
-const
-  splitter = '<wbr />';
+function esc(const s: string; splitAfter: int = -1): string;
 var
   i, j, k, partLen: int;
 begin
@@ -257,26 +298,52 @@ begin
         partLen := 0;
         add(result, splitter);
       end;
-      for i := j to k do addXmlChar(result, s[i]);
+      for i := j to k do escChar(result, s[i]);
       inc(partLen, k - j + 1);
       j := k+1;
     end;
   end
   else begin
-    for i := strStart to length(s)+strStart-1 do addXmlChar(result, s[i])
+    for i := strStart to length(s)+strStart-1 do escChar(result, s[i])
   end
 end;
 
-function renderRstToHtml(d: PDoc; n: PRstNode): PRope; forward;
+function disp(const xml, tex: string): string;
+begin  
+  if gCmd <> cmdRst2Tex then
+    result := xml
+  else
+    result := tex
+end;
+
+function dispF(const xml, tex: string; const args: array of PRope): PRope;
+begin
+  if gCmd <> cmdRst2Tex then
+    result := ropef(xml, args)
+  else
+    result := ropef(tex, args)
+end;
+
+procedure dispA(var dest: PRope; const xml, tex: string;
+                const args: array of PRope);
+begin
+  if gCmd <> cmdRst2Tex then
+    appf(dest, xml, args)
+  else
+    appf(dest, tex, args)
+end;
+
+// ---------------------------------------------------------------------------
+
+function renderRstToOut(d: PDoc; n: PRstNode): PRope; forward;
 
-function renderAux(d: PDoc; n: PRstNode; const outer: string = '$1';
-                   const inner: string = '$1'): PRope;
+function renderAux(d: PDoc; n: PRstNode; const outer: string = '$1'): PRope;
 var
   i: int;
 begin
   result := nil;
   for i := 0 to rsonsLen(n)-1 do
-    appf(result, inner, [renderRstToHtml(d, n.sons[i])]);
+    app(result, renderRstToOut(d, n.sons[i]));
   result := ropef(outer, [result]);
 end;
 
@@ -286,7 +353,8 @@ var
 begin
   if d.theIndex = nil then exit;
   h := newRstNode(rnHyperlink);
-  a := newRstNode(rnLeaf, d.indexValFilename +{&} '#' +{&} toString(id));
+  a := newRstNode(rnLeaf, d.indexValFilename +{&} disp('#'+'', '')
+                  +{&} toString(id));
   addSon(h, a);
   addSon(h, a);
   a := newRstNode(rnIdx);
@@ -299,9 +367,11 @@ var
   a, h: PRstNode;
 begin
   inc(d.id);
-  result := ropef('<em id="$1">$2</em>', [toRope(d.id), renderAux(d, n)]);
+  result := dispF('<em id="$1">$2</em>',
+                  '$2\label{$1}', [toRope(d.id), renderAux(d, n)]);
   h := newRstNode(rnHyperlink);
-  a := newRstNode(rnLeaf, d.indexValFilename +{&} '#' +{&} toString(d.id));
+  a := newRstNode(rnLeaf, d.indexValFilename +{&} disp('#'+'', '')
+                  +{&} toString(d.id));
   addSon(h, a);
   addSon(h, a);
   setIndexPair(d.theIndex, n, h);
@@ -312,10 +382,9 @@ var
   dummyHasToc: bool;
 begin
   if (n.comment <> snil) and startsWith(n.comment, '##') then
-    result := renderRstToHtml(d, rstParse(n.comment, true,
-                        toFilename(n.info),
-                        toLineNumber(n.info), toColumn(n.info),
-                        dummyHasToc))
+    result := renderRstToOut(d, rstParse(n.comment, true, toFilename(n.info),
+                                          toLineNumber(n.info),
+                                          toColumn(n.info), dummyHasToc))
   else
     result := nil;
 end;
@@ -359,9 +428,11 @@ begin
   case n.kind of
     nkPostfix: result := getName(n.sons[1], splitAfter);
     nkPragmaExpr: result := getName(n.sons[0], splitAfter);
-    nkSym: result := toXML(n.sym.name.s, splitAfter);
-    nkIdent: result := toXML(n.ident.s, splitAfter);
-    nkAccQuoted: result := '`' +{&} getName(n.sons[0], splitAfter) +{&} '`';
+    nkSym: result := esc(n.sym.name.s, splitAfter);
+    nkIdent: result := esc(n.ident.s, splitAfter);
+    nkAccQuoted:
+      result := esc('`'+'') +{&} getName(n.sons[0], splitAfter) +{&}
+                esc('`'+'');
     else begin
       internalError(n.info, 'getName()');
       result := ''
@@ -407,39 +478,47 @@ begin
     case kind of
       tkEof: break;
       tkComment:
-        appf(result, '<span class="Comment">$1</span>',
-                      [toRope(toXml(literal))]);
+        dispA(result, '<span class="Comment">$1</span>',
+                      '\spanComment{$1}',
+                      [toRope(esc(literal))]);
       tokKeywordLow..tokKeywordHigh:
-        appf(result, '<span class="Keyword">$1</span>',
+        dispA(result, '<span class="Keyword">$1</span>',
+                      '\spanKeyword{$1}',
                       [toRope(literal)]);
       tkOpr, tkHat:
-        appf(result, '<span class="Operator">$1</span>',
-                      [toRope(toXml(literal))]);
+        dispA(result, '<span class="Operator">$1</span>',
+                      '\spanOperator{$1}',
+                      [toRope(esc(literal))]);
       tkStrLit..tkTripleStrLit:
-        appf(result, '<span class="StringLit">$1</span>',
-                      [toRope(toXml(literal))]);
+        dispA(result, '<span class="StringLit">$1</span>',
+                      '\spanStringLit{$1}',
+                      [toRope(esc(literal))]);
       tkCharLit:
-        appf(result, '<span class="CharLit">$1</span>',
-                      [toRope(toXml(literal))]);
+        dispA(result, '<span class="CharLit">$1</span>',
+                      '\spanCharLit{$1}',
+                      [toRope(esc(literal))]);
       tkIntLit..tkInt64Lit:
-        appf(result, '<span class="DecNumber">$1</span>',
-                      [toRope(literal)]);
+        dispA(result, '<span class="DecNumber">$1</span>',
+                      '\spanDecNumber{$1}',
+                      [toRope(esc(literal))]);
       tkFloatLit..tkFloat64Lit:
-        appf(result, '<span class="FloatNumber">$1</span>',
-                      [toRope(literal)]);
+        dispA(result, '<span class="FloatNumber">$1</span>',
+                      '\spanFloatNumber{$1}',
+                      [toRope(esc(literal))]);
       tkSymbol:
-        appf(result, '<span class="Identifier">$1</span>',
-                      [toRope(literal)]);
-      tkInd, tkSad, tkDed, tkSpaces:
-        app(result, literal);
-        //appf(result, '<span class="Whitespace">$1</span>',
-        //              [toRope(literal)]);
+        dispA(result, '<span class="Identifier">$1</span>',
+                      '\spanIdentifier{$1}',
+                      [toRope(esc(literal))]);
+      tkInd, tkSad, tkDed, tkSpaces: begin
+        app(result, literal)
+      end;
       tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
       tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi,
       tkParDotLe, tkParDotRi, tkComma, tkSemiColon, tkColon,
       tkEquals, tkDot, tkDotDot, tkAccent:
-        appf(result, '<span class="Other">$1</span>',
-                      [toRope(literal)]);
+        dispA(result, '<span class="Other">$1</span>',
+                      '\spanOther{$1}',
+                      [toRope(esc(literal))]);
       else InternalError(n.info, 'docgen.genThing(' + toktypeToStr[kind] + ')');
     end
   end;
@@ -460,7 +539,7 @@ var
 begin
   result := nil;
   for i := 0 to rsonsLen(n)-1 do
-    app(result, renderRstToHtml(d, n.sons[i]));
+    app(result, renderRstToOut(d, n.sons[i]));
   refname := toRope(rstnodeToRefname(n));
   if d.hasToc then begin
     len := length(d.tocPart);
@@ -468,13 +547,17 @@ begin
     d.tocPart[len].refname := refname;
     d.tocPart[len].n := n;
     d.tocPart[len].header := result;
-    result := ropef('<h$1><a class="toc-backref" id="$2" href="#$2_toc">$3'+
-                         '</a></h$1>',
-                         [toRope(n.level), d.tocPart[len].refname, result]);
+    result := dispF(
+      '<h$1><a class="toc-backref" id="$2" href="#$2_toc">$3</a></h$1>',
+      '\rsth$4{$3}\label{$2}$n',
+      [toRope(n.level), d.tocPart[len].refname, result,
+       toRope(chr(n.level-1+ord('A'))+'')]);
   end
   else
-    result := ropef('<h$1 id="$2">$3</h$1>',
-                         [toRope(n.level), refname, result]);
+    result := dispF('<h$1 id="$2">$3</h$1>',
+                    '\rsth$4{$3}\label{$2}$n',
+                    [toRope(n.level), refname, result,
+                     toRope(chr(n.level-1+ord('A'))+'')]);
 end;
 
 function renderOverline(d: PDoc; n: PRstNode): PRope;
@@ -484,13 +567,15 @@ var
 begin
   t := nil;
   for i := 0 to rsonsLen(n)-1 do
-    app(t, renderRstToHtml(d, n.sons[i]));
+    app(t, renderRstToOut(d, n.sons[i]));
   result := nil;
   if d.meta[metaTitle] = nil then d.meta[metaTitle] := t
   else if d.meta[metaSubtitle] = nil then d.meta[metaSubtitle] := t
   else
-    result := ropef('<h$1 id="$2"><center>$3</center></h$1>',
-                         [toRope(n.level), toRope(rstnodeToRefname(n)), t]);
+    result := dispF('<h$1 id="$2"><center>$3</center></h$1>',
+                    '\rstov$4{$3}\label{$2}$n',
+                    [toRope(n.level), toRope(rstnodeToRefname(n)), t,
+                     toRope(chr(n.level-1+ord('A'))+'')]);
 end;
 
 function renderRstToRst(d: PDoc; n: PRstNode): PRope; forward;
@@ -645,8 +730,10 @@ end;
 
 function renderTocEntry(d: PDoc; const e: TTocEntry): PRope;
 begin
-  result := ropef('<li><a class="reference" id="$1_toc" href="#$1">$2' +
-                       '</a></li>$n', [e.refname, e.header]);
+  result := dispF(
+    '<li><a class="reference" id="$1_toc" href="#$1">$2</a></li>$n',
+    '\item\label{$1_toc} $2\ref{$1}$n',
+    [e.refname, e.header]);
 end;
 
 function renderTocEntries(d: PDoc; var j: int; lvl: int): PRope;
@@ -666,7 +753,8 @@ begin
       break
   end;
   if lvl > 1 then
-    result := ropef('<ul class="simple">$1</ul>', [result]);
+    result := dispF('<ul class="simple">$1</ul>',
+                    '\begin{enumerate}$1\end{enumerate}', [result]);
 end;
 
 function fieldAux(const s: string): PRope;
@@ -676,21 +764,28 @@ end;
 
 function renderImage(d: PDoc; n: PRstNode): PRope;
 var
-  s: string;
+  s, scale: string;
+  options: PRope;
 begin
-  result := ropef('<img src="$1"', [toRope(getArgument(n))]);
+  options := nil;
+  s := getFieldValue(n, 'scale');
+  if s <> '' then dispA(options, ' scale="$1"', ' scale=$1', [fieldAux(scale)]);
+  
   s := getFieldValue(n, 'height');
-  if s <> '' then appf(result, ' height="$1"', [fieldAux(s)]);
+  if s <> '' then dispA(options, ' height="$1"', ' height=$1', [fieldAux(s)]);
+  
   s := getFieldValue(n, 'width');
-  if s <> '' then appf(result, ' width="$1"', [fieldAux(s)]);
-  s := getFieldValue(n, 'scale');
-  if s <> '' then appf(result, ' scale="$1"', [fieldAux(s)]);
+  if s <> '' then dispA(options, ' width="$1"', ' width=$1', [fieldAux(s)]);
+  
   s := getFieldValue(n, 'alt');
-  if s <> '' then appf(result, ' alt="$1"', [fieldAux(s)]);
+  if s <> '' then dispA(options, ' alt="$1"', '', [fieldAux(s)]);
   s := getFieldValue(n, 'align');
-  if s <> '' then appf(result, ' align="$1"', [fieldAux(s)]);
-  app(result, ' />');
-  if rsonsLen(n) >= 3 then app(result, renderRstToHtml(d, n.sons[2]))
+  if s <> '' then dispA(options, ' align="$1"', '', [fieldAux(s)]);
+    
+  if options <> nil then options := dispF('$1', '[$1]', [options]);
+  result := dispF('<img src="$1"$2 />',
+    '\includegraphics$2{$1}', [toRope(getArgument(n)), options]);
+  if rsonsLen(n) >= 3 then app(result, renderRstToOut(d, n.sons[2]))
 end;
 
 function renderCodeBlock(d: PDoc; n: PRstNode): PRope;
@@ -709,7 +804,7 @@ begin
   else lang := getSourceLanguage(langstr);
   if lang = langNone then begin
     rawMessage(warnLanguageXNotSupported, langstr);
-    result := ropef('<pre>$1</pre>', [toRope(m.text)])
+    result := toRope(m.text)
   end
   else begin
     initGeneralTokenizer(g, m.text);
@@ -717,164 +812,220 @@ begin
       getNextToken(g, lang);
       case g.kind of
         gtEof: break;
-        gtNone, gtWhitespace:
+        gtNone, gtWhitespace: begin
           app(result, ncopy(m.text, g.start+strStart,
-                            g.len+g.start-1+strStart));
+                            g.len+g.start-1+strStart))
+        end
         else
-          appf(result, '<span class="$2">$1</span>',
-            [toRope(toXml(ncopy(m.text, g.start+strStart,
-                                g.len+g.start-1+strStart))),
-             toRope(tokenClassToStr[g.kind])]);
+          dispA(result,
+                '<span class="$2">$1</span>',
+                '\span$2{$1}',
+                [toRope(esc(ncopy(m.text, g.start+strStart,
+                                  g.len+g.start-1+strStart))),
+                 toRope(tokenClassToStr[g.kind])]);
       end;
     end;
     deinitGeneralTokenizer(g);
-    if result <> nil then result := ropef('<pre>$1</pre>', [result]);
-  end
+  end;
+  if result <> nil then
+    result := dispF('<pre>$1</pre>', '\begin{rstpre}$n$1$n\end{rstpre}$n',
+                    [result])
 end;
 
 function renderContainer(d: PDoc; n: PRstNode): PRope;
 var
   arg: PRope;
 begin
-  result := renderRstToHtml(d, n.sons[2]);
+  result := renderRstToOut(d, n.sons[2]);
   arg := toRope(strip(getArgument(n)));
-  if arg = nil then result := ropef('<div>$1</div>', [result])
-  else result := ropef('<div class="$1">$2</div>', [arg, result])  
+  if arg = nil then result := dispF('<div>$1</div>', '$1', [result])
+  else result := dispF('<div class="$1">$2</div>', '$2', [arg, result])  
+end;
+
+function texColumns(n: PRstNode): string;
+var
+  i: int;
+begin
+  result := '';
+  for i := 1 to rsonsLen(n) do add(result, '|X');
+end;
+
+function renderField(d: PDoc; n: PRstNode): PRope;
+var
+  fieldname: string;
+  fieldval: PRope;
+  b: bool;
+begin
+  b := false;
+  if gCmd = cmdRst2Tex then begin
+    fieldname := addNodes(n.sons[0]);
+    fieldval := toRope(esc(strip(addNodes(n.sons[1]))));
+    if cmpIgnoreStyle(fieldname, 'author') = 0 then begin
+      if d.meta[metaAuthor] = nil then begin
+        d.meta[metaAuthor] := fieldval;
+        b := true
+      end
+    end
+    else if cmpIgnoreStyle(fieldName, 'version') = 0 then begin
+      if d.meta[metaVersion] = nil then begin
+        d.meta[metaVersion] := fieldval;
+        b := true
+      end
+    end
+  end;
+  if b then result := nil
+  else result := renderAux(d, n, disp('<tr>$1</tr>$n', '$1'));
 end;
 
-function renderRstToHtml(d: PDoc; n: PRstNode): PRope;
+function renderRstToOut(d: PDoc; n: PRstNode): PRope;
 var
-  outer, inner: string;
+  i: int;
 begin
   if n = nil then begin result := nil; exit end;
-  outer := '$1';
-  inner := '$1';
   case n.kind of
-    rnInner: begin end;
-    rnHeadline: begin
-      result := renderHeadline(d, n); exit;
-    end;
-    rnOverline: begin
-      result := renderOverline(d, n);
-      exit;
-    end;
-    rnTransition: outer := '<hr />'+nl;
-    rnParagraph: outer := '<p>$1</p>'+nl;
-    rnBulletList: outer := '<ul class="simple">$1</ul>'+nl;
-    rnBulletItem, rnEnumItem: outer := '<li>$1</li>'+nl;
-    rnEnumList: outer := '<ol class="simple">$1</ol>'+nl;
-    rnDefList: outer := '<dl class="docutils">$1</dl>'+nl;
-    rnDefItem: begin end;
-    rnDefName: outer := '<dt>$1</dt>'+nl;
-    rnDefBody: outer := '<dd>$1</dd>'+nl;
-    rnFieldList:
-      outer := '<table class="docinfo" frame="void" rules="none">' +
-               '<col class="docinfo-name" />' +
-               '<col class="docinfo-content" />' +
-               '<tbody valign="top">$1' +
-               '</tbody></table>';
-    rnField: outer := '<tr>$1</tr>$n';
-    rnFieldName: outer := '<th class="docinfo-name">$1:</th>';
-    rnFieldBody: outer := '<td>$1</td>';
-    rnIndex: begin
-      result := renderRstToHtml(d, n.sons[2]);
-      exit
+    rnInner: result := renderAux(d, n);
+    rnHeadline: result := renderHeadline(d, n);
+    rnOverline: result := renderOverline(d, n);
+    rnTransition:
+      result := renderAux(d, n, disp('<hr />'+nl, '\hrule'+nl));
+    rnParagraph:
+      result := renderAux(d, n, disp('<p>$1</p>'+nl, '$1$n$n'));
+    rnBulletList:
+      result := renderAux(d, n, disp('<ul class="simple">$1</ul>'+nl,
+                                '\begin{itemize}$1\end{itemize}'+nl));
+    rnBulletItem, rnEnumItem:
+      result := renderAux(d, n, disp('<li>$1</li>'+nl, '\item $1'+nl));
+    rnEnumList:
+      result := renderAux(d, n, disp('<ol class="simple">$1</ol>'+nl,
+                                     '\begin{enumerate}$1\end{enumerate}'+nl));
+    rnDefList: 
+      result := renderAux(d, n, disp('<dl class="docutils">$1</dl>'+nl,
+                        '\begin{description}$1\end{description}'+nl));
+    rnDefItem: 
+      result := renderAux(d, n);
+    rnDefName:
+      result := renderAux(d, n, disp('<dt>$1</dt>'+nl, '\item[$1] '));
+    rnDefBody:
+      result := renderAux(d, n, disp('<dd>$1</dd>'+nl, '$1'+nl));
+    rnFieldList: begin
+      result := nil;
+      for i := 0 to rsonsLen(n)-1 do app(result, renderRstToOut(d, n.sons[i]));
+      if result <> nil then
+        result := dispf('<table class="docinfo" frame="void" rules="none">' +
+                        '<col class="docinfo-name" />' +
+                        '<col class="docinfo-content" />' +
+                        '<tbody valign="top">$1' +
+                        '</tbody></table>',
+                        '\begin{description}$1\end{description}'+nl, [result]);
     end;
+    rnField: result := renderField(d, n);
+    rnFieldName:
+      result := renderAux(d, n, disp(
+                  '<th class="docinfo-name">$1:</th>', '\item[$1:]'));
+    rnFieldBody:
+      result := renderAux(d, n, disp('<td>$1</td>', ' $1$n'));
+    rnIndex:
+      result := renderRstToOut(d, n.sons[2]);
 
     rnOptionList:
-      outer := '<table frame="void">$1</table>';
+      result := renderAux(d, n, disp('<table frame="void">$1</table>',
+                    '\begin{description}$n$1\end{description}'+nl));
     rnOptionListItem:
-      outer := '<tr>$1</tr>$n';
-    rnOptionGroup: outer := '<th align="left">$1</th>';
-    rnDescription: outer := '<td align="left">$1</td>$n';
+      result := renderAux(d, n, disp('<tr>$1</tr>$n', '$1'));
+    rnOptionGroup:
+      result := renderAux(d, n, disp('<th align="left">$1</th>', '\item[$1]'));
+    rnDescription:
+      result := renderAux(d, n, disp('<td align="left">$1</td>$n', ' $1$n'));
     rnOption,
     rnOptionString,
-    rnOptionArgument: InternalError('renderRstToHtml');
+    rnOptionArgument: InternalError('renderRstToOut');
 
-    rnLiteralBlock: outer := '<pre>$1</pre>'+nl;
-    rnQuotedLiteralBlock: InternalError('renderRstToHtml');
+    rnLiteralBlock: 
+      result := renderAux(d, n, disp('<pre>$1</pre>$n',
+                                     '\begin{rstpre}$n$1$n\end{rstpre}$n'));
+    rnQuotedLiteralBlock: InternalError('renderRstToOut');
 
-    rnLineBlock: outer := '<p>$1</p>';
-    rnLineBlockItem: outer := '$1<br />';
+    rnLineBlock: result := renderAux(d, n, disp('<p>$1</p>', '$1$n$n'));
+    rnLineBlockItem: result := renderAux(d, n, disp('$1<br />', '$1\\$n'));
 
-    rnBlockQuote: outer := '<blockquote><p>$1</p></blockquote>$n';
+    rnBlockQuote:
+      result := renderAux(d, n, disp('<blockquote><p>$1</p></blockquote>$n',
+                                     '\begin{quote}$1\end{quote}$n'));
 
-    rnTable, rnGridTable:
-      outer := '<table border="1" class="docutils">$1</table>';
-    rnTableRow: outer := '<tr>$1</tr>$n';
-    rnTableDataCell: outer := '<td>$1</td>';
-    rnTableHeaderCell: outer := '<th>$1</th>';
+    rnTable, rnGridTable: begin
+      result := renderAux(d, n,
+                          disp('<table border="1" class="docutils">$1</table>',
+                               '\begin{table}\begin{rsttab}{' +{&}
+                               texColumns(n) +{&}
+                               '|}$n\hline$n$1\end{rsttab}\end{table}'));
+    end;
+    rnTableRow: begin
+      if rsonsLen(n) >= 1 then begin
+        result := renderRstToOut(d, n.sons[0]);
+        for i := 1 to rsonsLen(n)-1 do
+          dispa(result, '$1', ' & $1', [renderRstToOut(d, n.sons[i])]);
+        result := dispf('<tr>$1</tr>$n', '$1\\$n\hline$n', [result]);
+      end
+      else
+        result := nil;
+    end;
+    rnTableDataCell: result := renderAux(d, n, disp('<td>$1</td>', '$1'));
+    rnTableHeaderCell:
+      result := renderAux(d, n, disp('<th>$1</th>', '\textbf{$1}'));
 
-    rnLabel: InternalError('renderRstToHtml'); // used for footnotes and other
-    rnFootnote: InternalError('renderRstToHtml'); // a footnote
+    rnLabel: InternalError('renderRstToOut'); // used for footnotes and other
+    rnFootnote: InternalError('renderRstToOut'); // a footnote
 
-    rnCitation: InternalError('renderRstToHtml');    // similar to footnote
-    rnRef: begin
-      result := ropef('<a class="reference external" href="#$2">$1</a>',
-                           [renderAux(d, n), toRope(rstnodeToRefname(n))]);
-      exit
-    end;
+    rnCitation: InternalError('renderRstToOut');    // similar to footnote
+    rnRef: 
+      result := dispF('<a class="reference external" href="#$2">$1</a>',
+                      '$1\ref{$2}',
+                      [renderAux(d, n), toRope(rstnodeToRefname(n))]);
     rnStandaloneHyperlink:
-      outer := '<a class="reference external" href="$1">$1</a>';
-    rnHyperlink: begin
-      result := ropef('<a class="reference external" href="$2">$1</a>',
-                           [renderRstToHtml(d, n.sons[0]),
-                            renderRstToHtml(d, n.sons[1])]);
-      exit
-    end;
-    rnDirArg, rnRaw: begin end;
-    rnImage, rnFigure: begin
-      result := renderImage(d, n);
-      exit
-    end;
-    rnCodeBlock: begin
-      result := renderCodeBlock(d, n);
-      exit
-    end;
-    rnContainer: begin 
-      result := renderContainer(d, n);
-      exit
-    end;
-    rnSubstitutionReferences, rnSubstitutionDef: outer := '|$1|';
-    rnDirective: outer := '';
+      result := renderAux(d, n, disp(
+                    '<a class="reference external" href="$1">$1</a>',
+                    '\href{$1}{$1}'));
+    rnHyperlink: 
+      result := dispF('<a class="reference external" href="$2">$1</a>',
+                      '\href{$2}{$1}',
+                      [renderRstToOut(d, n.sons[0]),
+                       renderRstToOut(d, n.sons[1])]);
+    rnDirArg, rnRaw: result := renderAux(d, n);
+    rnImage, rnFigure: result := renderImage(d, n);
+    rnCodeBlock: result := renderCodeBlock(d, n);
+    rnContainer: result := renderContainer(d, n);
+    rnSubstitutionReferences, rnSubstitutionDef:
+      result := renderAux(d, n, disp('|$1|', '|$1|'));
+    rnDirective: result := renderAux(d, n, '');
 
     // Inline markup:
-    rnGeneralRole: begin
-      result := ropef('<span class="$2">$1</span>',
-                           [renderRstToHtml(d, n.sons[0]),
-                            renderRstToHtml(d, n.sons[1])]);
-      exit
-    end;
-    rnSub: outer := '<sub>$1</sub>';
-    rnSup: outer := '<sup>$1</sup>';
-    rnEmphasis: outer := '<em>$1</em>';
-    rnStrongEmphasis: outer := '<strong>$1</strong>';
-    rnInterpretedText: outer := '<cite>$1</cite>';
+    rnGeneralRole: 
+      result := dispF('<span class="$2">$1</span>',
+                      '\span$2{$1}',
+                      [renderRstToOut(d, n.sons[0]),
+                       renderRstToOut(d, n.sons[1])]);
+    rnSub: result := renderAux(d, n, disp('<sub>$1</sub>', '\rstsub{$1}'));
+    rnSup: result := renderAux(d, n, disp('<sup>$1</sup>', '\rstsup{$1}'));
+    rnEmphasis: result := renderAux(d, n, disp('<em>$1</em>', '\emph{$1}'));
+    rnStrongEmphasis:
+      result := renderAux(d, n, disp('<strong>$1</strong>', '\textbf{$1}'));
+    rnInterpretedText:
+      result := renderAux(d, n, disp('<cite>$1</cite>', '\emph{$1}'));
     rnIdx: begin
       if d.theIndex = nil then
-        outer := '<em>$1</em>'
-      else begin
-        result := renderIndexTerm(d, n); exit
-      end
+        result := renderAux(d, n, disp('<em>$1</em>', '\emph{$1}'))
+      else
+        result := renderIndexTerm(d, n);
     end;
     rnInlineLiteral:
-      outer := '<tt class="docutils literal"><span class="pre">'
-             +{&} '$1</span></tt>';
-    rnLeaf: begin
-      result := toRope(toXml(n.text));
-      exit
-    end;
-    rnContents: begin
-      d.hasToc := true;
-      exit;
-    end;
-    rnTitle: begin
-      d.meta[metaTitle] := renderRstToHtml(d, n.sons[0]);
-      exit
-    end;
-    else InternalError('renderRstToHtml');
-  end;
-  result := renderAux(d, n, outer, inner);
+      result := renderAux(d, n, disp(
+        '<tt class="docutils literal"><span class="pre">$1</span></tt>',
+        '\texttt{$1}'));
+    rnLeaf: result := toRope(esc(n.text));
+    rnContents: d.hasToc := true;
+    rnTitle: d.meta[metaTitle] := renderRstToOut(d, n.sons[0]);
+    else InternalError('renderRstToOut');
+  end
 end;
 
 procedure generateDoc(d: PDoc; n: PNode);
@@ -929,7 +1080,7 @@ begin
     [toRope(ord(kind)), title, toRope(ord(kind)+50), d.toc[kind]]);
 end;
 
-function genHtmlFile(d: PDoc): PRope;
+function genOutFile(d: PDoc): PRope;
 var
   code, toc, title, content: PRope;
   bodyname: string;
@@ -947,8 +1098,7 @@ begin
   end;
   if toc <> nil then
     toc := ropeFormatNamedVars(getConfigVar('doc.toc'), ['content'], [toc]);
-  for i := low(TSymKind) to high(TSymKind) do
-    app(code, d.section[i]);
+  for i := low(TSymKind) to high(TSymKind) do app(code, d.section[i]);
   if d.meta[metaTitle] <> nil then
     title := d.meta[metaTitle]
   else
@@ -962,9 +1112,10 @@ begin
     [title, toc, d.modDesc, toRope(getDateStr()), toRope(getClockStr()), code]);
   if not (optCompileOnly in gGlobalOptions) then
     code := ropeFormatNamedVars(getConfigVar('doc.file'),
-      ['title', 'tableofcontents', 'moduledesc', 'date', 'time', 'content'],
-      [title, toc, d.modDesc,
-       toRope(getDateStr()), toRope(getClockStr()), content])
+      ['title', 'tableofcontents', 'moduledesc', 'date', 'time',
+       'content', 'author', 'version'],
+      [title, toc, d.modDesc, toRope(getDateStr()), toRope(getClockStr()),
+       content, d.meta[metaAuthor], d.meta[metaVersion]])
   else
     code := content;
   result := code;
@@ -989,11 +1140,11 @@ begin
   initIndexFile(d);
   d.hasToc := true;
   generateDoc(d, ast);
-  writeRope(genHtmlFile(d), getOutFile(filename, HtmlExt));
+  writeRope(genOutFile(d), getOutFile(filename, HtmlExt));
   generateIndex(d);
 end;
 
-procedure CommandRst2Html(const filename: string);
+procedure CommandRstAux(const filename, outExt: string);
 var
   filen: string;
   d: PDoc;
@@ -1004,10 +1155,21 @@ begin
   d := newDocumentor(filen);
   initIndexFile(d);
   rst := rstParse(readFile(filen), false, filen, 0, 1, d.hasToc);
-  d.modDesc := renderRstToHtml(d, rst);
-  code := genHtmlFile(d);
-  writeRope(code, getOutFile(filename, HtmlExt));
+  d.modDesc := renderRstToOut(d, rst);
+  code := genOutFile(d);
+  writeRope(code, getOutFile(filename, outExt));
   generateIndex(d);
 end;
 
+procedure CommandRst2Html(const filename: string);
+begin
+  CommandRstAux(filename, HtmlExt);
+end;
+
+procedure CommandRst2TeX(const filename: string);
+begin
+  splitter := '\-';
+  CommandRstAux(filename, TexExt);
+end;
+
 end.
diff --git a/nim/ecmasgen.pas b/nim/ecmasgen.pas
index 9ffa550ae..73faa4ddb 100644..100755
--- a/nim/ecmasgen.pas
+++ b/nim/ecmasgen.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.
@@ -108,10 +108,13 @@ const
                           tyOpenArray, tySet, tyVar, tyRef, tyPtr];
 
 function mapType(typ: PType): TEcmasTypeKind;
+var
+  t: PType;
 begin
-  case skipTypes(typ, abstractInst).kind of
+  t := skipTypes(typ, abstractInst);
+  case t.kind of
     tyVar, tyRef, tyPtr: begin
-      if typ.sons[0].kind in mappedToObject then
+      if skipTypes(t.sons[0], abstractInst).kind in mappedToObject then
         result := etyObject
       else
         result := etyBaseIndex
@@ -120,7 +123,7 @@ begin
       // treat a tyPointer like a typed pointer to an array of bytes
       result := etyInt;
     end;
-    tyRange, tyAbstract, tyOrdinal: result := mapType(typ.sons[0]);
+    tyRange, tyDistinct, tyOrdinal: result := mapType(t.sons[0]);
     tyInt..tyInt64, tyEnum, tyChar:
       result := etyInt;
     tyBool: result := etyBool;
@@ -133,7 +136,8 @@ begin
     tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray:
       result := etyObject;
     tyNil: result := etyNull;
-    tyGenericInst, tyGenericParam, tyGeneric, tyNone, tyForward, tyEmpty:
+    tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation,
+    tyNone, tyForward, tyEmpty, tyExpr, tyStmt, tyTypeDesc:
       result := etyNone;
     tyProc: result := etyProc;
     tyCString: result := etyString;
@@ -299,7 +303,7 @@ begin
   result := ropef('NTI$1', [toRope(t.id)]);
   if IntSetContainsOrIncl(p.globals.TypeInfoGenerated, t.id) then exit;
   case t.kind of 
-    tyAbstract: result := genTypeInfo(p, typ.sons[0]);
+    tyDistinct: result := genTypeInfo(p, typ.sons[0]);
     tyPointer, tyProc, tyBool, tyChar, tyCString, tyString,
     tyInt..tyFloat128: begin
       s := ropef(
@@ -889,7 +893,8 @@ const
                                nkFloatLit..nkFloat64Lit,
                                nkCurly, nkPar, 
                                nkStringToCString, nkCStringToString,
-                               nkCall, nkCommand, nkHiddenCallConv];
+                               nkCall, nkCommand, nkHiddenCallConv,
+                               nkCallStrLit];
 
 function needsNoCopy(y: PNode): bool;
 begin
@@ -1772,7 +1777,7 @@ begin
     end;
     nkBlockExpr: genBlock(p, n, r);
     nkIfExpr: genIfExpr(p, n, r);
-    nkCall, nkHiddenCallConv, nkCommand: begin
+    nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit: begin
       if (n.sons[0].kind = nkSym) and (n.sons[0].sym.magic <> mNone) then
         genMagic(p, n, r)
       else
diff --git a/nim/evals.pas b/nim/evals.pas
index d522dfaf0..b88fa3304 100644..100755
--- a/nim/evals.pas
+++ b/nim/evals.pas
@@ -278,11 +278,13 @@ begin
   case t.kind of
     tyBool, tyChar, tyInt..tyInt64: result := newNodeIT(nkIntLit, info, t);
     tyFloat..tyFloat128: result := newNodeIt(nkFloatLit, info, t);
-    tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString:
+    tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,
+    tyStmt, tyTypeDesc:
       result := newNodeIT(nkNilLit, info, t);
     tyObject: begin
       result := newNodeIT(nkPar, info, t);
       internalError(info, 'init to implement');
+      // XXX
     end;
     tyArray, tyArrayConstr: begin
       result := newNodeIT(nkBracket, info, t);
@@ -1283,7 +1285,7 @@ begin
     nkType..pred(nkNilLit): result := copyNode(n);
     nkNilLit: result := n; // end of atoms
 
-    nkCall, nkHiddenCallConv, nkMacroStmt, nkCommand: 
+    nkCall, nkHiddenCallConv, nkMacroStmt, nkCommand, nkCallStrLit: 
       result := evalMagicOrCall(c, n);
     nkCurly, nkBracket, nkRange: begin
       a := copyNode(n);
diff --git a/nim/extccomp.pas b/nim/extccomp.pas
index a3e4ff367..9e7c7e4cc 100644..100755
--- a/nim/extccomp.pas
+++ b/nim/extccomp.pas
@@ -27,7 +27,8 @@ type
   TInfoCCProp = ( // properties of the C compiler:
     hasSwitchRange,  // CC allows ranges in switch statements (GNU C extension)
     hasComputedGoto, // CC has computed goto (GNU C extension)
-    hasCpp           // CC is/contains a C++ compiler
+    hasCpp,          // CC is/contains a C++ compiler
+    hasAssume        // CC has __assume (Visual C extension)
   );
   TInfoCCProps = set of TInfoCCProp;
   TInfoCC = record{@tuple}
@@ -167,7 +168,7 @@ const
       debug: ' /GZ /Zi ';
       pic: '';
       asmStmtFrmt: '__asm{$n$1$n}$n';
-      props: {@set}[hasCpp];
+      props: {@set}[hasCpp, hasAssume];
     ),
     (
       name: 'tcc';
diff --git a/nim/hashtest.pas b/nim/hashtest.pas
index 7e93ca5bf..7e93ca5bf 100644..100755
--- a/nim/hashtest.pas
+++ b/nim/hashtest.pas
diff --git a/nim/highlite.pas b/nim/highlite.pas
index 1867268d3..ec5374663 100644..100755
--- a/nim/highlite.pas
+++ b/nim/highlite.pas
@@ -134,14 +134,19 @@ end;
 
 procedure initGeneralTokenizer(var g: TGeneralTokenizer;
                                const buf: string);
+var
+  pos: int;
 begin
 {@ignore} fillChar(g, sizeof(g), 0); {@emit}
   g.buf := PChar(buf);
   g.kind := low(TTokenClass);
   g.start := 0;
   g.len := 0;
-  g.pos := 0;
   g.state := low(TTokenClass);
+  pos := 0;
+  // skip initial whitespace:
+  while g.buf[pos] in [' ', #9..#13] do inc(pos);
+  g.pos := pos;
 end;
 
 procedure deinitGeneralTokenizer(var g: TGeneralTokenizer);
diff --git a/nim/idents.pas b/nim/idents.pas
index c1c1755e9..c1c1755e9 100644..100755
--- a/nim/idents.pas
+++ b/nim/idents.pas
diff --git a/nim/importer.pas b/nim/importer.pas
index fdb72fd4b..fdb72fd4b 100644..100755
--- a/nim/importer.pas
+++ b/nim/importer.pas
diff --git a/nim/interact.pas b/nim/interact.pas
index aab3c7fc2..aab3c7fc2 100644..100755
--- a/nim/interact.pas
+++ b/nim/interact.pas
diff --git a/nim/lexbase.pas b/nim/lexbase.pas
index 2b056c04f..2b056c04f 100644..100755
--- a/nim/lexbase.pas
+++ b/nim/lexbase.pas
diff --git a/nim/lists.pas b/nim/lists.pas
index e3442eb29..e3442eb29 100644..100755
--- a/nim/lists.pas
+++ b/nim/lists.pas
diff --git a/nim/llstream.pas b/nim/llstream.pas
index df4c823a6..df4c823a6 100644..100755
--- a/nim/llstream.pas
+++ b/nim/llstream.pas
diff --git a/nim/llvmdyn.pas b/nim/llvmdyn.pas
index 34839a1c8..e039939e5 100644..100755
--- a/nim/llvmdyn.pas
+++ b/nim/llvmdyn.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.
diff --git a/nim/llvmstat.pas b/nim/llvmstat.pas
index e7d06a284..e7d06a284 100644..100755
--- a/nim/llvmstat.pas
+++ b/nim/llvmstat.pas
diff --git a/nim/lookups.pas b/nim/lookups.pas
index d106ef302..5caceaf46 100644..100755
--- a/nim/lookups.pas
+++ b/nim/lookups.pas
@@ -72,7 +72,7 @@ begin
       liMessage(s.info, errImplOfXexpected, getSymRepr(s))
     else if ([sfUsed, sfInInterface] * s.flags = []) and
             (optHints in s.options) then // BUGFIX: check options in s!
-      if not (s.kind in [skForVar, skParam]) then
+      if not (s.kind in [skForVar, skParam, skUnknown]) then
         liMessage(s.info, hintXDeclaredButNotUsed, getSymRepr(s));
     s := NextIter(it, tab.stack[tab.tos-1]);
   end;
@@ -103,7 +103,7 @@ begin
   if not (fn.kind in OverloadableSyms) then
     InternalError(fn.info, 'addOverloadableSymAt');
   check := StrTableGet(c.tab.stack[at], fn.name);
-  if (check <> nil) and (check.Kind <> fn.kind) then
+  if (check <> nil) and not (check.Kind in OverloadableSyms) then
     liMessage(fn.info, errAttemptToRedefine, fn.Name.s);
   SymTabAddAt(c.tab, fn, at);
 end;
@@ -136,17 +136,16 @@ function lookUp(c: PContext; n: PNode): PSym;
 begin
   case n.kind of
     nkAccQuoted: result := lookup(c, n.sons[0]);
-    nkSym: begin
+    nkSym: begin (*
       result := SymtabGet(c.Tab, n.sym.name);
       if result = nil then
-        liMessage(n.info, errUndeclaredIdentifier, n.sym.name.s);
-      //include(result.flags, sfUsed);
+        liMessage(n.info, errUndeclaredIdentifier, n.sym.name.s); *)
+      result := n.sym;
     end;
     nkIdent: begin
       result := SymtabGet(c.Tab, n.ident);
       if result = nil then
         liMessage(n.info, errUndeclaredIdentifier, n.ident.s);
-      //include(result.flags, sfUsed);
     end
     else InternalError(n.info, 'lookUp');
   end;
@@ -169,12 +168,13 @@ begin
           and IntSetContains(c.AmbiguousSymbols, result.id) then
         liMessage(n.info, errUseQualifier, n.ident.s)
     end;
-    nkSym: begin
+    nkSym: begin (*
       result := SymtabGet(c.Tab, n.sym.name);
       if result = nil then
         liMessage(n.info, errUndeclaredIdentifier, n.sym.name.s)
-      else if ambiguousCheck
-          and IntSetContains(c.AmbiguousSymbols, result.id) then
+      else *)
+      result := n.sym;
+      if ambiguousCheck and IntSetContains(c.AmbiguousSymbols, result.id) then
         liMessage(n.info, errUseQualifier, n.sym.name.s)
     end;
     nkDotExpr, nkQualified: begin
diff --git a/nim/magicsys.pas b/nim/magicsys.pas
index db801d5f2..d9dde8871 100644..100755
--- a/nim/magicsys.pas
+++ b/nim/magicsys.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.
diff --git a/nim/main.pas b/nim/main.pas
index b1c58c2b9..1bb2ce586 100644..100755
--- a/nim/main.pas
+++ b/nim/main.pas
@@ -375,6 +375,12 @@ begin
       wantFile(filename);
       CommandRst2Html(filename);
     end;
+    wRst2tex: begin
+      gCmd := cmdRst2tex;
+      LoadSpecialConfig(DocTexConfig);
+      wantFile(filename);
+      CommandRst2TeX(filename);
+    end;
     wPas: begin
       gCmd := cmdPas;
       wantFile(filename);
diff --git a/nim/msgs.pas b/nim/msgs.pas
index 0f47695af..9d421a5bf 100644..100755
--- a/nim/msgs.pas
+++ b/nim/msgs.pas
@@ -1,54 +1,54 @@
-//

-//

-//           The Nimrod Compiler

-//        (c) Copyright 2009 Andreas Rumpf

-//

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

-//    distribution, for details about the copyright.

-//

-unit msgs;

-

-interface

-

-{$include 'config.inc'}

-

-uses

-  nsystem, options, strutils, nos;

-

-//[[[cog

-//from string import replace

-//enum = "type\n  TMsgKind = (\n"

-//msgs = "const\n  MsgKindToStr: array [TMsgKind] of string = (\n"

-//warns = "const\n  WarningsToStr: array [0..%d] of string = (\n"

-//hints = "const\n  HintsToStr: array [0..%d] of string = (\n"

-//w = 0 # counts the warnings

-//h = 0 # counts the hints

-//

-//for elem in eval(open('data/messages.yml').read()):

-//  for key, val in elem.items():

-//    enum = enum + '    %s,\n' % key

-//    v = replace(val, "'", "''")

-//    if key[0:4] == 'warn':

-//      msgs = msgs +  "    '%s [%s]',\n" % (v, key[4:])

-//      warns = warns + "    '%s',\n" % key[4:]

-//      w = w + 1

-//    elif key[0:4] == 'hint':

-//      msgs = msgs + "    '%s [%s]',\n" % (v, key[4:])

-//      hints = hints + "    '%s',\n" % key[4:]

-//      h = h + 1

-//    else:

-//      msgs = msgs + "    '%s',\n" % v

-//

-//enum = enum[:-2] + ');\n\n'

-//msgs = msgs[:-2] + '\n  );\n'

-//warns = (warns[:-2] + '\n  );\n') % (w-1)

-//hints = (hints[:-2] + '\n  );\n') % (h-1)

-//

-//cog.out(enum)

-//cog.out(msgs)

-//cog.out(warns)

-//cog.out(hints)

-//]]]

+//
+//
+//           The Nimrod Compiler
+//        (c) Copyright 2009 Andreas Rumpf
+//
+//    See the file "copying.txt", included in this
+//    distribution, for details about the copyright.
+//
+unit msgs;
+
+interface
+
+{$include 'config.inc'}
+
+uses
+  nsystem, options, strutils, nos;
+
+//[[[cog
+//from string import replace
+//enum = "type\n  TMsgKind = (\n"
+//msgs = "const\n  MsgKindToStr: array [TMsgKind] of string = (\n"
+//warns = "const\n  WarningsToStr: array [0..%d] of string = (\n"
+//hints = "const\n  HintsToStr: array [0..%d] of string = (\n"
+//w = 0 # counts the warnings
+//h = 0 # counts the hints
+//
+//for elem in eval(open('data/messages.yml').read()):
+//  for key, val in elem.items():
+//    enum = enum + '    %s,\n' % key
+//    v = replace(val, "'", "''")
+//    if key[0:4] == 'warn':
+//      msgs = msgs +  "    '%s [%s]',\n" % (v, key[4:])
+//      warns = warns + "    '%s',\n" % key[4:]
+//      w = w + 1
+//    elif key[0:4] == 'hint':
+//      msgs = msgs + "    '%s [%s]',\n" % (v, key[4:])
+//      hints = hints + "    '%s',\n" % key[4:]
+//      h = h + 1
+//    else:
+//      msgs = msgs + "    '%s',\n" % v
+//
+//enum = enum[:-2] + ');\n\n'
+//msgs = msgs[:-2] + '\n  );\n'
+//warns = (warns[:-2] + '\n  );\n') % (w-1)
+//hints = (hints[:-2] + '\n  );\n') % (h-1)
+//
+//cog.out(enum)
+//cog.out(msgs)
+//cog.out(warns)
+//cog.out(hints)
+//]]]
 type
   TMsgKind = (
     errUnknown,
@@ -74,13 +74,12 @@ type
     errOperatorExpected,
     errTokenExpected,
     errStringAfterIncludeExpected,
-    errRecursiveInclude,
+    errRecursiveDependencyX,
     errOnOrOffExpected,
     errNoneSpeedOrSizeExpected,
     errInvalidPragma,
     errUnknownPragma,
-    errUnknownDirective,
-    errInvalidDirective,
+    errInvalidDirectiveX,
     errAtPopWithoutPush,
     errEmptyAsm,
     errInvalidIndentation,
@@ -128,8 +127,6 @@ type
     errOverOrUnderflow,
     errCannotEvalXBecauseIncompletelyDefined,
     errChrExpectsRange0_255,
-    errStaticAssertFailed,
-    errStaticAssertCannotBeEval,
     errDotRequiresRecordOrObjectType,
     errUndeclaredFieldX,
     errNilAccess,
@@ -184,7 +181,7 @@ type
     errButExpected,
     errButExpectedX,
     errAmbiguousCallXYZ,
-    errWrongNumberOfTypeParams,
+    errWrongNumberOfArguments,
     errInlineProcHasNoAddress,
     errXCannotBeInParamDecl,
     errPragmaOnlyInHeaderOfProc,
@@ -230,11 +227,9 @@ type
     errInitHereNotAllowed,
     errXCannotBeAssignedTo,
     errIteratorNotAllowed,
-    errIteratorNeedsImplementation,
-    errIteratorNeedsReturnType,
+    errXNeedsReturnType,
     errInvalidCommandX,
     errXOnlyAtModuleScope,
-    errTypeXNeedsImplementation,
     errTemplateInstantiationTooNested,
     errInstantiationFrom,
     errInvalidIndexValueForTuple,
@@ -257,12 +252,12 @@ type
     errInvalidConversionFromTypeX,
     errAssertionFailed,
     errCannotGenerateCodeForX,
-    errXNeedsReturnType,
     errXRequiresOneArgument,
     errUnhandledExceptionX,
     errCyclicTree,
     errXisNoMacroOrTemplate,
     errXhasSideEffects,
+    errIteratorExpected,
     errUser,
     warnCannotOpenFile,
     warnOctalEscape,
@@ -317,15 +312,14 @@ const
     'operator expected, but found ''$1''',
     '''$1'' expected',
     'string after ''include'' expected',
-    'recursive include file: ''$1''',
+    'recursive dependency: ''$1''',
     '''on'' or ''off'' expected',
     '''none'', ''speed'' or ''size'' expected',
     'invalid pragma',
     'unknown pragma: ''$1''',
-    'unknown directive: ''$1''',
-    'invalid directive',
+    'invalid directive: ''$1''',
     '''pop'' without a ''push'' pragma',
-    'empty asm statement makes no sense',
+    'empty asm statement',
     'invalid indentation',
     'exception expected',
     'exception already handled',
@@ -371,8 +365,6 @@ const
     'over- or underflow',
     'cannot evalutate ''$1'' because type is not defined completely',
     '''chr'' expects an int in the range 0..255',
-    '''staticAssert'' failed: condition is false',
-    'argument to ''staticAssert'' cannot be evaluated at compile time',
     '''.'' requires a record or object type',
     'undeclared field: ''$1''',
     'attempt to access a nil address',
@@ -427,7 +419,7 @@ const
     'but expected one of: ',
     'but expected ''$1''',
     'ambiguous call; both $1 and $2 match for: $3',
-    'wrong number of type parameters',
+    'wrong number of arguments',
     'an inline proc has no address',
     '$1 cannot be declared in parameter declaration',
     'pragmas are only in the header of a proc allowed',
@@ -469,15 +461,13 @@ const
     'named expression not allowed here',
     '''$1'' expects one type parameter',
     'array expects two type parameters',
-    'invalid invisibility: ''$1''',
+    'invalid visibility: ''$1''',
     'initialization not allowed here',
     '''$1'' cannot be assigned to',
     'iterators can only be defined at the module''s top level',
-    'iterator needs an implementation',
-    'iterator needs a return type',
+    '$1 needs a return type',
     'invalid command: ''$1''',
     '''$1'' is only allowed at top level',
-    'type ''$1'' needs an implementation',
     'template instantiation too nested',
     'instantiation from here',
     'invalid index value for tuple subscript',
@@ -500,12 +490,12 @@ const
     'invalid conversion from type ''$1''',
     'assertion failed',
     'cannot generate code for ''$1''',
-    'converter needs return type',
-    'converter requires one parameter',
+    '$1 requires one parameter',
     'unhandled exception: $1',
     'macro returned a cyclic abstract syntax tree',
     '''$1'' is no macro or template',
     '''$1'' can have side effects',
+    'iterator within for loop context expected',
     '$1',
     'cannot open ''$1'' [CannotOpenFile]',
     'octal escape sequences do not exist; leading zero is ignored [OctalEscape]',
@@ -568,322 +558,335 @@ const
     'Conf',
     'User'
   );
-//[[[end]]]

-

-const

-  fatalMin = errUnknown;

-  fatalMax = errInternal;

-  errMin = errUnknown;

-  errMax = errUser;

-  warnMin = warnCannotOpenFile;

-  warnMax = pred(hintSuccess);

-  hintMin = hintSuccess;

-  hintMax = high(TMsgKind);

-

-type

-  TNoteKind = warnMin..hintMax;

-  // "notes" are warnings or hints

-  TNoteKinds = set of TNoteKind;

-

-  TLineInfo = record

-    // This is designed to be as small as possible, because it is used

-    // in syntax nodes. We safe space here by using two int16 and an int32

-    // on 64 bit and on 32 bit systems this is only 8 bytes.

-    line, col: int16;

-    fileIndex: int32;

-  end;

-

-function UnknownLineInfo(): TLineInfo;

-

-var

-  gNotes: TNoteKinds = [low(TNoteKind)..high(TNoteKind)];

-  gErrorCounter: int = 0; // counts the number of errors

-  gHintCounter: int = 0;

-  gWarnCounter: int = 0;

-  gErrorMax: int = 1; // stop after gErrorMax errors

-

-const // this format is understood by many text editors: it is the same that

-  // Borland and Freepascal use

-  PosErrorFormat = '$1($2, $3) Error: $4';

-  PosWarningFormat = '$1($2, $3) Warning: $4';

-  PosHintFormat = '$1($2, $3) Hint: $4';

-

-  RawErrorFormat = 'Error: $1';

-  RawWarningFormat = 'Warning: $1';

-  RawHintFormat = 'Hint: $1';

-

-procedure MessageOut(const s: string);

-

-procedure rawMessage(const msg: TMsgKind; const arg: string = ''); overload;

-procedure rawMessage(const msg: TMsgKind; const args: array of string); overload;

-

-procedure liMessage(const info: TLineInfo; const msg: TMsgKind;

-                    const arg: string = '');

-

-procedure InternalError(const info: TLineInfo; const errMsg: string);

-  overload;

-procedure InternalError(const errMsg: string); overload;

-

-function newLineInfo(const filename: string; line, col: int): TLineInfo;

-

-function ToFilename(const info: TLineInfo): string;

-function toColumn(const info: TLineInfo): int;

-function ToLinenumber(const info: TLineInfo): int;

-

-function MsgKindToString(kind: TMsgKind): string;

-

-// checkpoints are used for debugging:

-function checkpoint(const info: TLineInfo; const filename: string;

-                    line: int): boolean;

-

-procedure addCheckpoint(const info: TLineInfo); overload;

-procedure addCheckpoint(const filename: string; line: int); overload;

-function inCheckpoint(const current: TLineInfo): boolean;

-// prints the line information if in checkpoint

-

-procedure pushInfoContext(const info: TLineInfo);

-procedure popInfoContext;

-

-implementation

-

-function UnknownLineInfo(): TLineInfo;

-begin

-  result.line := int16(-1);

-  result.col := int16(-1);

-  result.fileIndex := -1;

-end;

-

-{@ignore}

-var

-  filenames: array of string;

-  msgContext: array of TLineInfo;

-{@emit

-var

-  filenames: array of string = @[];

-  msgContext: array of TLineInfo = @[];

-}

-

-procedure pushInfoContext(const info: TLineInfo);

-var

-  len: int;

-begin

-  len := length(msgContext);

-  setLength(msgContext, len+1);

-  msgContext[len] := info;

-end;

-

-procedure popInfoContext;

-begin

-  setLength(msgContext, length(msgContext)-1);

-end;

-

-function includeFilename(const f: string): int;

-var

-  i: int;

-begin

-  for i := high(filenames) downto low(filenames) do

-    if filenames[i] = f then begin

-      result := i; exit

-    end;

-  // not found, so add it:

-  result := length(filenames);

-  setLength(filenames, result+1);

-  filenames[result] := f;

-end;

-

-function checkpoint(const info: TLineInfo; const filename: string;

-                    line: int): boolean;

-begin

-  result := (int(info.line) = line) and (

-    ChangeFileExt(extractFilename(filenames[info.fileIndex]), '') = filename);

-end;

-

-

-{@ignore}

-var

-  checkPoints: array of TLineInfo;

-{@emit

-var

-  checkPoints: array of TLineInfo = @[];

-}

-

-procedure addCheckpoint(const info: TLineInfo); overload;

-var

-  len: int;

-begin

-  len := length(checkPoints);

-  setLength(checkPoints, len+1);

-  checkPoints[len] := info;

-end;

-

-procedure addCheckpoint(const filename: string; line: int); overload;

-begin

-  addCheckpoint(newLineInfo(filename, line, -1));

-end;

-

-function newLineInfo(const filename: string; line, col: int): TLineInfo;

-begin

-  result.fileIndex := includeFilename(filename);

-  result.line := int16(line);

-  result.col := int16(col);

-end;

-

-function ToFilename(const info: TLineInfo): string;

-begin

-  if info.fileIndex = -1 then result := '???'

-  else result := filenames[info.fileIndex]

-end;

-

-function ToLinenumber(const info: TLineInfo): int;

-begin

-  result := info.line

-end;

-

-function toColumn(const info: TLineInfo): int;

-begin

-  result := info.col

-end;

-

-procedure MessageOut(const s: string);

-begin  // change only this proc to put it elsewhere

-  Writeln(output, s);

-end;

-

-function coordToStr(const coord: int): string;

-begin

-  if coord = -1 then result := '???'

-  else result := toString(coord)

-end;

-

-function MsgKindToString(kind: TMsgKind): string;

-begin // later versions may provide translated error messages

-  result := msgKindToStr[kind];

-end;

-

-function getMessageStr(msg: TMsgKind; const arg: string): string;

-begin

-  result := format(msgKindToString(msg), [arg]);

-end;

-

-function inCheckpoint(const current: TLineInfo): boolean;

-var

-  i: int;

-begin

-  result := false;

-  if not (optCheckpoints in gOptions) then exit; // ignore all checkpoints

-  for i := 0 to high(checkPoints) do begin

-    if (current.line = checkPoints[i].line) and

-       (current.fileIndex = (checkPoints[i].fileIndex)) then begin

-      MessageOut(Format('$1($2, $3) Checkpoint: ', [toFilename(current),

-                           coordToStr(current.line),

-                           coordToStr(current.col)]));

-      result := true;

-      exit

-    end

-  end

-end;

-

-procedure handleError(const msg: TMsgKind);

-begin

-  if msg = errInternal then assert(false); // we want a stack trace here

-  if (msg >= fatalMin) and (msg <= fatalMax) then begin

-    if gVerbosity >= 3 then assert(false);

-    halt(1)

-  end;

-  if (msg >= errMin) and (msg <= errMax) then begin

-    inc(gErrorCounter);

-    if gErrorCounter >= gErrorMax then begin

-      if gVerbosity >= 3 then assert(false);

-      halt(1) // one error stops the compiler

-    end

-  end

-end;

-

-procedure writeContext;

-var

-  i: int;

-begin

-  for i := 0 to length(msgContext)-1 do begin

-    MessageOut(Format(posErrorFormat, [toFilename(msgContext[i]),

-                             coordToStr(msgContext[i].line),

-                             coordToStr(msgContext[i].col),

-                             getMessageStr(errInstantiationFrom, '')]));

-  end;

-end;

-

-procedure rawMessage(const msg: TMsgKind; const args: array of string);

-var

-  frmt: string;

-begin

-  case msg of

-    errMin..errMax: begin

-      writeContext();

-      frmt := rawErrorFormat;

-    end;

-    warnMin..warnMax: begin

-      if not (optWarns in gOptions) then exit;

-      if not (msg in gNotes) then exit;

-      frmt := rawWarningFormat;

-      inc(gWarnCounter);

-    end;

-    hintMin..hintMax: begin

-      if not (optHints in gOptions) then exit;

-      if not (msg in gNotes) then exit;

-      frmt := rawHintFormat;

-      inc(gHintCounter);

-    end;

-    else assert(false) // cannot happen

-  end;

-  MessageOut(Format(frmt, format(msgKindToString(msg), args)));

-  handleError(msg);

-end;

-

-procedure rawMessage(const msg: TMsgKind; const arg: string = '');

-begin

-  rawMessage(msg, [arg]);

-end;

-

-procedure liMessage(const info: TLineInfo; const msg: TMsgKind;

-                    const arg: string = '');

-var

-  frmt: string;

-begin

-  case msg of

-    errMin..errMax: begin

-      writeContext();

-      frmt := posErrorFormat;

-    end;

-    warnMin..warnMax: begin

-      if not (optWarns in gOptions) then exit;

-      if not (msg in gNotes) then exit;

-      frmt := posWarningFormat;

-      inc(gWarnCounter);

-    end;

-    hintMin..hintMax: begin

-      if not (optHints in gOptions) then exit;

-      if not (msg in gNotes) then exit;

-      frmt := posHintFormat;

-      inc(gHintCounter);

-    end;

-    else assert(false) // cannot happen

-  end;

-  MessageOut(Format(frmt, [toFilename(info),

-                           coordToStr(info.line),

-                           coordToStr(info.col),

-                           getMessageStr(msg, arg)]));

-  handleError(msg);

-end;

-

-procedure InternalError(const info: TLineInfo; const errMsg: string);

-begin

-  writeContext();

-  liMessage(info, errInternal, errMsg);

-end;

-

-procedure InternalError(const errMsg: string); overload;

-begin

-  writeContext();

-  rawMessage(errInternal, errMsg);

-end;

-

-end.

+//[[[end]]]
+
+const
+  fatalMin = errUnknown;
+  fatalMax = errInternal;
+  errMin = errUnknown;
+  errMax = errUser;
+  warnMin = warnCannotOpenFile;
+  warnMax = pred(hintSuccess);
+  hintMin = hintSuccess;
+  hintMax = high(TMsgKind);
+
+type
+  TNoteKind = warnMin..hintMax;
+  // "notes" are warnings or hints
+  TNoteKinds = set of TNoteKind;
+
+  TLineInfo = record
+    // This is designed to be as small as possible, because it is used
+    // in syntax nodes. We safe space here by using two int16 and an int32
+    // on 64 bit and on 32 bit systems this is only 8 bytes.
+    line, col: int16;
+    fileIndex: int32;
+  end;
+
+function UnknownLineInfo(): TLineInfo;
+
+var
+  gNotes: TNoteKinds = [low(TNoteKind)..high(TNoteKind)];
+  gErrorCounter: int = 0; // counts the number of errors
+  gHintCounter: int = 0;
+  gWarnCounter: int = 0;
+  gErrorMax: int = 1; // stop after gErrorMax errors
+
+const // this format is understood by many text editors: it is the same that
+  // Borland and Freepascal use
+  PosErrorFormat = '$1($2, $3) Error: $4';
+  PosWarningFormat = '$1($2, $3) Warning: $4';
+  PosHintFormat = '$1($2, $3) Hint: $4';
+
+  RawErrorFormat = 'Error: $1';
+  RawWarningFormat = 'Warning: $1';
+  RawHintFormat = 'Hint: $1';
+
+procedure MessageOut(const s: string);
+
+procedure rawMessage(const msg: TMsgKind; const arg: string = ''); overload;
+procedure rawMessage(const msg: TMsgKind; const args: array of string); overload;
+
+procedure liMessage(const info: TLineInfo; const msg: TMsgKind;
+                    const arg: string = '');
+
+procedure InternalError(const info: TLineInfo; const errMsg: string);
+  overload;
+procedure InternalError(const errMsg: string); overload;
+
+function newLineInfo(const filename: string; line, col: int): TLineInfo;
+
+function ToFilename(const info: TLineInfo): string;
+function toColumn(const info: TLineInfo): int;
+function ToLinenumber(const info: TLineInfo): int;
+
+function MsgKindToString(kind: TMsgKind): string;
+
+// checkpoints are used for debugging:
+function checkpoint(const info: TLineInfo; const filename: string;
+                    line: int): boolean;
+
+procedure addCheckpoint(const info: TLineInfo); overload;
+procedure addCheckpoint(const filename: string; line: int); overload;
+function inCheckpoint(const current: TLineInfo): boolean;
+// prints the line information if in checkpoint
+
+procedure pushInfoContext(const info: TLineInfo);
+procedure popInfoContext;
+
+function includeFilename(const f: string): int;
+
+
+implementation
+
+function UnknownLineInfo(): TLineInfo;
+begin
+  result.line := int16(-1);
+  result.col := int16(-1);
+  result.fileIndex := -1;
+end;
+
+{@ignore}
+var
+  filenames: array of string;
+  msgContext: array of TLineInfo;
+{@emit
+var
+  filenames: array of string = @[];
+  msgContext: array of TLineInfo = @[];
+}
+
+procedure pushInfoContext(const info: TLineInfo);
+var
+  len: int;
+begin
+  len := length(msgContext);
+  setLength(msgContext, len+1);
+  msgContext[len] := info;
+end;
+
+procedure popInfoContext;
+begin
+  setLength(msgContext, length(msgContext)-1);
+end;
+
+function includeFilename(const f: string): int;
+var
+  i: int;
+begin
+  for i := high(filenames) downto low(filenames) do
+    if filenames[i] = f then begin
+      result := i; exit
+    end;
+  // not found, so add it:
+  result := length(filenames);
+  setLength(filenames, result+1);
+  filenames[result] := f;
+end;
+
+function checkpoint(const info: TLineInfo; const filename: string;
+                    line: int): boolean;
+begin
+  result := (int(info.line) = line) and (
+    ChangeFileExt(extractFilename(filenames[info.fileIndex]), '') = filename);
+end;
+
+
+{@ignore}
+var
+  checkPoints: array of TLineInfo;
+{@emit
+var
+  checkPoints: array of TLineInfo = @[];
+}
+
+procedure addCheckpoint(const info: TLineInfo); overload;
+var
+  len: int;
+begin
+  len := length(checkPoints);
+  setLength(checkPoints, len+1);
+  checkPoints[len] := info;
+end;
+
+procedure addCheckpoint(const filename: string; line: int); overload;
+begin
+  addCheckpoint(newLineInfo(filename, line, -1));
+end;
+
+function newLineInfo(const filename: string; line, col: int): TLineInfo;
+begin
+  result.fileIndex := includeFilename(filename);
+  result.line := int16(line);
+  result.col := int16(col);
+end;
+
+function ToFilename(const info: TLineInfo): string;
+begin
+  if info.fileIndex = -1 then result := '???'
+  else result := filenames[info.fileIndex]
+end;
+
+function ToLinenumber(const info: TLineInfo): int;
+begin
+  result := info.line
+end;
+
+function toColumn(const info: TLineInfo): int;
+begin
+  result := info.col
+end;
+
+procedure MessageOut(const s: string);
+begin  // change only this proc to put it elsewhere
+  Writeln(output, s);
+end;
+
+function coordToStr(const coord: int): string;
+begin
+  if coord = -1 then result := '???'
+  else result := toString(coord)
+end;
+
+function MsgKindToString(kind: TMsgKind): string;
+begin // later versions may provide translated error messages
+  result := msgKindToStr[kind];
+end;
+
+function getMessageStr(msg: TMsgKind; const arg: string): string;
+begin
+  result := format(msgKindToString(msg), [arg]);
+end;
+
+function inCheckpoint(const current: TLineInfo): boolean;
+var
+  i: int;
+begin
+  result := false;
+  if not (optCheckpoints in gOptions) then exit; // ignore all checkpoints
+  for i := 0 to high(checkPoints) do begin
+    if (current.line = checkPoints[i].line) and
+       (current.fileIndex = (checkPoints[i].fileIndex)) then begin
+      MessageOut(Format('$1($2, $3) Checkpoint: ', [toFilename(current),
+                           coordToStr(current.line),
+                           coordToStr(current.col)]));
+      result := true;
+      exit
+    end
+  end
+end;
+
+procedure handleError(const msg: TMsgKind);
+begin
+  if msg = errInternal then assert(false); // we want a stack trace here
+  if (msg >= fatalMin) and (msg <= fatalMax) then begin
+    if gVerbosity >= 3 then assert(false);
+    halt(1)
+  end;
+  if (msg >= errMin) and (msg <= errMax) then begin
+    inc(gErrorCounter);
+    if gErrorCounter >= gErrorMax then begin
+      if gVerbosity >= 3 then assert(false);
+      halt(1) // one error stops the compiler
+    end
+  end
+end;
+
+function sameLineInfo(const a, b: TLineInfo): bool;
+begin
+  result := (a.line = b.line) and (a.fileIndex = b.fileIndex);
+end;
+
+procedure writeContext(const lastinfo: TLineInfo);
+var
+  i: int;
+  info: TLineInfo;
+begin
+  info := lastInfo;
+  for i := 0 to length(msgContext)-1 do begin
+    if not sameLineInfo(msgContext[i], lastInfo)
+    and not sameLineInfo(msgContext[i], info) then
+      MessageOut(Format(posErrorFormat, [toFilename(msgContext[i]),
+                        coordToStr(msgContext[i].line),
+                        coordToStr(msgContext[i].col),
+                        getMessageStr(errInstantiationFrom, '')]));
+    info := msgContext[i];
+  end;
+end;
+
+procedure rawMessage(const msg: TMsgKind; const args: array of string);
+var
+  frmt: string;
+begin
+  case msg of
+    errMin..errMax: begin
+      writeContext(unknownLineInfo());
+      frmt := rawErrorFormat;
+    end;
+    warnMin..warnMax: begin
+      if not (optWarns in gOptions) then exit;
+      if not (msg in gNotes) then exit;
+      frmt := rawWarningFormat;
+      inc(gWarnCounter);
+    end;
+    hintMin..hintMax: begin
+      if not (optHints in gOptions) then exit;
+      if not (msg in gNotes) then exit;
+      frmt := rawHintFormat;
+      inc(gHintCounter);
+    end;
+    else assert(false) // cannot happen
+  end;
+  MessageOut(Format(frmt, format(msgKindToString(msg), args)));
+  handleError(msg);
+end;
+
+procedure rawMessage(const msg: TMsgKind; const arg: string = '');
+begin
+  rawMessage(msg, [arg]);
+end;
+
+procedure liMessage(const info: TLineInfo; const msg: TMsgKind;
+                    const arg: string = '');
+var
+  frmt: string;
+begin
+  case msg of
+    errMin..errMax: begin
+      writeContext(info);
+      frmt := posErrorFormat;
+    end;
+    warnMin..warnMax: begin
+      if not (optWarns in gOptions) then exit;
+      if not (msg in gNotes) then exit;
+      frmt := posWarningFormat;
+      inc(gWarnCounter);
+    end;
+    hintMin..hintMax: begin
+      if not (optHints in gOptions) then exit;
+      if not (msg in gNotes) then exit;
+      frmt := posHintFormat;
+      inc(gHintCounter);
+    end;
+    else assert(false) // cannot happen
+  end;
+  MessageOut(Format(frmt, [toFilename(info),
+                           coordToStr(info.line),
+                           coordToStr(info.col),
+                           getMessageStr(msg, arg)]));
+  handleError(msg);
+end;
+
+procedure InternalError(const info: TLineInfo; const errMsg: string);
+begin
+  writeContext(info);
+  liMessage(info, errInternal, errMsg);
+end;
+
+procedure InternalError(const errMsg: string); overload;
+begin
+  writeContext(UnknownLineInfo());
+  rawMessage(errInternal, errMsg);
+end;
+
+end.
diff --git a/nim/nhashes.pas b/nim/nhashes.pas
index 0564f6f47..0564f6f47 100644..100755
--- a/nim/nhashes.pas
+++ b/nim/nhashes.pas
diff --git a/nim/nimconf.pas b/nim/nimconf.pas
index 842446ae9..69c6f7618 100644..100755
--- a/nim/nimconf.pas
+++ b/nim/nimconf.pas
@@ -218,7 +218,7 @@ begin
       ppGetTok(L, tok)
     end
     else
-      lexMessage(L, errUnknownDirective, tokToStr(tok))
+      lexMessage(L, errInvalidDirectiveX, tokToStr(tok))
   end
 end;
 
diff --git a/nim/nimrod.pas b/nim/nimrod.pas
index 728325ccc..728325ccc 100644..100755
--- a/nim/nimrod.pas
+++ b/nim/nimrod.pas
diff --git a/nim/nimsets.pas b/nim/nimsets.pas
index 9795817b8..9795817b8 100644..100755
--- a/nim/nimsets.pas
+++ b/nim/nimsets.pas
diff --git a/nim/nmath.pas b/nim/nmath.pas
index 8b638eb42..8b638eb42 100644..100755
--- a/nim/nmath.pas
+++ b/nim/nmath.pas
diff --git a/nim/nos.pas b/nim/nos.pas
index 4926c99b0..2edb0864e 100644..100755
--- a/nim/nos.pas
+++ b/nim/nos.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.
@@ -220,7 +220,7 @@ begin
   if (length(result) > 0) and (result[1] <> '/') then begin
     // not an absolute path?
     // iterate over any path in the $PATH environment variable
-    paths := splitSeq(getEnv('PATH'), [':']);
+    paths := split(getEnv('PATH'), [':']);
     for p := 0 to high(paths) do begin
       tail := joinPath(paths[p], result);
       if ExistsFile(tail) then begin result := tail; exit end
diff --git a/nim/nstrtabs.pas b/nim/nstrtabs.pas
index bcb10f2ed..bcb10f2ed 100644..100755
--- a/nim/nstrtabs.pas
+++ b/nim/nstrtabs.pas
diff --git a/nim/nsystem.pas b/nim/nsystem.pas
index 51ca05605..49d17b172 100644..100755
--- a/nim/nsystem.pas
+++ b/nim/nsystem.pas
@@ -217,8 +217,15 @@ procedure nimWrite(var f: tBinaryFile; const str: string); overload;
 procedure add(var x: string; const y: string);
 // Pascal version of string appending. Terminating zero is ignored.
 
+function isNil(s: string): bool;
+
 implementation
 
+function isNil(s: string): bool;
+begin
+  result := s = '';
+end;
+
 {@ignore}
 procedure add(var x: string; const y: string);
 // Pascal version of string appending. Terminating zero is ignored.
diff --git a/nim/ntime.pas b/nim/ntime.pas
index 9135c26c3..9135c26c3 100644..100755
--- a/nim/ntime.pas
+++ b/nim/ntime.pas
diff --git a/nim/nversion.pas b/nim/nversion.pas
index e15f88068..add85acd1 100644..100755
--- a/nim/nversion.pas
+++ b/nim/nversion.pas
@@ -31,10 +31,10 @@ const
   //cog.outl('VersionMinor = %s;' % ver[1])

   //cog.outl('VersionPatch = %s;' % ver[2])

   //]]]

-  VersionAsString = '0.7.10';
+  VersionAsString = '0.8.0';
   VersionMajor = 0;
-  VersionMinor = 7;
-  VersionPatch = 10;
+  VersionMinor = 8;
+  VersionPatch = 0;
   //[[[[end]]]]

 

 implementation

diff --git a/nim/options.pas b/nim/options.pas
index f84d8458c..d210f3b44 100644..100755
--- a/nim/options.pas
+++ b/nim/options.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.
@@ -46,7 +46,8 @@ type
     optRun,            // run the compiled project
     optSymbolFiles,    // use symbol files for speeding up compilation
     optSkipConfigFile, // skip the general config file
-    optSkipProjConfigFile // skip the project's config file
+    optSkipProjConfigFile, // skip the project's config file
+    optNoMain          // do not generate a "main" proc
   );
   TGlobalOptions = set of TGlobalOption;
 
@@ -68,6 +69,7 @@ type
     cmdScan,       // scan a single file (for debugging)
     cmdDebugTrans, // debug a transformation pass
     cmdRst2html,   // convert a reStructuredText file to HTML
+    cmdRst2tex,    // convert a reStructuredText file to TeX
     cmdInteractive // start interactive session
   );
   TStringSeq = array of string;
@@ -107,9 +109,11 @@ const
   NimExt = 'nim';
   RodExt = 'rod';
   HtmlExt = 'html';
+  TexExt = 'tex';
   IniExt = 'ini';
   TmplExt = 'tmpl';
   DocConfig = 'nimdoc.cfg';
+  DocTexConfig = 'nimdoc.tex.cfg';
 
 function completeGeneratedFilePath(const f: string;
                                    createSubDir: bool = true): string;
diff --git a/nim/osproc.pas b/nim/osproc.pas
index dd6bd10f0..dd6bd10f0 100644..100755
--- a/nim/osproc.pas
+++ b/nim/osproc.pas
diff --git a/nim/parsecfg.pas b/nim/parsecfg.pas
index ba6a98679..ba6a98679 100644..100755
--- a/nim/parsecfg.pas
+++ b/nim/parsecfg.pas
diff --git a/nim/parseopt.pas b/nim/parseopt.pas
index 0ca87bd37..0ca87bd37 100644..100755
--- a/nim/parseopt.pas
+++ b/nim/parseopt.pas
diff --git a/nim/paslex.pas b/nim/paslex.pas
index f3d8daaeb..f3d8daaeb 100644..100755
--- a/nim/paslex.pas
+++ b/nim/paslex.pas
diff --git a/nim/pasparse.pas b/nim/pasparse.pas
index 73280aeca..8a73feca5 100644..100755
--- a/nim/pasparse.pas
+++ b/nim/pasparse.pas
@@ -293,7 +293,7 @@ begin
       addSon(result, a.sons[1]);
     end
     else begin
-      parMessage(p, errInvalidDirective);
+      parMessage(p, errInvalidDirectiveX, pasTokToStr(p.tok));
       result := a
     end
   end
@@ -334,7 +334,7 @@ begin
     getTok(p); eat(p, pxCurlyDirRi);
   end
   else begin
-    parMessage(p, errUnknownDirective, pasTokToStr(p.tok));
+    parMessage(p, errInvalidDirectiveX, pasTokToStr(p.tok));
     while true do begin
       getTok(p);
       if (p.tok.xkind = pxCurlyDirRi) or (p.tok.xkind = pxEof) then break;
diff --git a/nim/passaux.pas b/nim/passaux.pas
index 8b052257f..8b052257f 100644..100755
--- a/nim/passaux.pas
+++ b/nim/passaux.pas
diff --git a/nim/passes.pas b/nim/passes.pas
index f5dff3559..f5dff3559 100644..100755
--- a/nim/passes.pas
+++ b/nim/passes.pas
diff --git a/nim/platform.pas b/nim/platform.pas
index 9f8d30f60..9f8d30f60 100644..100755
--- a/nim/platform.pas
+++ b/nim/platform.pas
diff --git a/nim/pnimsyn.pas b/nim/pnimsyn.pas
index 2ca411770..dae7de539 100644..100755
--- a/nim/pnimsyn.pas
+++ b/nim/pnimsyn.pas
@@ -612,6 +612,18 @@ begin
       result := newStrNodeP(nkTripleStrLit, p.tok.literal, p);
       getTok(p);
     end;
+    tkCallRStrLit: begin
+      result := newNodeP(nkCallStrLit, p);
+      addSon(result, newIdentNodeP(p.tok.ident, p));
+      addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p));
+      getTok(p);
+    end;
+    tkCallTripleStrLit: begin
+      result := newNodeP(nkCallStrLit, p);
+      addSon(result, newIdentNodeP(p.tok.ident, p));
+      addSon(result, newStrNodeP(nkTripleStrLit, p.tok.literal, p));
+      getTok(p);
+    end;
     tkCharLit: begin
       result := newIntNodeP(nkCharLit, ord(p.tok.literal[strStart]), p);
       getTok(p);
@@ -885,8 +897,8 @@ begin
   while true do begin
     case p.tok.tokType of
       tkEof, tkSad, tkDed: break;
-      tkSymbol, tkAccent:   a := parseSymbol(p);
-      tkRStrLit:  begin
+      tkSymbol, tkAccent: a := parseSymbol(p);
+      tkRStrLit: begin
         a := newStrNodeP(nkRStrLit, p.tok.literal, p);
         getTok(p)
       end;
@@ -901,16 +913,7 @@ begin
       else begin
         parMessage(p, errIdentifierExpected, tokToStr(p.tok));
         break
-      end;
-    end;
-    //optInd(p, a);
-    if p.tok.tokType = tkAs then begin
-      getTok(p);
-      optInd(p, a);
-      b := a;
-      a := newNodeP(nkImportAs, p);
-      addSon(a, b);
-      addSon(a, parseSymbol(p));
+      end
     end;
     addSon(result, a);
     if p.tok.tokType <> tkComma then break;
@@ -1227,24 +1230,31 @@ begin
     result := a
 end;
 
-function parseIdentColonEquals(var p: TParser; withPragma: bool): PNode;
+type
+  TDeclaredIdentFlag = (
+    withPragma,                // identifier may have pragma
+    withBothOptional           // both ':' and '=' parts are optional
+  );
+  TDeclaredIdentFlags = set of TDeclaredIdentFlag;
+
+function parseIdentColonEquals(var p: TParser;
+                               flags: TDeclaredIdentFlags): PNode;
 var
   a: PNode;
 begin
   result := newNodeP(nkIdentDefs, p);
   while true do begin
     case p.tok.tokType of
-      tkColon, tkEof, tkSad, tkDed, tkParRi, tkEquals: break;
-      else begin
-        if withPragma then
+      tkSymbol, tkAccent: begin
+        if withPragma in flags then
           a := identWithPragma(p)
         else
           a := parseSymbol(p);
         if a = nil then exit;
-      end
+      end;
+      else break;
     end;
     addSon(result, a);
-    //optInd(p, a);
     if p.tok.tokType <> tkComma then break;
     getTok(p);
     optInd(p, a)
@@ -1255,7 +1265,7 @@ begin
   end
   else begin
     addSon(result, nil);
-    if p.tok.tokType <> tkEquals then
+    if (p.tok.tokType <> tkEquals) and not (withBothOptional in flags) then
       parMessage(p, errColonOrEqualsExpected, tokToStr(p.tok))
   end;
   if p.tok.tokType = tkEquals then begin
@@ -1277,7 +1287,7 @@ begin
     optInd(p, result);
     while true do begin
       case p.tok.tokType of
-        tkSymbol, tkAccent: a := parseIdentColonEquals(p, false);
+        tkSymbol, tkAccent: a := parseIdentColonEquals(p, {@set}[]);
         tkParRi: break;
         else begin parMessage(p, errTokenExpected, ')'+''); break; end;
       end;
@@ -1335,7 +1345,7 @@ begin
       eat(p, tkBracketLe);
       optInd(p, result);
       while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin
-        a := parseIdentColonEquals(p, false);
+        a := parseIdentColonEquals(p, {@set}[]);
         addSon(result, a);        
         if p.tok.tokType <> tkComma then break;
         getTok(p);
@@ -1360,23 +1370,6 @@ begin
   end
 end;
 
-function parseGenericParam(var p: TParser): PNode;
-var
-  a: PNode;
-begin
-  a := parseSymbol(p);
-  optInd(p, a);
-  if p.tok.tokType = tkEquals then begin
-    result := newNodeP(nkDefaultTypeParam, p);
-    getTok(p);
-    optInd(p, a);
-    addSon(result, a);
-    addSon(result, parseTypeDesc(p));
-  end
-  else
-    result := a
-end;
-
 function parseGenericParamList(var p: TParser): PNode;
 var
   a: PNode;
@@ -1385,7 +1378,7 @@ begin
   getTok(p);
   optInd(p, result);
   while (p.tok.tokType = tkSymbol) or (p.tok.tokType = tkAccent) do begin
-    a := parseGenericParam(p);
+    a := parseIdentColonEquals(p, {@set}[withBothOptional]);
     addSon(result, a);
     if p.tok.tokType <> tkComma then break;
     getTok(p);
@@ -1479,7 +1472,10 @@ begin
       end;
       popInd(p.lex^);
     end;
-    tkSymbol, tkAccent: addSon(result, defparser(p));
+    tkSymbol, tkAccent, tkParLe: begin
+      // tkParLe is allowed for ``var (x, y) = ...`` tuple parsing
+      addSon(result, defparser(p));
+    end
     else parMessage(p, errIdentifierExpected, tokToStr(p.tok));
   end
 end;
@@ -1627,7 +1623,7 @@ begin
     tkWhen: result := parseRecordWhen(p);
     tkCase: result := parseRecordCase(p);
     tkSymbol, tkAccent: begin
-      result := parseIdentColonEquals(p, true);
+      result := parseIdentColonEquals(p, {@set}[withPragma]);
       skipComment(p, result);
     end;
     tkNil: begin
@@ -1660,9 +1656,9 @@ begin
   addSon(result, parseRecordPart(p));
 end;
 
-function parseAbstract(var p: TParser): PNode;
+function parseDistinct(var p: TParser): PNode;
 begin
-  result := newNodeP(nkAbstractTy, p);
+  result := newNodeP(nkDistinctTy, p);
   getTok(p);
   optInd(p, result);
   addSon(result, parseTypeDesc(p));
@@ -1681,7 +1677,7 @@ begin
     case p.tok.tokType of
       tkObject: a := parseRecordOrObject(p, nkObjectTy);
       tkEnum: a := parseEnum(p);
-      tkAbstract: a := parseAbstract(p);
+      tkDistinct: a := parseDistinct(p);
       else a := parseTypeDesc(p);
     end;
     addSon(result, a);
@@ -1718,7 +1714,7 @@ begin
   if p.tok.tokType = tkParLe then 
     result := parseVarTuple(p)
   else
-    result := parseIdentColonEquals(p, true);
+    result := parseIdentColonEquals(p, {@set}[withPragma]);
   indAndComment(p, result); // special extension!
 end;
 
diff --git a/nim/pragmas.pas b/nim/pragmas.pas
index f81cdd6e2..5ec706f19 100644..100755
--- a/nim/pragmas.pas
+++ b/nim/pragmas.pas
@@ -19,16 +19,45 @@ uses
   rnimsyn, wordrecg, ropes, options, strutils, lists, extccomp, nmath,
   magicsys;
 
-procedure pragmaProc(c: PContext; s: PSym; n: PNode);
-procedure pragmaMacro(c: PContext; s: PSym; n: PNode);
-procedure pragmaIterator(c: PContext; s: PSym; n: PNode);
-procedure pragmaStmt(c: PContext; s: PSym; n: PNode);
-procedure pragmaLambda(c: PContext; s: PSym; n: PNode);
-procedure pragmaType(c: PContext; s: PSym; n: PNode);
-procedure pragmaField(c: PContext; s: PSym; n: PNode);
-procedure pragmaVar(c: PContext; s: PSym; n: PNode);
-procedure pragmaConst(c: PContext; s: PSym; n: PNode);
-procedure pragmaProcType(c: PContext; s: PSym; n: PNode);
+const
+  FirstCallConv = wNimcall;
+  LastCallConv  = wNoconv;
+
+const
+  procPragmas = {@set}[FirstCallConv..LastCallConv,
+    wImportc, wExportc, wNodecl, wMagic, wNosideEffect, wSideEffect,
+    wNoreturn, wDynLib, wHeader, wCompilerProc, wPure,
+    wCppMethod, wDeprecated, wVarargs, wCompileTime, wMerge,
+    wBorrow];
+  converterPragmas = procPragmas;
+  macroPragmas = {@set}[FirstCallConv..LastCallConv,
+    wImportc, wExportc, wNodecl, wMagic, wNosideEffect,
+    wCompilerProc, wDeprecated, wTypeCheck];
+  iteratorPragmas = {@set}[FirstCallConv..LastCallConv, 
+    wNosideEffect, wSideEffect,
+    wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow];
+  stmtPragmas = {@set}[wChecks, wObjChecks, wFieldChecks, wRangechecks,
+    wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings,
+    wHints, wLinedir, wStacktrace, wLinetrace, wOptimization,
+    wHint, wWarning, wError, wFatal, wDefine, wUndef,
+    wCompile, wLink, wLinkSys, wPure,
+    wPush, wPop, wBreakpoint, wCheckpoint,
+    wPassL, wPassC, wDeadCodeElim];
+  lambdaPragmas = {@set}[FirstCallConv..LastCallConv,
+    wImportc, wExportc, wNodecl, wNosideEffect, wSideEffect, 
+    wNoreturn, wDynLib, wHeader, wPure, wDeprecated];
+  typePragmas = {@set}[wImportc, wExportc, wDeprecated, wMagic, wAcyclic,
+                      wNodecl, wPure, wHeader, wCompilerProc, wFinal];
+  fieldPragmas = {@set}[wImportc, wExportc, wDeprecated];
+  varPragmas = {@set}[wImportc, wExportc, wVolatile, wRegister, wThreadVar,
+                      wNodecl, wMagic, wHeader, wDeprecated, wCompilerProc,
+                      wDynLib];
+  constPragmas = {@set}[wImportc, wExportc, wHeader, wDeprecated,
+                        wMagic, wNodecl];
+  procTypePragmas = [FirstCallConv..LastCallConv, wVarargs, wNosideEffect];
+
+procedure pragma(c: PContext; sym: PSym; n: PNode;
+                 const validPragmas: TSpecialWords);
 
 function pragmaAsm(c: PContext; n: PNode): char;
 
@@ -66,9 +95,6 @@ begin
 end;
 
 const
-  FirstCallConv = wNimcall;
-  LastCallConv  = wNoconv;
-
   FirstPragmaWord = wMagic;
   LastPragmaWord = wNoconv;
 
@@ -598,74 +624,4 @@ begin
   end
 end;
 
-procedure pragmaProc(c: PContext; s: PSym; n: PNode);
-begin
-  pragma(c, s, n, {@set}[FirstCallConv..LastCallConv,
-    wImportc, wExportc, wNodecl, wMagic, wNosideEffect, wSideEffect,
-    wNoreturn, wDynLib, wHeader, wCompilerProc, wPure,
-    wCppMethod, wDeprecated, wVarargs, wCompileTime, wMerge,
-    wBorrow]);
-end;
-
-procedure pragmaMacro(c: PContext; s: PSym; n: PNode);
-begin
-  pragma(c, s, n, {@set}[FirstCallConv..LastCallConv,
-    wImportc, wExportc, wNodecl, wMagic, wNosideEffect,
-    wCompilerProc, wDeprecated, wTypeCheck]);
-end;
-
-procedure pragmaIterator(c: PContext; s: PSym; n: PNode);
-begin
-  pragma(c, s, n, {@set}[FirstCallConv..LastCallConv, 
-         wNosideEffect, wSideEffect,
-         wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow]);
-end;
-
-procedure pragmaStmt(c: PContext; s: PSym; n: PNode);
-begin
-  pragma(c, s, n, {@set}[wChecks, wObjChecks, wFieldChecks, wRangechecks,
-      wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings,
-      wHints, wLinedir, wStacktrace, wLinetrace, wOptimization,
-      wHint, wWarning, wError, wFatal, wDefine, wUndef,
-      wCompile, wLink, wLinkSys, wPure,
-      wPush, wPop, wBreakpoint, wCheckpoint,
-      wPassL, wPassC, wDeadCodeElim]);
-end;
-
-procedure pragmaLambda(c: PContext; s: PSym; n: PNode);
-begin
-  pragma(c, s, n, {@set}[FirstCallConv..LastCallConv,
-    wImportc, wExportc, wNodecl, wNosideEffect, wSideEffect, 
-    wNoreturn, wDynLib, wHeader, wPure, wDeprecated]);
-end;
-
-procedure pragmaType(c: PContext; s: PSym; n: PNode);
-begin
-  pragma(c, s, n, {@set}[wImportc, wExportc, wDeprecated, wMagic, wAcyclic,
-                         wNodecl, wPure, wHeader, wCompilerProc, wFinal]);
-end;
-
-procedure pragmaField(c: PContext; s: PSym; n: PNode);
-begin
-  pragma(c, s, n, {@set}[wImportc, wExportc, wDeprecated]);
-end;
-
-procedure pragmaVar(c: PContext; s: PSym; n: PNode);
-begin
-  pragma(c, s, n, {@set}[wImportc, wExportc, wVolatile, wRegister, wThreadVar,
-                         wNodecl, wMagic, wHeader, wDeprecated, wCompilerProc,
-                         wDynLib]);
-end;
-
-procedure pragmaConst(c: PContext; s: PSym; n: PNode);
-begin
-  pragma(c, s, n, {@set}[wImportc, wExportc, wHeader, wDeprecated,
-                         wMagic, wNodecl]);
-end;
-
-procedure pragmaProcType(c: PContext; s: PSym; n: PNode);
-begin
-  pragma(c, s, n, [FirstCallConv..LastCallConv, wVarargs]);
-end;
-
 end.
diff --git a/nim/procfind.pas b/nim/procfind.pas
index c8792586a..e93820ab3 100644..100755
--- a/nim/procfind.pas
+++ b/nim/procfind.pas
@@ -16,7 +16,7 @@ interface
 {$include 'config.inc'}
 
 uses 
-  nsystem, ast, astalgo, msgs, semdata, types;
+  nsystem, ast, astalgo, msgs, semdata, types, trees;
 
 function SearchForProc(c: PContext; fn: PSym; tos: int): PSym;
 // Searchs for the fn in the symbol table. If the parameter lists are exactly
@@ -45,7 +45,9 @@ begin
       InternalError(procB.info, 'equalGenericParams');
     a := procA.sons[i].sym;
     b := procB.sons[i].sym;
-    if (a.name.id <> b.name.id) or not sameType(a.typ, b.typ) then exit;
+    if (a.name.id <> b.name.id) or not sameTypeOrNil(a.typ, b.typ) then exit;
+    if (a.ast <> nil) and (b.ast <> nil) then
+      if not ExprStructuralEquivalent(a.ast, b.ast) then exit;
   end;
   result := true
 end;
@@ -85,10 +87,10 @@ begin
       m := a.sons[i].sym;
       n := b.sons[i].sym;
       assert((m.kind = skParam) and (n.kind = skParam));
-      if not equalOrAbstractOf(m.typ, n.typ) then exit;
+      if not equalOrDistinctOf(m.typ, n.typ) then exit;
     end;
     // return type:
-    if not equalOrAbstractOf(a.sons[0].typ, b.sons[0].typ) then exit;
+    if not equalOrDistinctOf(a.sons[0].typ, b.sons[0].typ) then exit;
     result := true
   end
 end;
diff --git a/nim/ptmplsyn.pas b/nim/ptmplsyn.pas
index 2368b22c7..2368b22c7 100644..100755
--- a/nim/ptmplsyn.pas
+++ b/nim/ptmplsyn.pas
diff --git a/nim/readme.txt b/nim/readme.txt
index 99d574bac..99d574bac 100644..100755
--- a/nim/readme.txt
+++ b/nim/readme.txt
diff --git a/nim/rnimsyn.pas b/nim/rnimsyn.pas
index 0ed3cfcd7..b3271a3bb 100644..100755
--- a/nim/rnimsyn.pas
+++ b/nim/rnimsyn.pas
@@ -188,10 +188,8 @@ var
   i: int;
 begin
   result := '"' + '';
-  for i := strStart to length(s)+strStart-1 do begin
-    result := result +{&} toNimChar(s[i]);
-  end;
-  result := result + '"';
+  for i := strStart to length(s)+strStart-1 do add(result, toNimChar(s[i]));
+  addChar(result, '"');
 end;
 
 procedure putComment(var g: TSrcGen; s: string);
@@ -496,7 +494,7 @@ begin
     nkAddr: result := lsub(n.sons[0])+length('addr()');
     nkHiddenAddr, nkHiddenDeref: result := lsub(n.sons[0]);
     nkCommand: result := lsub(n.sons[0])+lcomma(n, 1)+1;
-    nkExprEqExpr, nkDefaultTypeParam, nkAsgn, nkFastAsgn: result := lsons(n)+3;
+    nkExprEqExpr, 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[]');
@@ -528,10 +526,10 @@ begin
     nkInfix:          result := lsons(n) + 2;
     nkPrefix:         result := lsons(n) + 1;
     nkPostfix:        result := lsons(n);
+    nkCallStrLit:     result := lsons(n);
     nkPragmaExpr:     result := lsub(n.sons[0])+lcomma(n, 1);
     nkRange:          result := lsons(n) + 2;
     nkDerefExpr:      result := lsub(n.sons[0])+2;
-    nkImportAs:       result := lsons(n) + length('_as_');
     nkAccQuoted:      result := lsub(n.sons[0]) + 2;
 
     nkIfExpr:         result := lsub(n.sons[0].sons[0])+lsub(n.sons[0].sons[1])
@@ -544,7 +542,7 @@ begin
     nkRefTy:          result := lsub(n.sons[0])+length('ref_');
     nkPtrTy:          result := lsub(n.sons[0])+length('ptr_');
     nkVarTy:          result := lsub(n.sons[0])+length('var_');
-    nkAbstractTy:     result := lsub(n.sons[0])+length('abstract_');
+    nkDistinctTy:     result := lsub(n.sons[0])+length('Distinct_');
     nkTypeDef:        result := lsons(n)+3;
     nkOfInherit:      result := lsub(n.sons[0])+length('of_');
     nkProcTy:         result := lsons(n)+length('proc_');
@@ -612,11 +610,6 @@ begin
   gsub(g, n, c);
 end;
 
-function one(b: bool): int;
-begin
-  if b then result := 1 else result := 0
-end;
-
 function hasCom(n: PNode): bool;
 var
   i: int;
@@ -649,7 +642,7 @@ var
 begin
   for i := start to sonsLen(n)+theEnd do begin
     c := i < sonsLen(n)+theEnd;
-    sublen := lsub(n.sons[i])+one(c);
+    sublen := lsub(n.sons[i])+ord(c);
     if not fits(g, sublen) and (ind+sublen < maxLineLen) then optNL(g, ind);
     gsub(g, n.sons[i]);
     if c then begin
@@ -959,6 +952,13 @@ begin
       gcomma(g, n, 1);
       put(g, tkParRi, ')'+'');
     end;
+    nkCallStrLit: begin
+      gsub(g, n.sons[0]);
+      if n.sons[1].kind = nkRStrLit then
+        put(g, tkRStrLit, '"' + n.sons[1].strVal + '"')
+      else
+        gsub(g, n.sons[0]);
+    end;
     nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: begin
       gsub(g, n.sons[0]);
     end;
@@ -992,7 +992,7 @@ begin
       put(g, tkSpaces, space);
       gcomma(g, n, 1);
     end;
-    nkExprEqExpr, nkDefaultTypeParam, nkAsgn, nkFastAsgn: begin
+    nkExprEqExpr, nkAsgn, nkFastAsgn: begin
       gsub(g, n.sons[0]);
       put(g, tkSpaces, Space);
       putWithSpace(g, tkEquals, '='+'');
@@ -1121,12 +1121,6 @@ begin
       // unfortunately this requires a space, because ^. would be
       // only one operator
     end;
-    nkImportAs: begin
-      gsub(g, n.sons[0]);
-      put(g, tkSpaces, Space);
-      putWithSpace(g, tkAs, 'as');
-      gsub(g, n.sons[1]);
-    end;
     nkAccQuoted: begin
       put(g, tkAccent, '`'+'');
       gsub(g, n.sons[0]);
@@ -1167,8 +1161,8 @@ begin
       putWithSpace(g, tkVar, 'var');
       gsub(g, n.sons[0]);
     end;
-    nkAbstractTy: begin
-      putWithSpace(g, tkAbstract, 'abstract');
+    nkDistinctTy: begin
+      putWithSpace(g, tkDistinct, 'distinct');
       gsub(g, n.sons[0]);
     end;
     nkTypeDef: begin
diff --git a/nim/rodread.pas b/nim/rodread.pas
index a34153ccf..dc3630a45 100644..100755
--- a/nim/rodread.pas
+++ b/nim/rodread.pas
@@ -172,7 +172,7 @@ begin
   res := '';
   for i := strStart to length(s)+strStart-1 do begin
     case s[i] of
-      '0'..'9', 'a'..'z', 'A'..'Z', '_':
+      'a'..'z', 'A'..'Z', '0'..'9', '_':
         addChar(res, s[i]);
       else
         res := res +{&} '\' +{&} toHex(ord(s[i]), 2)
@@ -535,7 +535,7 @@ var
 begin
   i := r.pos;
   sign := -1;
-  assert(r.s[i] in ['0'..'9', 'a'..'z', 'A'..'Z', '-', #128..#255]);
+  assert(r.s[i] in ['a'..'z', 'A'..'Z', '0'..'9', '-', #128..#255]);
   if r.s[i] = '-' then begin
     inc(i);
     sign := 1
@@ -562,7 +562,7 @@ var
 begin
   i := r.pos;
   sign := -1;
-  assert(r.s[i] in ['0'..'9', 'a'..'z', 'A'..'Z', '-', #128..#255]);
+  assert(r.s[i] in ['a'..'z', 'A'..'Z', '0'..'9', '-', #128..#255]);
   if r.s[i] = '-' then begin
     inc(i);
     sign := 1
@@ -606,7 +606,7 @@ begin
         hexChar(r.s[i-1], xi);
         addChar(result, chr(xi));
       end;
-      'a'..'z', '0'..'9', 'A'..'Z', '_': begin
+      'a'..'z', 'A'..'Z', '0'..'9', '_': begin
         addChar(result, r.s[i]);
         inc(i);
       end
diff --git a/nim/rodwrite.pas b/nim/rodwrite.pas
index 72d5c893d..72d5c893d 100644..100755
--- a/nim/rodwrite.pas
+++ b/nim/rodwrite.pas
diff --git a/nim/ropes.pas b/nim/ropes.pas
index 286f1b9e6..286f1b9e6 100644..100755
--- a/nim/ropes.pas
+++ b/nim/ropes.pas
diff --git a/nim/rst.pas b/nim/rst.pas
index d2afc7e33..d5cde5c7e 100644..100755
--- a/nim/rst.pas
+++ b/nim/rst.pas
@@ -142,6 +142,8 @@ procedure addSon(father, son: PRstNode);
 
 function rstnodeToRefname(n: PRstNode): string;
 
+function addNodes(n: PRstNode): string;
+
 function getFieldValue(n: PRstNode; const fieldname: string): string;
 function getArgument(n: PRstNode): string;
 
@@ -1834,7 +1836,6 @@ begin
       rnDirective: a := parseDotDot(p);
       rnEnumList: a := parseEnumList(p);
       rnLeaf: begin
-        //writeln(ord(p.tok[p.idx].kind), '  ', p.tok[p.idx].symbol);
         rstMessage(p, errNewSectionExpected);
       end;
       rnParagraph: begin end;
@@ -1856,14 +1857,9 @@ begin
     end;
     addSonIfNotNil(result, a);
   end;
-  //if (result.kind in [rnBulletItem]) and
   if (sonKind(result, 0) = rnParagraph)
   and (sonKind(result, 1) <> rnParagraph) then
     result.sons[0].kind := rnInner;
-  (*
-  if (result.kind <> rnInner) and (rsonsLen(result) = 1)
-  and (result.sons[0].kind = rnParagraph) then
-    result.sons[0].kind := rnInner; *)
 end;
 
 function parseSectionWrapper(var p: TRstParser): PRstNode;
@@ -1921,7 +1917,6 @@ begin
   if (assigned(contentParser)) and (p.tok[p.idx].kind = tkIndent)
   and (p.tok[p.idx].ival > currInd(p)) then begin
     pushInd(p, p.tok[p.idx].ival);
-    //while p.tok[p.idx].kind = tkIndent do inc(p.idx);
     content := contentParser(p);
     popInd(p);
     addSon(result, content)
@@ -2085,7 +2080,7 @@ begin
       dkRaw:        result := dirRaw(p);
       dkCodeblock:  result := dirCodeBlock(p);
       dkIndex:      result := dirIndex(p);
-      else          rstMessage(p, errUnknownDirective, d);
+      else          rstMessage(p, errInvalidDirectiveX, d);
     end;
     popInd(p);
   end
@@ -2112,7 +2107,7 @@ begin
       b := dirImage(p);
     end
     else
-      rstMessage(p, errUnknownDirective, p.tok[p.idx].symbol);
+      rstMessage(p, errInvalidDirectiveX, p.tok[p.idx].symbol);
     setSub(p, addNodes(a), b);
   end
   else if match(p, p.idx, ' [') then begin
@@ -2172,6 +2167,8 @@ function rstParse(const text: string; // the text to be parsed
 var
   p: TRstParser;
 begin
+  if isNil(text) then
+    rawMessage(errCannotOpenFile, filename);
   initParser(p, newSharedState());
   p.filename := filename;
   p.line := line;
diff --git a/nim/scanner.pas b/nim/scanner.pas
index edc9ca24a..ffe1741f5 100644..100755
--- a/nim/scanner.pas
+++ b/nim/scanner.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.
@@ -52,10 +52,10 @@ type
     //  i = i + 1
     //cog.out(idents)
     //]]]
-    tkAbstract, tkAddr, tkAnd, tkAs, 
-    tkAsm, tkBind, tkBlock, tkBreak, 
-    tkCase, tkCast, tkConst, tkContinue, 
-    tkConverter, tkDiscard, tkDiv, tkElif, 
+    tkAddr, tkAnd, tkAs, tkAsm, 
+    tkBind, tkBlock, tkBreak, tkCase, 
+    tkCast, tkConst, tkContinue, tkConverter, 
+    tkDiscard, tkDistinct, tkDiv, tkElif, 
     tkElse, tkEnd, tkEnum, tkExcept, 
     tkFinally, tkFor, tkFrom, tkGeneric, 
     tkIf, tkImplies, tkImport, tkIn, 
@@ -71,8 +71,8 @@ type
     //[[[end]]]
     tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit,
     tkFloatLit, tkFloat32Lit, tkFloat64Lit,
-    tkStrLit, tkRStrLit, tkTripleStrLit, tkCharLit,
-    tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
+    tkStrLit, tkRStrLit, tkTripleStrLit, tkCallRStrLit, tkCallTripleStrLit,
+    tkCharLit, tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
     tkBracketDotLe, tkBracketDotRi, // [. and  .]
     tkCurlyDotLe, tkCurlyDotRi, // {.  and  .}
     tkParDotLe, tkParDotRi, // (. and .)
@@ -96,10 +96,10 @@ const
     //[[[cog
     //cog.out(strings)
     //]]]
-    'abstract', 'addr', 'and', 'as', 
-    'asm', 'bind', 'block', 'break', 
-    'case', 'cast', 'const', 'continue', 
-    'converter', 'discard', 'div', 'elif', 
+    'addr', 'and', 'as', 'asm', 
+    'bind', 'block', 'break', 'case', 
+    'cast', 'const', 'continue', 'converter', 
+    'discard', 'distinct', 'div', 'elif', 
     'else', 'end', 'enum', 'except', 
     'finally', 'for', 'from', 'generic', 
     'if', 'implies', 'import', 'in', 
@@ -115,7 +115,9 @@ const
     //[[[end]]]
     'tkIntLit', 'tkInt8Lit', 'tkInt16Lit', 'tkInt32Lit', 'tkInt64Lit',
     'tkFloatLit', 'tkFloat32Lit', 'tkFloat64Lit',
-    'tkStrLit', 'tkRStrLit', 'tkTripleStrLit', 'tkCharLit',
+    'tkStrLit', 'tkRStrLit', 'tkTripleStrLit',
+    'tkCallRStrLit', 'tkCallTripleStrLit',
+    'tkCharLit',
     '('+'', ')'+'', '['+'', ']'+'', '{'+'', '}'+'',
     '[.', '.]', '{.', '.}', '(.', '.)', ','+'', ';'+'', ':'+'',
     '='+'', '.'+'', '..', '^'+'', 'tkOpr',
@@ -764,7 +766,12 @@ begin
      (tok.ident.id > ord(tokKeywordHigh)-ord(tkSymbol)) then
     tok.tokType := tkSymbol
   else
-    tok.tokType := TTokType(tok.ident.id+ord(tkSymbol))
+    tok.tokType := TTokType(tok.ident.id+ord(tkSymbol));
+  if buf[pos] = '"' then begin
+    getString(L, tok, true);
+    if tok.tokType = tkRStrLit then tok.tokType := tkCallRStrLit
+    else tok.tokType := tkCallTripleStrLit
+  end
 end;
 
 procedure getOperator(var L: TLexer; var tok: TToken);
diff --git a/nim/sem.pas b/nim/sem.pas
index 1fd141f5a..029ba869f 100644..100755
--- a/nim/sem.pas
+++ b/nim/sem.pas
@@ -15,7 +15,7 @@ interface
 {$include 'config.inc'}
 
 uses
-  sysutils, nsystem, charsets, strutils,
+  sysutils, nsystem, charsets, strutils, nhashes,
   lists, options, scanner, ast, astalgo, trees, treetab, wordrecg,
   ropes, msgs, nos, condsyms, idents, rnimsyn, types, platform,
   nmath, magicsys, pnimsyn, nversion, nimsets,
@@ -29,8 +29,6 @@ function semPass(): TPass;
 
 implementation
 
-function semp(c: PContext; n: PNode): PNode; forward;
-
 function considerAcc(n: PNode): PIdent;
 var
   x: PNode;
@@ -47,6 +45,11 @@ begin
   end
 end;
 
+function isTopLevel(c: PContext): bool;
+begin
+  result := c.tab.tos <= 2
+end;
+
 function newSymS(const kind: TSymKind; n: PNode; c: PContext): PSym;
 begin
   result := newSym(kind, considerAcc(n), getCurrOwner());
@@ -62,27 +65,32 @@ function semIdentWithPragma(c: PContext; kind: TSymKind;
 function semStmtScope(c: PContext; n: PNode): PNode; forward;
 
 type
-  TExprFlag = (efAllowType, efLValue);
+  TExprFlag = (efAllowType, efLValue, efWantIterator);
   TExprFlags = set of TExprFlag;
 
 function semExpr(c: PContext; n: PNode;
                  flags: TExprFlags = {@set}[]): PNode; forward;
 function semExprWithType(c: PContext; n: PNode;
                          flags: TExprFlags = {@set}[]): PNode; forward;
+function fitNode(c: PContext; formal: PType; arg: PNode): PNode; forward;
 function semLambda(c: PContext; n: PNode): PNode; forward;
 function semTypeNode(c: PContext; n: PNode; prev: PType): PType; forward;
 function semStmt(c: PContext; n: PNode): PNode; forward;
+procedure semParamList(c: PContext; n, genericParams: PNode; s: PSym); forward;
+procedure addParams(c: PContext; n: PNode); forward;
+procedure addResult(c: PContext; t: PType; const info: TLineInfo); forward;
+procedure addResultNode(c: PContext; n: PNode); forward;
+
+function instGenericContainer(c: PContext; n: PNode; header: PType): PType; forward;
 
 function semConstExpr(c: PContext; n: PNode): PNode;
-var
-  e: PNode;
 begin
-  e := semExprWithType(c, n);
-  if e = nil then begin
+  result := semExprWithType(c, n);
+  if result = nil then begin
     liMessage(n.info, errConstExprExpected);
-    result := nil; exit
+    exit
   end;
-  result := getConstExpr(c.module, e);
+  result := getConstExpr(c.module, result);
   if result = nil then 
     liMessage(n.info, errConstExprExpected);
 end;
@@ -105,24 +113,19 @@ begin
   end
 end;
 
-function semAfterMacroCall(c: PContext; n, p: PNode): PNode;
+function semAfterMacroCall(c: PContext; n: PNode; s: PSym): PNode;
 begin
   result := n;
-  if (p = nil) or (p.kind <> nkIdent) then
-    liMessage(n.info, errInvalidParamKindX, renderTree(p))
-  else begin
-    case p.ident.id of
-      ord(wExpr): result := semExprWithType(c, result);
-      ord(wStmt): result := semStmt(c, result);
-      ord(wTypeDesc): 
-        result.typ := semTypeNode(c, result, nil);
-      else
-        liMessage(p.info, errInvalidParamKindX, p.ident.s)
-    end
+  case s.typ.sons[0].kind of
+    tyExpr: result := semExprWithType(c, result);
+    tyStmt: result := semStmt(c, result);
+    tyTypeDesc: result.typ := semTypeNode(c, result, nil);
+    else liMessage(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
   end
 end;
 
-function semMacroExpr(c: PContext; n: PNode; sym: PSym): PNode;
+function semMacroExpr(c: PContext; n: PNode; sym: PSym;
+                      semCheck: bool = true): PNode;
 var
   p: PEvalContext;
   s: PStackFrame;
@@ -139,9 +142,8 @@ begin
   result := s.params[0];
   popStackFrame(p);
   if cyclicTree(result) then liMessage(n.info, errCyclicTree);
-  result := semAfterMacroCall(c, result, sym.ast.sons[paramsPos].sons[0]);
-  // now, that was easy ...
-  // and we get more flexibility than in any other programming language
+  if semCheck then
+    result := semAfterMacroCall(c, result, sym);
 end;
 
 {$include 'semtempl.pas'}
@@ -164,13 +166,9 @@ end;
 
 {$include 'semtypes.pas'}
 {$include 'semexprs.pas'}
+{$include 'semgnrc.pas'}
 {$include 'semstmts.pas'}
 
-function semp(c: PContext; n: PNode): PNode;
-begin
-  result := semStmt(c, n);
-end;
-
 procedure addCodeForGenerics(c: PContext; n: PNode);
 var
   i: int;
diff --git a/nim/semdata.pas b/nim/semdata.pas
index acaffd3bf..37934f3d6 100644..100755
--- a/nim/semdata.pas
+++ b/nim/semdata.pas
@@ -42,24 +42,29 @@ type
 
   PContext = ^TContext;
   TContext = object(TPassContext) // a context represents a module
-    module: PSym;            // the module sym belonging to the context
-    filename: string;        // the module's filename
-    tab: TSymTab;            // each module has its own symbol table
-    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
-                             // symbol and the instantiated symbol
-    converters: TSymSeq;     // sequence of converters
+    module: PSym;                 // the module sym belonging to the context
+    p: PProcCon;                  // procedure context
+    InstCounter: int;             // to prevent endless instantiations
+    generics: PNode;              // a list of the things to compile; list of
+                                  // nkExprEqExpr nodes which contain the
+                                  // generic symbol and the instantiated symbol
+    lastGenericIdx: int;          // used for the generics stack
+    tab: TSymTab;                 // each module has its own symbol table
+    AmbiguousSymbols: TIntSet;    // ids of all ambiguous symbols (cannot
+                                  // store this info in the syms themselves!)
+    converters: TSymSeq;          // sequence of converters
     optionStack: TLinkedList;
-    libs: TLinkedList;       // all libs used by this module
-    p: PProcCon;             // procedure context
-    fromCache: bool;         // is the module read from a cache?
-    lastGenericIdx: int;     // used for the generics stack
+    libs: TLinkedList;            // all libs used by this module
+    fromCache: bool;              // is the module read from a cache?
     semConstExpr: function (c: PContext; n: PNode): PNode;
       // for the pragmas module
+    includedFiles: TIntSet;       // used to detect recursive include files
+    filename: string;             // the module's filename
   end;
 
+var
+  gInstTypes: TIdTable; // map PType to PType
+
 function newContext(module: PSym; const nimfile: string): PContext;
 function newProcCon(owner: PSym): PProcCon;
 
@@ -164,6 +169,7 @@ begin
   result.generics := newNode(nkStmtList);
 {@emit result.converters := @[];}
   result.filename := nimfile;
+  IntSetInit(result.includedFiles);
 end;
 
 procedure addConverter(c: PContext; conv: PSym);
@@ -255,4 +261,6 @@ begin
   if (n = nil) or (sonsLen(n) < len) then illFormedAst(n);
 end;
 
+initialization
+  initIdTable(gInstTypes);
 end.
diff --git a/nim/semexprs.pas b/nim/semexprs.pas
index de37295b7..2fd0d6843 100644..100755
--- a/nim/semexprs.pas
+++ b/nim/semexprs.pas
@@ -10,6 +10,17 @@
 
 // this module does the semantic checking for expressions
 
+function semTemplateExpr(c: PContext; n: PNode; s: PSym;
+                         semCheck: bool = true): PNode;
+begin
+  include(s.flags, sfUsed);
+  pushInfoContext(n.info);
+  result := evalTemplate(c, n, s);
+  if semCheck then
+    result := semAfterMacroCall(c, result, s);
+  popInfoContext();
+end;
+
 function semDotExpr(c: PContext; n: PNode;
                     flags: TExprFlags = {@set}[]): PNode; forward;
 
@@ -79,8 +90,8 @@ begin
     // we use d, s here to speed up that operation a bit:
     case cmpTypes(d, s) of
       isNone, isGeneric: begin
-        if not equalOrAbstractOf(castDest, src) and
-           not equalOrAbstractOf(src, castDest) then
+        if not equalOrDistinctOf(castDest, src) and
+           not equalOrDistinctOf(src, castDest) then
           liMessage(info, errGenerated,
             format(MsgKindToString(errIllegalConvFromXtoY),
               [typeToString(src), typeToString(castDest)]));
@@ -457,15 +468,21 @@ begin
       n.sons[i] := analyseIfAddressTaken(c, n.sons[i]);
 end;
 
-function semDirectCallAnalyseEffects(c: PContext; n: PNode): PNode;
+function semDirectCallAnalyseEffects(c: PContext; n: PNode; 
+                                     flags: TExprFlags): PNode;
 var
   callee: PSym;
 begin
-  result := semDirectCall(c, n);
+  if not (efWantIterator in flags) then 
+    result := semDirectCall(c, n, {@set}[skProc, skConverter])
+  else
+    result := semDirectCall(c, n, {@set}[skIterator]);
   if result <> nil then begin
     if result.sons[0].kind <> nkSym then 
       InternalError('semDirectCallAnalyseEffects');
     callee := result.sons[0].sym;
+    if (callee.kind = skIterator) and (callee.id = c.p.owner.id) then
+      liMessage(n.info, errRecursiveDependencyX, callee.name.s);
     if not (sfNoSideEffect in callee.flags) then 
       if (sfForward in callee.flags) 
       or ([sfImportc, sfSideEffect] * callee.flags <> []) then 
@@ -473,12 +490,13 @@ begin
   end
 end;
 
-function semIndirectOp(c: PContext; n: PNode): PNode;
+function semIndirectOp(c: PContext; n: PNode; flags: TExprFlags): PNode;
 var
   m: TCandidate;
   msg: string;
   i: int;
   prc: PNode;
+  t: PType;
 begin
   result := nil;
   prc := n.sons[0];
@@ -496,13 +514,12 @@ begin
       end
     end;
     else n.sons[0] := semExpr(c, n.sons[0]);
-  end;
-  if n.sons[0].typ = nil then
-    liMessage(n.sons[0].info, errExprXHasNoType,
-              renderTree(n.sons[0], {@set}[renderNoComments]));
+  end; 
   semOpAux(c, n);
-  if (n.sons[0].typ <> nil) and (n.sons[0].typ.kind = tyProc) then begin
-    initCandidate(m, n.sons[0].typ);
+  if (n.sons[0].typ <> nil) then t := skipTypes(n.sons[0].typ, abstractInst)
+  else t := nil;
+  if (t <> nil) and (t.kind = tyProc) then begin
+    initCandidate(m, t);
     matches(c, n, m);
     if m.state <> csMatch then begin
       msg := msgKindToString(errTypeMismatch);
@@ -519,7 +536,8 @@ begin
       result := m.call;
     // we assume that a procedure that calls something indirectly 
     // has side-effects:
-    include(c.p.owner.flags, sfSideEffect);
+    if not (tfNoSideEffect in t.flags) then
+      include(c.p.owner.flags, sfSideEffect);
   end
   else begin
     result := overloadedCallOpr(c, n);
@@ -527,7 +545,7 @@ begin
     // 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);
+      result := semDirectCallAnalyseEffects(c, n, flags);
     end;
     if result = nil then 
       liMessage(n.info, errExprXCannotBeCalled, 
@@ -537,11 +555,11 @@ begin
   analyseIfAddressTakenInCall(c, result);
 end;
 
-function semDirectOp(c: PContext; n: PNode): PNode;
+function semDirectOp(c: PContext; n: PNode; flags: TExprFlags): PNode;
 begin
   // this seems to be a hotspot in the compiler!
   semOpAux(c, n);
-  result := semDirectCallAnalyseEffects(c, n);
+  result := semDirectCallAnalyseEffects(c, n, flags);
   if result = nil then begin
     result := overloadedCallOpr(c, n);
     if result = nil then
@@ -624,18 +642,19 @@ begin
   n.sons[0].info := n.info;
 end;
 
-function semMagic(c: PContext; n: PNode; s: PSym): PNode;
+function semMagic(c: PContext; n: PNode; s: PSym; flags: TExprFlags): PNode;
 // this is a hotspot in the compiler!
 begin
   result := n;
   case s.magic of // magics that need special treatment
     mDefined: result := semDefined(c, setMs(n, s));
+    mDefinedInScope: result := semDefinedInScope(c, setMs(n, s));
     mLow:     result := semLowHigh(c, setMs(n, s), mLow);
     mHigh:    result := semLowHigh(c, setMs(n, s), mHigh);
     mSizeOf:  result := semSizeof(c, setMs(n, s));
     mIs:      result := semIs(c, setMs(n, s));
     mEcho:    result := semEcho(c, setMs(n, s)); 
-    else      result := semDirectOp(c, n);
+    else      result := semDirectOp(c, n, flags);
   end;
 end;
 
@@ -644,67 +663,6 @@ begin
   if sfDeprecated in s.flags then liMessage(n.info, warnDeprecated, s.name.s);  
 end;
 
-function semSym(c: PContext; n: PNode; s: PSym; flags: TExprFlags): PNode;
-begin
-  if (s.kind = skType) and not (efAllowType in flags) then
-    liMessage(n.info, errATypeHasNoValue);
-  case s.kind of
-    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::
-          const x = []
-          proc p(a: openarray[int], i: int)
-          proc q(a: openarray[char], c: char)
-          p(x, 0)
-          q(x, '\0')
-
-        It is clear that ``[]`` means two totally different things. Thus, we
-        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;
-    skTemplate: begin
-      include(s.flags, sfUsed);
-      // Templates and macros can be invoked without ``()``
-      pushInfoContext(n.info);
-      result := evalTemplate(c, n, s);
-      popInfoContext();
-    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;
-
 function isTypeExpr(n: PNode): bool;
 begin
   case n.kind of
@@ -797,12 +755,12 @@ var
   t: PType;
   a: PNode;
 begin
-  t := n.typ;
+  t := skipTypes(n.typ, {@set}[tyGenericInst]);
   result := n;
   if t.kind = tyVar then begin
     result := newNodeIT(nkHiddenDeref, n.info, t.sons[0]);
     addSon(result, n);
-    t := t.sons[0];
+    t := skipTypes(t.sons[0], {@set}[tyGenericInst]);
   end;
   if t.kind in [tyPtr, tyRef] then begin
     a := result;
@@ -830,7 +788,7 @@ begin
     // look up if the identifier belongs to the enum:
     while (ty <> nil) do begin
       f := getSymFromList(ty.n, i);
-      if f <> nil then breaK;
+      if f <> nil then break;
       ty := ty.sons[0]; // enum inheritance
     end;
     if f <> nil then begin
@@ -891,7 +849,7 @@ begin
   // --> replace("", ...)
   f := SymTabGet(c.tab, i);
   //if (f <> nil) and (f.kind = skStub) then loadStub(f);
-  // XXX ``loadStub`` is not correct here as we don't care for ``f`` really
+  // ``loadStub`` is not correct here as we don't care for ``f`` really
   if (f <> nil) then begin
     // BUGFIX: do not check for (f.kind in [skProc, skIterator]) here
     result := newNodeI(nkDotCall, n.info);
@@ -1168,24 +1126,13 @@ begin
   Dec(c.p.nestedBlockCounter);
 end;
 
-function semDotExpr(c: PContext; n: PNode; flags: TExprFlags): PNode;
-var
-  s: PSym;
-begin
-  s := qualifiedLookup(c, n, true); // check for ambiguity
-  if s <> nil then
-    result := semSym(c, n, s, flags)
-  else
-    // this is a test comment; please don't touch it
-    result := semFieldAccess(c, n, flags);
-end;
-
 function isCallExpr(n: PNode): bool;
 begin
-  result := n.kind in [nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand];
+  result := n.kind in [nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand,
+                       nkCallStrLit];
 end;
 
-function semMacroStmt(c: PContext; n: PNode): PNode;
+function semMacroStmt(c: PContext; n: PNode; semCheck: bool = true): PNode;
 var
   s: PSym;
   a: PNode;
@@ -1200,9 +1147,8 @@ begin
   if (s <> nil) then begin
     checkDeprecated(n, s);
     case s.kind of
-      skMacro: result := semMacroExpr(c, n, s);
+      skMacro: result := semMacroExpr(c, n, s, semCheck);
       skTemplate: begin
-        include(s.flags, sfUsed);
         // transform
         // nkMacroStmt(nkCall(a...), stmt, b...)
         // to
@@ -1213,11 +1159,8 @@ begin
           for i := 1 to sonsLen(n.sons[0])-1 do
             addSon(result, n.sons[0].sons[i]);
         end;
-        for i := 1 to sonsLen(n)-1 do
-          addSon(result, n.sons[i]);
-        pushInfoContext(n.info);
-        result := evalTemplate(c, result, s);
-        popInfoContext();
+        for i := 1 to sonsLen(n)-1 do addSon(result, n.sons[i]);
+        result := semTemplateExpr(c, result, s, semCheck);
       end;
       else
         liMessage(n.info, errXisNoMacroOrTemplate, s.name.s);
@@ -1228,9 +1171,78 @@ begin
               renderTree(a, {@set}[renderNoComments]));
 end;
 
+function semSym(c: PContext; n: PNode; s: PSym; flags: TExprFlags): PNode;
+begin
+  if (s.kind = skType) and not (efAllowType in flags) then
+    liMessage(n.info, errATypeHasNoValue);
+  case s.kind of
+    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::
+          const x = []
+          proc p(a: openarray[int])
+          proc q(a: openarray[char])
+          p(x)
+          q(x)
+
+        It is clear that ``[]`` means two totally different things. Thus, we
+        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: result := semMacroExpr(c, n, s);
+    skTemplate: result := semTemplateExpr(c, n, s);
+    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;
+    skGenericParam: begin
+      if s.ast = nil then InternalError(n.info, 'no default for');
+      result := semExpr(c, s.ast);
+    end
+    else begin
+      include(s.flags, sfUsed);
+      result := newSymNode(s);
+      result.info := n.info;
+    end
+  end;
+  checkDeprecated(n, s);
+end;
+
+function semDotExpr(c: PContext; n: PNode; flags: TExprFlags): PNode;
+var
+  s: PSym;
+begin
+  s := qualifiedLookup(c, n, true); // check for ambiguity
+  if s <> nil then
+    result := semSym(c, n, s, flags)
+  else
+    // this is a test comment; please don't touch it
+    result := semFieldAccess(c, n, flags);
+end;
+
 function semExpr(c: PContext; n: PNode; flags: TExprFlags = {@set}[]): PNode;
 var
   s: PSym;
+  t: PType;
 begin
   result := n;
   if n = nil then exit;
@@ -1242,13 +1254,16 @@ begin
       result := semSym(c, n, s, flags);
     end;
     nkSym: begin
-      s := n.sym;
+      (*s := n.sym;
       include(s.flags, sfUsed);
       if (s.kind = skType) and not (efAllowType in flags) then
         liMessage(n.info, errATypeHasNoValue);
       if (s.magic <> mNone) and
           (s.kind in [skProc, skIterator, skConverter]) then
-        liMessage(n.info, errInvalidContextForBuiltinX, s.name.s);
+        liMessage(n.info, errInvalidContextForBuiltinX, s.name.s); *)
+      // because of the changed symbol binding, this does not mean that we
+      // don't have to check the symbol for semantics here again!
+      result := semSym(c, n, n.sym, flags);
     end;
     nkEmpty, nkNone: begin end;
     nkNilLit: result.typ := getSysType(tyNil);
@@ -1276,7 +1291,7 @@ begin
       end;
     end;
     nkBind: result := semExpr(c, n.sons[0], flags);
-    nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand: begin
+    nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: begin
       // check if it is an expression macro:
       checkMinSonsLen(n, 1);
       s := qualifiedLookup(c, n.sons[0], false);
@@ -1284,26 +1299,28 @@ begin
         checkDeprecated(n, s);
         case s.kind of
           skMacro: result := semMacroExpr(c, n, s);
-          skTemplate: begin
-            include(s.flags, sfUsed);
-            pushInfoContext(n.info);
-            result := evalTemplate(c, n, s);
-            popInfoContext();
-          end;
+          skTemplate: result := semTemplateExpr(c, n, s);
           skType: begin
             include(s.flags, sfUsed);
             if n.kind <> nkCall then
               liMessage(n.info, errXisNotCallable, s.name.s);
+            // XXX does this check make any sense?
             result := semConv(c, n, s);
           end;
           skProc, skConverter, skIterator: begin
-            if s.magic = mNone then result := semDirectOp(c, n)
-            else result := semMagic(c, n, s);
+            if s.magic = mNone then result := semDirectOp(c, n, flags)
+            else result := semMagic(c, n, s, flags);
           end;
-          else result := semIndirectOp(c, n)
+          else begin
+            //liMessage(n.info, warnUser, renderTree(n));
+            result := semIndirectOp(c, n, flags)
+          end
         end
       end
-      else result := semIndirectOp(c, n);
+      else if n.sons[0].kind = nkSymChoice then
+        result := semDirectOp(c, n, flags)
+      else
+        result := semIndirectOp(c, n, flags);
     end;
     nkMacroStmt: begin
       result := semMacroStmt(c, n);
@@ -1341,8 +1358,9 @@ begin
       checkSonsLen(n, 1);
       n.sons[0] := semExprWithType(c, n.sons[0]);
       result := n;
-      case skipTypes(n.sons[0].typ, {@set}[tyGenericInst, tyVar]).kind of
-        tyRef, tyPtr: n.typ := n.sons[0].typ.sons[0];
+      t := skipTypes(n.sons[0].typ, {@set}[tyGenericInst, tyVar]);
+      case t.kind of
+        tyRef, tyPtr: n.typ := t.sons[0];
         else liMessage(n.sons[0].info, errCircumNeedsPointer);
       end;
       result := n;
diff --git a/nim/semfold.pas b/nim/semfold.pas
index 556dabe9b..acca84c71 100644..100755
--- a/nim/semfold.pas
+++ b/nim/semfold.pas
@@ -417,7 +417,7 @@ begin
     end;
     nkCharLit..nkNilLit: result := copyNode(n);
     nkIfExpr: result := getConstIfExpr(module, n);
-    nkCall, nkCommand: begin
+    nkCall, nkCommand, nkCallStrLit: begin
       if (n.sons[0].kind <> nkSym) then exit;
       s := n.sons[0].sym;
       if (s.kind <> skProc) then exit;
diff --git a/nim/seminst.pas b/nim/seminst.pas
index a49d8478e..6a6f272de 100644..100755
--- a/nim/seminst.pas
+++ b/nim/seminst.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.
@@ -10,102 +10,50 @@
 // This module does the instantiation of generic procs and types.
 
 function generateInstance(c: PContext; fn: PSym; const pt: TIdTable;
-                          const instantiator: TLineInfo): PSym; forward;
+                          const info: TLineInfo): PSym; forward;
 // generates an instantiated proc
 
-type
-  TInstantiateClosure = object(NObject)
-    typeMap: TIdTable;            // map PType to PType
-    symMap: TIdTable;             // map PSym to PSym
-    fn: PSym;
-    module: PSym;
-    //newOwner: PSym;
-    instantiator: TLineInfo;
-  end;
-  PInstantiateClosure = ^TInstantiateClosure;
-  PInstClosure = PInstantiateClosure;
-
-function instantiateTree(c: PInstantiateClosure; t: PNode): PNode; forward;
-function instantiateSym(c: PInstantiateClosure; sym: PSym): PSym; forward;
-function instantiateType(c: PInstantiateClosure; typ: PType): PType; forward;
-
-function containsGenericTypeIter(t: PType; closure: PObject): bool;
-begin
-  result := t.kind in GenericTypes;
-end;
-
-function containsGenericType(t: PType): bool;
-begin
-  result := iterOverType(t, containsGenericTypeIter, nil);
-end;
 
-function instTypeNode(c: PInstantiateClosure; n: PNode): PNode;
+function searchInstTypes(const tab: TIdTable; key: PType): PType;
 var
-  i: int;
-begin
-  result := nil;
-  if n <> nil then begin
-    result := copyNode(n);
-    result.typ := instantiateType(c, n.typ);
-    case n.kind of
-      nkNone..nkNilLit: begin // a leaf
-      end;
-      else begin
-        for i := 0 to sonsLen(n)-1 do
-          addSon(result, instTypeNode(c, n.sons[i]));
+  t: PType;
+  h: THash;
+  j: int;
+  match: bool;
+begin // returns nil if we need to declare this type
+  result := PType(IdTableGet(tab, key));
+  if (result = nil) and (tab.counter > 0) then begin
+    // we have to do a slow linear search because types may need
+    // to be compared by their structure:
+    for h := 0 to high(tab.data) do begin
+      t := PType(tab.data[h].key);
+      if t <> nil then begin
+        if key.containerId = t.containerID then begin
+          match := true;
+          for j := 0 to sonsLen(t) - 1 do begin
+            // XXX sameType is not really correct for nested generics?
+            if not sameType(t.sons[j], key.sons[j]) then begin
+              match := false; break
+            end
+          end;
+          if match then begin result := PType(tab.data[h].val); exit end;
+        end
       end
     end
   end
 end;
 
-procedure genericToConcreteTypeKind(t: PType);
-var
-  body: PNode;
+function containsGenericTypeIter(t: PType; closure: PObject): bool;
 begin
-  if (t.kind = tyGeneric) and (t.sym <> nil) then begin
-    body := t.sym.ast.sons[2];
-    case body.kind of
-      nkObjectTy: t.kind := tyObject;
-      nkTupleTy: t.kind := tyTuple;
-      nkRefTy: t.kind := tyRef;
-      nkPtrTy: t.kind := tyPtr;
-      nkVarTy: t.kind := tyVar;
-      nkProcTy: t.kind := tyProc;
-      else InternalError('genericToConcreteTypeKind');
-    end
-  end
+  result := t.kind in GenericTypes;
 end;
 
-function instantiateType(c: PInstantiateClosure; typ: PType): PType;
-var
-  i: int;
+function containsGenericType(t: PType): bool;
 begin
-  if typ = nil then begin result := nil; exit end;
-  result := PType(idTableGet(c.typeMap, typ));
-  if result <> nil then exit;
-  //if typ.kind = tyOpenArray then
-  //  liMessage(c.instantiator, warnUser, 'instantiating type for: openarray');
-  if containsGenericType(typ) then begin
-    result := copyType(typ, typ.owner, false);
-    idTablePut(c.typeMap, typ, result); // to avoid cycles
-    for i := 0 to sonsLen(result)-1 do
-      result.sons[i] := instantiateType(c, result.sons[i]);
-    if result.n <> nil then
-      result.n := instTypeNode(c, result.n);
-    genericToConcreteTypeKind(result);
-  end
-  else
-    result := typ;
-  if result.Kind in GenericTypes then begin
-    liMessage(c.instantiator, errCannotInstantiateX,
-              TypeToString(typ, preferName));
-  end
-  else if result.kind = tyVar then begin
-    if result.sons[0].kind = tyVar then
-      liMessage(c.instantiator, errVarVarTypeNotAllowed);
-  end;
+  result := iterOverType(t, containsGenericTypeIter, nil);
 end;
 
+(*
 function instantiateSym(c: PInstantiateClosure; sym: PSym): PSym;
 begin
   if sym = nil then begin result := nil; exit end; // BUGFIX
@@ -128,56 +76,31 @@ begin
       result := sym // do not copy t!
   end
 end;
+*)
 
-function instantiateTree(c: PInstantiateClosure; t: PNode): PNode;
-var
-  len, i: int;
-begin
-  if t = nil then begin result := nil; exit end;
-  result := copyNode(t);
-  if result.typ <> nil then result.typ := instantiateType(c, result.typ);
-  case t.kind of
-    nkNone..pred(nkSym), succ(nkSym)..nkNilLit: begin end;
-    nkSym: begin
-      if result.sym <> nil then result.sym := instantiateSym(c, result.sym);
-    end
-    else begin
-      len := sonsLen(t);
-      if len > 0 then begin
-        newSons(result, len);
-        for i := 0 to len-1 do
-          result.sons[i] := instantiateTree(c, t.sons[i]);
-      end
-    end
-  end
-end;
-
-procedure instantiateGenericParamList(c: PContext; n: PNode;
-                                      const pt: TIdTable);
+procedure instantiateGenericParamList(c: PContext; n: PNode; const pt: TIdTable);
 var
   i: int;
   s, q: PSym;
   t: PType;
+  a: PNode;
 begin
   if (n.kind <> nkGenericParams) then 
-    InternalError(n.info, 'instantiateGenericParamList');
+    InternalError(n.info, 'instantiateGenericParamList; no generic params');
   for i := 0 to sonsLen(n)-1 do begin
-    if n.sons[i].kind = nkDefaultTypeParam then begin
-      internalError(n.sons[i].info,
-        'instantiateGenericParamList() to implement');
-      // XXX
-    end;
-    if (n.sons[i].kind <> nkSym) then 
-      InternalError(n.info, 'instantiateGenericParamList');
-    q := n.sons[i].sym;
+    a := n.sons[i];
+    if a.kind <> nkSym then 
+      InternalError(a.info, 'instantiateGenericParamList; no symbol');
+    q := a.sym;
+    if not (q.typ.kind in [tyTypeDesc, tyGenericParam]) then continue;
     s := newSym(skType, q.name, getCurrOwner());
     t := PType(IdTableGet(pt, q.typ));
-    if t = nil then
-      liMessage(n.sons[i].info, errCannotInstantiateX, s.name.s);
-    if (t.kind = tyGenericParam) then
-      InternalError(n.info, 'instantiateGenericParamList');    
+    if t = nil then liMessage(a.info, errCannotInstantiateX, s.name.s);
+    if (t.kind = tyGenericParam) then begin
+      InternalError(a.info, 'instantiateGenericParamList: ' + q.name.s);
+    end;
     s.typ := t;
-    addDecl(c, s);
+    addDecl(c, s)
   end
 end;
 
@@ -212,25 +135,24 @@ begin
   addSon(c.generics, n);
 end;
 
-procedure semParamList(c: PContext; n: PNode; s: PSym); forward;
-procedure addParams(c: PContext; n: PNode); forward;
-procedure addResult(c: PContext; t: PType; const info: TLineInfo); forward;
-procedure addResultNode(c: PContext; n: PNode); forward;
-
 function generateInstance(c: PContext; fn: PSym; const pt: TIdTable;
-                          const instantiator: TLineInfo): PSym;
+                          const info: TLineInfo): PSym;
 // generates an instantiated proc
 var
-  oldPrc: PSym;
+  oldPrc, oldMod: PSym;
   oldP: PProcCon;
   n: PNode;
 begin
+  if c.InstCounter > 1000 then InternalError(fn.ast.info, 'nesting too deep');
+  inc(c.InstCounter);
   oldP := c.p; // restore later
+  // NOTE: for access of private fields within generics from a different module
+  // and other identifiers we fake the current module temporarily!
+  oldMod := c.module;
+  c.module := getModule(fn);
   result := copySym(fn, false);
   include(result.flags, sfFromGeneric);
-  //include(fn.flags, sfFromGeneric);
   result.owner := getCurrOwner().owner;
-  //idTablePut(c.mapping, fn, result);
   n := copyTree(fn.ast);
   result.ast := n;
   pushOwner(result);
@@ -238,13 +160,13 @@ begin
   if (n.sons[genericParamsPos] = nil) then 
     InternalError(n.info, 'generateInstance');
   n.sons[namePos] := newSymNode(result);
-  pushInfoContext(instantiator);
+  pushInfoContext(info);
 
   instantiateGenericParamList(c, n.sons[genericParamsPos], pt);
   n.sons[genericParamsPos] := nil;
   // semantic checking for the parameters:
   if n.sons[paramsPos] <> nil then begin
-    semParamList(c, n.sons[ParamsPos], result);
+    semParamList(c, n.sons[ParamsPos], nil, result);
     addParams(c, result.typ.n);
   end
   else begin
@@ -256,6 +178,7 @@ begin
   oldPrc := GenericCacheGet(c, fn, result);
   if oldPrc = nil then begin
     // add it here, so that recursive generic procs are possible:
+    GenericCacheAdd(c, fn, result);
     addDecl(c, result);
     if n.sons[codePos] <> nil then begin
       c.p := newProcCon(result);
@@ -264,8 +187,7 @@ begin
         addResultNode(c, n);
       end;
       n.sons[codePos] := semStmtScope(c, n.sons[codePos]);
-    end;
-    GenericCacheAdd(c, fn, result);
+    end
   end
   else
     result := oldPrc;
@@ -273,37 +195,168 @@ begin
   closeScope(c.tab); // close scope for parameters
   popOwner();
   c.p := oldP; // restore
+  c.module := oldMod;
+  dec(c.InstCounter);
 end;
 
-function generateTypeInstance(p: PContext; const pt: TIdTable;
-                              const instantiator: TLineInfo; t: PType): PType;
+procedure checkConstructedType(const info: TLineInfo; t: PType);
+begin
+  if (tfAcyclic in t.flags)
+  and (skipTypes(t, abstractInst).kind <> tyObject) then
+    liMessage(info, errInvalidPragmaX, 'acyclic');
+  if computeSize(t) < 0 then
+    liMessage(info, errIllegalRecursionInTypeX, typeToString(t));
+  if (t.kind = tyVar) and (t.sons[0].kind = tyVar) then
+    liMessage(info, errVarVarTypeNotAllowed);
+end;
+
+type
+  TReplTypeVars = record
+    c: PContext;
+    typeMap: TIdTable; // map PType to PType
+    symMap: TIdTable;  // map PSym to PSym
+    info: TLineInfo;
+  end;
+
+function ReplaceTypeVarsT(var cl: TReplTypeVars; t: PType): PType; forward;
+function ReplaceTypeVarsS(var cl: TReplTypeVars; s: PSym): PSym; forward;
+
+function ReplaceTypeVarsN(var cl: TReplTypeVars; n: PNode): PNode;
 var
-  c: PInstantiateClosure;
+  i, Len: int;
 begin
-  new(c);
-{@ignore}
-  fillChar(c^, sizeof(c^), 0);
-{@emit}
-  copyIdTable(c.typeMap, pt);
-  InitIdTable(c.symMap);
-  c.fn := nil;
-  c.instantiator := instantiator;
-  c.module := p.module;
-  result := instantiateType(c, t);
+  result := nil;
+  if n <> nil then begin
+    result := copyNode(n);
+    result.typ := ReplaceTypeVarsT(cl, n.typ);
+    case n.kind of
+      nkNone..pred(nkSym), succ(nkSym)..nkNilLit: begin end;
+      nkSym: begin
+        result.sym := ReplaceTypeVarsS(cl, n.sym);
+      end;
+      else begin
+        len := sonsLen(n);
+        if len > 0 then begin
+          newSons(result, len);
+          for i := 0 to len-1 do
+            result.sons[i] := ReplaceTypeVarsN(cl, n.sons[i]);
+        end
+      end
+    end
+  end
 end;
 
-function newInstantiateClosure(p: PContext;
-          const instantiator: TLineInfo): PInstantiateClosure;
+function ReplaceTypeVarsS(var cl: TReplTypeVars; s: PSym): PSym;
 begin
-  new(result);
-{@ignore}
-  fillChar(result^, sizeof(result^), 0);
-{@emit}
-  InitIdTable(result.typeMap);
-  InitIdTable(result.symMap);
-  result.fn := nil;
-  result.instantiator := instantiator;
-  result.module := p.module;
+  if s = nil then begin result := nil; exit end;
+  result := PSym(idTableGet(cl.symMap, s));
+  if (result = nil) then begin
+    result := copySym(s, false);
+    include(result.flags, sfFromGeneric);
+    idTablePut(cl.symMap, s, result);
+    result.typ := ReplaceTypeVarsT(cl, s.typ);
+    result.owner := s.owner;
+    result.ast := ReplaceTypeVarsN(cl, s.ast);
+  end
+end;
+
+function lookupTypeVar(cl: TReplTypeVars; t: PType): PType;
+begin
+  result := PType(idTableGet(cl.typeMap, t));
+  if result = nil then
+    liMessage(t.sym.info, errCannotInstantiateX, typeToString(t))
+  else if result.kind = tyGenericParam then
+    InternalError(cl.info, 'substitution with generic parameter');
+end;
+
+function ReplaceTypeVarsT(var cl: TReplTypeVars; t: PType): PType;
+var
+  i: int;
+  body, newbody, x, header: PType;
+begin
+  result := t;
+  if t = nil then exit;
+  case t.kind of
+    tyGenericParam: begin
+      result := lookupTypeVar(cl, t);
+    end;
+    tyGenericInvokation: begin
+      body := t.sons[0];
+      if body.kind <> tyGenericBody then
+        InternalError(cl.info, 'no generic body');
+      header := nil;
+      for i := 1 to sonsLen(t)-1 do begin
+        if t.sons[i].kind = tyGenericParam then begin
+          x := lookupTypeVar(cl, t.sons[i]);
+          if header = nil then header := copyType(t, t.owner, false);
+          header.sons[i] := x;
+        end
+        else
+          x := t.sons[i];
+        idTablePut(cl.typeMap, body.sons[i-1], x);
+      end;
+      // cycle detection:
+      if header = nil then header := t;
+      result := searchInstTypes(gInstTypes, header);
+      if result <> nil then exit;
+      
+      result := newType(tyGenericInst, t.sons[0].owner);
+      for i := 0 to sonsLen(t)-1 do begin
+        // if one of the params is not concrete, we cannot do anything
+        // but we already raised an error!
+        addSon(result, header.sons[i]);
+      end;
+      // add these before recursive calls:
+      idTablePut(gInstTypes, header, result);
+
+      newbody := ReplaceTypeVarsT(cl, lastSon(body));
+      newbody.n := ReplaceTypeVarsN(cl, lastSon(body).n);
+      addSon(result, newbody);
+      //writeln(output, ropeToStr(Typetoyaml(newbody)));
+      checkConstructedType(cl.info, newbody);
+    end;
+    tyGenericBody: begin
+      InternalError(cl.info, 'ReplaceTypeVarsT: tyGenericBody');
+      result := ReplaceTypeVarsT(cl, lastSon(t));
+    end 
+    else begin
+      if containsGenericType(t) then begin
+        result := copyType(t, t.owner, false);
+        for i := 0 to sonsLen(result)-1 do
+          result.sons[i] := ReplaceTypeVarsT(cl, result.sons[i]);
+        result.n := ReplaceTypeVarsN(cl, result.n);
+        if result.Kind in GenericTypes then 
+          liMessage(cl.info, errCannotInstantiateX, TypeToString(t, preferName));
+        //writeln(output, ropeToStr(Typetoyaml(result)));
+        //checkConstructedType(cl.info, result);
+      end
+    end
+  end
+end;
+
+function instGenericContainer(c: PContext; n: PNode; header: PType): PType;
+var
+  cl: TReplTypeVars;
+begin
+  InitIdTable(cl.symMap);
+  InitIdTable(cl.typeMap);
+  cl.info := n.info;
+  cl.c := c;
+  result := ReplaceTypeVarsT(cl, header);
+end;
+
+function generateTypeInstance(p: PContext; const pt: TIdTable;
+                              arg: PNode; t: PType): PType;
+var
+  cl: TReplTypeVars;
+begin
+  InitIdTable(cl.symMap);
+  copyIdTable(cl.typeMap, pt);
+  cl.info := arg.info;
+  cl.c := p;
+  pushInfoContext(arg.info);
+  result := ReplaceTypeVarsT(cl, t);
+  popInfoContext();
 end;
 
 function partialSpecialization(c: PContext; n: PNode; s: PSym): PNode;
diff --git a/nim/semstmts.pas b/nim/semstmts.pas
index 686ff775d..efbee6da8 100644..100755
--- a/nim/semstmts.pas
+++ b/nim/semstmts.pas
@@ -9,11 +9,6 @@
 
 // this module does the semantic checking of statements
 
-function isTopLevel(c: PContext): bool;
-begin
-  result := c.tab.tos <= 2
-end;
-
 function semWhen(c: PContext; n: PNode): PNode;
 var
   i: int;
@@ -71,7 +66,7 @@ begin
       end;
       else illFormedAst(n)
     end
-  end;
+  end
 end;
 
 function semDiscard(c: PContext; n: PNode): PNode;
@@ -90,19 +85,19 @@ begin
   result := n;
   checkSonsLen(n, 1);
   if n.sons[0] <> nil then begin
-    if n.sons[0].kind = nkIdent then begin
-      // lookup the symbol:
-      s := lookUp(c, n.sons[0]);
-      if (s.kind = skLabel) and (s.owner.id = c.p.owner.id) then begin
-        x := newSymNode(s);
-        x.info := n.info;
-        include(s.flags, sfUsed);
-        n.sons[0] := x
-      end
-      else
-        liMessage(n.info, errInvalidControlFlowX, s.name.s)
+    case n.sons[0].kind of
+      nkIdent: s := lookUp(c, n.sons[0]);
+      nkSym: s := n.sons[0].sym;
+      else illFormedAst(n)
+    end;
+    if (s.kind = skLabel) and (s.owner.id = c.p.owner.id) then begin
+      x := newSymNode(s);
+      x.info := n.info;
+      include(s.flags, sfUsed);
+      n.sons[0] := x
     end
-    else illFormedAst(n)
+    else
+      liMessage(n.info, errInvalidControlFlowX, s.name.s)
   end
   else if (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0) then
     liMessage(n.info, errInvalidControlFlowX,
@@ -257,7 +252,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 := semDirectCallAnalyseEffects(c, result);
+      result := semDirectCallAnalyseEffects(c, result, {@set}[]);
       if result <> nil then begin
         fixAbstractType(c, result);
         analyseIfAddressTakenInCall(c, result);
@@ -277,7 +272,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 := semDirectCallAnalyseEffects(c, result);
+        result := semDirectCallAnalyseEffects(c, result, {@set}[]);
         if result <> nil then begin
           fixAbstractType(c, result);
           analyseIfAddressTakenInCall(c, result);
@@ -289,7 +284,7 @@ begin
         addSon(result, semExpr(c, a.sons[0]));
         addSon(result, semExpr(c, a.sons[1]));
         addSon(result, semExpr(c, n.sons[1]));
-        result := semDirectCallAnalyseEffects(c, result);
+        result := semDirectCallAnalyseEffects(c, result, {@set}[]);
         if result <> nil then begin
           fixAbstractType(c, result);
           analyseIfAddressTakenInCall(c, result);
@@ -355,8 +350,7 @@ var
 begin
   result := n;
   checkSonsLen(n, 1);
-  if (c.p.owner = nil) or (c.p.owner.kind <> skIterator)
-  or (c.p.nestedLoopCounter <= 0) then
+  if (c.p.owner = nil) or (c.p.owner.kind <> skIterator) then
     liMessage(n.info, errYieldNotAllowedHere);
   if (n.sons[0] <> nil) then begin
     n.sons[0] := SemExprWithType(c, n.sons[0]);
@@ -409,13 +403,20 @@ begin
     end
     else
       def := nil;
-    if not typeAllowed(typ, skVar) then
+    if not typeAllowed(typ, skVar) then begin
+      //debug(typ);
       liMessage(a.info, errXisNoType, typeToString(typ));
+    end;
     tup := skipTypes(typ, {@set}[tyGenericInst]);
     if a.kind = nkVarTuple then begin
       if tup.kind <> tyTuple then liMessage(a.info, errXExpected, 'tuple');
       if len-2 <> sonsLen(tup) then
         liMessage(a.info, errWrongNumberOfVariables);
+      b := newNodeI(nkVarTuple, a.info);
+      newSons(b, len);
+      b.sons[len-2] := nil; // no type desc
+      b.sons[len-1] := def;
+      addSon(result, b);
     end;
     for j := 0 to len-3 do begin
       if (c.p.owner.kind = skModule) then begin
@@ -424,16 +425,21 @@ begin
       end
       else
         v := semIdentWithPragma(c, skVar, a.sons[j], {@set}[]);
-      if a.kind <> nkVarTuple then v.typ := typ
-      else v.typ := tup.sons[j];
       if v.flags * [sfStar, sfMinus] <> {@set}[] then
         include(v.flags, sfInInterface);
       addInterfaceDecl(c, v);
-      b := newNodeI(nkIdentDefs, a.info);
-      addSon(b, newSymNode(v));
-      addSon(b, nil); // no type description
-      addSon(b, copyTree(def));
-      addSon(result, b);
+      if a.kind <> nkVarTuple then begin
+        v.typ := typ;
+        b := newNodeI(nkIdentDefs, a.info);
+        addSon(b, newSymNode(v));
+        addSon(b, nil); // no type description
+        addSon(b, copyTree(def));
+        addSon(result, b);
+      end
+      else begin
+        v.typ := tup.sons[j];
+        b.sons[j] := newSymNode(v);
+      end
     end
   end
 end;
@@ -485,9 +491,9 @@ end;
 function semFor(c: PContext; n: PNode): PNode;
 var
   i, len: int;
-  v: PSym;
+  v, countup: PSym;
   iter: PType;
-  countupNode, m: PNode;
+  countupNode, call: PNode;
 begin
   result := n;
   checkMinSonsLen(n, 3);
@@ -496,22 +502,22 @@ begin
   if n.sons[len-2].kind = nkRange then begin
     checkSonsLen(n.sons[len-2], 2);
     // convert ``in 3..5`` to ``in countup(3, 5)``
-    // YYY: if the programmer overrides system.countup in a local scope
-    // this leads to wrong code. This is extremely hard to fix! But it may
-    // not even be a bug, but a feature...
-    countupNode := newNodeI(nkCall, n.sons[len-2].info);
+    countupNode := newNodeI(nkCall, n.sons[len-2].info);    
+    countUp := StrTableGet(magicsys.systemModule.Tab, getIdent('countup'));
+    if (countUp = nil) then
+      liMessage(countupNode.info, errSystemNeeds, 'countup');
     newSons(countupNode, 3);
-    countupNode.sons[0] := newNodeI(nkQualified, n.sons[len-2].info);
-    newSons(countupNode.sons[0], 2);
-    m := newIdentNode(getIdent('system'), n.sons[len-2].info);
-    countupNode.sons[0].sons[0] := m;
-    m := newIdentNode(getIdent('countup'), n.sons[len-2].info);
-    countupNode.sons[0].sons[1] := m;
+    countupnode.sons[0] := newSymNode(countup);
     countupNode.sons[1] := n.sons[len-2].sons[0];
     countupNode.sons[2] := n.sons[len-2].sons[1];
+    
     n.sons[len-2] := countupNode;
   end;
-  n.sons[len-2] := semExprWithType(c, n.sons[len-2]);
+  n.sons[len-2] := semExprWithType(c, n.sons[len-2], {@set}[efWantIterator]);
+  call := n.sons[len-2];
+  if (call.kind <> nkCall) or (call.sons[0].kind <> nkSym)
+  or (call.sons[0].sym.kind <> skIterator) then
+    liMessage(n.sons[len-2].info, errIteratorExpected);
   iter := skipTypes(n.sons[len-2].typ, {@set}[tyGenericInst]);
   if iter.kind <> tyTuple then begin
     if len <> 3 then liMessage(n.info, errWrongNumberOfVariables);
@@ -521,8 +527,7 @@ begin
     addDecl(c, v);
   end
   else begin
-    if len-2 <> sonsLen(iter) then
-      liMessage(n.info, errWrongNumberOfVariables);
+    if len-2 <> sonsLen(iter) then liMessage(n.info, errWrongNumberOfVariables);
     for i := 0 to len-3 do begin
       v := newSymS(skForVar, n.sons[i], c);
       v.typ := iter.sons[i];
@@ -585,66 +590,57 @@ begin
   end;
 end;
 
-procedure semGenericParamList(c: PContext; n: PNode; father: PType = nil);
+function semGenericParamList(c: PContext; n: PNode; father: PType = nil): PNode;
 var
-  i: int;
+  i, j, L: int;
   s: PSym;
+  a, def: PNode;
+  typ: PType;
 begin
+  result := copyNode(n);
   if n.kind <> nkGenericParams then
     InternalError(n.info, 'semGenericParamList');
   for i := 0 to sonsLen(n)-1 do begin
-    if n.sons[i].kind = nkDefaultTypeParam then begin
-      internalError(n.sons[i].info, 'semGenericParamList() to implement');
-      // XXX
-    end
-    else begin
-      s := newSymS(skTypeParam, n.sons[i], c);
-      s.typ := newTypeS(tyGenericParam, c);
+    a := n.sons[i];
+    if a.kind <> nkIdentDefs then illFormedAst(n);
+    L := sonsLen(a);
+    def := a.sons[L-1];
+    if a.sons[L-2] <> nil then
+      typ := semTypeNode(c, a.sons[L-2], nil)
+    else if def <> nil then
+      typ := newTypeS(tyExpr, c)
+    else
+      typ := nil;
+    for j := 0 to L-3 do begin
+      if (typ = nil) or (typ.kind = tyTypeDesc) then begin
+        s := newSymS(skType, a.sons[j], c);      
+        s.typ := newTypeS(tyGenericParam, c)
+      end
+      else begin
+        s := newSymS(skGenericParam, a.sons[j], c);
+        s.typ := typ
+      end;
+      s.ast := def;
       s.typ.sym := s;
-    end;
-    if father <> nil then addSon(father, s.typ);
-    s.position := i;
-    n.sons[i] := newSymNode(s);
-    addDecl(c, s);
+      if father <> nil then addSon(father, s.typ);
+      s.position := i;
+      addSon(result, newSymNode(s));
+      addDecl(c, s);
+    end
   end
 end;
 
 procedure addGenericParamListToScope(c: PContext; n: PNode);
 var
   i: int;
-  s: PSym;
+  a: PNode;
 begin
   if n.kind <> nkGenericParams then
     InternalError(n.info, 'addGenericParamListToScope');
   for i := 0 to sonsLen(n)-1 do begin
-    if n.sons[i].kind <> nkSym then
-      InternalError(n.sons[i].info, 'addGenericParamListToScope');
-    s := n.sons[i].sym;
-    addDecl(c, s);
-  end
-end;
-
-function resolveGenericParams(c: PContext; n: PNode; 
-                              withinBind: bool = false): PNode;
-var
-  i: int;
-  s: PSym;
-begin
-  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
+    a := n.sons[i];
+    if a.kind <> nkSym then internalError(a.info, 'addGenericParamListToScope');
+    addDecl(c, a.sym)
   end
 end;
 
@@ -652,7 +648,7 @@ function SemTypeSection(c: PContext; n: PNode): PNode;
 var
   i: int;
   s: PSym;
-  t: PType;
+  t, body: PType;
   a: PNode;
 begin
   result := n;
@@ -674,7 +670,8 @@ begin
     s.typ := newTypeS(tyForward, c);
     s.typ.sym := s;
     // process pragmas:
-    if a.sons[0].kind = nkPragmaExpr then pragmaType(c, s, a.sons[0].sons[1]);
+    if a.sons[0].kind = nkPragmaExpr then
+      pragma(c, s, a.sons[0].sons[1], typePragmas);
     // add it here, so that recursive types are possible:
     addInterfaceDecl(c, s);
     a.sons[0] := newSymNode(s);
@@ -689,23 +686,24 @@ begin
     if (a.sons[0].kind <> nkSym) then IllFormedAst(a);
     s := a.sons[0].sym;
     if (s.magic = mNone) and (a.sons[2] = nil) then
-      liMessage(a.info, errTypeXNeedsImplementation, s.name.s);
+      liMessage(a.info, errImplOfXexpected, s.name.s);
     if s.magic <> mNone then processMagicType(c, s);
     if a.sons[1] <> nil then begin
-      // we have a generic type declaration here, so we don't process the
-      // type's body:
+      // We have a generic type declaration here. In generic types,
+      // symbol lookup needs to be done here.
       openScope(c.tab);
       pushOwner(s);
-      s.typ.kind := tyGeneric;
-      semGenericParamList(c, a.sons[1], s.typ);
-      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], false);
-      s.ast := a;
+      s.typ.kind := tyGenericBody;
       if s.typ.containerID <> 0 then
         InternalError(a.info, 'semTypeSection: containerID');
       s.typ.containerID := getID();
+      a.sons[1] := semGenericParamList(c, a.sons[1], s.typ);
+      addSon(s.typ, nil); // to be filled out later
+      s.ast := a;
+      body := semTypeNode(c, a.sons[2], nil);
+      if body <> nil then body.sym := s;
+      s.typ.sons[sonsLen(s.typ)-1] := body;
+      //debug(s.typ);
       popOwner();
       closeScope(c.tab);
     end
@@ -718,8 +716,6 @@ begin
       s.typ := t;
       s.ast := a;
       popOwner();
-      if (tfAcyclic in t.flags) and (t.kind <> tyObject) then
-        liMessage(s.info, errInvalidPragmaX, 'acyclic');
     end;
   end;
   // unfortunately we need another pass over the section for checking of
@@ -741,15 +737,14 @@ begin
           s.typ.id := t.id; // same id
         end
       end;
-      if computeSize(s.typ) < 0 then
-        liMessage(s.info, errIllegalRecursionInTypeX, s.name.s);
+      checkConstructedType(s.info, s.typ);
     end
   end
 end;
 
-procedure semParamList(c: PContext; n: PNode; s: PSym);
+procedure semParamList(c: PContext; n, genericParams: PNode; s: PSym);
 begin
-  s.typ := semProcTypeNode(c, n, nil);
+  s.typ := semProcTypeNode(c, n, genericParams, nil);
 end;
 
 procedure addParams(c: PContext; n: PNode);
@@ -780,62 +775,6 @@ begin
     liMessage(s.info, errXhasSideEffects, s.name.s);
 end;
 
-function semIterator(c: PContext; n: PNode): PNode;
-var
-  s: PSym;
-  oldP: PProcCon;
-begin
-  result := n;
-  checkSonsLen(n, codePos+1);
-  if c.p.owner.kind <> skModule then
-    liMessage(n.info, errIteratorNotAllowed);
-  oldP := c.p; // restore later
-  s := semIdentVis(c, skIterator, n.sons[0], {@set}[sfStar]);
-  n.sons[namePos] := newSymNode(s);
-  include(s.flags, sfGlobal);
-  if sfStar in s.flags then include(s.flags, sfInInterface);
-  s.ast := n;
-  pushOwner(s);
-  if n.sons[genericParamsPos] <> nil then begin
-    // we have a generic type declaration here, so we don't process the
-    // type's body:
-    openScope(c.tab);
-    semGenericParamList(c, n.sons[genericParamsPos]);
-  end;
-  // process parameters:
-  if n.sons[paramsPos] <> nil then
-    semParamList(c, n.sons[ParamsPos], s)
-  else
-    liMessage(n.info, errIteratorNeedsReturnType);
-  s.typ.callConv := lastOptionEntry(c).defaultCC;
-  if n.sons[pragmasPos] <> nil then
-    pragmaIterator(c, s, n.sons[pragmasPos]);
-  s.options := gOptions;
-  if n.sons[codePos] <> nil then begin
-    if sfBorrow in s.flags then
-      liMessage(n.info, errImplOfXNotAllowed, s.name.s);
-    if n.sons[genericParamsPos] = nil then begin
-      c.p := newProcCon(s);
-      openScope(c.tab);
-      addParams(c, s.typ.n);
-      n.sons[codePos] := semStmtScope(c, n.sons[codePos]);
-    end
-    else begin
-      n.sons[codePos] := resolveGenericParams(c, n.sons[codePos]);
-    end
-  end
-  else if (sfBorrow in s.flags) then
-    semBorrow(c, n, s)
-  else
-    liMessage(n.info, errIteratorNeedsImplementation);
-  closeScope(c.tab);
-  popOwner();
-  c.p := oldP;
-  // add it here, so that recursive iterators are impossible:
-  addInterfaceOverloadableSymAt(c, s, c.tab.tos-1);
-  //writeln(renderTree(n.sons[codePos], {@set}[renderIds]));
-end;
-
 procedure addResult(c: PContext; t: PType; const info: TLineInfo);
 var
   s: PSym;
@@ -872,10 +811,10 @@ begin
 
   pushOwner(s);
   openScope(c.tab);
-  if (n.sons[genericParamsPos] <> nil) then InternalError(n.info, 'semLambda');
+  if (n.sons[genericParamsPos] <> nil) then illFormedAst(n);
   // process parameters:
   if n.sons[paramsPos] <> nil then begin
-    semParamList(c, n.sons[ParamsPos], s);
+    semParamList(c, n.sons[ParamsPos], nil, s);
     addParams(c, s.typ.n);
   end
   else begin
@@ -886,7 +825,7 @@ begin
   // we are in a nested proc:
   s.typ.callConv := ccClosure;
   if n.sons[pragmasPos] <> nil then
-    pragmaLambda(c, s, n.sons[pragmasPos]);
+    pragma(c, s, n.sons[pragmasPos], lambdaPragmas);
 
   s.options := gOptions;
   if n.sons[codePos] <> nil then begin
@@ -905,10 +844,12 @@ begin
   result.typ := s.typ;
 end;
 
-function semProcAux(c: PContext; n: PNode; kind: TSymKind): PNode;
+function semProcAux(c: PContext; n: PNode; kind: TSymKind;
+                    const validPragmas: TSpecialWords): PNode;
 var
   s, proto: PSym;
   oldP: PProcCon;
+  gp: PNode;
 begin
   result := n;
   checkSonsLen(n, codePos+1);
@@ -925,11 +866,16 @@ begin
 
   pushOwner(s);
   openScope(c.tab);
-  if n.sons[genericParamsPos] <> nil then
-    semGenericParamList(c, n.sons[genericParamsPos]);
+  if n.sons[genericParamsPos] <> nil then begin
+    n.sons[genericParamsPos] := semGenericParamList(c, n.sons[genericParamsPos]);
+    gp := n.sons[genericParamsPos]
+  end
+  else
+    gp := newNodeI(nkGenericParams, n.info);
   // process parameters:
   if n.sons[paramsPos] <> nil then begin
-    semParamList(c, n.sons[ParamsPos], s);
+    semParamList(c, n.sons[ParamsPos], gp, s);
+    if sonsLen(gp) > 0 then n.sons[genericParamsPos] := gp;
     addParams(c, s.typ.n);
   end
   else begin
@@ -951,8 +897,7 @@ begin
     else
       addDeclAt(c, s, c.tab.tos-2);
     if n.sons[pragmasPos] <> nil then
-      if kind = skMacro then pragmaMacro(c, s, n.sons[pragmasPos])
-      else pragmaProc(c, s, n.sons[pragmasPos]);
+      pragma(c, s, n.sons[pragmasPos], validPragmas)
   end
   else begin
     if n.sons[pragmasPos] <> nil then
@@ -981,15 +926,19 @@ begin
   if n.sons[codePos] <> nil then begin
     if [sfImportc, sfBorrow] * s.flags <> [] then
       liMessage(n.sons[codePos].info, errImplOfXNotAllowed, s.name.s);
-    if n.sons[genericParamsPos] = nil then begin
+    if (n.sons[genericParamsPos] = nil) then begin
       c.p := newProcCon(s);
-      addResult(c, s.typ.sons[0], n.info);
+      if (s.typ.sons[0] <> nil) and (kind <> skIterator) then
+        addResult(c, s.typ.sons[0], n.info);
       n.sons[codePos] := semStmtScope(c, n.sons[codePos]);
-      addResultNode(c, n);
+      if (s.typ.sons[0] <> nil) and (kind <> skIterator) then
+        addResultNode(c, n);
     end
     else begin
-      n.sons[codePos] := resolveGenericParams(c, n.sons[codePos]);
-    end;
+      if (s.typ.sons[0] <> nil) and (kind <> skIterator) then
+        addDecl(c, newSym(skUnknown, getIdent('result'), nil));
+      n.sons[codePos] := semGenericStmtScope(c, n.sons[codePos]);
+    end
   end
   else begin
     if proto <> nil then
@@ -1004,9 +953,21 @@ begin
   c.p := oldP; // restore
 end;
 
+function semIterator(c: PContext; n: PNode): PNode;
+var
+  t: PType;
+  s: PSym;
+begin
+  result := semProcAux(c, n, skIterator, iteratorPragmas);
+  s := result.sons[namePos].sym;
+  t := s.typ;
+  if t.sons[0] = nil then liMessage(n.info, errXNeedsReturnType, 'iterator');
+  if n.sons[codePos] = nil then liMessage(n.info, errImplOfXexpected, s.name.s);
+end;
+
 function semProc(c: PContext; n: PNode): PNode;
 begin
-  result := semProcAux(c, n, skProc);
+  result := semProcAux(c, n, skProc, procPragmas);
 end;
 
 function semConverterDef(c: PContext; n: PNode): PNode;
@@ -1017,13 +978,11 @@ begin
   checkSonsLen(n, codePos+1);
   if n.sons[genericParamsPos] <> nil then
     liMessage(n.info, errNoGenericParamsAllowedForX, 'converter');
-  result := semProcAux(c, n, skConverter);
+  result := semProcAux(c, n, skConverter, converterPragmas);
   s := result.sons[namePos].sym;
   t := s.typ;
-  if t.sons[0] = nil then
-    liMessage(n.info, errXNeedsReturnType, 'converter');
-  if sonsLen(t) <> 2 then
-    liMessage(n.info, errXRequiresOneArgument, 'converter');
+  if t.sons[0] = nil then liMessage(n.info, errXNeedsReturnType, 'converter');
+  if sonsLen(t) <> 2 then liMessage(n.info, errXRequiresOneArgument, 'converter');
   addConverter(c, s);
 end;
 
@@ -1035,18 +994,17 @@ begin
   checkSonsLen(n, codePos+1);
   if n.sons[genericParamsPos] <> nil then
     liMessage(n.info, errNoGenericParamsAllowedForX, 'macro');
-  result := semProcAux(c, n, skMacro);
+  result := semProcAux(c, n, skMacro, macroPragmas);
   s := result.sons[namePos].sym;
   t := s.typ;
-  if t.sons[0] = nil then
-    liMessage(n.info, errXNeedsReturnType, 'macro');
-  if sonsLen(t) <> 2 then
-    liMessage(n.info, errXRequiresOneArgument, 'macro');
+  if t.sons[0] = nil then liMessage(n.info, errXNeedsReturnType, 'macro');
+  if sonsLen(t) <> 2 then liMessage(n.info, errXRequiresOneArgument, 'macro');
+  if n.sons[codePos] = nil then liMessage(n.info, errImplOfXexpected, s.name.s);
 end;
 
 function evalInclude(c: PContext; n: PNode): PNode;
 var
-  i: int;
+  i, fileIndex: int;
   x: PNode;
   f, name, ext: string;
 begin
@@ -1054,6 +1012,9 @@ begin
   addSon(result, n); // the rodwriter needs include information!
   for i := 0 to sonsLen(n)-1 do begin
     f := getModuleFile(n.sons[i]);
+    fileIndex := includeFilename(f);
+    if IntSetContainsOrIncl(c.includedFiles, fileIndex) then
+      liMessage(n.info, errRecursiveDependencyX, f);
     SplitFilename(f, name, ext);
     if cmpIgnoreCase(ext, '.'+TmplExt) = 0 then
       x := gIncludeTmplFile(f)
@@ -1061,6 +1022,7 @@ begin
       x := gIncludeFile(f);
     x := semStmt(c, x);
     addSon(result, x);
+    IntSetExcl(c.includedFiles, fileIndex);
   end;
 end;
 
@@ -1083,7 +1045,7 @@ begin
   if nfSem in n.flags then exit;
   case n.kind of
     nkAsgn: result := semAsgn(c, n);
-    nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkMacroStmt:
+    nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkMacroStmt, nkCallStrLit:
       result := semCommand(c, n);
     nkEmpty, nkCommentStmt, nkNilLit: begin end;
     nkBlockStmt: result := semBlock(c, n);
@@ -1115,7 +1077,7 @@ begin
     nkReturnStmt: result := semReturn(c, n);
     nkAsmStmt: result := semAsm(c, n);
     nkYieldStmt: result := semYield(c, n);
-    nkPragma: pragmaStmt(c, c.p.owner, n);
+    nkPragma: pragma(c, c.p.owner, n, stmtPragmas);
     nkIteratorDef: result := semIterator(c, n);
     nkProcDef: result := semProc(c, n);
     nkConverterDef: result := semConverterDef(c, n);
diff --git a/nim/semtempl.pas b/nim/semtempl.pas
index b8107095f..f4173d9ff 100644..100755
--- a/nim/semtempl.pas
+++ b/nim/semtempl.pas
@@ -46,16 +46,17 @@ begin
   end
 end;
 
-function evalTemplateAux(c: PContext; templ, actual: PNode;
-                         sym: PSym): PNode;
+function evalTemplateAux(c: PContext; templ, actual: PNode; sym: PSym): PNode;
 var
   i: int;
+  p: PSym;
 begin
   if templ = nil then begin result := nil; exit end;
   case templ.kind of
     nkSym: begin
-      if (templ.sym.kind = skParam) and (templ.sym.owner.id = sym.id) then
-        result := copyTree(actual.sons[templ.sym.position+1]) // BUGFIX: +1
+      p := templ.sym;
+      if (p.kind = skParam) and (p.owner.id = sym.id) then 
+        result := copyTree(actual.sons[p.position])
       else
         result := copyNode(templ)
     end;
@@ -74,19 +75,45 @@ var
   evalTemplateCounter: int = 0; // to prevend endless recursion in templates
                                 // instantation
 
+function evalTemplateArgs(c: PContext; n: PNode; s: PSym): PNode;
+var
+  f, a, i: int;
+  arg: PNode;
+begin
+  f := sonsLen(s.typ);
+  // if the template has zero arguments, it can be called without ``()``
+  // `n` is then a nkSym or something similar
+  case n.kind of
+    nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
+      a := sonsLen(n);
+    else a := 0
+  end;
+  if a > f then liMessage(n.info, errWrongNumberOfArguments);
+  result := copyNode(n);
+  for i := 1 to f-1 do begin
+    if i < a then 
+      arg := n.sons[i]
+    else 
+      arg := copyTree(s.ast.sons[paramsPos].sons[i-1].sym.ast);
+    if arg = nil then liMessage(n.info, errWrongNumberOfArguments);
+    if not (s.typ.sons[i].kind in [tyTypeDesc, tyStmt, tyExpr]) then begin
+      // concrete type means semantic checking for argument:
+      arg := fitNode(c, s.typ.sons[i], semExprWithType(c, arg));
+    end;
+    addSon(result, arg);
+  end
+end;
+
 function evalTemplate(c: PContext; n: PNode; sym: PSym): PNode;
 var
-  r: PNode;
+  args: PNode;
 begin
   inc(evalTemplateCounter);
   if evalTemplateCounter > 100 then
     liMessage(n.info, errTemplateInstantiationTooNested);
   // replace each param by the corresponding node:
-  r := sym.ast.sons[paramsPos].sons[0];
-  if (r.kind <> nkIdent) then InternalError(r.info, 'evalTemplate');
-  result := evalTemplateAux(c, sym.ast.sons[codePos], n, sym);
-  if r.ident.id = ord(wExpr) then result := semExpr(c, result)
-  else result := semStmt(c, result);
+  args := evalTemplateArgs(c, n, sym);
+  result := evalTemplateAux(c, sym.ast.sons[codePos], args, sym);
   dec(evalTemplateCounter);
 end;
 
@@ -108,19 +135,19 @@ begin
     include(s.flags, sfUsed);
   end
   else begin
-    // semantic checking requires a type; ``fitNode`` deal with it
+    // semantic checking requires a type; ``fitNode`` deals 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;
+    //liMessage(n.info, warnUser, s.name.s + ' is here symchoice');
   end
 end;
 
-function resolveTemplateParams(c: PContext; n: PNode; 
-                               withinBind: bool): PNode;
+function resolveTemplateParams(c: PContext; n: PNode; withinBind: bool): PNode;
 var
   i: int;
   s: PSym;
@@ -153,20 +180,6 @@ begin
   end
 end;
 
-function semTemplateParamKind(c: PContext; n, p: PNode): PNode;
-begin
-  if (p = nil) or (p.kind <> nkIdent) then
-    liMessage(n.info, errInvalidParamKindX, renderTree(p))
-  else begin
-    case p.ident.id of
-      ord(wExpr), ord(wStmt), ord(wTypeDesc): begin end;
-      else
-        liMessage(p.info, errInvalidParamKindX, p.ident.s)
-    end
-  end;
-  result := p;
-end;
-
 function transformToExpr(n: PNode): PNode;
 var
   i, realStmt: int;
@@ -197,9 +210,7 @@ end;
 
 function semTemplateDef(c: PContext; n: PNode): PNode;
 var
-  s, param: PSym;
-  i, j, len, counter: int;
-  params, p, paramKind: PNode;
+  s: PSym;
 begin
   if c.p.owner.kind = skModule then begin
     s := semIdentVis(c, skTemplate, n.sons[0], {@set}[sfStar]);
@@ -211,23 +222,6 @@ begin
   // check parameter list:
   pushOwner(s);
   openScope(c.tab);
-  params := n.sons[paramsPos];
-  counter := 0;
-  for i := 1 to sonsLen(params)-1 do begin
-    p := params.sons[i];
-    len := sonsLen(p);
-    paramKind := semTemplateParamKind(c, p, p.sons[len-2]);
-    if (p.sons[len-1] <> nil) then
-      liMessage(p.sons[len-1].info, errDefaultArgumentInvalid);
-    for j := 0 to len-3 do begin
-      param := newSymS(skParam, p.sons[j], c);
-      param.position := counter;
-      param.ast := paramKind;
-      inc(counter);
-      addDecl(c, param)
-    end;
-  end;
-  params.sons[0] := semTemplateParamKind(c, params, params.sons[0]);
   n.sons[namePos] := newSymNode(s);
 
   // check that no pragmas exist:
@@ -236,9 +230,26 @@ begin
   // check that no generic parameters exist:
   if n.sons[genericParamsPos] <> nil then
     liMessage(n.info, errNoGenericParamsAllowedForX, 'template');
+  if (n.sons[paramsPos] = nil) then begin
+    // use ``stmt`` as implicit result type
+    s.typ := newTypeS(tyProc, c);
+    s.typ.n := newNodeI(nkFormalParams, n.info);
+    addSon(s.typ, newTypeS(tyStmt, c));
+    addSon(s.typ.n, newNodeIT(nkType, n.info, s.typ.sons[0]));
+  end
+  else begin
+    semParamList(c, n.sons[ParamsPos], nil, s);
+    if n.sons[paramsPos].sons[0] = nil then begin
+      // use ``stmt`` as implicit result type
+      s.typ.sons[0] := newTypeS(tyStmt, c);
+      s.typ.n.sons[0] := newNodeIT(nkType, n.info, s.typ.sons[0]);
+    end
+  end;
+  addParams(c, s.typ.n);
+  
   // resolve parameters:
   n.sons[codePos] := resolveTemplateParams(c, n.sons[codePos], false);
-  if params.sons[0].ident.id = ord(wExpr) then
+  if not (s.typ.sons[0].kind in [tyStmt, tyTypeDesc]) then
     n.sons[codePos] := transformToExpr(n.sons[codePos]);
 
   // only parameters are resolved, no type checking is performed
diff --git a/nim/semtypes.pas b/nim/semtypes.pas
index c968d4b72..934196de4 100644..100755
--- a/nim/semtypes.pas
+++ b/nim/semtypes.pas
@@ -140,13 +140,13 @@ begin
     liMessage(n.info, errXExpectsOneTypeParam, 'var');
 end;
 
-function semAbstract(c: PContext; n: PNode; prev: PType): PType;
+function semDistinct(c: PContext; n: PNode; prev: PType): PType;
 begin
-  result := newOrPrevType(tyAbstract, prev, c);
+  result := newOrPrevType(tyDistinct, prev, c);
   if sonsLen(n) = 1 then 
     addSon(result, semTypeNode(c, n.sons[0], nil))
   else
-    liMessage(n.info, errXExpectsOneTypeParam, 'abstract');
+    liMessage(n.info, errXExpectsOneTypeParam, 'distinct');
 end;
 
 function semRangeAux(c: PContext; n: PNode; prev: PType): PType;
@@ -233,8 +233,7 @@ begin
   result := qualifiedLookup(c, n, true);
   if (result <> nil) then begin
     include(result.flags, sfUsed);
-    if not (result.kind in [skTypeParam, skType]) then
-      liMessage(n.info, errTypeExpected);
+    if result.kind <> skType then liMessage(n.info, errTypeExpected);
   end
   else
     liMessage(n.info, errIdentifierExpected);
@@ -275,87 +274,36 @@ begin
     end
   end
 end;
-(*
-function instGenericAux(c: PContext; templ, actual: PNode;
-                        sym: PSym): PNode;
-var
-  i: int;
-begin
-  if templ = nil then begin result := nil; exit end;
-  case templ.kind of
-    nkSym: begin
-      if (templ.sym.kind = skTypeParam) then
-      //and (templ.sym.owner.id = sym.id) then 
-        result := copyTree(actual.sons[templ.sym.position+1])
-      else
-        result := copyNode(templ)
-    end;
-    nkNone..nkIdent, nkType..nkNilLit: // atom
-      result := copyNode(templ);
-    else begin
-      result := copyNode(templ);
-      newSons(result, sonsLen(templ));
-      for i := 0 to sonsLen(templ)-1 do
-        result.sons[i] := instGenericAux(c, templ.sons[i], actual, sym);
-    end
-  end
-end; *)
 
 function semGeneric(c: PContext; n: PNode; s: PSym; prev: PType): PType;
 var
   i: int;
   elem: PType;
-  inst: PNode;
-  cl: PInstantiateClosure;
+  isConcrete: bool;
 begin
-  if (s.typ = nil) or (s.typ.kind <> tyGeneric) then
+  if (s.typ = nil) or (s.typ.kind <> tyGenericBody) then
     liMessage(n.info, errCannotInstantiateX, s.name.s);
-  result := newOrPrevType(tyGenericInst, prev, c); // new ID...
-  result.containerID := s.typ.containerID; // ... but the same containerID
-  result.sym := s;
+  result := newOrPrevType(tyGenericInvokation, prev, c);
   if (s.typ.containerID = 0) then InternalError(n.info, 'semtypes.semGeneric');
-  cl := newInstantiateClosure(c, n.info);
-  // check the number of supplied arguments suffices:
-  if sonsLen(n) <> sonsLen(s.typ) then begin
-    //MessageOut('n: ' +{&} toString(sonsLen(n)) +{&} ' s: '
-    //           +{&} toString(sonsLen(s.typ)));
-    liMessage(n.info, errWrongNumberOfTypeParams);
-  end;
-  // a generic type should be instantiated with itself:
-  // idTablePut(cl.typeMap, s.typ, result);
+  if sonsLen(n) <> sonsLen(s.typ) then 
+    liMessage(n.info, errWrongNumberOfArguments);
+  addSon(result, s.typ);
+  isConcrete := true;
   // iterate over arguments:
   for i := 1 to sonsLen(n)-1 do begin
     elem := semTypeNode(c, n.sons[i], nil);
-    if elem.kind = tyGenericParam then 
-      result.kind := tyGeneric // prevend type from instantiation
-    else
-      idTablePut(cl.typeMap, s.typ.sons[i-1], elem);
+    if elem.kind = tyGenericParam then isConcrete := false;
     addSon(result, elem);
   end;
-  if s.ast <> nil then begin
-    if (result.kind = tyGenericInst) then begin
-      // inst := instGenericAux(c, s.ast.sons[2], n, s);
-      internalError(n.info, 'Generic containers not implemented');
-      // XXX: implementation does not work this way
-      // we need to do the following: 
-      // traverse and copy the type and replace any tyGenericParam type
-      // does checking of instantiated type for us:
-      elem := instantiateType(cl, s.typ); //semTypeNode(c, inst, nil);
-      elem.id := result.containerID;
-      addSon(result, elem);
-    end
-    else
-      addSon(result, nil);
+  if isConcrete then begin
+    if s.ast = nil then liMessage(n.info, errCannotInstantiateX, s.name.s);
+    result := instGenericContainer(c, n, result);
   end
-  else
-    liMessage(n.info, errCannotInstantiateX, s.name.s); 
-  (*if computeSize(result) < 0 then
-    liMessage(s.info, errIllegalRecursionInTypeX, s.name.s);*)
 end;
 
 function semIdentVis(c: PContext; kind: TSymKind; n: PNode;
                      const allowed: TSymFlags): PSym;
-// identifier with visability
+// identifier with visibility
 var
   v: PIdent;
 begin
@@ -388,9 +336,9 @@ begin
       skType: begin
         // process pragmas later, because result.typ has not been set yet
       end;
-      skField: pragmaField(c, result, n.sons[1]);
-      skVar: pragmaVar(c, result, n.sons[1]);
-      skConst: pragmaConst(c, result, n.sons[1]);
+      skField: pragma(c, result, n.sons[1], fieldPragmas);
+      skVar: pragma(c, result, n.sons[1], varPragmas);
+      skConst: pragma(c, result, n.sons[1], constPragmas);
       else begin end
     end
   end
@@ -546,8 +494,7 @@ begin
       for i := 0 to sonsLen(n)-1 do begin
         semRecordNodeAux(c, n.sons[i], check, pos, a, rectype);
       end;
-      if a <> father then
-        addSon(father, a);
+      if a <> father then addSon(father, a);
     end;
     nkIdentDefs: begin
       checkMinSonsLen(n, 3);
@@ -644,10 +591,8 @@ begin
   end
   else
     base := nil;
-  if n.kind = nkObjectTy then
-    result := newOrPrevType(tyObject, prev, c)
-  else
-    InternalError(n.info, 'semObjectNode');
+  if n.kind <> nkObjectTy then InternalError(n.info, 'semObjectNode');
+  result := newOrPrevType(tyObject, prev, c);
   addSon(result, base);
   result.n := newNodeI(nkRecList, n.info);
   semRecordNodeAux(c, n.sons[2], check, pos, result.n, result.sym);
@@ -655,26 +600,75 @@ begin
     liMessage(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects);
 end;
 
-function semProcTypeNode(c: PContext; n: PNode; prev: PType): PType;
+function addTypeVarsOfGenericBody(c: PContext; t: PType; genericParams: PNode;
+                                  var cl: TIntSet): PType;
+var
+  i, L: int;
+  s: PSym;
+begin
+  result := t;
+  if (t = nil) then exit;
+  if IntSetContainsOrIncl(cl, t.id) then exit;
+  case t.kind of
+    tyGenericBody: begin
+      result := newTypeS(tyGenericInvokation, c);
+      addSon(result, t);
+      for i := 0 to sonsLen(t)-2 do begin
+        if t.sons[i].kind <> tyGenericParam then
+          InternalError('addTypeVarsOfGenericBody');
+        s := copySym(t.sons[i].sym);
+        s.position := sonsLen(genericParams);
+        addDecl(c, s);
+        addSon(genericParams, newSymNode(s));
+        addSon(result, t.sons[i]);
+      end;
+    end;
+    tyGenericInst: begin
+      L := sonsLen(t)-1;
+      t.sons[L] := addTypeVarsOfGenericBody(c, t.sons[L], genericParams, cl);
+    end;
+    tyGenericInvokation: begin
+      for i := 1 to sonsLen(t)-1 do
+        t.sons[i] := addTypeVarsOfGenericBody(c, t.sons[i], genericParams, cl);
+    end
+    else begin
+      for i := 0 to sonsLen(t)-1 do
+        t.sons[i] := addTypeVarsOfGenericBody(c, t.sons[i], genericParams, cl);
+    end
+  end
+end;
+
+function paramType(c: PContext; n, genericParams: PNode;
+                   var cl: TIntSet): PType;
+begin
+  result := semTypeNode(c, n, nil);
+  if (genericParams <> nil) and (sonsLen(genericParams) = 0) then 
+    result := addTypeVarsOfGenericBody(c, result, genericParams, cl);
+end;
+
+function semProcTypeNode(c: PContext; n, genericParams: PNode;
+                         prev: PType): PType;
 var
   i, j, len, counter: int;
   a, def, res: PNode;
   typ: PType;
   arg: PSym;
-  check: TIntSet;
+  check, cl: TIntSet;
 begin
   checkMinSonsLen(n, 1);
   result := newOrPrevType(tyProc, prev, c);
   result.callConv := lastOptionEntry(c).defaultCC;
   result.n := newNodeI(nkFormalParams, n.info);
+  if (genericParams <> nil) and (sonsLen(genericParams) = 0) then
+    IntSetInit(cl);
   if n.sons[0] = nil then begin
     addSon(result, nil); // return type
     addSon(result.n, newNodeI(nkType, n.info)); // BUGFIX: nkType must exist!
+    // XXX but it does not, if n.sons[paramsPos] == nil?
   end
   else begin
-    addSon(result, semTypeNode(c, n.sons[0], nil)); // return type
+    addSon(result, nil);
     res := newNodeI(nkType, n.info);
-    res.typ := result.sons[0];
     addSon(result.n, res);
   end;
   IntSetInit(check);
@@ -685,7 +679,7 @@ begin
     checkMinSonsLen(a, 3);
     len := sonsLen(a);
     if a.sons[len-2] <> nil then
-      typ := semTypeNode(c, a.sons[len-2], nil)
+      typ := paramType(c, a.sons[len-2], genericParams, cl)
     else
       typ := nil;
     if a.sons[len-1] <> nil then begin
@@ -712,6 +706,11 @@ begin
       addSon(result.n, newSymNode(arg));
       addSon(result, typ);
     end
+  end;
+  // NOTE: semantic checking of the result type needs to be done here!
+  if n.sons[0] <> nil then begin
+    result.sons[0] := paramType(c, n.sons[0], genericParams, cl);
+    res.typ := result.sons[0];
   end
 end;
 
@@ -751,6 +750,7 @@ end;
 function semTypeNode(c: PContext; n: PNode; prev: PType): PType;
 var
   s: PSym;
+  t: PType;
 begin
   result := nil;
   if n = nil then exit;
@@ -784,11 +784,12 @@ begin
       end
     end;
     nkSym: begin
-      if (n.sym.kind in [skTypeParam, skType]) and (n.sym.typ <> nil) then begin
+      if (n.sym.kind = skType) and (n.sym.typ <> nil) then begin
+        t := n.sym.typ;
         if prev = nil then
-          result := n.sym.typ
+          result := t
         else begin
-          assignType(prev, s.typ);
+          assignType(prev, t);
           result := prev;
         end;
         include(n.sym.flags, sfUsed); // BUGFIX
@@ -801,14 +802,14 @@ begin
     nkRefTy: result := semAnyRef(c, n, tyRef, 'ref', prev);
     nkPtrTy: result := semAnyRef(c, n, tyPtr, 'ptr', prev);
     nkVarTy: result := semVarType(c, n, prev);
-    nkAbstractTy: result := semAbstract(c, n, prev);
+    nkDistinctTy: result := semDistinct(c, n, prev);
     nkProcTy: begin
       checkSonsLen(n, 2);
-      result := semProcTypeNode(c, n.sons[0], prev);
+      result := semProcTypeNode(c, n.sons[0], nil, prev);
       // dummy symbol for `pragma`:
       s := newSymS(skProc, newIdentNode(getIdent('dummy'), n.info), c);
       s.typ := result;
-      pragmaProcType(c, s, n.sons[1]);
+      pragma(c, s, n.sons[1], procTypePragmas);
     end;
     nkEnumTy: result := semEnum(c, n, prev);
     nkType: result := n.typ;
@@ -859,6 +860,9 @@ begin
       exit
     end;
     mNil: setMagicType(m, tyNil, ptrSize);
+    mExpr: setMagicType(m, tyExpr, 0);
+    mStmt: setMagicType(m, tyStmt, 0);
+    mTypeDesc: setMagicType(m, tyTypeDesc, 0);
     mArray, mOpenArray, mRange, mSet, mSeq, mOrdinal: exit;
     else liMessage(m.info, errTypeExpected);
   end;
diff --git a/nim/sigmatch.pas b/nim/sigmatch.pas
index ccd05d413..aa53a741c 100644..100755
--- a/nim/sigmatch.pas
+++ b/nim/sigmatch.pas
@@ -43,7 +43,7 @@ begin
   c.call := nil;
   c.baseTypeMatch := false;
   initIdTable(c.bindings);
-  assert(c.callee <> nil);
+  //assert(c.callee <> nil);
 end;
 
 procedure copyCandidate(var a: TCandidate; const b: TCandidate);
@@ -117,7 +117,7 @@ end;
 function typeRel(var mapping: TIdTable; f, a: PType): TTypeRelation; overload;
   forward;
 
-function concreteType(t: PType): PType;
+function concreteType(const mapping: TIdTable; t: PType): PType;
 begin
   case t.kind of
     tyArrayConstr: begin  // make it an array
@@ -126,6 +126,14 @@ begin
       addSon(result, t.sons[1]); // XXX: semantic checking for the type?
     end;
     tyNil: result := nil; // what should it be?
+    tyGenericParam: begin
+      result := t;
+      while true do begin
+        result := PType(idTableGet(mapping, t));
+        if result = nil then InternalError('lookup failed');
+        if result.kind <> tyGenericParam then break
+      end
+    end;
     else result := t // Note: empty is valid here
   end
 end;
@@ -218,8 +226,9 @@ begin // is a subtype of f?
   result := isNone;
   assert(f <> nil);
   assert(a <> nil);
-  if (a.kind = tyGenericInst) and 
-      (skipTypes(f, {@set}[tyVar]).kind <> tyGeneric) then begin
+  if (a.kind = tyGenericInst) and not
+      (skipTypes(f, {@set}[tyVar]).kind in [tyGenericBody, tyGenericInvokation])
+  then begin
     result := typeRel(mapping, f, lastSon(a));
     exit
   end;
@@ -348,8 +357,8 @@ begin // is a subtype of f?
         else if isObjectSubtype(a, f) then result := isSubtype
       end
     end;
-    tyAbstract: begin
-      if (a.kind = tyAbstract) and (a.id = f.id) then result := isEqual;
+    tyDistinct: begin
+      if (a.kind = tyDistinct) and (a.id = f.id) then result := isEqual;
     end;
     tySet: begin
       if a.kind = tySet then begin
@@ -415,6 +424,8 @@ begin // is a subtype of f?
                 result := isNone
             end
             else if a.sons[0] <> nil then
+              result := isNone;
+            if (tfNoSideEffect in f.flags) and not (tfNoSideEffect in a.flags) then
               result := isNone
           end
         end
@@ -458,12 +469,11 @@ begin // is a subtype of f?
     end;
     tyGenericInst: begin
       result := typeRel(mapping, lastSon(f), a);
-    end;
-    tyGeneric: begin
+    end; (*
+    tyGenericBody: begin
       x := PType(idTableGet(mapping, f));
       if x = nil then begin
         assert(f.containerID <> 0);
-        assert(lastSon(f) = nil);
         if (a.kind = tyGenericInst) and (f.containerID = a.containerID) and
            (sonsLen(a) = sonsLen(f)) then begin
           for i := 0 to sonsLen(f)-2 do begin
@@ -476,22 +486,64 @@ begin // is a subtype of f?
       else begin
         result := typeRel(mapping, x, a) // check if it fits
       end
+    end; *)
+    tyGenericBody: begin
+      result := typeRel(mapping, lastSon(f), a);
+    end;
+    tyGenericInvokation: begin
+      assert(f.sons[0].kind = tyGenericBody);
+      if a.kind = tyGenericInvokation then begin
+        InternalError('typeRel: tyGenericInvokation -> tyGenericInvokation');
+      end;
+      if (a.kind = tyGenericInst) then begin
+        if (f.sons[0].containerID = a.sons[0].containerID)
+        and (sonsLen(a)-1 = sonsLen(f)) then begin
+          assert(a.sons[0].kind = tyGenericBody);
+          for i := 1 to sonsLen(f)-1 do begin
+            if a.sons[i].kind = tyGenericParam then begin
+              InternalError('wrong instantiated type!');
+            end;
+            if typeRel(mapping, f.sons[i], a.sons[i]) < isGeneric then exit;
+          end;
+          result := isGeneric;
+        end (*
+        else begin
+          MessageOut('came here: ' + toString(sonsLen(f)) + ' ' +
+                        toString(sonsLen(a)) + '  '+
+                        toString(f.sons[0].containerID) + ' '+
+                        toString(a.sons[0].containerID));
+        end *)
+      end 
+      else begin
+        result := typeRel(mapping, f.sons[0], a);
+        if result <> isNone then begin
+          // we steal the generic parameters from the tyGenericBody:
+          for i := 1 to sonsLen(f)-1 do begin
+            x := PType(idTableGet(mapping, f.sons[0].sons[i-1]));
+            if (x = nil) or (x.kind = tyGenericParam) then
+              InternalError('wrong instantiated type!');
+            idTablePut(mapping, f.sons[i], x);
+          end
+        end
+      end 
     end;
     tyGenericParam: begin
       x := PType(idTableGet(mapping, f));
       if x = nil then begin
         if sonsLen(f) = 0 then begin // no constraints
-          concrete := concreteType(a);
+          concrete := concreteType(mapping, a);
           if concrete <> nil then begin
+            //MessageOut('putting: ' + f.sym.name.s);
             idTablePut(mapping, f, concrete);
             result := isGeneric
           end;
         end
         else begin
+          InternalError(f.sym.info, 'has constraints: ' + f.sym.name.s);
           // check constraints:
           for i := 0 to sonsLen(f)-1 do begin
             if typeRel(mapping, f.sons[i], a) >= isSubtype then begin
-              concrete := concreteType(a);
+              concrete := concreteType(mapping, a);
               if concrete <> nil then begin
                 idTablePut(mapping, f, concrete);
                 result := isGeneric
@@ -503,10 +555,20 @@ begin // is a subtype of f?
       end
       else if a.kind = tyEmpty then
         result := isGeneric
-      else begin
-        result := typeRel(mapping, x, a); // check if it fits
-      end
-    end
+      else if x.kind = tyGenericParam then
+        result := isGeneric
+      else 
+        result := typeRel(mapping, x, a) // check if it fits
+    end;
+    tyExpr, tyStmt, tyTypeDesc: begin
+      if a.kind = f.kind then result := isEqual
+      else
+        case a.kind of
+          tyExpr, tyStmt, tyTypeDesc: result := isGeneric;
+          tyNil: result := isSubtype;
+          else begin end
+        end
+    end;
     else internalError('typeRel(' +{&} typeKindToStr[f.kind] +{&} ')');
   end
 end;
@@ -524,7 +586,7 @@ function getInstantiatedType(c: PContext; arg: PNode; const m: TCandidate;
 begin
   result := PType(idTableGet(m.bindings, f));
   if result = nil then begin
-    result := generateTypeInstance(c, m.bindings, arg.info, f);
+    result := generateTypeInstance(c, m.bindings, arg, f);
   end;
   if result = nil then InternalError(arg.info, 'getInstantiatedType');
 end;
@@ -630,8 +692,9 @@ var
   x, y, z: TCandidate;
   r: TTypeRelation;
 begin
-  if (arg = nil) or (arg.kind <> nkSymChoice) then
+  if (arg = nil) or (arg.kind <> nkSymChoice) then begin
     result := ParamTypesMatchAux(c, m, f, a, arg)
+  end
   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
@@ -645,16 +708,19 @@ begin
     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
+      // iterators are not first class yet, so ignore them
+      if arg.sons[i].sym.kind in {@set}[skProc, skConverter] then 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
@@ -818,13 +884,14 @@ begin
   end
 end;
 
-function semDirectCall(c: PContext; n: PNode): PNode;
+function semDirectCall(c: PContext; n: PNode; filter: TSymKinds): PNode;
 var
   sym: PSym;
   o: TOverloadIter;
   x, y, z: TCandidate;
   cmp: int;
 begin
+  //liMessage(n.info, warnUser, renderTree(n));
   sym := initOverloadIter(o, c, n.sons[0]);
   result := nil;
   if sym = nil then exit;
@@ -833,7 +900,7 @@ begin
   initCandidate(y, sym.typ);
   y.calleeSym := sym;
   while sym <> nil do begin
-    if sym.kind in [skProc, skIterator, skConverter] then begin
+    if sym.kind in filter then begin
       initCandidate(z, sym.typ);
       z.calleeSym := sym;
       matches(c, n, z);
diff --git a/nim/strutils.pas b/nim/strutils.pas
index f34379fcb..be20b52b2 100644..100755
--- a/nim/strutils.pas
+++ b/nim/strutils.pas
@@ -66,7 +66,7 @@ function repeatChar(count: int; c: Char = ' '): string;
 type
   TStringSeq = array of string;
   TCharSet = set of Char;
-function splitSeq(const s: string; const seps: TCharSet): TStringSeq;
+function split(const s: string; const seps: TCharSet): TStringSeq;
 
 function startsWith(const s, prefix: string): bool;
 function endsWith(const s, postfix: string): bool;
@@ -78,9 +78,15 @@ function strip(const s: string; const chars: TCharSet = WhiteSpace): string;
 function allCharsInSet(const s: string; const theSet: TCharSet): bool;
 
 function quoteIfContainsWhite(const s: string): string;
+procedure addSep(var dest: string; sep: string = ', '); 
 
 implementation
 
+procedure addSep(var dest: string; sep: string = ', '); 
+begin
+  if length(dest) > 0 then add(dest, sep)
+end;
+
 function quoteIfContainsWhite(const s: string): string;
 begin
   if ((find(s, ' ') >= strStart)
@@ -148,7 +154,7 @@ begin
   end
 end;
 
-function splitSeq(const s: string; const seps: TCharSet): TStringSeq;
+function split(const s: string; const seps: TCharSet): TStringSeq;
 var
   first, last, len: int;
 begin
diff --git a/nim/syntaxes.pas b/nim/syntaxes.pas
index 1068064ce..1068064ce 100644..100755
--- a/nim/syntaxes.pas
+++ b/nim/syntaxes.pas
diff --git a/nim/tigen.pas b/nim/tigen.pas
index 687b70920..687b70920 100644..100755
--- a/nim/tigen.pas
+++ b/nim/tigen.pas
diff --git a/nim/transf.pas b/nim/transf.pas
index 3e3b2a611..79f65b754 100644..100755
--- a/nim/transf.pas
+++ b/nim/transf.pas
@@ -124,7 +124,7 @@ Should be transformed into::
         return a[i]
         block L1: inc(c.i)
 
-More efficient, but not implementable:
+More efficient, but not implementable::
 
   type
     TItemsClosure = record
@@ -288,7 +288,7 @@ end;
 
 function inlineIter(c: PTransf; n: PNode): PNode;
 var
-  i: int;
+  i, j, L: int;
   it: PNode;
   newVar: PSym;
 begin
@@ -304,16 +304,33 @@ begin
       for i := 0 to sonsLen(result)-1 do begin
         it := result.sons[i];
         if it.kind = nkCommentStmt then continue;
-        if (it.kind <> nkIdentDefs) or (it.sons[0].kind <> nkSym) then
-          InternalError(it.info, 'inlineIter');
-        newVar := copySym(it.sons[0].sym);
-        include(newVar.flags, sfFromGeneric);
-        // fixes a strange bug for rodgen:
-        //include(it.sons[0].sym.flags, sfFromGeneric);
-        newVar.owner := getCurrOwner(c);
-        IdNodeTablePut(c.transCon.mapping, it.sons[0].sym, newSymNode(newVar));
-        it.sons[0] := newSymNode(newVar);
-        it.sons[2] := transform(c, it.sons[2]);
+        if it.kind = nkIdentDefs then begin
+          if (it.sons[0].kind <> nkSym) then
+            InternalError(it.info, 'inlineIter');
+          newVar := copySym(it.sons[0].sym);
+          include(newVar.flags, sfFromGeneric);
+          // fixes a strange bug for rodgen:
+          //include(it.sons[0].sym.flags, sfFromGeneric);
+          newVar.owner := getCurrOwner(c);
+          IdNodeTablePut(c.transCon.mapping, it.sons[0].sym, newSymNode(newVar));
+          it.sons[0] := newSymNode(newVar);
+          it.sons[2] := transform(c, it.sons[2]);
+        end
+        else begin
+          if it.kind <> nkVarTuple then
+            InternalError(it.info, 'inlineIter: not nkVarTuple');
+          L := sonsLen(it);
+          for j := 0 to L-3 do begin
+            newVar := copySym(it.sons[j].sym);
+            include(newVar.flags, sfFromGeneric);
+            newVar.owner := getCurrOwner(c);
+            IdNodeTablePut(c.transCon.mapping, it.sons[j].sym,
+                           newSymNode(newVar));
+            it.sons[j] := newSymNode(newVar);
+          end;
+          assert(it.sons[L-2] = nil);
+          it.sons[L-1] := transform(c, it.sons[L-1]);
+        end
       end
     end
     else begin
@@ -758,7 +775,8 @@ function getMergeOp(n: PNode): PSym;
 begin
   result := nil;
   case n.kind of
-    nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix: begin
+    nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
+    nkCallStrLit: begin
       if (n.sons[0].Kind = nkSym) and (n.sons[0].sym.kind = skProc) 
       and (sfMerge in n.sons[0].sym.flags) then 
         result := n.sons[0].sym;
@@ -873,7 +891,8 @@ begin
       n.sons[0] := transform(c, n.sons[0]);
       n.sons[1] := transformContinue(c, n.sons[1]);
     end;
-    nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix:
+    nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
+    nkCallStrLit:
       result := transformCall(c, result);
     nkAddr, nkHiddenAddr:
       result := transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref);
diff --git a/nim/transtmp.pas b/nim/transtmp.pas
index 77ba157f3..15a07f5a2 100644..100755
--- a/nim/transtmp.pas
+++ b/nim/transtmp.pas
@@ -140,7 +140,7 @@ begin
         addSon(father, newAsgnStmt(dest, src));
       end
     end;
-    nkCall, nkCommand: begin
+    nkCall, nkCommand, nkCallStrLit: begin
     
     end;
     
diff --git a/nim/trees.pas b/nim/trees.pas
index 4df85f6bb..0e0c04a22 100644..100755
--- a/nim/trees.pas
+++ b/nim/trees.pas
@@ -144,21 +144,19 @@ end;
 
 function getOpSym(op: PNode): PSym;
 begin
-  if not (op.kind in [nkCall, nkGenericCall, nkHiddenCallConv, nkCommand]) then
+  if not (op.kind in [nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit]) then
     result := nil
   else begin
     if (sonsLen(op) <= 0) then InternalError(op.info, 'getOpSym');
-    case op.sons[0].Kind of
-      nkSym, nkQualified: result := op.sons[0].sym;
-      else result := nil
-    end
+    if op.sons[0].Kind = nkSym then result := op.sons[0].sym
+    else result := nil
   end
 end;
 
 function getMagic(op: PNode): TMagic;
 begin
   case op.kind of
-    nkCall, nkHiddenCallConv, nkCommand: begin
+    nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit: begin
       case op.sons[0].Kind of
         nkSym: begin
           result := op.sons[0].sym.magic;
@@ -166,9 +164,6 @@ begin
         else result := mNone
       end
     end;
-    nkExplicitTypeListCall, nkGenericCall: begin
-      result := getMagic(op.sons[sonsLen(op)-1]);
-    end;
     else
       result := mNone
   end
diff --git a/nim/treetab.pas b/nim/treetab.pas
index 31d7aa0cf..31d7aa0cf 100644..100755
--- a/nim/treetab.pas
+++ b/nim/treetab.pas
diff --git a/nim/types.pas b/nim/types.pas
index d2aee2413..a881b2f11 100644..100755
--- a/nim/types.pas
+++ b/nim/types.pas
@@ -48,7 +48,7 @@ function mutateType(t: PType; iter: TTypeMutator; closure: PObject): PType;
 
 function SameType(x, y: PType): Boolean;
 function SameTypeOrNil(a, b: PType): Boolean;
-function equalOrAbstractOf(x, y: PType): bool;
+function equalOrDistinctOf(x, y: PType): bool;
 
 type
   TParamsEquality = (paramsNotEqual,      // parameters are not equal
@@ -66,11 +66,11 @@ function isOrdinalType(t: PType): Boolean;
 function enumHasWholes(t: PType): Boolean;
 
 const
-  abstractPtrs = {@set}[tyVar, tyPtr, tyRef, tyGenericInst, tyAbstract, tyOrdinal];
-  abstractVar = {@set}[tyVar, tyGenericInst, tyAbstract, tyOrdinal];
-  abstractRange = {@set}[tyGenericInst, tyRange, tyAbstract, tyOrdinal];
-  abstractVarRange = {@set}[tyGenericInst, tyRange, tyVar, tyAbstract, tyOrdinal];
-  abstractInst = {@set}[tyGenericInst, tyAbstract, tyOrdinal];
+  abstractPtrs = {@set}[tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal];
+  abstractVar = {@set}[tyVar, tyGenericInst, tyDistinct, tyOrdinal];
+  abstractRange = {@set}[tyGenericInst, tyRange, tyDistinct, tyOrdinal];
+  abstractVarRange = {@set}[tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal];
+  abstractInst = {@set}[tyGenericInst, tyDistinct, tyOrdinal];
 
 function skipTypes(t: PType; kinds: TTypeKinds): PType;
 
@@ -202,7 +202,7 @@ function elemType(t: PType): PType;
 begin
   assert(t <> nil);
   case t.kind of
-    tyGenericInst, tyAbstract: result := elemType(lastSon(t));
+    tyGenericInst, tyDistinct: result := elemType(lastSon(t));
     tyArray, tyArrayConstr: result := t.sons[1];
     else result := t.sons[0];
   end;
@@ -317,12 +317,17 @@ begin
   result := iter(t, closure);
   if result then exit;
   if not IntSetContainsOrIncl(marker, t.id) then begin
-    for i := 0 to sonsLen(t)-1 do begin
-      result := iterOverTypeAux(marker, t.sons[i], iter, closure);
-      if result then exit;
-    end;
-    if t.n <> nil then
-      result := iterOverNode(marker, t.n, iter, closure)
+    case t.kind of
+      tyGenericInst, tyGenericBody: 
+        result := iterOverTypeAux(marker, lastSon(t), iter, closure);
+      else begin
+        for i := 0 to sonsLen(t)-1 do begin
+          result := iterOverTypeAux(marker, t.sons[i], iter, closure);
+          if result then exit;
+        end;
+        if t.n <> nil then result := iterOverNode(marker, t.n, iter, closure)
+      end
+    end
   end
 end;
 
@@ -388,7 +393,7 @@ begin
       if not result then
         result := searchTypeNodeForAux(t.n, predicate, marker);
     end;
-    tyGenericInst, tyAbstract:
+    tyGenericInst, tyDistinct:
       result := searchTypeForAux(lastSon(t), predicate, marker);
     tyArray, tyArrayConstr, tySet, tyTuple: begin
       for i := 0 to sonsLen(t)-1 do begin
@@ -421,7 +426,7 @@ end;
 function isObjectWithTypeFieldPredicate(t: PType): bool;
 begin
   result := (t.kind = tyObject) and (t.sons[0] = nil) 
-    and not (sfPure in t.sym.flags) 
+    and not ((t.sym <> nil) and (sfPure in t.sym.flags))
     and not (tfFinal in t.flags);
 end;
 
@@ -447,7 +452,7 @@ begin
       if result = frNone then
         if isObjectWithTypeFieldPredicate(t) then result := frHeader
     end;
-    tyGenericInst, tyAbstract: 
+    tyGenericInst, tyDistinct: 
       result := analyseObjectWithTypeFieldAux(lastSon(t), marker);
     tyArray, tyArrayConstr, tyTuple: begin
       for i := 0 to sonsLen(t)-1 do begin
@@ -491,7 +496,7 @@ begin
   result := searchTypeFor(typ, isHiddenPointer);
 end;
 
-function canFormAcycleAux(var marker: TIntSet; t: PType; 
+function canFormAcycleAux(var marker: TIntSet; typ: PType; 
                           startId: int): bool; forward;
 
 function canFormAcycleNode(var marker: TIntSet; n: PNode; startId: int): bool;
@@ -514,14 +519,17 @@ begin
   end
 end;
 
-function canFormAcycleAux(var marker: TIntSet; t: PType; startId: int): bool;
+function canFormAcycleAux(var marker: TIntSet; typ: PType; startId: int): bool;
 var
   i: int;
+  t: PType;
 begin
   result := false;
-  if t = nil then exit;
+  if typ = nil then exit;
+  if tfAcyclic in typ.flags then exit;
+  t := skipTypes(typ, abstractInst);
   if tfAcyclic in t.flags then exit;
-  case skipTypes(t, abstractInst).kind of 
+  case t.kind of 
     tyTuple, tyObject, tyRef, tySequence, tyArray, tyArrayConstr,
     tyOpenArray: begin
       if not IntSetContainsOrIncl(marker, t.id) then begin
@@ -606,8 +614,10 @@ end;
 function TypeToString(typ: PType; prefer: TPreferedDesc = preferName): string;
 const
   typeToStr: array [TTypeKind] of string = (
-    'None', 'bool', 'Char', 'empty', 'Array Constructor [$1]', 'nil',
-    'Generic', 'GenericInst', 'GenericParam', 'abstract $1',
+    'None', 'bool', 'Char', 'empty', 'Array Constructor [$1]', 'nil', 'expr',
+    'stmt', 'typeDesc',
+    'GenericInvokation',
+    'GenericBody', 'GenericInst', 'GenericParam', 'distinct $1',
     'enum', 'ordinal[$1]',
     'array[$1, $2]', 'object', 'tuple', 'set[$1]', 'range[$1]',
     'ptr ', 'ref ', 'var ', 'seq[$1]', 'proc', 'pointer',
@@ -618,6 +628,7 @@ const
 var
   t: PType;
   i: int;
+  prag: string;
 begin
   t := typ;
   result := '';
@@ -637,6 +648,14 @@ begin
         result := 'array[' +{&} typeToString(t.sons[0]) +{&} ', '
                   +{&} typeToString(t.sons[1]) +{&} ']'
     end;
+    tyGenericInvokation, tyGenericBody: begin
+      result := typeToString(t.sons[0]) + '[';
+      for i := 1 to sonsLen(t)-1 do begin
+        if i > 1 then add(result, ', ');
+        add(result, typeToString(t.sons[i]));
+      end;
+      addChar(result, ']');
+    end;
     tyArrayConstr:
       result := 'Array constructor[' +{&} rangeToStr(t.sons[0].n) +{&} ', '
                 +{&} typeToString(t.sons[1]) +{&} ']';
@@ -644,7 +663,7 @@ begin
     tyOrdinal: result := 'ordinal[' +{&} typeToString(t.sons[0]) +{&} ']';
     tySet: result := 'set[' +{&} typeToString(t.sons[0]) +{&} ']';
     tyOpenArray: result := 'openarray[' +{&} typeToString(t.sons[0]) +{&} ']';
-    tyAbstract: result := 'abstract ' +{&} typeToString(t.sons[0], preferName);
+    tyDistinct: result := 'distinct ' +{&} typeToString(t.sons[0], preferName);
     tyTuple: begin
       // we iterate over t.sons here, because t.n may be nil
       result := 'tuple[';
@@ -679,8 +698,13 @@ begin
       addChar(result, ')');
       if t.sons[0] <> nil then
         add(result, ': ' +{&} TypeToString(t.sons[0]));
-      if t.callConv <> ccDefault then
-        add(result, '{.' +{&} CallingConvToStr[t.callConv] +{&} '.}');
+      if t.callConv <> ccDefault then prag := CallingConvToStr[t.callConv]
+      else prag := '';
+      if tfNoSideEffect in t.flags then begin
+        addSep(prag);
+        add(prag, 'noSideEffect')
+      end;
+      if length(prag) <> 0 then add(result, '{.' +{&} prag +{&} '.}');
     end;
     else begin
       result := typeToStr[t.kind]
@@ -730,7 +754,7 @@ begin
         result := t.n.sons[0].sym.position;
       end;
     end;
-    tyGenericInst, tyAbstract: result := firstOrd(lastSon(t));
+    tyGenericInst, tyDistinct: result := firstOrd(lastSon(t));
     else begin
       InternalError('invalid kind for first(' +{&}
         typeKindToStr[t.kind] +{&} ')');
@@ -766,7 +790,7 @@ begin
       assert(t.n.sons[sonsLen(t.n)-1].kind = nkSym);
       result := t.n.sons[sonsLen(t.n)-1].sym.position;
     end;
-    tyGenericInst, tyAbstract: result := firstOrd(lastSon(t));
+    tyGenericInst, tyDistinct: result := firstOrd(lastSon(t));
     else begin
       InternalError('invalid kind for last(' +{&}
         typeKindToStr[t.kind] +{&} ')');
@@ -779,7 +803,7 @@ function lengthOrd(t: PType): biggestInt;
 begin
   case t.kind of
     tyInt64, tyInt32, tyInt: result := lastOrd(t);
-    tyAbstract: result := lengthOrd(t.sons[0]);
+    tyDistinct: result := lengthOrd(t.sons[0]);
     else result := lastOrd(t) - firstOrd(t) + 1;
   end
 end;
@@ -868,7 +892,7 @@ begin
     SameLiteral(a.sons[1], b.sons[1])
 end;
 
-function sameTuple(a, b: PType; AbstractOf: bool): boolean;
+function sameTuple(a, b: PType; DistinctOf: bool): boolean;
 // two tuples are equivalent iff the names, types and positions are the same;
 // however, both types may not have any field names (t.n may be nil) which
 // complicates the matter a bit.
@@ -879,8 +903,8 @@ begin
   if sonsLen(a) = sonsLen(b) then begin
     result := true;
     for i := 0 to sonsLen(a)-1 do begin
-      if AbstractOf then 
-        result := equalOrAbstractOf(a.sons[i], b.sons[i])
+      if DistinctOf then 
+        result := equalOrDistinctOf(a.sons[i], b.sons[i])
       else
         result := SameType(a.sons[i], b.sons[i]);
       if not result then exit
@@ -914,15 +938,15 @@ begin
   if a.kind <> b.kind then begin result := false; exit end;
   case a.Kind of
     tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString, 
-    tyInt..tyFloat128: 
+    tyInt..tyFloat128, tyExpr, tyStmt, tyTypeDesc: 
       result := true;
-    tyEnum, tyForward, tyObject, tyAbstract:
+    tyEnum, tyForward, tyObject, tyDistinct:
       result := (a.id = b.id);
     tyTuple: 
       result := sameTuple(a, b, false);
     tyGenericInst:
       result := sameType(lastSon(a), lastSon(b));
-    tyGenericParam, tyGeneric, tySequence, tyOrdinal,
+    tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence, tyOrdinal,
     tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
     tyArray, tyProc: begin
       if sonsLen(a) = sonsLen(b) then begin
@@ -946,7 +970,7 @@ begin
   end
 end;
 
-function equalOrAbstractOf(x, y: PType): bool;
+function equalOrDistinctOf(x, y: PType): bool;
 var
   i: int;
   a, b: PType;
@@ -958,26 +982,26 @@ begin
   assert(a <> nil);
   assert(b <> nil);
   if a.kind <> b.kind then begin 
-    if a.kind = tyAbstract then a := a.sons[0];
+    if a.kind = tyDistinct then a := a.sons[0];
     if a.kind <> b.kind then begin result := false; exit end
   end;
   case a.Kind of
     tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString, 
-    tyInt..tyFloat128: 
+    tyInt..tyFloat128, tyExpr, tyStmt, tyTypeDesc: 
       result := true;
-    tyEnum, tyForward, tyObject, tyAbstract:
+    tyEnum, tyForward, tyObject, tyDistinct:
       result := (a.id = b.id);
     tyTuple: 
       result := sameTuple(a, b, true);
     tyGenericInst:
-      result := equalOrAbstractOf(lastSon(a), lastSon(b));
-    tyGenericParam, tyGeneric, tySequence, tyOrdinal,
+      result := equalOrDistinctOf(lastSon(a), lastSon(b));
+    tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence, tyOrdinal,
     tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
     tyArray, tyProc: begin
       if sonsLen(a) = sonsLen(b) then begin
         result := true;
         for i := 0 to sonsLen(a)-1 do begin
-          result := equalOrAbstractOf(a.sons[i], b.sons[i]);
+          result := equalOrDistinctOf(a.sons[i], b.sons[i]);
           if not result then exit
         end;
         if result and (a.kind = tyProc) then 
@@ -987,7 +1011,7 @@ begin
         result := false;
     end;
     tyRange: begin
-      result := equalOrAbstractOf(a.sons[0], b.sons[0])
+      result := equalOrDistinctOf(a.sons[0], b.sons[0])
         and SameValue(a.n.sons[0], b.n.sons[0])
         and SameValue(a.n.sons[1], b.n.sons[1])
     end;
@@ -995,7 +1019,7 @@ begin
   end
 end;
 
-function typeAllowedAux(var marker: TIntSet; t: PType; 
+function typeAllowedAux(var marker: TIntSet; typ: PType; 
                         kind: TSymKind): bool; forward;
 
 function typeAllowedNode(var marker: TIntSet; n: PNode; kind: TSymKind): bool;
@@ -1005,6 +1029,7 @@ begin
   result := true;
   if n <> nil then begin
     result := typeAllowedAux(marker, n.typ, kind);
+    if not result then debug(n.typ);
     if result then 
       case n.kind of
         nkNone..nkNilLit: begin end;
@@ -1018,24 +1043,27 @@ begin
   end
 end;
 
-function typeAllowedAux(var marker: TIntSet; t: PType; kind: TSymKind): bool;
+function typeAllowedAux(var marker: TIntSet; typ: PType; kind: TSymKind): bool;
 var
   i: int;
+  t, t2: PType;
 begin
   assert(kind in [skVar, skConst, skParam]);
   result := true;
-  if t = nil then exit;
+  if typ = nil then exit;
   // if we have already checked the type, return true, because we stop the
   // evaluation if something is wrong:
-  if IntSetContainsOrIncl(marker, t.id) then exit;
-  case skipTypes(t, abstractInst).kind of 
+  if IntSetContainsOrIncl(marker, typ.id) then exit;
+  t := skipTypes(typ, abstractInst);
+  case t.kind of 
     tyVar: begin
-      case skipTypes(t.sons[0], abstractInst).kind of
+      t2 := skipTypes(t.sons[0], abstractInst);
+      case t2.kind of
         tyVar: result := false; // ``var var`` is always an invalid type:
         tyOpenArray: result := (kind = skParam) and 
-                                typeAllowedAux(marker, t.sons[0], kind);
+                                typeAllowedAux(marker, t2, kind);
         else result := (kind <> skConst) and 
-                                typeAllowedAux(marker, t.sons[0], kind);
+                                typeAllowedAux(marker, t2, kind);
       end
     end;
     tyProc: begin
@@ -1046,12 +1074,16 @@ begin
       if t.sons[0] <> nil then
         result := typeAllowedAux(marker, t.sons[0], skVar)
     end;
-    tyGeneric, tyGenericParam, tyForward, tyNone: result := false;
+    tyExpr, tyStmt, tyTypeDesc: result := true;
+    tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation: begin
+      result := false;
+      //InternalError('shit found');
+    end;
     tyEmpty, tyNil: result := kind = skConst;
     tyString, tyBool, tyChar, tyEnum, tyInt..tyFloat128, tyCString, tyPointer: 
       result := true;
     tyOrdinal: result := kind = skParam;
-    tyGenericInst, tyAbstract: 
+    tyGenericInst, tyDistinct: 
       result := typeAllowedAux(marker, lastSon(t), kind);
     tyRange: 
       result := skipTypes(t.sons[0], abstractInst).kind in
@@ -1074,8 +1106,8 @@ begin
         result := typeAllowedAux(marker, t.sons[i], skVar);
         if not result then exit
       end;
-      if t.n <> nil then result := typeAllowedNode(marker, t.n, skVar)
-    end
+      if t.n <> nil then result := typeAllowedNode(marker, t.n, skVar);
+    end;
   end
 end;
 
@@ -1221,7 +1253,7 @@ begin
         if result < 0 then exit;
         maxAlign := a
       end
-      else if typ.kind = tyObject then begin
+      else if isObjectWithTypeFieldPredicate(typ) then begin
         result := intSize; maxAlign := result;
       end
       else begin
@@ -1233,7 +1265,7 @@ begin
       if a < maxAlign then a := maxAlign;
       result := align(result, a);
     end;
-    tyGenericInst, tyAbstract: begin
+    tyGenericInst, tyDistinct, tyGenericBody: begin
       result := computeSizeAux(lastSon(typ), a);
     end;
     else begin
diff --git a/nim/wordrecg.pas b/nim/wordrecg.pas
index 1f4513ed5..9bf3de256 100644..100755
--- a/nim/wordrecg.pas
+++ b/nim/wordrecg.pas
@@ -39,10 +39,10 @@ type
     //  i = i + 1
     //cog.out(idents)
     //]]]
-    wAbstract, wAddr, wAnd, wAs, 
-    wAsm, wBind, wBlock, wBreak, 
-    wCase, wCast, wConst, wContinue, 
-    wConverter, wDiscard, wDiv, wElif, 
+    wAddr, wAnd, wAs, wAsm, 
+    wBind, wBlock, wBreak, wCase, 
+    wCast, wConst, wContinue, wConverter, 
+    wDiscard, wDistinct, wDiv, wElif, 
     wElse, wEnd, wEnum, wExcept, 
     wFinally, wFor, wFrom, wGeneric, 
     wIf, wImplies, wImport, wIn, 
@@ -81,13 +81,13 @@ type
     wBorrow, wRun, wR, wVerbosity, wV, wHelp,
     wH, wSymbolFiles, wFieldChecks, wX, wVersion, wAdvanced,
     wSkipcfg, wSkipProjCfg, wCc, wGenscript, wCheckPoint, wCheckPoints,
-    wMaxErr, wExpr, wStmt, wTypeDesc,
-    wSubsChar, wAstCache, wAcyclic, wIndex,
+    wNoMain,
+    wSubsChar, wAcyclic, wIndex,
     // commands:
     wCompileToC, wCompileToCpp, wCompileToEcmaScript, wCompileToLLVM,
     wPretty, wDoc, wPas,
     wGenDepend, wListDef, wCheck, wParse, wScan, wBoot, wLazy,
-    wRst2html, wI,
+    wRst2html, wRst2tex, wI,
     // special for the preprocessor of configuration files:
     wWrite, wPutEnv, wPrependEnv, wAppendEnv,
     // additional Pascal keywords:
@@ -107,16 +107,15 @@ type
 const
   oprLow = ord(wColon);
   oprHigh = ord(wHat);
-  specialWords: array [low(TSpecialWord)..high(TSpecialWord)]
-                of string = ('',
+  specialWords: array [low(TSpecialWord)..high(TSpecialWord)] of string = ('',
     // keywords:
     //[[[cog
     //cog.out(strings)
     //]]]
-    'abstract', 'addr', 'and', 'as', 
-    'asm', 'bind', 'block', 'break', 
-    'case', 'cast', 'const', 'continue', 
-    'converter', 'discard', 'div', 'elif', 
+    'addr', 'and', 'as', 'asm', 
+    'bind', 'block', 'break', 'case', 
+    'cast', 'const', 'continue', 'converter', 
+    'discard', 'distinct', 'div', 'elif', 
     'else', 'end', 'enum', 'except', 
     'finally', 'for', 'from', 'generic', 
     'if', 'implies', 'import', 'in', 
@@ -155,12 +154,12 @@ const
     'borrow', 'run', 'r'+'', 'verbosity', 'v'+'', 'help',
     'h'+'', 'symbolfiles', 'fieldchecks', 'x'+'', 'version', 'advanced',
     'skipcfg', 'skipprojcfg', 'cc', 'genscript', 'checkpoint', 'checkpoints',
-    'maxerr', 'expr', 'stmt', 'typedesc',
-    'subschar', 'astcache', 'acyclic', 'index',
+    'nomain',
+    'subschar', 'acyclic', 'index',
     // commands:
     'compiletoc', 'compiletocpp', 'compiletoecmascript', 'compiletollvm',
     'pretty', 'doc', 'pas', 'gendepend', 'listdef', 'check', 'parse',
-    'scan', 'boot', 'lazy', 'rst2html', 'i'+'',
+    'scan', 'boot', 'lazy', 'rst2html', 'rst2tex', 'i'+'',
 
     // special for the preprocessor of configuration files:
     'write', 'putenv', 'prependenv', 'appendenv',