summary refs log tree commit diff stats
path: root/nim
diff options
context:
space:
mode:
authorAndreas Rumpf <andreasrumpf@noname>2009-09-23 23:38:00 +0200
committerAndreas Rumpf <andreasrumpf@noname>2009-09-23 23:38:00 +0200
commit3f3dda5a77fa8faf6d97aa5a0ed3b0fc6e8c0918 (patch)
tree81fcf664ab2abfda200061e57fa488ae17b03192 /nim
parent66a7e3d37c0303997a6b1a3b7ec263dfb8c07748 (diff)
downloadNim-3f3dda5a77fa8faf6d97aa5a0ed3b0fc6e8c0918.tar.gz
implemented multi methods
Diffstat (limited to 'nim')
-rwxr-xr-xnim/ast.pas147
-rwxr-xr-xnim/ccgexprs.pas27
-rwxr-xr-xnim/ccgstmts.pas7
-rwxr-xr-xnim/ccgtypes.pas18
-rwxr-xr-xnim/cgen.pas33
-rw-r--r--nim/cgmeth.pas269
-rwxr-xr-xnim/docgen.pas1
-rwxr-xr-xnim/ecmasgen.pas2
-rwxr-xr-xnim/evals.pas20
-rwxr-xr-xnim/highlite.pas39
-rwxr-xr-xnim/importer.pas4
-rwxr-xr-xnim/lookups.pas4
-rwxr-xr-xnim/magicsys.pas16
-rwxr-xr-xnim/nhashes.pas2
-rwxr-xr-xnim/nversion.pas4
-rwxr-xr-xnim/pasparse.pas7
-rwxr-xr-xnim/passaux.pas2
-rwxr-xr-xnim/passes.pas2
-rwxr-xr-xnim/pnimsyn.pas36
-rwxr-xr-xnim/pragmas.pas6
-rwxr-xr-xnim/rnimsyn.pas4
-rwxr-xr-xnim/rodwrite.pas2
-rwxr-xr-xnim/sem.pas11
-rwxr-xr-xnim/semexprs.pas69
-rwxr-xr-xnim/semfold.pas4
-rwxr-xr-xnim/seminst.pas2
-rwxr-xr-xnim/semstmts.pas12
-rwxr-xr-xnim/semtempl.pas4
-rwxr-xr-xnim/semtypes.pas4
-rwxr-xr-xnim/sigmatch.pas24
-rwxr-xr-xnim/transf.pas18
31 files changed, 571 insertions, 229 deletions
diff --git a/nim/ast.pas b/nim/ast.pas
index aec165585..cbe5b37fd 100755
--- a/nim/ast.pas
+++ b/nim/ast.pas
@@ -84,20 +84,21 @@ type
     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, nkDistinctTy, 
-    nkProcTy, nkEnumTy, nkEnumFieldDef, nkReturnToken);
+    nkOfInherit, nkModule, nkProcDef, nkMethodDef, 
+    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, 
+    nkDistinctTy, nkProcTy, nkEnumTy, nkEnumFieldDef, 
+    nkReturnToken);
   TNodeKinds = set of TNodeKind;
 const
   NodeKindToStr: array [TNodeKind] of string = (
@@ -118,20 +119,21 @@ const
     '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', 'nkDistinctTy', 
-    'nkProcTy', 'nkEnumTy', 'nkEnumFieldDef', 'nkReturnToken');
+    'nkOfInherit', 'nkModule', 'nkProcDef', 'nkMethodDef', 
+    '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', 
+    'nkDistinctTy', 'nkProcTy', 'nkEnumTy', 'nkEnumFieldDef', 
+    'nkReturnToken');
 type
   TSymFlag = (
     sfUsed, sfStar, sfMinus, sfInInterface, 
@@ -200,17 +202,19 @@ type
   TSymKind = (
     skUnknown, skConditional, skDynLib, skParam, 
     skGenericParam, skTemp, skType, skConst, 
-    skVar, skProc, skIterator, skConverter, 
-    skMacro, skTemplate, skField, skEnumField, 
-    skForVar, skModule, skLabel, skStub);
+    skVar, skProc, skMethod, skIterator, 
+    skConverter, skMacro, skTemplate, skField, 
+    skEnumField, skForVar, skModule, skLabel, 
+    skStub);
   TSymKinds = set of TSymKind;
 const
   SymKindToStr: array [TSymKind] of string = (
     'skUnknown', 'skConditional', 'skDynLib', 'skParam', 
     'skGenericParam', 'skTemp', 'skType', 'skConst', 
-    'skVar', 'skProc', 'skIterator', 'skConverter', 
-    'skMacro', 'skTemplate', 'skField', 'skEnumField', 
-    'skForVar', 'skModule', 'skLabel', 'skStub');
+    'skVar', 'skProc', 'skMethod', 'skIterator', 
+    'skConverter', 'skMacro', 'skTemplate', 'skField', 
+    'skEnumField', 'skForVar', 'skModule', 'skLabel', 
+    'skStub');
 {[[[end]]]}
 
 type
@@ -223,9 +227,9 @@ type
     //  if (i+1) % 6 == 0: cog.outl("")
     //cog.outl("m" + magics[-1])
     //]]]
-    mNone, mDefined, mLow, mHigh, mSizeOf, mIs, 
-    mEcho, mSucc, mPred, mInc, mDec, mOrd, 
-    mNew, mNewFinalize, mNewSeq, mRegisterFinalizer, mLengthOpenArray, mLengthStr, 
+    mNone, mDefined, mDefinedInScope, mLow, mHigh, mSizeOf, 
+    mIs, mEcho, mSucc, mPred, mInc, mDec, 
+    mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray, mLengthStr, 
     mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, 
     mGCref, mGCunref, mAddI, mSubI, mMulI, mDivI, 
     mModI, mAddI64, mSubI64, mMulI64, mDivI64, mModI64, 
@@ -247,21 +251,20 @@ type
     mStrToStr, mEnumToStr, mAnd, mOr, mEqStr, mLeStr, 
     mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, 
     mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT, mConTArr, 
-    mConTT, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendSeqSeq, 
-    mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, 
-    mAssert, mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, 
-    mNewString, mArray, mOpenArray, mRange, mSet, mSeq, 
-    mOrdinal, mInt, mInt8, mInt16, mInt32, mInt64, 
-    mFloat, mFloat32, mFloat64, mBool, mChar, mString, 
-    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
+    mConTT, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mInRange, 
+    mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mAssert, 
+    mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, mNewString, 
+    mArray, mOpenArray, mRange, mSet, mSeq, mOrdinal, 
+    mInt, mInt8, mInt16, mInt32, mInt64, mFloat, 
+    mFloat32, mFloat64, mBool, mChar, mString, 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]]]
   );
 
@@ -472,7 +475,7 @@ type
   end;
 
 const
-  OverloadableSyms = {@set}[skProc, skIterator, skConverter];
+  OverloadableSyms = {@set}[skProc, skMethod, skIterator, skConverter];
 
 const // "MagicToStr" array:
   MagicToStr: array [TMagic] of string = (
@@ -482,9 +485,9 @@ const // "MagicToStr" array:
     //  if (i+1) % 6 == 0: cog.outl("")
     //cog.outl("'%s'" % magics[-1])
     //]]]
-    'None', 'Defined', 'Low', 'High', 'SizeOf', 'Is', 
-    'Echo', 'Succ', 'Pred', 'Inc', 'Dec', 'Ord', 
-    'New', 'NewFinalize', 'NewSeq', 'RegisterFinalizer', 'LengthOpenArray', 'LengthStr', 
+    'None', 'Defined', 'DefinedInScope', 'Low', 'High', 'SizeOf', 
+    'Is', 'Echo', 'Succ', 'Pred', 'Inc', 'Dec', 
+    'Ord', 'New', 'NewFinalize', 'NewSeq', 'LengthOpenArray', 'LengthStr', 
     'LengthArray', 'LengthSeq', 'Incl', 'Excl', 'Card', 'Chr', 
     'GCref', 'GCunref', 'AddI', 'SubI', 'MulI', 'DivI', 
     'ModI', 'AddI64', 'SubI64', 'MulI64', 'DivI64', 'ModI64', 
@@ -506,21 +509,20 @@ const // "MagicToStr" array:
     'StrToStr', 'EnumToStr', 'And', 'Or', 'EqStr', 'LeStr', 
     'LtStr', 'EqSet', 'LeSet', 'LtSet', 'MulSet', 'PlusSet', 
     'MinusSet', 'SymDiffSet', 'ConStrStr', 'ConArrArr', 'ConArrT', 'ConTArr', 
-    'ConTT', 'Slice', 'AppendStrCh', 'AppendStrStr', 'AppendSeqElem', 'AppendSeqSeq', 
-    'InRange', 'InSet', 'Repr', 'Exit', 'SetLengthStr', 'SetLengthSeq', 
-    'Assert', 'Swap', 'IsNil', 'ArrToSeq', 'CopyStr', 'CopyStrLast', 
-    'NewString', 'Array', 'OpenArray', 'Range', 'Set', 'Seq', 
-    'Ordinal', 'Int', 'Int8', 'Int16', 'Int32', 'Int64', 
-    'Float', 'Float32', 'Float64', 'Bool', 'Char', 'String', 
-    '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'
+    'ConTT', 'Slice', 'AppendStrCh', 'AppendStrStr', 'AppendSeqElem', 'InRange', 
+    'InSet', 'Repr', 'Exit', 'SetLengthStr', 'SetLengthSeq', 'Assert', 
+    'Swap', 'IsNil', 'ArrToSeq', 'CopyStr', 'CopyStrLast', 'NewString', 
+    'Array', 'OpenArray', 'Range', 'Set', 'Seq', 'Ordinal', 
+    'Int', 'Int8', 'Int16', 'Int32', 'Int64', 'Float', 
+    'Float32', 'Float64', 'Bool', 'Char', 'String', '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]]]
   );
 
