diff options
author | Andreas Rumpf <andreasrumpf@noname> | 2009-09-23 23:38:00 +0200 |
---|---|---|
committer | Andreas Rumpf <andreasrumpf@noname> | 2009-09-23 23:38:00 +0200 |
commit | 3f3dda5a77fa8faf6d97aa5a0ed3b0fc6e8c0918 (patch) | |
tree | 81fcf664ab2abfda200061e57fa488ae17b03192 /nim | |
parent | 66a7e3d37c0303997a6b1a3b7ec263dfb8c07748 (diff) | |
download | Nim-3f3dda5a77fa8faf6d97aa5a0ed3b0fc6e8c0918.tar.gz |
implemented multi methods
Diffstat (limited to 'nim')
-rwxr-xr-x | nim/ast.pas | 147 | ||||
-rwxr-xr-x | nim/ccgexprs.pas | 27 | ||||
-rwxr-xr-x | nim/ccgstmts.pas | 7 | ||||
-rwxr-xr-x | nim/ccgtypes.pas | 18 | ||||
-rwxr-xr-x | nim/cgen.pas | 33 | ||||
-rw-r--r-- | nim/cgmeth.pas | 269 | ||||
-rwxr-xr-x | nim/docgen.pas | 1 | ||||
-rwxr-xr-x | nim/ecmasgen.pas | 2 | ||||
-rwxr-xr-x | nim/evals.pas | 20 | ||||
-rwxr-xr-x | nim/highlite.pas | 39 | ||||
-rwxr-xr-x | nim/importer.pas | 4 | ||||
-rwxr-xr-x | nim/lookups.pas | 4 | ||||
-rwxr-xr-x | nim/magicsys.pas | 16 | ||||
-rwxr-xr-x | nim/nhashes.pas | 2 | ||||
-rwxr-xr-x | nim/nversion.pas | 4 | ||||
-rwxr-xr-x | nim/pasparse.pas | 7 | ||||
-rwxr-xr-x | nim/passaux.pas | 2 | ||||
-rwxr-xr-x | nim/passes.pas | 2 | ||||
-rwxr-xr-x | nim/pnimsyn.pas | 36 | ||||
-rwxr-xr-x | nim/pragmas.pas | 6 | ||||
-rwxr-xr-x | nim/rnimsyn.pas | 4 | ||||
-rwxr-xr-x | nim/rodwrite.pas | 2 | ||||
-rwxr-xr-x | nim/sem.pas | 11 | ||||
-rwxr-xr-x | nim/semexprs.pas | 69 | ||||
-rwxr-xr-x | nim/semfold.pas | 4 | ||||
-rwxr-xr-x | nim/seminst.pas | 2 | ||||
-rwxr-xr-x | nim/semstmts.pas | 12 | ||||
-rwxr-xr-x | nim/semtempl.pas | 4 | ||||
-rwxr-xr-x | nim/semtypes.pas | 4 | ||||
-rwxr-xr-x | nim/sigmatch.pas | 24 | ||||
-rwxr-xr-x | nim/transf.pas | 18 |
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'); |