mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-12 22:33:49 +00:00
fixes #1940; code breakage! stricter template evaluation
This commit is contained in:
383
compiler/ast.nim
383
compiler/ast.nim
@@ -9,12 +9,12 @@
|
||||
|
||||
# abstract syntax tree + symbol table
|
||||
|
||||
import
|
||||
msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists,
|
||||
import
|
||||
msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists,
|
||||
intsets, idgen
|
||||
|
||||
type
|
||||
TCallingConvention* = enum
|
||||
TCallingConvention* = enum
|
||||
ccDefault, # proc has no explicit calling convention
|
||||
ccStdCall, # procedure is stdcall
|
||||
ccCDecl, # cdecl
|
||||
@@ -26,12 +26,12 @@ type
|
||||
ccClosure, # proc has a closure
|
||||
ccNoConvention # needed for generating proper C procs sometimes
|
||||
|
||||
const
|
||||
CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall",
|
||||
const
|
||||
CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall",
|
||||
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall",
|
||||
"closure", "noconv"]
|
||||
|
||||
type
|
||||
type
|
||||
TNodeKind* = enum # order is extremely important, because ranges are used
|
||||
# to check whether a node belongs to a certain class
|
||||
nkNone, # unknown node kind: indicates an error
|
||||
@@ -64,13 +64,13 @@ type
|
||||
# end of atoms
|
||||
nkMetaNode_Obsolete, # difficult to explain; represents itself
|
||||
# (used for macros)
|
||||
nkDotCall, # used to temporarily flag a nkCall node;
|
||||
nkDotCall, # used to temporarily flag a nkCall node;
|
||||
# this is used
|
||||
# for transforming ``s.len`` to ``len(s)``
|
||||
|
||||
nkCommand, # a call like ``p 2, 4`` without parenthesis
|
||||
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, nkTripleStrLit
|
||||
nkInfix, # a call like (a + b)
|
||||
@@ -126,7 +126,7 @@ type
|
||||
|
||||
nkAsgn, # a = b
|
||||
nkFastAsgn, # internal node for a fast ``a = b``
|
||||
# (no string copy)
|
||||
# (no string copy)
|
||||
nkGenericParams, # generic parameters
|
||||
nkFormalParams, # formal parameters
|
||||
nkOfInherit, # inherited from symbol
|
||||
@@ -192,7 +192,7 @@ type
|
||||
|
||||
nkWith, # distinct with `foo`
|
||||
nkWithout, # distinct without `foo`
|
||||
|
||||
|
||||
nkTypeOfExpr, # type(1+2)
|
||||
nkObjectTy, # object body
|
||||
nkTupleTy, # tuple body
|
||||
@@ -226,7 +226,7 @@ type
|
||||
TSymFlag* = enum # already 32 flags!
|
||||
sfUsed, # read access of sym (for warnings) or simply used
|
||||
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
|
||||
# be written into the ROD file
|
||||
sfGlobal, # symbol is at global scope
|
||||
@@ -284,9 +284,9 @@ const
|
||||
|
||||
sfAnon* = sfDiscardable
|
||||
# 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.
|
||||
|
||||
|
||||
sfNoForward* = sfRegister
|
||||
# forward declarations are not required (per module)
|
||||
|
||||
@@ -300,7 +300,7 @@ const
|
||||
# getting ready for the future expr/stmt merge
|
||||
nkWhen* = nkWhenStmt
|
||||
nkWhenExpr* = nkWhenStmt
|
||||
nkEffectList* = nkArgList
|
||||
nkEffectList* = nkArgList
|
||||
# hacks ahead: an nkEffectList is a node with 4 children:
|
||||
exceptionEffects* = 0 # exceptions at position 0
|
||||
usesEffects* = 1 # read effects at position 1
|
||||
@@ -321,7 +321,7 @@ type
|
||||
# unless this is an instance of a generic alias type.
|
||||
# then realInstance will be the tyGenericInst of the
|
||||
# completely (recursively) resolved alias.
|
||||
|
||||
|
||||
tyGenericParam, # ``a`` in the above patterns
|
||||
tyDistinct,
|
||||
tyEnum,
|
||||
@@ -340,14 +340,14 @@ type
|
||||
tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers
|
||||
tyFloat, tyFloat32, tyFloat64, tyFloat128,
|
||||
tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64,
|
||||
tyBigNum,
|
||||
tyConst, tyMutable, tyVarargs,
|
||||
tyBigNum,
|
||||
tyConst, tyMutable, tyVarargs,
|
||||
tyIter, # unused
|
||||
tyProxy # used as errornous type (for idetools)
|
||||
|
||||
|
||||
tyBuiltInTypeClass #\
|
||||
# Type such as the catch-all object, tuple, seq, etc
|
||||
|
||||
|
||||
tyUserTypeClass #\
|
||||
# the body of a user-defined type class
|
||||
|
||||
@@ -357,24 +357,24 @@ type
|
||||
# tyGenericInst represents concrete types, while
|
||||
# this is still a "generic param" that will bind types
|
||||
# and resolves them during sigmatch and instantiation.
|
||||
|
||||
|
||||
tyCompositeTypeClass #\
|
||||
# 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[1]: fully expanded and instantiated meta type
|
||||
# (potentially following aliases)
|
||||
|
||||
|
||||
tyAnd, tyOr, tyNot #\
|
||||
# boolean type classes such as `string|int`,`not seq`,
|
||||
# `Sortable and Enumable`, etc
|
||||
|
||||
|
||||
tyAnything #\
|
||||
# a type class matching any type
|
||||
|
||||
|
||||
tyStatic #\
|
||||
# a value known at compile type (the underlying type is .base)
|
||||
|
||||
|
||||
tyFromExpr #\
|
||||
# This is a type representing an expression that depends
|
||||
# on generic parameters (the expression is stored in t.n)
|
||||
@@ -390,7 +390,7 @@ type
|
||||
# sons[0]: type of containing object or tuple
|
||||
# sons[1]: field type
|
||||
# .n: nkDotExpr storing the field name
|
||||
|
||||
|
||||
static:
|
||||
# remind us when TTypeKind stops to fit in a single 64-bit word
|
||||
assert TTypeKind.high.ord <= 63
|
||||
@@ -408,7 +408,7 @@ const
|
||||
tyAnd, tyOr, tyNot, tyAnything}
|
||||
|
||||
tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyExpr} + tyTypeClasses
|
||||
|
||||
|
||||
type
|
||||
TTypeKinds* = set[TTypeKind]
|
||||
|
||||
@@ -429,7 +429,7 @@ type
|
||||
nfExprCall # this is an attempt to call a regular expression
|
||||
nfIsRef # this node is a 'ref' node; used for the VM
|
||||
nfIsCursor # this node is attached a cursor; used for idetools
|
||||
|
||||
|
||||
TNodeFlags* = set[TNodeFlag]
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 28)
|
||||
tfVarargs, # procedure has C styled varargs
|
||||
@@ -448,7 +448,7 @@ type
|
||||
# proc foo(L: static[int]): array[L, int]
|
||||
# can be attached to ranges to indicate that the range
|
||||
# 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)
|
||||
tfCapturesEnv, # whether proc really captures some environment
|
||||
tfByCopy, # pass object/tuple by copy (C backend)
|
||||
@@ -456,7 +456,7 @@ type
|
||||
tfIterator, # type is really an iterator, not a tyProc
|
||||
tfShared, # type is 'shared'
|
||||
tfNotNil, # type cannot be 'nil'
|
||||
|
||||
|
||||
tfNeedsInit, # type constains a "not nil" constraint somewhere or some
|
||||
# other type so that it requires inititalization
|
||||
tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode
|
||||
@@ -520,7 +520,7 @@ const
|
||||
tfGcSafe* = tfThread
|
||||
tfObjHasKids* = tfEnumHasHoles
|
||||
skError* = skUnknown
|
||||
|
||||
|
||||
# type flags that are essential for type equality:
|
||||
eqTypeFlags* = {tfIterator, tfShared, tfNotNil, tfVarIsPtr}
|
||||
|
||||
@@ -531,29 +531,29 @@ type
|
||||
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf,
|
||||
mEcho, mShallowCopy, mSlurp, mStaticExec,
|
||||
mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
|
||||
mUnaryLt, 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,
|
||||
mUnaryLt, 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,
|
||||
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,
|
||||
mMinF64, mMaxF64, mAddU, mSubU, mMulU,
|
||||
mMinF64, mMaxF64, mAddU, mSubU, mMulU,
|
||||
mDivU, mModU, mEqI, mLeI,
|
||||
mLtI,
|
||||
mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
|
||||
mLeU, mLtU, mLeU64, mLtU64,
|
||||
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
|
||||
mLtI,
|
||||
mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
|
||||
mLeU, mLtU, mLeU64, mLtU64,
|
||||
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
|
||||
mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mEqProc, mUnaryMinusI,
|
||||
mUnaryMinusI64, mAbsI, mAbsI64, mNot,
|
||||
mUnaryPlusI, mBitnotI, mUnaryPlusI64,
|
||||
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
|
||||
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
||||
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
|
||||
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
|
||||
mUnaryMinusI64, mAbsI, mAbsI64, mNot,
|
||||
mUnaryPlusI, mBitnotI, mUnaryPlusI64,
|
||||
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
|
||||
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
||||
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
|
||||
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
|
||||
mConTArr, mConTT, mSlice,
|
||||
mFields, mFieldPairs, mOmpParFor,
|
||||
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||
@@ -584,36 +584,36 @@ type
|
||||
|
||||
# things that we can evaluate safely at compile time, even if not asked for it:
|
||||
const
|
||||
ctfeWhitelist* = {mNone, mUnaryLt, mSucc,
|
||||
mPred, mInc, mDec, mOrd, mLengthOpenArray,
|
||||
mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr,
|
||||
mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
|
||||
ctfeWhitelist* = {mNone, mUnaryLt, mSucc,
|
||||
mPred, mInc, mDec, mOrd, mLengthOpenArray,
|
||||
mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr,
|
||||
mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
|
||||
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,
|
||||
mMinF64, mMaxF64, mAddU, mSubU, mMulU,
|
||||
mMinF64, mMaxF64, mAddU, mSubU, mMulU,
|
||||
mDivU, mModU, mEqI, mLeI,
|
||||
mLtI,
|
||||
mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
|
||||
mLeU, mLtU, mLeU64, mLtU64,
|
||||
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
|
||||
mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI,
|
||||
mUnaryMinusI64, mAbsI, mAbsI64, mNot,
|
||||
mUnaryPlusI, mBitnotI, mUnaryPlusI64,
|
||||
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
|
||||
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
||||
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
|
||||
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
|
||||
mLtI,
|
||||
mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
|
||||
mLeU, mLtU, mLeU64, mLtU64,
|
||||
mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
|
||||
mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI,
|
||||
mUnaryMinusI64, mAbsI, mAbsI64, mNot,
|
||||
mUnaryPlusI, mBitnotI, mUnaryPlusI64,
|
||||
mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
|
||||
mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
|
||||
mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
|
||||
mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
|
||||
mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
|
||||
mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT,
|
||||
mConTArr, mConTT,
|
||||
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||
mAppendStrCh, mAppendStrStr, mAppendSeqElem,
|
||||
mInRange, mInSet, mRepr,
|
||||
mCopyStr, mCopyStrLast}
|
||||
# magics that require special semantic checking and
|
||||
# thus cannot be overloaded (also documented in the spec!):
|
||||
SpecialSemMagics* = {
|
||||
mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf,
|
||||
mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf,
|
||||
mEcho, mShallowCopy, mExpandToAst, mParallel, mSpawn, mAstToStr}
|
||||
|
||||
type
|
||||
@@ -634,21 +634,21 @@ type
|
||||
floatVal*: BiggestFloat
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
strVal*: string
|
||||
of nkSym:
|
||||
of nkSym:
|
||||
sym*: PSym
|
||||
of nkIdent:
|
||||
of nkIdent:
|
||||
ident*: PIdent
|
||||
else:
|
||||
sons*: TNodeSeq
|
||||
comment*: string
|
||||
|
||||
|
||||
TSymSeq* = seq[PSym]
|
||||
TStrTable* = object # a table[PIdent] of PSym
|
||||
counter*: int
|
||||
data*: TSymSeq
|
||||
|
||||
|
||||
# -------------- backend information -------------------------------
|
||||
TLocKind* = enum
|
||||
TLocKind* = enum
|
||||
locNone, # no location
|
||||
locTemp, # temporary location
|
||||
locLocalVar, # location is a local variable
|
||||
@@ -660,7 +660,7 @@ type
|
||||
locData, # location is a constant
|
||||
locCall, # location is a call expression
|
||||
locOther # location is something other
|
||||
TLocFlag* = enum
|
||||
TLocFlag* = enum
|
||||
lfIndirect, # backend introduced a pointer
|
||||
lfParamCopy, # backend introduced a parameter copy (LLVM)
|
||||
lfNoDeepCopy, # no need for a deep copy
|
||||
@@ -670,13 +670,13 @@ type
|
||||
lfHeader, # include header file for symbol
|
||||
lfImportCompilerProc, # ``importc`` of a compilerproc
|
||||
lfSingleUse # no location yet and will only be used once
|
||||
TStorageLoc* = enum
|
||||
TStorageLoc* = enum
|
||||
OnUnknown, # location is unknown (stack, heap or static)
|
||||
OnStack, # location is on hardware stack
|
||||
OnHeap # location is on heap or global
|
||||
# (reference counting needed)
|
||||
TLocFlags* = set[TLocFlag]
|
||||
TLoc* = object
|
||||
TLoc* = object
|
||||
k*: TLocKind # kind of location
|
||||
s*: TStorageLoc
|
||||
flags*: TLocFlags # location's flags
|
||||
@@ -688,7 +688,7 @@ type
|
||||
|
||||
# ---------------- end of backend information ------------------------------
|
||||
|
||||
TLibKind* = enum
|
||||
TLibKind* = enum
|
||||
libHeader, libDynamic
|
||||
TLib* = object of lists.TListEntry # also misused for headers!
|
||||
kind*: TLibKind
|
||||
@@ -696,17 +696,17 @@ type
|
||||
isOverriden*: bool
|
||||
name*: PRope
|
||||
path*: PNode # can be a string literal!
|
||||
|
||||
|
||||
TInstantiation* = object
|
||||
sym*: PSym
|
||||
concreteTypes*: seq[PType]
|
||||
usedBy*: seq[int32] # list of modules using the generic
|
||||
# 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
|
||||
|
||||
|
||||
PInstantiation* = ref TInstantiation
|
||||
|
||||
|
||||
TScope* = object
|
||||
depthLevel*: int
|
||||
symbols*: TStrTable
|
||||
@@ -773,7 +773,7 @@ type
|
||||
constraint*: PNode # additional constraints like 'lit|result'; also
|
||||
# misused for the codegenDecl pragma in the hope
|
||||
# it won't cause problems
|
||||
|
||||
|
||||
TTypeSeq* = seq[PType]
|
||||
TLockLevel* = distinct int16
|
||||
TType* {.acyclic.} = object of TIdObj # \
|
||||
@@ -806,7 +806,7 @@ type
|
||||
lockLevel*: TLockLevel # lock level as required for deadlock checking
|
||||
loc*: TLoc
|
||||
|
||||
TPair*{.final.} = object
|
||||
TPair*{.final.} = object
|
||||
key*, val*: RootRef
|
||||
|
||||
TPairSeq* = seq[TPair]
|
||||
@@ -814,7 +814,7 @@ type
|
||||
counter*: int
|
||||
data*: TPairSeq
|
||||
|
||||
TIdPair*{.final.} = object
|
||||
TIdPair*{.final.} = object
|
||||
key*: PIdObj
|
||||
val*: RootRef
|
||||
|
||||
@@ -823,7 +823,7 @@ type
|
||||
counter*: int
|
||||
data*: TIdPairSeq
|
||||
|
||||
TIdNodePair*{.final.} = object
|
||||
TIdNodePair*{.final.} = object
|
||||
key*: PIdObj
|
||||
val*: PNode
|
||||
|
||||
@@ -832,7 +832,7 @@ type
|
||||
counter*: int
|
||||
data*: TIdNodePairSeq
|
||||
|
||||
TNodePair*{.final.} = object
|
||||
TNodePair*{.final.} = object
|
||||
h*: THash # because it is expensive to compute!
|
||||
key*: PNode
|
||||
val*: int
|
||||
@@ -844,7 +844,7 @@ type
|
||||
data*: TNodePairSeq
|
||||
|
||||
TObjectSeq* = seq[RootRef]
|
||||
TObjectSet*{.final.} = object
|
||||
TObjectSet*{.final.} = object
|
||||
counter*: int
|
||||
data*: TObjectSeq
|
||||
|
||||
@@ -855,27 +855,27 @@ type
|
||||
# same name as an imported module. This is necessary because of
|
||||
# the poor naming choices in the standard library.
|
||||
|
||||
const
|
||||
const
|
||||
OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator,
|
||||
skConverter, skModule, skTemplate, skMacro}
|
||||
|
||||
GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody,
|
||||
GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody,
|
||||
tyGenericParam}
|
||||
|
||||
StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray,
|
||||
|
||||
StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray,
|
||||
tySet, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyOpenArray,
|
||||
tyVarargs}
|
||||
|
||||
|
||||
ConcreteTypes*: TTypeKinds = { # types of the expr that may occur in::
|
||||
# var x = expr
|
||||
tyBool, tyChar, tyEnum, tyArray, tyObject,
|
||||
tyBool, tyChar, tyEnum, tyArray, tyObject,
|
||||
tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc,
|
||||
tyPointer,
|
||||
tyPointer,
|
||||
tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||
tyUInt..tyUInt64}
|
||||
IntegralTypes* = {tyBool, tyChar, tyEnum, tyInt..tyInt64,
|
||||
tyFloat..tyFloat128, tyUInt..tyUInt64}
|
||||
ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet,
|
||||
ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet,
|
||||
tyTuple, tySequence}
|
||||
NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence,
|
||||
tyProc, tyString, tyError}
|
||||
@@ -926,17 +926,17 @@ proc discardSons*(father: PNode)
|
||||
proc len*(n: PNode): int {.inline.} =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
|
||||
proc safeLen*(n: PNode): int {.inline.} =
|
||||
## works even for leaves.
|
||||
if n.kind in {nkNone..nkNilLit} or isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
|
||||
proc add*(father, son: PNode) =
|
||||
assert son != nil
|
||||
if isNil(father.sons): father.sons = @[]
|
||||
add(father.sons, son)
|
||||
|
||||
|
||||
proc `[]`*(n: PNode, i: int): PNode {.inline.} =
|
||||
result = n.sons[i]
|
||||
|
||||
@@ -946,13 +946,10 @@ template `{}=`*(n: PNode, i: int, s: PNode): stmt =
|
||||
n.sons[i -| n] = s
|
||||
|
||||
when defined(useNodeIds):
|
||||
const nodeIdToDebug* = -1 # 884953 # 612794
|
||||
#612840 # 612905 # 614635 # 614637 # 614641
|
||||
# 423408
|
||||
#429107 # 430443 # 441048 # 441090 # 441153
|
||||
const nodeIdToDebug* = -1 # 299750 # 300761 #300863 # 300879
|
||||
var gNodeId: int
|
||||
|
||||
proc newNode*(kind: TNodeKind): PNode =
|
||||
proc newNode*(kind: TNodeKind): PNode =
|
||||
new(result)
|
||||
result.kind = kind
|
||||
#result.info = UnknownLineInfo() inlined:
|
||||
@@ -966,24 +963,24 @@ proc newNode*(kind: TNodeKind): PNode =
|
||||
writeStackTrace()
|
||||
inc gNodeId
|
||||
|
||||
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
|
||||
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
|
||||
result = newNode(kind)
|
||||
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.typ = typ
|
||||
|
||||
proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode =
|
||||
proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode =
|
||||
result = newNode(kind)
|
||||
result.floatVal = floatVal
|
||||
|
||||
proc newStrNode*(kind: TNodeKind, strVal: string): PNode =
|
||||
proc newStrNode*(kind: TNodeKind, strVal: string): PNode =
|
||||
result = newNode(kind)
|
||||
result.strVal = strVal
|
||||
|
||||
proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
|
||||
info: TLineInfo): PSym =
|
||||
info: TLineInfo): PSym =
|
||||
# generates a symbol and initializes the hash field too
|
||||
new(result)
|
||||
result.name = name
|
||||
@@ -994,7 +991,7 @@ proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
|
||||
result.owner = owner
|
||||
result.offset = - 1
|
||||
result.id = getID()
|
||||
when debugIds:
|
||||
when debugIds:
|
||||
registerId(result)
|
||||
#if result.id < 2000:
|
||||
# MessageOut(name.s & " has id: " & toString(result.id))
|
||||
@@ -1036,54 +1033,54 @@ proc appendToModule*(m: PSym, n: PNode) =
|
||||
else:
|
||||
assert m.ast.kind == nkStmtList
|
||||
m.ast.sons.add(n)
|
||||
|
||||
|
||||
const # for all kind of hash tables:
|
||||
GrowthFactor* = 2 # 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
|
||||
if isNil(src.data): return
|
||||
if isNil(src.data): return
|
||||
setLen(dest.data, len(src.data))
|
||||
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
|
||||
if isNil(src.data): return
|
||||
if isNil(src.data): return
|
||||
newSeq(dest.data, len(src.data))
|
||||
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
|
||||
if isNil(src.data): return
|
||||
if isNil(src.data): return
|
||||
setLen(dest.data, len(src.data))
|
||||
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
|
||||
if isNil(src.data): return
|
||||
if isNil(src.data): return
|
||||
setLen(dest.data, len(src.data))
|
||||
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
|
||||
|
||||
proc withInfo*(n: PNode, info: TLineInfo): PNode =
|
||||
n.info = info
|
||||
return n
|
||||
|
||||
proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode =
|
||||
proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode =
|
||||
result = newNode(nkIdent)
|
||||
result.ident = ident
|
||||
result.info = info
|
||||
|
||||
proc newSymNode*(sym: PSym): PNode =
|
||||
proc newSymNode*(sym: PSym): PNode =
|
||||
result = newNode(nkSym)
|
||||
result.sym = sym
|
||||
result.typ = sym.typ
|
||||
result.info = sym.info
|
||||
|
||||
proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
|
||||
proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
|
||||
result = newNode(nkSym)
|
||||
result.sym = sym
|
||||
result.typ = sym.typ
|
||||
@@ -1128,12 +1125,12 @@ proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[],
|
||||
writeStackTrace()
|
||||
inc gNodeId
|
||||
|
||||
proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
|
||||
proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
|
||||
result = newNode(kind)
|
||||
result.info = info
|
||||
result.typ = typ
|
||||
|
||||
proc addSon*(father, son: PNode) =
|
||||
proc addSon*(father, son: PNode) =
|
||||
assert son != nil
|
||||
if isNil(father.sons): father.sons = @[]
|
||||
add(father.sons, son)
|
||||
@@ -1159,7 +1156,7 @@ proc `$`*(x: TLockLevel): string =
|
||||
elif x.ord == UnknownLockLevel.ord: result = "<unknown>"
|
||||
else: result = $int16(x)
|
||||
|
||||
proc newType*(kind: TTypeKind, owner: PSym): PType =
|
||||
proc newType*(kind: TTypeKind, owner: PSym): PType =
|
||||
new(result)
|
||||
result.kind = kind
|
||||
result.owner = owner
|
||||
@@ -1171,7 +1168,7 @@ proc newType*(kind: TTypeKind, owner: PSym): PType =
|
||||
registerId(result)
|
||||
#if result.id < 2000:
|
||||
# messageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
|
||||
|
||||
|
||||
proc mergeLoc(a: var TLoc, b: TLoc) =
|
||||
if a.k == low(a.k): a.k = b.k
|
||||
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.a == 0: a.a = b.a
|
||||
|
||||
proc newSons*(father: PNode, length: int) =
|
||||
if isNil(father.sons):
|
||||
proc newSons*(father: PNode, length: int) =
|
||||
if isNil(father.sons):
|
||||
newSeq(father.sons, length)
|
||||
else:
|
||||
setLen(father.sons, length)
|
||||
|
||||
proc newSons*(father: PType, length: int) =
|
||||
if isNil(father.sons):
|
||||
proc newSons*(father: PType, length: int) =
|
||||
if isNil(father.sons):
|
||||
newSeq(father.sons, length)
|
||||
else:
|
||||
setLen(father.sons, length)
|
||||
|
||||
proc sonsLen*(n: PType): int =
|
||||
proc sonsLen*(n: PType): int =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc len*(n: PType): int =
|
||||
proc len*(n: PType): int =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc sonsLen*(n: PNode): int =
|
||||
|
||||
proc sonsLen*(n: PNode): int =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc lastSon*(n: PNode): PNode =
|
||||
|
||||
proc lastSon*(n: PNode): PNode =
|
||||
result = n.sons[sonsLen(n) - 1]
|
||||
|
||||
proc lastSon*(n: PType): PType =
|
||||
proc lastSon*(n: PType): PType =
|
||||
result = n.sons[sonsLen(n) - 1]
|
||||
|
||||
proc assignType*(dest, src: PType) =
|
||||
proc assignType*(dest, src: PType) =
|
||||
dest.kind = src.kind
|
||||
dest.flags = src.flags
|
||||
dest.callConv = src.callConv
|
||||
@@ -1230,23 +1227,23 @@ proc assignType*(dest, src: PType) =
|
||||
dest.sym = src.sym
|
||||
newSons(dest, sonsLen(src))
|
||||
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)
|
||||
assignType(result, t)
|
||||
if keepId:
|
||||
if keepId:
|
||||
result.id = t.id
|
||||
else:
|
||||
else:
|
||||
when debugIds: registerId(result)
|
||||
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.ast = nil # BUGFIX; was: s.ast which made problems
|
||||
result.typ = s.typ
|
||||
if keepId:
|
||||
result.id = s.id
|
||||
else:
|
||||
else:
|
||||
result.id = getID()
|
||||
when debugIds: registerId(result)
|
||||
result.flags = s.flags
|
||||
@@ -1273,19 +1270,19 @@ proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym =
|
||||
result.annex = s.annex
|
||||
# XXX once usedGenerics is used, ensure module aliases keep working!
|
||||
assert s.usedGenerics == nil
|
||||
|
||||
proc initStrTable*(x: var TStrTable) =
|
||||
|
||||
proc initStrTable*(x: var TStrTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc newStrTable*: TStrTable =
|
||||
initStrTable(result)
|
||||
|
||||
proc initTable(x: var TTable) =
|
||||
proc initTable(x: var TTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc initIdTable*(x: var TIdTable) =
|
||||
proc initIdTable*(x: var TIdTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
@@ -1295,15 +1292,15 @@ proc resetIdTable*(x: var TIdTable) =
|
||||
setLen(x.data, 0)
|
||||
setLen(x.data, StartSize)
|
||||
|
||||
proc initObjectSet*(x: var TObjectSet) =
|
||||
proc initObjectSet*(x: var TObjectSet) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc initIdNodeTable*(x: var TIdNodeTable) =
|
||||
proc initIdNodeTable*(x: var TIdNodeTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc initNodeTable*(x: var TNodeTable) =
|
||||
proc initNodeTable*(x: var TNodeTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
@@ -1327,11 +1324,11 @@ proc propagateToOwner*(owner, elem: PType) =
|
||||
owner.flags.incl tfNotNil
|
||||
elif owner.kind notin HaveTheirOwnEmpty:
|
||||
owner.flags.incl tfNeedsInit
|
||||
|
||||
|
||||
if tfNeedsInit in elem.flags:
|
||||
if owner.kind in HaveTheirOwnEmpty: discard
|
||||
else: owner.flags.incl tfNeedsInit
|
||||
|
||||
|
||||
if elem.isMetaType:
|
||||
owner.flags.incl tfHasMeta
|
||||
|
||||
@@ -1348,15 +1345,15 @@ proc addSonNilAllowed*(father, son: PNode) =
|
||||
if isNil(father.sons): father.sons = @[]
|
||||
add(father.sons, son)
|
||||
|
||||
proc delSon*(father: PNode, idx: int) =
|
||||
if isNil(father.sons): return
|
||||
proc delSon*(father: PNode, idx: int) =
|
||||
if isNil(father.sons): return
|
||||
var length = sonsLen(father)
|
||||
for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1]
|
||||
setLen(father.sons, length - 1)
|
||||
|
||||
proc copyNode*(src: PNode): PNode =
|
||||
proc copyNode*(src: PNode): PNode =
|
||||
# does not copy its sons!
|
||||
if src == nil:
|
||||
if src == nil:
|
||||
return nil
|
||||
result = newNode(src.kind)
|
||||
result.info = src.info
|
||||
@@ -1373,7 +1370,7 @@ proc copyNode*(src: PNode): PNode =
|
||||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
else: discard
|
||||
|
||||
proc shallowCopy*(src: PNode): PNode =
|
||||
proc shallowCopy*(src: PNode): PNode =
|
||||
# does not copy its sons, but provides space for them:
|
||||
if src == nil: return nil
|
||||
result = newNode(src.kind)
|
||||
@@ -1391,9 +1388,9 @@ proc shallowCopy*(src: PNode): PNode =
|
||||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
else: newSeq(result.sons, sonsLen(src))
|
||||
|
||||
proc copyTree*(src: PNode): PNode =
|
||||
proc copyTree*(src: PNode): PNode =
|
||||
# copy a whole syntax tree; performs deep copying
|
||||
if src == nil:
|
||||
if src == nil:
|
||||
return nil
|
||||
result = newNode(src.kind)
|
||||
result.info = src.info
|
||||
@@ -1408,20 +1405,20 @@ proc copyTree*(src: PNode): PNode =
|
||||
of nkSym: result.sym = src.sym
|
||||
of nkIdent: result.ident = src.ident
|
||||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
else:
|
||||
else:
|
||||
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])
|
||||
|
||||
proc hasSonWith*(n: PNode, kind: TNodeKind): bool =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i].kind == kind:
|
||||
proc hasSonWith*(n: PNode, kind: TNodeKind): bool =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i].kind == kind:
|
||||
return true
|
||||
result = false
|
||||
|
||||
proc hasNilSon*(n: PNode): bool =
|
||||
for i in countup(0, safeLen(n) - 1):
|
||||
if n.sons[i] == nil:
|
||||
proc hasNilSon*(n: PNode): bool =
|
||||
for i in countup(0, safeLen(n) - 1):
|
||||
if n.sons[i] == nil:
|
||||
return true
|
||||
elif hasNilSon(n.sons[i]):
|
||||
return true
|
||||
@@ -1435,47 +1432,47 @@ proc containsNode*(n: PNode, kinds: TNodeKinds): bool =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
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
|
||||
of nkEmpty..nkNilLit: result = n.kind == kind
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if (n.sons[i].kind == kind) or hasSubnodeWith(n.sons[i], kind):
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if (n.sons[i].kind == kind) or hasSubnodeWith(n.sons[i], kind):
|
||||
return true
|
||||
result = false
|
||||
|
||||
proc replaceSons(n: PNode, oldKind, newKind: TNodeKind) =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
proc replaceSons(n: PNode, oldKind, newKind: TNodeKind) =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i].kind == oldKind: n.sons[i].kind = newKind
|
||||
|
||||
proc sonsNotNil(n: PNode): bool =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i] == nil:
|
||||
|
||||
proc sonsNotNil(n: PNode): bool =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i] == nil:
|
||||
return false
|
||||
result = true
|
||||
|
||||
proc getInt*(a: PNode): BiggestInt =
|
||||
proc getInt*(a: PNode): BiggestInt =
|
||||
case a.kind
|
||||
of nkIntLit..nkUInt64Lit: result = a.intVal
|
||||
else:
|
||||
else:
|
||||
internalError(a.info, "getInt")
|
||||
result = 0
|
||||
|
||||
proc getFloat*(a: PNode): BiggestFloat =
|
||||
proc getFloat*(a: PNode): BiggestFloat =
|
||||
case a.kind
|
||||
of nkFloatLit..nkFloat128Lit: result = a.floatVal
|
||||
else:
|
||||
else:
|
||||
internalError(a.info, "getFloat")
|
||||
result = 0.0
|
||||
|
||||
proc getStr*(a: PNode): string =
|
||||
proc getStr*(a: PNode): string =
|
||||
case a.kind
|
||||
of nkStrLit..nkTripleStrLit: result = a.strVal
|
||||
else:
|
||||
else:
|
||||
internalError(a.info, "getStr")
|
||||
result = ""
|
||||
|
||||
proc getStrOrChar*(a: PNode): string =
|
||||
proc getStrOrChar*(a: PNode): string =
|
||||
case a.kind
|
||||
of nkStrLit..nkTripleStrLit: result = a.strVal
|
||||
of nkCharLit..nkUInt64Lit: result = $chr(int(a.intVal))
|
||||
@@ -1483,7 +1480,7 @@ proc getStrOrChar*(a: PNode): string =
|
||||
internalError(a.info, "getStrOrChar")
|
||||
result = ""
|
||||
|
||||
proc isGenericRoutine*(s: PSym): bool =
|
||||
proc isGenericRoutine*(s: PSym): bool =
|
||||
case s.kind
|
||||
of skProcKinds:
|
||||
result = sfFromGeneric in s.flags or
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## Template evaluation engine. Now hygienic.
|
||||
|
||||
import
|
||||
strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer,
|
||||
strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer,
|
||||
rodread
|
||||
|
||||
type
|
||||
@@ -49,7 +49,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
||||
result.add copyNode(c, templ, actual)
|
||||
else:
|
||||
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)
|
||||
result.add res
|
||||
|
||||
@@ -86,9 +86,9 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
|
||||
ctx.owner = tmpl
|
||||
ctx.genSymOwner = genSymOwner
|
||||
initIdTable(ctx.mapping)
|
||||
|
||||
|
||||
let body = tmpl.getBody
|
||||
if isAtom(body):
|
||||
if isAtom(body):
|
||||
result = newNodeI(nkPar, body.info)
|
||||
evalTemplateAux(body, args, ctx, result)
|
||||
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
|
||||
for i in countup(0, safeLen(body) - 1):
|
||||
evalTemplateAux(body.sons[i], args, ctx, result)
|
||||
|
||||
|
||||
dec(evalTemplateCounter)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1232,7 +1232,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||
elif f.kind == tyStatic:
|
||||
return arg.typ.n
|
||||
else:
|
||||
return argOrig
|
||||
return argSemantized # argOrig
|
||||
|
||||
if r != isNone and f.isInlineIterator:
|
||||
var inlined = newTypeS(tyStatic, c)
|
||||
|
||||
@@ -121,7 +121,7 @@ export Port, SocketFlag
|
||||
##
|
||||
## Limitations/Bugs
|
||||
## ----------------
|
||||
##
|
||||
##
|
||||
## * ``except`` statement (without `try`) does not work inside async procedures.
|
||||
## * The effect system (``raises: []``) does not work with async procedures.
|
||||
## * 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:
|
||||
raise newException(ValueError,
|
||||
"No handles or timers registered in dispatcher.")
|
||||
|
||||
|
||||
let llTimeout =
|
||||
if timeout == -1: winlean.INFINITE
|
||||
else: timeout.int32
|
||||
@@ -436,12 +436,12 @@ when defined(windows) or defined(nimdoc):
|
||||
if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS):
|
||||
raiseOSError(osLastError())
|
||||
|
||||
proc connectEx(s: SocketHandle, name: ptr SockAddr, namelen: cint,
|
||||
proc connectEx(s: SocketHandle, name: ptr SockAddr, namelen: cint,
|
||||
lpSendBuffer: pointer, dwSendDataLength: Dword,
|
||||
lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool =
|
||||
if connectExPtr.isNil: raise newException(ValueError, "Need to initialise ConnectEx().")
|
||||
let fun =
|
||||
cast[proc (s: SocketHandle, name: ptr SockAddr, namelen: cint,
|
||||
cast[proc (s: SocketHandle, name: ptr SockAddr, namelen: cint,
|
||||
lpSendBuffer: pointer, dwSendDataLength: Dword,
|
||||
lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](connectExPtr)
|
||||
|
||||
@@ -475,7 +475,7 @@ when defined(windows) or defined(nimdoc):
|
||||
dwRemoteAddressLength: Dword, LocalSockaddr: ptr ptr SockAddr,
|
||||
LocalSockaddrLength: LPInt, RemoteSockaddr: ptr ptr SockAddr,
|
||||
RemoteSockaddrLength: LPInt) {.stdcall,gcsafe.}](getAcceptExSockAddrsPtr)
|
||||
|
||||
|
||||
fun(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength,
|
||||
dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength,
|
||||
RemoteSockaddr, RemoteSockaddrLength)
|
||||
@@ -514,7 +514,7 @@ when defined(windows) or defined(nimdoc):
|
||||
else:
|
||||
retFuture.fail(newException(OSError, osErrorMsg(errcode)))
|
||||
)
|
||||
|
||||
|
||||
var ret = connectEx(socket.SocketHandle, it.ai_addr,
|
||||
sizeof(Sockaddr_in).cint, nil, 0, nil,
|
||||
cast[POVERLAPPED](ol))
|
||||
@@ -565,7 +565,7 @@ when defined(windows) or defined(nimdoc):
|
||||
var dataBuf: TWSABuf
|
||||
dataBuf.buf = cast[cstring](alloc0(size))
|
||||
dataBuf.len = size
|
||||
|
||||
|
||||
var bytesReceived: Dword
|
||||
var flagsio = flags.toOSFlags().Dword
|
||||
var ol = PCustomOverlapped()
|
||||
@@ -612,9 +612,9 @@ when defined(windows) or defined(nimdoc):
|
||||
# the empty string (which signals a disconnection) when there is
|
||||
# nothing left to read.
|
||||
retFuture.complete("")
|
||||
# TODO: "For message-oriented sockets, where a zero byte message is often
|
||||
# allowable, a failure with an error code of WSAEDISCON is used to
|
||||
# indicate graceful closure."
|
||||
# TODO: "For message-oriented sockets, where a zero byte message is often
|
||||
# allowable, a failure with an error code of WSAEDISCON is used to
|
||||
# indicate graceful closure."
|
||||
# ~ http://msdn.microsoft.com/en-us/library/ms741688%28v=vs.85%29.aspx
|
||||
else:
|
||||
# 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
|
||||
let ret = acceptEx(socket.SocketHandle, clientSock, addr lpOutputBuf[0],
|
||||
dwReceiveDataLength,
|
||||
dwReceiveDataLength,
|
||||
dwLocalAddressLength,
|
||||
dwRemoteAddressLength,
|
||||
addr dwBytesReceived, cast[POVERLAPPED](ol))
|
||||
@@ -803,7 +803,7 @@ else:
|
||||
else:
|
||||
from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK,
|
||||
MSG_NOSIGNAL
|
||||
|
||||
|
||||
type
|
||||
TAsyncFD* = distinct cint
|
||||
TCallback = proc (fd: TAsyncFD): bool {.closure,gcsafe.}
|
||||
@@ -849,7 +849,7 @@ else:
|
||||
result = newRawSocket(domain, typ, protocol).TAsyncFD
|
||||
result.SocketHandle.setBlocking(false)
|
||||
register(result)
|
||||
|
||||
|
||||
proc closeSocket*(sock: TAsyncFD) =
|
||||
let disp = getGlobalDispatcher()
|
||||
sock.SocketHandle.close()
|
||||
@@ -864,14 +864,14 @@ else:
|
||||
raise newException(ValueError, "File descriptor not registered.")
|
||||
p.selector[fd.SocketHandle].data.PData.readCBs.add(cb)
|
||||
update(fd, p.selector[fd.SocketHandle].events + {EvRead})
|
||||
|
||||
|
||||
proc addWrite*(fd: TAsyncFD, cb: TCallback) =
|
||||
let p = getGlobalDispatcher()
|
||||
if fd.SocketHandle notin p.selector:
|
||||
raise newException(ValueError, "File descriptor not registered.")
|
||||
p.selector[fd.SocketHandle].data.PData.writeCBs.add(cb)
|
||||
update(fd, p.selector[fd.SocketHandle].events + {EvWrite})
|
||||
|
||||
|
||||
proc poll*(timeout = 500) =
|
||||
let p = getGlobalDispatcher()
|
||||
for info in p.selector.select(timeout):
|
||||
@@ -892,7 +892,7 @@ else:
|
||||
if not cb(data.fd):
|
||||
# Callback wants to be called again.
|
||||
data.readCBs.add(cb)
|
||||
|
||||
|
||||
if EvWrite in info.events:
|
||||
let currentCBs = data.writeCBs
|
||||
data.writeCBs = @[]
|
||||
@@ -900,7 +900,7 @@ else:
|
||||
if not cb(data.fd):
|
||||
# Callback wants to be called again.
|
||||
data.writeCBs.add(cb)
|
||||
|
||||
|
||||
if info.key in p.selector:
|
||||
var newEvents: set[Event]
|
||||
if data.readCBs.len != 0: newEvents = {EvRead}
|
||||
@@ -913,16 +913,16 @@ else:
|
||||
discard
|
||||
|
||||
processTimers(p)
|
||||
|
||||
|
||||
proc connect*(socket: TAsyncFD, address: string, port: Port,
|
||||
af = AF_INET): Future[void] =
|
||||
var retFuture = newFuture[void]("connect")
|
||||
|
||||
|
||||
proc cb(fd: TAsyncFD): bool =
|
||||
# We have connected.
|
||||
retFuture.complete()
|
||||
return true
|
||||
|
||||
|
||||
var aiList = getAddrInfo(address, port, af)
|
||||
var success = false
|
||||
var lastError: OSErrorCode
|
||||
@@ -952,7 +952,7 @@ else:
|
||||
proc recv*(socket: TAsyncFD, size: int,
|
||||
flags = {SocketFlag.SafeDisconn}): Future[string] =
|
||||
var retFuture = newFuture[string]("recv")
|
||||
|
||||
|
||||
var readBuffer = newString(size)
|
||||
|
||||
proc cb(sock: TAsyncFD): bool =
|
||||
@@ -983,9 +983,9 @@ else:
|
||||
proc send*(socket: TAsyncFD, data: string,
|
||||
flags = {SocketFlag.SafeDisconn}): Future[void] =
|
||||
var retFuture = newFuture[void]("send")
|
||||
|
||||
|
||||
var written = 0
|
||||
|
||||
|
||||
proc cb(sock: TAsyncFD): bool =
|
||||
result = true
|
||||
let netSize = data.len-written
|
||||
@@ -1222,7 +1222,7 @@ proc processBody(node, retFutureSym: PNimrodNode,
|
||||
of nnkTryStmt:
|
||||
# try: await x; except: ...
|
||||
result = newNimNode(nnkStmtList, node)
|
||||
template wrapInTry(n, tryBody: PNimrodNode) =
|
||||
template wrapInTry(n, tryBody: expr) =
|
||||
var temp = n
|
||||
n[0] = tryBody
|
||||
tryBody = temp
|
||||
@@ -1315,14 +1315,14 @@ macro async*(prc: stmt): stmt {.immediate.} =
|
||||
if returnType.kind == nnkEmpty: newIdentNode("void")
|
||||
else: returnType[1]
|
||||
outerProcBody.add(
|
||||
newVarStmt(retFutureSym,
|
||||
newVarStmt(retFutureSym,
|
||||
newCall(
|
||||
newNimNode(nnkBracketExpr, prc[6]).add(
|
||||
newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`.
|
||||
subRetType),
|
||||
newLit(prc[0].getName)))) # Get type from return type of this proc
|
||||
|
||||
# -> iterator nameIter(): FutureBase {.closure.} =
|
||||
|
||||
# -> iterator nameIter(): FutureBase {.closure.} =
|
||||
# -> var result: T
|
||||
# -> <proc_body>
|
||||
# -> complete(retFuture, result)
|
||||
@@ -1337,7 +1337,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
|
||||
else:
|
||||
# -> complete(retFuture)
|
||||
procBody.add(newCall(newIdentNode("complete"), retFutureSym))
|
||||
|
||||
|
||||
var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
|
||||
procBody, nnkIteratorDef)
|
||||
closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure"))
|
||||
@@ -1351,7 +1351,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
|
||||
|
||||
# -> return retFuture
|
||||
outerProcBody.add newNimNode(nnkReturnStmt, prc[6][prc[6].len-1]).add(retFutureSym)
|
||||
|
||||
|
||||
result = prc
|
||||
|
||||
# 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
|
||||
## added to ``line``, however if solely ``\r\L`` is read then ``line``
|
||||
## will be set to it.
|
||||
##
|
||||
##
|
||||
## If the socket is disconnected, ``line`` will be set to ``""``.
|
||||
##
|
||||
## 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
|
||||
## use ``asyncnet.recvLine`` instead.
|
||||
|
||||
|
||||
template addNLIfEmpty(): stmt =
|
||||
if result.len == 0:
|
||||
result.add("\c\L")
|
||||
|
||||
47
tests/template/texponential_eval.nim
Normal file
47
tests/template/texponential_eval.nim
Normal 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 "==="
|
||||
Reference in New Issue
Block a user