@@ -553,7 +555,7 @@ const
     tyFloat..tyFloat128
   ];
   ConstantDataTypes: TTypeKinds = {@set}[tyArray, tySet, tyTuple];
-  ExportableSymKinds = {@set}[skVar, skConst, skProc, skType,
+  ExportableSymKinds = {@set}[skVar, skConst, skProc, skMethod, skType,
                               skIterator, skMacro, skTemplate, skConverter,
                               skStub];
   PersistentNodeFlags: TNodeFlags = {@set}[
@@ -564,6 +566,7 @@ const
   pragmasPos = 3;
   codePos = 4;
   resultPos = 5;
+  dispatcherPos = 6;
 
 var
   gId: int;
diff --git a/nim/ccgexprs.pas b/nim/ccgexprs.pas
index 97a24caeb..99d36da2d 100755
--- a/nim/ccgexprs.pas
+++ b/nim/ccgexprs.pas
@@ -1285,14 +1285,14 @@ begin
   genAssignment(p, a, c, {@set}[]);
 end;
 
-procedure genIs(p: BProc; n: PNode; var d: TLoc);
+procedure genIs(p: BProc; x: PNode; typ: PType; var d: TLoc); overload;
 var
   a: TLoc;
   dest, t: PType;
   r, nilcheck: PRope;
 begin
-  initLocExpr(p, n.sons[1], a);
-  dest := skipTypes(n.sons[2].typ, abstractPtrs);
+  initLocExpr(p, x, a);
+  dest := skipTypes(typ, abstractPtrs);
   useMagic(p.module, 'isObj');
   r := rdLoc(a);
   nilCheck := nil;
@@ -1313,7 +1313,12 @@ begin
   else
     r := ropef('isObj($1.m_type, $2)',
       [r, genTypeInfo(p.module, dest)]);
-  putIntoDest(p, d, n.typ, r);
+  putIntoDest(p, d, getSysType(tyBool), r);
+end;
+
+procedure genIs(p: BProc; n: PNode; var d: TLoc); overload;
+begin
+  genIs(p, n.sons[1], n.sons[2].typ, d);
 end;
 
 procedure genNewFinalize(p: BProc; e: PNode);
@@ -1330,14 +1335,14 @@ begin
   // This is a little hack: 
   // XXX this is also a bug, if the finalizer expression produces side-effects
   oldModule := p.module;
-  p.module := gmti;
+  p.module := gNimDat;
   InitLocExpr(p, e.sons[2], f);
   p.module := oldModule;
   
   initLoc(b, locExpr, a.t, OnHeap);
   ti := genTypeInfo(p.module, refType);
   
-  appf(gmti.s[cfsTypeInit3], '$1->finalizer = (void*)$2;$n', [
+  appf(gNimDat.s[cfsTypeInit3], '$1->finalizer = (void*)$2;$n', [
     ti, rdLoc(f)]);
   b.r := ropef('($1) newObj($2, sizeof($3))',
            [getTypeDesc(p.module, refType), ti,
@@ -2164,6 +2169,16 @@ begin
     nkSym: begin
       sym := e.sym;
       case sym.Kind of
+        skMethod: begin
+          if sym.ast.sons[codePos] = nil then begin
+            // we cannot produce code for the dispatcher yet:
+            fillProcLoc(sym);
+            genProcPrototype(p.module, sym);
+          end
+          else
+            genProc(p.module, sym);
+          putLocIntoDest(p, d, sym.loc);
+        end;
         skProc, skConverter: begin
           genProc(p.module, sym);
           if ((sym.loc.r = nil) or (sym.loc.t = nil)) then
diff --git a/nim/ccgstmts.pas b/nim/ccgstmts.pas
index 03d6edb01..97641f0c8 100755
--- a/nim/ccgstmts.pas
+++ b/nim/ccgstmts.pas
@@ -326,7 +326,7 @@ begin
       nkStrLit..nkTripleStrLit: app(s, t.sons[i].strVal);
       nkSym: begin
         sym := t.sons[i].sym;
-        if sym.kind = skProc then begin
+        if sym.kind in [skProc, skMethod] then begin
           initLocExpr(p, t.sons[i], a);
           app(s, rdLoc(a));
         end
@@ -970,12 +970,13 @@ begin
     nkCommentStmt, nkNilLit, nkIteratorDef, nkIncludeStmt, nkImportStmt,
     nkFromStmt, nkTemplateDef, nkMacroDef: begin end;
     nkPragma: genPragma(p, t);
-    nkProcDef, nkConverterDef: begin
+    nkProcDef, nkMethodDef, nkConverterDef: begin
       if (t.sons[genericParamsPos] = nil) then begin
         prc := t.sons[namePos].sym;
         if not (optDeadCodeElim in gGlobalOptions) and
             not (sfDeadCodeElim in getModule(prc).flags)
-        or ([sfExportc, sfCompilerProc] * prc.flags = [sfExportc]) then begin
+        or ([sfExportc, sfCompilerProc] * prc.flags = [sfExportc])
+        or (prc.kind = skMethod) then begin
           if (t.sons[codePos] <> nil) or (lfDynamicLib in prc.loc.flags) then begin
             genProc(p.module, prc)
           end
diff --git a/nim/ccgtypes.pas b/nim/ccgtypes.pas
index 8c17514ff..db07a6864 100755
--- a/nim/ccgtypes.pas
+++ b/nim/ccgtypes.pas
@@ -47,7 +47,7 @@ begin
   if result = nil then begin
     if gCmd = cmdCompileToLLVM then begin
       case s.kind of
-        skProc, skConverter, skConst: result := toRope('@'+'');
+        skProc, skMethod, skConverter, skConst: result := toRope('@'+'');
         skVar: begin
           if (sfGlobal in s.flags) then result := toRope('@'+'')
           else result := toRope('%'+'');
@@ -1026,15 +1026,15 @@ begin
     tyEmpty: result := toRope('0'+'');
     tyPointer, tyProc, tyBool, tyChar, tyCString, tyString,
     tyInt..tyFloat128, tyVar:
-      genTypeInfoAuxBase(gmti, t, result, toRope('0'+''));
-    tyRef, tyPtr, tySequence, tyRange: genTypeInfoAux(gmti, t, result);
-    tyArrayConstr, tyArray: genArrayInfo(gmti, t, result);
-    tySet: genSetInfo(gmti, t, result);
-    tyEnum: genEnumInfo(gmti, t, result);
-    tyObject: genObjectInfo(gmti, t, result);
+      genTypeInfoAuxBase(gNimDat, t, result, toRope('0'+''));
+    tyRef, tyPtr, tySequence, tyRange: genTypeInfoAux(gNimDat, t, result);
+    tyArrayConstr, tyArray: genArrayInfo(gNimDat, t, result);
+    tySet: genSetInfo(gNimDat, t, result);
+    tyEnum: genEnumInfo(gNimDat, t, result);
+    tyObject: genObjectInfo(gNimDat, t, result);
     tyTuple: begin
-      if t.n <> nil then genObjectInfo(gmti, t, result)
-      else genTupleInfo(gmti, t, result);
+      if t.n <> nil then genObjectInfo(gNimDat, t, result)
+      else genTupleInfo(gNimDat, t, result);
     end;
     else InternalError('genTypeInfo(' + typekindToStr[t.kind] + ')');
   end
diff --git a/nim/cgen.pas b/nim/cgen.pas
index 04c19d444..17ae8b461 100755
--- a/nim/cgen.pas
+++ b/nim/cgen.pas
@@ -19,7 +19,7 @@ uses
   nsystem, ast, astalgo, strutils, nhashes, trees, platform, magicsys,
   extccomp, options, nversion, nimsets, msgs, crc, bitsets, idents,
   lists, types, ccgutils, nos, ntime, ropes, nmath, passes, rodread,
-  wordrecg, rnimsyn, treetab;
+  wordrecg, rnimsyn, treetab, cgmeth;
   
 function cgenPass(): TPass;
 
@@ -131,7 +131,7 @@ var
   gPendingModules: array of BModule = {@ignore} nil {@emit @[]};
     // list of modules that are not finished with code generation
   gForwardedProcsCounter: int = 0;
-  gmti: BModule; // generated type info: no need to initialize: defaults fit
+  gNimDat: BModule; // generated global data
 
 function ropeff(const cformat, llvmformat: string; 
                 const args: array of PRope): PRope;
@@ -557,7 +557,7 @@ begin
   sym := magicsys.getCompilerProc(name);
   if sym <> nil then 
     case sym.kind of
-      skProc, skConverter: genProc(m, sym);
+      skProc, skMethod, skConverter: genProc(m, sym);
       skVar: genVarPrototype(m, sym);
       skType: {@discard} getTypeDesc(m, sym.typ);
       else InternalError('useMagic: ' + name)
@@ -730,6 +730,7 @@ begin
     app(generatedProc, '}' + tnl);
   end;
   app(m.s[cfsProcs], generatedProc);
+  //if prc.kind = skMethod then addMethodToCompile(gNimDat, prc);
 end;
 
 procedure genProcPrototype(m: BModule; sym: PSym);
@@ -746,8 +747,9 @@ begin
     end
   end
   else begin
-    if not IntSetContainsOrIncl(m.declaredProtos, sym.id) then
+    if not IntSetContainsOrIncl(m.declaredProtos, sym.id) then begin
       appf(m.s[cfsProcHeaders], '$1;$n', [genProcHeader(m, sym)]);
+    end
   end
 end;
 
@@ -836,18 +838,18 @@ function getFileHeader(const cfilenoext: string): PRope;
 begin
   if optCompileOnly in gGlobalOptions then
     result := ropeff(
-      '/* Generated by the Nimrod Compiler v$1 */$n' +
+      '/* Generated by Nimrod Compiler v$1 */$n' +
       '/*   (c) 2009 Andreas Rumpf */$n',
-      '; Generated by the Nimrod Compiler v$1$n' +
+      '; Generated by Nimrod Compiler v$1$n' +
       ';   (c) 2009 Andreas Rumpf$n',
       [toRope(versionAsString)])
   else
     result := ropeff(
-      '/* Generated by the Nimrod Compiler v$1 */$n' +
+      '/* Generated by Nimrod Compiler v$1 */$n' +
       '/*   (c) 2009 Andreas Rumpf */$n' +
       '/* Compiled for: $2, $3, $4 */$n' +
       '/* Command for C compiler:$n   $5 */$n',
-      '; Generated by the Nimrod Compiler v$1$n' +
+      '; Generated by Nimrod Compiler v$1$n' +
       ';   (c) 2009 Andreas Rumpf$n' +
       '; Compiled for: $2, $3, $4$n' +
       '; Command for LLVM compiler:$n   $5$n',
@@ -1115,15 +1117,15 @@ var
   s: PSym;
 begin
   s := NewSym(skModule, getIdent(moduleName), nil);
-  gmti := rawNewModule(s, joinPath(options.projectPath, moduleName)+'.nim');
-  addPendingModule(gmti);
+  gNimDat := rawNewModule(s, joinPath(options.projectPath, moduleName)+'.nim');
+  addPendingModule(gNimDat);
   appff(mainModProcs, 'N_NOINLINE(void, $1)(void);$n',
                       'declare void $1() noinline$n', [getInitName(s)]);
 end;
 
 function myOpen(module: PSym; const filename: string): PPassContext;
 begin
-  if gmti = nil then registerTypeInfoModule();
+  if gNimDat = nil then registerTypeInfoModule();
   result := newModule(module, filename);
 end;
 
@@ -1132,7 +1134,7 @@ function myOpenCached(module: PSym; const filename: string;
 var
   cfile, cfilenoext, objFile: string;
 begin
-  if gmti = nil then registerTypeInfoModule();
+  if gNimDat = nil then registerTypeInfoModule();
   //MessageOut('cgen.myOpenCached has been called ' + filename);
   cfile := changeFileExt(completeCFilePath(filename), cExt);
   cfilenoext := changeFileExt(cfile, '');
@@ -1177,7 +1179,7 @@ begin
   i := 0;
   while i <= high(m.forwardedProcs) do begin
     // Note: ``genProc`` may add to ``m.forwardedProcs``, so we cannot use
-    // a for loop here
+    // a ``for`` loop here
     prc := m.forwardedProcs[i];
     if sfForward in prc.flags then InternalError(prc.info, 'still forwarded');
     genProcNoForward(m, prc);
@@ -1214,6 +1216,7 @@ function myClose(b: PPassContext; n: PNode): PNode;
 var
   m: BModule;
   i: int;
+  disp: PNode;
 begin
   result := n;
   if b = nil then exit;
@@ -1227,6 +1230,8 @@ begin
       not (sfDeadCodeElim in m.module.flags) then
     finishModule(m);
   if sfMainModule in m.module.flags then begin
+    disp := generateMethodDispatchers();
+    for i := 0 to sonsLen(disp)-1 do genProcAux(gNimDat, disp.sons[i].sym);
     genMainProc(m);
     // we need to process the transitive closure because recursive module
     // deps are allowed (and the system module is processed in the wrong
@@ -1241,7 +1246,7 @@ begin
       not (sfDeadCodeElim in m.module.flags) then
     writeModule(m);
   if sfMainModule in m.module.flags then 
-    writeMapping(gMapping);  
+    writeMapping(gMapping);
 end;
 
 function cgenPass(): TPass;
diff --git a/nim/cgmeth.pas b/nim/cgmeth.pas
new file mode 100644
index 000000000..6b9335c4c
--- /dev/null
+++ b/nim/cgmeth.pas
@@ -0,0 +1,269 @@
+//
+//
+//           The Nimrod Compiler
+//        (c) Copyright 2009 Andreas Rumpf
+//
+//    See the file "copying.txt", included in this
+//    distribution, for details about the copyright.
+//
+
+unit cgmeth;
+
+// This module implements code generation for multi methods.
+  
+interface
+
+{$include 'config.inc'}
+
+uses
+  sysutils, nsystem, 
+  options, ast, astalgo, msgs, idents, rnimsyn, types, magicsys;
+
+procedure methodDef(s: PSym);
+function methodCall(n: PNode): PNode;
+function generateMethodDispatchers(): PNode;
+
+implementation
+
+const
+  skipPtrs = {@set}[tyVar, tyPtr, tyRef, tyGenericInst];
+
+function genConv(n: PNode; d: PType; downcast: bool): PNode;
+var
+  dest, source: PType;
+  diff: int;
+begin
+  dest := skipTypes(d, abstractPtrs);
+  source := skipTypes(n.typ, abstractPtrs);
+  if (source.kind = tyObject) and (dest.kind = tyObject) then begin
+    diff := inheritanceDiff(dest, source);
+    if diff = high(int) then InternalError(n.info, 'cgmeth.genConv');
+    if diff < 0 then begin
+      result := newNodeIT(nkObjUpConv, n.info, d);
+      addSon(result, n);
+      if downCast then
+        InternalError(n.info, 'cgmeth.genConv: no upcast allowed');
+    end
+    else if diff > 0 then begin
+      result := newNodeIT(nkObjDownConv, n.info, d);
+      addSon(result, n);
+      if not downCast then
+        InternalError(n.info, 'cgmeth.genConv: no downcast allowed');
+    end
+    else result := n
+  end
+  else result := n
+end;
+
+function methodCall(n: PNode): PNode;
+var
+  disp: PSym;
+  i: int;
+begin
+  result := n;
+  disp := lastSon(result.sons[0].sym.ast).sym;
+  result.sons[0].sym := disp;
+  for i := 1 to sonsLen(result)-1 do
+    result.sons[i] := genConv(result.sons[i], disp.typ.sons[i], true)
+end;
+
+var
+  gMethods: array of TSymSeq;
+
+function sameMethodBucket(a, b: PSym): bool;
+var
+  i: int;
+  aa, bb: PType;
+begin
+  result := false;
+  if a.name.id <> b.name.id then exit;
+  if sonsLen(a.typ) <> sonsLen(b.typ) then exit;
+  // check for return type:
+  if not sameTypeOrNil(a.typ.sons[0], b.typ.sons[0]) then exit;
+  for i := 1 to sonsLen(a.typ)-1 do begin
+    aa := a.typ.sons[i];
+    bb := b.typ.sons[i];
+    while true do begin
+      aa := skipTypes(aa, {@set}[tyGenericInst]);
+      bb := skipTypes(bb, {@set}[tyGenericInst]);
+      if (aa.kind = bb.kind) and (aa.kind in [tyVar, tyPtr, tyRef]) then begin
+        aa := aa.sons[0];
+        bb := bb.sons[0];
+      end
+      else
+        break
+    end;
+    if sameType(aa, bb)
+    or (aa.kind = tyObject) and (bb.kind = tyObject)
+        and (inheritanceDiff(bb, aa) < 0) then begin end
+    else exit;
+  end;
+  result := true
+end;
+
+procedure methodDef(s: PSym);
+var
+  i, L, q: int;
+  disp: PSym;
+begin 
+  L := length(gMethods);
+  for i := 0 to L-1 do begin
+    if sameMethodBucket(gMethods[i][0], s) then begin
+    {@ignore}
+      q := length(gMethods[i]);
+      setLength(gMethods[i], q+1);
+      gMethods[i][q] := s;
+    {@emit
+      add(gMethods[i], s);
+    }
+      // store a symbol to the dispatcher:
+      addSon(s.ast, lastSon(gMethods[i][0].ast));
+      exit
+    end
+  end;
+{@ignore}
+  setLength(gMethods, L+1);
+  setLength(gMethods[L], 1);
+  gMethods[L][0] := s;
+{@emit
+  add(gMethods, @[s]);
+}
+  // create a new dispatcher:
+  disp := copySym(s);
+  disp.typ := copyType(disp.typ, disp.typ.owner, false);
+  if disp.typ.callConv = ccInline then disp.typ.callConv := ccDefault;
+  disp.ast := copyTree(s.ast);
+  disp.ast.sons[codePos] := nil;
+  if s.typ.sons[0] <> nil then
+    disp.ast.sons[resultPos].sym := copySym(s.ast.sons[resultPos].sym);
+  addSon(s.ast, newSymNode(disp));
+end;
+
+function relevantCol(methods: TSymSeq; col: int): bool;
+var
+  t: PType;
+  i: int;
+begin
+  // returns true iff the position is relevant
+  t := methods[0].typ.sons[col];
+  result := false;
+  if skipTypes(t, skipPtrs).kind = tyObject then 
+    for i := 1 to high(methods) do
+      if not SameType(methods[i].typ.sons[col], t) then begin
+        result := true; exit
+      end
+end;
+
+function cmpSignatures(a, b: PSym; const relevantCols: TIntSet): int;
+var
+  col, d: int;
+  aa, bb: PType;
+begin
+  result := 0;
+  for col := 1 to sonsLen(a.typ)-1 do
+    if intSetContains(relevantCols, col) then begin
+      aa := skipTypes(a.typ.sons[col], skipPtrs);
+      bb := skipTypes(b.typ.sons[col], skipPtrs);
+      d := inheritanceDiff(aa, bb);
+      if (d <> high(int)) then begin
+        result := d; exit
+      end
+    end
+end;
+
+procedure sortBucket(var a: TSymSeq; const relevantCols: TIntSet);
+// we use shellsort here; fast and simple
+var
+  N, i, j, h: int;
+  v: PSym;
+begin
+  N := length(a);
+  h := 1; repeat h := 3*h+1; until h > N;
+  repeat
+    h := h div 3;
+    for i := h to N-1 do begin
+      v := a[i]; j := i;
+      while cmpSignatures(a[j-h], v, relevantCols) >= 0 do begin
+        a[j] := a[j-h]; j := j - h;
+        if j < h then break
+      end;
+      a[j] := v;
+    end;
+  until h = 1
+end;
+
+function genDispatcher(methods: TSymSeq; const relevantCols: TIntSet): PSym;
+var
+  disp, cond, call, ret, a, isn: PNode;
+  base, curr, ands, iss: PSym;
+  meth, col, paramLen: int;
+begin
+  base := lastSon(methods[0].ast).sym;
+  result := base;
+  paramLen := sonsLen(base.typ);
+  disp := newNodeI(nkIfStmt, base.info);
+  ands := getSysSym('and');
+  iss := getSysSym('is');
+  for meth := 0 to high(methods) do begin
+    curr := methods[meth];
+    // generate condition:
+    cond := nil;
+    for col := 1 to paramLen-1 do begin
+      if IntSetContains(relevantCols, col) then begin
+        isn := newNodeIT(nkCall, base.info, getSysType(tyBool));
+        addSon(isn, newSymNode(iss));
+        addSon(isn, newSymNode(base.typ.n.sons[col].sym));
+        addSon(isn, newNodeIT(nkType, base.info, curr.typ.sons[col]));
+        if cond <> nil then begin
+          a := newNodeIT(nkCall, base.info, getSysType(tyBool));
+          addSon(a, newSymNode(ands));
+          addSon(a, cond);
+          addSon(a, isn);
+          cond := a
+        end
+        else
+          cond := isn
+      end
+    end;
+    // generate action:
+    call := newNodeI(nkCall, base.info);
+    addSon(call, newSymNode(curr));
+    for col := 1 to paramLen-1 do begin
+      addSon(call, genConv(newSymNode(base.typ.n.sons[col].sym),
+                           curr.typ.sons[col], false));
+    end;
+    if base.typ.sons[0] <> nil then begin
+      a := newNodeI(nkAsgn, base.info);
+      addSon(a, newSymNode(base.ast.sons[resultPos].sym));
+      addSon(a, call);
+      ret := newNodeI(nkReturnStmt, base.info);
+      addSon(ret, a);
+    end
+    else
+      ret := call;
+    a := newNodeI(nkElifBranch, base.info);
+    addSon(a, cond);
+    addSon(a, ret);
+    addSon(disp, a);
+  end;
+  result.ast.sons[codePos] := disp;
+end;
+
+function generateMethodDispatchers(): PNode;
+var
+  bucket, col: int;
+  relevantCols: TIntSet;
+begin
+  result := newNode(nkStmtList);
+  for bucket := 0 to length(gMethods)-1 do begin
+    IntSetInit(relevantCols);
+    for col := 1 to sonsLen(gMethods[bucket][0].typ)-1 do
+      if relevantCol(gMethods[bucket], col) then IntSetIncl(relevantCols, col);
+    sortBucket(gMethods[bucket], relevantCols);
+    addSon(result, newSymNode(genDispatcher(gMethods[bucket], relevantCols)));
+  end
+end;
+
+initialization
+  {@emit gMethods := @[]; }
+end.
diff --git a/nim/docgen.pas b/nim/docgen.pas
index 39a9069c7..4d94a2a68 100755
--- a/nim/docgen.pas
+++ b/nim/docgen.pas
@@ -1036,6 +1036,7 @@ begin
   case n.kind of
     nkCommentStmt:  app(d.modDesc, genComment(d, n));
     nkProcDef:      genItem(d, n, n.sons[namePos], skProc);
+    nkMethodDef:    genItem(d, n, n.sons[namePos], skMethod);
     nkIteratorDef:  genItem(d, n, n.sons[namePos], skIterator);
     nkMacroDef:     genItem(d, n, n.sons[namePos], skMacro);
     nkTemplateDef:  genItem(d, n, n.sons[namePos], skTemplate);
diff --git a/nim/ecmasgen.pas b/nim/ecmasgen.pas
index 73faa4ddb..8edd2605a 100755
--- a/nim/ecmasgen.pas
+++ b/nim/ecmasgen.pas
@@ -1717,7 +1717,7 @@ begin
     nkTypeSection, nkCommentStmt, nkIteratorDef,
     nkIncludeStmt, nkImportStmt,
     nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: begin end;
-    nkProcDef, nkConverterDef: begin
+    nkProcDef, nkMethodDef, nkConverterDef: begin
       if (n.sons[genericParamsPos] = nil) then begin
         prc := n.sons[namePos].sym;
         if (n.sons[codePos] <> nil) and not (lfNoDecl in prc.loc.flags) then
diff --git a/nim/evals.pas b/nim/evals.pas
index b88fa3304..3787ff371 100755
--- a/nim/evals.pas
+++ b/nim/evals.pas
@@ -938,23 +938,6 @@ begin
   result := emptyNode;
 end;
 
-function evalAppendSeqSeq(c: PEvalContext; n: PNode): PNode;
-var
-  a, b: PNode;
-  i: int;
-begin
-  result := evalAux(c, n.sons[1]);
-  if result.kind = nkExceptBranch then exit;
-  a := result;
-  result := evalAux(c, n.sons[2]);
-  if result.kind = nkExceptBranch then exit;
-  b := result;
-  if a.kind = nkBracket then
-    for i := 0 to sonsLen(b)-1 do addSon(a, copyTree(b.sons[i]))
-  else InternalError(n.info, 'evalAppendSeqSeq');
-  result := emptyNode;
-end;
-
 function evalRepr(c: PEvalContext; n: PNode): PNode;
 begin
   result := evalAux(c, n.sons[1]);
@@ -993,7 +976,6 @@ begin
     mAppendStrCh: result := evalAppendStrCh(c, n);
     mAppendStrStr: result := evalAppendStrStr(c, n);
     mAppendSeqElem: result := evalAppendSeqElem(c, n);
-    mAppendSeqSeq: result := evalAppendSeqSeq(c, n);
 
     mNLen: begin
       result := evalAux(c, n.sons[1]);
@@ -1338,7 +1320,7 @@ begin
         end
       end
     end;
-    nkProcDef, nkMacroDef, nkCommentStmt, nkPragma, nkTypeSection,
+    nkProcDef, nkMethodDef, nkMacroDef, nkCommentStmt, nkPragma, nkTypeSection,
     nkTemplateDef, nkConstSection, nkIteratorDef, nkConverterDef,
     nkIncludeStmt, nkImportStmt, nkFromStmt: begin end;
     nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr,
diff --git a/nim/highlite.pas b/nim/highlite.pas
index ec5374663..fa760d2a2 100755
--- a/nim/highlite.pas
+++ b/nim/highlite.pas
@@ -264,18 +264,37 @@ begin
         while not (g.buf[pos] in [#0, #10, #13]) do inc(pos);
       end;
       'a'..'z', 'A'..'Z', '_', #128..#255: begin
-        if (g.buf[pos+1] = '"') and (g.buf[pos] in ['r', 'R']) then begin
-          g.kind := gtRawData;
-          inc(pos, 2);
-          while not (g.buf[pos] in [#0, '"', #10, #13]) do inc(pos);
-          if g.buf[pos] = '"' then inc(pos);
+        id := '';
+        while g.buf[pos] in scanner.SymChars+['_'] do begin
+          addChar(id, g.buf[pos]);
+          inc(pos)
+        end;
+        if (g.buf[pos] = '"') then begin
+          if (g.buf[pos+1] = '"') and (g.buf[pos+2] = '"') then begin
+            inc(pos, 3);
+            g.kind := gtLongStringLit;
+            while true do begin
+              case g.buf[pos] of
+                #0: break;
+                '"': begin
+                  inc(pos);
+                  if (g.buf[pos] = '"') and (g.buf[pos+1] = '"') then begin
+                    inc(pos, 2);
+                    break
+                  end
+                end;
+                else inc(pos);
+              end
+            end
+          end
+          else begin
+            g.kind := gtRawData;
+            inc(pos);
+            while not (g.buf[pos] in [#0, '"', #10, #13]) do inc(pos);
+            if g.buf[pos] = '"' then inc(pos);
+          end
         end
         else begin
-          id := '';
-          while g.buf[pos] in scanner.SymChars+['_'] do begin
-            addChar(id, g.buf[pos]);
-            inc(pos)
-          end;
           g.kind := nimGetKeyword(id);
         end
       end;
diff --git a/nim/importer.pas b/nim/importer.pas
index fdb72fd4b..d031ffe3a 100755
--- a/nim/importer.pas
+++ b/nim/importer.pas
@@ -113,7 +113,7 @@ begin
     InternalError(ident.info, 'importSymbol: 2');
   // for an enumeration we have to add all identifiers
   case s.Kind of
-    skProc, skIterator, skMacro, skTemplate, skConverter: begin
+    skProc, skMethod, skIterator, skMacro, skTemplate, skConverter: begin
       // for a overloadable syms add all overloaded routines
       e := InitIdentIter(it, fromMod.tab, s.name);
       while e <> nil do begin
@@ -155,6 +155,8 @@ begin
   for i := 0 to sonsLen(n)-1 do begin
     f := getModuleFile(n.sons[i]);
     m := gImportModule(f);
+    if sfDeprecated in m.flags then
+      liMessage(n.sons[i].info, warnDeprecated, m.name.s);
     // ``addDecl`` needs to be done before ``importAllSymbols``!
     addDecl(c, m); // add symbol to symbol table of module
     importAllSymbols(c, m);
diff --git a/nim/lookups.pas b/nim/lookups.pas
index 5caceaf46..d68095635 100755
--- a/nim/lookups.pas
+++ b/nim/lookups.pas
@@ -54,7 +54,7 @@ implementation
 function getSymRepr(s: PSym): string;
 begin
   case s.kind of
-    skProc, skConverter, skIterator: result := getProcHeader(s);
+    skProc, skMethod, skConverter, skIterator: result := getProcHeader(s);
     else result := s.name.s
   end
 end;
@@ -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, skUnknown]) then
+      if not (s.kind in [skForVar, skParam, skMethod, skUnknown]) then
         liMessage(s.info, hintXDeclaredButNotUsed, getSymRepr(s));
     s := NextIter(it, tab.stack[tab.tos-1]);
   end;
diff --git a/nim/magicsys.pas b/nim/magicsys.pas
index d9dde8871..f4e4beafe 100755
--- a/nim/magicsys.pas
+++ b/nim/magicsys.pas
@@ -30,6 +30,8 @@ procedure registerCompilerProc(s: PSym);
 procedure InitSystem(var tab: TSymTab);
 procedure FinishSystem(const tab: TStrTable);
 
+function getSysSym(const name: string): PSym;
+
 implementation
 
 var
@@ -48,14 +50,16 @@ begin
   result.align := size;
 end;
 
+function getSysSym(const name: string): PSym;
+begin
+  result := StrTableGet(systemModule.tab, getIdent(name));
+  if result = nil then rawMessage(errSystemNeeds, name);
+  if result.kind = skStub then loadStub(result); 
+end;
+
 function sysTypeFromName(const name: string): PType;
-var
-  s: PSym;
 begin
-  s := StrTableGet(systemModule.tab, getIdent(name));
-  if s = nil then rawMessage(errSystemNeeds, name);
-  if s.kind = skStub then loadStub(s); 
-  result := s.typ;
+  result := getSysSym(name).typ;
 end;
 
 function getSysType(const kind: TTypeKind): PType;
diff --git a/nim/nhashes.pas b/nim/nhashes.pas
index 0564f6f47..95bfd62f5 100755
--- a/nim/nhashes.pas
+++ b/nim/nhashes.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/nversion.pas b/nim/nversion.pas
index add85acd1..b2ba371f6 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.8.0';
+  VersionAsString = '0.8.1';
   VersionMajor = 0;
   VersionMinor = 8;
-  VersionPatch = 0;
+  VersionPatch = 1;
   //[[[[end]]]]

 

 implementation

diff --git a/nim/pasparse.pas b/nim/pasparse.pas
index 8a73feca5..c44c735d6 100755
--- a/nim/pasparse.pas
+++ b/nim/pasparse.pas
@@ -61,7 +61,7 @@ const
     ('len',          'length'),
     ('setlength',    'setlen')
   );
-  nimReplacements: array [1..32] of TReplaceTuple = (
+  nimReplacements: array [1..34] of TReplaceTuple = (
     ('nimread',      'read'),
     ('nimwrite',     'write'),
     ('nimclosefile', 'close'),
@@ -96,7 +96,10 @@ const
     ('snil', 'nil'),
     ('tostringf', '$'+''),
     ('ttextfile', 'tfile'),
-    ('tbinaryfile', 'tfile') {,
+    ('tbinaryfile', 'tfile'),
+    ('strstart', '0'+''),
+    ('nl', '"\n"')
+    {,
     ('NL', '"\n"'),
     ('tabulator', '''\t'''),
     ('esc', '''\e'''),
diff --git a/nim/passaux.pas b/nim/passaux.pas
index 8b052257f..7898d8278 100755
--- a/nim/passaux.pas
+++ b/nim/passaux.pas
@@ -56,7 +56,7 @@ begin
     nkStmtList: begin
       for i := 0 to sonsLen(n)-1 do {@discard} cleanup(c, n.sons[i]);
     end;
-    nkProcDef: begin
+    nkProcDef, nkMethodDef: begin
       if (n.sons[namePos].kind = nkSym) then begin
         s := n.sons[namePos].sym;
         if not (sfDeadCodeElim in getModule(s).flags) and
diff --git a/nim/passes.pas b/nim/passes.pas
index f5dff3559..8d961e5d3 100755
--- a/nim/passes.pas
+++ b/nim/passes.pas
@@ -67,7 +67,7 @@ implementation
 
 function astNeeded(s: PSym): bool;
 begin
-  if (s.kind = skProc)
+  if (s.kind in [skMethod, skProc])
   and ([sfCompilerProc, sfCompileTime] * s.flags = [])
   and (s.typ.callConv <> ccInline)
   and (s.ast.sons[genericParamsPos] = nil) then
diff --git a/nim/pnimsyn.pas b/nim/pnimsyn.pas
index dae7de539..724a85a38 100755
--- a/nim/pnimsyn.pas
+++ b/nim/pnimsyn.pas
@@ -889,7 +889,7 @@ end;
 
 function parseImportStmt(var p: TParser): PNode;
 var
-  a, b: PNode;
+  a: PNode;
 begin
   result := newNodeP(nkImportStmt, p);
   getTok(p); // skip `import`
@@ -1535,9 +1535,9 @@ begin
   end
 end;
 
-function parseRecordPart(var p: TParser): PNode; forward;
+function parseObjectPart(var p: TParser): PNode; forward;
 
-function parseRecordWhen(var p: TParser): PNode;
+function parseObjectWhen(var p: TParser): PNode;
 var
   branch: PNode;
 begin
@@ -1549,7 +1549,7 @@ begin
     addSon(branch, parseExpr(p));
     eat(p, tkColon);
     skipComment(p, branch);
-    addSon(branch, parseRecordPart(p));
+    addSon(branch, parseObjectPart(p));
     skipComment(p, branch);
     addSon(result, branch);
     if p.tok.tokType <> tkElif then break
@@ -1558,12 +1558,12 @@ begin
     branch := newNodeP(nkElse, p);
     eat(p, tkElse); eat(p, tkColon);
     skipComment(p, branch);
-    addSon(branch, parseRecordPart(p));
+    addSon(branch, parseObjectPart(p));
     addSon(result, branch);
   end
 end;
 
-function parseRecordCase(var p: TParser): PNode;
+function parseObjectCase(var p: TParser): PNode;
 var
   a, b: PNode;
 begin
@@ -1591,13 +1591,13 @@ begin
       else break;
     end;
     skipComment(p, b);
-    addSon(b, parseRecordPart(p));
+    addSon(b, parseObjectPart(p));
     addSon(result, b);
     if b.kind = nkElse then break;
   end
 end;
 
-function parseRecordPart(var p: TParser): PNode;
+function parseObjectPart(var p: TParser): PNode;
 begin
   case p.tok.tokType of
     tkInd: begin
@@ -1608,7 +1608,7 @@ begin
         case p.tok.tokType of
           tkSad: getTok(p);
           tkCase, tkWhen, tkSymbol, tkAccent, tkNil: begin
-            addSon(result, parseRecordPart(p));
+            addSon(result, parseObjectPart(p));
           end;
           tkDed: begin getTok(p); break end;
           tkEof: break;
@@ -1620,8 +1620,8 @@ begin
       end;
       popInd(p.lex^);
     end;
-    tkWhen: result := parseRecordWhen(p);
-    tkCase: result := parseRecordCase(p);
+    tkWhen: result := parseObjectWhen(p);
+    tkCase: result := parseObjectCase(p);
     tkSymbol, tkAccent: begin
       result := parseIdentColonEquals(p, {@set}[withPragma]);
       skipComment(p, result);
@@ -1634,11 +1634,11 @@ begin
   end
 end;
 
-function parseRecordOrObject(var p: TParser; kind: TNodeKind): PNode;
+function parseObject(var p: TParser): PNode;
 var
   a: PNode;
 begin
-  result := newNodeP(kind, p);
+  result := newNodeP(nkObjectTy, p);
   getTok(p);
   if p.tok.tokType = tkCurlyDotLe then addSon(result, parsePragma(p))
   else addSon(result, nil);
@@ -1646,14 +1646,11 @@ begin
     a := newNodeP(nkOfInherit, p);
     getTok(p);
     addSon(a, parseTypeDesc(p));
-    if kind = nkObjectTy then
-      addSon(result, a)
-    else
-      parMessage(p, errInheritanceOnlyWithNonFinalObjects);
+    addSon(result, a);
   end
   else addSon(result, nil);
   skipComment(p, result);
-  addSon(result, parseRecordPart(p));
+  addSon(result, parseObjectPart(p));
 end;
 
 function parseDistinct(var p: TParser): PNode;
@@ -1675,7 +1672,7 @@ begin
   if p.tok.tokType = tkEquals then begin
     getTok(p); optInd(p, result);
     case p.tok.tokType of
-      tkObject: a := parseRecordOrObject(p, nkObjectTy);
+      tkObject: a := parseObject(p);
       tkEnum: a := parseEnum(p);
       tkDistinct: a := parseDistinct(p);
       else a := parseTypeDesc(p);
@@ -1754,6 +1751,7 @@ begin
     tkBlock:     result := parseBlock(p);
     tkAsm:       result := parseAsm(p);
     tkProc:      result := parseRoutine(p, nkProcDef);
+    tkMethod:    result := parseRoutine(p, nkMethodDef);
     tkIterator:  result := parseRoutine(p, nkIteratorDef);
     tkMacro:     result := parseRoutine(p, nkMacroDef);
     tkTemplate:  result := parseRoutine(p, nkTemplateDef);
diff --git a/nim/pragmas.pas b/nim/pragmas.pas
index 5ec706f19..fc354cd2c 100755
--- a/nim/pragmas.pas
+++ b/nim/pragmas.pas
@@ -30,6 +30,7 @@ const
     wCppMethod, wDeprecated, wVarargs, wCompileTime, wMerge,
     wBorrow];
   converterPragmas = procPragmas;
+  methodPragmas = procPragmas;
   macroPragmas = {@set}[FirstCallConv..LastCallConv,
     wImportc, wExportc, wNodecl, wMagic, wNosideEffect,
     wCompilerProc, wDeprecated, wTypeCheck];
@@ -42,7 +43,7 @@ const
     wHint, wWarning, wError, wFatal, wDefine, wUndef,
     wCompile, wLink, wLinkSys, wPure,
     wPush, wPop, wBreakpoint, wCheckpoint,
-    wPassL, wPassC, wDeadCodeElim];
+    wPassL, wPassC, wDeadCodeElim, wDeprecated];
   lambdaPragmas = {@set}[FirstCallConv..LastCallConv,
     wImportc, wExportc, wNodecl, wNosideEffect, wSideEffect, 
     wNoreturn, wDynLib, wHeader, wPure, wDeprecated];
@@ -545,7 +546,8 @@ begin
           end;
           wDeprecated: begin
             noVal(it);
-            include(sym.flags, sfDeprecated);
+            if sym <> nil then include(sym.flags, sfDeprecated)
+            else include(c.module.flags, sfDeprecated);
           end;
           wVarargs: begin
             noVal(it);
diff --git a/nim/rnimsyn.pas b/nim/rnimsyn.pas
index b3271a3bb..1ad1c9408 100755
--- a/nim/rnimsyn.pas
+++ b/nim/rnimsyn.pas
@@ -1235,6 +1235,10 @@ begin
       putWithSpace(g, tkProc, 'proc');
       gproc(g, n);
     end;
+    nkMethodDef: begin
+      putWithSpace(g, tkMethod, 'method');
+      gproc(g, n);
+    end;
     nkIteratorDef: begin
       putWithSpace(g, tkIterator, 'iterator');
       gproc(g, n);
diff --git a/nim/rodwrite.pas b/nim/rodwrite.pas
index 72d5c893d..c71eda7e3 100755
--- a/nim/rodwrite.pas
+++ b/nim/rodwrite.pas
@@ -519,7 +519,7 @@ begin
       s := n.sons[namePos].sym;
       addInterfaceSym(w, s);    
     end; 
-    nkProcDef, nkIteratorDef, nkConverterDef: begin
+    nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef: begin
       s := n.sons[namePos].sym;
       if s = nil then InternalError(n.info, 'rodwrite.process');
       if (n.sons[codePos] <> nil) or (s.magic <> mNone)
diff --git a/nim/sem.pas b/nim/sem.pas
index 029ba869f..64cdbd436 100755
--- a/nim/sem.pas
+++ b/nim/sem.pas
@@ -56,6 +56,12 @@ begin
   result.info := n.info;
 end;
 
+procedure markUsed(n: PNode; s: PSym);
+begin
+  include(s.flags, sfUsed);
+  if sfDeprecated in s.flags then liMessage(n.info, warnDeprecated, s.name.s);  
+end;
+
 function semIdentVis(c: PContext; kind: TSymKind; n: PNode;
                      const allowed: TSymFlags): PSym; forward;
 // identifier with visability
@@ -130,7 +136,7 @@ var
   p: PEvalContext;
   s: PStackFrame;
 begin
-  include(sym.flags, sfUsed);
+  markUsed(n, sym);
   p := newEvalContext(c.module, '', false);
   s := newStackFrame();
   s.call := n;
@@ -179,7 +185,8 @@ begin
     it := c.generics.sons[i].sons[1];
     if it.kind <> nkSym then InternalError('addCodeForGenerics');
     prc := it.sym;
-    if (prc.kind in [skProc, skConverter]) and (prc.magic = mNone) then begin
+    if (prc.kind in [skProc, skMethod, skConverter])
+    and (prc.magic = mNone) then begin
       if (prc.ast = nil) or (prc.ast.sons[codePos] = nil) then 
         InternalError(prc.info, 'no code for ' + prc.name.s);
       addSon(n, prc.ast);
diff --git a/nim/semexprs.pas b/nim/semexprs.pas
index 2fd0d6843..43eb9ac6f 100755
--- a/nim/semexprs.pas
+++ b/nim/semexprs.pas
@@ -13,7 +13,7 @@
 function semTemplateExpr(c: PContext; n: PNode; s: PSym;
                          semCheck: bool = true): PNode;
 begin
-  include(s.flags, sfUsed);
+  markUsed(n, s);
   pushInfoContext(n.info);
   result := evalTemplate(c, n, s);
   if semCheck then
@@ -47,8 +47,6 @@ var
   diff: int;
 begin
   diff := inheritanceDiff(castDest, src);
-  //if diff = 0 then
-  //  liMessage(info, hintConvToBaseNotNeeded)
   if diff = high(int) then
     liMessage(info, errGenerated,
       format(MsgKindToString(errIllegalConvFromXtoY),
@@ -136,7 +134,7 @@ begin
   else begin
     for i := 0 to sonsLen(op)-1 do begin
       if sameType(result.typ, op.sons[i].typ) then begin
-        include(op.sons[i].sym.flags, sfUsed);
+        markUsed(n, op.sons[i].sym);
         result := op.sons[i]; exit
       end
     end;
@@ -453,8 +451,7 @@ const
   FakeVarParams = {@set}[mNew, mNewFinalize, mInc, ast.mDec, mIncl,
                          mExcl, mSetLengthStr, mSetLengthSeq,
                          mAppendStrCh, mAppendStrStr, mSwap,
-                         mAppendSeqElem, mAppendSeqSeq,
-                         mNewSeq];
+                         mAppendSeqElem, mNewSeq];
 var
   i: int;
   t: PType;
@@ -474,7 +471,7 @@ var
   callee: PSym;
 begin
   if not (efWantIterator in flags) then 
-    result := semDirectCall(c, n, {@set}[skProc, skConverter])
+    result := semDirectCall(c, n, {@set}[skProc, skMethod, skConverter])
   else
     result := semDirectCall(c, n, {@set}[skIterator]);
   if result <> nil then begin
@@ -586,17 +583,23 @@ begin
   result := n;
 end;
 
-function LookUpForDefined(c: PContext; n: PNode): PSym;
+function LookUpForDefined(c: PContext; n: PNode; onlyCurrentScope: bool): PSym;
 var
   m: PSym;
   ident: PIdent;
 begin
   case n.kind of
-    nkIdent: result := SymtabGet(c.Tab, n.ident); // no need for stub loading
+    nkIdent: begin
+      if onlyCurrentScope then
+        result := SymtabLocalGet(c.tab, n.ident)
+      else
+        result := SymtabGet(c.Tab, n.ident); // no need for stub loading
+    end;
     nkDotExpr, nkQualified: begin
-      checkSonsLen(n, 2);
       result := nil;
-      m := LookupForDefined(c, n.sons[0]);
+      if onlyCurrentScope then exit;
+      checkSonsLen(n, 2);
+      m := LookupForDefined(c, n.sons[0], onlyCurrentScope);
       if (m <> nil) and (m.kind = skModule) then begin
         if (n.sons[1].kind = nkIdent) then begin
           ident := n.sons[1].ident;
@@ -612,7 +615,7 @@ begin
     end;
     nkAccQuoted: begin
       checkSonsLen(n, 1);
-      result := lookupForDefined(c, n.sons[0]);
+      result := lookupForDefined(c, n.sons[0], onlyCurrentScope);
     end
     else begin
       liMessage(n.info, errIdentifierExpected, renderTree(n));
@@ -621,14 +624,14 @@ begin
   end
 end;
 
-function semDefined(c: PContext; n: PNode): PNode;
+function semDefined(c: PContext; n: PNode; onlyCurrentScope: bool): PNode;
 begin
   checkSonsLen(n, 2);
   result := newIntNode(nkIntLit, 0);
   // we replace this node by a 'true' or 'false' node
-  if LookUpForDefined(c, n.sons[1]) <> nil then
+  if LookUpForDefined(c, n.sons[1], onlyCurrentScope) <> nil then
     result.intVal := 1
-  else if (n.sons[1].kind = nkIdent)
+  else if not onlyCurrentScope and (n.sons[1].kind = nkIdent)
       and condsyms.isDefined(n.sons[1].ident) then
     result.intVal := 1;
   result.info := n.info;
@@ -647,8 +650,8 @@ function semMagic(c: PContext; n: PNode; s: PSym; flags: TExprFlags): PNode;
 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));
+    mDefined: result := semDefined(c, setMs(n, s), false);
+    mDefinedInScope: result := semDefined(c, setMs(n, s), true);
     mLow:     result := semLowHigh(c, setMs(n, s), mLow);
     mHigh:    result := semLowHigh(c, setMs(n, s), mHigh);
     mSizeOf:  result := semSizeof(c, setMs(n, s));
@@ -658,11 +661,6 @@ begin
   end;
 end;
 
-procedure checkDeprecated(n: PNode; s: PSym);
-begin
-  if sfDeprecated in s.flags then liMessage(n.info, warnDeprecated, s.name.s);  
-end;
-
 function isTypeExpr(n: PNode): bool;
 begin
   case n.kind of
@@ -795,7 +793,7 @@ begin
       result := newSymNode(f);
       result.info := n.info;
       result.typ := ty;
-      checkDeprecated(n, f);
+      markUsed(n, f);
     end
     else
       liMessage(n.sons[1].info, errEnumHasNoValueX, i.s);
@@ -823,7 +821,7 @@ begin
         n.sons[0] := makeDeref(n.sons[0]);
         n.sons[1] := newSymNode(f); // we now have the correct field
         n.typ := f.typ;
-        checkDeprecated(n, f);
+        markUsed(n, f);
         if check = nil then result := n
         else begin
           check.sons[0] := n;
@@ -841,7 +839,7 @@ begin
       n.sons[1] := newSymNode(f);
       n.typ := f.typ;
       result := n;
-      checkDeprecated(n, f);
+      markUsed(n, f);
       exit
     end
   end;
@@ -851,7 +849,7 @@ begin
   //if (f <> nil) and (f.kind = skStub) then loadStub(f);
   // ``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
+    // BUGFIX: do not check for (f.kind in [skProc, skMethod, skIterator]) here
     result := newNodeI(nkDotCall, n.info);
     // This special node kind is to merge with the call handler in `semExpr`.
     addSon(result, newIdentNode(i, n.info));
@@ -1145,7 +1143,6 @@ begin
     a := n.sons[0];
   s := qualifiedLookup(c, a, false);
   if (s <> nil) then begin
-    checkDeprecated(n, s);
     case s.kind of
       skMacro: result := semMacroExpr(c, n, s, semCheck);
       skTemplate: begin
@@ -1176,7 +1173,7 @@ begin
   if (s.kind = skType) and not (efAllowType in flags) then
     liMessage(n.info, errATypeHasNoValue);
   case s.kind of
-    skProc, skIterator, skConverter: begin
+    skProc, skMethod, skIterator, skConverter: begin
       if (s.magic <> mNone) then
         liMessage(n.info, errInvalidContextForBuiltinX, s.name.s);
       result := symChoice(c, n, s);
@@ -1194,7 +1191,7 @@ begin
         copy `x`'s AST into each context, so that the type fixup phase can
         deal with two different ``[]``.
       *)
-      include(s.flags, sfUsed);
+      markUsed(n, s);
       if s.typ.kind in ConstAbstractTypes then begin
         result := copyTree(s.ast);
         result.info := n.info;
@@ -1208,7 +1205,7 @@ begin
     skMacro: result := semMacroExpr(c, n, s);
     skTemplate: result := semTemplateExpr(c, n, s);
     skVar: begin
-      include(s.flags, sfUsed);
+      markUsed(n, s);
       // 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);
@@ -1219,12 +1216,11 @@ begin
       result := semExpr(c, s.ast);
     end
     else begin
-      include(s.flags, sfUsed);
+      markUsed(n, s);
       result := newSymNode(s);
       result.info := n.info;
     end
   end;
-  checkDeprecated(n, s);
 end;
 
 function semDotExpr(c: PContext; n: PNode; flags: TExprFlags): PNode;
@@ -1259,7 +1255,7 @@ begin
       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
+          (s.kind in [skProc, skMethod, skIterator, skConverter]) then
         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!
@@ -1296,18 +1292,16 @@ begin
       checkMinSonsLen(n, 1);
       s := qualifiedLookup(c, n.sons[0], false);
       if (s <> nil) then begin
-        checkDeprecated(n, s);
         case s.kind of
           skMacro: result := semMacroExpr(c, n, s);
           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
+          skProc, skMethod, skConverter, skIterator: begin
             if s.magic = mNone then result := semDirectOp(c, n, flags)
             else result := semMagic(c, n, s, flags);
           end;
@@ -1328,7 +1322,8 @@ begin
     nkBracketExpr: begin
       checkMinSonsLen(n, 1);
       s := qualifiedLookup(c, n.sons[0], false);
-      if (s <> nil) and (s.kind in [skProc, skConverter, skIterator]) then begin
+      if (s <> nil)
+      and (s.kind in [skProc, skMethod, skConverter, skIterator]) then begin
         // type parameters: partial generic specialization
         // XXX: too implement!
         internalError(n.info, 'explicit generic instantation not implemented');
diff --git a/nim/semfold.pas b/nim/semfold.pas
index acca84c71..791f39149 100755
--- a/nim/semfold.pas
+++ b/nim/semfold.pas
@@ -288,7 +288,7 @@ begin
       result.typ := n.typ;
     end;
     mNewString, mExit, mInc, ast.mDec, mEcho, mAssert, mSwap,
-    mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendSeqSeq,
+    mAppendStrCh, mAppendStrStr, mAppendSeqElem,
     mSetLengthStr, mSetLengthSeq, mNLen..mNError: begin end;
     else InternalError(a.info, 'evalOp(' +{&} magicToStr[m] +{&} ')');
   end
@@ -412,7 +412,7 @@ begin
           else            result := copyTree(s.ast); // BUGFIX
         end
       end
-      else if s.kind = skProc then // BUGFIX
+      else if s.kind in [skProc, skMethod] then // BUGFIX
         result := n
     end;
     nkCharLit..nkNilLit: result := copyNode(n);
diff --git a/nim/seminst.pas b/nim/seminst.pas
index 6a6f272de..ea8889007 100755
--- a/nim/seminst.pas
+++ b/nim/seminst.pas
@@ -182,7 +182,7 @@ begin
     addDecl(c, result);
     if n.sons[codePos] <> nil then begin
       c.p := newProcCon(result);
-      if result.kind in [skProc, skConverter] then begin
+      if result.kind in [skProc, skMethod, skConverter] then begin
         addResult(c, result.typ.sons[0], n.info);
         addResultNode(c, n);
       end;
diff --git a/nim/semstmts.pas b/nim/semstmts.pas
index efbee6da8..b4b72a25b 100755
--- a/nim/semstmts.pas
+++ b/nim/semstmts.pas
@@ -316,7 +316,7 @@ var
 begin
   result := n;
   checkSonsLen(n, 1);
-  if not (c.p.owner.kind in [skConverter, skProc, skMacro]) then
+  if not (c.p.owner.kind in [skConverter, skMethod, skProc, skMacro]) then
     liMessage(n.info, errXNotAllowedHere, '''return''');
   if (n.sons[0] <> nil) then begin
     n.sons[0] := SemExprWithType(c, n.sons[0]);
@@ -970,11 +970,20 @@ begin
   result := semProcAux(c, n, skProc, procPragmas);
 end;
 
+function semMethod(c: PContext; n: PNode): PNode;
+begin
+  if not isTopLevel(c) then
+    liMessage(n.info, errXOnlyAtModuleScope, 'method');
+  result := semProcAux(c, n, skMethod, methodPragmas);
+end;
+
 function semConverterDef(c: PContext; n: PNode): PNode;
 var
   t: PType;
   s: PSym;
 begin
+  if not isTopLevel(c) then
+    liMessage(n.info, errXOnlyAtModuleScope, 'converter');
   checkSonsLen(n, codePos+1);
   if n.sons[genericParamsPos] <> nil then
     liMessage(n.info, errNoGenericParamsAllowedForX, 'converter');
@@ -1080,6 +1089,7 @@ begin
     nkPragma: pragma(c, c.p.owner, n, stmtPragmas);
     nkIteratorDef: result := semIterator(c, n);
     nkProcDef: result := semProc(c, n);
+    nkMethodDef: result := semMethod(c, n);
     nkConverterDef: result := semConverterDef(c, n);
     nkMacroDef: result := semMacroDef(c, n);
     nkTemplateDef: result := semTemplateDef(c, n);
diff --git a/nim/semtempl.pas b/nim/semtempl.pas
index f4173d9ff..8e37a1ea3 100755
--- a/nim/semtempl.pas
+++ b/nim/semtempl.pas
@@ -94,7 +94,7 @@ begin
     if i < a then 
       arg := n.sons[i]
     else 
-      arg := copyTree(s.ast.sons[paramsPos].sons[i-1].sym.ast);
+      arg := copyTree(s.typ.n.sons[i].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:
@@ -132,7 +132,7 @@ begin
   if i <= 1 then begin
     result := newSymNode(s);
     result.info := n.info;
-    include(s.flags, sfUsed);
+    markUsed(n, s);
   end
   else begin
     // semantic checking requires a type; ``fitNode`` deals with it
diff --git a/nim/semtypes.pas b/nim/semtypes.pas
index 934196de4..c0b86be86 100755
--- a/nim/semtypes.pas
+++ b/nim/semtypes.pas
@@ -232,7 +232,7 @@ function semTypeIdent(c: PContext; n: PNode): PSym;
 begin
   result := qualifiedLookup(c, n, true);
   if (result <> nil) then begin
-    include(result.flags, sfUsed);
+    markUsed(n, result);
     if result.kind <> skType then liMessage(n.info, errTypeExpected);
   end
   else
@@ -792,7 +792,7 @@ begin
           assignType(prev, t);
           result := prev;
         end;
-        include(n.sym.flags, sfUsed); // BUGFIX
+        markUsed(n, n.sym);
       end
       else
         liMessage(n.info, errTypeExpected);
diff --git a/nim/sigmatch.pas b/nim/sigmatch.pas
index aa53a741c..45a29fc29 100755
--- a/nim/sigmatch.pas
+++ b/nim/sigmatch.pas
@@ -103,7 +103,7 @@ begin
   candidates := '';
   sym := initOverloadIter(o, c, n.sons[0]);
   while sym <> nil do begin
-    if sym.kind in [skProc, skIterator, skConverter] then begin
+    if sym.kind in [skProc, skMethod, skIterator, skConverter] then begin
       add(candidates, getProcHeader(sym));
       add(candidates, nl)
     end;
@@ -709,7 +709,7 @@ begin
     best := -1;
     for i := 0 to sonsLen(arg)-1 do begin
       // iterators are not first class yet, so ignore them
-      if arg.sons[i].sym.kind in {@set}[skProc, skConverter] then begin
+      if arg.sons[i].sym.kind in {@set}[skProc, skMethod, skConverter] then begin
         copyCandidate(z, m);
         r := typeRel(z.bindings, f, arg.sons[i].typ);
         if r <> isNone then begin
@@ -734,7 +734,7 @@ begin
     end
     else begin
       // only one valid interpretation found:
-      include(arg.sons[best].sym.flags, sfUsed);
+      markUsed(arg, arg.sons[best].sym);
       result := ParamTypesMatchAux(c, m, f, arg.sons[best].typ, arg.sons[best]);
     end
   end
@@ -884,6 +884,19 @@ begin
   end
 end;
 
+function sameMethodDispatcher(a, b: PSym): bool;
+var
+  aa, bb: PNode;
+begin
+  result := false;
+  if (a.kind = skMethod) and (b.kind = skMethod) then begin
+    aa := lastSon(a.ast);
+    bb := lastSon(b.ast);
+    if (aa.kind = nkSym) and (bb.kind = nkSym) and
+      (aa.sym = bb.sym) then result := true
+  end
+end;
+
 function semDirectCall(c: PContext; n: PNode; filter: TSymKinds): PNode;
 var
   sym: PSym;
@@ -923,7 +936,8 @@ begin
     // do not generate an error yet; the semantic checking will check for
     // an overloaded () operator
   end
-  else if (y.state = csMatch) and (cmpCandidates(x, y) = 0) then begin
+  else if (y.state = csMatch) and (cmpCandidates(x, y) = 0)
+  and not sameMethodDispatcher(x.calleeSym, y.calleeSym) then begin
     if x.state <> csMatch then
       InternalError(n.info, 'x.state is not csMatch');
     //writeMatches(x);
@@ -935,7 +949,7 @@ begin
   end
   else begin
     // only one valid interpretation found:
-    include(x.calleeSym.flags, sfUsed);
+    markUsed(n, x.calleeSym);
     if x.calleeSym.ast = nil then
       internalError(n.info, 'calleeSym.ast is nil'); // XXX: remove this check!
     if x.calleeSym.ast.sons[genericParamsPos] <> nil then begin
diff --git a/nim/transf.pas b/nim/transf.pas
index 79f65b754..15e885b40 100755
--- a/nim/transf.pas
+++ b/nim/transf.pas
@@ -15,7 +15,7 @@ unit transf;
 // * inlines constants
 // * performes contant folding
 // * introduces nkHiddenDeref, nkHiddenSubConv, etc.
-// * aggressive compile-time evaluation based on the side-effect analysis
+// * introduces method dispatchers
 
 interface
 
@@ -24,7 +24,7 @@ interface
 uses
   sysutils, nsystem, charsets, strutils,
   lists, options, ast, astalgo, trees, treetab, evals,
-  msgs, nos, idents, rnimsyn, types, passes, semfold, magicsys;
+  msgs, nos, idents, rnimsyn, types, passes, semfold, magicsys, cgmeth;
 
 const
   genPrefix = ':tmp'; // prefix for generated names
@@ -574,7 +574,7 @@ end;
 function getMagicOp(call: PNode): TMagic;
 begin
   if (call.sons[0].kind = nkSym)
-  and (call.sons[0].sym.kind in [skProc, skConverter]) then
+  and (call.sons[0].sym.kind in [skProc, skMethod, skConverter]) then
     result := call.sons[0].sym.magic
   else
     result := mNone
@@ -842,6 +842,11 @@ begin
     if sonsLen(result) = 2 then
       result := result.sons[1];
   end
+  else if (result.sons[0].kind = nkSym)
+  and (result.sons[0].sym.kind = skMethod) then begin
+    // use the dispatcher for the call:
+    result := methodCall(result);
+  end
   (*
   else if result.sons[0].kind = nkSym then begin
     // optimization still too aggressive
@@ -882,9 +887,12 @@ begin
     nkLambda: result := transformLambda(c, n);
     nkForStmt: result := transformFor(c, n);
     nkCaseStmt: result := transformCase(c, n);
-    nkProcDef, nkIteratorDef, nkMacroDef: begin
-      if n.sons[genericParamsPos] = nil then
+    nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef: begin
+      if n.sons[genericParamsPos] = nil then begin
         n.sons[codePos] := transform(c, n.sons[codePos]);
+        if n.kind = nkMethodDef then
+          methodDef(n.sons[namePos].sym);
+      end
     end;
     nkWhileStmt: begin
       if (sonsLen(n) <> 2) then InternalError(n.info, 'transform');