fixes #1940; code breakage! stricter template evaluation

This commit is contained in:
Araq 2015-03-07 02:30:51 +01:00
commit d58212ccc5
6 changed files with 479 additions and 435 deletions

View file

@ -9,12 +9,12 @@
# abstract syntax tree + symbol table # abstract syntax tree + symbol table
import import
msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists, msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists,
intsets, idgen intsets, idgen
type type
TCallingConvention* = enum TCallingConvention* = enum
ccDefault, # proc has no explicit calling convention ccDefault, # proc has no explicit calling convention
ccStdCall, # procedure is stdcall ccStdCall, # procedure is stdcall
ccCDecl, # cdecl ccCDecl, # cdecl
@ -26,12 +26,12 @@ type
ccClosure, # proc has a closure ccClosure, # proc has a closure
ccNoConvention # needed for generating proper C procs sometimes ccNoConvention # needed for generating proper C procs sometimes
const const
CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall", CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall",
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall",
"closure", "noconv"] "closure", "noconv"]
type type
TNodeKind* = enum # order is extremely important, because ranges are used TNodeKind* = enum # order is extremely important, because ranges are used
# to check whether a node belongs to a certain class # to check whether a node belongs to a certain class
nkNone, # unknown node kind: indicates an error nkNone, # unknown node kind: indicates an error
@ -64,13 +64,13 @@ type
# end of atoms # end of atoms
nkMetaNode_Obsolete, # difficult to explain; represents itself nkMetaNode_Obsolete, # difficult to explain; represents itself
# (used for macros) # (used for macros)
nkDotCall, # used to temporarily flag a nkCall node; nkDotCall, # used to temporarily flag a nkCall node;
# this is used # this is used
# for transforming ``s.len`` to ``len(s)`` # for transforming ``s.len`` to ``len(s)``
nkCommand, # a call like ``p 2, 4`` without parenthesis nkCommand, # a call like ``p 2, 4`` without parenthesis
nkCall, # a call like p(x, y) or an operation like +(a, b) nkCall, # a call like p(x, y) or an operation like +(a, b)
nkCallStrLit, # a call with a string literal nkCallStrLit, # a call with a string literal
# x"abc" has two sons: nkIdent, nkRStrLit # x"abc" has two sons: nkIdent, nkRStrLit
# x"""abc""" has two sons: nkIdent, nkTripleStrLit # x"""abc""" has two sons: nkIdent, nkTripleStrLit
nkInfix, # a call like (a + b) nkInfix, # a call like (a + b)
@ -126,7 +126,7 @@ type
nkAsgn, # a = b nkAsgn, # a = b
nkFastAsgn, # internal node for a fast ``a = b`` nkFastAsgn, # internal node for a fast ``a = b``
# (no string copy) # (no string copy)
nkGenericParams, # generic parameters nkGenericParams, # generic parameters
nkFormalParams, # formal parameters nkFormalParams, # formal parameters
nkOfInherit, # inherited from symbol nkOfInherit, # inherited from symbol
@ -192,7 +192,7 @@ type
nkWith, # distinct with `foo` nkWith, # distinct with `foo`
nkWithout, # distinct without `foo` nkWithout, # distinct without `foo`
nkTypeOfExpr, # type(1+2) nkTypeOfExpr, # type(1+2)
nkObjectTy, # object body nkObjectTy, # object body
nkTupleTy, # tuple body nkTupleTy, # tuple body
@ -226,7 +226,7 @@ type
TSymFlag* = enum # already 32 flags! TSymFlag* = enum # already 32 flags!
sfUsed, # read access of sym (for warnings) or simply used sfUsed, # read access of sym (for warnings) or simply used
sfExported, # symbol is exported from module sfExported, # symbol is exported from module
sfFromGeneric, # symbol is instantiation of a generic; this is needed sfFromGeneric, # symbol is instantiation of a generic; this is needed
# for symbol file generation; such symbols should always # for symbol file generation; such symbols should always
# be written into the ROD file # be written into the ROD file
sfGlobal, # symbol is at global scope sfGlobal, # symbol is at global scope
@ -284,9 +284,9 @@ const
sfAnon* = sfDiscardable sfAnon* = sfDiscardable
# symbol name that was generated by the compiler # symbol name that was generated by the compiler
# the compiler will avoid printing such names # the compiler will avoid printing such names
# in user messages. # in user messages.
sfNoForward* = sfRegister sfNoForward* = sfRegister
# forward declarations are not required (per module) # forward declarations are not required (per module)
@ -300,7 +300,7 @@ const
# getting ready for the future expr/stmt merge # getting ready for the future expr/stmt merge
nkWhen* = nkWhenStmt nkWhen* = nkWhenStmt
nkWhenExpr* = nkWhenStmt nkWhenExpr* = nkWhenStmt
nkEffectList* = nkArgList nkEffectList* = nkArgList
# hacks ahead: an nkEffectList is a node with 4 children: # hacks ahead: an nkEffectList is a node with 4 children:
exceptionEffects* = 0 # exceptions at position 0 exceptionEffects* = 0 # exceptions at position 0
usesEffects* = 1 # read effects at position 1 usesEffects* = 1 # read effects at position 1
@ -321,7 +321,7 @@ type
# unless this is an instance of a generic alias type. # unless this is an instance of a generic alias type.
# then realInstance will be the tyGenericInst of the # then realInstance will be the tyGenericInst of the
# completely (recursively) resolved alias. # completely (recursively) resolved alias.
tyGenericParam, # ``a`` in the above patterns tyGenericParam, # ``a`` in the above patterns
tyDistinct, tyDistinct,
tyEnum, tyEnum,
@ -340,14 +340,14 @@ type
tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers
tyFloat, tyFloat32, tyFloat64, tyFloat128, tyFloat, tyFloat32, tyFloat64, tyFloat128,
tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64, tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64,
tyBigNum, tyBigNum,
tyConst, tyMutable, tyVarargs, tyConst, tyMutable, tyVarargs,
tyIter, # unused tyIter, # unused
tyProxy # used as errornous type (for idetools) tyProxy # used as errornous type (for idetools)
tyBuiltInTypeClass #\ tyBuiltInTypeClass #\
# Type such as the catch-all object, tuple, seq, etc # Type such as the catch-all object, tuple, seq, etc
tyUserTypeClass #\ tyUserTypeClass #\
# the body of a user-defined type class # the body of a user-defined type class
@ -357,24 +357,24 @@ type
# tyGenericInst represents concrete types, while # tyGenericInst represents concrete types, while
# this is still a "generic param" that will bind types # this is still a "generic param" that will bind types
# and resolves them during sigmatch and instantiation. # and resolves them during sigmatch and instantiation.
tyCompositeTypeClass #\ tyCompositeTypeClass #\
# Type such as seq[Number] # Type such as seq[Number]
# The notes for tyUserTypeClassInst apply here as well # The notes for tyUserTypeClassInst apply here as well
# sons[0]: the original expression used by the user. # sons[0]: the original expression used by the user.
# sons[1]: fully expanded and instantiated meta type # sons[1]: fully expanded and instantiated meta type
# (potentially following aliases) # (potentially following aliases)
tyAnd, tyOr, tyNot #\ tyAnd, tyOr, tyNot #\
# boolean type classes such as `string|int`,`not seq`, # boolean type classes such as `string|int`,`not seq`,
# `Sortable and Enumable`, etc # `Sortable and Enumable`, etc
tyAnything #\ tyAnything #\
# a type class matching any type # a type class matching any type
tyStatic #\ tyStatic #\
# a value known at compile type (the underlying type is .base) # a value known at compile type (the underlying type is .base)
tyFromExpr #\ tyFromExpr #\
# This is a type representing an expression that depends # This is a type representing an expression that depends
# on generic parameters (the expression is stored in t.n) # on generic parameters (the expression is stored in t.n)
@ -390,7 +390,7 @@ type
# sons[0]: type of containing object or tuple # sons[0]: type of containing object or tuple
# sons[1]: field type # sons[1]: field type
# .n: nkDotExpr storing the field name # .n: nkDotExpr storing the field name
static: static:
# remind us when TTypeKind stops to fit in a single 64-bit word # remind us when TTypeKind stops to fit in a single 64-bit word
assert TTypeKind.high.ord <= 63 assert TTypeKind.high.ord <= 63
@ -408,7 +408,7 @@ const
tyAnd, tyOr, tyNot, tyAnything} tyAnd, tyOr, tyNot, tyAnything}
tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyExpr} + tyTypeClasses tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyExpr} + tyTypeClasses
type type
TTypeKinds* = set[TTypeKind] TTypeKinds* = set[TTypeKind]
@ -429,7 +429,7 @@ type
nfExprCall # this is an attempt to call a regular expression nfExprCall # this is an attempt to call a regular expression
nfIsRef # this node is a 'ref' node; used for the VM nfIsRef # this node is a 'ref' node; used for the VM
nfIsCursor # this node is attached a cursor; used for idetools nfIsCursor # this node is attached a cursor; used for idetools
TNodeFlags* = set[TNodeFlag] TNodeFlags* = set[TNodeFlag]
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 28) TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 28)
tfVarargs, # procedure has C styled varargs tfVarargs, # procedure has C styled varargs
@ -448,7 +448,7 @@ type
# proc foo(L: static[int]): array[L, int] # proc foo(L: static[int]): array[L, int]
# can be attached to ranges to indicate that the range # can be attached to ranges to indicate that the range
# depends on unresolved static params. # depends on unresolved static params.
tfRetType, # marks return types in proc (used to detect type classes tfRetType, # marks return types in proc (used to detect type classes
# used as return types for return type inference) # used as return types for return type inference)
tfCapturesEnv, # whether proc really captures some environment tfCapturesEnv, # whether proc really captures some environment
tfByCopy, # pass object/tuple by copy (C backend) tfByCopy, # pass object/tuple by copy (C backend)
@ -456,7 +456,7 @@ type
tfIterator, # type is really an iterator, not a tyProc tfIterator, # type is really an iterator, not a tyProc
tfShared, # type is 'shared' tfShared, # type is 'shared'
tfNotNil, # type cannot be 'nil' tfNotNil, # type cannot be 'nil'
tfNeedsInit, # type constains a "not nil" constraint somewhere or some tfNeedsInit, # type constains a "not nil" constraint somewhere or some
# other type so that it requires inititalization # other type so that it requires inititalization
tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode
@ -520,7 +520,7 @@ const
tfGcSafe* = tfThread tfGcSafe* = tfThread
tfObjHasKids* = tfEnumHasHoles tfObjHasKids* = tfEnumHasHoles
skError* = skUnknown skError* = skUnknown
# type flags that are essential for type equality: # type flags that are essential for type equality:
eqTypeFlags* = {tfIterator, tfShared, tfNotNil, tfVarIsPtr} eqTypeFlags* = {tfIterator, tfShared, tfNotNil, tfVarIsPtr}
@ -531,29 +531,29 @@ type
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf,
mEcho, mShallowCopy, mSlurp, mStaticExec, mEcho, mShallowCopy, mSlurp, mStaticExec,
mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst, mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
mUnaryLt, mSucc, mUnaryLt, mSucc,
mPred, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray, mPred, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref, mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref,
mGCunref, mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64, mGCunref, mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
mDivI64, mModI64, mDivI64, mModI64,
mAddF64, mSubF64, mMulF64, mDivF64, mAddF64, mSubF64, mMulF64, mDivF64,
mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI, mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64, mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
mMinF64, mMaxF64, mAddU, mSubU, mMulU, mMinF64, mMaxF64, mAddU, mSubU, mMulU,
mDivU, mModU, mEqI, mLeI, mDivU, mModU, mEqI, mLeI,
mLtI, mLtI,
mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64, mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
mLeU, mLtU, mLeU64, mLtU64, mLeU, mLtU, mLeU64, mLtU64,
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef, mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mEqProc, mUnaryMinusI, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mEqProc, mUnaryMinusI,
mUnaryMinusI64, mAbsI, mAbsI64, mNot, mUnaryMinusI64, mAbsI, mAbsI64, mNot,
mUnaryPlusI, mBitnotI, mUnaryPlusI64, mUnaryPlusI, mBitnotI, mUnaryPlusI64,
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64, mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr, mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT, mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
mConTArr, mConTT, mSlice, mConTArr, mConTT, mSlice,
mFields, mFieldPairs, mOmpParFor, mFields, mFieldPairs, mOmpParFor,
mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
@ -584,36 +584,36 @@ type
# things that we can evaluate safely at compile time, even if not asked for it: # things that we can evaluate safely at compile time, even if not asked for it:
const const
ctfeWhitelist* = {mNone, mUnaryLt, mSucc, ctfeWhitelist* = {mNone, mUnaryLt, mSucc,
mPred, mInc, mDec, mOrd, mLengthOpenArray, mPred, mInc, mDec, mOrd, mLengthOpenArray,
mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr,
mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64, mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
mDivI64, mModI64, mAddF64, mSubF64, mMulF64, mDivF64, mDivI64, mModI64, mAddF64, mSubF64, mMulF64, mDivF64,
mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI, mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64, mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
mMinF64, mMaxF64, mAddU, mSubU, mMulU, mMinF64, mMaxF64, mAddU, mSubU, mMulU,
mDivU, mModU, mEqI, mLeI, mDivU, mModU, mEqI, mLeI,
mLtI, mLtI,
mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64, mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
mLeU, mLtU, mLeU64, mLtU64, mLeU, mLtU, mLeU64, mLtU64,
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef, mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI, mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI,
mUnaryMinusI64, mAbsI, mAbsI64, mNot, mUnaryMinusI64, mAbsI, mAbsI64, mNot,
mUnaryPlusI, mBitnotI, mUnaryPlusI64, mUnaryPlusI, mBitnotI, mUnaryPlusI64,
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64, mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr, mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT, mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
mConTArr, mConTT, mConTArr, mConTT,
mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mInRange, mInSet, mRepr, mInRange, mInSet, mRepr,
mCopyStr, mCopyStrLast} mCopyStr, mCopyStrLast}
# magics that require special semantic checking and # magics that require special semantic checking and
# thus cannot be overloaded (also documented in the spec!): # thus cannot be overloaded (also documented in the spec!):
SpecialSemMagics* = { SpecialSemMagics* = {
mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf, mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf,
mEcho, mShallowCopy, mExpandToAst, mParallel, mSpawn, mAstToStr} mEcho, mShallowCopy, mExpandToAst, mParallel, mSpawn, mAstToStr}
type type
@ -634,21 +634,21 @@ type
floatVal*: BiggestFloat floatVal*: BiggestFloat
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
strVal*: string strVal*: string
of nkSym: of nkSym:
sym*: PSym sym*: PSym
of nkIdent: of nkIdent:
ident*: PIdent ident*: PIdent
else: else:
sons*: TNodeSeq sons*: TNodeSeq
comment*: string comment*: string
TSymSeq* = seq[PSym] TSymSeq* = seq[PSym]
TStrTable* = object # a table[PIdent] of PSym TStrTable* = object # a table[PIdent] of PSym
counter*: int counter*: int
data*: TSymSeq data*: TSymSeq
# -------------- backend information ------------------------------- # -------------- backend information -------------------------------
TLocKind* = enum TLocKind* = enum
locNone, # no location locNone, # no location
locTemp, # temporary location locTemp, # temporary location
locLocalVar, # location is a local variable locLocalVar, # location is a local variable
@ -660,7 +660,7 @@ type
locData, # location is a constant locData, # location is a constant
locCall, # location is a call expression locCall, # location is a call expression
locOther # location is something other locOther # location is something other
TLocFlag* = enum TLocFlag* = enum
lfIndirect, # backend introduced a pointer lfIndirect, # backend introduced a pointer
lfParamCopy, # backend introduced a parameter copy (LLVM) lfParamCopy, # backend introduced a parameter copy (LLVM)
lfNoDeepCopy, # no need for a deep copy lfNoDeepCopy, # no need for a deep copy
@ -670,13 +670,13 @@ type
lfHeader, # include header file for symbol lfHeader, # include header file for symbol
lfImportCompilerProc, # ``importc`` of a compilerproc lfImportCompilerProc, # ``importc`` of a compilerproc
lfSingleUse # no location yet and will only be used once lfSingleUse # no location yet and will only be used once
TStorageLoc* = enum TStorageLoc* = enum
OnUnknown, # location is unknown (stack, heap or static) OnUnknown, # location is unknown (stack, heap or static)
OnStack, # location is on hardware stack OnStack, # location is on hardware stack
OnHeap # location is on heap or global OnHeap # location is on heap or global
# (reference counting needed) # (reference counting needed)
TLocFlags* = set[TLocFlag] TLocFlags* = set[TLocFlag]
TLoc* = object TLoc* = object
k*: TLocKind # kind of location k*: TLocKind # kind of location
s*: TStorageLoc s*: TStorageLoc
flags*: TLocFlags # location's flags flags*: TLocFlags # location's flags
@ -688,7 +688,7 @@ type
# ---------------- end of backend information ------------------------------ # ---------------- end of backend information ------------------------------
TLibKind* = enum TLibKind* = enum
libHeader, libDynamic libHeader, libDynamic
TLib* = object of lists.TListEntry # also misused for headers! TLib* = object of lists.TListEntry # also misused for headers!
kind*: TLibKind kind*: TLibKind
@ -696,17 +696,17 @@ type
isOverriden*: bool isOverriden*: bool
name*: PRope name*: PRope
path*: PNode # can be a string literal! path*: PNode # can be a string literal!
TInstantiation* = object TInstantiation* = object
sym*: PSym sym*: PSym
concreteTypes*: seq[PType] concreteTypes*: seq[PType]
usedBy*: seq[int32] # list of modules using the generic usedBy*: seq[int32] # list of modules using the generic
# needed in caas mode for purging the cache # needed in caas mode for purging the cache
# XXX: it's possible to switch to a # XXX: it's possible to switch to a
# simple ref count here # simple ref count here
PInstantiation* = ref TInstantiation PInstantiation* = ref TInstantiation
TScope* = object TScope* = object
depthLevel*: int depthLevel*: int
symbols*: TStrTable symbols*: TStrTable
@ -773,7 +773,7 @@ type
constraint*: PNode # additional constraints like 'lit|result'; also constraint*: PNode # additional constraints like 'lit|result'; also
# misused for the codegenDecl pragma in the hope # misused for the codegenDecl pragma in the hope
# it won't cause problems # it won't cause problems
TTypeSeq* = seq[PType] TTypeSeq* = seq[PType]
TLockLevel* = distinct int16 TLockLevel* = distinct int16
TType* {.acyclic.} = object of TIdObj # \ TType* {.acyclic.} = object of TIdObj # \
@ -806,7 +806,7 @@ type
lockLevel*: TLockLevel # lock level as required for deadlock checking lockLevel*: TLockLevel # lock level as required for deadlock checking
loc*: TLoc loc*: TLoc
TPair*{.final.} = object TPair*{.final.} = object
key*, val*: RootRef key*, val*: RootRef
TPairSeq* = seq[TPair] TPairSeq* = seq[TPair]
@ -814,7 +814,7 @@ type
counter*: int counter*: int
data*: TPairSeq data*: TPairSeq
TIdPair*{.final.} = object TIdPair*{.final.} = object
key*: PIdObj key*: PIdObj
val*: RootRef val*: RootRef
@ -823,7 +823,7 @@ type
counter*: int counter*: int
data*: TIdPairSeq data*: TIdPairSeq
TIdNodePair*{.final.} = object TIdNodePair*{.final.} = object
key*: PIdObj key*: PIdObj
val*: PNode val*: PNode
@ -832,7 +832,7 @@ type
counter*: int counter*: int
data*: TIdNodePairSeq data*: TIdNodePairSeq
TNodePair*{.final.} = object TNodePair*{.final.} = object
h*: THash # because it is expensive to compute! h*: THash # because it is expensive to compute!
key*: PNode key*: PNode
val*: int val*: int
@ -844,7 +844,7 @@ type
data*: TNodePairSeq data*: TNodePairSeq
TObjectSeq* = seq[RootRef] TObjectSeq* = seq[RootRef]
TObjectSet*{.final.} = object TObjectSet*{.final.} = object
counter*: int counter*: int
data*: TObjectSeq data*: TObjectSeq
@ -855,27 +855,27 @@ type
# same name as an imported module. This is necessary because of # same name as an imported module. This is necessary because of
# the poor naming choices in the standard library. # the poor naming choices in the standard library.
const const
OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator, OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator,
skConverter, skModule, skTemplate, skMacro} skConverter, skModule, skTemplate, skMacro}
GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody, GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody,
tyGenericParam} tyGenericParam}
StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray, StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray,
tySet, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyOpenArray, tySet, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyOpenArray,
tyVarargs} tyVarargs}
ConcreteTypes*: TTypeKinds = { # types of the expr that may occur in:: ConcreteTypes*: TTypeKinds = { # types of the expr that may occur in::
# var x = expr # var x = expr
tyBool, tyChar, tyEnum, tyArray, tyObject, tyBool, tyChar, tyEnum, tyArray, tyObject,
tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc,
tyPointer, tyPointer,
tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128, tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
tyUInt..tyUInt64} tyUInt..tyUInt64}
IntegralTypes* = {tyBool, tyChar, tyEnum, tyInt..tyInt64, IntegralTypes* = {tyBool, tyChar, tyEnum, tyInt..tyInt64,
tyFloat..tyFloat128, tyUInt..tyUInt64} tyFloat..tyFloat128, tyUInt..tyUInt64}
ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet, ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet,
tyTuple, tySequence} tyTuple, tySequence}
NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence, NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence,
tyProc, tyString, tyError} tyProc, tyString, tyError}
@ -926,17 +926,17 @@ proc discardSons*(father: PNode)
proc len*(n: PNode): int {.inline.} = proc len*(n: PNode): int {.inline.} =
if isNil(n.sons): result = 0 if isNil(n.sons): result = 0
else: result = len(n.sons) else: result = len(n.sons)
proc safeLen*(n: PNode): int {.inline.} = proc safeLen*(n: PNode): int {.inline.} =
## works even for leaves. ## works even for leaves.
if n.kind in {nkNone..nkNilLit} or isNil(n.sons): result = 0 if n.kind in {nkNone..nkNilLit} or isNil(n.sons): result = 0
else: result = len(n.sons) else: result = len(n.sons)
proc add*(father, son: PNode) = proc add*(father, son: PNode) =
assert son != nil assert son != nil
if isNil(father.sons): father.sons = @[] if isNil(father.sons): father.sons = @[]
add(father.sons, son) add(father.sons, son)
proc `[]`*(n: PNode, i: int): PNode {.inline.} = proc `[]`*(n: PNode, i: int): PNode {.inline.} =
result = n.sons[i] result = n.sons[i]
@ -946,13 +946,10 @@ template `{}=`*(n: PNode, i: int, s: PNode): stmt =
n.sons[i -| n] = s n.sons[i -| n] = s
when defined(useNodeIds): when defined(useNodeIds):
const nodeIdToDebug* = -1 # 884953 # 612794 const nodeIdToDebug* = -1 # 299750 # 300761 #300863 # 300879
#612840 # 612905 # 614635 # 614637 # 614641
# 423408
#429107 # 430443 # 441048 # 441090 # 441153
var gNodeId: int var gNodeId: int
proc newNode*(kind: TNodeKind): PNode = proc newNode*(kind: TNodeKind): PNode =
new(result) new(result)
result.kind = kind result.kind = kind
#result.info = UnknownLineInfo() inlined: #result.info = UnknownLineInfo() inlined:
@ -966,24 +963,24 @@ proc newNode*(kind: TNodeKind): PNode =
writeStackTrace() writeStackTrace()
inc gNodeId inc gNodeId
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode = proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
result = newNode(kind) result = newNode(kind)
result.intVal = intVal result.intVal = intVal
proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode = proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode =
result = newIntNode(kind, intVal) result = newIntNode(kind, intVal)
result.typ = typ result.typ = typ
proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode = proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode =
result = newNode(kind) result = newNode(kind)
result.floatVal = floatVal result.floatVal = floatVal
proc newStrNode*(kind: TNodeKind, strVal: string): PNode = proc newStrNode*(kind: TNodeKind, strVal: string): PNode =
result = newNode(kind) result = newNode(kind)
result.strVal = strVal result.strVal = strVal
proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym, proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
info: TLineInfo): PSym = info: TLineInfo): PSym =
# generates a symbol and initializes the hash field too # generates a symbol and initializes the hash field too
new(result) new(result)
result.name = name result.name = name
@ -994,7 +991,7 @@ proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
result.owner = owner result.owner = owner
result.offset = - 1 result.offset = - 1
result.id = getID() result.id = getID()
when debugIds: when debugIds:
registerId(result) registerId(result)
#if result.id < 2000: #if result.id < 2000:
# MessageOut(name.s & " has id: " & toString(result.id)) # MessageOut(name.s & " has id: " & toString(result.id))
@ -1036,54 +1033,54 @@ proc appendToModule*(m: PSym, n: PNode) =
else: else:
assert m.ast.kind == nkStmtList assert m.ast.kind == nkStmtList
m.ast.sons.add(n) m.ast.sons.add(n)
const # for all kind of hash tables: const # for all kind of hash tables:
GrowthFactor* = 2 # must be power of 2, > 0 GrowthFactor* = 2 # must be power of 2, > 0
StartSize* = 8 # must be power of 2, > 0 StartSize* = 8 # must be power of 2, > 0
proc copyStrTable*(dest: var TStrTable, src: TStrTable) = proc copyStrTable*(dest: var TStrTable, src: TStrTable) =
dest.counter = src.counter dest.counter = src.counter
if isNil(src.data): return if isNil(src.data): return
setLen(dest.data, len(src.data)) setLen(dest.data, len(src.data))
for i in countup(0, high(src.data)): dest.data[i] = src.data[i] for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
proc copyIdTable*(dest: var TIdTable, src: TIdTable) = proc copyIdTable*(dest: var TIdTable, src: TIdTable) =
dest.counter = src.counter dest.counter = src.counter
if isNil(src.data): return if isNil(src.data): return
newSeq(dest.data, len(src.data)) newSeq(dest.data, len(src.data))
for i in countup(0, high(src.data)): dest.data[i] = src.data[i] for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
proc copyTable*(dest: var TTable, src: TTable) = proc copyTable*(dest: var TTable, src: TTable) =
dest.counter = src.counter dest.counter = src.counter
if isNil(src.data): return if isNil(src.data): return
setLen(dest.data, len(src.data)) setLen(dest.data, len(src.data))
for i in countup(0, high(src.data)): dest.data[i] = src.data[i] for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) = proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
dest.counter = src.counter dest.counter = src.counter
if isNil(src.data): return if isNil(src.data): return
setLen(dest.data, len(src.data)) setLen(dest.data, len(src.data))
for i in countup(0, high(src.data)): dest.data[i] = src.data[i] for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
proc discardSons*(father: PNode) = proc discardSons*(father: PNode) =
father.sons = nil father.sons = nil
proc withInfo*(n: PNode, info: TLineInfo): PNode = proc withInfo*(n: PNode, info: TLineInfo): PNode =
n.info = info n.info = info
return n return n
proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode = proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode =
result = newNode(nkIdent) result = newNode(nkIdent)
result.ident = ident result.ident = ident
result.info = info result.info = info
proc newSymNode*(sym: PSym): PNode = proc newSymNode*(sym: PSym): PNode =
result = newNode(nkSym) result = newNode(nkSym)
result.sym = sym result.sym = sym
result.typ = sym.typ result.typ = sym.typ
result.info = sym.info result.info = sym.info
proc newSymNode*(sym: PSym, info: TLineInfo): PNode = proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
result = newNode(nkSym) result = newNode(nkSym)
result.sym = sym result.sym = sym
result.typ = sym.typ result.typ = sym.typ
@ -1128,12 +1125,12 @@ proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[],
writeStackTrace() writeStackTrace()
inc gNodeId inc gNodeId
proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode = proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
result = newNode(kind) result = newNode(kind)
result.info = info result.info = info
result.typ = typ result.typ = typ
proc addSon*(father, son: PNode) = proc addSon*(father, son: PNode) =
assert son != nil assert son != nil
if isNil(father.sons): father.sons = @[] if isNil(father.sons): father.sons = @[]
add(father.sons, son) add(father.sons, son)
@ -1159,7 +1156,7 @@ proc `$`*(x: TLockLevel): string =
elif x.ord == UnknownLockLevel.ord: result = "<unknown>" elif x.ord == UnknownLockLevel.ord: result = "<unknown>"
else: result = $int16(x) else: result = $int16(x)
proc newType*(kind: TTypeKind, owner: PSym): PType = proc newType*(kind: TTypeKind, owner: PSym): PType =
new(result) new(result)
result.kind = kind result.kind = kind
result.owner = owner result.owner = owner
@ -1171,7 +1168,7 @@ proc newType*(kind: TTypeKind, owner: PSym): PType =
registerId(result) registerId(result)
#if result.id < 2000: #if result.id < 2000:
# messageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id)) # messageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
proc mergeLoc(a: var TLoc, b: TLoc) = proc mergeLoc(a: var TLoc, b: TLoc) =
if a.k == low(a.k): a.k = b.k if a.k == low(a.k): a.k = b.k
if a.s == low(a.s): a.s = b.s if a.s == low(a.s): a.s = b.s
@ -1180,37 +1177,37 @@ proc mergeLoc(a: var TLoc, b: TLoc) =
if a.r == nil: a.r = b.r if a.r == nil: a.r = b.r
#if a.a == 0: a.a = b.a #if a.a == 0: a.a = b.a
proc newSons*(father: PNode, length: int) = proc newSons*(father: PNode, length: int) =
if isNil(father.sons): if isNil(father.sons):
newSeq(father.sons, length) newSeq(father.sons, length)
else: else:
setLen(father.sons, length) setLen(father.sons, length)
proc newSons*(father: PType, length: int) = proc newSons*(father: PType, length: int) =
if isNil(father.sons): if isNil(father.sons):
newSeq(father.sons, length) newSeq(father.sons, length)
else: else:
setLen(father.sons, length) setLen(father.sons, length)
proc sonsLen*(n: PType): int = proc sonsLen*(n: PType): int =
if isNil(n.sons): result = 0 if isNil(n.sons): result = 0
else: result = len(n.sons) else: result = len(n.sons)
proc len*(n: PType): int = proc len*(n: PType): int =
if isNil(n.sons): result = 0 if isNil(n.sons): result = 0
else: result = len(n.sons) else: result = len(n.sons)
proc sonsLen*(n: PNode): int = proc sonsLen*(n: PNode): int =
if isNil(n.sons): result = 0 if isNil(n.sons): result = 0
else: result = len(n.sons) else: result = len(n.sons)
proc lastSon*(n: PNode): PNode = proc lastSon*(n: PNode): PNode =
result = n.sons[sonsLen(n) - 1] result = n.sons[sonsLen(n) - 1]
proc lastSon*(n: PType): PType = proc lastSon*(n: PType): PType =
result = n.sons[sonsLen(n) - 1] result = n.sons[sonsLen(n) - 1]
proc assignType*(dest, src: PType) = proc assignType*(dest, src: PType) =
dest.kind = src.kind dest.kind = src.kind
dest.flags = src.flags dest.flags = src.flags
dest.callConv = src.callConv dest.callConv = src.callConv
@ -1230,23 +1227,23 @@ proc assignType*(dest, src: PType) =
dest.sym = src.sym dest.sym = src.sym
newSons(dest, sonsLen(src)) newSons(dest, sonsLen(src))
for i in countup(0, sonsLen(src) - 1): dest.sons[i] = src.sons[i] for i in countup(0, sonsLen(src) - 1): dest.sons[i] = src.sons[i]
proc copyType*(t: PType, owner: PSym, keepId: bool): PType = proc copyType*(t: PType, owner: PSym, keepId: bool): PType =
result = newType(t.kind, owner) result = newType(t.kind, owner)
assignType(result, t) assignType(result, t)
if keepId: if keepId:
result.id = t.id result.id = t.id
else: else:
when debugIds: registerId(result) when debugIds: registerId(result)
result.sym = t.sym # backend-info should not be copied result.sym = t.sym # backend-info should not be copied
proc copySym*(s: PSym, keepId: bool = false): PSym = proc copySym*(s: PSym, keepId: bool = false): PSym =
result = newSym(s.kind, s.name, s.owner, s.info) result = newSym(s.kind, s.name, s.owner, s.info)
#result.ast = nil # BUGFIX; was: s.ast which made problems #result.ast = nil # BUGFIX; was: s.ast which made problems
result.typ = s.typ result.typ = s.typ
if keepId: if keepId:
result.id = s.id result.id = s.id
else: else:
result.id = getID() result.id = getID()
when debugIds: registerId(result) when debugIds: registerId(result)
result.flags = s.flags result.flags = s.flags
@ -1273,19 +1270,19 @@ proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym =
result.annex = s.annex result.annex = s.annex
# XXX once usedGenerics is used, ensure module aliases keep working! # XXX once usedGenerics is used, ensure module aliases keep working!
assert s.usedGenerics == nil assert s.usedGenerics == nil
proc initStrTable*(x: var TStrTable) = proc initStrTable*(x: var TStrTable) =
x.counter = 0 x.counter = 0
newSeq(x.data, StartSize) newSeq(x.data, StartSize)
proc newStrTable*: TStrTable = proc newStrTable*: TStrTable =
initStrTable(result) initStrTable(result)
proc initTable(x: var TTable) = proc initTable(x: var TTable) =
x.counter = 0 x.counter = 0
newSeq(x.data, StartSize) newSeq(x.data, StartSize)
proc initIdTable*(x: var TIdTable) = proc initIdTable*(x: var TIdTable) =
x.counter = 0 x.counter = 0
newSeq(x.data, StartSize) newSeq(x.data, StartSize)
@ -1295,15 +1292,15 @@ proc resetIdTable*(x: var TIdTable) =
setLen(x.data, 0) setLen(x.data, 0)
setLen(x.data, StartSize) setLen(x.data, StartSize)
proc initObjectSet*(x: var TObjectSet) = proc initObjectSet*(x: var TObjectSet) =
x.counter = 0 x.counter = 0
newSeq(x.data, StartSize) newSeq(x.data, StartSize)
proc initIdNodeTable*(x: var TIdNodeTable) = proc initIdNodeTable*(x: var TIdNodeTable) =
x.counter = 0 x.counter = 0
newSeq(x.data, StartSize) newSeq(x.data, StartSize)
proc initNodeTable*(x: var TNodeTable) = proc initNodeTable*(x: var TNodeTable) =
x.counter = 0 x.counter = 0
newSeq(x.data, StartSize) newSeq(x.data, StartSize)
@ -1327,11 +1324,11 @@ proc propagateToOwner*(owner, elem: PType) =
owner.flags.incl tfNotNil owner.flags.incl tfNotNil
elif owner.kind notin HaveTheirOwnEmpty: elif owner.kind notin HaveTheirOwnEmpty:
owner.flags.incl tfNeedsInit owner.flags.incl tfNeedsInit
if tfNeedsInit in elem.flags: if tfNeedsInit in elem.flags:
if owner.kind in HaveTheirOwnEmpty: discard if owner.kind in HaveTheirOwnEmpty: discard
else: owner.flags.incl tfNeedsInit else: owner.flags.incl tfNeedsInit
if elem.isMetaType: if elem.isMetaType:
owner.flags.incl tfHasMeta owner.flags.incl tfHasMeta
@ -1348,15 +1345,15 @@ proc addSonNilAllowed*(father, son: PNode) =
if isNil(father.sons): father.sons = @[] if isNil(father.sons): father.sons = @[]
add(father.sons, son) add(father.sons, son)
proc delSon*(father: PNode, idx: int) = proc delSon*(father: PNode, idx: int) =
if isNil(father.sons): return if isNil(father.sons): return
var length = sonsLen(father) var length = sonsLen(father)
for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1] for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1]
setLen(father.sons, length - 1) setLen(father.sons, length - 1)
proc copyNode*(src: PNode): PNode = proc copyNode*(src: PNode): PNode =
# does not copy its sons! # does not copy its sons!
if src == nil: if src == nil:
return nil return nil
result = newNode(src.kind) result = newNode(src.kind)
result.info = src.info result.info = src.info
@ -1373,7 +1370,7 @@ proc copyNode*(src: PNode): PNode =
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
else: discard else: discard
proc shallowCopy*(src: PNode): PNode = proc shallowCopy*(src: PNode): PNode =
# does not copy its sons, but provides space for them: # does not copy its sons, but provides space for them:
if src == nil: return nil if src == nil: return nil
result = newNode(src.kind) result = newNode(src.kind)
@ -1391,9 +1388,9 @@ proc shallowCopy*(src: PNode): PNode =
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
else: newSeq(result.sons, sonsLen(src)) else: newSeq(result.sons, sonsLen(src))
proc copyTree*(src: PNode): PNode = proc copyTree*(src: PNode): PNode =
# copy a whole syntax tree; performs deep copying # copy a whole syntax tree; performs deep copying
if src == nil: if src == nil:
return nil return nil
result = newNode(src.kind) result = newNode(src.kind)
result.info = src.info result.info = src.info
@ -1408,20 +1405,20 @@ proc copyTree*(src: PNode): PNode =
of nkSym: result.sym = src.sym of nkSym: result.sym = src.sym
of nkIdent: result.ident = src.ident of nkIdent: result.ident = src.ident
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
else: else:
newSeq(result.sons, sonsLen(src)) newSeq(result.sons, sonsLen(src))
for i in countup(0, sonsLen(src) - 1): for i in countup(0, sonsLen(src) - 1):
result.sons[i] = copyTree(src.sons[i]) result.sons[i] = copyTree(src.sons[i])
proc hasSonWith*(n: PNode, kind: TNodeKind): bool = proc hasSonWith*(n: PNode, kind: TNodeKind): bool =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if n.sons[i].kind == kind: if n.sons[i].kind == kind:
return true return true
result = false result = false
proc hasNilSon*(n: PNode): bool = proc hasNilSon*(n: PNode): bool =
for i in countup(0, safeLen(n) - 1): for i in countup(0, safeLen(n) - 1):
if n.sons[i] == nil: if n.sons[i] == nil:
return true return true
elif hasNilSon(n.sons[i]): elif hasNilSon(n.sons[i]):
return true return true
@ -1435,47 +1432,47 @@ proc containsNode*(n: PNode, kinds: TNodeKinds): bool =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if n.kind in kinds or containsNode(n.sons[i], kinds): return true if n.kind in kinds or containsNode(n.sons[i], kinds): return true
proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool = proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool =
case n.kind case n.kind
of nkEmpty..nkNilLit: result = n.kind == kind of nkEmpty..nkNilLit: result = n.kind == kind
else: else:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if (n.sons[i].kind == kind) or hasSubnodeWith(n.sons[i], kind): if (n.sons[i].kind == kind) or hasSubnodeWith(n.sons[i], kind):
return true return true
result = false result = false
proc replaceSons(n: PNode, oldKind, newKind: TNodeKind) = proc replaceSons(n: PNode, oldKind, newKind: TNodeKind) =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if n.sons[i].kind == oldKind: n.sons[i].kind = newKind if n.sons[i].kind == oldKind: n.sons[i].kind = newKind
proc sonsNotNil(n: PNode): bool = proc sonsNotNil(n: PNode): bool =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if n.sons[i] == nil: if n.sons[i] == nil:
return false return false
result = true result = true
proc getInt*(a: PNode): BiggestInt = proc getInt*(a: PNode): BiggestInt =
case a.kind case a.kind
of nkIntLit..nkUInt64Lit: result = a.intVal of nkIntLit..nkUInt64Lit: result = a.intVal
else: else:
internalError(a.info, "getInt") internalError(a.info, "getInt")
result = 0 result = 0
proc getFloat*(a: PNode): BiggestFloat = proc getFloat*(a: PNode): BiggestFloat =
case a.kind case a.kind
of nkFloatLit..nkFloat128Lit: result = a.floatVal of nkFloatLit..nkFloat128Lit: result = a.floatVal
else: else:
internalError(a.info, "getFloat") internalError(a.info, "getFloat")
result = 0.0 result = 0.0
proc getStr*(a: PNode): string = proc getStr*(a: PNode): string =
case a.kind case a.kind
of nkStrLit..nkTripleStrLit: result = a.strVal of nkStrLit..nkTripleStrLit: result = a.strVal
else: else:
internalError(a.info, "getStr") internalError(a.info, "getStr")
result = "" result = ""
proc getStrOrChar*(a: PNode): string = proc getStrOrChar*(a: PNode): string =
case a.kind case a.kind
of nkStrLit..nkTripleStrLit: result = a.strVal of nkStrLit..nkTripleStrLit: result = a.strVal
of nkCharLit..nkUInt64Lit: result = $chr(int(a.intVal)) of nkCharLit..nkUInt64Lit: result = $chr(int(a.intVal))
@ -1483,7 +1480,7 @@ proc getStrOrChar*(a: PNode): string =
internalError(a.info, "getStrOrChar") internalError(a.info, "getStrOrChar")
result = "" result = ""
proc isGenericRoutine*(s: PSym): bool = proc isGenericRoutine*(s: PSym): bool =
case s.kind case s.kind
of skProcKinds: of skProcKinds:
result = sfFromGeneric in s.flags or result = sfFromGeneric in s.flags or

View file

@ -10,7 +10,7 @@
## Template evaluation engine. Now hygienic. ## Template evaluation engine. Now hygienic.
import import
strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer, strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer,
rodread rodread
type type
@ -49,7 +49,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
result.add copyNode(c, templ, actual) result.add copyNode(c, templ, actual)
else: else:
var res = copyNode(c, templ, actual) var res = copyNode(c, templ, actual)
for i in countup(0, sonsLen(templ) - 1): for i in countup(0, sonsLen(templ) - 1):
evalTemplateAux(templ.sons[i], actual, c, res) evalTemplateAux(templ.sons[i], actual, c, res)
result.add res result.add res
@ -86,9 +86,9 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
ctx.owner = tmpl ctx.owner = tmpl
ctx.genSymOwner = genSymOwner ctx.genSymOwner = genSymOwner
initIdTable(ctx.mapping) initIdTable(ctx.mapping)
let body = tmpl.getBody let body = tmpl.getBody
if isAtom(body): if isAtom(body):
result = newNodeI(nkPar, body.info) result = newNodeI(nkPar, body.info)
evalTemplateAux(body, args, ctx, result) evalTemplateAux(body, args, ctx, result)
if result.len == 1: result = result.sons[0] if result.len == 1: result = result.sons[0]
@ -102,5 +102,5 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
if ctx.instLines: result.info = n.info if ctx.instLines: result.info = n.info
for i in countup(0, safeLen(body) - 1): for i in countup(0, safeLen(body) - 1):
evalTemplateAux(body.sons[i], args, ctx, result) evalTemplateAux(body.sons[i], args, ctx, result)
dec(evalTemplateCounter) dec(evalTemplateCounter)

File diff suppressed because it is too large Load diff

View file

@ -1232,7 +1232,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
elif f.kind == tyStatic: elif f.kind == tyStatic:
return arg.typ.n return arg.typ.n
else: else:
return argOrig return argSemantized # argOrig
if r != isNone and f.isInlineIterator: if r != isNone and f.isInlineIterator:
var inlined = newTypeS(tyStatic, c) var inlined = newTypeS(tyStatic, c)

View file

@ -121,7 +121,7 @@ export Port, SocketFlag
## ##
## Limitations/Bugs ## Limitations/Bugs
## ---------------- ## ----------------
## ##
## * ``except`` statement (without `try`) does not work inside async procedures. ## * ``except`` statement (without `try`) does not work inside async procedures.
## * The effect system (``raises: []``) does not work with async procedures. ## * The effect system (``raises: []``) does not work with async procedures.
## * Can't await in a ``except`` body ## * Can't await in a ``except`` body
@ -379,7 +379,7 @@ when defined(windows) or defined(nimdoc):
if p.handles.len == 0 and p.timers.len == 0: if p.handles.len == 0 and p.timers.len == 0:
raise newException(ValueError, raise newException(ValueError,
"No handles or timers registered in dispatcher.") "No handles or timers registered in dispatcher.")
let llTimeout = let llTimeout =
if timeout == -1: winlean.INFINITE if timeout == -1: winlean.INFINITE
else: timeout.int32 else: timeout.int32
@ -436,12 +436,12 @@ when defined(windows) or defined(nimdoc):
if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS): if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS):
raiseOSError(osLastError()) raiseOSError(osLastError())
proc connectEx(s: SocketHandle, name: ptr SockAddr, namelen: cint, proc connectEx(s: SocketHandle, name: ptr SockAddr, namelen: cint,
lpSendBuffer: pointer, dwSendDataLength: Dword, lpSendBuffer: pointer, dwSendDataLength: Dword,
lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool = lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool =
if connectExPtr.isNil: raise newException(ValueError, "Need to initialise ConnectEx().") if connectExPtr.isNil: raise newException(ValueError, "Need to initialise ConnectEx().")
let fun = let fun =
cast[proc (s: SocketHandle, name: ptr SockAddr, namelen: cint, cast[proc (s: SocketHandle, name: ptr SockAddr, namelen: cint,
lpSendBuffer: pointer, dwSendDataLength: Dword, lpSendBuffer: pointer, dwSendDataLength: Dword,
lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](connectExPtr) lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](connectExPtr)
@ -475,7 +475,7 @@ when defined(windows) or defined(nimdoc):
dwRemoteAddressLength: Dword, LocalSockaddr: ptr ptr SockAddr, dwRemoteAddressLength: Dword, LocalSockaddr: ptr ptr SockAddr,
LocalSockaddrLength: LPInt, RemoteSockaddr: ptr ptr SockAddr, LocalSockaddrLength: LPInt, RemoteSockaddr: ptr ptr SockAddr,
RemoteSockaddrLength: LPInt) {.stdcall,gcsafe.}](getAcceptExSockAddrsPtr) RemoteSockaddrLength: LPInt) {.stdcall,gcsafe.}](getAcceptExSockAddrsPtr)
fun(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength, fun(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength,
dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength, dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength,
RemoteSockaddr, RemoteSockaddrLength) RemoteSockaddr, RemoteSockaddrLength)
@ -514,7 +514,7 @@ when defined(windows) or defined(nimdoc):
else: else:
retFuture.fail(newException(OSError, osErrorMsg(errcode))) retFuture.fail(newException(OSError, osErrorMsg(errcode)))
) )
var ret = connectEx(socket.SocketHandle, it.ai_addr, var ret = connectEx(socket.SocketHandle, it.ai_addr,
sizeof(Sockaddr_in).cint, nil, 0, nil, sizeof(Sockaddr_in).cint, nil, 0, nil,
cast[POVERLAPPED](ol)) cast[POVERLAPPED](ol))
@ -565,7 +565,7 @@ when defined(windows) or defined(nimdoc):
var dataBuf: TWSABuf var dataBuf: TWSABuf
dataBuf.buf = cast[cstring](alloc0(size)) dataBuf.buf = cast[cstring](alloc0(size))
dataBuf.len = size dataBuf.len = size
var bytesReceived: Dword var bytesReceived: Dword
var flagsio = flags.toOSFlags().Dword var flagsio = flags.toOSFlags().Dword
var ol = PCustomOverlapped() var ol = PCustomOverlapped()
@ -612,9 +612,9 @@ when defined(windows) or defined(nimdoc):
# the empty string (which signals a disconnection) when there is # the empty string (which signals a disconnection) when there is
# nothing left to read. # nothing left to read.
retFuture.complete("") retFuture.complete("")
# TODO: "For message-oriented sockets, where a zero byte message is often # TODO: "For message-oriented sockets, where a zero byte message is often
# allowable, a failure with an error code of WSAEDISCON is used to # allowable, a failure with an error code of WSAEDISCON is used to
# indicate graceful closure." # indicate graceful closure."
# ~ http://msdn.microsoft.com/en-us/library/ms741688%28v=vs.85%29.aspx # ~ http://msdn.microsoft.com/en-us/library/ms741688%28v=vs.85%29.aspx
else: else:
# Request to read completed immediately. # Request to read completed immediately.
@ -748,7 +748,7 @@ when defined(windows) or defined(nimdoc):
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms737524%28v=vs.85%29.aspx # http://msdn.microsoft.com/en-us/library/windows/desktop/ms737524%28v=vs.85%29.aspx
let ret = acceptEx(socket.SocketHandle, clientSock, addr lpOutputBuf[0], let ret = acceptEx(socket.SocketHandle, clientSock, addr lpOutputBuf[0],
dwReceiveDataLength, dwReceiveDataLength,
dwLocalAddressLength, dwLocalAddressLength,
dwRemoteAddressLength, dwRemoteAddressLength,
addr dwBytesReceived, cast[POVERLAPPED](ol)) addr dwBytesReceived, cast[POVERLAPPED](ol))
@ -803,7 +803,7 @@ else:
else: else:
from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK, from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK,
MSG_NOSIGNAL MSG_NOSIGNAL
type type
TAsyncFD* = distinct cint TAsyncFD* = distinct cint
TCallback = proc (fd: TAsyncFD): bool {.closure,gcsafe.} TCallback = proc (fd: TAsyncFD): bool {.closure,gcsafe.}
@ -849,7 +849,7 @@ else:
result = newRawSocket(domain, typ, protocol).TAsyncFD result = newRawSocket(domain, typ, protocol).TAsyncFD
result.SocketHandle.setBlocking(false) result.SocketHandle.setBlocking(false)
register(result) register(result)
proc closeSocket*(sock: TAsyncFD) = proc closeSocket*(sock: TAsyncFD) =
let disp = getGlobalDispatcher() let disp = getGlobalDispatcher()
sock.SocketHandle.close() sock.SocketHandle.close()
@ -864,14 +864,14 @@ else:
raise newException(ValueError, "File descriptor not registered.") raise newException(ValueError, "File descriptor not registered.")
p.selector[fd.SocketHandle].data.PData.readCBs.add(cb) p.selector[fd.SocketHandle].data.PData.readCBs.add(cb)
update(fd, p.selector[fd.SocketHandle].events + {EvRead}) update(fd, p.selector[fd.SocketHandle].events + {EvRead})
proc addWrite*(fd: TAsyncFD, cb: TCallback) = proc addWrite*(fd: TAsyncFD, cb: TCallback) =
let p = getGlobalDispatcher() let p = getGlobalDispatcher()
if fd.SocketHandle notin p.selector: if fd.SocketHandle notin p.selector:
raise newException(ValueError, "File descriptor not registered.") raise newException(ValueError, "File descriptor not registered.")
p.selector[fd.SocketHandle].data.PData.writeCBs.add(cb) p.selector[fd.SocketHandle].data.PData.writeCBs.add(cb)
update(fd, p.selector[fd.SocketHandle].events + {EvWrite}) update(fd, p.selector[fd.SocketHandle].events + {EvWrite})
proc poll*(timeout = 500) = proc poll*(timeout = 500) =
let p = getGlobalDispatcher() let p = getGlobalDispatcher()
for info in p.selector.select(timeout): for info in p.selector.select(timeout):
@ -892,7 +892,7 @@ else:
if not cb(data.fd): if not cb(data.fd):
# Callback wants to be called again. # Callback wants to be called again.
data.readCBs.add(cb) data.readCBs.add(cb)
if EvWrite in info.events: if EvWrite in info.events:
let currentCBs = data.writeCBs let currentCBs = data.writeCBs
data.writeCBs = @[] data.writeCBs = @[]
@ -900,7 +900,7 @@ else:
if not cb(data.fd): if not cb(data.fd):
# Callback wants to be called again. # Callback wants to be called again.
data.writeCBs.add(cb) data.writeCBs.add(cb)
if info.key in p.selector: if info.key in p.selector:
var newEvents: set[Event] var newEvents: set[Event]
if data.readCBs.len != 0: newEvents = {EvRead} if data.readCBs.len != 0: newEvents = {EvRead}
@ -913,16 +913,16 @@ else:
discard discard
processTimers(p) processTimers(p)
proc connect*(socket: TAsyncFD, address: string, port: Port, proc connect*(socket: TAsyncFD, address: string, port: Port,
af = AF_INET): Future[void] = af = AF_INET): Future[void] =
var retFuture = newFuture[void]("connect") var retFuture = newFuture[void]("connect")
proc cb(fd: TAsyncFD): bool = proc cb(fd: TAsyncFD): bool =
# We have connected. # We have connected.
retFuture.complete() retFuture.complete()
return true return true
var aiList = getAddrInfo(address, port, af) var aiList = getAddrInfo(address, port, af)
var success = false var success = false
var lastError: OSErrorCode var lastError: OSErrorCode
@ -952,7 +952,7 @@ else:
proc recv*(socket: TAsyncFD, size: int, proc recv*(socket: TAsyncFD, size: int,
flags = {SocketFlag.SafeDisconn}): Future[string] = flags = {SocketFlag.SafeDisconn}): Future[string] =
var retFuture = newFuture[string]("recv") var retFuture = newFuture[string]("recv")
var readBuffer = newString(size) var readBuffer = newString(size)
proc cb(sock: TAsyncFD): bool = proc cb(sock: TAsyncFD): bool =
@ -983,9 +983,9 @@ else:
proc send*(socket: TAsyncFD, data: string, proc send*(socket: TAsyncFD, data: string,
flags = {SocketFlag.SafeDisconn}): Future[void] = flags = {SocketFlag.SafeDisconn}): Future[void] =
var retFuture = newFuture[void]("send") var retFuture = newFuture[void]("send")
var written = 0 var written = 0
proc cb(sock: TAsyncFD): bool = proc cb(sock: TAsyncFD): bool =
result = true result = true
let netSize = data.len-written let netSize = data.len-written
@ -1222,7 +1222,7 @@ proc processBody(node, retFutureSym: PNimrodNode,
of nnkTryStmt: of nnkTryStmt:
# try: await x; except: ... # try: await x; except: ...
result = newNimNode(nnkStmtList, node) result = newNimNode(nnkStmtList, node)
template wrapInTry(n, tryBody: PNimrodNode) = template wrapInTry(n, tryBody: expr) =
var temp = n var temp = n
n[0] = tryBody n[0] = tryBody
tryBody = temp tryBody = temp
@ -1315,14 +1315,14 @@ macro async*(prc: stmt): stmt {.immediate.} =
if returnType.kind == nnkEmpty: newIdentNode("void") if returnType.kind == nnkEmpty: newIdentNode("void")
else: returnType[1] else: returnType[1]
outerProcBody.add( outerProcBody.add(
newVarStmt(retFutureSym, newVarStmt(retFutureSym,
newCall( newCall(
newNimNode(nnkBracketExpr, prc[6]).add( newNimNode(nnkBracketExpr, prc[6]).add(
newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`. newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`.
subRetType), subRetType),
newLit(prc[0].getName)))) # Get type from return type of this proc newLit(prc[0].getName)))) # Get type from return type of this proc
# -> iterator nameIter(): FutureBase {.closure.} = # -> iterator nameIter(): FutureBase {.closure.} =
# -> var result: T # -> var result: T
# -> <proc_body> # -> <proc_body>
# -> complete(retFuture, result) # -> complete(retFuture, result)
@ -1337,7 +1337,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
else: else:
# -> complete(retFuture) # -> complete(retFuture)
procBody.add(newCall(newIdentNode("complete"), retFutureSym)) procBody.add(newCall(newIdentNode("complete"), retFutureSym))
var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")], var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
procBody, nnkIteratorDef) procBody, nnkIteratorDef)
closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure")) closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure"))
@ -1351,7 +1351,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
# -> return retFuture # -> return retFuture
outerProcBody.add newNimNode(nnkReturnStmt, prc[6][prc[6].len-1]).add(retFutureSym) outerProcBody.add newNimNode(nnkReturnStmt, prc[6][prc[6].len-1]).add(retFutureSym)
result = prc result = prc
# Remove the 'async' pragma. # Remove the 'async' pragma.
@ -1377,7 +1377,7 @@ proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
## If a full line is read ``\r\L`` is not ## If a full line is read ``\r\L`` is not
## added to ``line``, however if solely ``\r\L`` is read then ``line`` ## added to ``line``, however if solely ``\r\L`` is read then ``line``
## will be set to it. ## will be set to it.
## ##
## If the socket is disconnected, ``line`` will be set to ``""``. ## If the socket is disconnected, ``line`` will be set to ``""``.
## ##
## If the socket is disconnected in the middle of a line (before ``\r\L`` ## If the socket is disconnected in the middle of a line (before ``\r\L``
@ -1388,7 +1388,7 @@ proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
## ##
## **Note**: This procedure is mostly used for testing. You likely want to ## **Note**: This procedure is mostly used for testing. You likely want to
## use ``asyncnet.recvLine`` instead. ## use ``asyncnet.recvLine`` instead.
template addNLIfEmpty(): stmt = template addNLIfEmpty(): stmt =
if result.len == 0: if result.len == 0:
result.add("\c\L") result.add("\c\L")

View file

@ -0,0 +1,47 @@
# bug #1940
discard """
nimout: '''===
merge (A) with (B)
merge (A B) with (C)
merge (A B C) with (D)
merge (A B C D) with (E)
merge (A B C D E) with (F)
==='''
"""
type SqlStmt = tuple
sql: string
parts: int
proc sql(q: string): SqlStmt =
result.sql = q
result.parts = 1
template `&%%`(x, y: SqlStmt): SqlStmt =
const a = x
const b = y
static:
#echo "some merge"
echo "merge (", a.sql, ") with (", b.sql, ")"
const newSql = a.sql & " " & b.sql
const newParts = a.parts + b.parts
SqlStmt((sql: newSql, parts: newParts))
static:
echo "==="
let c =(sql("A") &%%
sql("B")) &%%
sql("C") &%%
sql("D") &%%
sql("E") &%%
sql("F")
echo c.sql
static:
echo "==="