Merge remote-tracking branch 'upstream/devel' into devel
This commit is contained in:
commit
50ed39fd66
129 changed files with 3195 additions and 2204 deletions
388
compiler/ast.nim
388
compiler/ast.nim
|
|
@ -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,10 +192,11 @@ 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
|
||||||
|
nkTupleClassTy, # tuple type class
|
||||||
nkTypeClassTy, # user-defined type class
|
nkTypeClassTy, # user-defined type class
|
||||||
nkStaticTy, # ``static[T]``
|
nkStaticTy, # ``static[T]``
|
||||||
nkRecList, # list of object parts
|
nkRecList, # list of object parts
|
||||||
|
|
@ -226,7 +227,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 +285,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 +301,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 +322,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 +341,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 +358,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 +391,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 +409,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 +430,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 +449,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,9 +457,9 @@ 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 initalization
|
||||||
tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode
|
tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode
|
||||||
tfHasMeta, # type contains "wildcard" sub-types such as generic params
|
tfHasMeta, # type contains "wildcard" sub-types such as generic params
|
||||||
# or other type classes
|
# or other type classes
|
||||||
|
|
@ -520,7 +521,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 +532,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 +585,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 +635,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 +661,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 +671,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 +689,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 +697,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 +774,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 +807,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 +815,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 +824,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 +833,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 +845,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 +856,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 +927,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 +947,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 +964,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 +992,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 +1034,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 +1126,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 +1157,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 +1169,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 +1178,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 +1228,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 +1271,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 +1293,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)
|
||||||
|
|
||||||
|
|
@ -1320,18 +1318,18 @@ proc isGCedMem*(t: PType): bool {.inline.} =
|
||||||
t.kind == tyProc and t.callConv == ccClosure
|
t.kind == tyProc and t.callConv == ccClosure
|
||||||
|
|
||||||
proc propagateToOwner*(owner, elem: PType) =
|
proc propagateToOwner*(owner, elem: PType) =
|
||||||
const HaveTheirOwnEmpty = {tySequence, tySet}
|
const HaveTheirOwnEmpty = {tySequence, tySet, tyPtr, tyRef, tyProc}
|
||||||
owner.flags = owner.flags + (elem.flags * {tfHasMeta})
|
owner.flags = owner.flags + (elem.flags * {tfHasMeta})
|
||||||
if tfNotNil in elem.flags:
|
if tfNotNil in elem.flags:
|
||||||
if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}:
|
if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}:
|
||||||
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 +1346,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 +1371,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 +1389,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 +1406,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 +1433,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 +1481,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
|
||||||
|
|
|
||||||
|
|
@ -203,9 +203,9 @@ proc mustRehash(length, counter: int): bool =
|
||||||
assert(length > counter)
|
assert(length > counter)
|
||||||
result = (length * 2 < counter * 3) or (length - counter < 4)
|
result = (length * 2 < counter * 3) or (length - counter < 4)
|
||||||
|
|
||||||
proc spaces(x: int): PRope =
|
proc rspaces(x: int): PRope =
|
||||||
# returns x spaces
|
# returns x spaces
|
||||||
result = toRope(repeatChar(x))
|
result = toRope(spaces(x))
|
||||||
|
|
||||||
proc toYamlChar(c: char): string =
|
proc toYamlChar(c: char): string =
|
||||||
case c
|
case c
|
||||||
|
|
@ -253,7 +253,7 @@ proc typeToYamlAux(n: PType, marker: var IntSet,
|
||||||
indent, maxRecDepth: int): PRope
|
indent, maxRecDepth: int): PRope
|
||||||
proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
|
proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
|
||||||
maxRecDepth: int): PRope =
|
maxRecDepth: int): PRope =
|
||||||
var istr = spaces(indent + 2)
|
var istr = rspaces(indent + 2)
|
||||||
result = toRope("[")
|
result = toRope("[")
|
||||||
var mycount = 0
|
var mycount = 0
|
||||||
for i in countup(0, high(n.data)):
|
for i in countup(0, high(n.data)):
|
||||||
|
|
@ -262,20 +262,20 @@ proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
|
||||||
appf(result, "$N$1$2",
|
appf(result, "$N$1$2",
|
||||||
[istr, symToYamlAux(n.data[i], marker, indent + 2, maxRecDepth - 1)])
|
[istr, symToYamlAux(n.data[i], marker, indent + 2, maxRecDepth - 1)])
|
||||||
inc(mycount)
|
inc(mycount)
|
||||||
if mycount > 0: appf(result, "$N$1", [spaces(indent)])
|
if mycount > 0: appf(result, "$N$1", [rspaces(indent)])
|
||||||
app(result, "]")
|
app(result, "]")
|
||||||
assert(mycount == n.counter)
|
assert(mycount == n.counter)
|
||||||
|
|
||||||
proc ropeConstr(indent: int, c: openArray[PRope]): PRope =
|
proc ropeConstr(indent: int, c: openArray[PRope]): PRope =
|
||||||
# array of (name, value) pairs
|
# array of (name, value) pairs
|
||||||
var istr = spaces(indent + 2)
|
var istr = rspaces(indent + 2)
|
||||||
result = toRope("{")
|
result = toRope("{")
|
||||||
var i = 0
|
var i = 0
|
||||||
while i <= high(c):
|
while i <= high(c):
|
||||||
if i > 0: app(result, ",")
|
if i > 0: app(result, ",")
|
||||||
appf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]])
|
appf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]])
|
||||||
inc(i, 2)
|
inc(i, 2)
|
||||||
appf(result, "$N$1}", [spaces(indent)])
|
appf(result, "$N$1}", [rspaces(indent)])
|
||||||
|
|
||||||
proc symToYamlAux(n: PSym, marker: var IntSet, indent: int,
|
proc symToYamlAux(n: PSym, marker: var IntSet, indent: int,
|
||||||
maxRecDepth: int): PRope =
|
maxRecDepth: int): PRope =
|
||||||
|
|
@ -310,9 +310,9 @@ proc typeToYamlAux(n: PType, marker: var IntSet, indent: int,
|
||||||
result = toRope("[")
|
result = toRope("[")
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
if i > 0: app(result, ",")
|
if i > 0: app(result, ",")
|
||||||
appf(result, "$N$1$2", [spaces(indent + 4), typeToYamlAux(n.sons[i],
|
appf(result, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(n.sons[i],
|
||||||
marker, indent + 4, maxRecDepth - 1)])
|
marker, indent + 4, maxRecDepth - 1)])
|
||||||
appf(result, "$N$1]", [spaces(indent + 2)])
|
appf(result, "$N$1]", [rspaces(indent + 2)])
|
||||||
else:
|
else:
|
||||||
result = toRope("null")
|
result = toRope("null")
|
||||||
result = ropeConstr(indent, [toRope("kind"),
|
result = ropeConstr(indent, [toRope("kind"),
|
||||||
|
|
@ -331,7 +331,7 @@ proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
|
||||||
if n == nil:
|
if n == nil:
|
||||||
result = toRope("null")
|
result = toRope("null")
|
||||||
else:
|
else:
|
||||||
var istr = spaces(indent + 2)
|
var istr = rspaces(indent + 2)
|
||||||
result = ropef("{$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
|
result = ropef("{$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
|
||||||
if maxRecDepth != 0:
|
if maxRecDepth != 0:
|
||||||
appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
|
appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
|
||||||
|
|
@ -359,12 +359,12 @@ proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
|
||||||
appf(result, ",$N$1\"sons\": [", [istr])
|
appf(result, ",$N$1\"sons\": [", [istr])
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
if i > 0: app(result, ",")
|
if i > 0: app(result, ",")
|
||||||
appf(result, "$N$1$2", [spaces(indent + 4), treeToYamlAux(n.sons[i],
|
appf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(n.sons[i],
|
||||||
marker, indent + 4, maxRecDepth - 1)])
|
marker, indent + 4, maxRecDepth - 1)])
|
||||||
appf(result, "$N$1]", [istr])
|
appf(result, "$N$1]", [istr])
|
||||||
appf(result, ",$N$1\"typ\": $2",
|
appf(result, ",$N$1\"typ\": $2",
|
||||||
[istr, typeToYamlAux(n.typ, marker, indent + 2, maxRecDepth)])
|
[istr, typeToYamlAux(n.typ, marker, indent + 2, maxRecDepth)])
|
||||||
appf(result, "$N$1}", [spaces(indent)])
|
appf(result, "$N$1}", [rspaces(indent)])
|
||||||
|
|
||||||
proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope =
|
proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope =
|
||||||
var marker = initIntSet()
|
var marker = initIntSet()
|
||||||
|
|
@ -408,7 +408,7 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
|
||||||
if n == nil:
|
if n == nil:
|
||||||
result = toRope("null")
|
result = toRope("null")
|
||||||
else:
|
else:
|
||||||
var istr = spaces(indent + 2)
|
var istr = rspaces(indent + 2)
|
||||||
result = ropef("{$N$1\"kind\": $2",
|
result = ropef("{$N$1\"kind\": $2",
|
||||||
[istr, makeYamlString($n.kind)])
|
[istr, makeYamlString($n.kind)])
|
||||||
if maxRecDepth != 0:
|
if maxRecDepth != 0:
|
||||||
|
|
@ -440,11 +440,11 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
|
||||||
appf(result, ",$N$1\"sons\": [", [istr])
|
appf(result, ",$N$1\"sons\": [", [istr])
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
if i > 0: app(result, ",")
|
if i > 0: app(result, ",")
|
||||||
appf(result, "$N$1$2", [spaces(indent + 4), debugTree(n.sons[i],
|
appf(result, "$N$1$2", [rspaces(indent + 4), debugTree(n.sons[i],
|
||||||
indent + 4, maxRecDepth - 1, renderType)])
|
indent + 4, maxRecDepth - 1, renderType)])
|
||||||
appf(result, "$N$1]", [istr])
|
appf(result, "$N$1]", [istr])
|
||||||
appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
|
appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
|
||||||
appf(result, "$N$1}", [spaces(indent)])
|
appf(result, "$N$1}", [rspaces(indent)])
|
||||||
|
|
||||||
proc debug(n: PSym) =
|
proc debug(n: PSym) =
|
||||||
if n == nil:
|
if n == nil:
|
||||||
|
|
@ -681,9 +681,8 @@ proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
|
||||||
else: result = nextIdentIter(ti, tab)
|
else: result = nextIdentIter(ti, tab)
|
||||||
|
|
||||||
proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
|
proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
|
||||||
var h, start: THash
|
var h = ti.h and high(tab.data)
|
||||||
h = ti.h and high(tab.data)
|
var start = h
|
||||||
start = h
|
|
||||||
result = tab.data[h]
|
result = tab.data[h]
|
||||||
while result != nil:
|
while result != nil:
|
||||||
if result.name.id == ti.name.id: break
|
if result.name.id == ti.name.id: break
|
||||||
|
|
|
||||||
|
|
@ -135,14 +135,14 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): PRope =
|
||||||
elif ccgIntroducedPtr(param):
|
elif ccgIntroducedPtr(param):
|
||||||
initLocExpr(p, n, a)
|
initLocExpr(p, n, a)
|
||||||
result = addrLoc(a)
|
result = addrLoc(a)
|
||||||
elif p.module.compileToCpp and param.typ.kind == tyVar and
|
elif p.module.compileToCpp and param.typ.kind == tyVar and
|
||||||
n.kind == nkHiddenAddr:
|
n.kind == nkHiddenAddr:
|
||||||
initLocExprSingleUse(p, n.sons[0], a)
|
initLocExprSingleUse(p, n.sons[0], a)
|
||||||
# if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
|
# if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
|
||||||
# means '*T'. See posix.nim for lots of examples that do that in the wild.
|
# means '*T'. See posix.nim for lots of examples that do that in the wild.
|
||||||
let callee = call.sons[0]
|
let callee = call.sons[0]
|
||||||
if callee.kind == nkSym and
|
if callee.kind == nkSym and
|
||||||
{sfImportC, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportC} and
|
{sfImportC, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportC} and
|
||||||
{lfHeader, lfNoDecl} * callee.sym.loc.flags != {}:
|
{lfHeader, lfNoDecl} * callee.sym.loc.flags != {}:
|
||||||
result = addrLoc(a)
|
result = addrLoc(a)
|
||||||
else:
|
else:
|
||||||
|
|
@ -192,7 +192,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
var op: TLoc
|
var op: TLoc
|
||||||
initLocExpr(p, ri.sons[0], op)
|
initLocExpr(p, ri.sons[0], op)
|
||||||
var pl: PRope
|
var pl: PRope
|
||||||
|
|
||||||
var typ = skipTypes(ri.sons[0].typ, abstractInst)
|
var typ = skipTypes(ri.sons[0].typ, abstractInst)
|
||||||
assert(typ.kind == tyProc)
|
assert(typ.kind == tyProc)
|
||||||
var length = sonsLen(ri)
|
var length = sonsLen(ri)
|
||||||
|
|
@ -204,7 +204,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
else:
|
else:
|
||||||
app(pl, genArgNoParam(p, ri.sons[i]))
|
app(pl, genArgNoParam(p, ri.sons[i]))
|
||||||
if i < length - 1: app(pl, ~", ")
|
if i < length - 1: app(pl, ~", ")
|
||||||
|
|
||||||
template genCallPattern {.dirty.} =
|
template genCallPattern {.dirty.} =
|
||||||
lineF(p, cpsStmts, callPattern & ";$n", op.r, pl, pl.addComma, rawProc)
|
lineF(p, cpsStmts, callPattern & ";$n", op.r, pl, pl.addComma, rawProc)
|
||||||
|
|
||||||
|
|
@ -339,7 +339,8 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope =
|
||||||
let typ = skipTypes(ri.sons[0].typ, abstractInst)
|
let typ = skipTypes(ri.sons[0].typ, abstractInst)
|
||||||
if pat[i+1] == '+': result.app genArgNoParam(p, ri.sons[0])
|
if pat[i+1] == '+': result.app genArgNoParam(p, ri.sons[0])
|
||||||
result.app(~"(")
|
result.app(~"(")
|
||||||
result.app genOtherArg(p, ri, 1, typ)
|
if 1 < ri.len:
|
||||||
|
result.app genOtherArg(p, ri, 1, typ)
|
||||||
for k in j+1 .. < ri.len:
|
for k in j+1 .. < ri.len:
|
||||||
result.app(~", ")
|
result.app(~", ")
|
||||||
result.app genOtherArg(p, ri, k, typ)
|
result.app genOtherArg(p, ri, k, typ)
|
||||||
|
|
|
||||||
|
|
@ -56,11 +56,6 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
|
||||||
case skipTypes(ty, abstractVarRange).kind
|
case skipTypes(ty, abstractVarRange).kind
|
||||||
of tyChar, tyNil:
|
of tyChar, tyNil:
|
||||||
result = intLiteral(n.intVal)
|
result = intLiteral(n.intVal)
|
||||||
of tyInt:
|
|
||||||
if n.intVal >= low(int32) and n.intVal <= high(int32):
|
|
||||||
result = int32Literal(int32(n.intVal))
|
|
||||||
else:
|
|
||||||
result = intLiteral(n.intVal)
|
|
||||||
of tyBool:
|
of tyBool:
|
||||||
if n.intVal != 0: result = ~"NIM_TRUE"
|
if n.intVal != 0: result = ~"NIM_TRUE"
|
||||||
else: result = ~"NIM_FALSE"
|
else: result = ~"NIM_FALSE"
|
||||||
|
|
@ -89,7 +84,7 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
|
||||||
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
|
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
|
||||||
if id == gBackendId:
|
if id == gBackendId:
|
||||||
# string literal not found in the cache:
|
# string literal not found in the cache:
|
||||||
result = ropecg(p.module, "((#NimStringDesc*) &$1)",
|
result = ropecg(p.module, "((#NimStringDesc*) &$1)",
|
||||||
[getStrLit(p.module, n.strVal)])
|
[getStrLit(p.module, n.strVal)])
|
||||||
else:
|
else:
|
||||||
result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [toRope(id)])
|
result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [toRope(id)])
|
||||||
|
|
@ -158,7 +153,7 @@ proc getStorageLoc(n: PNode): TStorageLoc =
|
||||||
of skVar, skForVar, skResult, skLet:
|
of skVar, skForVar, skResult, skLet:
|
||||||
if sfGlobal in n.sym.flags: result = OnHeap
|
if sfGlobal in n.sym.flags: result = OnHeap
|
||||||
else: result = OnStack
|
else: result = OnStack
|
||||||
of skConst:
|
of skConst:
|
||||||
if sfGlobal in n.sym.flags: result = OnHeap
|
if sfGlobal in n.sym.flags: result = OnHeap
|
||||||
else: result = OnUnknown
|
else: result = OnUnknown
|
||||||
else: result = OnUnknown
|
else: result = OnUnknown
|
||||||
|
|
@ -236,7 +231,7 @@ proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
for i in 0 .. <t.len:
|
for i in 0 .. <t.len:
|
||||||
let t = t.sons[i]
|
let t = t.sons[i]
|
||||||
let field = ropef("Field$1", i.toRope)
|
let field = ropef("Field$1", i.toRope)
|
||||||
genAssignment(p, optAsgnLoc(dest, t, field),
|
genAssignment(p, optAsgnLoc(dest, t, field),
|
||||||
optAsgnLoc(src, t, field), newflags)
|
optAsgnLoc(src, t, field), newflags)
|
||||||
|
|
||||||
proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
|
proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
|
||||||
|
|
@ -252,20 +247,20 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
|
||||||
case t.kind
|
case t.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
let field = t.sym
|
let field = t.sym
|
||||||
genAssignment(p, optAsgnLoc(dest, field.typ, field.loc.r),
|
genAssignment(p, optAsgnLoc(dest, field.typ, field.loc.r),
|
||||||
optAsgnLoc(src, field.typ, field.loc.r), newflags)
|
optAsgnLoc(src, field.typ, field.loc.r), newflags)
|
||||||
of nkRecList:
|
of nkRecList:
|
||||||
for child in items(t): genOptAsgnObject(p, dest, src, newflags, child)
|
for child in items(t): genOptAsgnObject(p, dest, src, newflags, child)
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
# Consider:
|
# Consider:
|
||||||
# type TMyFastString {.shallow.} = string
|
# type TMyFastString {.shallow.} = string
|
||||||
# Due to the implementation of pragmas this would end up to set the
|
# Due to the implementation of pragmas this would end up to set the
|
||||||
# tfShallow flag for the built-in string type too! So we check only
|
# tfShallow flag for the built-in string type too! So we check only
|
||||||
# here for this flag, where it is reasonably safe to do so
|
# here for this flag, where it is reasonably safe to do so
|
||||||
# (for objects, etc.):
|
# (for objects, etc.):
|
||||||
if needToCopy notin flags or
|
if needToCopy notin flags or
|
||||||
tfShallow in skipTypes(dest.t, abstractVarRange).flags:
|
tfShallow in skipTypes(dest.t, abstractVarRange).flags:
|
||||||
if dest.s == OnStack or not usesNativeGC():
|
if dest.s == OnStack or not usesNativeGC():
|
||||||
useStringh(p.module)
|
useStringh(p.module)
|
||||||
|
|
@ -510,7 +505,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||||
var storage: PRope
|
var storage: PRope
|
||||||
var size = getSize(t)
|
var size = getSize(t)
|
||||||
if size < platform.intSize:
|
if size < platform.intSize:
|
||||||
storage = toRope("NI")
|
storage = toRope("NI")
|
||||||
else:
|
else:
|
||||||
storage = getTypeDesc(p.module, t)
|
storage = getTypeDesc(p.module, t)
|
||||||
var tmp = getTempName()
|
var tmp = getTempName()
|
||||||
|
|
@ -547,7 +542,7 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
"(($4)($1) - ($4)($2))", # SubF64
|
"(($4)($1) - ($4)($2))", # SubF64
|
||||||
"(($4)($1) * ($4)($2))", # MulF64
|
"(($4)($1) * ($4)($2))", # MulF64
|
||||||
"(($4)($1) / ($4)($2))", # DivF64
|
"(($4)($1) / ($4)($2))", # DivF64
|
||||||
|
|
||||||
"($4)((NU$3)($1) >> (NU$3)($2))", # ShrI
|
"($4)((NU$3)($1) >> (NU$3)($2))", # ShrI
|
||||||
"($4)((NU$3)($1) << (NU$3)($2))", # ShlI
|
"($4)((NU$3)($1) << (NU$3)($2))", # ShlI
|
||||||
"($4)($1 & $2)", # BitandI
|
"($4)($1 & $2)", # BitandI
|
||||||
|
|
@ -617,7 +612,7 @@ proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
|
||||||
initLocExpr(p, e.sons[1], a)
|
initLocExpr(p, e.sons[1], a)
|
||||||
initLocExpr(p, e.sons[2], b)
|
initLocExpr(p, e.sons[2], b)
|
||||||
if a.t.callConv == ccClosure:
|
if a.t.callConv == ccClosure:
|
||||||
putIntoDest(p, d, e.typ,
|
putIntoDest(p, d, e.typ,
|
||||||
ropef("($1.ClPrc == $2.ClPrc && $1.ClEnv == $2.ClEnv)", [
|
ropef("($1.ClPrc == $2.ClPrc && $1.ClEnv == $2.ClEnv)", [
|
||||||
rdLoc(a), rdLoc(b)]))
|
rdLoc(a), rdLoc(b)]))
|
||||||
else:
|
else:
|
||||||
|
|
@ -721,7 +716,7 @@ template inheritLocation(d: var TLoc, a: TLoc) =
|
||||||
if d.k == locNone: d.s = a.s
|
if d.k == locNone: d.s = a.s
|
||||||
if d.heapRoot == nil:
|
if d.heapRoot == nil:
|
||||||
d.heapRoot = if a.heapRoot != nil: a.heapRoot else: a.r
|
d.heapRoot = if a.heapRoot != nil: a.heapRoot else: a.r
|
||||||
|
|
||||||
proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc): PType =
|
proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc): PType =
|
||||||
initLocExpr(p, e.sons[0], a)
|
initLocExpr(p, e.sons[0], a)
|
||||||
if e.sons[1].kind != nkSym: internalError(e.info, "genRecordFieldAux")
|
if e.sons[1].kind != nkSym: internalError(e.info, "genRecordFieldAux")
|
||||||
|
|
@ -954,7 +949,7 @@ proc genEcho(p: BProc, n: PNode) =
|
||||||
initLocExpr(p, n.sons[i], a)
|
initLocExpr(p, n.sons[i], a)
|
||||||
appf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
|
appf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
|
||||||
linefmt(p, cpsStmts, "printf($1$2);$n",
|
linefmt(p, cpsStmts, "printf($1$2);$n",
|
||||||
makeCString(repeatStr(n.len, "%s") & tnl), args)
|
makeCString(repeat("%s", n.len) & tnl), args)
|
||||||
|
|
||||||
proc gcUsage(n: PNode) =
|
proc gcUsage(n: PNode) =
|
||||||
if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
|
if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
|
||||||
|
|
@ -1061,7 +1056,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||||
genAssignment(p, dest, b, {needToCopy, afDestIsNil})
|
genAssignment(p, dest, b, {needToCopy, afDestIsNil})
|
||||||
gcUsage(e)
|
gcUsage(e)
|
||||||
|
|
||||||
proc genReset(p: BProc, n: PNode) =
|
proc genReset(p: BProc, n: PNode) =
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
initLocExpr(p, n.sons[1], a)
|
initLocExpr(p, n.sons[1], a)
|
||||||
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
|
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
|
||||||
|
|
@ -1120,14 +1115,14 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
|
||||||
else:
|
else:
|
||||||
call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args)
|
call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args)
|
||||||
genAssignment(p, dest, call, {needToKeepAlive})
|
genAssignment(p, dest, call, {needToKeepAlive})
|
||||||
|
|
||||||
proc genNewSeq(p: BProc, e: PNode) =
|
proc genNewSeq(p: BProc, e: PNode) =
|
||||||
var a, b: TLoc
|
var a, b: TLoc
|
||||||
initLocExpr(p, e.sons[1], a)
|
initLocExpr(p, e.sons[1], a)
|
||||||
initLocExpr(p, e.sons[2], b)
|
initLocExpr(p, e.sons[2], b)
|
||||||
genNewSeqAux(p, a, b.rdLoc)
|
genNewSeqAux(p, a, b.rdLoc)
|
||||||
gcUsage(e)
|
gcUsage(e)
|
||||||
|
|
||||||
proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||||
var tmp: TLoc
|
var tmp: TLoc
|
||||||
var t = e.typ.skipTypes(abstractInst)
|
var t = e.typ.skipTypes(abstractInst)
|
||||||
|
|
@ -1168,7 +1163,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||||
d = tmp
|
d = tmp
|
||||||
else:
|
else:
|
||||||
genAssignment(p, d, tmp, {})
|
genAssignment(p, d, tmp, {})
|
||||||
|
|
||||||
proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) =
|
proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) =
|
||||||
var arr: TLoc
|
var arr: TLoc
|
||||||
if d.k == locNone:
|
if d.k == locNone:
|
||||||
|
|
@ -1192,7 +1187,7 @@ proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) =
|
||||||
getTemp(p, t.typ, d)
|
getTemp(p, t.typ, d)
|
||||||
# generate call to newSeq before adding the elements per hand:
|
# generate call to newSeq before adding the elements per hand:
|
||||||
var L = int(lengthOrd(t.sons[1].typ))
|
var L = int(lengthOrd(t.sons[1].typ))
|
||||||
|
|
||||||
genNewSeqAux(p, d, intLiteral(L))
|
genNewSeqAux(p, d, intLiteral(L))
|
||||||
initLocExpr(p, t.sons[1], a)
|
initLocExpr(p, t.sons[1], a)
|
||||||
for i in countup(0, L - 1):
|
for i in countup(0, L - 1):
|
||||||
|
|
@ -1202,7 +1197,7 @@ proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) =
|
||||||
initLoc(arr, locExpr, elemType(skipTypes(t.sons[1].typ, abstractInst)), a.s)
|
initLoc(arr, locExpr, elemType(skipTypes(t.sons[1].typ, abstractInst)), a.s)
|
||||||
arr.r = rfmt(nil, "$1[$2]", rdLoc(a), intLiteral(i))
|
arr.r = rfmt(nil, "$1[$2]", rdLoc(a), intLiteral(i))
|
||||||
genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
|
genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
|
||||||
|
|
||||||
proc genNewFinalize(p: BProc, e: PNode) =
|
proc genNewFinalize(p: BProc, e: PNode) =
|
||||||
var
|
var
|
||||||
a, b, f: TLoc
|
a, b, f: TLoc
|
||||||
|
|
@ -1258,7 +1253,7 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
|
||||||
app(r, ~".Sup")
|
app(r, ~".Sup")
|
||||||
t = skipTypes(t.sons[0], typedescInst)
|
t = skipTypes(t.sons[0], typedescInst)
|
||||||
if isObjLackingTypeField(t):
|
if isObjLackingTypeField(t):
|
||||||
globalError(x.info, errGenerated,
|
globalError(x.info, errGenerated,
|
||||||
"no 'of' operator available for pure objects")
|
"no 'of' operator available for pure objects")
|
||||||
if nilCheck != nil:
|
if nilCheck != nil:
|
||||||
r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r))
|
r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r))
|
||||||
|
|
@ -1275,7 +1270,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
|
||||||
var t = skipTypes(e.sons[1].typ, abstractVarRange)
|
var t = skipTypes(e.sons[1].typ, abstractVarRange)
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyInt..tyInt64, tyUInt..tyUInt64:
|
of tyInt..tyInt64, tyUInt..tyUInt64:
|
||||||
putIntoDest(p, d, e.typ,
|
putIntoDest(p, d, e.typ,
|
||||||
ropecg(p.module, "#reprInt((NI64)$1)", [rdLoc(a)]))
|
ropecg(p.module, "#reprInt((NI64)$1)", [rdLoc(a)]))
|
||||||
of tyFloat..tyFloat128:
|
of tyFloat..tyFloat128:
|
||||||
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprFloat($1)", [rdLoc(a)]))
|
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprFloat($1)", [rdLoc(a)]))
|
||||||
|
|
@ -1298,13 +1293,13 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
putIntoDest(p, b, e.typ, ropef("$1, $1Len0", [rdLoc(a)]))
|
putIntoDest(p, b, e.typ, ropef("$1, $1Len0", [rdLoc(a)]))
|
||||||
of tyString, tySequence:
|
of tyString, tySequence:
|
||||||
putIntoDest(p, b, e.typ,
|
putIntoDest(p, b, e.typ,
|
||||||
ropef("$1->data, $1->$2", [rdLoc(a), lenField(p)]))
|
ropef("$1->data, $1->$2", [rdLoc(a), lenField(p)]))
|
||||||
of tyArray, tyArrayConstr:
|
of tyArray, tyArrayConstr:
|
||||||
putIntoDest(p, b, e.typ,
|
putIntoDest(p, b, e.typ,
|
||||||
ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))]))
|
ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))]))
|
||||||
else: internalError(e.sons[0].info, "genRepr()")
|
else: internalError(e.sons[0].info, "genRepr()")
|
||||||
putIntoDest(p, d, e.typ,
|
putIntoDest(p, d, e.typ,
|
||||||
ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
|
ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
|
||||||
genTypeInfo(p.module, elemType(t))]))
|
genTypeInfo(p.module, elemType(t))]))
|
||||||
of tyCString, tyArray, tyArrayConstr, tyRef, tyPtr, tyPointer, tyNil,
|
of tyCString, tyArray, tyArrayConstr, tyRef, tyPtr, tyPointer, tyNil,
|
||||||
|
|
@ -1433,7 +1428,7 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
|
||||||
# do not emit the set, but generate a bunch of comparisons; and if we do
|
# do not emit the set, but generate a bunch of comparisons; and if we do
|
||||||
# so, we skip the unnecessary range check: This is a semantical extension
|
# so, we skip the unnecessary range check: This is a semantical extension
|
||||||
# that code now relies on. :-/ XXX
|
# that code now relies on. :-/ XXX
|
||||||
let ea = if e.sons[2].kind in {nkChckRange, nkChckRange64}:
|
let ea = if e.sons[2].kind in {nkChckRange, nkChckRange64}:
|
||||||
e.sons[2].sons[0]
|
e.sons[2].sons[0]
|
||||||
else:
|
else:
|
||||||
e.sons[2]
|
e.sons[2]
|
||||||
|
|
@ -1518,7 +1513,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
initLocExpr(p, e.sons[2], b)
|
initLocExpr(p, e.sons[2], b)
|
||||||
if d.k == locNone: getTemp(p, a.t, d)
|
if d.k == locNone: getTemp(p, a.t, d)
|
||||||
lineF(p, cpsStmts,
|
lineF(p, cpsStmts,
|
||||||
"for ($1 = 0; $1 < $2; $1++) $n" &
|
"for ($1 = 0; $1 < $2; $1++) $n" &
|
||||||
" $3[$1] = $4[$1] $6 $5[$1];$n", [
|
" $3[$1] = $4[$1] $6 $5[$1];$n", [
|
||||||
rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b),
|
rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b),
|
||||||
toRope(lookupOpr[op])])
|
toRope(lookupOpr[op])])
|
||||||
|
|
@ -1549,7 +1544,7 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
|
||||||
|
|
||||||
proc genCast(p: BProc, e: PNode, d: var TLoc) =
|
proc genCast(p: BProc, e: PNode, d: var TLoc) =
|
||||||
const floatTypes = {tyFloat..tyFloat128}
|
const floatTypes = {tyFloat..tyFloat128}
|
||||||
let
|
let
|
||||||
destt = skipTypes(e.typ, abstractRange)
|
destt = skipTypes(e.typ, abstractRange)
|
||||||
srct = skipTypes(e.sons[1].typ, abstractRange)
|
srct = skipTypes(e.sons[1].typ, abstractRange)
|
||||||
if destt.kind in floatTypes or srct.kind in floatTypes:
|
if destt.kind in floatTypes or srct.kind in floatTypes:
|
||||||
|
|
@ -1656,7 +1651,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
of mRepr: genRepr(p, e, d)
|
of mRepr: genRepr(p, e, d)
|
||||||
of mGetTypeInfo: genGetTypeInfo(p, e, d)
|
of mGetTypeInfo: genGetTypeInfo(p, e, d)
|
||||||
of mSwap: genSwap(p, e, d)
|
of mSwap: genSwap(p, e, d)
|
||||||
of mUnaryLt:
|
of mUnaryLt:
|
||||||
if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)")
|
if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)")
|
||||||
else: unaryExpr(p, e, d, "#subInt($1, 1)")
|
else: unaryExpr(p, e, d, "#subInt($1, 1)")
|
||||||
of mPred:
|
of mPred:
|
||||||
|
|
@ -1830,10 +1825,10 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
proc isConstClosure(n: PNode): bool {.inline.} =
|
proc isConstClosure(n: PNode): bool {.inline.} =
|
||||||
result = n.sons[0].kind == nkSym and isRoutine(n.sons[0].sym) and
|
result = n.sons[0].kind == nkSym and isRoutine(n.sons[0].sym) and
|
||||||
n.sons[1].kind == nkNilLit
|
n.sons[1].kind == nkNilLit
|
||||||
|
|
||||||
proc genClosure(p: BProc, n: PNode, d: var TLoc) =
|
proc genClosure(p: BProc, n: PNode, d: var TLoc) =
|
||||||
assert n.kind == nkClosure
|
assert n.kind == nkClosure
|
||||||
|
|
||||||
if isConstClosure(n):
|
if isConstClosure(n):
|
||||||
inc(p.labels)
|
inc(p.labels)
|
||||||
var tmp = con("LOC", toRope(p.labels))
|
var tmp = con("LOC", toRope(p.labels))
|
||||||
|
|
@ -1920,7 +1915,7 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
|
||||||
if isRef:
|
if isRef:
|
||||||
# it can happen that we end up generating '&&x->Sup' here, so we pack
|
# it can happen that we end up generating '&&x->Sup' here, so we pack
|
||||||
# the '&x->Sup' into a temporary and then those address is taken
|
# the '&x->Sup' into a temporary and then those address is taken
|
||||||
# (see bug #837). However sometimes using a temporary is not correct:
|
# (see bug #837). However sometimes using a temporary is not correct:
|
||||||
# init(TFigure(my)) # where it is passed to a 'var TFigure'. We test
|
# init(TFigure(my)) # where it is passed to a 'var TFigure'. We test
|
||||||
# this by ensuring the destination is also a pointer:
|
# this by ensuring the destination is also a pointer:
|
||||||
if d.k == locNone and skipTypes(n.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}:
|
if d.k == locNone and skipTypes(n.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}:
|
||||||
|
|
@ -1937,13 +1932,13 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
|
||||||
discard getTypeDesc(p.module, t) # so that any fields are initialized
|
discard getTypeDesc(p.module, t) # so that any fields are initialized
|
||||||
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
|
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
|
||||||
var tmp = con("TMP", toRope(id))
|
var tmp = con("TMP", toRope(id))
|
||||||
|
|
||||||
if id == gBackendId:
|
if id == gBackendId:
|
||||||
# expression not found in the cache:
|
# expression not found in the cache:
|
||||||
inc(gBackendId)
|
inc(gBackendId)
|
||||||
appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
|
appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
|
||||||
[getTypeDesc(p.module, t), tmp, genConstExpr(p, n)])
|
[getTypeDesc(p.module, t), tmp, genConstExpr(p, n)])
|
||||||
|
|
||||||
if d.k == locNone:
|
if d.k == locNone:
|
||||||
fillLoc(d, locData, t, tmp, OnHeap)
|
fillLoc(d, locData, t, tmp, OnHeap)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1984,7 +1979,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
internalError n.info, "expr: var not init " & sym.name.s & "_" & $sym.id
|
internalError n.info, "expr: var not init " & sym.name.s & "_" & $sym.id
|
||||||
if sfThread in sym.flags:
|
if sfThread in sym.flags:
|
||||||
accessThreadLocalVar(p, sym)
|
accessThreadLocalVar(p, sym)
|
||||||
if emulatedThreadVars():
|
if emulatedThreadVars():
|
||||||
putIntoDest(p, d, sym.loc.t, con("NimTV->", sym.loc.r))
|
putIntoDest(p, d, sym.loc.t, con("NimTV->", sym.loc.r))
|
||||||
else:
|
else:
|
||||||
putLocIntoDest(p, d, sym.loc)
|
putLocIntoDest(p, d, sym.loc)
|
||||||
|
|
@ -2001,7 +1996,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
#echo "FAILED FOR PRCO ", p.prc.name.s
|
#echo "FAILED FOR PRCO ", p.prc.name.s
|
||||||
#debug p.prc.typ.n
|
#debug p.prc.typ.n
|
||||||
#echo renderTree(p.prc.ast, {renderIds})
|
#echo renderTree(p.prc.ast, {renderIds})
|
||||||
internalError(n.info, "expr: param not init " & sym.name.s & "_" & $sym.id)
|
internalError(n.info, "expr: param not init " & sym.name.s & "_" & $sym.id)
|
||||||
putLocIntoDest(p, d, sym.loc)
|
putLocIntoDest(p, d, sym.loc)
|
||||||
else: internalError(n.info, "expr(" & $sym.kind & "); unknown symbol")
|
else: internalError(n.info, "expr(" & $sym.kind & "); unknown symbol")
|
||||||
of nkNilLit:
|
of nkNilLit:
|
||||||
|
|
@ -2101,9 +2096,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
# we have to emit the type information for object types here to support
|
# we have to emit the type information for object types here to support
|
||||||
# separate compilation:
|
# separate compilation:
|
||||||
genTypeSection(p.module, n)
|
genTypeSection(p.module, n)
|
||||||
of nkCommentStmt, nkIteratorDef, nkIncludeStmt,
|
of nkCommentStmt, nkIteratorDef, nkIncludeStmt,
|
||||||
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
|
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
|
||||||
nkFromStmt, nkTemplateDef, nkMacroDef:
|
nkFromStmt, nkTemplateDef, nkMacroDef:
|
||||||
discard
|
discard
|
||||||
of nkPragma: genPragma(p, n)
|
of nkPragma: genPragma(p, n)
|
||||||
of nkPragmaBlock: expr(p, n.lastSon, d)
|
of nkPragmaBlock: expr(p, n.lastSon, d)
|
||||||
|
|
@ -2118,8 +2113,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
sfDeadCodeElim notin getModule(prc).flags) or
|
sfDeadCodeElim notin getModule(prc).flags) or
|
||||||
({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
|
({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
|
||||||
(sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
|
(sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
|
||||||
(prc.kind == skMethod):
|
(prc.kind == skMethod):
|
||||||
# we have not only the header:
|
# we have not only the header:
|
||||||
if prc.getBody.kind != nkEmpty or lfDynamicLib in prc.loc.flags:
|
if prc.getBody.kind != nkEmpty or lfDynamicLib in prc.loc.flags:
|
||||||
genProc(p.module, prc)
|
genProc(p.module, prc)
|
||||||
of nkParForStmt: genParForStmt(p, n)
|
of nkParForStmt: genParForStmt(p, n)
|
||||||
|
|
@ -2142,7 +2137,7 @@ proc genConstSimpleList(p: BProc, n: PNode): PRope =
|
||||||
|
|
||||||
proc genConstSeq(p: BProc, n: PNode, t: PType): PRope =
|
proc genConstSeq(p: BProc, n: PNode, t: PType): PRope =
|
||||||
var data = ropef("{{$1, $1}", n.len.toRope)
|
var data = ropef("{{$1, $1}", n.len.toRope)
|
||||||
if n.len > 0:
|
if n.len > 0:
|
||||||
# array part needs extra curlies:
|
# array part needs extra curlies:
|
||||||
data.app(", {")
|
data.app(", {")
|
||||||
for i in countup(0, n.len - 1):
|
for i in countup(0, n.len - 1):
|
||||||
|
|
@ -2150,14 +2145,14 @@ proc genConstSeq(p: BProc, n: PNode, t: PType): PRope =
|
||||||
data.app genConstExpr(p, n.sons[i])
|
data.app genConstExpr(p, n.sons[i])
|
||||||
data.app("}")
|
data.app("}")
|
||||||
data.app("}")
|
data.app("}")
|
||||||
|
|
||||||
inc(gBackendId)
|
inc(gBackendId)
|
||||||
result = con("CNSTSEQ", gBackendId.toRope)
|
result = con("CNSTSEQ", gBackendId.toRope)
|
||||||
|
|
||||||
appcg(p.module, cfsData,
|
appcg(p.module, cfsData,
|
||||||
"NIM_CONST struct {$n" &
|
"NIM_CONST struct {$n" &
|
||||||
" #TGenericSeq Sup;$n" &
|
" #TGenericSeq Sup;$n" &
|
||||||
" $1 data[$2];$n" &
|
" $1 data[$2];$n" &
|
||||||
"} $3 = $4;$n", [
|
"} $3 = $4;$n", [
|
||||||
getTypeDesc(p.module, t.sons[0]), n.len.toRope, result, data])
|
getTypeDesc(p.module, t.sons[0]), n.len.toRope, result, data])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,31 +9,31 @@
|
||||||
|
|
||||||
# This module declares some helpers for the C code generator.
|
# This module declares some helpers for the C code generator.
|
||||||
|
|
||||||
import
|
import
|
||||||
ast, astalgo, ropes, lists, hashes, strutils, types, msgs, wordrecg,
|
ast, astalgo, ropes, lists, hashes, strutils, types, msgs, wordrecg,
|
||||||
platform, trees
|
platform, trees
|
||||||
|
|
||||||
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
|
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkStmtList:
|
of nkStmtList:
|
||||||
for i in 0 .. < n.len:
|
for i in 0 .. < n.len:
|
||||||
result = getPragmaStmt(n[i], w)
|
result = getPragmaStmt(n[i], w)
|
||||||
if result != nil: break
|
if result != nil: break
|
||||||
of nkPragma:
|
of nkPragma:
|
||||||
for i in 0 .. < n.len:
|
for i in 0 .. < n.len:
|
||||||
if whichPragma(n[i]) == w: return n[i]
|
if whichPragma(n[i]) == w: return n[i]
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
|
proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
|
||||||
result = getPragmaStmt(n, w) != nil
|
result = getPragmaStmt(n, w) != nil
|
||||||
|
|
||||||
proc hashString*(s: string): BiggestInt =
|
proc hashString*(s: string): BiggestInt =
|
||||||
# has to be the same algorithm as system.hashString!
|
# has to be the same algorithm as system.hashString!
|
||||||
if CPU[targetCPU].bit == 64:
|
if CPU[targetCPU].bit == 64:
|
||||||
# we have to use the same bitwidth
|
# we have to use the same bitwidth
|
||||||
# as the target CPU
|
# as the target CPU
|
||||||
var b = 0'i64
|
var b = 0'i64
|
||||||
for i in countup(0, len(s) - 1):
|
for i in countup(0, len(s) - 1):
|
||||||
b = b +% ord(s[i])
|
b = b +% ord(s[i])
|
||||||
b = b +% `shl`(b, 10)
|
b = b +% `shl`(b, 10)
|
||||||
b = b xor `shr`(b, 6)
|
b = b xor `shr`(b, 6)
|
||||||
|
|
@ -41,9 +41,9 @@ proc hashString*(s: string): BiggestInt =
|
||||||
b = b xor `shr`(b, 11)
|
b = b xor `shr`(b, 11)
|
||||||
b = b +% `shl`(b, 15)
|
b = b +% `shl`(b, 15)
|
||||||
result = b
|
result = b
|
||||||
else:
|
else:
|
||||||
var a = 0'i32
|
var a = 0'i32
|
||||||
for i in countup(0, len(s) - 1):
|
for i in countup(0, len(s) - 1):
|
||||||
a = a +% ord(s[i]).int32
|
a = a +% ord(s[i]).int32
|
||||||
a = a +% `shl`(a, 10'i32)
|
a = a +% `shl`(a, 10'i32)
|
||||||
a = a xor `shr`(a, 6'i32)
|
a = a xor `shr`(a, 6'i32)
|
||||||
|
|
@ -52,11 +52,11 @@ proc hashString*(s: string): BiggestInt =
|
||||||
a = a +% `shl`(a, 15'i32)
|
a = a +% `shl`(a, 15'i32)
|
||||||
result = a
|
result = a
|
||||||
|
|
||||||
var
|
var
|
||||||
gTypeTable: array[TTypeKind, TIdTable]
|
gTypeTable: array[TTypeKind, TIdTable]
|
||||||
gCanonicalTypes: array[TTypeKind, PType]
|
gCanonicalTypes: array[TTypeKind, PType]
|
||||||
|
|
||||||
proc initTypeTables() =
|
proc initTypeTables() =
|
||||||
for i in countup(low(TTypeKind), high(TTypeKind)): initIdTable(gTypeTable[i])
|
for i in countup(low(TTypeKind), high(TTypeKind)): initIdTable(gTypeTable[i])
|
||||||
|
|
||||||
proc resetCaches* =
|
proc resetCaches* =
|
||||||
|
|
@ -67,7 +67,7 @@ proc resetCaches* =
|
||||||
|
|
||||||
when false:
|
when false:
|
||||||
proc echoStats*() =
|
proc echoStats*() =
|
||||||
for i in countup(low(TTypeKind), high(TTypeKind)):
|
for i in countup(low(TTypeKind), high(TTypeKind)):
|
||||||
echo i, " ", gTypeTable[i].counter
|
echo i, " ", gTypeTable[i].counter
|
||||||
|
|
||||||
proc slowSearch(key: PType; k: TTypeKind): PType =
|
proc slowSearch(key: PType; k: TTypeKind): PType =
|
||||||
|
|
@ -78,28 +78,28 @@ proc slowSearch(key: PType; k: TTypeKind): PType =
|
||||||
if idTableHasObjectAsKey(gTypeTable[k], key): return key
|
if idTableHasObjectAsKey(gTypeTable[k], key): return key
|
||||||
for h in countup(0, high(gTypeTable[k].data)):
|
for h in countup(0, high(gTypeTable[k].data)):
|
||||||
var t = PType(gTypeTable[k].data[h].key)
|
var t = PType(gTypeTable[k].data[h].key)
|
||||||
if t != nil and sameBackendType(t, key):
|
if t != nil and sameBackendType(t, key):
|
||||||
return t
|
return t
|
||||||
idTablePut(gTypeTable[k], key, key)
|
idTablePut(gTypeTable[k], key, key)
|
||||||
result = key
|
result = key
|
||||||
|
|
||||||
proc getUniqueType*(key: PType): PType =
|
proc getUniqueType*(key: PType): PType =
|
||||||
# this is a hotspot in the compiler!
|
# this is a hotspot in the compiler!
|
||||||
if key == nil: return
|
if key == nil: return
|
||||||
var k = key.kind
|
var k = key.kind
|
||||||
case k
|
case k
|
||||||
of tyBool, tyChar, tyInt..tyUInt64:
|
of tyBool, tyChar, tyInt..tyUInt64:
|
||||||
# no canonicalization for integral types, so that e.g. ``pid_t`` is
|
# no canonicalization for integral types, so that e.g. ``pid_t`` is
|
||||||
# produced instead of ``NI``.
|
# produced instead of ``NI``.
|
||||||
result = key
|
result = key
|
||||||
of tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString,
|
of tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString,
|
||||||
tyCString, tyNone, tyBigNum:
|
tyCString, tyNone, tyBigNum:
|
||||||
result = gCanonicalTypes[k]
|
result = gCanonicalTypes[k]
|
||||||
if result == nil:
|
if result == nil:
|
||||||
gCanonicalTypes[k] = key
|
gCanonicalTypes[k] = key
|
||||||
result = key
|
result = key
|
||||||
of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor:
|
of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor:
|
||||||
internalError("GetUniqueType")
|
internalError("getUniqueType")
|
||||||
of tyDistinct:
|
of tyDistinct:
|
||||||
if key.deepCopy != nil: result = key
|
if key.deepCopy != nil: result = key
|
||||||
else: result = getUniqueType(lastSon(key))
|
else: result = getUniqueType(lastSon(key))
|
||||||
|
|
@ -127,21 +127,21 @@ proc getUniqueType*(key: PType): PType =
|
||||||
if tfFromGeneric notin key.flags:
|
if tfFromGeneric notin key.flags:
|
||||||
# fast case; lookup per id suffices:
|
# fast case; lookup per id suffices:
|
||||||
result = PType(idTableGet(gTypeTable[k], key))
|
result = PType(idTableGet(gTypeTable[k], key))
|
||||||
if result == nil:
|
if result == nil:
|
||||||
idTablePut(gTypeTable[k], key, key)
|
idTablePut(gTypeTable[k], key, key)
|
||||||
result = key
|
result = key
|
||||||
else:
|
else:
|
||||||
# ugly slow case: need to compare by structure
|
# ugly slow case: need to compare by structure
|
||||||
if idTableHasObjectAsKey(gTypeTable[k], key): return key
|
if idTableHasObjectAsKey(gTypeTable[k], key): return key
|
||||||
for h in countup(0, high(gTypeTable[k].data)):
|
for h in countup(0, high(gTypeTable[k].data)):
|
||||||
var t = PType(gTypeTable[k].data[h].key)
|
var t = PType(gTypeTable[k].data[h].key)
|
||||||
if t != nil and sameType(t, key):
|
if t != nil and sameBackendType(t, key):
|
||||||
return t
|
return t
|
||||||
idTablePut(gTypeTable[k], key, key)
|
idTablePut(gTypeTable[k], key, key)
|
||||||
result = key
|
result = key
|
||||||
of tyEnum:
|
of tyEnum:
|
||||||
result = PType(idTableGet(gTypeTable[k], key))
|
result = PType(idTableGet(gTypeTable[k], key))
|
||||||
if result == nil:
|
if result == nil:
|
||||||
idTablePut(gTypeTable[k], key, key)
|
idTablePut(gTypeTable[k], key, key)
|
||||||
result = key
|
result = key
|
||||||
of tyProc:
|
of tyProc:
|
||||||
|
|
@ -151,16 +151,16 @@ proc getUniqueType*(key: PType): PType =
|
||||||
# ugh, we need the canon here:
|
# ugh, we need the canon here:
|
||||||
result = slowSearch(key, k)
|
result = slowSearch(key, k)
|
||||||
|
|
||||||
proc tableGetType*(tab: TIdTable, key: PType): RootRef =
|
proc tableGetType*(tab: TIdTable, key: PType): RootRef =
|
||||||
# returns nil if we need to declare this type
|
# returns nil if we need to declare this type
|
||||||
result = idTableGet(tab, key)
|
result = idTableGet(tab, key)
|
||||||
if (result == nil) and (tab.counter > 0):
|
if (result == nil) and (tab.counter > 0):
|
||||||
# we have to do a slow linear search because types may need
|
# we have to do a slow linear search because types may need
|
||||||
# to be compared by their structure:
|
# to be compared by their structure:
|
||||||
for h in countup(0, high(tab.data)):
|
for h in countup(0, high(tab.data)):
|
||||||
var t = PType(tab.data[h].key)
|
var t = PType(tab.data[h].key)
|
||||||
if t != nil:
|
if t != nil:
|
||||||
if sameType(t, key):
|
if sameType(t, key):
|
||||||
return tab.data[h].val
|
return tab.data[h].val
|
||||||
|
|
||||||
proc makeSingleLineCString*(s: string): string =
|
proc makeSingleLineCString*(s: string): string =
|
||||||
|
|
@ -193,16 +193,16 @@ proc mangle*(name: string): string =
|
||||||
else:
|
else:
|
||||||
add(result, "HEX" & toHex(ord(c), 2))
|
add(result, "HEX" & toHex(ord(c), 2))
|
||||||
|
|
||||||
proc makeLLVMString*(s: string): PRope =
|
proc makeLLVMString*(s: string): PRope =
|
||||||
const MaxLineLength = 64
|
const MaxLineLength = 64
|
||||||
result = nil
|
result = nil
|
||||||
var res = "c\""
|
var res = "c\""
|
||||||
for i in countup(0, len(s) - 1):
|
for i in countup(0, len(s) - 1):
|
||||||
if (i + 1) mod MaxLineLength == 0:
|
if (i + 1) mod MaxLineLength == 0:
|
||||||
app(result, toRope(res))
|
app(result, toRope(res))
|
||||||
setLen(res, 0)
|
setLen(res, 0)
|
||||||
case s[i]
|
case s[i]
|
||||||
of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\':
|
of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\':
|
||||||
add(res, '\\')
|
add(res, '\\')
|
||||||
add(res, toHex(ord(s[i]), 2))
|
add(res, toHex(ord(s[i]), 2))
|
||||||
else: add(res, s[i])
|
else: add(res, s[i])
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,7 @@ proc packObject(x: PNode, typ: PType, res: pointer) =
|
||||||
let field = getField(typ.n, i)
|
let field = getField(typ.n, i)
|
||||||
pack(it, field.typ, res +! field.offset)
|
pack(it, field.typ, res +! field.offset)
|
||||||
else:
|
else:
|
||||||
|
# XXX: todo
|
||||||
globalError(x.info, "cannot pack unnamed tuple")
|
globalError(x.info, "cannot pack unnamed tuple")
|
||||||
|
|
||||||
const maxPackDepth = 20
|
const maxPackDepth = 20
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -572,6 +572,9 @@ proc footprint(filename: string): TCrc32 =
|
||||||
getCompileCFileCmd(filename, true)
|
getCompileCFileCmd(filename, true)
|
||||||
|
|
||||||
proc externalFileChanged(filename: string): bool =
|
proc externalFileChanged(filename: string): bool =
|
||||||
|
if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
|
||||||
|
return false
|
||||||
|
|
||||||
var crcFile = toGeneratedFile(filename.withPackageName, "crc")
|
var crcFile = toGeneratedFile(filename.withPackageName, "crc")
|
||||||
var currentCrc = int(footprint(filename))
|
var currentCrc = int(footprint(filename))
|
||||||
var f: File
|
var f: File
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,11 @@ const
|
||||||
PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'}
|
PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'}
|
||||||
|
|
||||||
proc newLine(p: var TTmplParser) =
|
proc newLine(p: var TTmplParser) =
|
||||||
llStreamWrite(p.outp, repeatChar(p.emitPar, ')'))
|
llStreamWrite(p.outp, repeat(')', p.emitPar))
|
||||||
p.emitPar = 0
|
p.emitPar = 0
|
||||||
if p.info.line > int16(1): llStreamWrite(p.outp, "\n")
|
if p.info.line > int16(1): llStreamWrite(p.outp, "\n")
|
||||||
if p.pendingExprLine:
|
if p.pendingExprLine:
|
||||||
llStreamWrite(p.outp, repeatChar(2))
|
llStreamWrite(p.outp, spaces(2))
|
||||||
p.pendingExprLine = false
|
p.pendingExprLine = false
|
||||||
|
|
||||||
proc scanPar(p: var TTmplParser, d: int) =
|
proc scanPar(p: var TTmplParser, d: int) =
|
||||||
|
|
@ -88,24 +88,24 @@ proc parseLine(p: var TTmplParser) =
|
||||||
else:
|
else:
|
||||||
p.info.col = int16(j)
|
p.info.col = int16(j)
|
||||||
localError(p.info, errXNotAllowedHere, "end")
|
localError(p.info, errXNotAllowedHere, "end")
|
||||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
llStreamWrite(p.outp, spaces(p.indent))
|
||||||
llStreamWrite(p.outp, "#end")
|
llStreamWrite(p.outp, "#end")
|
||||||
of wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator,
|
of wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator,
|
||||||
wConverter, wMacro, wTemplate, wMethod:
|
wConverter, wMacro, wTemplate, wMethod:
|
||||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
llStreamWrite(p.outp, spaces(p.indent))
|
||||||
llStreamWrite(p.outp, substr(p.x, d))
|
llStreamWrite(p.outp, substr(p.x, d))
|
||||||
inc(p.indent, 2)
|
inc(p.indent, 2)
|
||||||
of wElif, wOf, wElse, wExcept, wFinally:
|
of wElif, wOf, wElse, wExcept, wFinally:
|
||||||
llStreamWrite(p.outp, repeatChar(p.indent - 2))
|
llStreamWrite(p.outp, spaces(p.indent - 2))
|
||||||
llStreamWrite(p.outp, substr(p.x, d))
|
llStreamWrite(p.outp, substr(p.x, d))
|
||||||
of wLet, wVar, wConst, wType:
|
of wLet, wVar, wConst, wType:
|
||||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
llStreamWrite(p.outp, spaces(p.indent))
|
||||||
llStreamWrite(p.outp, substr(p.x, d))
|
llStreamWrite(p.outp, substr(p.x, d))
|
||||||
if not p.x.contains({':', '='}):
|
if not p.x.contains({':', '='}):
|
||||||
# no inline element --> treat as block:
|
# no inline element --> treat as block:
|
||||||
inc(p.indent, 2)
|
inc(p.indent, 2)
|
||||||
else:
|
else:
|
||||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
llStreamWrite(p.outp, spaces(p.indent))
|
||||||
llStreamWrite(p.outp, substr(p.x, d))
|
llStreamWrite(p.outp, substr(p.x, d))
|
||||||
p.state = psDirective
|
p.state = psDirective
|
||||||
else:
|
else:
|
||||||
|
|
@ -120,11 +120,11 @@ proc parseLine(p: var TTmplParser) =
|
||||||
# next line of string literal:
|
# next line of string literal:
|
||||||
llStreamWrite(p.outp, p.conc)
|
llStreamWrite(p.outp, p.conc)
|
||||||
llStreamWrite(p.outp, "\n")
|
llStreamWrite(p.outp, "\n")
|
||||||
llStreamWrite(p.outp, repeatChar(p.indent + 2))
|
llStreamWrite(p.outp, spaces(p.indent + 2))
|
||||||
llStreamWrite(p.outp, "\"")
|
llStreamWrite(p.outp, "\"")
|
||||||
of psDirective:
|
of psDirective:
|
||||||
newLine(p)
|
newLine(p)
|
||||||
llStreamWrite(p.outp, repeatChar(p.indent))
|
llStreamWrite(p.outp, spaces(p.indent))
|
||||||
llStreamWrite(p.outp, p.emit)
|
llStreamWrite(p.outp, p.emit)
|
||||||
llStreamWrite(p.outp, "(\"")
|
llStreamWrite(p.outp, "(\"")
|
||||||
inc(p.emitPar)
|
inc(p.emitPar)
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ proc getModuleName*(n: PNode): string =
|
||||||
result = n.ident.s
|
result = n.ident.s
|
||||||
of nkSym:
|
of nkSym:
|
||||||
result = n.sym.name.s
|
result = n.sym.name.s
|
||||||
of nkInfix:
|
of nkInfix, nkPrefix:
|
||||||
if n.sons[0].kind == nkIdent and n.sons[0].ident.id == getIdent("as").id:
|
if n.sons[0].kind == nkIdent and n.sons[0].ident.id == getIdent("as").id:
|
||||||
# XXX hack ahead:
|
# XXX hack ahead:
|
||||||
n.kind = nkImportAs
|
n.kind = nkImportAs
|
||||||
|
|
|
||||||
|
|
@ -780,7 +780,7 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
moveInto(p, stmt, r)
|
moveInto(p, stmt, r)
|
||||||
appf(p.body, "}$n" | "end$n")
|
appf(p.body, "}$n" | "end$n")
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
app(p.body, repeatChar(toClose, '}') & tnl)
|
app(p.body, repeat('}', toClose) & tnl)
|
||||||
else:
|
else:
|
||||||
for i in 1..toClose: appf(p.body, "end$n")
|
for i in 1..toClose: appf(p.body, "end$n")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ proc llStreamOpen*(data: string): PLLStream =
|
||||||
result.s = data
|
result.s = data
|
||||||
result.kind = llsString
|
result.kind = llsString
|
||||||
|
|
||||||
proc llStreamOpen*(f: var File): PLLStream =
|
proc llStreamOpen*(f: File): PLLStream =
|
||||||
new(result)
|
new(result)
|
||||||
result.f = f
|
result.f = f
|
||||||
result.kind = llsFile
|
result.kind = llsFile
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ proc addInterfaceDeclAux(c: PContext, sym: PSym) =
|
||||||
if sfExported in sym.flags:
|
if sfExported in sym.flags:
|
||||||
# add to interface:
|
# add to interface:
|
||||||
if c.module != nil: strTableAdd(c.module.tab, sym)
|
if c.module != nil: strTableAdd(c.module.tab, sym)
|
||||||
else: internalError(sym.info, "AddInterfaceDeclAux")
|
else: internalError(sym.info, "addInterfaceDeclAux")
|
||||||
|
|
||||||
proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) =
|
proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) =
|
||||||
addDeclAt(scope, sym)
|
addDeclAt(scope, sym)
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,8 @@ type
|
||||||
warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
|
warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
|
||||||
warnEachIdentIsTuple, warnShadowIdent,
|
warnEachIdentIsTuple, warnShadowIdent,
|
||||||
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
||||||
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnUser,
|
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
|
||||||
|
warnUser,
|
||||||
hintSuccess, hintSuccessX,
|
hintSuccess, hintSuccessX,
|
||||||
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
||||||
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
||||||
|
|
@ -391,6 +392,7 @@ const
|
||||||
warnGcMem: "'$1' uses GC'ed memory [GcMem]",
|
warnGcMem: "'$1' uses GC'ed memory [GcMem]",
|
||||||
warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future. [Destructor]",
|
warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future. [Destructor]",
|
||||||
warnLockLevel: "$1 [LockLevel]",
|
warnLockLevel: "$1 [LockLevel]",
|
||||||
|
warnResultShadowed: "Special variable 'result' is shadowed. [ResultShadowed]",
|
||||||
warnUser: "$1 [User]",
|
warnUser: "$1 [User]",
|
||||||
hintSuccess: "operation successful [Success]",
|
hintSuccess: "operation successful [Success]",
|
||||||
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]",
|
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]",
|
||||||
|
|
@ -411,7 +413,7 @@ const
|
||||||
hintUser: "$1 [User]"]
|
hintUser: "$1 [User]"]
|
||||||
|
|
||||||
const
|
const
|
||||||
WarningsToStr*: array[0..29, string] = ["CannotOpenFile", "OctalEscape",
|
WarningsToStr*: array[0..30, string] = ["CannotOpenFile", "OctalEscape",
|
||||||
"XIsNeverRead", "XmightNotBeenInit",
|
"XIsNeverRead", "XmightNotBeenInit",
|
||||||
"Deprecated", "ConfigDeprecated",
|
"Deprecated", "ConfigDeprecated",
|
||||||
"SmallLshouldNotBeUsed", "UnknownMagic",
|
"SmallLshouldNotBeUsed", "UnknownMagic",
|
||||||
|
|
@ -421,7 +423,7 @@ const
|
||||||
"TypelessParam", "DifferentHeaps", "WriteToForeignHeap",
|
"TypelessParam", "DifferentHeaps", "WriteToForeignHeap",
|
||||||
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
|
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
|
||||||
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
||||||
"GcMem", "Destructor", "LockLevel", "User"]
|
"GcMem", "Destructor", "LockLevel", "ResultShadowed", "User"]
|
||||||
|
|
||||||
HintsToStr*: array[0..16, string] = ["Success", "SuccessX", "LineTooLong",
|
HintsToStr*: array[0..16, string] = ["Success", "SuccessX", "LineTooLong",
|
||||||
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||||
|
|
@ -784,7 +786,7 @@ proc rawMessage*(msg: TMsgKind, arg: string) =
|
||||||
proc writeSurroundingSrc(info: TLineInfo) =
|
proc writeSurroundingSrc(info: TLineInfo) =
|
||||||
const indent = " "
|
const indent = " "
|
||||||
msgWriteln(indent & info.sourceLine.ropeToStr)
|
msgWriteln(indent & info.sourceLine.ropeToStr)
|
||||||
msgWriteln(indent & repeatChar(info.col, ' ') & '^')
|
msgWriteln(indent & spaces(info.col) & '^')
|
||||||
|
|
||||||
proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
|
proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
|
||||||
let frmt = case msg
|
let frmt = case msg
|
||||||
|
|
|
||||||
|
|
@ -18,3 +18,4 @@ define:useStdoutAsStdmsg
|
||||||
cs:partial
|
cs:partial
|
||||||
#define:useNodeIds
|
#define:useNodeIds
|
||||||
symbol:nimfix
|
symbol:nimfix
|
||||||
|
#gc:markAndSweep
|
||||||
|
|
|
||||||
|
|
@ -166,4 +166,4 @@ proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
|
||||||
inc(i)
|
inc(i)
|
||||||
result.add("\n")
|
result.add("\n")
|
||||||
if marker:
|
if marker:
|
||||||
result.add(repeatChar(getColNumber(L, L.bufpos)) & '^' & "\n")
|
result.add(spaces(getColNumber(L, L.bufpos)) & '^' & "\n")
|
||||||
|
|
|
||||||
|
|
@ -865,6 +865,7 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
|
||||||
#| [' optInd (identColonEquals (comma/semicolon)?)* optPar ']'
|
#| [' optInd (identColonEquals (comma/semicolon)?)* optPar ']'
|
||||||
#| extTupleDecl = 'tuple'
|
#| extTupleDecl = 'tuple'
|
||||||
#| COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
|
#| COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
|
||||||
|
#| tupleClass = 'tuple'
|
||||||
result = newNodeP(nkTupleTy, p)
|
result = newNodeP(nkTupleTy, p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
if p.tok.tokType == tkBracketLe:
|
if p.tok.tokType == tkBracketLe:
|
||||||
|
|
@ -894,6 +895,8 @@ proc parseTuple(p: var TParser, indentAllowed = false): PNode =
|
||||||
parMessage(p, errIdentifierExpected, p.tok)
|
parMessage(p, errIdentifierExpected, p.tok)
|
||||||
break
|
break
|
||||||
if not sameInd(p): break
|
if not sameInd(p): break
|
||||||
|
else:
|
||||||
|
result = newNodeP(nkTupleClassTy, p)
|
||||||
|
|
||||||
proc parseParamList(p: var TParser, retColon = true): PNode =
|
proc parseParamList(p: var TParser, retColon = true): PNode =
|
||||||
#| paramList = '(' declColonEquals ^* (comma/semicolon) ')'
|
#| paramList = '(' declColonEquals ^* (comma/semicolon) ')'
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,15 @@
|
||||||
# This module implements the passes functionality. A pass must implement the
|
# This module implements the passes functionality. A pass must implement the
|
||||||
# `TPass` interface.
|
# `TPass` interface.
|
||||||
|
|
||||||
import
|
import
|
||||||
strutils, lists, options, ast, astalgo, llstream, msgs, platform, os,
|
strutils, lists, options, ast, astalgo, llstream, msgs, platform, os,
|
||||||
condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
|
condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
|
||||||
nimsets, syntaxes, times, rodread, idgen
|
nimsets, syntaxes, times, rodread, idgen
|
||||||
|
|
||||||
type
|
type
|
||||||
TPassContext* = object of RootObj # the pass's context
|
TPassContext* = object of RootObj # the pass's context
|
||||||
fromCache*: bool # true if created by "openCached"
|
fromCache*: bool # true if created by "openCached"
|
||||||
|
|
||||||
PPassContext* = ref TPassContext
|
PPassContext* = ref TPassContext
|
||||||
|
|
||||||
TPassOpen* = proc (module: PSym): PPassContext {.nimcall.}
|
TPassOpen* = proc (module: PSym): PPassContext {.nimcall.}
|
||||||
|
|
@ -33,8 +33,8 @@ type
|
||||||
TPassData* = tuple[input: PNode, closeOutput: PNode]
|
TPassData* = tuple[input: PNode, closeOutput: PNode]
|
||||||
TPasses* = openArray[TPass]
|
TPasses* = openArray[TPass]
|
||||||
|
|
||||||
# a pass is a tuple of procedure vars ``TPass.close`` may produce additional
|
# a pass is a tuple of procedure vars ``TPass.close`` may produce additional
|
||||||
# nodes. These are passed to the other close procedures.
|
# nodes. These are passed to the other close procedures.
|
||||||
# This mechanism used to be used for the instantiation of generics.
|
# This mechanism used to be used for the instantiation of generics.
|
||||||
|
|
||||||
proc makePass*(open: TPassOpen = nil,
|
proc makePass*(open: TPassOpen = nil,
|
||||||
|
|
@ -53,46 +53,46 @@ proc makePass*(open: TPassOpen = nil,
|
||||||
proc processModule*(module: PSym, stream: PLLStream, rd: PRodReader)
|
proc processModule*(module: PSym, stream: PLLStream, rd: PRodReader)
|
||||||
|
|
||||||
# the semantic checker needs these:
|
# the semantic checker needs these:
|
||||||
var
|
var
|
||||||
gImportModule*: proc (m: PSym, fileIdx: int32): PSym {.nimcall.}
|
gImportModule*: proc (m: PSym, fileIdx: int32): PSym {.nimcall.}
|
||||||
gIncludeFile*: proc (m: PSym, fileIdx: int32): PNode {.nimcall.}
|
gIncludeFile*: proc (m: PSym, fileIdx: int32): PNode {.nimcall.}
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
proc skipCodegen*(n: PNode): bool {.inline.} =
|
proc skipCodegen*(n: PNode): bool {.inline.} =
|
||||||
# can be used by codegen passes to determine whether they should do
|
# can be used by codegen passes to determine whether they should do
|
||||||
# something with `n`. Currently, this ignores `n` and uses the global
|
# something with `n`. Currently, this ignores `n` and uses the global
|
||||||
# error count instead.
|
# error count instead.
|
||||||
result = msgs.gErrorCounter > 0
|
result = msgs.gErrorCounter > 0
|
||||||
|
|
||||||
proc astNeeded*(s: PSym): bool =
|
proc astNeeded*(s: PSym): bool =
|
||||||
# The ``rodwrite`` module uses this to determine if the body of a proc
|
# The ``rodwrite`` module uses this to determine if the body of a proc
|
||||||
# needs to be stored. The passes manager frees s.sons[codePos] when
|
# needs to be stored. The passes manager frees s.sons[codePos] when
|
||||||
# appropriate to free the procedure body's memory. This is important
|
# appropriate to free the procedure body's memory. This is important
|
||||||
# to keep memory usage down.
|
# to keep memory usage down.
|
||||||
if (s.kind in {skMethod, skProc}) and
|
if (s.kind in {skMethod, skProc}) and
|
||||||
({sfCompilerProc, sfCompileTime} * s.flags == {}) and
|
({sfCompilerProc, sfCompileTime} * s.flags == {}) and
|
||||||
(s.typ.callConv != ccInline) and
|
(s.typ.callConv != ccInline) and
|
||||||
(s.ast.sons[genericParamsPos].kind == nkEmpty):
|
(s.ast.sons[genericParamsPos].kind == nkEmpty):
|
||||||
result = false
|
result = false
|
||||||
# XXX this doesn't really make sense with excessive CTFE
|
# XXX this doesn't really make sense with excessive CTFE
|
||||||
else:
|
else:
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
const
|
const
|
||||||
maxPasses = 10
|
maxPasses = 10
|
||||||
|
|
||||||
type
|
type
|
||||||
TPassContextArray = array[0..maxPasses - 1, PPassContext]
|
TPassContextArray = array[0..maxPasses - 1, PPassContext]
|
||||||
|
|
||||||
var
|
var
|
||||||
gPasses: array[0..maxPasses - 1, TPass]
|
gPasses: array[0..maxPasses - 1, TPass]
|
||||||
gPassesLen*: int
|
gPassesLen*: int
|
||||||
|
|
||||||
proc clearPasses* =
|
proc clearPasses* =
|
||||||
gPassesLen = 0
|
gPassesLen = 0
|
||||||
|
|
||||||
proc registerPass*(p: TPass) =
|
proc registerPass*(p: TPass) =
|
||||||
gPasses[gPassesLen] = p
|
gPasses[gPassesLen] = p
|
||||||
inc(gPassesLen)
|
inc(gPassesLen)
|
||||||
|
|
||||||
|
|
@ -109,48 +109,48 @@ proc carryPasses*(nodes: PNode, module: PSym, passes: TPasses) =
|
||||||
passdata = carryPass(pass, module, passdata)
|
passdata = carryPass(pass, module, passdata)
|
||||||
|
|
||||||
proc openPasses(a: var TPassContextArray, module: PSym) =
|
proc openPasses(a: var TPassContextArray, module: PSym) =
|
||||||
for i in countup(0, gPassesLen - 1):
|
for i in countup(0, gPassesLen - 1):
|
||||||
if not isNil(gPasses[i].open):
|
if not isNil(gPasses[i].open):
|
||||||
a[i] = gPasses[i].open(module)
|
a[i] = gPasses[i].open(module)
|
||||||
else: a[i] = nil
|
else: a[i] = nil
|
||||||
|
|
||||||
proc openPassesCached(a: var TPassContextArray, module: PSym, rd: PRodReader) =
|
proc openPassesCached(a: var TPassContextArray, module: PSym, rd: PRodReader) =
|
||||||
for i in countup(0, gPassesLen - 1):
|
for i in countup(0, gPassesLen - 1):
|
||||||
if not isNil(gPasses[i].openCached):
|
if not isNil(gPasses[i].openCached):
|
||||||
a[i] = gPasses[i].openCached(module, rd)
|
a[i] = gPasses[i].openCached(module, rd)
|
||||||
if a[i] != nil:
|
if a[i] != nil:
|
||||||
a[i].fromCache = true
|
a[i].fromCache = true
|
||||||
else:
|
else:
|
||||||
a[i] = nil
|
a[i] = nil
|
||||||
|
|
||||||
proc closePasses(a: var TPassContextArray) =
|
proc closePasses(a: var TPassContextArray) =
|
||||||
var m: PNode = nil
|
var m: PNode = nil
|
||||||
for i in countup(0, gPassesLen - 1):
|
for i in countup(0, gPassesLen - 1):
|
||||||
if not isNil(gPasses[i].close): m = gPasses[i].close(a[i], m)
|
if not isNil(gPasses[i].close): m = gPasses[i].close(a[i], m)
|
||||||
a[i] = nil # free the memory here
|
a[i] = nil # free the memory here
|
||||||
|
|
||||||
proc processTopLevelStmt(n: PNode, a: var TPassContextArray): bool =
|
proc processTopLevelStmt(n: PNode, a: var TPassContextArray): bool =
|
||||||
# this implements the code transformation pipeline
|
# this implements the code transformation pipeline
|
||||||
var m = n
|
var m = n
|
||||||
for i in countup(0, gPassesLen - 1):
|
for i in countup(0, gPassesLen - 1):
|
||||||
if not isNil(gPasses[i].process):
|
if not isNil(gPasses[i].process):
|
||||||
m = gPasses[i].process(a[i], m)
|
m = gPasses[i].process(a[i], m)
|
||||||
if isNil(m): return false
|
if isNil(m): return false
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) =
|
proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) =
|
||||||
# this implements the code transformation pipeline
|
# this implements the code transformation pipeline
|
||||||
var m = n
|
var m = n
|
||||||
for i in countup(0, gPassesLen - 1):
|
for i in countup(0, gPassesLen - 1):
|
||||||
if not isNil(gPasses[i].openCached): m = gPasses[i].process(a[i], m)
|
if not isNil(gPasses[i].openCached): m = gPasses[i].process(a[i], m)
|
||||||
|
|
||||||
proc closePassesCached(a: var TPassContextArray) =
|
proc closePassesCached(a: var TPassContextArray) =
|
||||||
var m: PNode = nil
|
var m: PNode = nil
|
||||||
for i in countup(0, gPassesLen - 1):
|
for i in countup(0, gPassesLen - 1):
|
||||||
if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close):
|
if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close):
|
||||||
m = gPasses[i].close(a[i], m)
|
m = gPasses[i].close(a[i], m)
|
||||||
a[i] = nil # free the memory here
|
a[i] = nil # free the memory here
|
||||||
|
|
||||||
proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
|
proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
|
||||||
a: var TPassContextArray) =
|
a: var TPassContextArray) =
|
||||||
for module in items(implicits):
|
for module in items(implicits):
|
||||||
|
|
@ -159,45 +159,45 @@ proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
|
||||||
str.info = gCmdLineInfo
|
str.info = gCmdLineInfo
|
||||||
importStmt.addSon str
|
importStmt.addSon str
|
||||||
if not processTopLevelStmt(importStmt, a): break
|
if not processTopLevelStmt(importStmt, a): break
|
||||||
|
|
||||||
proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
|
proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
|
||||||
var
|
var
|
||||||
p: TParsers
|
p: TParsers
|
||||||
a: TPassContextArray
|
a: TPassContextArray
|
||||||
s: PLLStream
|
s: PLLStream
|
||||||
fileIdx = module.fileIdx
|
fileIdx = module.fileIdx
|
||||||
if rd == nil:
|
if rd == nil:
|
||||||
openPasses(a, module)
|
openPasses(a, module)
|
||||||
if stream == nil:
|
if stream == nil:
|
||||||
let filename = fileIdx.toFullPathConsiderDirty
|
let filename = fileIdx.toFullPathConsiderDirty
|
||||||
if module.name.s == "-":
|
if module.name.s == "-":
|
||||||
module.name.s = "stdinfile"
|
module.name.s = "stdinfile"
|
||||||
s = llStreamOpenStdIn()
|
s = llStreamOpen(stdin)
|
||||||
else:
|
else:
|
||||||
s = llStreamOpen(filename, fmRead)
|
s = llStreamOpen(filename, fmRead)
|
||||||
if s == nil:
|
if s == nil:
|
||||||
rawMessage(errCannotOpenFile, filename)
|
rawMessage(errCannotOpenFile, filename)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
s = stream
|
s = stream
|
||||||
while true:
|
while true:
|
||||||
openParsers(p, fileIdx, s)
|
openParsers(p, fileIdx, s)
|
||||||
|
|
||||||
if sfSystemModule notin module.flags:
|
if sfSystemModule notin module.flags:
|
||||||
# XXX what about caching? no processing then? what if I change the
|
# XXX what about caching? no processing then? what if I change the
|
||||||
# modules to include between compilation runs? we'd need to track that
|
# modules to include between compilation runs? we'd need to track that
|
||||||
# in ROD files. I think we should enable this feature only
|
# in ROD files. I think we should enable this feature only
|
||||||
# for the interactive mode.
|
# for the interactive mode.
|
||||||
processImplicits implicitImports, nkImportStmt, a
|
processImplicits implicitImports, nkImportStmt, a
|
||||||
processImplicits implicitIncludes, nkIncludeStmt, a
|
processImplicits implicitIncludes, nkIncludeStmt, a
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
var n = parseTopLevelStmt(p)
|
var n = parseTopLevelStmt(p)
|
||||||
if n.kind == nkEmpty: break
|
if n.kind == nkEmpty: break
|
||||||
if not processTopLevelStmt(n, a): break
|
if not processTopLevelStmt(n, a): break
|
||||||
|
|
||||||
closeParsers(p)
|
closeParsers(p)
|
||||||
if s.kind != llsStdIn: break
|
if s.kind != llsStdIn: break
|
||||||
closePasses(a)
|
closePasses(a)
|
||||||
# id synchronization point for more consistent code generation:
|
# id synchronization point for more consistent code generation:
|
||||||
idSynchronizationPoint(1000)
|
idSynchronizationPoint(1000)
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
|
||||||
|
|
||||||
proc addPendingNL(g: var TSrcGen) =
|
proc addPendingNL(g: var TSrcGen) =
|
||||||
if g.pendingNL >= 0:
|
if g.pendingNL >= 0:
|
||||||
addTok(g, tkSpaces, "\n" & repeatChar(g.pendingNL))
|
addTok(g, tkSpaces, "\n" & spaces(g.pendingNL))
|
||||||
g.lineLen = g.pendingNL
|
g.lineLen = g.pendingNL
|
||||||
g.pendingNL = - 1
|
g.pendingNL = - 1
|
||||||
|
|
||||||
|
|
@ -190,7 +190,7 @@ proc putComment(g: var TSrcGen, s: string) =
|
||||||
if not isCode and (g.lineLen + (j - i) > MaxLineLen):
|
if not isCode and (g.lineLen + (j - i) > MaxLineLen):
|
||||||
put(g, tkComment, com)
|
put(g, tkComment, com)
|
||||||
optNL(g, ind)
|
optNL(g, ind)
|
||||||
com = '#' & repeatChar(comIndent)
|
com = '#' & spaces(comIndent)
|
||||||
while s[i] > ' ':
|
while s[i] > ' ':
|
||||||
add(com, s[i])
|
add(com, s[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
@ -280,7 +280,7 @@ proc gcom(g: var TSrcGen, n: PNode) =
|
||||||
(g.lineLen < LineCommentColumn):
|
(g.lineLen < LineCommentColumn):
|
||||||
var ml = maxLineLength(n.comment)
|
var ml = maxLineLength(n.comment)
|
||||||
if ml + LineCommentColumn <= MaxLineLen:
|
if ml + LineCommentColumn <= MaxLineLen:
|
||||||
put(g, tkSpaces, repeatChar(LineCommentColumn - g.lineLen))
|
put(g, tkSpaces, spaces(LineCommentColumn - g.lineLen))
|
||||||
putComment(g, n.comment) #assert(g.comStack[high(g.comStack)] = n);
|
putComment(g, n.comment) #assert(g.comStack[high(g.comStack)] = n);
|
||||||
|
|
||||||
proc gcoms(g: var TSrcGen) =
|
proc gcoms(g: var TSrcGen) =
|
||||||
|
|
@ -395,6 +395,7 @@ proc lsub(n: PNode): int =
|
||||||
of nkClosedSymChoice, nkOpenSymChoice:
|
of nkClosedSymChoice, nkOpenSymChoice:
|
||||||
result = lsons(n) + len("()") + sonsLen(n) - 1
|
result = lsons(n) + len("()") + sonsLen(n) - 1
|
||||||
of nkTupleTy: result = lcomma(n) + len("tuple[]")
|
of nkTupleTy: result = lcomma(n) + len("tuple[]")
|
||||||
|
of nkTupleClassTy: result = len("tuple")
|
||||||
of nkDotExpr: result = lsons(n) + 1
|
of nkDotExpr: result = lsons(n) + 1
|
||||||
of nkBind: result = lsons(n) + len("bind_")
|
of nkBind: result = lsons(n) + len("bind_")
|
||||||
of nkBindStmt: result = lcomma(n) + len("bind_")
|
of nkBindStmt: result = lcomma(n) + len("bind_")
|
||||||
|
|
@ -1292,10 +1293,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
gsub(g, n.sons[0])
|
gsub(g, n.sons[0])
|
||||||
of nkTupleTy:
|
of nkTupleTy:
|
||||||
put(g, tkTuple, "tuple")
|
put(g, tkTuple, "tuple")
|
||||||
if sonsLen(n) > 0:
|
put(g, tkBracketLe, "[")
|
||||||
put(g, tkBracketLe, "[")
|
gcomma(g, n)
|
||||||
gcomma(g, n)
|
put(g, tkBracketRi, "]")
|
||||||
put(g, tkBracketRi, "]")
|
of nkTupleClassTy:
|
||||||
|
put(g, tkTuple, "tuple")
|
||||||
of nkMetaNode_Obsolete:
|
of nkMetaNode_Obsolete:
|
||||||
put(g, tkParLe, "(META|")
|
put(g, tkParLe, "(META|")
|
||||||
gsub(g, n.sons[0])
|
gsub(g, n.sons[0])
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,8 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
|
||||||
echo "passing to safeSemExpr: ", renderTree(n)
|
echo "passing to safeSemExpr: ", renderTree(n)
|
||||||
discard safeSemExpr(c, n)
|
discard safeSemExpr(c, n)
|
||||||
|
|
||||||
proc typeMismatch(n: PNode, formal, actual: PType) =
|
proc typeMismatch(n: PNode, formal, actual: PType) =
|
||||||
if formal.kind != tyError and actual.kind != tyError:
|
if formal.kind != tyError and actual.kind != tyError:
|
||||||
localError(n.info, errGenerated, msgKindToString(errTypeMismatch) &
|
localError(n.info, errGenerated, msgKindToString(errTypeMismatch) &
|
||||||
typeToString(actual) & ") " &
|
typeToString(actual) & ") " &
|
||||||
`%`(msgKindToString(errButExpectedX), [typeToString(formal)]))
|
`%`(msgKindToString(errButExpectedX), [typeToString(formal)]))
|
||||||
|
|
@ -113,7 +113,7 @@ proc commonType*(x, y: PType): PType =
|
||||||
else:
|
else:
|
||||||
result = newType(tyTypeDesc, a.owner)
|
result = newType(tyTypeDesc, a.owner)
|
||||||
rawAddSon(result, newType(tyNone, a.owner))
|
rawAddSon(result, newType(tyNone, a.owner))
|
||||||
elif b.kind in {tyArray, tyArrayConstr, tySet, tySequence} and
|
elif b.kind in {tyArray, tyArrayConstr, tySet, tySequence} and
|
||||||
a.kind == b.kind:
|
a.kind == b.kind:
|
||||||
# check for seq[empty] vs. seq[int]
|
# check for seq[empty] vs. seq[int]
|
||||||
let idx = ord(b.kind in {tyArray, tyArrayConstr})
|
let idx = ord(b.kind in {tyArray, tyArrayConstr})
|
||||||
|
|
@ -163,7 +163,7 @@ proc commonType*(x, y: PType): PType =
|
||||||
result = newType(k, r.owner)
|
result = newType(k, r.owner)
|
||||||
result.addSonSkipIntLit(r)
|
result.addSonSkipIntLit(r)
|
||||||
|
|
||||||
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
|
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
|
||||||
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info)
|
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info)
|
||||||
|
|
||||||
proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
|
proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
|
||||||
|
|
@ -182,7 +182,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
|
||||||
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||||
allowed: TSymFlags): PSym
|
allowed: TSymFlags): PSym
|
||||||
# identifier with visability
|
# identifier with visability
|
||||||
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||||
allowed: TSymFlags): PSym
|
allowed: TSymFlags): PSym
|
||||||
proc semStmtScope(c: PContext, n: PNode): PNode
|
proc semStmtScope(c: PContext, n: PNode): PNode
|
||||||
|
|
||||||
|
|
@ -190,7 +190,7 @@ proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind) =
|
||||||
let t = typeAllowed(typ, kind)
|
let t = typeAllowed(typ, kind)
|
||||||
if t != nil:
|
if t != nil:
|
||||||
if t == typ: localError(info, "invalid type: '" & typeToString(typ) & "'")
|
if t == typ: localError(info, "invalid type: '" & typeToString(typ) & "'")
|
||||||
else: localError(info, "invalid type: '" & typeToString(t) &
|
else: localError(info, "invalid type: '" & typeToString(t) &
|
||||||
"' in this context: '" & typeToString(typ) & "'")
|
"' in this context: '" & typeToString(typ) & "'")
|
||||||
|
|
||||||
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
|
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
|
||||||
|
|
@ -226,7 +226,7 @@ when false:
|
||||||
result = newSymNode(getSysSym"void")
|
result = newSymNode(getSysSym"void")
|
||||||
else:
|
else:
|
||||||
result.typ = makeTypeDesc(c, result.typ)
|
result.typ = makeTypeDesc(c, result.typ)
|
||||||
|
|
||||||
result.handleIsOperator = proc (n: PNode): PNode =
|
result.handleIsOperator = proc (n: PNode): PNode =
|
||||||
result = isOpImpl(c, n)
|
result = isOpImpl(c, n)
|
||||||
|
|
||||||
|
|
@ -248,7 +248,7 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
|
||||||
if result == nil:
|
if result == nil:
|
||||||
result = arg
|
result = arg
|
||||||
# for 'tcnstseq' we support [] to become 'seq'
|
# for 'tcnstseq' we support [] to become 'seq'
|
||||||
if eOrig.typ.skipTypes(abstractInst).kind == tySequence and
|
if eOrig.typ.skipTypes(abstractInst).kind == tySequence and
|
||||||
arg.typ.skipTypes(abstractInst).kind == tyArrayConstr:
|
arg.typ.skipTypes(abstractInst).kind == tyArrayConstr:
|
||||||
arg.typ = eOrig.typ
|
arg.typ = eOrig.typ
|
||||||
|
|
||||||
|
|
@ -320,7 +320,7 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
|
||||||
else:
|
else:
|
||||||
case s.typ.sons[0].kind
|
case s.typ.sons[0].kind
|
||||||
of tyExpr:
|
of tyExpr:
|
||||||
# BUGFIX: we cannot expect a type here, because module aliases would not
|
# BUGFIX: we cannot expect a type here, because module aliases would not
|
||||||
# work then (see the ``tmodulealias`` test)
|
# work then (see the ``tmodulealias`` test)
|
||||||
# semExprWithType(c, result)
|
# semExprWithType(c, result)
|
||||||
result = semExpr(c, result, flags)
|
result = semExpr(c, result, flags)
|
||||||
|
|
@ -355,18 +355,18 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||||
result = semAfterMacroCall(c, result, sym, flags)
|
result = semAfterMacroCall(c, result, sym, flags)
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
|
|
||||||
proc forceBool(c: PContext, n: PNode): PNode =
|
proc forceBool(c: PContext, n: PNode): PNode =
|
||||||
result = fitNode(c, getSysType(tyBool), n)
|
result = fitNode(c, getSysType(tyBool), n)
|
||||||
if result == nil: result = n
|
if result == nil: result = n
|
||||||
|
|
||||||
proc semConstBoolExpr(c: PContext, n: PNode): PNode =
|
proc semConstBoolExpr(c: PContext, n: PNode): PNode =
|
||||||
let nn = semExprWithType(c, n)
|
let nn = semExprWithType(c, n)
|
||||||
result = fitNode(c, getSysType(tyBool), nn)
|
result = fitNode(c, getSysType(tyBool), nn)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
localError(n.info, errConstExprExpected)
|
localError(n.info, errConstExprExpected)
|
||||||
return nn
|
return nn
|
||||||
result = getConstExpr(c.module, result)
|
result = getConstExpr(c.module, result)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
localError(n.info, errConstExprExpected)
|
localError(n.info, errConstExprExpected)
|
||||||
result = nn
|
result = nn
|
||||||
|
|
||||||
|
|
@ -403,9 +403,9 @@ proc myOpen(module: PSym): PPassContext =
|
||||||
pushOwner(c.module)
|
pushOwner(c.module)
|
||||||
c.importTable = openScope(c)
|
c.importTable = openScope(c)
|
||||||
c.importTable.addSym(module) # a module knows itself
|
c.importTable.addSym(module) # a module knows itself
|
||||||
if sfSystemModule in module.flags:
|
if sfSystemModule in module.flags:
|
||||||
magicsys.systemModule = module # set global variable!
|
magicsys.systemModule = module # set global variable!
|
||||||
else:
|
else:
|
||||||
c.importTable.addSym magicsys.systemModule # import the "System" identifier
|
c.importTable.addSym magicsys.systemModule # import the "System" identifier
|
||||||
importAllSymbols(c, magicsys.systemModule)
|
importAllSymbols(c, magicsys.systemModule)
|
||||||
c.topLevelScope = openScope(c)
|
c.topLevelScope = openScope(c)
|
||||||
|
|
@ -415,13 +415,13 @@ proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
|
||||||
result = myOpen(module)
|
result = myOpen(module)
|
||||||
for m in items(rd.methods): methodDef(m, true)
|
for m in items(rd.methods): methodDef(m, true)
|
||||||
|
|
||||||
proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||||
result = semStmt(c, n)
|
result = semStmt(c, n)
|
||||||
# BUGFIX: process newly generated generics here, not at the end!
|
# BUGFIX: process newly generated generics here, not at the end!
|
||||||
if c.lastGenericIdx < c.generics.len:
|
if c.lastGenericIdx < c.generics.len:
|
||||||
var a = newNodeI(nkStmtList, n.info)
|
var a = newNodeI(nkStmtList, n.info)
|
||||||
addCodeForGenerics(c, a)
|
addCodeForGenerics(c, a)
|
||||||
if sonsLen(a) > 0:
|
if sonsLen(a) > 0:
|
||||||
# a generic has been added to `a`:
|
# a generic has been added to `a`:
|
||||||
if result.kind != nkEmpty: addSon(a, result)
|
if result.kind != nkEmpty: addSon(a, result)
|
||||||
result = a
|
result = a
|
||||||
|
|
@ -429,17 +429,17 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||||
if gCmd == cmdInteractive and not isEmptyType(result.typ):
|
if gCmd == cmdInteractive and not isEmptyType(result.typ):
|
||||||
result = buildEchoStmt(c, result)
|
result = buildEchoStmt(c, result)
|
||||||
result = transformStmt(c.module, result)
|
result = transformStmt(c.module, result)
|
||||||
|
|
||||||
proc recoverContext(c: PContext) =
|
proc recoverContext(c: PContext) =
|
||||||
# clean up in case of a semantic error: We clean up the stacks, etc. This is
|
# clean up in case of a semantic error: We clean up the stacks, etc. This is
|
||||||
# faster than wrapping every stack operation in a 'try finally' block and
|
# faster than wrapping every stack operation in a 'try finally' block and
|
||||||
# requires far less code.
|
# requires far less code.
|
||||||
c.currentScope = c.topLevelScope
|
c.currentScope = c.topLevelScope
|
||||||
while getCurrOwner().kind != skModule: popOwner()
|
while getCurrOwner().kind != skModule: popOwner()
|
||||||
while c.p != nil and c.p.owner.kind != skModule: c.p = c.p.next
|
while c.p != nil and c.p.owner.kind != skModule: c.p = c.p.next
|
||||||
|
|
||||||
proc myProcess(context: PPassContext, n: PNode): PNode =
|
proc myProcess(context: PPassContext, n: PNode): PNode =
|
||||||
var c = PContext(context)
|
var c = PContext(context)
|
||||||
# no need for an expensive 'try' if we stop after the first error anyway:
|
# no need for an expensive 'try' if we stop after the first error anyway:
|
||||||
if msgs.gErrorMax <= 1:
|
if msgs.gErrorMax <= 1:
|
||||||
result = semStmtAndGenerateGenerics(c, n)
|
result = semStmtAndGenerateGenerics(c, n)
|
||||||
|
|
@ -455,8 +455,8 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
|
||||||
if getCurrentException() of ESuggestDone: result = nil
|
if getCurrentException() of ESuggestDone: result = nil
|
||||||
else: result = ast.emptyNode
|
else: result = ast.emptyNode
|
||||||
#if gCmd == cmdIdeTools: findSuggest(c, n)
|
#if gCmd == cmdIdeTools: findSuggest(c, n)
|
||||||
|
|
||||||
proc myClose(context: PPassContext, n: PNode): PNode =
|
proc myClose(context: PPassContext, n: PNode): PNode =
|
||||||
var c = PContext(context)
|
var c = PContext(context)
|
||||||
closeScope(c) # close module's scope
|
closeScope(c) # close module's scope
|
||||||
rawCloseScope(c) # imported symbols; don't check for unused ones!
|
rawCloseScope(c) # imported symbols; don't check for unused ones!
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,16 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
## This module implements semantic checking for calls.
|
## This module implements semantic checking for calls.
|
||||||
# included from sem.nim
|
# included from sem.nim
|
||||||
|
|
||||||
proc sameMethodDispatcher(a, b: PSym): bool =
|
proc sameMethodDispatcher(a, b: PSym): bool =
|
||||||
result = false
|
result = false
|
||||||
if a.kind == skMethod and b.kind == skMethod:
|
if a.kind == skMethod and b.kind == skMethod:
|
||||||
var aa = lastSon(a.ast)
|
var aa = lastSon(a.ast)
|
||||||
var bb = lastSon(b.ast)
|
var bb = lastSon(b.ast)
|
||||||
if aa.kind == nkSym and bb.kind == nkSym:
|
if aa.kind == nkSym and bb.kind == nkSym:
|
||||||
if aa.sym == bb.sym:
|
if aa.sym == bb.sym:
|
||||||
result = true
|
result = true
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
|
@ -31,7 +31,7 @@ proc sameMethodDispatcher(a, b: PSym): bool =
|
||||||
# to avoid subtle problems, the call remains ambiguous and needs to
|
# to avoid subtle problems, the call remains ambiguous and needs to
|
||||||
# be disambiguated by the programmer; this way the right generic is
|
# be disambiguated by the programmer; this way the right generic is
|
||||||
# instantiated.
|
# instantiated.
|
||||||
|
|
||||||
proc determineType(c: PContext, s: PSym)
|
proc determineType(c: PContext, s: PSym)
|
||||||
|
|
||||||
proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
|
|
@ -41,73 +41,80 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
best, alt: var TCandidate,
|
best, alt: var TCandidate,
|
||||||
errors: var CandidateErrors) =
|
errors: var CandidateErrors) =
|
||||||
var o: TOverloadIter
|
var o: TOverloadIter
|
||||||
var sym = initOverloadIter(o, c, headSymbol)
|
# thanks to the lazy semchecking for operands, we need to iterate over the
|
||||||
var symScope = o.lastOverloadScope
|
# symbol table *before* any call to 'initCandidate' which might invoke
|
||||||
|
# semExpr which might modify the symbol table in cases like
|
||||||
|
# 'init(a, 1, (var b = new(Type2); b))'.
|
||||||
|
var symx = initOverloadIter(o, c, headSymbol)
|
||||||
|
let symScope = o.lastOverloadScope
|
||||||
|
|
||||||
|
var syms: seq[tuple[a: PSym, b: int]] = @[]
|
||||||
|
while symx != nil:
|
||||||
|
if symx.kind in filter: syms.add((symx, o.lastOverloadScope))
|
||||||
|
symx = nextOverloadIter(o, c, headSymbol)
|
||||||
|
if syms.len == 0: return
|
||||||
|
|
||||||
var z: TCandidate
|
var z: TCandidate
|
||||||
|
initCandidate(c, best, syms[0][0], initialBinding, symScope)
|
||||||
if sym == nil: return
|
initCandidate(c, alt, syms[0][0], initialBinding, symScope)
|
||||||
initCandidate(c, best, sym, initialBinding, symScope)
|
|
||||||
initCandidate(c, alt, sym, initialBinding, symScope)
|
|
||||||
best.state = csNoMatch
|
best.state = csNoMatch
|
||||||
|
|
||||||
while sym != nil:
|
|
||||||
if sym.kind in filter:
|
|
||||||
determineType(c, sym)
|
|
||||||
initCandidate(c, z, sym, initialBinding, o.lastOverloadScope)
|
|
||||||
z.calleeSym = sym
|
|
||||||
|
|
||||||
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
|
for i in 0 .. <syms.len:
|
||||||
# gDebug = true
|
let sym = syms[i][0]
|
||||||
matches(c, n, orig, z)
|
determineType(c, sym)
|
||||||
if errors != nil:
|
initCandidate(c, z, sym, initialBinding, syms[i][1])
|
||||||
errors.safeAdd(sym)
|
z.calleeSym = sym
|
||||||
if z.errors != nil:
|
|
||||||
for err in z.errors:
|
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
|
||||||
errors.add(err)
|
# gDebug = true
|
||||||
if z.state == csMatch:
|
matches(c, n, orig, z)
|
||||||
# little hack so that iterators are preferred over everything else:
|
if errors != nil:
|
||||||
if sym.kind in skIterators: inc(z.exactMatches, 200)
|
errors.safeAdd(sym)
|
||||||
case best.state
|
if z.errors != nil:
|
||||||
of csEmpty, csNoMatch: best = z
|
for err in z.errors:
|
||||||
of csMatch:
|
errors.add(err)
|
||||||
var cmp = cmpCandidates(best, z)
|
if z.state == csMatch:
|
||||||
if cmp < 0: best = z # x is better than the best so far
|
# little hack so that iterators are preferred over everything else:
|
||||||
elif cmp == 0: alt = z # x is as good as the best so far
|
if sym.kind in skIterators: inc(z.exactMatches, 200)
|
||||||
else: discard
|
case best.state
|
||||||
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
|
of csEmpty, csNoMatch: best = z
|
||||||
# echo "Matches ", n.info, " ", typeToString(sym.typ)
|
of csMatch:
|
||||||
# debug sym
|
var cmp = cmpCandidates(best, z)
|
||||||
# writeMatches(z)
|
if cmp < 0: best = z # x is better than the best so far
|
||||||
# for i in 1 .. <len(z.call):
|
elif cmp == 0: alt = z # x is as good as the best so far
|
||||||
# z.call[i].typ.debug
|
else: discard
|
||||||
# quit 1
|
#if sym.name.s == "cmp" and (n.info ?? "rstgen.nim") and n.info.line == 516:
|
||||||
sym = nextOverloadIter(o, c, headSymbol)
|
# echo "Matches ", n.info, " ", typeToString(sym.typ)
|
||||||
|
# debug sym
|
||||||
|
# writeMatches(z)
|
||||||
|
# for i in 1 .. <len(z.call):
|
||||||
|
# z.call[i].typ.debug
|
||||||
|
# quit 1
|
||||||
|
|
||||||
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||||
# Gives a detailed error message; this is separated from semOverloadedCall,
|
# Gives a detailed error message; this is separated from semOverloadedCall,
|
||||||
# as semOverlodedCall is already pretty slow (and we need this information
|
# as semOverlodedCall is already pretty slow (and we need this information
|
||||||
# only in case of an error).
|
# only in case of an error).
|
||||||
if c.inCompilesContext > 0:
|
if c.inCompilesContext > 0:
|
||||||
# fail fast:
|
# fail fast:
|
||||||
globalError(n.info, errTypeMismatch, "")
|
globalError(n.info, errTypeMismatch, "")
|
||||||
if errors.isNil or errors.len == 0:
|
if errors.isNil or errors.len == 0:
|
||||||
localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
|
localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
|
||||||
return
|
return
|
||||||
|
|
||||||
# to avoid confusing errors like:
|
# to avoid confusing errors like:
|
||||||
# got (SslPtr, SocketHandle)
|
# got (SslPtr, SocketHandle)
|
||||||
# but expected one of:
|
# but expected one of:
|
||||||
# openssl.SSL_set_fd(ssl: SslPtr, fd: SocketHandle): cint
|
# openssl.SSL_set_fd(ssl: SslPtr, fd: SocketHandle): cint
|
||||||
# we do a pre-analysis. If all types produce the same string, we will add
|
# we do a pre-analysis. If all types produce the same string, we will add
|
||||||
# module information.
|
# module information.
|
||||||
let proto = describeArgs(c, n, 1, preferName)
|
let proto = describeArgs(c, n, 1, preferName)
|
||||||
|
|
||||||
var prefer = preferName
|
var prefer = preferName
|
||||||
for err in errors:
|
for err in errors:
|
||||||
var errProto = ""
|
var errProto = ""
|
||||||
let n = err.typ.n
|
let n = err.typ.n
|
||||||
for i in countup(1, n.len - 1):
|
for i in countup(1, n.len - 1):
|
||||||
var p = n.sons[i]
|
var p = n.sons[i]
|
||||||
if p.kind == nkSym:
|
if p.kind == nkSym:
|
||||||
add(errProto, typeToString(p.sym.typ, preferName))
|
add(errProto, typeToString(p.sym.typ, preferName))
|
||||||
|
|
@ -159,9 +166,9 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
|
|
||||||
n.sons.insert(hiddenArg, 1)
|
n.sons.insert(hiddenArg, 1)
|
||||||
orig.sons.insert(hiddenArg, 1)
|
orig.sons.insert(hiddenArg, 1)
|
||||||
|
|
||||||
pickBest(f)
|
pickBest(f)
|
||||||
|
|
||||||
if result.state != csMatch:
|
if result.state != csMatch:
|
||||||
n.sons.delete(1)
|
n.sons.delete(1)
|
||||||
orig.sons.delete(1)
|
orig.sons.delete(1)
|
||||||
|
|
@ -179,7 +186,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
# we are going to try multiple variants
|
# we are going to try multiple variants
|
||||||
n.sons[0..1] = [nil, n[1], calleeName]
|
n.sons[0..1] = [nil, n[1], calleeName]
|
||||||
orig.sons[0..1] = [nil, orig[1], calleeName]
|
orig.sons[0..1] = [nil, orig[1], calleeName]
|
||||||
|
|
||||||
template tryOp(x) =
|
template tryOp(x) =
|
||||||
let op = newIdentNode(getIdent(x), n.info)
|
let op = newIdentNode(getIdent(x), n.info)
|
||||||
n.sons[0] = op
|
n.sons[0] = op
|
||||||
|
|
@ -188,7 +195,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
|
|
||||||
if nfExplicitCall in n.flags:
|
if nfExplicitCall in n.flags:
|
||||||
tryOp ".()"
|
tryOp ".()"
|
||||||
|
|
||||||
if result.state in {csEmpty, csNoMatch}:
|
if result.state in {csEmpty, csNoMatch}:
|
||||||
tryOp "."
|
tryOp "."
|
||||||
|
|
||||||
|
|
@ -199,7 +206,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
n.sons[0..1] = [callOp, n[1], calleeName]
|
n.sons[0..1] = [callOp, n[1], calleeName]
|
||||||
orig.sons[0..1] = [callOp, orig[1], calleeName]
|
orig.sons[0..1] = [callOp, orig[1], calleeName]
|
||||||
pickBest(callOp)
|
pickBest(callOp)
|
||||||
|
|
||||||
if overloadsState == csEmpty and result.state == csEmpty:
|
if overloadsState == csEmpty and result.state == csEmpty:
|
||||||
localError(n.info, errUndeclaredIdentifier, considerQuotedIdent(f).s)
|
localError(n.info, errUndeclaredIdentifier, considerQuotedIdent(f).s)
|
||||||
return
|
return
|
||||||
|
|
@ -224,7 +231,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
internalAssert result.state == csMatch
|
internalAssert result.state == csMatch
|
||||||
#writeMatches(result)
|
#writeMatches(result)
|
||||||
#writeMatches(alt)
|
#writeMatches(alt)
|
||||||
if c.inCompilesContext > 0:
|
if c.inCompilesContext > 0:
|
||||||
# quick error message for performance of 'compiles' built-in:
|
# quick error message for performance of 'compiles' built-in:
|
||||||
globalError(n.info, errGenerated, "ambiguous call")
|
globalError(n.info, errGenerated, "ambiguous call")
|
||||||
elif gErrorCounter == 0:
|
elif gErrorCounter == 0:
|
||||||
|
|
@ -254,7 +261,7 @@ proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
|
||||||
for i in 1 .. <n.len:
|
for i in 1 .. <n.len:
|
||||||
instGenericConvertersArg(c, n.sons[i], x)
|
instGenericConvertersArg(c, n.sons[i], x)
|
||||||
|
|
||||||
proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
|
proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
|
||||||
var m: TCandidate
|
var m: TCandidate
|
||||||
initCandidate(c, m, f)
|
initCandidate(c, m, f)
|
||||||
result = paramTypesMatch(m, f, a, arg, nil)
|
result = paramTypesMatch(m, f, a, arg, nil)
|
||||||
|
|
@ -325,7 +332,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
||||||
# get rid of the deref again for a better error message:
|
# get rid of the deref again for a better error message:
|
||||||
n.sons[1] = n.sons[1].sons[0]
|
n.sons[1] = n.sons[1].sons[0]
|
||||||
notFoundError(c, n, errors)
|
notFoundError(c, n, errors)
|
||||||
else:
|
else:
|
||||||
notFoundError(c, n, errors)
|
notFoundError(c, n, errors)
|
||||||
# else: result = errorNode(c, n)
|
# else: result = errorNode(c, n)
|
||||||
|
|
||||||
|
|
@ -341,7 +348,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
styleCheckUse(n.info, s)
|
styleCheckUse(n.info, s)
|
||||||
result = newSymNode(newInst, n.info)
|
result = newSymNode(newInst, n.info)
|
||||||
|
|
||||||
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
assert n.kind == nkBracketExpr
|
assert n.kind == nkBracketExpr
|
||||||
for i in 1..sonsLen(n)-1:
|
for i in 1..sonsLen(n)-1:
|
||||||
n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
|
n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
|
||||||
|
|
@ -361,11 +368,11 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
# XXX I think this could be improved by reusing sigmatch.paramTypesMatch.
|
# XXX I think this could be improved by reusing sigmatch.paramTypesMatch.
|
||||||
# It's good enough for now.
|
# It's good enough for now.
|
||||||
result = newNodeI(a.kind, n.info)
|
result = newNodeI(a.kind, n.info)
|
||||||
for i in countup(0, len(a)-1):
|
for i in countup(0, len(a)-1):
|
||||||
var candidate = a.sons[i].sym
|
var candidate = a.sons[i].sym
|
||||||
if candidate.kind in {skProc, skMethod, skConverter,
|
if candidate.kind in {skProc, skMethod, skConverter,
|
||||||
skIterator, skClosureIterator}:
|
skIterator, skClosureIterator}:
|
||||||
# it suffices that the candidate has the proper number of generic
|
# it suffices that the candidate has the proper number of generic
|
||||||
# type parameters:
|
# type parameters:
|
||||||
if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
|
if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
|
||||||
result.add(explicitGenericSym(c, n, candidate))
|
result.add(explicitGenericSym(c, n, candidate))
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -356,7 +356,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
of nkIdent: a = n.sons[i]
|
of nkIdent: a = n.sons[i]
|
||||||
else: illFormedAst(n)
|
else: illFormedAst(n)
|
||||||
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
|
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
|
||||||
of nkObjectTy, nkTupleTy:
|
of nkObjectTy, nkTupleTy, nkTupleClassTy:
|
||||||
discard
|
discard
|
||||||
of nkFormalParams:
|
of nkFormalParams:
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,12 @@
|
||||||
# included from sem.nim
|
# included from sem.nim
|
||||||
|
|
||||||
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||||
entry: var TInstantiation) =
|
entry: var TInstantiation) =
|
||||||
if n.kind != nkGenericParams:
|
if n.kind != nkGenericParams:
|
||||||
internalError(n.info, "instantiateGenericParamList; no generic params")
|
internalError(n.info, "instantiateGenericParamList; no generic params")
|
||||||
newSeq(entry.concreteTypes, n.len)
|
newSeq(entry.concreteTypes, n.len)
|
||||||
for i, a in n.pairs:
|
for i, a in n.pairs:
|
||||||
if a.kind != nkSym:
|
if a.kind != nkSym:
|
||||||
internalError(a.info, "instantiateGenericParamList; no symbol")
|
internalError(a.info, "instantiateGenericParamList; no symbol")
|
||||||
var q = a.sym
|
var q = a.sym
|
||||||
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
|
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
|
||||||
|
|
@ -27,13 +27,13 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||||
var t = PType(idTableGet(pt, q.typ))
|
var t = PType(idTableGet(pt, q.typ))
|
||||||
if t == nil:
|
if t == nil:
|
||||||
if tfRetType in q.typ.flags:
|
if tfRetType in q.typ.flags:
|
||||||
# keep the generic type and allow the return type to be bound
|
# keep the generic type and allow the return type to be bound
|
||||||
# later by semAsgn in return type inference scenario
|
# later by semAsgn in return type inference scenario
|
||||||
t = q.typ
|
t = q.typ
|
||||||
else:
|
else:
|
||||||
localError(a.info, errCannotInstantiateX, s.name.s)
|
localError(a.info, errCannotInstantiateX, s.name.s)
|
||||||
t = errorType(c)
|
t = errorType(c)
|
||||||
elif t.kind == tyGenericParam:
|
elif t.kind == tyGenericParam:
|
||||||
localError(a.info, errCannotInstantiateX, q.name.s)
|
localError(a.info, errCannotInstantiateX, q.name.s)
|
||||||
t = errorType(c)
|
t = errorType(c)
|
||||||
elif t.kind == tyGenericInvocation:
|
elif t.kind == tyGenericInvocation:
|
||||||
|
|
@ -58,17 +58,17 @@ proc genericCacheGet(genericSym: PSym, entry: TInstantiation): PSym =
|
||||||
if sameInstantiation(entry, inst[]):
|
if sameInstantiation(entry, inst[]):
|
||||||
return inst.sym
|
return inst.sym
|
||||||
|
|
||||||
proc removeDefaultParamValues(n: PNode) =
|
proc removeDefaultParamValues(n: PNode) =
|
||||||
# we remove default params, because they cannot be instantiated properly
|
# we remove default params, because they cannot be instantiated properly
|
||||||
# and they are not needed anyway for instantiation (each param is already
|
# and they are not needed anyway for instantiation (each param is already
|
||||||
# provided).
|
# provided).
|
||||||
when false:
|
when false:
|
||||||
for i in countup(1, sonsLen(n)-1):
|
for i in countup(1, sonsLen(n)-1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind != nkIdentDefs: IllFormedAst(a)
|
if a.kind != nkIdentDefs: IllFormedAst(a)
|
||||||
var L = a.len
|
var L = a.len
|
||||||
if a.sons[L-1].kind != nkEmpty and a.sons[L-2].kind != nkEmpty:
|
if a.sons[L-1].kind != nkEmpty and a.sons[L-2].kind != nkEmpty:
|
||||||
# ``param: typ = defaultVal``.
|
# ``param: typ = defaultVal``.
|
||||||
# We don't need defaultVal for semantic checking and it's wrong for
|
# We don't need defaultVal for semantic checking and it's wrong for
|
||||||
# ``cmp: proc (a, b: T): int = cmp``. Hm, for ``cmp = cmp`` that is
|
# ``cmp: proc (a, b: T): int = cmp``. Hm, for ``cmp = cmp`` that is
|
||||||
# not possible... XXX We don't solve this issue here.
|
# not possible... XXX We don't solve this issue here.
|
||||||
|
|
@ -97,7 +97,7 @@ proc addProcDecls(c: PContext, fn: PSym) =
|
||||||
var param = fn.typ.n.sons[i].sym
|
var param = fn.typ.n.sons[i].sym
|
||||||
param.owner = fn
|
param.owner = fn
|
||||||
addParamOrResult(c, param, fn.kind)
|
addParamOrResult(c, param, fn.kind)
|
||||||
|
|
||||||
maybeAddResult(c, fn, fn.ast)
|
maybeAddResult(c, fn, fn.ast)
|
||||||
|
|
||||||
proc instantiateBody(c: PContext, n, params: PNode, result: PSym) =
|
proc instantiateBody(c: PContext, n, params: PNode, result: PSym) =
|
||||||
|
|
@ -132,9 +132,9 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
|
|
||||||
proc sideEffectsCheck(c: PContext, s: PSym) =
|
proc sideEffectsCheck(c: PContext, s: PSym) =
|
||||||
if {sfNoSideEffect, sfSideEffect} * s.flags ==
|
if {sfNoSideEffect, sfSideEffect} * s.flags ==
|
||||||
{sfNoSideEffect, sfSideEffect}:
|
{sfNoSideEffect, sfSideEffect}:
|
||||||
localError(s.info, errXhasSideEffects, s.name.s)
|
localError(s.info, errXhasSideEffects, s.name.s)
|
||||||
|
|
||||||
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
||||||
|
|
@ -162,18 +162,18 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||||
# Alas, doing this here is probably not enough, because another
|
# Alas, doing this here is probably not enough, because another
|
||||||
# proc signature could appear in the params:
|
# proc signature could appear in the params:
|
||||||
# proc foo[T](a: proc (x: T, b: type(x.y))
|
# proc foo[T](a: proc (x: T, b: type(x.y))
|
||||||
#
|
#
|
||||||
# The solution would be to move this logic into semtypinst, but
|
# The solution would be to move this logic into semtypinst, but
|
||||||
# at this point semtypinst have to become part of sem, because it
|
# at this point semtypinst have to become part of sem, because it
|
||||||
# will need to use openScope, addDecl, etc.
|
# will need to use openScope, addDecl, etc.
|
||||||
addDecl(c, prc)
|
addDecl(c, prc)
|
||||||
|
|
||||||
pushInfoContext(info)
|
pushInfoContext(info)
|
||||||
var cl = initTypeVars(c, pt, info)
|
var cl = initTypeVars(c, pt, info)
|
||||||
var result = instCopyType(cl, prc.typ)
|
var result = instCopyType(cl, prc.typ)
|
||||||
let originalParams = result.n
|
let originalParams = result.n
|
||||||
result.n = originalParams.shallowCopy
|
result.n = originalParams.shallowCopy
|
||||||
|
|
||||||
for i in 1 .. <result.len:
|
for i in 1 .. <result.len:
|
||||||
# twrong_field_caching requires these 'resetIdTable' calls:
|
# twrong_field_caching requires these 'resetIdTable' calls:
|
||||||
if i > 1: resetIdTable(cl.symMap)
|
if i > 1: resetIdTable(cl.symMap)
|
||||||
|
|
@ -198,10 +198,10 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||||
resetIdTable(cl.symMap)
|
resetIdTable(cl.symMap)
|
||||||
result.sons[0] = replaceTypeVarsT(cl, result.sons[0])
|
result.sons[0] = replaceTypeVarsT(cl, result.sons[0])
|
||||||
result.n.sons[0] = originalParams[0].copyTree
|
result.n.sons[0] = originalParams[0].copyTree
|
||||||
|
|
||||||
eraseVoidParams(result)
|
eraseVoidParams(result)
|
||||||
skipIntLiteralParams(result)
|
skipIntLiteralParams(result)
|
||||||
|
|
||||||
prc.typ = result
|
prc.typ = result
|
||||||
maybeAddResult(c, prc, prc.ast)
|
maybeAddResult(c, prc, prc.ast)
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
|
||||||
if g.kind == skUnknown:
|
if g.kind == skUnknown:
|
||||||
var field: PSym = nil
|
var field: PSym = nil
|
||||||
var ty = n.sons[0].typ.skipTypes(abstractPtrs)
|
var ty = n.sons[0].typ.skipTypes(abstractPtrs)
|
||||||
if ty.kind == tyTuple:
|
if ty.kind == tyTuple and not ty.n.isNil:
|
||||||
field = lookupInRecord(ty.n, g.name)
|
field = lookupInRecord(ty.n, g.name)
|
||||||
else:
|
else:
|
||||||
while ty != nil and ty.kind == tyObject:
|
while ty != nil and ty.kind == tyObject:
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,13 @@
|
||||||
|
|
||||||
var enforceVoidContext = PType(kind: tyStmt)
|
var enforceVoidContext = PType(kind: tyStmt)
|
||||||
|
|
||||||
proc semDiscard(c: PContext, n: PNode): PNode =
|
proc semDiscard(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkSonsLen(n, 1)
|
checkSonsLen(n, 1)
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
n.sons[0] = semExprWithType(c, n.sons[0])
|
n.sons[0] = semExprWithType(c, n.sons[0])
|
||||||
if isEmptyType(n.sons[0].typ): localError(n.info, errInvalidDiscard)
|
if isEmptyType(n.sons[0].typ): localError(n.info, errInvalidDiscard)
|
||||||
|
|
||||||
proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkSonsLen(n, 1)
|
checkSonsLen(n, 1)
|
||||||
|
|
@ -29,7 +29,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
||||||
of nkIdent: s = lookUp(c, n.sons[0])
|
of nkIdent: s = lookUp(c, n.sons[0])
|
||||||
of nkSym: s = n.sons[0].sym
|
of nkSym: s = n.sons[0].sym
|
||||||
else: illFormedAst(n)
|
else: illFormedAst(n)
|
||||||
if s.kind == skLabel and s.owner.id == c.p.owner.id:
|
if s.kind == skLabel and s.owner.id == c.p.owner.id:
|
||||||
var x = newSymNode(s)
|
var x = newSymNode(s)
|
||||||
x.info = n.info
|
x.info = n.info
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
|
|
@ -41,16 +41,16 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
localError(n.info, errGenerated, "'continue' cannot have a label")
|
localError(n.info, errGenerated, "'continue' cannot have a label")
|
||||||
elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
|
elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
|
||||||
localError(n.info, errInvalidControlFlowX,
|
localError(n.info, errInvalidControlFlowX,
|
||||||
renderTree(n, {renderNoComments}))
|
renderTree(n, {renderNoComments}))
|
||||||
|
|
||||||
proc semAsm(con: PContext, n: PNode): PNode =
|
proc semAsm(con: PContext, n: PNode): PNode =
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
var marker = pragmaAsm(con, n.sons[0])
|
var marker = pragmaAsm(con, n.sons[0])
|
||||||
if marker == '\0': marker = '`' # default marker
|
if marker == '\0': marker = '`' # default marker
|
||||||
result = semAsmOrEmit(con, n, marker)
|
result = semAsmOrEmit(con, n, marker)
|
||||||
|
|
||||||
proc semWhile(c: PContext, n: PNode): PNode =
|
proc semWhile(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
|
|
@ -62,16 +62,16 @@ proc semWhile(c: PContext, n: PNode): PNode =
|
||||||
if n.sons[1].typ == enforceVoidContext:
|
if n.sons[1].typ == enforceVoidContext:
|
||||||
result.typ = enforceVoidContext
|
result.typ = enforceVoidContext
|
||||||
|
|
||||||
proc toCover(t: PType): BiggestInt =
|
proc toCover(t: PType): BiggestInt =
|
||||||
var t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
|
var t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
|
||||||
if t2.kind == tyEnum and enumHasHoles(t2):
|
if t2.kind == tyEnum and enumHasHoles(t2):
|
||||||
result = sonsLen(t2.n)
|
result = sonsLen(t2.n)
|
||||||
else:
|
else:
|
||||||
result = lengthOrd(skipTypes(t, abstractVar-{tyTypeDesc}))
|
result = lengthOrd(skipTypes(t, abstractVar-{tyTypeDesc}))
|
||||||
|
|
||||||
proc performProcvarCheck(c: PContext, n: PNode, s: PSym) =
|
proc performProcvarCheck(c: PContext, n: PNode, s: PSym) =
|
||||||
## Checks that the given symbol is a proper procedure variable, meaning
|
## Checks that the given symbol is a proper procedure variable, meaning
|
||||||
## that it
|
## that it
|
||||||
var smoduleId = getModule(s).id
|
var smoduleId = getModule(s).id
|
||||||
if sfProcvar notin s.flags and s.typ.callConv == ccDefault and
|
if sfProcvar notin s.flags and s.typ.callConv == ccDefault and
|
||||||
smoduleId != c.module.id:
|
smoduleId != c.module.id:
|
||||||
|
|
@ -98,11 +98,11 @@ proc semDestructorCheck(c: PContext, n: PNode, flags: TExprFlags) {.inline.} =
|
||||||
localError(n.info, warnDestructor)
|
localError(n.info, warnDestructor)
|
||||||
# This still breaks too many things:
|
# This still breaks too many things:
|
||||||
when false:
|
when false:
|
||||||
if efDetermineType notin flags and n.typ.kind == tyTypeDesc and
|
if efDetermineType notin flags and n.typ.kind == tyTypeDesc and
|
||||||
c.p.owner.kind notin {skTemplate, skMacro}:
|
c.p.owner.kind notin {skTemplate, skMacro}:
|
||||||
localError(n.info, errGenerated, "value expected, but got a type")
|
localError(n.info, errGenerated, "value expected, but got a type")
|
||||||
|
|
||||||
proc newDeref(n: PNode): PNode {.inline.} =
|
proc newDeref(n: PNode): PNode {.inline.} =
|
||||||
result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
|
result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
|
||||||
addSon(result, n)
|
addSon(result, n)
|
||||||
|
|
||||||
|
|
@ -127,7 +127,7 @@ const
|
||||||
proc implicitlyDiscardable(n: PNode): bool =
|
proc implicitlyDiscardable(n: PNode): bool =
|
||||||
var n = n
|
var n = n
|
||||||
while n.kind in skipForDiscardable: n = n.lastSon
|
while n.kind in skipForDiscardable: n = n.lastSon
|
||||||
result = isCallExpr(n) and n.sons[0].kind == nkSym and
|
result = isCallExpr(n) and n.sons[0].kind == nkSym and
|
||||||
sfDiscardable in n.sons[0].sym.flags
|
sfDiscardable in n.sons[0].sym.flags
|
||||||
|
|
||||||
proc fixNilType(n: PNode) =
|
proc fixNilType(n: PNode) =
|
||||||
|
|
@ -160,11 +160,11 @@ proc discardCheck(c: PContext, result: PNode) =
|
||||||
while n.kind in skipForDiscardable: n = n.lastSon
|
while n.kind in skipForDiscardable: n = n.lastSon
|
||||||
localError(n.info, errDiscardValueX, result.typ.typeToString)
|
localError(n.info, errDiscardValueX, result.typ.typeToString)
|
||||||
|
|
||||||
proc semIf(c: PContext, n: PNode): PNode =
|
proc semIf(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
var typ = commonTypeBegin
|
var typ = commonTypeBegin
|
||||||
var hasElse = false
|
var hasElse = false
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
if it.len == 2:
|
if it.len == 2:
|
||||||
when newScopeForIf: openScope(c)
|
when newScopeForIf: openScope(c)
|
||||||
|
|
@ -208,10 +208,10 @@ proc semCase(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
localError(n.info, errSelectorMustBeOfCertainTypes)
|
localError(n.info, errSelectorMustBeOfCertainTypes)
|
||||||
return
|
return
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
var x = n.sons[i]
|
var x = n.sons[i]
|
||||||
case x.kind
|
case x.kind
|
||||||
of nkOfBranch:
|
of nkOfBranch:
|
||||||
checkMinSonsLen(x, 2)
|
checkMinSonsLen(x, 2)
|
||||||
semCaseBranch(c, n, x, i, covered)
|
semCaseBranch(c, n, x, i, covered)
|
||||||
var last = sonsLen(x)-1
|
var last = sonsLen(x)-1
|
||||||
|
|
@ -304,9 +304,9 @@ proc semTry(c: PContext, n: PNode): PNode =
|
||||||
it.sons[j] = fitNode(c, typ, it.sons[j])
|
it.sons[j] = fitNode(c, typ, it.sons[j])
|
||||||
result.typ = typ
|
result.typ = typ
|
||||||
|
|
||||||
proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
|
proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
|
||||||
result = fitNode(c, typ, n)
|
result = fitNode(c, typ, n)
|
||||||
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
|
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
|
||||||
changeType(result.sons[1], typ, check=true)
|
changeType(result.sons[1], typ, check=true)
|
||||||
result = result.sons[1]
|
result = result.sons[1]
|
||||||
elif not sameType(result.typ, typ):
|
elif not sameType(result.typ, typ):
|
||||||
|
|
@ -325,7 +325,7 @@ proc identWithin(n: PNode, s: PIdent): bool =
|
||||||
result = n.kind == nkSym and n.sym.name.id == s.id
|
result = n.kind == nkSym and n.sym.name.id == s.id
|
||||||
|
|
||||||
proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
|
proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
|
||||||
if isTopLevel(c):
|
if isTopLevel(c):
|
||||||
result = semIdentWithPragma(c, kind, n, {sfExported})
|
result = semIdentWithPragma(c, kind, n, {sfExported})
|
||||||
incl(result.flags, sfGlobal)
|
incl(result.flags, sfGlobal)
|
||||||
else:
|
else:
|
||||||
|
|
@ -340,14 +340,14 @@ proc checkNilable(v: PSym) =
|
||||||
elif tfNotNil in v.typ.flags and tfNotNil notin v.ast.typ.flags:
|
elif tfNotNil in v.typ.flags and tfNotNil notin v.ast.typ.flags:
|
||||||
message(v.info, warnProveInit, v.name.s)
|
message(v.info, warnProveInit, v.name.s)
|
||||||
|
|
||||||
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
var b: PNode
|
var b: PNode
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
var hasCompileTime = false
|
var hasCompileTime = false
|
||||||
for i in countup(0, sonsLen(n)-1):
|
for i in countup(0, sonsLen(n)-1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if gCmd == cmdIdeTools: suggestStmt(c, a)
|
if gCmd == cmdIdeTools: suggestStmt(c, a)
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a)
|
if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a)
|
||||||
checkMinSonsLen(a, 3)
|
checkMinSonsLen(a, 3)
|
||||||
var length = sonsLen(a)
|
var length = sonsLen(a)
|
||||||
|
|
@ -369,7 +369,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
typ = def.typ
|
typ = def.typ
|
||||||
else:
|
else:
|
||||||
# BUGFIX: ``fitNode`` is needed here!
|
# BUGFIX: ``fitNode`` is needed here!
|
||||||
# check type compatibility between def.typ and typ
|
# check type compatibility between def.typ and typ
|
||||||
def = fitNode(c, typ, def)
|
def = fitNode(c, typ, def)
|
||||||
#changeType(def.skipConv, typ, check=true)
|
#changeType(def.skipConv, typ, check=true)
|
||||||
else:
|
else:
|
||||||
|
|
@ -381,15 +381,15 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
else:
|
else:
|
||||||
def = ast.emptyNode
|
def = ast.emptyNode
|
||||||
if symkind == skLet: localError(a.info, errLetNeedsInit)
|
if symkind == skLet: localError(a.info, errLetNeedsInit)
|
||||||
|
|
||||||
# this can only happen for errornous var statements:
|
# this can only happen for errornous var statements:
|
||||||
if typ == nil: continue
|
if typ == nil: continue
|
||||||
typeAllowedCheck(a.info, typ, symkind)
|
typeAllowedCheck(a.info, typ, symkind)
|
||||||
var tup = skipTypes(typ, {tyGenericInst})
|
var tup = skipTypes(typ, {tyGenericInst})
|
||||||
if a.kind == nkVarTuple:
|
if a.kind == nkVarTuple:
|
||||||
if tup.kind != tyTuple:
|
if tup.kind != tyTuple:
|
||||||
localError(a.info, errXExpected, "tuple")
|
localError(a.info, errXExpected, "tuple")
|
||||||
elif length-2 != sonsLen(tup):
|
elif length-2 != sonsLen(tup):
|
||||||
localError(a.info, errWrongNumberOfVariables)
|
localError(a.info, errWrongNumberOfVariables)
|
||||||
else:
|
else:
|
||||||
b = newNodeI(nkVarTuple, a.info)
|
b = newNodeI(nkVarTuple, a.info)
|
||||||
|
|
@ -397,9 +397,10 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator
|
b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator
|
||||||
b.sons[length-1] = def
|
b.sons[length-1] = def
|
||||||
addSon(result, b)
|
addSon(result, b)
|
||||||
elif tup.kind == tyTuple and def.kind == nkPar and
|
elif tup.kind == tyTuple and def.kind == nkPar and
|
||||||
a.kind == nkIdentDefs and a.len > 3:
|
a.kind == nkIdentDefs and a.len > 3:
|
||||||
message(a.info, warnEachIdentIsTuple)
|
message(a.info, warnEachIdentIsTuple)
|
||||||
|
|
||||||
for j in countup(0, length-3):
|
for j in countup(0, length-3):
|
||||||
var v = semIdentDef(c, a.sons[j], symkind)
|
var v = semIdentDef(c, a.sons[j], symkind)
|
||||||
if sfGenSym notin v.flags: addInterfaceDecl(c, v)
|
if sfGenSym notin v.flags: addInterfaceDecl(c, v)
|
||||||
|
|
@ -409,6 +410,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
let shadowed = findShadowedVar(c, v)
|
let shadowed = findShadowedVar(c, v)
|
||||||
if shadowed != nil:
|
if shadowed != nil:
|
||||||
shadowed.flags.incl(sfShadowed)
|
shadowed.flags.incl(sfShadowed)
|
||||||
|
if shadowed.kind == skResult:
|
||||||
|
message(a.info, warnResultShadowed)
|
||||||
# a shadowed variable is an error unless it appears on the right
|
# a shadowed variable is an error unless it appears on the right
|
||||||
# side of the '=':
|
# side of the '=':
|
||||||
if warnShadowIdent in gNotes and not identWithin(def, v.name):
|
if warnShadowIdent in gNotes and not identWithin(def, v.name):
|
||||||
|
|
@ -435,12 +438,12 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
if sfCompileTime in v.flags: hasCompileTime = true
|
if sfCompileTime in v.flags: hasCompileTime = true
|
||||||
if hasCompileTime: vm.setupCompileTimeVar(c.module, result)
|
if hasCompileTime: vm.setupCompileTimeVar(c.module, result)
|
||||||
|
|
||||||
proc semConst(c: PContext, n: PNode): PNode =
|
proc semConst(c: PContext, n: PNode): PNode =
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if gCmd == cmdIdeTools: suggestStmt(c, a)
|
if gCmd == cmdIdeTools: suggestStmt(c, a)
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if (a.kind != nkConstDef): illFormedAst(a)
|
if (a.kind != nkConstDef): illFormedAst(a)
|
||||||
checkSonsLen(a, 3)
|
checkSonsLen(a, 3)
|
||||||
var v = semIdentDef(c, a.sons[0], skConst)
|
var v = semIdentDef(c, a.sons[0], skConst)
|
||||||
|
|
@ -495,7 +498,7 @@ proc semForVars(c: PContext, n: PNode): PNode =
|
||||||
var iter = skipTypes(iterBase, {tyGenericInst})
|
var iter = skipTypes(iterBase, {tyGenericInst})
|
||||||
# length == 3 means that there is one for loop variable
|
# length == 3 means that there is one for loop variable
|
||||||
# and thus no tuple unpacking:
|
# and thus no tuple unpacking:
|
||||||
if iter.kind != tyTuple or length == 3:
|
if iter.kind != tyTuple or length == 3:
|
||||||
if length == 3:
|
if length == 3:
|
||||||
var v = symForVar(c, n.sons[0])
|
var v = symForVar(c, n.sons[0])
|
||||||
if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal)
|
if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal)
|
||||||
|
|
@ -523,13 +526,13 @@ proc semForVars(c: PContext, n: PNode): PNode =
|
||||||
proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
|
proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
|
||||||
result = newNodeI(nkCall, arg.info)
|
result = newNodeI(nkCall, arg.info)
|
||||||
result.add(newIdentNode(it.getIdent, arg.info))
|
result.add(newIdentNode(it.getIdent, arg.info))
|
||||||
if arg.typ != nil and arg.typ.kind == tyVar:
|
if arg.typ != nil and arg.typ.kind == tyVar:
|
||||||
result.add newDeref(arg)
|
result.add newDeref(arg)
|
||||||
else:
|
else:
|
||||||
result.add arg
|
result.add arg
|
||||||
result = semExprNoDeref(c, result, {efWantIterator})
|
result = semExprNoDeref(c, result, {efWantIterator})
|
||||||
|
|
||||||
proc semFor(c: PContext, n: PNode): PNode =
|
proc semFor(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkMinSonsLen(n, 3)
|
checkMinSonsLen(n, 3)
|
||||||
var length = sonsLen(n)
|
var length = sonsLen(n)
|
||||||
|
|
@ -564,13 +567,13 @@ proc semFor(c: PContext, n: PNode): PNode =
|
||||||
result.typ = enforceVoidContext
|
result.typ = enforceVoidContext
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
||||||
proc semRaise(c: PContext, n: PNode): PNode =
|
proc semRaise(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkSonsLen(n, 1)
|
checkSonsLen(n, 1)
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
n.sons[0] = semExprWithType(c, n.sons[0])
|
n.sons[0] = semExprWithType(c, n.sons[0])
|
||||||
var typ = n.sons[0].typ
|
var typ = n.sons[0].typ
|
||||||
if typ.kind != tyRef or typ.sons[0].kind != tyObject:
|
if typ.kind != tyRef or typ.sons[0].kind != tyObject:
|
||||||
localError(n.info, errExprCannotBeRaised)
|
localError(n.info, errExprCannotBeRaised)
|
||||||
|
|
||||||
proc addGenericParamListToScope(c: PContext, n: PNode) =
|
proc addGenericParamListToScope(c: PContext, n: PNode) =
|
||||||
|
|
@ -580,13 +583,13 @@ proc addGenericParamListToScope(c: PContext, n: PNode) =
|
||||||
if a.kind == nkSym: addDecl(c, a.sym)
|
if a.kind == nkSym: addDecl(c, a.sym)
|
||||||
else: illFormedAst(a)
|
else: illFormedAst(a)
|
||||||
|
|
||||||
proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
||||||
# process the symbols on the left side for the whole type section, before
|
# process the symbols on the left side for the whole type section, before
|
||||||
# we even look at the type definitions on the right
|
# we even look at the type definitions on the right
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if gCmd == cmdIdeTools: suggestStmt(c, a)
|
if gCmd == cmdIdeTools: suggestStmt(c, a)
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if a.kind != nkTypeDef: illFormedAst(a)
|
if a.kind != nkTypeDef: illFormedAst(a)
|
||||||
checkSonsLen(a, 3)
|
checkSonsLen(a, 3)
|
||||||
var s = semIdentDef(c, a.sons[0], skType)
|
var s = semIdentDef(c, a.sons[0], skType)
|
||||||
|
|
@ -599,29 +602,29 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
||||||
a.sons[0] = newSymNode(s)
|
a.sons[0] = newSymNode(s)
|
||||||
|
|
||||||
proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if (a.kind != nkTypeDef): illFormedAst(a)
|
if (a.kind != nkTypeDef): illFormedAst(a)
|
||||||
checkSonsLen(a, 3)
|
checkSonsLen(a, 3)
|
||||||
if (a.sons[0].kind != nkSym): illFormedAst(a)
|
if (a.sons[0].kind != nkSym): illFormedAst(a)
|
||||||
var s = a.sons[0].sym
|
var s = a.sons[0].sym
|
||||||
if s.magic == mNone and a.sons[2].kind == nkEmpty:
|
if s.magic == mNone and a.sons[2].kind == nkEmpty:
|
||||||
localError(a.info, errImplOfXexpected, s.name.s)
|
localError(a.info, errImplOfXexpected, s.name.s)
|
||||||
if s.magic != mNone: processMagicType(c, s)
|
if s.magic != mNone: processMagicType(c, s)
|
||||||
if a.sons[1].kind != nkEmpty:
|
if a.sons[1].kind != nkEmpty:
|
||||||
# We have a generic type declaration here. In generic types,
|
# We have a generic type declaration here. In generic types,
|
||||||
# symbol lookup needs to be done here.
|
# symbol lookup needs to be done here.
|
||||||
openScope(c)
|
openScope(c)
|
||||||
pushOwner(s)
|
pushOwner(s)
|
||||||
if s.magic == mNone: s.typ.kind = tyGenericBody
|
if s.magic == mNone: s.typ.kind = tyGenericBody
|
||||||
# XXX for generic type aliases this is not correct! We need the
|
# XXX for generic type aliases this is not correct! We need the
|
||||||
# underlying Id really:
|
# underlying Id really:
|
||||||
#
|
#
|
||||||
# type
|
# type
|
||||||
# TGObj[T] = object
|
# TGObj[T] = object
|
||||||
# TAlias[T] = TGObj[T]
|
# TAlias[T] = TGObj[T]
|
||||||
#
|
#
|
||||||
s.typ.n = semGenericParamList(c, a.sons[1], s.typ)
|
s.typ.n = semGenericParamList(c, a.sons[1], s.typ)
|
||||||
a.sons[1] = s.typ.n
|
a.sons[1] = s.typ.n
|
||||||
s.typ.size = -1 # could not be computed properly
|
s.typ.size = -1 # could not be computed properly
|
||||||
|
|
@ -639,13 +642,13 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
|
||||||
s.typ.sons[sonsLen(s.typ) - 1] = body
|
s.typ.sons[sonsLen(s.typ) - 1] = body
|
||||||
popOwner()
|
popOwner()
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
elif a.sons[2].kind != nkEmpty:
|
elif a.sons[2].kind != nkEmpty:
|
||||||
# process the type's body:
|
# process the type's body:
|
||||||
pushOwner(s)
|
pushOwner(s)
|
||||||
var t = semTypeNode(c, a.sons[2], s.typ)
|
var t = semTypeNode(c, a.sons[2], s.typ)
|
||||||
if s.typ == nil:
|
if s.typ == nil:
|
||||||
s.typ = t
|
s.typ = t
|
||||||
elif t != s.typ:
|
elif t != s.typ:
|
||||||
# this can happen for e.g. tcan_alias_specialised_generic:
|
# this can happen for e.g. tcan_alias_specialised_generic:
|
||||||
assignType(s.typ, t)
|
assignType(s.typ, t)
|
||||||
#debug s.typ
|
#debug s.typ
|
||||||
|
|
@ -676,23 +679,23 @@ proc checkForMetaFields(n: PNode) =
|
||||||
else:
|
else:
|
||||||
internalAssert false
|
internalAssert false
|
||||||
|
|
||||||
proc typeSectionFinalPass(c: PContext, n: PNode) =
|
proc typeSectionFinalPass(c: PContext, n: PNode) =
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if a.sons[0].kind != nkSym: illFormedAst(a)
|
if a.sons[0].kind != nkSym: illFormedAst(a)
|
||||||
var s = a.sons[0].sym
|
var s = a.sons[0].sym
|
||||||
# compute the type's size and check for illegal recursions:
|
# compute the type's size and check for illegal recursions:
|
||||||
if a.sons[1].kind == nkEmpty:
|
if a.sons[1].kind == nkEmpty:
|
||||||
if a.sons[2].kind in {nkSym, nkIdent, nkAccQuoted}:
|
if a.sons[2].kind in {nkSym, nkIdent, nkAccQuoted}:
|
||||||
# type aliases are hard:
|
# type aliases are hard:
|
||||||
#MessageOut('for type ' + typeToString(s.typ));
|
#MessageOut('for type ' + typeToString(s.typ));
|
||||||
var t = semTypeNode(c, a.sons[2], nil)
|
var t = semTypeNode(c, a.sons[2], nil)
|
||||||
if t.kind in {tyObject, tyEnum}:
|
if t.kind in {tyObject, tyEnum}:
|
||||||
assignType(s.typ, t)
|
assignType(s.typ, t)
|
||||||
s.typ.id = t.id # same id
|
s.typ.id = t.id # same id
|
||||||
checkConstructedType(s.info, s.typ)
|
checkConstructedType(s.info, s.typ)
|
||||||
if s.typ.kind in {tyObject, tyTuple}:
|
if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil:
|
||||||
checkForMetaFields(s.typ.n)
|
checkForMetaFields(s.typ.n)
|
||||||
let aa = a.sons[2]
|
let aa = a.sons[2]
|
||||||
if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
|
if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
|
||||||
|
|
@ -720,21 +723,21 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym) =
|
||||||
if s.typ.sons[0] != nil and s.typ.sons[0].kind == tyStmt:
|
if s.typ.sons[0] != nil and s.typ.sons[0].kind == tyStmt:
|
||||||
localError(n.info, errGenerated, "invalid return type: 'stmt'")
|
localError(n.info, errGenerated, "invalid return type: 'stmt'")
|
||||||
|
|
||||||
proc addParams(c: PContext, n: PNode, kind: TSymKind) =
|
proc addParams(c: PContext, n: PNode, kind: TSymKind) =
|
||||||
for i in countup(1, sonsLen(n)-1):
|
for i in countup(1, sonsLen(n)-1):
|
||||||
if n.sons[i].kind == nkSym: addParamOrResult(c, n.sons[i].sym, kind)
|
if n.sons[i].kind == nkSym: addParamOrResult(c, n.sons[i].sym, kind)
|
||||||
else: illFormedAst(n)
|
else: illFormedAst(n)
|
||||||
|
|
||||||
proc semBorrow(c: PContext, n: PNode, s: PSym) =
|
proc semBorrow(c: PContext, n: PNode, s: PSym) =
|
||||||
# search for the correct alias:
|
# search for the correct alias:
|
||||||
var b = searchForBorrowProc(c, c.currentScope.parent, s)
|
var b = searchForBorrowProc(c, c.currentScope.parent, s)
|
||||||
if b != nil:
|
if b != nil:
|
||||||
# store the alias:
|
# store the alias:
|
||||||
n.sons[bodyPos] = newSymNode(b)
|
n.sons[bodyPos] = newSymNode(b)
|
||||||
else:
|
else:
|
||||||
localError(n.info, errNoSymbolToBorrowFromFound)
|
localError(n.info, errNoSymbolToBorrowFromFound)
|
||||||
|
|
||||||
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
|
proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
|
||||||
if t != nil:
|
if t != nil:
|
||||||
var s = newSym(skResult, getIdent"result", getCurrOwner(), info)
|
var s = newSym(skResult, getIdent"result", getCurrOwner(), info)
|
||||||
s.typ = t
|
s.typ = t
|
||||||
|
|
@ -742,7 +745,7 @@ proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
|
||||||
addParamOrResult(c, s, owner)
|
addParamOrResult(c, s, owner)
|
||||||
c.p.resultSym = s
|
c.p.resultSym = s
|
||||||
|
|
||||||
proc addResultNode(c: PContext, n: PNode) =
|
proc addResultNode(c: PContext, n: PNode) =
|
||||||
if c.p.resultSym != nil: addSon(n, newSymNode(c.p.resultSym))
|
if c.p.resultSym != nil: addSon(n, newSymNode(c.p.resultSym))
|
||||||
|
|
||||||
proc copyExcept(n: PNode, i: int): PNode =
|
proc copyExcept(n: PNode, i: int): PNode =
|
||||||
|
|
@ -786,7 +789,8 @@ proc semProcAnnotation(c: PContext, prc: PNode;
|
||||||
result = semStmt(c, x)
|
result = semStmt(c, x)
|
||||||
# since a proc annotation can set pragmas, we process these here again.
|
# since a proc annotation can set pragmas, we process these here again.
|
||||||
# This is required for SqueakNim-like export pragmas.
|
# This is required for SqueakNim-like export pragmas.
|
||||||
if result[namePos].kind == nkSym and result[pragmasPos].kind != nkEmpty:
|
if result.kind in procDefs and result[namePos].kind == nkSym and
|
||||||
|
result[pragmasPos].kind != nkEmpty:
|
||||||
pragma(c, result[namePos].sym, result[pragmasPos], validPragmas)
|
pragma(c, result[namePos].sym, result[pragmasPos], validPragmas)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -807,7 +811,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
pushOwner(s)
|
pushOwner(s)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
var gp: PNode
|
var gp: PNode
|
||||||
if n.sons[genericParamsPos].kind != nkEmpty:
|
if n.sons[genericParamsPos].kind != nkEmpty:
|
||||||
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
|
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
|
||||||
gp = n.sons[genericParamsPos]
|
gp = n.sons[genericParamsPos]
|
||||||
else:
|
else:
|
||||||
|
|
@ -857,13 +861,13 @@ proc semDo(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
|
||||||
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
|
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
|
||||||
var n = n
|
var n = n
|
||||||
|
|
||||||
n = replaceTypesInBody(c, pt, n)
|
n = replaceTypesInBody(c, pt, n)
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
n.sons[genericParamsPos] = emptyNode
|
n.sons[genericParamsPos] = emptyNode
|
||||||
n.sons[paramsPos] = n.typ.n
|
n.sons[paramsPos] = n.typ.n
|
||||||
|
|
||||||
openScope(c)
|
openScope(c)
|
||||||
var s = n.sons[namePos].sym
|
var s = n.sons[namePos].sym
|
||||||
pushOwner(s)
|
pushOwner(s)
|
||||||
|
|
@ -876,7 +880,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
|
||||||
popProcCon(c)
|
popProcCon(c)
|
||||||
popOwner()
|
popOwner()
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
||||||
s.ast = result
|
s.ast = result
|
||||||
|
|
||||||
# alternative variant (not quite working):
|
# alternative variant (not quite working):
|
||||||
|
|
@ -922,7 +926,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||||
else: break
|
else: break
|
||||||
if t.kind in {tyObject, tyDistinct, tyEnum}:
|
if t.kind in {tyObject, tyDistinct, tyEnum}:
|
||||||
if t.deepCopy.isNil: t.deepCopy = s
|
if t.deepCopy.isNil: t.deepCopy = s
|
||||||
else:
|
else:
|
||||||
localError(n.info, errGenerated,
|
localError(n.info, errGenerated,
|
||||||
"cannot bind another 'deepCopy' to: " & typeToString(t))
|
"cannot bind another 'deepCopy' to: " & typeToString(t))
|
||||||
else:
|
else:
|
||||||
|
|
@ -989,10 +993,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
pushOwner(s)
|
pushOwner(s)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
var gp: PNode
|
var gp: PNode
|
||||||
if n.sons[genericParamsPos].kind != nkEmpty:
|
if n.sons[genericParamsPos].kind != nkEmpty:
|
||||||
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
|
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
|
||||||
gp = n.sons[genericParamsPos]
|
gp = n.sons[genericParamsPos]
|
||||||
else:
|
else:
|
||||||
gp = newNodeI(nkGenericParams, n.info)
|
gp = newNodeI(nkGenericParams, n.info)
|
||||||
# process parameters:
|
# process parameters:
|
||||||
if n.sons[paramsPos].kind != nkEmpty:
|
if n.sons[paramsPos].kind != nkEmpty:
|
||||||
|
|
@ -1009,7 +1013,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
n.sons[patternPos] = semPattern(c, n.sons[patternPos])
|
n.sons[patternPos] = semPattern(c, n.sons[patternPos])
|
||||||
if s.kind in skIterators:
|
if s.kind in skIterators:
|
||||||
s.typ.flags.incl(tfIterator)
|
s.typ.flags.incl(tfIterator)
|
||||||
|
|
||||||
var proto = searchForProc(c, s.scope, s)
|
var proto = searchForProc(c, s.scope, s)
|
||||||
if proto == nil:
|
if proto == nil:
|
||||||
if s.kind == skClosureIterator: s.typ.callConv = ccClosure
|
if s.kind == skClosureIterator: s.typ.callConv = ccClosure
|
||||||
|
|
@ -1027,14 +1031,14 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
else:
|
else:
|
||||||
implicitPragmas(c, s, n, validPragmas)
|
implicitPragmas(c, s, n, validPragmas)
|
||||||
else:
|
else:
|
||||||
if n.sons[pragmasPos].kind != nkEmpty:
|
if n.sons[pragmasPos].kind != nkEmpty:
|
||||||
localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProc)
|
localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProc)
|
||||||
if sfForward notin proto.flags:
|
if sfForward notin proto.flags:
|
||||||
wrongRedefinition(n.info, proto.name.s)
|
wrongRedefinition(n.info, proto.name.s)
|
||||||
excl(proto.flags, sfForward)
|
excl(proto.flags, sfForward)
|
||||||
closeScope(c) # close scope with wrong parameter symbols
|
closeScope(c) # close scope with wrong parameter symbols
|
||||||
openScope(c) # open scope for old (correct) parameter symbols
|
openScope(c) # open scope for old (correct) parameter symbols
|
||||||
if proto.ast.sons[genericParamsPos].kind != nkEmpty:
|
if proto.ast.sons[genericParamsPos].kind != nkEmpty:
|
||||||
addGenericParamListToScope(c, proto.ast.sons[genericParamsPos])
|
addGenericParamListToScope(c, proto.ast.sons[genericParamsPos])
|
||||||
addParams(c, proto.typ.n, proto.kind)
|
addParams(c, proto.typ.n, proto.kind)
|
||||||
proto.info = s.info # more accurate line information
|
proto.info = s.info # more accurate line information
|
||||||
|
|
@ -1084,7 +1088,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
n.sons[bodyPos] = ast.emptyNode
|
n.sons[bodyPos] = ast.emptyNode
|
||||||
else:
|
else:
|
||||||
if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s)
|
if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s)
|
||||||
if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone:
|
if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone:
|
||||||
incl(s.flags, sfForward)
|
incl(s.flags, sfForward)
|
||||||
elif sfBorrow in s.flags: semBorrow(c, n, s)
|
elif sfBorrow in s.flags: semBorrow(c, n, s)
|
||||||
sideEffectsCheck(c, s)
|
sideEffectsCheck(c, s)
|
||||||
|
|
@ -1122,14 +1126,14 @@ proc semIterator(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
s.typ.callConv = ccInline
|
s.typ.callConv = ccInline
|
||||||
when false:
|
when false:
|
||||||
if s.typ.callConv != ccInline:
|
if s.typ.callConv != ccInline:
|
||||||
s.typ.callConv = ccClosure
|
s.typ.callConv = ccClosure
|
||||||
# and they always at least use the 'env' for the state field:
|
# and they always at least use the 'env' for the state field:
|
||||||
incl(s.typ.flags, tfCapturesEnv)
|
incl(s.typ.flags, tfCapturesEnv)
|
||||||
if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone:
|
if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone:
|
||||||
localError(n.info, errImplOfXexpected, s.name.s)
|
localError(n.info, errImplOfXexpected, s.name.s)
|
||||||
|
|
||||||
proc semProc(c: PContext, n: PNode): PNode =
|
proc semProc(c: PContext, n: PNode): PNode =
|
||||||
result = semProcAux(c, n, skProc, procPragmas)
|
result = semProcAux(c, n, skProc, procPragmas)
|
||||||
|
|
||||||
proc hasObjParam(s: PSym): bool =
|
proc hasObjParam(s: PSym): bool =
|
||||||
|
|
@ -1142,10 +1146,10 @@ proc finishMethod(c: PContext, s: PSym) =
|
||||||
if hasObjParam(s):
|
if hasObjParam(s):
|
||||||
methodDef(s, false)
|
methodDef(s, false)
|
||||||
|
|
||||||
proc semMethod(c: PContext, n: PNode): PNode =
|
proc semMethod(c: PContext, n: PNode): PNode =
|
||||||
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method")
|
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method")
|
||||||
result = semProcAux(c, n, skMethod, methodPragmas)
|
result = semProcAux(c, n, skMethod, methodPragmas)
|
||||||
|
|
||||||
var s = result.sons[namePos].sym
|
var s = result.sons[namePos].sym
|
||||||
if not isGenericRoutine(s) and result.sons[bodyPos].kind != nkEmpty:
|
if not isGenericRoutine(s) and result.sons[bodyPos].kind != nkEmpty:
|
||||||
if hasObjParam(s):
|
if hasObjParam(s):
|
||||||
|
|
@ -1153,7 +1157,7 @@ proc semMethod(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
localError(n.info, errXNeedsParamObjectType, "method")
|
localError(n.info, errXNeedsParamObjectType, "method")
|
||||||
|
|
||||||
proc semConverterDef(c: PContext, n: PNode): PNode =
|
proc semConverterDef(c: PContext, n: PNode): PNode =
|
||||||
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter")
|
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter")
|
||||||
checkSonsLen(n, bodyPos + 1)
|
checkSonsLen(n, bodyPos + 1)
|
||||||
result = semProcAux(c, n, skConverter, converterPragmas)
|
result = semProcAux(c, n, skConverter, converterPragmas)
|
||||||
|
|
@ -1163,7 +1167,7 @@ proc semConverterDef(c: PContext, n: PNode): PNode =
|
||||||
if sonsLen(t) != 2: localError(n.info, errXRequiresOneArgument, "converter")
|
if sonsLen(t) != 2: localError(n.info, errXRequiresOneArgument, "converter")
|
||||||
addConverter(c, s)
|
addConverter(c, s)
|
||||||
|
|
||||||
proc semMacroDef(c: PContext, n: PNode): PNode =
|
proc semMacroDef(c: PContext, n: PNode): PNode =
|
||||||
checkSonsLen(n, bodyPos + 1)
|
checkSonsLen(n, bodyPos + 1)
|
||||||
result = semProcAux(c, n, skMacro, macroPragmas)
|
result = semProcAux(c, n, skMacro, macroPragmas)
|
||||||
var s = result.sons[namePos].sym
|
var s = result.sons[namePos].sym
|
||||||
|
|
@ -1171,23 +1175,23 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
|
||||||
if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro")
|
if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro")
|
||||||
if n.sons[bodyPos].kind == nkEmpty:
|
if n.sons[bodyPos].kind == nkEmpty:
|
||||||
localError(n.info, errImplOfXexpected, s.name.s)
|
localError(n.info, errImplOfXexpected, s.name.s)
|
||||||
|
|
||||||
proc evalInclude(c: PContext, n: PNode): PNode =
|
proc evalInclude(c: PContext, n: PNode): PNode =
|
||||||
result = newNodeI(nkStmtList, n.info)
|
result = newNodeI(nkStmtList, n.info)
|
||||||
addSon(result, n)
|
addSon(result, n)
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var f = checkModuleName(n.sons[i])
|
var f = checkModuleName(n.sons[i])
|
||||||
if f != InvalidFileIDX:
|
if f != InvalidFileIDX:
|
||||||
if containsOrIncl(c.includedFiles, f):
|
if containsOrIncl(c.includedFiles, f):
|
||||||
localError(n.info, errRecursiveDependencyX, f.toFilename)
|
localError(n.info, errRecursiveDependencyX, f.toFilename)
|
||||||
else:
|
else:
|
||||||
addSon(result, semStmt(c, gIncludeFile(c.module, f)))
|
addSon(result, semStmt(c, gIncludeFile(c.module, f)))
|
||||||
excl(c.includedFiles, f)
|
excl(c.includedFiles, f)
|
||||||
|
|
||||||
proc setLine(n: PNode, info: TLineInfo) =
|
proc setLine(n: PNode, info: TLineInfo) =
|
||||||
for i in 0 .. <safeLen(n): setLine(n.sons[i], info)
|
for i in 0 .. <safeLen(n): setLine(n.sons[i], info)
|
||||||
n.info = info
|
n.info = info
|
||||||
|
|
||||||
proc semPragmaBlock(c: PContext, n: PNode): PNode =
|
proc semPragmaBlock(c: PContext, n: PNode): PNode =
|
||||||
let pragmaList = n.sons[0]
|
let pragmaList = n.sons[0]
|
||||||
pragma(c, nil, pragmaList, exprPragmas)
|
pragma(c, nil, pragmaList, exprPragmas)
|
||||||
|
|
@ -1196,7 +1200,7 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
|
||||||
for i in 0 .. <pragmaList.len:
|
for i in 0 .. <pragmaList.len:
|
||||||
case whichPragma(pragmaList.sons[i])
|
case whichPragma(pragmaList.sons[i])
|
||||||
of wLine: setLine(result, pragmaList.sons[i].info)
|
of wLine: setLine(result, pragmaList.sons[i].info)
|
||||||
of wLocks:
|
of wLocks:
|
||||||
result = n
|
result = n
|
||||||
result.typ = n.sons[1].typ
|
result.typ = n.sons[1].typ
|
||||||
else: discard
|
else: discard
|
||||||
|
|
@ -1311,8 +1315,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
inner.addSon(semStmtList(c, rest, flags))
|
inner.addSon(semStmtList(c, rest, flags))
|
||||||
n.sons.setLen(i+1)
|
n.sons.setLen(i+1)
|
||||||
return
|
return
|
||||||
of LastBlockStmts:
|
of LastBlockStmts:
|
||||||
for j in countup(i + 1, length - 1):
|
for j in countup(i + 1, length - 1):
|
||||||
case n.sons[j].kind
|
case n.sons[j].kind
|
||||||
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard
|
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard
|
||||||
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
|
else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
|
||||||
|
|
@ -1334,7 +1338,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
# "Last expression must be explicitly returned if it " &
|
# "Last expression must be explicitly returned if it " &
|
||||||
# "is discardable or discarded")
|
# "is discardable or discarded")
|
||||||
|
|
||||||
proc semStmt(c: PContext, n: PNode): PNode =
|
proc semStmt(c: PContext, n: PNode): PNode =
|
||||||
# now: simply an alias:
|
# now: simply an alias:
|
||||||
result = semExprNoType(c, n)
|
result = semExprNoType(c, n)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,14 @@
|
||||||
# this module does the semantic checking of type declarations
|
# this module does the semantic checking of type declarations
|
||||||
# included from sem.nim
|
# included from sem.nim
|
||||||
|
|
||||||
proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
|
proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
|
||||||
if prev == nil:
|
if prev == nil:
|
||||||
result = newTypeS(kind, c)
|
result = newTypeS(kind, c)
|
||||||
else:
|
else:
|
||||||
result = prev
|
result = prev
|
||||||
if result.kind == tyForward: result.kind = kind
|
if result.kind == tyForward: result.kind = kind
|
||||||
|
|
||||||
proc newConstraint(c: PContext, k: TTypeKind): PType =
|
proc newConstraint(c: PContext, k: TTypeKind): PType =
|
||||||
result = newTypeS(tyBuiltInTypeClass, c)
|
result = newTypeS(tyBuiltInTypeClass, c)
|
||||||
result.addSonSkipIntLit(newTypeS(k, c))
|
result.addSonSkipIntLit(newTypeS(k, c))
|
||||||
|
|
||||||
|
|
@ -32,22 +32,22 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = newOrPrevType(tyEnum, prev, c)
|
result = newOrPrevType(tyEnum, prev, c)
|
||||||
result.n = newNodeI(nkEnumTy, n.info)
|
result.n = newNodeI(nkEnumTy, n.info)
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
base = semTypeNode(c, n.sons[0].sons[0], nil)
|
base = semTypeNode(c, n.sons[0].sons[0], nil)
|
||||||
if base.kind != tyEnum:
|
if base.kind != tyEnum:
|
||||||
localError(n.sons[0].info, errInheritanceOnlyWithEnums)
|
localError(n.sons[0].info, errInheritanceOnlyWithEnums)
|
||||||
counter = lastOrd(base) + 1
|
counter = lastOrd(base) + 1
|
||||||
rawAddSon(result, base)
|
rawAddSon(result, base)
|
||||||
let isPure = result.sym != nil and sfPure in result.sym.flags
|
let isPure = result.sym != nil and sfPure in result.sym.flags
|
||||||
var hasNull = false
|
var hasNull = false
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
case n.sons[i].kind
|
case n.sons[i].kind
|
||||||
of nkEnumFieldDef:
|
of nkEnumFieldDef:
|
||||||
e = newSymS(skEnumField, n.sons[i].sons[0], c)
|
e = newSymS(skEnumField, n.sons[i].sons[0], c)
|
||||||
var v = semConstExpr(c, n.sons[i].sons[1])
|
var v = semConstExpr(c, n.sons[i].sons[1])
|
||||||
var strVal: PNode = nil
|
var strVal: PNode = nil
|
||||||
case skipTypes(v.typ, abstractInst-{tyTypeDesc}).kind
|
case skipTypes(v.typ, abstractInst-{tyTypeDesc}).kind
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
if sonsLen(v) == 2:
|
if sonsLen(v) == 2:
|
||||||
strVal = v.sons[1] # second tuple part is the string value
|
strVal = v.sons[1] # second tuple part is the string value
|
||||||
if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCString}:
|
if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCString}:
|
||||||
|
|
@ -63,14 +63,14 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||||
x = getOrdValue(v)
|
x = getOrdValue(v)
|
||||||
if i != 1:
|
if i != 1:
|
||||||
if x != counter: incl(result.flags, tfEnumHasHoles)
|
if x != counter: incl(result.flags, tfEnumHasHoles)
|
||||||
if x < counter:
|
if x < counter:
|
||||||
localError(n.sons[i].info, errInvalidOrderInEnumX, e.name.s)
|
localError(n.sons[i].info, errInvalidOrderInEnumX, e.name.s)
|
||||||
x = counter
|
x = counter
|
||||||
e.ast = strVal # might be nil
|
e.ast = strVal # might be nil
|
||||||
counter = x
|
counter = x
|
||||||
of nkSym:
|
of nkSym:
|
||||||
e = n.sons[i].sym
|
e = n.sons[i].sym
|
||||||
of nkIdent, nkAccQuoted:
|
of nkIdent, nkAccQuoted:
|
||||||
e = newSymS(skEnumField, n.sons[i], c)
|
e = newSymS(skEnumField, n.sons[i], c)
|
||||||
else:
|
else:
|
||||||
illFormedAst(n[i])
|
illFormedAst(n[i])
|
||||||
|
|
@ -87,28 +87,28 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||||
inc(counter)
|
inc(counter)
|
||||||
if not hasNull: incl(result.flags, tfNeedsInit)
|
if not hasNull: incl(result.flags, tfNeedsInit)
|
||||||
|
|
||||||
proc semSet(c: PContext, n: PNode, prev: PType): PType =
|
proc semSet(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = newOrPrevType(tySet, prev, c)
|
result = newOrPrevType(tySet, prev, c)
|
||||||
if sonsLen(n) == 2:
|
if sonsLen(n) == 2:
|
||||||
var base = semTypeNode(c, n.sons[1], nil)
|
var base = semTypeNode(c, n.sons[1], nil)
|
||||||
addSonSkipIntLit(result, base)
|
addSonSkipIntLit(result, base)
|
||||||
if base.kind == tyGenericInst: base = lastSon(base)
|
if base.kind == tyGenericInst: base = lastSon(base)
|
||||||
if base.kind != tyGenericParam:
|
if base.kind != tyGenericParam:
|
||||||
if not isOrdinalType(base):
|
if not isOrdinalType(base):
|
||||||
localError(n.info, errOrdinalTypeExpected)
|
localError(n.info, errOrdinalTypeExpected)
|
||||||
elif lengthOrd(base) > MaxSetElements:
|
elif lengthOrd(base) > MaxSetElements:
|
||||||
localError(n.info, errSetTooBig)
|
localError(n.info, errSetTooBig)
|
||||||
else:
|
else:
|
||||||
localError(n.info, errXExpectsOneTypeParam, "set")
|
localError(n.info, errXExpectsOneTypeParam, "set")
|
||||||
addSonSkipIntLit(result, errorType(c))
|
addSonSkipIntLit(result, errorType(c))
|
||||||
|
|
||||||
proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
|
proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
|
||||||
prev: PType): PType =
|
prev: PType): PType =
|
||||||
result = newOrPrevType(kind, prev, c)
|
result = newOrPrevType(kind, prev, c)
|
||||||
if sonsLen(n) == 2:
|
if sonsLen(n) == 2:
|
||||||
var base = semTypeNode(c, n.sons[1], nil)
|
var base = semTypeNode(c, n.sons[1], nil)
|
||||||
addSonSkipIntLit(result, base)
|
addSonSkipIntLit(result, base)
|
||||||
else:
|
else:
|
||||||
localError(n.info, errXExpectsOneTypeParam, kindStr)
|
localError(n.info, errXExpectsOneTypeParam, kindStr)
|
||||||
addSonSkipIntLit(result, errorType(c))
|
addSonSkipIntLit(result, errorType(c))
|
||||||
|
|
||||||
|
|
@ -140,23 +140,23 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
||||||
var base = semTypeNode(c, n.lastSon, nil)
|
var base = semTypeNode(c, n.lastSon, nil)
|
||||||
addSonSkipIntLit(result, base)
|
addSonSkipIntLit(result, base)
|
||||||
|
|
||||||
proc semVarType(c: PContext, n: PNode, prev: PType): PType =
|
proc semVarType(c: PContext, n: PNode, prev: PType): PType =
|
||||||
if sonsLen(n) == 1:
|
if sonsLen(n) == 1:
|
||||||
result = newOrPrevType(tyVar, prev, c)
|
result = newOrPrevType(tyVar, prev, c)
|
||||||
var base = semTypeNode(c, n.sons[0], nil)
|
var base = semTypeNode(c, n.sons[0], nil)
|
||||||
if base.kind == tyVar:
|
if base.kind == tyVar:
|
||||||
localError(n.info, errVarVarTypeNotAllowed)
|
localError(n.info, errVarVarTypeNotAllowed)
|
||||||
base = base.sons[0]
|
base = base.sons[0]
|
||||||
addSonSkipIntLit(result, base)
|
addSonSkipIntLit(result, base)
|
||||||
else:
|
else:
|
||||||
result = newConstraint(c, tyVar)
|
result = newConstraint(c, tyVar)
|
||||||
|
|
||||||
proc semDistinct(c: PContext, n: PNode, prev: PType): PType =
|
proc semDistinct(c: PContext, n: PNode, prev: PType): PType =
|
||||||
if n.len == 0: return newConstraint(c, tyDistinct)
|
if n.len == 0: return newConstraint(c, tyDistinct)
|
||||||
result = newOrPrevType(tyDistinct, prev, c)
|
result = newOrPrevType(tyDistinct, prev, c)
|
||||||
addSonSkipIntLit(result, semTypeNode(c, n.sons[0], nil))
|
addSonSkipIntLit(result, semTypeNode(c, n.sons[0], nil))
|
||||||
if n.len > 1: result.n = n[1]
|
if n.len > 1: result.n = n[1]
|
||||||
|
|
||||||
proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
|
proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
|
||||||
assert isRange(n)
|
assert isRange(n)
|
||||||
checkSonsLen(n, 3)
|
checkSonsLen(n, 3)
|
||||||
|
|
@ -164,11 +164,11 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result.n = newNodeI(nkRange, n.info)
|
result.n = newNodeI(nkRange, n.info)
|
||||||
if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty):
|
if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty):
|
||||||
localError(n.info, errRangeIsEmpty)
|
localError(n.info, errRangeIsEmpty)
|
||||||
|
|
||||||
var range: array[2, PNode]
|
var range: array[2, PNode]
|
||||||
range[0] = semExprWithType(c, n[1], {efDetermineType})
|
range[0] = semExprWithType(c, n[1], {efDetermineType})
|
||||||
range[1] = semExprWithType(c, n[2], {efDetermineType})
|
range[1] = semExprWithType(c, n[2], {efDetermineType})
|
||||||
|
|
||||||
var rangeT: array[2, PType]
|
var rangeT: array[2, PType]
|
||||||
for i in 0..1:
|
for i in 0..1:
|
||||||
rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit
|
rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit
|
||||||
|
|
@ -179,13 +179,13 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
|
||||||
localError(n.info, errOrdinalTypeExpected)
|
localError(n.info, errOrdinalTypeExpected)
|
||||||
elif enumHasHoles(rangeT[0]):
|
elif enumHasHoles(rangeT[0]):
|
||||||
localError(n.info, errEnumXHasHoles, rangeT[0].sym.name.s)
|
localError(n.info, errEnumXHasHoles, rangeT[0].sym.name.s)
|
||||||
|
|
||||||
for i in 0..1:
|
for i in 0..1:
|
||||||
if hasGenericArguments(range[i]):
|
if hasGenericArguments(range[i]):
|
||||||
result.n.addSon makeStaticExpr(c, range[i])
|
result.n.addSon makeStaticExpr(c, range[i])
|
||||||
else:
|
else:
|
||||||
result.n.addSon semConstExpr(c, range[i])
|
result.n.addSon semConstExpr(c, range[i])
|
||||||
|
|
||||||
if weakLeValue(result.n[0], result.n[1]) == impNo:
|
if weakLeValue(result.n[0], result.n[1]) == impNo:
|
||||||
localError(n.info, errRangeIsEmpty)
|
localError(n.info, errRangeIsEmpty)
|
||||||
|
|
||||||
|
|
@ -201,10 +201,10 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
|
||||||
incl(result.flags, tfNeedsInit)
|
incl(result.flags, tfNeedsInit)
|
||||||
elif n.sons[1].kind in {nkCharLit..nkUInt64Lit} and n.sons[1].intVal < 0:
|
elif n.sons[1].kind in {nkCharLit..nkUInt64Lit} and n.sons[1].intVal < 0:
|
||||||
incl(result.flags, tfNeedsInit)
|
incl(result.flags, tfNeedsInit)
|
||||||
elif n.sons[0].kind in {nkFloatLit..nkFloat64Lit} and
|
elif n.sons[0].kind in {nkFloatLit..nkFloat64Lit} and
|
||||||
n.sons[0].floatVal > 0.0:
|
n.sons[0].floatVal > 0.0:
|
||||||
incl(result.flags, tfNeedsInit)
|
incl(result.flags, tfNeedsInit)
|
||||||
elif n.sons[1].kind in {nkFloatLit..nkFloat64Lit} and
|
elif n.sons[1].kind in {nkFloatLit..nkFloat64Lit} and
|
||||||
n.sons[1].floatVal < 0.0:
|
n.sons[1].floatVal < 0.0:
|
||||||
incl(result.flags, tfNeedsInit)
|
incl(result.flags, tfNeedsInit)
|
||||||
else:
|
else:
|
||||||
|
|
@ -243,13 +243,13 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
|
||||||
else:
|
else:
|
||||||
let x = semConstExpr(c, e)
|
let x = semConstExpr(c, e)
|
||||||
if x.kind in {nkIntLit..nkUInt64Lit}:
|
if x.kind in {nkIntLit..nkUInt64Lit}:
|
||||||
result = makeRangeType(c, 0, x.intVal-1, n.info,
|
result = makeRangeType(c, 0, x.intVal-1, n.info,
|
||||||
x.typ.skipTypes({tyTypeDesc}))
|
x.typ.skipTypes({tyTypeDesc}))
|
||||||
else:
|
else:
|
||||||
result = x.typ.skipTypes({tyTypeDesc})
|
result = x.typ.skipTypes({tyTypeDesc})
|
||||||
#localError(n[1].info, errConstExprExpected)
|
#localError(n[1].info, errConstExprExpected)
|
||||||
|
|
||||||
proc semArray(c: PContext, n: PNode, prev: PType): PType =
|
proc semArray(c: PContext, n: PNode, prev: PType): PType =
|
||||||
var base: PType
|
var base: PType
|
||||||
result = newOrPrevType(tyArray, prev, c)
|
result = newOrPrevType(tyArray, prev, c)
|
||||||
if sonsLen(n) == 3:
|
if sonsLen(n) == 3:
|
||||||
|
|
@ -260,20 +260,20 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
|
||||||
if indx.kind notin {tyGenericParam, tyStatic, tyFromExpr}:
|
if indx.kind notin {tyGenericParam, tyStatic, tyFromExpr}:
|
||||||
if not isOrdinalType(indx):
|
if not isOrdinalType(indx):
|
||||||
localError(n.sons[1].info, errOrdinalTypeExpected)
|
localError(n.sons[1].info, errOrdinalTypeExpected)
|
||||||
elif enumHasHoles(indx):
|
elif enumHasHoles(indx):
|
||||||
localError(n.sons[1].info, errEnumXHasHoles, indx.sym.name.s)
|
localError(n.sons[1].info, errEnumXHasHoles, indx.sym.name.s)
|
||||||
base = semTypeNode(c, n.sons[2], nil)
|
base = semTypeNode(c, n.sons[2], nil)
|
||||||
addSonSkipIntLit(result, base)
|
addSonSkipIntLit(result, base)
|
||||||
else:
|
else:
|
||||||
localError(n.info, errArrayExpectsTwoTypeParams)
|
localError(n.info, errArrayExpectsTwoTypeParams)
|
||||||
result = newOrPrevType(tyError, prev, c)
|
result = newOrPrevType(tyError, prev, c)
|
||||||
|
|
||||||
proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
|
proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = newOrPrevType(tyOrdinal, prev, c)
|
result = newOrPrevType(tyOrdinal, prev, c)
|
||||||
if sonsLen(n) == 2:
|
if sonsLen(n) == 2:
|
||||||
var base = semTypeNode(c, n.sons[1], nil)
|
var base = semTypeNode(c, n.sons[1], nil)
|
||||||
if base.kind != tyGenericParam:
|
if base.kind != tyGenericParam:
|
||||||
if not isOrdinalType(base):
|
if not isOrdinalType(base):
|
||||||
localError(n.sons[1].info, errOrdinalTypeExpected)
|
localError(n.sons[1].info, errOrdinalTypeExpected)
|
||||||
addSonSkipIntLit(result, base)
|
addSonSkipIntLit(result, base)
|
||||||
else:
|
else:
|
||||||
|
|
@ -281,7 +281,7 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = newOrPrevType(tyError, prev, c)
|
result = newOrPrevType(tyError, prev, c)
|
||||||
|
|
||||||
proc semTypeIdent(c: PContext, n: PNode): PSym =
|
proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||||
if n.kind == nkSym:
|
if n.kind == nkSym:
|
||||||
result = n.sym
|
result = n.sym
|
||||||
else:
|
else:
|
||||||
when defined(nimfix):
|
when defined(nimfix):
|
||||||
|
|
@ -307,7 +307,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||||
result = result.typ.sym.copySym
|
result = result.typ.sym.copySym
|
||||||
result.typ = copyType(result.typ, result.typ.owner, true)
|
result.typ = copyType(result.typ, result.typ.owner, true)
|
||||||
result.typ.flags.incl tfUnresolved
|
result.typ.flags.incl tfUnresolved
|
||||||
|
|
||||||
if result.kind == skGenericParam:
|
if result.kind == skGenericParam:
|
||||||
if result.typ.kind == tyGenericParam and result.typ.len == 0 and
|
if result.typ.kind == tyGenericParam and result.typ.len == 0 and
|
||||||
tfWildcard in result.typ.flags:
|
tfWildcard in result.typ.flags:
|
||||||
|
|
@ -319,7 +319,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||||
localError(n.info, errTypeExpected)
|
localError(n.info, errTypeExpected)
|
||||||
return errorSym(c, n)
|
return errorSym(c, n)
|
||||||
|
|
||||||
if result.kind != skType:
|
if result.kind != skType:
|
||||||
# this implements the wanted ``var v: V, x: V`` feature ...
|
# this implements the wanted ``var v: V, x: V`` feature ...
|
||||||
var ov: TOverloadIter
|
var ov: TOverloadIter
|
||||||
var amb = initOverloadIter(ov, c, n)
|
var amb = initOverloadIter(ov, c, n)
|
||||||
|
|
@ -344,48 +344,54 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||||
else:
|
else:
|
||||||
localError(n.info, errIdentifierExpected)
|
localError(n.info, errIdentifierExpected)
|
||||||
result = errorSym(c, n)
|
result = errorSym(c, n)
|
||||||
|
|
||||||
|
proc semAnonTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||||
|
if sonsLen(n) == 0:
|
||||||
|
localError(n.info, errTypeExpected)
|
||||||
|
result = newOrPrevType(tyTuple, prev, c)
|
||||||
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
|
addSonSkipIntLit(result, semTypeNode(c, n.sons[i], nil))
|
||||||
|
|
||||||
proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||||
if n.sonsLen == 0: return newConstraint(c, tyTuple)
|
|
||||||
var typ: PType
|
var typ: PType
|
||||||
result = newOrPrevType(tyTuple, prev, c)
|
result = newOrPrevType(tyTuple, prev, c)
|
||||||
result.n = newNodeI(nkRecList, n.info)
|
result.n = newNodeI(nkRecList, n.info)
|
||||||
var check = initIntSet()
|
var check = initIntSet()
|
||||||
var counter = 0
|
var counter = 0
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if (a.kind != nkIdentDefs): illFormedAst(a)
|
if (a.kind != nkIdentDefs): illFormedAst(a)
|
||||||
checkMinSonsLen(a, 3)
|
checkMinSonsLen(a, 3)
|
||||||
var length = sonsLen(a)
|
var length = sonsLen(a)
|
||||||
if a.sons[length - 2].kind != nkEmpty:
|
if a.sons[length - 2].kind != nkEmpty:
|
||||||
typ = semTypeNode(c, a.sons[length - 2], nil)
|
typ = semTypeNode(c, a.sons[length - 2], nil)
|
||||||
else:
|
else:
|
||||||
localError(a.info, errTypeExpected)
|
localError(a.info, errTypeExpected)
|
||||||
typ = errorType(c)
|
typ = errorType(c)
|
||||||
if a.sons[length - 1].kind != nkEmpty:
|
if a.sons[length - 1].kind != nkEmpty:
|
||||||
localError(a.sons[length - 1].info, errInitHereNotAllowed)
|
localError(a.sons[length - 1].info, errInitHereNotAllowed)
|
||||||
for j in countup(0, length - 3):
|
for j in countup(0, length - 3):
|
||||||
var field = newSymG(skField, a.sons[j], c)
|
var field = newSymG(skField, a.sons[j], c)
|
||||||
field.typ = typ
|
field.typ = typ
|
||||||
field.position = counter
|
field.position = counter
|
||||||
inc(counter)
|
inc(counter)
|
||||||
if containsOrIncl(check, field.name.id):
|
if containsOrIncl(check, field.name.id):
|
||||||
localError(a.sons[j].info, errAttemptToRedefine, field.name.s)
|
localError(a.sons[j].info, errAttemptToRedefine, field.name.s)
|
||||||
else:
|
else:
|
||||||
addSon(result.n, newSymNode(field))
|
addSon(result.n, newSymNode(field))
|
||||||
addSonSkipIntLit(result, typ)
|
addSonSkipIntLit(result, typ)
|
||||||
if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, field)
|
if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, field)
|
||||||
|
|
||||||
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||||
allowed: TSymFlags): PSym =
|
allowed: TSymFlags): PSym =
|
||||||
# identifier with visibility
|
# identifier with visibility
|
||||||
if n.kind == nkPostfix:
|
if n.kind == nkPostfix:
|
||||||
if sonsLen(n) == 2 and n.sons[0].kind == nkIdent:
|
if sonsLen(n) == 2 and n.sons[0].kind == nkIdent:
|
||||||
# for gensym'ed identifiers the identifier may already have been
|
# for gensym'ed identifiers the identifier may already have been
|
||||||
# transformed to a symbol and we need to use that here:
|
# transformed to a symbol and we need to use that here:
|
||||||
result = newSymG(kind, n.sons[1], c)
|
result = newSymG(kind, n.sons[1], c)
|
||||||
var v = n.sons[0].ident
|
var v = n.sons[0].ident
|
||||||
if sfExported in allowed and v.id == ord(wStar):
|
if sfExported in allowed and v.id == ord(wStar):
|
||||||
incl(result.flags, sfExported)
|
incl(result.flags, sfExported)
|
||||||
else:
|
else:
|
||||||
localError(n.sons[0].info, errInvalidVisibilityX, v.s)
|
localError(n.sons[0].info, errInvalidVisibilityX, v.s)
|
||||||
|
|
@ -393,7 +399,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||||
illFormedAst(n)
|
illFormedAst(n)
|
||||||
else:
|
else:
|
||||||
result = newSymG(kind, n, c)
|
result = newSymG(kind, n, c)
|
||||||
|
|
||||||
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||||
allowed: TSymFlags): PSym =
|
allowed: TSymFlags): PSym =
|
||||||
if n.kind == nkPragmaExpr:
|
if n.kind == nkPragmaExpr:
|
||||||
|
|
@ -415,31 +421,31 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||||
proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
|
proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
|
||||||
let ex = t[branchIndex][currentEx].skipConv
|
let ex = t[branchIndex][currentEx].skipConv
|
||||||
for i in countup(1, branchIndex):
|
for i in countup(1, branchIndex):
|
||||||
for j in countup(0, sonsLen(t.sons[i]) - 2):
|
for j in countup(0, sonsLen(t.sons[i]) - 2):
|
||||||
if i == branchIndex and j == currentEx: break
|
if i == branchIndex and j == currentEx: break
|
||||||
if overlap(t.sons[i].sons[j].skipConv, ex):
|
if overlap(t.sons[i].sons[j].skipConv, ex):
|
||||||
localError(ex.info, errDuplicateCaseLabel)
|
localError(ex.info, errDuplicateCaseLabel)
|
||||||
|
|
||||||
proc semBranchRange(c: PContext, t, a, b: PNode, covered: var BiggestInt): PNode =
|
proc semBranchRange(c: PContext, t, a, b: PNode, covered: var BiggestInt): PNode =
|
||||||
checkMinSonsLen(t, 1)
|
checkMinSonsLen(t, 1)
|
||||||
let ac = semConstExpr(c, a)
|
let ac = semConstExpr(c, a)
|
||||||
let bc = semConstExpr(c, b)
|
let bc = semConstExpr(c, b)
|
||||||
let at = fitNode(c, t.sons[0].typ, ac).skipConvTakeType
|
let at = fitNode(c, t.sons[0].typ, ac).skipConvTakeType
|
||||||
let bt = fitNode(c, t.sons[0].typ, bc).skipConvTakeType
|
let bt = fitNode(c, t.sons[0].typ, bc).skipConvTakeType
|
||||||
|
|
||||||
result = newNodeI(nkRange, a.info)
|
result = newNodeI(nkRange, a.info)
|
||||||
result.add(at)
|
result.add(at)
|
||||||
result.add(bt)
|
result.add(bt)
|
||||||
if emptyRange(ac, bc): localError(b.info, errRangeIsEmpty)
|
if emptyRange(ac, bc): localError(b.info, errRangeIsEmpty)
|
||||||
else: covered = covered + getOrdValue(bc) - getOrdValue(ac) + 1
|
else: covered = covered + getOrdValue(bc) - getOrdValue(ac) + 1
|
||||||
|
|
||||||
proc semCaseBranchRange(c: PContext, t, b: PNode,
|
proc semCaseBranchRange(c: PContext, t, b: PNode,
|
||||||
covered: var BiggestInt): PNode =
|
covered: var BiggestInt): PNode =
|
||||||
checkSonsLen(b, 3)
|
checkSonsLen(b, 3)
|
||||||
result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
|
result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
|
||||||
|
|
||||||
proc semCaseBranchSetElem(c: PContext, t, b: PNode,
|
proc semCaseBranchSetElem(c: PContext, t, b: PNode,
|
||||||
covered: var BiggestInt): PNode =
|
covered: var BiggestInt): PNode =
|
||||||
if isRange(b):
|
if isRange(b):
|
||||||
checkSonsLen(b, 3)
|
checkSonsLen(b, 3)
|
||||||
result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
|
result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
|
||||||
|
|
@ -450,10 +456,10 @@ proc semCaseBranchSetElem(c: PContext, t, b: PNode,
|
||||||
result = fitNode(c, t.sons[0].typ, b)
|
result = fitNode(c, t.sons[0].typ, b)
|
||||||
inc(covered)
|
inc(covered)
|
||||||
|
|
||||||
proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
|
proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
|
||||||
covered: var BiggestInt) =
|
covered: var BiggestInt) =
|
||||||
|
|
||||||
for i in countup(0, sonsLen(branch) - 2):
|
for i in countup(0, sonsLen(branch) - 2):
|
||||||
var b = branch.sons[i]
|
var b = branch.sons[i]
|
||||||
if b.kind == nkRange:
|
if b.kind == nkRange:
|
||||||
branch.sons[i] = b
|
branch.sons[i] = b
|
||||||
|
|
@ -480,7 +486,7 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
|
||||||
var L = branch.len
|
var L = branch.len
|
||||||
swap(branch.sons[L-2], branch.sons[L-1])
|
swap(branch.sons[L-2], branch.sons[L-1])
|
||||||
checkForOverlap(c, t, i, branchIndex)
|
checkForOverlap(c, t, i, branchIndex)
|
||||||
|
|
||||||
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||||
father: PNode, rectype: PType)
|
father: PNode, rectype: PType)
|
||||||
proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||||
|
|
@ -514,11 +520,11 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||||
else: illFormedAst(n)
|
else: illFormedAst(n)
|
||||||
delSon(b, sonsLen(b) - 1)
|
delSon(b, sonsLen(b) - 1)
|
||||||
semRecordNodeAux(c, lastSon(n.sons[i]), check, pos, b, rectype)
|
semRecordNodeAux(c, lastSon(n.sons[i]), check, pos, b, rectype)
|
||||||
if chckCovered and (covered != lengthOrd(a.sons[0].typ)):
|
if chckCovered and (covered != lengthOrd(a.sons[0].typ)):
|
||||||
localError(a.info, errNotAllCasesCovered)
|
localError(a.info, errNotAllCasesCovered)
|
||||||
addSon(father, a)
|
addSon(father, a)
|
||||||
|
|
||||||
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||||
father: PNode, rectype: PType) =
|
father: PNode, rectype: PType) =
|
||||||
if n == nil: return
|
if n == nil: return
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -556,12 +562,12 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||||
semRecordNodeAux(c, branch, check, pos, father, rectype)
|
semRecordNodeAux(c, branch, check, pos, father, rectype)
|
||||||
of nkRecCase:
|
of nkRecCase:
|
||||||
semRecordCase(c, n, check, pos, father, rectype)
|
semRecordCase(c, n, check, pos, father, rectype)
|
||||||
of nkNilLit:
|
of nkNilLit:
|
||||||
if father.kind != nkRecList: addSon(father, newNodeI(nkRecList, n.info))
|
if father.kind != nkRecList: addSon(father, newNodeI(nkRecList, n.info))
|
||||||
of nkRecList:
|
of nkRecList:
|
||||||
# attempt to keep the nesting at a sane level:
|
# attempt to keep the nesting at a sane level:
|
||||||
var a = if father.kind == nkRecList: father else: copyNode(n)
|
var a = if father.kind == nkRecList: father else: copyNode(n)
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
semRecordNodeAux(c, n.sons[i], check, pos, a, rectype)
|
semRecordNodeAux(c, n.sons[i], check, pos, a, rectype)
|
||||||
if a != father: addSon(father, a)
|
if a != father: addSon(father, a)
|
||||||
of nkIdentDefs:
|
of nkIdentDefs:
|
||||||
|
|
@ -570,10 +576,10 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||||
var a: PNode
|
var a: PNode
|
||||||
if father.kind != nkRecList and length>=4: a = newNodeI(nkRecList, n.info)
|
if father.kind != nkRecList and length>=4: a = newNodeI(nkRecList, n.info)
|
||||||
else: a = ast.emptyNode
|
else: a = ast.emptyNode
|
||||||
if n.sons[length-1].kind != nkEmpty:
|
if n.sons[length-1].kind != nkEmpty:
|
||||||
localError(n.sons[length-1].info, errInitHereNotAllowed)
|
localError(n.sons[length-1].info, errInitHereNotAllowed)
|
||||||
var typ: PType
|
var typ: PType
|
||||||
if n.sons[length-2].kind == nkEmpty:
|
if n.sons[length-2].kind == nkEmpty:
|
||||||
localError(n.info, errTypeExpected)
|
localError(n.info, errTypeExpected)
|
||||||
typ = errorType(c)
|
typ = errorType(c)
|
||||||
else:
|
else:
|
||||||
|
|
@ -586,7 +592,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||||
f.typ = typ
|
f.typ = typ
|
||||||
f.position = pos
|
f.position = pos
|
||||||
if (rec != nil) and ({sfImportc, sfExportc} * rec.flags != {}) and
|
if (rec != nil) and ({sfImportc, sfExportc} * rec.flags != {}) and
|
||||||
(f.loc.r == nil):
|
(f.loc.r == nil):
|
||||||
f.loc.r = toRope(f.name.s)
|
f.loc.r = toRope(f.name.s)
|
||||||
f.flags = f.flags + ({sfImportc, sfExportc} * rec.flags)
|
f.flags = f.flags + ({sfImportc, sfExportc} * rec.flags)
|
||||||
inc(pos)
|
inc(pos)
|
||||||
|
|
@ -598,8 +604,8 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||||
if a.kind != nkEmpty: addSon(father, a)
|
if a.kind != nkEmpty: addSon(father, a)
|
||||||
of nkEmpty: discard
|
of nkEmpty: discard
|
||||||
else: illFormedAst(n)
|
else: illFormedAst(n)
|
||||||
|
|
||||||
proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
|
proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
|
||||||
n: PNode) =
|
n: PNode) =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkRecCase:
|
of nkRecCase:
|
||||||
|
|
@ -618,31 +624,31 @@ proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
|
||||||
inc(pos)
|
inc(pos)
|
||||||
else: internalError(n.info, "addInheritedFieldsAux()")
|
else: internalError(n.info, "addInheritedFieldsAux()")
|
||||||
|
|
||||||
proc skipGenericInvocation(t: PType): PType {.inline.} =
|
proc skipGenericInvocation(t: PType): PType {.inline.} =
|
||||||
result = t
|
result = t
|
||||||
if result.kind == tyGenericInvocation:
|
if result.kind == tyGenericInvocation:
|
||||||
result = result.sons[0]
|
result = result.sons[0]
|
||||||
if result.kind == tyGenericBody:
|
if result.kind == tyGenericBody:
|
||||||
result = lastSon(result)
|
result = lastSon(result)
|
||||||
|
|
||||||
proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
|
proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
|
||||||
obj: PType) =
|
obj: PType) =
|
||||||
assert obj.kind == tyObject
|
assert obj.kind == tyObject
|
||||||
if (sonsLen(obj) > 0) and (obj.sons[0] != nil):
|
if (sonsLen(obj) > 0) and (obj.sons[0] != nil):
|
||||||
addInheritedFields(c, check, pos, obj.sons[0].skipGenericInvocation)
|
addInheritedFields(c, check, pos, obj.sons[0].skipGenericInvocation)
|
||||||
addInheritedFieldsAux(c, check, pos, obj.n)
|
addInheritedFieldsAux(c, check, pos, obj.n)
|
||||||
|
|
||||||
proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
if n.sonsLen == 0: return newConstraint(c, tyObject)
|
if n.sonsLen == 0: return newConstraint(c, tyObject)
|
||||||
var check = initIntSet()
|
var check = initIntSet()
|
||||||
var pos = 0
|
var pos = 0
|
||||||
var base: PType = nil
|
var base: PType = nil
|
||||||
# n.sons[0] contains the pragmas (if any). We process these later...
|
# n.sons[0] contains the pragmas (if any). We process these later...
|
||||||
checkSonsLen(n, 3)
|
checkSonsLen(n, 3)
|
||||||
if n.sons[1].kind != nkEmpty:
|
if n.sons[1].kind != nkEmpty:
|
||||||
base = skipTypes(semTypeNode(c, n.sons[1].sons[0], nil), skipPtrs)
|
base = skipTypes(semTypeNode(c, n.sons[1].sons[0], nil), skipPtrs)
|
||||||
var concreteBase = skipGenericInvocation(base).skipTypes(skipPtrs)
|
var concreteBase = skipGenericInvocation(base).skipTypes(skipPtrs)
|
||||||
if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
|
if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
|
||||||
addInheritedFields(c, check, pos, concreteBase)
|
addInheritedFields(c, check, pos, concreteBase)
|
||||||
else:
|
else:
|
||||||
if concreteBase.kind != tyError:
|
if concreteBase.kind != tyError:
|
||||||
|
|
@ -723,7 +729,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
genericParams.addSon(newSymNode(s))
|
genericParams.addSon(newSymNode(s))
|
||||||
result = typeClass
|
result = typeClass
|
||||||
addDecl(c, s)
|
addDecl(c, s)
|
||||||
|
|
||||||
# XXX: There are codegen errors if this is turned into a nested proc
|
# XXX: There are codegen errors if this is turned into a nested proc
|
||||||
template liftingWalk(typ: PType, anonFlag = false): expr =
|
template liftingWalk(typ: PType, anonFlag = false): expr =
|
||||||
liftParamType(c, procKind, genericParams, typ, paramName, info, anonFlag)
|
liftParamType(c, procKind, genericParams, typ, paramName, info, anonFlag)
|
||||||
|
|
@ -742,7 +748,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
case paramType.kind:
|
case paramType.kind:
|
||||||
of tyAnything:
|
of tyAnything:
|
||||||
result = addImplicitGeneric(newTypeS(tyGenericParam, c))
|
result = addImplicitGeneric(newTypeS(tyGenericParam, c))
|
||||||
|
|
||||||
of tyStatic:
|
of tyStatic:
|
||||||
# proc(a: expr{string}, b: expr{nkLambda})
|
# proc(a: expr{string}, b: expr{nkLambda})
|
||||||
# overload on compile time values and AST trees
|
# overload on compile time values and AST trees
|
||||||
|
|
@ -753,7 +759,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
localError(info, errMacroBodyDependsOnGenericTypes, paramName)
|
localError(info, errMacroBodyDependsOnGenericTypes, paramName)
|
||||||
result = addImplicitGeneric(c.newTypeWithSons(tyStatic, @[base]))
|
result = addImplicitGeneric(c.newTypeWithSons(tyStatic, @[base]))
|
||||||
result.flags.incl({tfHasStatic, tfUnresolved})
|
result.flags.incl({tfHasStatic, tfUnresolved})
|
||||||
|
|
||||||
of tyTypeDesc:
|
of tyTypeDesc:
|
||||||
if tfUnresolved notin paramType.flags:
|
if tfUnresolved notin paramType.flags:
|
||||||
# naked typedescs are not bindOnce types
|
# naked typedescs are not bindOnce types
|
||||||
|
|
@ -761,12 +767,12 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
paramTypId.id == typedescId.id: paramTypId = nil
|
paramTypId.id == typedescId.id: paramTypId = nil
|
||||||
result = addImplicitGeneric(
|
result = addImplicitGeneric(
|
||||||
c.newTypeWithSons(tyTypeDesc, @[paramType.base]))
|
c.newTypeWithSons(tyTypeDesc, @[paramType.base]))
|
||||||
|
|
||||||
of tyDistinct:
|
of tyDistinct:
|
||||||
if paramType.sonsLen == 1:
|
if paramType.sonsLen == 1:
|
||||||
# disable the bindOnce behavior for the type class
|
# disable the bindOnce behavior for the type class
|
||||||
result = liftingWalk(paramType.sons[0], true)
|
result = liftingWalk(paramType.sons[0], true)
|
||||||
|
|
||||||
of tySequence, tySet, tyArray, tyOpenArray,
|
of tySequence, tySet, tyArray, tyOpenArray,
|
||||||
tyVar, tyPtr, tyRef, tyProc:
|
tyVar, tyPtr, tyRef, tyProc:
|
||||||
# XXX: this is a bit strange, but proc(s: seq)
|
# XXX: this is a bit strange, but proc(s: seq)
|
||||||
|
|
@ -785,22 +791,22 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
if lifted != nil:
|
if lifted != nil:
|
||||||
paramType.sons[i] = lifted
|
paramType.sons[i] = lifted
|
||||||
result = paramType
|
result = paramType
|
||||||
|
|
||||||
of tyGenericBody:
|
of tyGenericBody:
|
||||||
result = newTypeS(tyGenericInvocation, c)
|
result = newTypeS(tyGenericInvocation, c)
|
||||||
result.rawAddSon(paramType)
|
result.rawAddSon(paramType)
|
||||||
|
|
||||||
for i in 0 .. paramType.sonsLen - 2:
|
for i in 0 .. paramType.sonsLen - 2:
|
||||||
if paramType.sons[i].kind == tyStatic:
|
if paramType.sons[i].kind == tyStatic:
|
||||||
result.rawAddSon makeTypeFromExpr(c, ast.emptyNode) # aka 'tyUnknown'
|
result.rawAddSon makeTypeFromExpr(c, ast.emptyNode) # aka 'tyUnknown'
|
||||||
else:
|
else:
|
||||||
result.rawAddSon newTypeS(tyAnything, c)
|
result.rawAddSon newTypeS(tyAnything, c)
|
||||||
|
|
||||||
if paramType.lastSon.kind == tyUserTypeClass:
|
if paramType.lastSon.kind == tyUserTypeClass:
|
||||||
result.kind = tyUserTypeClassInst
|
result.kind = tyUserTypeClassInst
|
||||||
result.rawAddSon paramType.lastSon
|
result.rawAddSon paramType.lastSon
|
||||||
return addImplicitGeneric(result)
|
return addImplicitGeneric(result)
|
||||||
|
|
||||||
result = instGenericContainer(c, paramType.sym.info, result,
|
result = instGenericContainer(c, paramType.sym.info, result,
|
||||||
allowMetaTypes = true)
|
allowMetaTypes = true)
|
||||||
result = newTypeWithSons(c, tyCompositeTypeClass, @[paramType, result])
|
result = newTypeWithSons(c, tyCompositeTypeClass, @[paramType, result])
|
||||||
|
|
@ -832,7 +838,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
if liftBody != nil:
|
if liftBody != nil:
|
||||||
result = liftBody
|
result = liftBody
|
||||||
result.shouldHaveMeta
|
result.shouldHaveMeta
|
||||||
|
|
||||||
of tyGenericInvocation:
|
of tyGenericInvocation:
|
||||||
for i in 1 .. <paramType.sonsLen:
|
for i in 1 .. <paramType.sonsLen:
|
||||||
let lifted = liftingWalk(paramType.sons[i])
|
let lifted = liftingWalk(paramType.sons[i])
|
||||||
|
|
@ -844,18 +850,18 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
|
|
||||||
of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
|
of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
|
||||||
result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
|
result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
|
||||||
|
|
||||||
of tyExpr:
|
of tyExpr:
|
||||||
if procKind notin {skMacro, skTemplate}:
|
if procKind notin {skMacro, skTemplate}:
|
||||||
result = addImplicitGeneric(newTypeS(tyAnything, c))
|
result = addImplicitGeneric(newTypeS(tyAnything, c))
|
||||||
|
|
||||||
of tyGenericParam:
|
of tyGenericParam:
|
||||||
markUsed(info, paramType.sym)
|
markUsed(info, paramType.sym)
|
||||||
styleCheckUse(info, paramType.sym)
|
styleCheckUse(info, paramType.sym)
|
||||||
if tfWildcard in paramType.flags:
|
if tfWildcard in paramType.flags:
|
||||||
paramType.flags.excl tfWildcard
|
paramType.flags.excl tfWildcard
|
||||||
paramType.sym.kind = skType
|
paramType.sym.kind = skType
|
||||||
|
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
# result = liftingWalk(paramType)
|
# result = liftingWalk(paramType)
|
||||||
|
|
@ -872,7 +878,7 @@ proc newProcType(c: PContext; info: TLineInfo; prev: PType = nil): PType =
|
||||||
result.callConv = lastOptionEntry(c).defaultCC
|
result.callConv = lastOptionEntry(c).defaultCC
|
||||||
result.n = newNodeI(nkFormalParams, info)
|
result.n = newNodeI(nkFormalParams, info)
|
||||||
rawAddSon(result, nil) # return type
|
rawAddSon(result, nil) # return type
|
||||||
# result.n[0] used to be `nkType`, but now it's `nkEffectList` because
|
# result.n[0] used to be `nkType`, but now it's `nkEffectList` because
|
||||||
# the effects are now stored in there too ... this is a bit hacky, but as
|
# the effects are now stored in there too ... this is a bit hacky, but as
|
||||||
# usual we desperately try to save memory:
|
# usual we desperately try to save memory:
|
||||||
addSon(result.n, newNodeI(nkEffectList, info))
|
addSon(result.n, newNodeI(nkEffectList, info))
|
||||||
|
|
@ -909,7 +915,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
typ = semParamType(c, a.sons[length-2], constraint)
|
typ = semParamType(c, a.sons[length-2], constraint)
|
||||||
|
|
||||||
if hasDefault:
|
if hasDefault:
|
||||||
def = semExprWithType(c, a.sons[length-1])
|
def = semExprWithType(c, a.sons[length-1])
|
||||||
# check type compatibility between def.typ and typ:
|
# check type compatibility between def.typ and typ:
|
||||||
if typ == nil:
|
if typ == nil:
|
||||||
typ = def.typ
|
typ = def.typ
|
||||||
|
|
@ -927,7 +933,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
typ = newTypeS(tdef, c)
|
typ = newTypeS(tdef, c)
|
||||||
|
|
||||||
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
|
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
|
||||||
for j in countup(0, length-3):
|
for j in countup(0, length-3):
|
||||||
var arg = newSymG(skParam, a.sons[j], c)
|
var arg = newSymG(skParam, a.sons[j], c)
|
||||||
let lifted = liftParamType(c, kind, genericParams, typ,
|
let lifted = liftParamType(c, kind, genericParams, typ,
|
||||||
arg.name.s, arg.info)
|
arg.name.s, arg.info)
|
||||||
|
|
@ -937,7 +943,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
arg.constraint = constraint
|
arg.constraint = constraint
|
||||||
inc(counter)
|
inc(counter)
|
||||||
if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
|
if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
|
||||||
if containsOrIncl(check, arg.name.id):
|
if containsOrIncl(check, arg.name.id):
|
||||||
localError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
|
localError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
|
||||||
addSon(result.n, newSymNode(arg))
|
addSon(result.n, newSymNode(arg))
|
||||||
rawAddSon(result, finalType)
|
rawAddSon(result, finalType)
|
||||||
|
|
@ -950,9 +956,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
elif kind == skIterator:
|
elif kind == skIterator:
|
||||||
# XXX This is special magic we should likely get rid of
|
# XXX This is special magic we should likely get rid of
|
||||||
r = newTypeS(tyExpr, c)
|
r = newTypeS(tyExpr, c)
|
||||||
|
|
||||||
if r != nil:
|
if r != nil:
|
||||||
# turn explicit 'void' return type into 'nil' because the rest of the
|
# turn explicit 'void' return type into 'nil' because the rest of the
|
||||||
# compiler only checks for 'nil':
|
# compiler only checks for 'nil':
|
||||||
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
||||||
# 'auto' as a return type does not imply a generic:
|
# 'auto' as a return type does not imply a generic:
|
||||||
|
|
@ -988,8 +994,8 @@ proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
|
||||||
n.sons[length - 1].typ = result
|
n.sons[length - 1].typ = result
|
||||||
else:
|
else:
|
||||||
result = nil
|
result = nil
|
||||||
|
|
||||||
proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
|
proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
|
||||||
inc(c.p.nestedBlockCounter)
|
inc(c.p.nestedBlockCounter)
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
|
|
@ -1009,7 +1015,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||||
localError(n.info, "cannot instantiate the '$1' $2" %
|
localError(n.info, "cannot instantiate the '$1' $2" %
|
||||||
[s.name.s, ($s.kind).substr(2).toLower])
|
[s.name.s, ($s.kind).substr(2).toLower])
|
||||||
return newOrPrevType(tyError, prev, c)
|
return newOrPrevType(tyError, prev, c)
|
||||||
|
|
||||||
var t = s.typ
|
var t = s.typ
|
||||||
if t.kind == tyCompositeTypeClass and t.base.kind == tyGenericBody:
|
if t.kind == tyCompositeTypeClass and t.base.kind == tyGenericBody:
|
||||||
t = t.base
|
t = t.base
|
||||||
|
|
@ -1036,7 +1042,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||||
else:
|
else:
|
||||||
var m = newCandidate(c, t)
|
var m = newCandidate(c, t)
|
||||||
matches(c, n, copyTree(n), m)
|
matches(c, n, copyTree(n), m)
|
||||||
|
|
||||||
if m.state != csMatch:
|
if m.state != csMatch:
|
||||||
var err = "cannot instantiate " & typeToString(t) & "\n" &
|
var err = "cannot instantiate " & typeToString(t) & "\n" &
|
||||||
"got: (" & describeArgs(c, n) & ")\n" &
|
"got: (" & describeArgs(c, n) & ")\n" &
|
||||||
|
|
@ -1045,12 +1051,12 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||||
return newOrPrevType(tyError, prev, c)
|
return newOrPrevType(tyError, prev, c)
|
||||||
|
|
||||||
var isConcrete = true
|
var isConcrete = true
|
||||||
|
|
||||||
for i in 1 .. <m.call.len:
|
for i in 1 .. <m.call.len:
|
||||||
let typ = m.call[i].typ.skipTypes({tyTypeDesc})
|
let typ = m.call[i].typ.skipTypes({tyTypeDesc})
|
||||||
if containsGenericType(typ): isConcrete = false
|
if containsGenericType(typ): isConcrete = false
|
||||||
addToResult(typ)
|
addToResult(typ)
|
||||||
|
|
||||||
if isConcrete:
|
if isConcrete:
|
||||||
if s.ast == nil and s.typ.kind != tyCompositeTypeClass:
|
if s.ast == nil and s.typ.kind != tyCompositeTypeClass:
|
||||||
# XXX: What kind of error is this? is it still relevant?
|
# XXX: What kind of error is this? is it still relevant?
|
||||||
|
|
@ -1081,7 +1087,7 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
|
||||||
let
|
let
|
||||||
pragmas = n[1]
|
pragmas = n[1]
|
||||||
inherited = n[2]
|
inherited = n[2]
|
||||||
|
|
||||||
if inherited.kind != nkEmpty:
|
if inherited.kind != nkEmpty:
|
||||||
for n in inherited.sons:
|
for n in inherited.sons:
|
||||||
let typ = semTypeNode(c, n, nil)
|
let typ = semTypeNode(c, n, nil)
|
||||||
|
|
@ -1114,12 +1120,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
checkSonsLen(n, 1)
|
checkSonsLen(n, 1)
|
||||||
let typExpr = semExprWithType(c, n.sons[0], {efInTypeof})
|
let typExpr = semExprWithType(c, n.sons[0], {efInTypeof})
|
||||||
result = typExpr.typ.skipTypes({tyIter})
|
result = typExpr.typ.skipTypes({tyIter})
|
||||||
of nkPar:
|
of nkPar:
|
||||||
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
||||||
else:
|
else:
|
||||||
# XXX support anon tuple here
|
result = semAnonTuple(c, n, prev)
|
||||||
localError(n.info, errTypeExpected)
|
|
||||||
result = newOrPrevType(tyError, prev, c)
|
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
if isRange(n):
|
if isRange(n):
|
||||||
result = semRangeAux(c, n, prev)
|
result = semRangeAux(c, n, prev)
|
||||||
|
|
@ -1197,7 +1201,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = makeTypeFromExpr(c, preprocessed.copyTree)
|
result = makeTypeFromExpr(c, preprocessed.copyTree)
|
||||||
of nkIdent, nkAccQuoted:
|
of nkIdent, nkAccQuoted:
|
||||||
var s = semTypeIdent(c, n)
|
var s = semTypeIdent(c, n)
|
||||||
if s.typ == nil:
|
if s.typ == nil:
|
||||||
if s.kind != skError: localError(n.info, errTypeExpected)
|
if s.kind != skError: localError(n.info, errTypeExpected)
|
||||||
result = newOrPrevType(tyError, prev, c)
|
result = newOrPrevType(tyError, prev, c)
|
||||||
elif s.kind == skParam and s.typ.kind == tyTypeDesc:
|
elif s.kind == skParam and s.typ.kind == tyTypeDesc:
|
||||||
|
|
@ -1205,19 +1209,19 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = s.typ.base
|
result = s.typ.base
|
||||||
elif prev == nil:
|
elif prev == nil:
|
||||||
result = s.typ
|
result = s.typ
|
||||||
else:
|
else:
|
||||||
assignType(prev, s.typ)
|
assignType(prev, s.typ)
|
||||||
# bugfix: keep the fresh id for aliases to integral types:
|
# bugfix: keep the fresh id for aliases to integral types:
|
||||||
if s.typ.kind notin {tyBool, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
|
if s.typ.kind notin {tyBool, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||||
tyUInt..tyUInt64}:
|
tyUInt..tyUInt64}:
|
||||||
prev.id = s.typ.id
|
prev.id = s.typ.id
|
||||||
result = prev
|
result = prev
|
||||||
of nkSym:
|
of nkSym:
|
||||||
if n.sym.kind == skType and n.sym.typ != nil:
|
if n.sym.kind == skType and n.sym.typ != nil:
|
||||||
var t = n.sym.typ
|
var t = n.sym.typ
|
||||||
if prev == nil:
|
if prev == nil:
|
||||||
result = t
|
result = t
|
||||||
else:
|
else:
|
||||||
assignType(prev, t)
|
assignType(prev, t)
|
||||||
result = prev
|
result = prev
|
||||||
markUsed(n.info, n.sym)
|
markUsed(n.info, n.sym)
|
||||||
|
|
@ -1227,6 +1231,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = newOrPrevType(tyError, prev, c)
|
result = newOrPrevType(tyError, prev, c)
|
||||||
of nkObjectTy: result = semObjectNode(c, n, prev)
|
of nkObjectTy: result = semObjectNode(c, n, prev)
|
||||||
of nkTupleTy: result = semTuple(c, n, prev)
|
of nkTupleTy: result = semTuple(c, n, prev)
|
||||||
|
of nkTupleClassTy: result = newConstraint(c, tyTuple)
|
||||||
of nkTypeClassTy: result = semTypeClass(c, n, prev)
|
of nkTypeClassTy: result = semTypeClass(c, n, prev)
|
||||||
of nkRefTy: result = semAnyRef(c, n, tyRef, prev)
|
of nkRefTy: result = semAnyRef(c, n, tyRef, prev)
|
||||||
of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
|
of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
|
||||||
|
|
@ -1267,12 +1272,12 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = newOrPrevType(tyError, prev, c)
|
result = newOrPrevType(tyError, prev, c)
|
||||||
n.typ = result
|
n.typ = result
|
||||||
|
|
||||||
proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
|
proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
|
||||||
m.typ.kind = kind
|
m.typ.kind = kind
|
||||||
m.typ.align = size.int16
|
m.typ.align = size.int16
|
||||||
m.typ.size = size
|
m.typ.size = size
|
||||||
|
|
||||||
proc processMagicType(c: PContext, m: PSym) =
|
proc processMagicType(c: PContext, m: PSym) =
|
||||||
case m.magic
|
case m.magic
|
||||||
of mInt: setMagicType(m, tyInt, intSize)
|
of mInt: setMagicType(m, tyInt, intSize)
|
||||||
of mInt8: setMagicType(m, tyInt8, 1)
|
of mInt8: setMagicType(m, tyInt8, 1)
|
||||||
|
|
@ -1290,21 +1295,21 @@ proc processMagicType(c: PContext, m: PSym) =
|
||||||
of mFloat128: setMagicType(m, tyFloat128, 16)
|
of mFloat128: setMagicType(m, tyFloat128, 16)
|
||||||
of mBool: setMagicType(m, tyBool, 1)
|
of mBool: setMagicType(m, tyBool, 1)
|
||||||
of mChar: setMagicType(m, tyChar, 1)
|
of mChar: setMagicType(m, tyChar, 1)
|
||||||
of mString:
|
of mString:
|
||||||
setMagicType(m, tyString, ptrSize)
|
setMagicType(m, tyString, ptrSize)
|
||||||
rawAddSon(m.typ, getSysType(tyChar))
|
rawAddSon(m.typ, getSysType(tyChar))
|
||||||
of mCstring:
|
of mCstring:
|
||||||
setMagicType(m, tyCString, ptrSize)
|
setMagicType(m, tyCString, ptrSize)
|
||||||
rawAddSon(m.typ, getSysType(tyChar))
|
rawAddSon(m.typ, getSysType(tyChar))
|
||||||
of mPointer: setMagicType(m, tyPointer, ptrSize)
|
of mPointer: setMagicType(m, tyPointer, ptrSize)
|
||||||
of mEmptySet:
|
of mEmptySet:
|
||||||
setMagicType(m, tySet, 1)
|
setMagicType(m, tySet, 1)
|
||||||
rawAddSon(m.typ, newTypeS(tyEmpty, c))
|
rawAddSon(m.typ, newTypeS(tyEmpty, c))
|
||||||
of mIntSetBaseType: setMagicType(m, tyRange, intSize)
|
of mIntSetBaseType: setMagicType(m, tyRange, intSize)
|
||||||
of mNil: setMagicType(m, tyNil, ptrSize)
|
of mNil: setMagicType(m, tyNil, ptrSize)
|
||||||
of mExpr: setMagicType(m, tyExpr, 0)
|
of mExpr: setMagicType(m, tyExpr, 0)
|
||||||
of mStmt: setMagicType(m, tyStmt, 0)
|
of mStmt: setMagicType(m, tyStmt, 0)
|
||||||
of mTypeDesc:
|
of mTypeDesc:
|
||||||
setMagicType(m, tyTypeDesc, 0)
|
setMagicType(m, tyTypeDesc, 0)
|
||||||
rawAddSon(m.typ, newTypeS(tyNone, c))
|
rawAddSon(m.typ, newTypeS(tyNone, c))
|
||||||
of mVoidType: setMagicType(m, tyEmpty, 0)
|
of mVoidType: setMagicType(m, tyEmpty, 0)
|
||||||
|
|
@ -1318,8 +1323,8 @@ proc processMagicType(c: PContext, m: PSym) =
|
||||||
setMagicType(m, tyRange, 0)
|
setMagicType(m, tyRange, 0)
|
||||||
rawAddSon(m.typ, newTypeS(tyNone, c))
|
rawAddSon(m.typ, newTypeS(tyNone, c))
|
||||||
of mSet:
|
of mSet:
|
||||||
setMagicType(m, tySet, 0)
|
setMagicType(m, tySet, 0)
|
||||||
of mSeq:
|
of mSeq:
|
||||||
setMagicType(m, tySequence, 0)
|
setMagicType(m, tySequence, 0)
|
||||||
of mOrdinal:
|
of mOrdinal:
|
||||||
setMagicType(m, tyOrdinal, 0)
|
setMagicType(m, tyOrdinal, 0)
|
||||||
|
|
@ -1335,13 +1340,13 @@ proc processMagicType(c: PContext, m: PSym) =
|
||||||
incl m.typ.flags, tfShared
|
incl m.typ.flags, tfShared
|
||||||
rawAddSon(m.typ, sysTypeFromName"shared")
|
rawAddSon(m.typ, sysTypeFromName"shared")
|
||||||
else: localError(m.info, errTypeExpected)
|
else: localError(m.info, errTypeExpected)
|
||||||
|
|
||||||
proc semGenericConstraints(c: PContext, x: PType): PType =
|
proc semGenericConstraints(c: PContext, x: PType): PType =
|
||||||
result = newTypeWithSons(c, tyGenericParam, @[x])
|
result = newTypeWithSons(c, tyGenericParam, @[x])
|
||||||
|
|
||||||
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||||
result = copyNode(n)
|
result = copyNode(n)
|
||||||
if n.kind != nkGenericParams:
|
if n.kind != nkGenericParams:
|
||||||
illFormedAst(n)
|
illFormedAst(n)
|
||||||
return
|
return
|
||||||
for i in countup(0, sonsLen(n)-1):
|
for i in countup(0, sonsLen(n)-1):
|
||||||
|
|
@ -1351,7 +1356,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||||
var def = a{-1}
|
var def = a{-1}
|
||||||
let constraint = a{-2}
|
let constraint = a{-2}
|
||||||
var typ: PType
|
var typ: PType
|
||||||
|
|
||||||
if constraint.kind != nkEmpty:
|
if constraint.kind != nkEmpty:
|
||||||
typ = semTypeNode(c, constraint, nil)
|
typ = semTypeNode(c, constraint, nil)
|
||||||
if typ.kind != tyStatic or typ.len == 0:
|
if typ.kind != tyStatic or typ.len == 0:
|
||||||
|
|
@ -1360,7 +1365,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||||
typ = newTypeWithSons(c, tyTypeDesc, @[newTypeS(tyNone, c)])
|
typ = newTypeWithSons(c, tyTypeDesc, @[newTypeS(tyNone, c)])
|
||||||
else:
|
else:
|
||||||
typ = semGenericConstraints(c, typ)
|
typ = semGenericConstraints(c, typ)
|
||||||
|
|
||||||
if def.kind != nkEmpty:
|
if def.kind != nkEmpty:
|
||||||
def = semConstExpr(c, def)
|
def = semConstExpr(c, def)
|
||||||
if typ == nil:
|
if typ == nil:
|
||||||
|
|
@ -1372,7 +1377,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||||
def.typ = def.typ.skipTypes({tyTypeDesc})
|
def.typ = def.typ.skipTypes({tyTypeDesc})
|
||||||
if not containsGenericType(def.typ):
|
if not containsGenericType(def.typ):
|
||||||
def = fitNode(c, typ, def)
|
def = fitNode(c, typ, def)
|
||||||
|
|
||||||
if typ == nil:
|
if typ == nil:
|
||||||
typ = newTypeS(tyGenericParam, c)
|
typ = newTypeS(tyGenericParam, c)
|
||||||
if father == nil: typ.flags.incl tfWildcard
|
if father == nil: typ.flags.incl tfWildcard
|
||||||
|
|
|
||||||
|
|
@ -341,6 +341,8 @@ proc skipIntLiteralParams*(t: PType) =
|
||||||
proc propagateFieldFlags(t: PType, n: PNode) =
|
proc propagateFieldFlags(t: PType, n: PNode) =
|
||||||
# This is meant for objects and tuples
|
# This is meant for objects and tuples
|
||||||
# The type must be fully instantiated!
|
# The type must be fully instantiated!
|
||||||
|
if n.isNil:
|
||||||
|
return
|
||||||
internalAssert n.kind != nkRecWhen
|
internalAssert n.kind != nkRecWhen
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
## This module implements the signature matching for resolving
|
## This module implements the signature matching for resolving
|
||||||
## the call to overloaded procs, generic procs and operators.
|
## the call to overloaded procs, generic procs and operators.
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
|
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
|
||||||
magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees,
|
magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees,
|
||||||
nimfix.pretty
|
nimfix.pretty
|
||||||
|
|
@ -19,7 +19,7 @@ when not defined(noDocgen):
|
||||||
import docgen
|
import docgen
|
||||||
|
|
||||||
type
|
type
|
||||||
TCandidateState* = enum
|
TCandidateState* = enum
|
||||||
csEmpty, csMatch, csNoMatch
|
csEmpty, csMatch, csNoMatch
|
||||||
|
|
||||||
CandidateErrors* = seq[PSym]
|
CandidateErrors* = seq[PSym]
|
||||||
|
|
@ -62,10 +62,10 @@ type
|
||||||
isGeneric,
|
isGeneric,
|
||||||
isFromIntLit, # conversion *from* int literal; proven safe
|
isFromIntLit, # conversion *from* int literal; proven safe
|
||||||
isEqual
|
isEqual
|
||||||
|
|
||||||
const
|
const
|
||||||
isNilConversion = isConvertible # maybe 'isIntConv' fits better?
|
isNilConversion = isConvertible # maybe 'isIntConv' fits better?
|
||||||
|
|
||||||
proc markUsed*(info: TLineInfo, s: PSym)
|
proc markUsed*(info: TLineInfo, s: PSym)
|
||||||
|
|
||||||
template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone
|
template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone
|
||||||
|
|
@ -128,7 +128,7 @@ proc newCandidate*(ctx: PContext, callee: PSym,
|
||||||
proc newCandidate*(ctx: PContext, callee: PType): TCandidate =
|
proc newCandidate*(ctx: PContext, callee: PType): TCandidate =
|
||||||
initCandidate(ctx, result, callee)
|
initCandidate(ctx, result, callee)
|
||||||
|
|
||||||
proc copyCandidate(a: var TCandidate, b: TCandidate) =
|
proc copyCandidate(a: var TCandidate, b: TCandidate) =
|
||||||
a.c = b.c
|
a.c = b.c
|
||||||
a.exactMatches = b.exactMatches
|
a.exactMatches = b.exactMatches
|
||||||
a.subtypeMatches = b.subtypeMatches
|
a.subtypeMatches = b.subtypeMatches
|
||||||
|
|
@ -157,17 +157,40 @@ proc sumGeneric(t: PType): int =
|
||||||
result = ord(t.kind == tyGenericInvocation)
|
result = ord(t.kind == tyGenericInvocation)
|
||||||
for i in 0 .. <t.len: result += t.sons[i].sumGeneric
|
for i in 0 .. <t.len: result += t.sons[i].sumGeneric
|
||||||
break
|
break
|
||||||
of tyProc:
|
|
||||||
# proc matches proc better than 'stmt' to disambiguate 'spawn'
|
|
||||||
return 1
|
|
||||||
of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break
|
of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break
|
||||||
|
of tyBool, tyChar, tyEnum, tyObject, tyProc, tyPointer,
|
||||||
|
tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||||
|
tyUInt..tyUInt64:
|
||||||
|
return 1
|
||||||
else: return 0
|
else: return 0
|
||||||
|
|
||||||
|
#var ggDebug: bool
|
||||||
|
|
||||||
proc complexDisambiguation(a, b: PType): int =
|
proc complexDisambiguation(a, b: PType): int =
|
||||||
var x, y: int
|
# 'a' matches better if *every* argument matches better or equal than 'b'.
|
||||||
for i in 1 .. <a.len: x += a.sons[i].sumGeneric
|
var winner = 0
|
||||||
for i in 1 .. <b.len: y += b.sons[i].sumGeneric
|
for i in 1 .. <min(a.len, b.len):
|
||||||
result = x - y
|
let x = a.sons[i].sumGeneric
|
||||||
|
let y = b.sons[i].sumGeneric
|
||||||
|
#if ggDebug:
|
||||||
|
# echo "came her ", typeToString(a.sons[i]), " ", typeToString(b.sons[i])
|
||||||
|
if x != y:
|
||||||
|
if winner == 0:
|
||||||
|
if x > y: winner = 1
|
||||||
|
else: winner = -1
|
||||||
|
elif x > y:
|
||||||
|
if winner != 1:
|
||||||
|
# contradiction
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
if winner != -1:
|
||||||
|
return 0
|
||||||
|
result = winner
|
||||||
|
when false:
|
||||||
|
var x, y: int
|
||||||
|
for i in 1 .. <a.len: x += a.sons[i].sumGeneric
|
||||||
|
for i in 1 .. <b.len: y += b.sons[i].sumGeneric
|
||||||
|
result = x - y
|
||||||
when false:
|
when false:
|
||||||
proc betterThan(a, b: PType): bool {.inline.} = a.sumGeneric > b.sumGeneric
|
proc betterThan(a, b: PType): bool {.inline.} = a.sumGeneric > b.sumGeneric
|
||||||
|
|
||||||
|
|
@ -176,7 +199,7 @@ proc complexDisambiguation(a, b: PType): int =
|
||||||
let bb = b.sons[1].sumGeneric
|
let bb = b.sons[1].sumGeneric
|
||||||
var a = a
|
var a = a
|
||||||
var b = b
|
var b = b
|
||||||
|
|
||||||
if aa < bb: swap(a, b)
|
if aa < bb: swap(a, b)
|
||||||
# all must be better
|
# all must be better
|
||||||
for i in 2 .. <min(a.len, b.len):
|
for i in 2 .. <min(a.len, b.len):
|
||||||
|
|
@ -203,7 +226,7 @@ proc cmpCandidates*(a, b: TCandidate): int =
|
||||||
# prefer more specialized generic over more general generic:
|
# prefer more specialized generic over more general generic:
|
||||||
result = complexDisambiguation(a.callee, b.callee)
|
result = complexDisambiguation(a.callee, b.callee)
|
||||||
|
|
||||||
proc writeMatches*(c: TCandidate) =
|
proc writeMatches*(c: TCandidate) =
|
||||||
writeln(stdout, "exact matches: " & $c.exactMatches)
|
writeln(stdout, "exact matches: " & $c.exactMatches)
|
||||||
writeln(stdout, "generic matches: " & $c.genericMatches)
|
writeln(stdout, "generic matches: " & $c.genericMatches)
|
||||||
writeln(stdout, "subtype matches: " & $c.subtypeMatches)
|
writeln(stdout, "subtype matches: " & $c.subtypeMatches)
|
||||||
|
|
@ -225,7 +248,7 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
|
||||||
result = ""
|
result = ""
|
||||||
for i in countup(startIdx, n.len - 1):
|
for i in countup(startIdx, n.len - 1):
|
||||||
var arg = n.sons[i]
|
var arg = n.sons[i]
|
||||||
if n.sons[i].kind == nkExprEqExpr:
|
if n.sons[i].kind == nkExprEqExpr:
|
||||||
add(result, renderTree(n.sons[i].sons[0]))
|
add(result, renderTree(n.sons[i].sons[0]))
|
||||||
add(result, ": ")
|
add(result, ": ")
|
||||||
if arg.typ.isNil:
|
if arg.typ.isNil:
|
||||||
|
|
@ -241,9 +264,9 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
|
||||||
if i != sonsLen(n) - 1: add(result, ", ")
|
if i != sonsLen(n) - 1: add(result, ", ")
|
||||||
|
|
||||||
proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
|
proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
|
||||||
proc concreteType(c: TCandidate, t: PType): PType =
|
proc concreteType(c: TCandidate, t: PType): PType =
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyArrayConstr:
|
of tyArrayConstr:
|
||||||
# make it an array
|
# make it an array
|
||||||
result = newType(tyArray, t.owner)
|
result = newType(tyArray, t.owner)
|
||||||
addSonSkipIntLit(result, t.sons[0]) # XXX: t.owner is wrong for ID!
|
addSonSkipIntLit(result, t.sons[0]) # XXX: t.owner is wrong for ID!
|
||||||
|
|
@ -255,7 +278,7 @@ proc concreteType(c: TCandidate, t: PType): PType =
|
||||||
else: result = t
|
else: result = t
|
||||||
of tyGenericParam, tyAnything:
|
of tyGenericParam, tyAnything:
|
||||||
result = t
|
result = t
|
||||||
while true:
|
while true:
|
||||||
result = PType(idTableGet(c.bindings, t))
|
result = PType(idTableGet(c.bindings, t))
|
||||||
if result == nil:
|
if result == nil:
|
||||||
break # it's ok, no match
|
break # it's ok, no match
|
||||||
|
|
@ -267,15 +290,15 @@ proc concreteType(c: TCandidate, t: PType): PType =
|
||||||
result = t
|
result = t
|
||||||
else:
|
else:
|
||||||
result = t # Note: empty is valid here
|
result = t # Note: empty is valid here
|
||||||
|
|
||||||
proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
|
proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
|
||||||
if a.kind == f.kind:
|
if a.kind == f.kind:
|
||||||
result = isEqual
|
result = isEqual
|
||||||
else:
|
else:
|
||||||
let ab = skipTypes(a, {tyRange})
|
let ab = skipTypes(a, {tyRange})
|
||||||
let k = ab.kind
|
let k = ab.kind
|
||||||
if k == f.kind: result = isSubrange
|
if k == f.kind: result = isSubrange
|
||||||
elif k == tyInt and f.kind in {tyRange, tyInt8..tyInt64,
|
elif k == tyInt and f.kind in {tyRange, tyInt8..tyInt64,
|
||||||
tyUInt..tyUInt64} and
|
tyUInt..tyUInt64} and
|
||||||
isIntLit(ab) and ab.n.intVal >= firstOrd(f) and
|
isIntLit(ab) and ab.n.intVal >= firstOrd(f) and
|
||||||
ab.n.intVal <= lastOrd(f):
|
ab.n.intVal <= lastOrd(f):
|
||||||
|
|
@ -286,7 +309,7 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
|
||||||
result = isIntConv
|
result = isIntConv
|
||||||
elif k >= min and k <= max:
|
elif k >= min and k <= max:
|
||||||
result = isConvertible
|
result = isConvertible
|
||||||
elif a.kind == tyRange and a.sons[0].kind in {tyInt..tyInt64,
|
elif a.kind == tyRange and a.sons[0].kind in {tyInt..tyInt64,
|
||||||
tyUInt8..tyUInt32} and
|
tyUInt8..tyUInt32} and
|
||||||
a.n[0].intVal >= firstOrd(f) and
|
a.n[0].intVal >= firstOrd(f) and
|
||||||
a.n[1].intVal <= lastOrd(f):
|
a.n[1].intVal <= lastOrd(f):
|
||||||
|
|
@ -318,12 +341,12 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
|
||||||
if f.kind == tyFloat32: result = isConvertible
|
if f.kind == tyFloat32: result = isConvertible
|
||||||
else: result = isIntConv
|
else: result = isIntConv
|
||||||
else: result = isNone
|
else: result = isNone
|
||||||
|
|
||||||
proc isObjectSubtype(a, f: PType): int =
|
proc isObjectSubtype(a, f: PType): int =
|
||||||
var t = a
|
var t = a
|
||||||
assert t.kind == tyObject
|
assert t.kind == tyObject
|
||||||
var depth = 0
|
var depth = 0
|
||||||
while t != nil and not sameObjectTypes(f, t):
|
while t != nil and not sameObjectTypes(f, t):
|
||||||
assert t.kind == tyObject
|
assert t.kind == tyObject
|
||||||
t = t.sons[0]
|
t = t.sons[0]
|
||||||
if t == nil: break
|
if t == nil: break
|
||||||
|
|
@ -332,17 +355,18 @@ proc isObjectSubtype(a, f: PType): int =
|
||||||
if t != nil:
|
if t != nil:
|
||||||
result = depth
|
result = depth
|
||||||
|
|
||||||
proc minRel(a, b: TTypeRelation): TTypeRelation =
|
proc minRel(a, b: TTypeRelation): TTypeRelation =
|
||||||
if a <= b: result = a
|
if a <= b: result = a
|
||||||
else: result = b
|
else: result = b
|
||||||
|
|
||||||
proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
result = isNone
|
result = isNone
|
||||||
if sameType(f, a): result = isEqual
|
if sameType(f, a):
|
||||||
|
result = isEqual
|
||||||
elif sonsLen(a) == sonsLen(f):
|
elif sonsLen(a) == sonsLen(f):
|
||||||
result = isEqual
|
result = isEqual
|
||||||
let firstField = if f.kind == tyTuple: 0
|
let firstField = if f.kind == tyTuple: 0
|
||||||
else: 1
|
else: 1
|
||||||
for i in countup(firstField, sonsLen(f) - 1):
|
for i in countup(firstField, sonsLen(f) - 1):
|
||||||
var m = typeRel(c, f.sons[i], a.sons[i])
|
var m = typeRel(c, f.sons[i], a.sons[i])
|
||||||
if m < isSubtype: return isNone
|
if m < isSubtype: return isNone
|
||||||
|
|
@ -373,32 +397,32 @@ proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
# We are matching a generic proc (as proc param)
|
# We are matching a generic proc (as proc param)
|
||||||
# to another generic type appearing in the proc
|
# to another generic type appearing in the proc
|
||||||
# signature. There is a change that the target
|
# signature. There is a change that the target
|
||||||
# type is already fully-determined, so we are
|
# type is already fully-determined, so we are
|
||||||
# going to try resolve it
|
# going to try resolve it
|
||||||
f = generateTypeInstance(c.c, c.bindings, c.call.info, f)
|
f = generateTypeInstance(c.c, c.bindings, c.call.info, f)
|
||||||
if f == nil or f.isMetaType:
|
if f == nil or f.isMetaType:
|
||||||
# no luck resolving the type, so the inference fails
|
# no luck resolving the type, so the inference fails
|
||||||
return isNone
|
return isNone
|
||||||
let reverseRel = typeRel(c, a, f)
|
let reverseRel = typeRel(c, a, f)
|
||||||
if reverseRel == isGeneric:
|
if reverseRel >= isGeneric:
|
||||||
result = isInferred
|
result = isInferred
|
||||||
inc c.genericMatches
|
#inc c.genericMatches
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, f, a)
|
result = typeRel(c, f, a)
|
||||||
|
|
||||||
if result <= isSubtype or inconsistentVarTypes(f, a):
|
if result <= isSubtype or inconsistentVarTypes(f, a):
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
||||||
if result == isEqual:
|
#if result == isEqual:
|
||||||
inc c.exactMatches
|
# inc c.exactMatches
|
||||||
|
|
||||||
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
case a.kind
|
case a.kind
|
||||||
of tyProc:
|
of tyProc:
|
||||||
if sonsLen(f) != sonsLen(a): return
|
if sonsLen(f) != sonsLen(a): return
|
||||||
result = isEqual # start with maximum; also correct for no
|
result = isEqual # start with maximum; also correct for no
|
||||||
# params at all
|
# params at all
|
||||||
|
|
||||||
template checkParam(f, a) =
|
template checkParam(f, a) =
|
||||||
result = minRel(result, procParamTypeRel(c, f, a))
|
result = minRel(result, procParamTypeRel(c, f, a))
|
||||||
if result == isNone: return
|
if result == isNone: return
|
||||||
|
|
@ -407,7 +431,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
# return type!
|
# return type!
|
||||||
for i in 1 .. <f.sonsLen:
|
for i in 1 .. <f.sonsLen:
|
||||||
checkParam(f.sons[i], a.sons[i])
|
checkParam(f.sons[i], a.sons[i])
|
||||||
|
|
||||||
if f.sons[0] != nil:
|
if f.sons[0] != nil:
|
||||||
if a.sons[0] != nil:
|
if a.sons[0] != nil:
|
||||||
checkParam(f.sons[0], a.sons[0])
|
checkParam(f.sons[0], a.sons[0])
|
||||||
|
|
@ -433,6 +457,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
return isNone
|
return isNone
|
||||||
when useEffectSystem:
|
when useEffectSystem:
|
||||||
if not compatibleEffects(f, a): return isNone
|
if not compatibleEffects(f, a): return isNone
|
||||||
|
|
||||||
of tyNil:
|
of tyNil:
|
||||||
result = f.allowsNil
|
result = f.allowsNil
|
||||||
of tyIter:
|
of tyIter:
|
||||||
|
|
@ -487,14 +512,14 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
else:
|
else:
|
||||||
param = paramSym skType
|
param = paramSym skType
|
||||||
param.typ = makeTypeDesc(c, typ)
|
param.typ = makeTypeDesc(c, typ)
|
||||||
|
|
||||||
addDecl(c, param)
|
addDecl(c, param)
|
||||||
|
|
||||||
for param in body.n[0]:
|
for param in body.n[0]:
|
||||||
var
|
var
|
||||||
dummyName: PNode
|
dummyName: PNode
|
||||||
dummyType: PType
|
dummyType: PType
|
||||||
|
|
||||||
if param.kind == nkVarTy:
|
if param.kind == nkVarTy:
|
||||||
dummyName = param[0]
|
dummyName = param[0]
|
||||||
dummyType = if a.kind != tyVar: makeVarType(c, a)
|
dummyType = if a.kind != tyVar: makeVarType(c, a)
|
||||||
|
|
@ -520,7 +545,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
of nkTypeSection: discard
|
of nkTypeSection: discard
|
||||||
of nkConstDef: discard
|
of nkConstDef: discard
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
return isGeneric
|
return isGeneric
|
||||||
|
|
||||||
proc shouldSkipDistinct(rules: PNode, callIdent: PIdent): bool =
|
proc shouldSkipDistinct(rules: PNode, callIdent: PIdent): bool =
|
||||||
|
|
@ -554,7 +579,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
# typeRel can be used to establish various relationships between types:
|
# typeRel can be used to establish various relationships between types:
|
||||||
#
|
#
|
||||||
# 1) When used with concrete types, it will check for type equivalence
|
# 1) When used with concrete types, it will check for type equivalence
|
||||||
# or a subtype relationship.
|
# or a subtype relationship.
|
||||||
#
|
#
|
||||||
# 2) When used with a concrete type against a type class (such as generic
|
# 2) When used with a concrete type against a type class (such as generic
|
||||||
# signature of a proc), it will check whether the concrete type is a member
|
# signature of a proc), it will check whether the concrete type is a member
|
||||||
|
|
@ -569,7 +594,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
|
|
||||||
result = isNone
|
result = isNone
|
||||||
assert(f != nil)
|
assert(f != nil)
|
||||||
|
|
||||||
if f.kind == tyExpr:
|
if f.kind == tyExpr:
|
||||||
if aOrig != nil: put(c.bindings, f, aOrig)
|
if aOrig != nil: put(c.bindings, f, aOrig)
|
||||||
return isGeneric
|
return isGeneric
|
||||||
|
|
@ -582,7 +607,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
# start the param matching process. This could be done in `prepareOperand`
|
# start the param matching process. This could be done in `prepareOperand`
|
||||||
# for example, but unfortunately `prepareOperand` is not called in certain
|
# for example, but unfortunately `prepareOperand` is not called in certain
|
||||||
# situation when nkDotExpr are rotated to nkDotCalls
|
# situation when nkDotExpr are rotated to nkDotCalls
|
||||||
|
|
||||||
if a.kind == tyGenericInst and
|
if a.kind == tyGenericInst and
|
||||||
skipTypes(f, {tyVar}).kind notin {
|
skipTypes(f, {tyVar}).kind notin {
|
||||||
tyGenericBody, tyGenericInvocation,
|
tyGenericBody, tyGenericInvocation,
|
||||||
|
|
@ -590,10 +615,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
return typeRel(c, f, lastSon(a))
|
return typeRel(c, f, lastSon(a))
|
||||||
|
|
||||||
template bindingRet(res) =
|
template bindingRet(res) =
|
||||||
when res == isGeneric:
|
if doBind:
|
||||||
if doBind:
|
let bound = aOrig.skipTypes({tyRange}).skipIntLit
|
||||||
let bound = aOrig.skipTypes({tyRange}).skipIntLit
|
if doBind: put(c.bindings, f, bound)
|
||||||
if doBind: put(c.bindings, f, bound)
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
template considerPreviousT(body: stmt) {.immediate.} =
|
template considerPreviousT(body: stmt) {.immediate.} =
|
||||||
|
|
@ -605,20 +629,21 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
of tyOr:
|
of tyOr:
|
||||||
# seq[int|string] vs seq[number]
|
# seq[int|string] vs seq[number]
|
||||||
# both int and string must match against number
|
# both int and string must match against number
|
||||||
|
# but ensure that '[T: A|A]' matches as good as '[T: A]' (bug #2219):
|
||||||
|
result = isGeneric
|
||||||
for branch in a.sons:
|
for branch in a.sons:
|
||||||
if typeRel(c, f, branch, false) == isNone:
|
let x = typeRel(c, f, branch, false)
|
||||||
return isNone
|
if x == isNone: return isNone
|
||||||
|
if x < result: result = x
|
||||||
return isGeneric
|
|
||||||
|
|
||||||
of tyAnd:
|
of tyAnd:
|
||||||
# seq[Sortable and Iterable] vs seq[Sortable]
|
# seq[Sortable and Iterable] vs seq[Sortable]
|
||||||
# only one match is enough
|
# only one match is enough
|
||||||
for branch in a.sons:
|
for branch in a.sons:
|
||||||
if typeRel(c, f, branch, false) != isNone:
|
let x = typeRel(c, f, branch, false)
|
||||||
return isGeneric
|
if x != isNone:
|
||||||
|
return if x >= isGeneric: isGeneric else: x
|
||||||
return isNone
|
result = isNone
|
||||||
|
|
||||||
of tyNot:
|
of tyNot:
|
||||||
case f.kind
|
case f.kind
|
||||||
|
|
@ -626,9 +651,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
# seq[!int] vs seq[!number]
|
# seq[!int] vs seq[!number]
|
||||||
# seq[float] matches the first, but not the second
|
# seq[float] matches the first, but not the second
|
||||||
# we must turn the problem around:
|
# we must turn the problem around:
|
||||||
# is number a subset of int?
|
# is number a subset of int?
|
||||||
return typeRel(c, a.lastSon, f.lastSon)
|
return typeRel(c, a.lastSon, f.lastSon)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# negative type classes are essentially infinite,
|
# negative type classes are essentially infinite,
|
||||||
# so only the `any` type class is their superset
|
# so only the `any` type class is their superset
|
||||||
|
|
@ -727,20 +752,20 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
result = typeRel(c, base(f), base(a))
|
result = typeRel(c, base(f), base(a))
|
||||||
if result < isGeneric: result = isNone
|
if result < isGeneric: result = isNone
|
||||||
of tyArrayConstr:
|
of tyArrayConstr:
|
||||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
|
if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
|
||||||
result = isSubtype # [] is allowed here
|
result = isSubtype # [] is allowed here
|
||||||
elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
|
elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
|
||||||
result = isSubtype
|
result = isSubtype
|
||||||
of tyArray:
|
of tyArray:
|
||||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
|
if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
|
||||||
result = isSubtype
|
result = isSubtype
|
||||||
elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
|
elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
|
||||||
result = isConvertible
|
result = isConvertible
|
||||||
of tySequence:
|
of tySequence:
|
||||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
||||||
result = isConvertible
|
result = isConvertible
|
||||||
elif typeRel(c, base(f), a.sons[0]) >= isGeneric:
|
elif typeRel(c, base(f), a.sons[0]) >= isGeneric:
|
||||||
result = isConvertible
|
result = isConvertible
|
||||||
else: discard
|
else: discard
|
||||||
of tySequence:
|
of tySequence:
|
||||||
|
|
@ -768,7 +793,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
of tyForward: internalError("forward type in typeRel()")
|
of tyForward: internalError("forward type in typeRel()")
|
||||||
of tyNil:
|
of tyNil:
|
||||||
if a.kind == f.kind: result = isEqual
|
if a.kind == f.kind: result = isEqual
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
if a.kind == tyTuple: result = recordRel(c, f, a)
|
if a.kind == tyTuple: result = recordRel(c, f, a)
|
||||||
of tyObject:
|
of tyObject:
|
||||||
if a.kind == tyObject:
|
if a.kind == tyObject:
|
||||||
|
|
@ -781,15 +806,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
inc(c.inheritancePenalty, depth)
|
inc(c.inheritancePenalty, depth)
|
||||||
result = isSubtype
|
result = isSubtype
|
||||||
of tyDistinct:
|
of tyDistinct:
|
||||||
if (a.kind == tyDistinct) and sameDistinctTypes(f, a): result = isEqual
|
if a.kind == tyDistinct and sameDistinctTypes(f, a): result = isEqual
|
||||||
elif c.coerceDistincts: result = typeRel(c, f.base, a)
|
elif c.coerceDistincts: result = typeRel(c, f.base, a)
|
||||||
of tySet:
|
of tySet:
|
||||||
if a.kind == tySet:
|
if a.kind == tySet:
|
||||||
if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
|
if f.sons[0].kind != tyGenericParam and a.sons[0].kind == tyEmpty:
|
||||||
result = isSubtype
|
result = isSubtype
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, f.sons[0], a.sons[0])
|
result = typeRel(c, f.sons[0], a.sons[0])
|
||||||
if result <= isConvertible:
|
if result <= isConvertible:
|
||||||
result = isNone # BUGFIX!
|
result = isNone # BUGFIX!
|
||||||
of tyPtr, tyRef:
|
of tyPtr, tyRef:
|
||||||
if a.kind == f.kind:
|
if a.kind == f.kind:
|
||||||
|
|
@ -823,9 +848,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
if a.len == 1: result = isConvertible
|
if a.len == 1: result = isConvertible
|
||||||
of tyCString: result = isConvertible
|
of tyCString: result = isConvertible
|
||||||
else: discard
|
else: discard
|
||||||
of tyString:
|
of tyString:
|
||||||
case a.kind
|
case a.kind
|
||||||
of tyString:
|
of tyString:
|
||||||
if tfNotNil in f.flags and tfNotNil notin a.flags:
|
if tfNotNil in f.flags and tfNotNil notin a.flags:
|
||||||
result = isNilConversion
|
result = isNilConversion
|
||||||
else:
|
else:
|
||||||
|
|
@ -848,7 +873,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
of tyArray:
|
of tyArray:
|
||||||
if (firstOrd(a.sons[0]) == 0) and
|
if (firstOrd(a.sons[0]) == 0) and
|
||||||
(skipTypes(a.sons[0], {tyRange}).kind in {tyInt..tyInt64}) and
|
(skipTypes(a.sons[0], {tyRange}).kind in {tyInt..tyInt64}) and
|
||||||
(a.sons[1].kind == tyChar):
|
(a.sons[1].kind == tyChar):
|
||||||
result = isConvertible
|
result = isConvertible
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
|
|
@ -863,9 +888,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
let ff = rootf.sons[i]
|
let ff = rootf.sons[i]
|
||||||
let aa = roota.sons[i]
|
let aa = roota.sons[i]
|
||||||
result = typeRel(c, ff, aa)
|
result = typeRel(c, ff, aa)
|
||||||
if result == isNone: return
|
if result == isNone: return
|
||||||
if ff.kind == tyRange and result != isEqual: return isNone
|
if ff.kind == tyRange and result != isEqual: return isNone
|
||||||
result = isGeneric
|
#result = isGeneric
|
||||||
# XXX See bug #2220. A[int] should match A[int] better than some generic X
|
# XXX See bug #2220. A[int] should match A[int] better than some generic X
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, lastSon(f), a)
|
result = typeRel(c, lastSon(f), a)
|
||||||
|
|
@ -883,13 +908,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
#InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
|
#InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
|
||||||
# simply no match for now:
|
# simply no match for now:
|
||||||
discard
|
discard
|
||||||
elif x.kind == tyGenericInst and
|
elif x.kind == tyGenericInst and
|
||||||
(f.sons[0] == x.sons[0]) and
|
(f.sons[0] == x.sons[0]) and
|
||||||
(sonsLen(x) - 1 == sonsLen(f)):
|
(sonsLen(x) - 1 == sonsLen(f)):
|
||||||
for i in countup(1, sonsLen(f) - 1):
|
for i in countup(1, sonsLen(f) - 1):
|
||||||
if x.sons[i].kind == tyGenericParam:
|
if x.sons[i].kind == tyGenericParam:
|
||||||
internalError("wrong instantiated type!")
|
internalError("wrong instantiated type!")
|
||||||
elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return
|
elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, f.sons[0], x)
|
result = typeRel(c, f.sons[0], x)
|
||||||
|
|
@ -900,29 +925,34 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
if x == nil or x.kind in {tyGenericInvocation, tyGenericParam}:
|
if x == nil or x.kind in {tyGenericInvocation, tyGenericParam}:
|
||||||
internalError("wrong instantiated type!")
|
internalError("wrong instantiated type!")
|
||||||
put(c.bindings, f.sons[i], x)
|
put(c.bindings, f.sons[i], x)
|
||||||
|
|
||||||
of tyAnd:
|
of tyAnd:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
for branch in f.sons:
|
for branch in f.sons:
|
||||||
if typeRel(c, branch, aOrig) < isSubtype:
|
let x = typeRel(c, branch, aOrig)
|
||||||
return isNone
|
if x < isSubtype: return isNone
|
||||||
|
# 'and' implies minimum matching result:
|
||||||
bindingRet isGeneric
|
if x < result: result = x
|
||||||
|
bindingRet result
|
||||||
|
|
||||||
of tyOr:
|
of tyOr:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
|
result = isNone
|
||||||
for branch in f.sons:
|
for branch in f.sons:
|
||||||
if typeRel(c, branch, aOrig) >= isSubtype:
|
let x = typeRel(c, branch, aOrig)
|
||||||
bindingRet isGeneric
|
# 'or' implies maximum matching result:
|
||||||
|
if x > result: result = x
|
||||||
return isNone
|
if result >= isSubtype:
|
||||||
|
bindingRet result
|
||||||
|
else:
|
||||||
|
result = isNone
|
||||||
|
|
||||||
of tyNot:
|
of tyNot:
|
||||||
considerPreviousT:
|
considerPreviousT:
|
||||||
for branch in f.sons:
|
for branch in f.sons:
|
||||||
if typeRel(c, branch, aOrig) != isNone:
|
if typeRel(c, branch, aOrig) != isNone:
|
||||||
return isNone
|
return isNone
|
||||||
|
|
||||||
bindingRet isGeneric
|
bindingRet isGeneric
|
||||||
|
|
||||||
of tyAnything:
|
of tyAnything:
|
||||||
|
|
@ -961,7 +991,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
if x == nil:
|
if x == nil:
|
||||||
if c.callee.kind == tyGenericBody and
|
if c.callee.kind == tyGenericBody and
|
||||||
f.kind == tyGenericParam and not c.typedescMatched:
|
f.kind == tyGenericParam and not c.typedescMatched:
|
||||||
# XXX: The fact that generic types currently use tyGenericParam for
|
# XXX: The fact that generic types currently use tyGenericParam for
|
||||||
# their parameters is really a misnomer. tyGenericParam means "match
|
# their parameters is really a misnomer. tyGenericParam means "match
|
||||||
# any value" and what we need is "match any type", which can be encoded
|
# any value" and what we need is "match any type", which can be encoded
|
||||||
# by a tyTypeDesc params. Unfortunately, this requires more substantial
|
# by a tyTypeDesc params. Unfortunately, this requires more substantial
|
||||||
|
|
@ -975,6 +1005,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
internalAssert a.sons != nil and a.sons.len > 0
|
internalAssert a.sons != nil and a.sons.len > 0
|
||||||
c.typedescMatched = true
|
c.typedescMatched = true
|
||||||
result = typeRel(c, f.base, a.skipTypes({tyGenericParam, tyTypeDesc}))
|
result = typeRel(c, f.base, a.skipTypes({tyGenericParam, tyTypeDesc}))
|
||||||
|
if result > isGeneric: result = isGeneric
|
||||||
else:
|
else:
|
||||||
result = isNone
|
result = isNone
|
||||||
else:
|
else:
|
||||||
|
|
@ -998,13 +1029,16 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
return isNone
|
return isNone
|
||||||
if doBind:
|
if doBind:
|
||||||
put(c.bindings, f, concrete)
|
put(c.bindings, f, concrete)
|
||||||
|
elif result > isGeneric:
|
||||||
|
result = isGeneric
|
||||||
elif a.kind == tyEmpty:
|
elif a.kind == tyEmpty:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
elif x.kind == tyGenericParam:
|
elif x.kind == tyGenericParam:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, x, a) # check if it fits
|
result = typeRel(c, x, a) # check if it fits
|
||||||
|
if result > isGeneric: result = isGeneric
|
||||||
|
|
||||||
of tyStatic:
|
of tyStatic:
|
||||||
let prev = PType(idTableGet(c.bindings, f))
|
let prev = PType(idTableGet(c.bindings, f))
|
||||||
if prev == nil:
|
if prev == nil:
|
||||||
|
|
@ -1034,12 +1068,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
# when `f` is an unresolved typedesc, `a` could be any
|
# when `f` is an unresolved typedesc, `a` could be any
|
||||||
# type, so we should not perform this check earlier
|
# type, so we should not perform this check earlier
|
||||||
if a.kind != tyTypeDesc: return isNone
|
if a.kind != tyTypeDesc: return isNone
|
||||||
|
|
||||||
if f.base.kind == tyNone:
|
if f.base.kind == tyNone:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
else:
|
else:
|
||||||
result = typeRel(c, f.base, a.base)
|
result = typeRel(c, f.base, a.base)
|
||||||
|
|
||||||
if result != isNone:
|
if result != isNone:
|
||||||
put(c.bindings, f, a)
|
put(c.bindings, f, a)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1049,9 +1083,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
result = typeRel(c, prev.base, a.base)
|
result = typeRel(c, prev.base, a.base)
|
||||||
else:
|
else:
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
||||||
of tyIter:
|
of tyIter:
|
||||||
if a.kind == tyIter or
|
if a.kind == tyIter or
|
||||||
(a.kind == tyProc and tfIterator in a.flags):
|
(a.kind == tyProc and tfIterator in a.flags):
|
||||||
result = typeRel(c, f.base, a.base)
|
result = typeRel(c, f.base, a.base)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1059,7 +1093,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
|
|
||||||
of tyStmt:
|
of tyStmt:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
|
|
||||||
of tyProxy:
|
of tyProxy:
|
||||||
result = isEqual
|
result = isEqual
|
||||||
|
|
||||||
|
|
@ -1078,11 +1112,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
else:
|
else:
|
||||||
localError(f.n.info, errTypeExpected)
|
localError(f.n.info, errTypeExpected)
|
||||||
result = isNone
|
result = isNone
|
||||||
|
|
||||||
else:
|
else:
|
||||||
internalAssert false
|
internalAssert false
|
||||||
|
|
||||||
proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
|
proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
|
||||||
var m: TCandidate
|
var m: TCandidate
|
||||||
initCandidate(c, m, f)
|
initCandidate(c, m, f)
|
||||||
result = typeRel(m, f, a)
|
result = typeRel(m, f, a)
|
||||||
|
|
@ -1095,9 +1129,9 @@ proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate,
|
||||||
if result == nil:
|
if result == nil:
|
||||||
internalError(arg.info, "getInstantiatedType")
|
internalError(arg.info, "getInstantiatedType")
|
||||||
result = errorType(c)
|
result = errorType(c)
|
||||||
|
|
||||||
proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
|
proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
|
||||||
c: PContext): PNode =
|
c: PContext): PNode =
|
||||||
result = newNodeI(kind, arg.info)
|
result = newNodeI(kind, arg.info)
|
||||||
if containsGenericType(f):
|
if containsGenericType(f):
|
||||||
if not m.hasFauxMatch:
|
if not m.hasFauxMatch:
|
||||||
|
|
@ -1110,10 +1144,10 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
|
||||||
addSon(result, ast.emptyNode)
|
addSon(result, ast.emptyNode)
|
||||||
addSon(result, arg)
|
addSon(result, arg)
|
||||||
|
|
||||||
proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
arg: PNode): PNode =
|
arg: PNode): PNode =
|
||||||
result = nil
|
result = nil
|
||||||
for i in countup(0, len(c.converters) - 1):
|
for i in countup(0, len(c.converters) - 1):
|
||||||
var src = c.converters[i].typ.sons[1]
|
var src = c.converters[i].typ.sons[1]
|
||||||
var dest = c.converters[i].typ.sons[0]
|
var dest = c.converters[i].typ.sons[0]
|
||||||
# for generic type converters we need to check 'src <- a' before
|
# for generic type converters we need to check 'src <- a' before
|
||||||
|
|
@ -1121,12 +1155,12 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
# see tests/tgenericconverter:
|
# see tests/tgenericconverter:
|
||||||
let srca = typeRel(m, src, a)
|
let srca = typeRel(m, src, a)
|
||||||
if srca notin {isEqual, isGeneric}: continue
|
if srca notin {isEqual, isGeneric}: continue
|
||||||
|
|
||||||
let destIsGeneric = containsGenericType(dest)
|
let destIsGeneric = containsGenericType(dest)
|
||||||
if destIsGeneric:
|
if destIsGeneric:
|
||||||
dest = generateTypeInstance(c, m.bindings, arg, dest)
|
dest = generateTypeInstance(c, m.bindings, arg, dest)
|
||||||
let fdest = typeRel(m, f, dest)
|
let fdest = typeRel(m, f, dest)
|
||||||
if fdest in {isEqual, isGeneric}:
|
if fdest in {isEqual, isGeneric}:
|
||||||
markUsed(arg.info, c.converters[i])
|
markUsed(arg.info, c.converters[i])
|
||||||
var s = newSymNode(c.converters[i])
|
var s = newSymNode(c.converters[i])
|
||||||
s.typ = c.converters[i].typ
|
s.typ = c.converters[i].typ
|
||||||
|
|
@ -1138,8 +1172,8 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
m.genericConverter = srca == isGeneric or destIsGeneric
|
m.genericConverter = srca == isGeneric or destIsGeneric
|
||||||
return result
|
return result
|
||||||
|
|
||||||
proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
arg: PNode): PNode =
|
arg: PNode): PNode =
|
||||||
# arg.typ can be nil in 'suggest':
|
# arg.typ can be nil in 'suggest':
|
||||||
if isNil(arg.typ): return nil
|
if isNil(arg.typ): return nil
|
||||||
|
|
||||||
|
|
@ -1181,12 +1215,12 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
arg = argSemantized
|
arg = argSemantized
|
||||||
argType = argType
|
argType = argType
|
||||||
c = m.c
|
c = m.c
|
||||||
|
|
||||||
if tfHasStatic in fMaybeStatic.flags:
|
if tfHasStatic in fMaybeStatic.flags:
|
||||||
# XXX: When implicit statics are the default
|
# XXX: When implicit statics are the default
|
||||||
# this will be done earlier - we just have to
|
# this will be done earlier - we just have to
|
||||||
# make sure that static types enter here
|
# make sure that static types enter here
|
||||||
|
|
||||||
# XXX: weaken tyGenericParam and call it tyGenericPlaceholder
|
# XXX: weaken tyGenericParam and call it tyGenericPlaceholder
|
||||||
# and finally start using tyTypedesc for generic types properly.
|
# and finally start using tyTypedesc for generic types properly.
|
||||||
if argType.kind == tyGenericParam and tfWildcard in argType.flags:
|
if argType.kind == tyGenericParam and tfWildcard in argType.flags:
|
||||||
|
|
@ -1205,11 +1239,11 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
arg.typ.sons = @[evaluated.typ]
|
arg.typ.sons = @[evaluated.typ]
|
||||||
arg.typ.n = evaluated
|
arg.typ.n = evaluated
|
||||||
argType = arg.typ
|
argType = arg.typ
|
||||||
|
|
||||||
var
|
var
|
||||||
a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc, tyFieldAccessor})
|
a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc, tyFieldAccessor})
|
||||||
else: argType
|
else: argType
|
||||||
|
|
||||||
r = typeRel(m, f, a)
|
r = typeRel(m, f, a)
|
||||||
|
|
||||||
if r != isNone and m.calleeSym != nil and
|
if r != isNone and m.calleeSym != nil and
|
||||||
|
|
@ -1220,8 +1254,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
of isConvertible, isIntConv: inc(m.convMatches)
|
of isConvertible, isIntConv: inc(m.convMatches)
|
||||||
of isSubtype, isSubrange: inc(m.subtypeMatches)
|
of isSubtype, isSubrange: inc(m.subtypeMatches)
|
||||||
of isGeneric, isInferred: inc(m.genericMatches)
|
of isGeneric, isInferred: inc(m.genericMatches)
|
||||||
of isInferredConvertible: inc(m.genericMatches); inc(m.convMatches)
|
|
||||||
of isFromIntLit: inc(m.intConvMatches, 256)
|
of isFromIntLit: inc(m.intConvMatches, 256)
|
||||||
|
of isInferredConvertible:
|
||||||
|
inc(m.convMatches)
|
||||||
of isEqual: inc(m.exactMatches)
|
of isEqual: inc(m.exactMatches)
|
||||||
of isNone: discard
|
of isNone: discard
|
||||||
|
|
||||||
|
|
@ -1232,7 +1267,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)
|
||||||
|
|
@ -1244,21 +1279,22 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
case r
|
case r
|
||||||
of isConvertible:
|
of isConvertible:
|
||||||
inc(m.convMatches)
|
inc(m.convMatches)
|
||||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||||
of isIntConv:
|
of isIntConv:
|
||||||
# I'm too lazy to introduce another ``*matches`` field, so we conflate
|
# I'm too lazy to introduce another ``*matches`` field, so we conflate
|
||||||
# ``isIntConv`` and ``isIntLit`` here:
|
# ``isIntConv`` and ``isIntLit`` here:
|
||||||
inc(m.intConvMatches)
|
inc(m.intConvMatches)
|
||||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||||
of isSubtype:
|
of isSubtype:
|
||||||
inc(m.subtypeMatches)
|
inc(m.subtypeMatches)
|
||||||
result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
|
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
|
||||||
of isSubrange:
|
of isSubrange:
|
||||||
inc(m.subtypeMatches)
|
inc(m.subtypeMatches)
|
||||||
#result = copyTree(arg)
|
if f.kind == tyVar:
|
||||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
result = arg
|
||||||
|
else:
|
||||||
|
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||||
of isInferred, isInferredConvertible:
|
of isInferred, isInferredConvertible:
|
||||||
inc(m.genericMatches)
|
|
||||||
if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
|
if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
|
||||||
result = c.semInferredLambda(c, m.bindings, arg)
|
result = c.semInferredLambda(c, m.bindings, arg)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1267,42 +1303,36 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
if r == isInferredConvertible:
|
if r == isInferredConvertible:
|
||||||
inc(m.convMatches)
|
inc(m.convMatches)
|
||||||
result = implicitConv(nkHiddenStdConv, f, result, m, c)
|
result = implicitConv(nkHiddenStdConv, f, result, m, c)
|
||||||
|
else:
|
||||||
|
inc(m.genericMatches)
|
||||||
of isGeneric:
|
of isGeneric:
|
||||||
inc(m.genericMatches)
|
inc(m.genericMatches)
|
||||||
when true:
|
if arg.typ == nil:
|
||||||
if skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
|
result = arg
|
||||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
|
||||||
elif arg.typ != nil and arg.typ.isEmptyContainer:
|
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||||
result = arg.copyTree
|
elif arg.typ.isEmptyContainer:
|
||||||
result.typ = getInstantiatedType(c, arg, m, f)
|
result = arg.copyTree
|
||||||
else:
|
|
||||||
result = arg
|
|
||||||
else:
|
|
||||||
# XXX Why is this ever necessary? arg's type should not be retrofitted
|
|
||||||
# to match formal's type in this way!
|
|
||||||
result = copyTree(arg)
|
|
||||||
result.typ = getInstantiatedType(c, arg, m, f)
|
result.typ = getInstantiatedType(c, arg, m, f)
|
||||||
# BUG: f may not be the right key!
|
else:
|
||||||
if skipTypes(result.typ, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
|
result = arg
|
||||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
|
||||||
# BUGFIX: use ``result.typ`` and not `f` here
|
|
||||||
of isFromIntLit:
|
of isFromIntLit:
|
||||||
# too lazy to introduce another ``*matches`` field, so we conflate
|
# too lazy to introduce another ``*matches`` field, so we conflate
|
||||||
# ``isIntConv`` and ``isIntLit`` here:
|
# ``isIntConv`` and ``isIntLit`` here:
|
||||||
inc(m.intConvMatches, 256)
|
inc(m.intConvMatches, 256)
|
||||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||||
of isEqual:
|
of isEqual:
|
||||||
inc(m.exactMatches)
|
inc(m.exactMatches)
|
||||||
result = copyTree(arg)
|
result = arg
|
||||||
if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
|
if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
|
||||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||||
of isNone:
|
of isNone:
|
||||||
# do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
|
# do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
|
||||||
if a.kind in {tyProxy, tyUnknown}:
|
if a.kind in {tyProxy, tyUnknown}:
|
||||||
inc(m.genericMatches)
|
inc(m.genericMatches)
|
||||||
m.fauxMatch = a.kind
|
m.fauxMatch = a.kind
|
||||||
return copyTree(arg)
|
return arg
|
||||||
result = userConvMatch(c, m, f, a, arg)
|
result = userConvMatch(c, m, f, a, arg)
|
||||||
# check for a base type match, which supports varargs[T] without []
|
# check for a base type match, which supports varargs[T] without []
|
||||||
# constructor in a call:
|
# constructor in a call:
|
||||||
if result == nil and f.kind == tyVarargs:
|
if result == nil and f.kind == tyVarargs:
|
||||||
|
|
@ -1323,7 +1353,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
||||||
arg, argOrig: PNode): PNode =
|
arg, argOrig: PNode): PNode =
|
||||||
if arg == nil or arg.kind notin nkSymChoices:
|
if arg == nil or arg.kind notin nkSymChoices:
|
||||||
result = paramTypesMatchAux(m, f, a, arg, argOrig)
|
result = paramTypesMatchAux(m, f, a, arg, argOrig)
|
||||||
else:
|
else:
|
||||||
# CAUTION: The order depends on the used hashing scheme. Thus it is
|
# CAUTION: The order depends on the used hashing scheme. Thus it is
|
||||||
# incorrect to simply use the first fitting match. However, to implement
|
# incorrect to simply use the first fitting match. However, to implement
|
||||||
# this correctly is inefficient. We have to copy `m` here to be able to
|
# this correctly is inefficient. We have to copy `m` here to be able to
|
||||||
|
|
@ -1337,28 +1367,37 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
||||||
y.calleeSym = m.calleeSym
|
y.calleeSym = m.calleeSym
|
||||||
z.calleeSym = m.calleeSym
|
z.calleeSym = m.calleeSym
|
||||||
var best = -1
|
var best = -1
|
||||||
for i in countup(0, sonsLen(arg) - 1):
|
for i in countup(0, sonsLen(arg) - 1):
|
||||||
if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}+skIterators:
|
if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}+skIterators:
|
||||||
copyCandidate(z, m)
|
copyCandidate(z, m)
|
||||||
|
z.callee = arg.sons[i].typ
|
||||||
|
z.calleeSym = arg.sons[i].sym
|
||||||
|
#if arg.sons[i].sym.name.s == "cmp":
|
||||||
|
# ggDebug = true
|
||||||
|
# echo "CALLLEEEEEEEE ", typeToString(z.callee)
|
||||||
var r = typeRel(z, f, arg.sons[i].typ)
|
var r = typeRel(z, f, arg.sons[i].typ)
|
||||||
if r != isNone:
|
#if arg.sons[i].sym.name.s == "cmp": # and arg.info.line == 606:
|
||||||
|
# echo "M ", r, " ", arg.info, " ", typeToString(arg.sons[i].sym.typ)
|
||||||
|
# debug arg.sons[i].sym
|
||||||
|
# writeMatches(z)
|
||||||
|
if r != isNone:
|
||||||
case x.state
|
case x.state
|
||||||
of csEmpty, csNoMatch:
|
of csEmpty, csNoMatch:
|
||||||
x = z
|
x = z
|
||||||
best = i
|
best = i
|
||||||
x.state = csMatch
|
x.state = csMatch
|
||||||
of csMatch:
|
of csMatch:
|
||||||
var cmp = cmpCandidates(x, z)
|
var cmp = cmpCandidates(x, z)
|
||||||
if cmp < 0:
|
if cmp < 0:
|
||||||
best = i
|
best = i
|
||||||
x = z
|
x = z
|
||||||
elif cmp == 0:
|
elif cmp == 0:
|
||||||
y = z # z is as good as x
|
y = z # z is as good as x
|
||||||
if x.state == csEmpty:
|
if x.state == csEmpty:
|
||||||
result = nil
|
result = nil
|
||||||
elif y.state == csMatch and cmpCandidates(x, y) == 0:
|
elif y.state == csMatch and cmpCandidates(x, y) == 0:
|
||||||
if x.state != csMatch:
|
if x.state != csMatch:
|
||||||
internalError(arg.info, "x.state is not csMatch")
|
internalError(arg.info, "x.state is not csMatch")
|
||||||
# ambiguous: more than one symbol fits!
|
# ambiguous: more than one symbol fits!
|
||||||
# See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match
|
# See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match
|
||||||
# anyway:
|
# anyway:
|
||||||
|
|
@ -1371,7 +1410,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
||||||
result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
|
result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
|
||||||
argOrig)
|
argOrig)
|
||||||
|
|
||||||
proc setSon(father: PNode, at: int, son: PNode) =
|
proc setSon(father: PNode, at: int, son: PNode) =
|
||||||
if sonsLen(father) <= at: setLen(father.sons, at + 1)
|
if sonsLen(father) <= at: setLen(father.sons, at + 1)
|
||||||
father.sons[at] = son
|
father.sons[at] = son
|
||||||
|
|
||||||
|
|
@ -1415,7 +1454,7 @@ proc incrIndexType(t: PType) =
|
||||||
inc t.sons[0].n.sons[1].intVal
|
inc t.sons[0].n.sons[1].intVal
|
||||||
|
|
||||||
proc matchesAux(c: PContext, n, nOrig: PNode,
|
proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
m: var TCandidate, marker: var IntSet) =
|
m: var TCandidate, marker: var IntSet) =
|
||||||
template checkConstraint(n: expr) {.immediate, dirty.} =
|
template checkConstraint(n: expr) {.immediate, dirty.} =
|
||||||
if not formal.constraint.isNil:
|
if not formal.constraint.isNil:
|
||||||
if matchNodeKinds(formal.constraint, n):
|
if matchNodeKinds(formal.constraint, n):
|
||||||
|
|
@ -1445,20 +1484,20 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
# named param
|
# named param
|
||||||
# check if m.callee has such a param:
|
# check if m.callee has such a param:
|
||||||
prepareNamedParam(n.sons[a])
|
prepareNamedParam(n.sons[a])
|
||||||
if n.sons[a].sons[0].kind != nkIdent:
|
if n.sons[a].sons[0].kind != nkIdent:
|
||||||
localError(n.sons[a].info, errNamedParamHasToBeIdent)
|
localError(n.sons[a].info, errNamedParamHasToBeIdent)
|
||||||
m.state = csNoMatch
|
m.state = csNoMatch
|
||||||
return
|
return
|
||||||
formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1)
|
formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1)
|
||||||
if formal == nil:
|
if formal == nil:
|
||||||
# no error message!
|
# no error message!
|
||||||
m.state = csNoMatch
|
m.state = csNoMatch
|
||||||
return
|
return
|
||||||
if containsOrIncl(marker, formal.position):
|
if containsOrIncl(marker, formal.position):
|
||||||
# already in namedParams:
|
# already in namedParams:
|
||||||
localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
|
localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
|
||||||
m.state = csNoMatch
|
m.state = csNoMatch
|
||||||
return
|
return
|
||||||
m.baseTypeMatch = false
|
m.baseTypeMatch = false
|
||||||
n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1])
|
n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1])
|
||||||
n.sons[a].typ = n.sons[a].sons[1].typ
|
n.sons[a].typ = n.sons[a].sons[1].typ
|
||||||
|
|
@ -1468,7 +1507,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
m.state = csNoMatch
|
m.state = csNoMatch
|
||||||
return
|
return
|
||||||
checkConstraint(n.sons[a].sons[1])
|
checkConstraint(n.sons[a].sons[1])
|
||||||
if m.baseTypeMatch:
|
if m.baseTypeMatch:
|
||||||
#assert(container == nil)
|
#assert(container == nil)
|
||||||
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
|
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
|
||||||
addSon(container, arg)
|
addSon(container, arg)
|
||||||
|
|
@ -1505,7 +1544,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
m.state = csNoMatch
|
m.state = csNoMatch
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
if m.callee.n.sons[f].kind != nkSym:
|
if m.callee.n.sons[f].kind != nkSym:
|
||||||
internalError(n.sons[a].info, "matches")
|
internalError(n.sons[a].info, "matches")
|
||||||
return
|
return
|
||||||
formal = m.callee.n.sons[f].sym
|
formal = m.callee.n.sons[f].sym
|
||||||
|
|
@ -1513,7 +1552,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
# already in namedParams:
|
# already in namedParams:
|
||||||
localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
|
localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
|
||||||
m.state = csNoMatch
|
m.state = csNoMatch
|
||||||
return
|
return
|
||||||
m.baseTypeMatch = false
|
m.baseTypeMatch = false
|
||||||
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
|
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
|
||||||
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
|
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
|
||||||
|
|
@ -1526,7 +1565,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
if container.isNil:
|
if container.isNil:
|
||||||
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
|
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
|
||||||
addSon(container, arg)
|
addSon(container, arg)
|
||||||
setSon(m.call, formal.position + 1,
|
setSon(m.call, formal.position + 1,
|
||||||
implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
|
implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
|
||||||
#if f != formalLen - 1: container = nil
|
#if f != formalLen - 1: container = nil
|
||||||
|
|
||||||
|
|
@ -1601,7 +1640,7 @@ when not declared(tests):
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo())
|
var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo())
|
||||||
|
|
||||||
proc `|` (t1, t2: PType): PType =
|
proc `|` (t1, t2: PType): PType =
|
||||||
result = newType(tyOr, dummyOwner)
|
result = newType(tyOr, dummyOwner)
|
||||||
result.rawAddSon(t1)
|
result.rawAddSon(t1)
|
||||||
|
|
@ -1622,12 +1661,12 @@ tests:
|
||||||
|
|
||||||
proc array(x: int, t: PType): PType =
|
proc array(x: int, t: PType): PType =
|
||||||
result = newType(tyArray, dummyOwner)
|
result = newType(tyArray, dummyOwner)
|
||||||
|
|
||||||
var n = newNodeI(nkRange, UnknownLineInfo())
|
var n = newNodeI(nkRange, UnknownLineInfo())
|
||||||
addSon(n, newIntNode(nkIntLit, 0))
|
addSon(n, newIntNode(nkIntLit, 0))
|
||||||
addSon(n, newIntNode(nkIntLit, x))
|
addSon(n, newIntNode(nkIntLit, x))
|
||||||
let range = newType(tyRange, dummyOwner)
|
let range = newType(tyRange, dummyOwner)
|
||||||
|
|
||||||
result.rawAddSon(range)
|
result.rawAddSon(range)
|
||||||
result.rawAddSon(t)
|
result.rawAddSon(t)
|
||||||
|
|
||||||
|
|
@ -1653,7 +1692,7 @@ tests:
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
var c: TCandidate
|
var c: TCandidate
|
||||||
InitCandidate(nil, c, nil)
|
initCandidate(nil, c, nil)
|
||||||
|
|
||||||
template yes(x, y) =
|
template yes(x, y) =
|
||||||
test astToStr(x) & " is " & astToStr(y):
|
test astToStr(x) & " is " & astToStr(y):
|
||||||
|
|
@ -1662,7 +1701,7 @@ tests:
|
||||||
template no(x, y) =
|
template no(x, y) =
|
||||||
test astToStr(x) & " is not " & astToStr(y):
|
test astToStr(x) & " is not " & astToStr(y):
|
||||||
check typeRel(c, y, x) == isNone
|
check typeRel(c, y, x) == isNone
|
||||||
|
|
||||||
yes seq(any), array(10, int) | seq(any)
|
yes seq(any), array(10, int) | seq(any)
|
||||||
# Sure, seq[any] is directly included
|
# Sure, seq[any] is directly included
|
||||||
|
|
||||||
|
|
@ -1670,16 +1709,16 @@ tests:
|
||||||
yes seq(int), seq(number)
|
yes seq(int), seq(number)
|
||||||
# Sure, the int sequence is certainly
|
# Sure, the int sequence is certainly
|
||||||
# part of the number sequences (and all sequences)
|
# part of the number sequences (and all sequences)
|
||||||
|
|
||||||
no seq(any), seq(float)
|
no seq(any), seq(float)
|
||||||
# Nope, seq[any] includes types that are not seq[float] (e.g. seq[int])
|
# Nope, seq[any] includes types that are not seq[float] (e.g. seq[int])
|
||||||
|
|
||||||
yes seq(int|string), seq(any)
|
yes seq(int|string), seq(any)
|
||||||
# Sure
|
# Sure
|
||||||
|
|
||||||
yes seq(int&string), seq(any)
|
yes seq(int&string), seq(any)
|
||||||
# Again
|
# Again
|
||||||
|
|
||||||
yes seq(int&string), seq(int)
|
yes seq(int&string), seq(int)
|
||||||
# A bit more complicated
|
# A bit more complicated
|
||||||
# seq[int&string] is not a real type, but it's analogous to
|
# seq[int&string] is not a real type, but it's analogous to
|
||||||
|
|
@ -1688,23 +1727,23 @@ tests:
|
||||||
no seq(int|string), seq(int|float)
|
no seq(int|string), seq(int|float)
|
||||||
# Nope, seq[string] is not included in not included in
|
# Nope, seq[string] is not included in not included in
|
||||||
# the seq[int|float] set
|
# the seq[int|float] set
|
||||||
|
|
||||||
no seq(!(int|string)), seq(string)
|
no seq(!(int|string)), seq(string)
|
||||||
# A sequence that is neither seq[int] or seq[string]
|
# A sequence that is neither seq[int] or seq[string]
|
||||||
# is obviously not seq[string]
|
# is obviously not seq[string]
|
||||||
|
|
||||||
no seq(!int), seq(number)
|
no seq(!int), seq(number)
|
||||||
# Now your head should start to hurt a bit
|
# Now your head should start to hurt a bit
|
||||||
# A sequence that is not seq[int] is not necessarily a number sequence
|
# A sequence that is not seq[int] is not necessarily a number sequence
|
||||||
# it could well be seq[string] for example
|
# it could well be seq[string] for example
|
||||||
|
|
||||||
yes seq(!(int|string)), seq(!string)
|
yes seq(!(int|string)), seq(!string)
|
||||||
# all sequnece types besides seq[int] and seq[string]
|
# all sequnece types besides seq[int] and seq[string]
|
||||||
# are subset of all sequence types that are not seq[string]
|
# are subset of all sequence types that are not seq[string]
|
||||||
|
|
||||||
no seq(!(int|string)), seq(!(string|TFoo))
|
no seq(!(int|string)), seq(!(string|TFoo))
|
||||||
# Nope, seq[TFoo] is included in the first set, but not in the second
|
# Nope, seq[TFoo] is included in the first set, but not in the second
|
||||||
|
|
||||||
no seq(!string), seq(!number)
|
no seq(!string), seq(!number)
|
||||||
# Nope, seq[int] in included in the first set, but not in the second
|
# Nope, seq[int] in included in the first set, but not in the second
|
||||||
|
|
||||||
|
|
@ -1712,7 +1751,7 @@ tests:
|
||||||
yes seq(!int), seq(any)
|
yes seq(!int), seq(any)
|
||||||
no seq(any), seq(!any)
|
no seq(any), seq(!any)
|
||||||
no seq(!int), seq(!any)
|
no seq(!int), seq(!any)
|
||||||
|
|
||||||
yes int, ordinal
|
yes int, ordinal
|
||||||
no string, ordinal
|
no string, ordinal
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,27 +17,27 @@
|
||||||
# * introduces method dispatchers
|
# * introduces method dispatchers
|
||||||
# * performs lambda lifting for closure support
|
# * performs lambda lifting for closure support
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
|
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
|
||||||
idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread,
|
idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread,
|
||||||
lambdalifting, sempass2, lowerings
|
lambdalifting, sempass2, lowerings
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
type
|
type
|
||||||
PTransNode* = distinct PNode
|
PTransNode* = distinct PNode
|
||||||
|
|
||||||
PTransCon = ref TTransCon
|
PTransCon = ref TTransCon
|
||||||
TTransCon{.final.} = object # part of TContext; stackable
|
TTransCon{.final.} = object # part of TContext; stackable
|
||||||
mapping: TIdNodeTable # mapping from symbols to nodes
|
mapping: TIdNodeTable # mapping from symbols to nodes
|
||||||
owner: PSym # current owner
|
owner: PSym # current owner
|
||||||
forStmt: PNode # current for stmt
|
forStmt: PNode # current for stmt
|
||||||
forLoopBody: PTransNode # transformed for loop body
|
forLoopBody: PTransNode # transformed for loop body
|
||||||
yieldStmts: int # we count the number of yield statements,
|
yieldStmts: int # we count the number of yield statements,
|
||||||
# because we need to introduce new variables
|
# because we need to introduce new variables
|
||||||
# if we encounter the 2nd yield statement
|
# if we encounter the 2nd yield statement
|
||||||
next: PTransCon # for stacking
|
next: PTransCon # for stacking
|
||||||
|
|
||||||
TTransfContext = object of passes.TPassContext
|
TTransfContext = object of passes.TPassContext
|
||||||
module: PSym
|
module: PSym
|
||||||
transCon: PTransCon # top of a TransCon stack
|
transCon: PTransCon # top of a TransCon stack
|
||||||
|
|
@ -46,52 +46,52 @@ type
|
||||||
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
||||||
PTransf = ref TTransfContext
|
PTransf = ref TTransfContext
|
||||||
|
|
||||||
proc newTransNode(a: PNode): PTransNode {.inline.} =
|
proc newTransNode(a: PNode): PTransNode {.inline.} =
|
||||||
result = PTransNode(shallowCopy(a))
|
result = PTransNode(shallowCopy(a))
|
||||||
|
|
||||||
proc newTransNode(kind: TNodeKind, info: TLineInfo,
|
proc newTransNode(kind: TNodeKind, info: TLineInfo,
|
||||||
sons: int): PTransNode {.inline.} =
|
sons: int): PTransNode {.inline.} =
|
||||||
var x = newNodeI(kind, info)
|
var x = newNodeI(kind, info)
|
||||||
newSeq(x.sons, sons)
|
newSeq(x.sons, sons)
|
||||||
result = x.PTransNode
|
result = x.PTransNode
|
||||||
|
|
||||||
proc newTransNode(kind: TNodeKind, n: PNode,
|
proc newTransNode(kind: TNodeKind, n: PNode,
|
||||||
sons: int): PTransNode {.inline.} =
|
sons: int): PTransNode {.inline.} =
|
||||||
var x = newNodeIT(kind, n.info, n.typ)
|
var x = newNodeIT(kind, n.info, n.typ)
|
||||||
newSeq(x.sons, sons)
|
newSeq(x.sons, sons)
|
||||||
x.typ = n.typ
|
x.typ = n.typ
|
||||||
result = x.PTransNode
|
result = x.PTransNode
|
||||||
|
|
||||||
proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
|
proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
|
||||||
var n = PNode(a)
|
var n = PNode(a)
|
||||||
n.sons[i] = PNode(x)
|
n.sons[i] = PNode(x)
|
||||||
|
|
||||||
proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} =
|
proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} =
|
||||||
var n = PNode(a)
|
var n = PNode(a)
|
||||||
result = n.sons[i].PTransNode
|
result = n.sons[i].PTransNode
|
||||||
|
|
||||||
proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
|
proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
|
||||||
proc len(a: PTransNode): int {.inline.} = result = sonsLen(a.PNode)
|
proc len(a: PTransNode): int {.inline.} = result = sonsLen(a.PNode)
|
||||||
|
|
||||||
proc newTransCon(owner: PSym): PTransCon =
|
proc newTransCon(owner: PSym): PTransCon =
|
||||||
assert owner != nil
|
assert owner != nil
|
||||||
new(result)
|
new(result)
|
||||||
initIdNodeTable(result.mapping)
|
initIdNodeTable(result.mapping)
|
||||||
result.owner = owner
|
result.owner = owner
|
||||||
|
|
||||||
proc pushTransCon(c: PTransf, t: PTransCon) =
|
proc pushTransCon(c: PTransf, t: PTransCon) =
|
||||||
t.next = c.transCon
|
t.next = c.transCon
|
||||||
c.transCon = t
|
c.transCon = t
|
||||||
|
|
||||||
proc popTransCon(c: PTransf) =
|
proc popTransCon(c: PTransf) =
|
||||||
if (c.transCon == nil): internalError("popTransCon")
|
if (c.transCon == nil): internalError("popTransCon")
|
||||||
c.transCon = c.transCon.next
|
c.transCon = c.transCon.next
|
||||||
|
|
||||||
proc getCurrOwner(c: PTransf): PSym =
|
proc getCurrOwner(c: PTransf): PSym =
|
||||||
if c.transCon != nil: result = c.transCon.owner
|
if c.transCon != nil: result = c.transCon.owner
|
||||||
else: result = c.module
|
else: result = c.module
|
||||||
|
|
||||||
proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PSym =
|
proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PSym =
|
||||||
result = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c), info)
|
result = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c), info)
|
||||||
result.typ = skipTypes(typ, {tyGenericInst})
|
result.typ = skipTypes(typ, {tyGenericInst})
|
||||||
incl(result.flags, sfFromGeneric)
|
incl(result.flags, sfFromGeneric)
|
||||||
|
|
@ -100,10 +100,10 @@ proc transform(c: PTransf, n: PNode): PTransNode
|
||||||
|
|
||||||
proc transformSons(c: PTransf, n: PNode): PTransNode =
|
proc transformSons(c: PTransf, n: PNode): PTransNode =
|
||||||
result = newTransNode(n)
|
result = newTransNode(n)
|
||||||
for i in countup(0, sonsLen(n)-1):
|
for i in countup(0, sonsLen(n)-1):
|
||||||
result[i] = transform(c, n.sons[i])
|
result[i] = transform(c, n.sons[i])
|
||||||
|
|
||||||
proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
|
proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
|
||||||
result = newTransNode(nkFastAsgn, PNode(ri).info, 2)
|
result = newTransNode(nkFastAsgn, PNode(ri).info, 2)
|
||||||
result[0] = PTransNode(le)
|
result[0] = PTransNode(le)
|
||||||
result[1] = ri
|
result[1] = ri
|
||||||
|
|
@ -113,30 +113,30 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
|
||||||
# return liftIterSym(n)
|
# return liftIterSym(n)
|
||||||
var b: PNode
|
var b: PNode
|
||||||
var tc = c.transCon
|
var tc = c.transCon
|
||||||
if sfBorrow in n.sym.flags:
|
if sfBorrow in n.sym.flags:
|
||||||
# simply exchange the symbol:
|
# simply exchange the symbol:
|
||||||
b = n.sym.getBody
|
b = n.sym.getBody
|
||||||
if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol")
|
if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol")
|
||||||
b = newSymNode(b.sym)
|
b = newSymNode(b.sym)
|
||||||
b.info = n.info
|
b.info = n.info
|
||||||
else:
|
else:
|
||||||
b = n
|
b = n
|
||||||
while tc != nil:
|
while tc != nil:
|
||||||
result = idNodeTableGet(tc.mapping, b.sym)
|
result = idNodeTableGet(tc.mapping, b.sym)
|
||||||
if result != nil: return
|
if result != nil: return
|
||||||
tc = tc.next
|
tc = tc.next
|
||||||
result = b
|
result = b
|
||||||
|
|
||||||
proc transformSym(c: PTransf, n: PNode): PTransNode =
|
proc transformSym(c: PTransf, n: PNode): PTransNode =
|
||||||
result = PTransNode(transformSymAux(c, n))
|
result = PTransNode(transformSymAux(c, n))
|
||||||
|
|
||||||
proc transformVarSection(c: PTransf, v: PNode): PTransNode =
|
proc transformVarSection(c: PTransf, v: PNode): PTransNode =
|
||||||
result = newTransNode(v)
|
result = newTransNode(v)
|
||||||
for i in countup(0, sonsLen(v)-1):
|
for i in countup(0, sonsLen(v)-1):
|
||||||
var it = v.sons[i]
|
var it = v.sons[i]
|
||||||
if it.kind == nkCommentStmt:
|
if it.kind == nkCommentStmt:
|
||||||
result[i] = PTransNode(it)
|
result[i] = PTransNode(it)
|
||||||
elif it.kind == nkIdentDefs:
|
elif it.kind == nkIdentDefs:
|
||||||
if it.sons[0].kind != nkSym: internalError(it.info, "transformVarSection")
|
if it.sons[0].kind != nkSym: internalError(it.info, "transformVarSection")
|
||||||
internalAssert(it.len == 3)
|
internalAssert(it.len == 3)
|
||||||
var newVar = copySym(it.sons[0].sym)
|
var newVar = copySym(it.sons[0].sym)
|
||||||
|
|
@ -153,12 +153,12 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode =
|
||||||
defs[1] = it.sons[1].PTransNode
|
defs[1] = it.sons[1].PTransNode
|
||||||
defs[2] = transform(c, it.sons[2])
|
defs[2] = transform(c, it.sons[2])
|
||||||
result[i] = defs
|
result[i] = defs
|
||||||
else:
|
else:
|
||||||
if it.kind != nkVarTuple:
|
if it.kind != nkVarTuple:
|
||||||
internalError(it.info, "transformVarSection: not nkVarTuple")
|
internalError(it.info, "transformVarSection: not nkVarTuple")
|
||||||
var L = sonsLen(it)
|
var L = sonsLen(it)
|
||||||
var defs = newTransNode(it.kind, it.info, L)
|
var defs = newTransNode(it.kind, it.info, L)
|
||||||
for j in countup(0, L-3):
|
for j in countup(0, L-3):
|
||||||
var newVar = copySym(it.sons[j].sym)
|
var newVar = copySym(it.sons[j].sym)
|
||||||
incl(newVar.flags, sfFromGeneric)
|
incl(newVar.flags, sfFromGeneric)
|
||||||
newVar.owner = getCurrOwner(c)
|
newVar.owner = getCurrOwner(c)
|
||||||
|
|
@ -188,12 +188,12 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode =
|
||||||
else:
|
else:
|
||||||
result[i] = PTransNode(it)
|
result[i] = PTransNode(it)
|
||||||
|
|
||||||
proc hasContinue(n: PNode): bool =
|
proc hasContinue(n: PNode): bool =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: discard
|
of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: discard
|
||||||
of nkContinueStmt: result = true
|
of nkContinueStmt: result = true
|
||||||
else:
|
else:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
if hasContinue(n.sons[i]): return true
|
if hasContinue(n.sons[i]): return true
|
||||||
|
|
||||||
proc newLabel(c: PTransf, n: PNode): PSym =
|
proc newLabel(c: PTransf, n: PNode): PSym =
|
||||||
|
|
@ -224,10 +224,10 @@ proc transformBlock(c: PTransf, n: PNode): PTransNode =
|
||||||
discard c.breakSyms.pop
|
discard c.breakSyms.pop
|
||||||
result[0] = newSymNode(labl).PTransNode
|
result[0] = newSymNode(labl).PTransNode
|
||||||
|
|
||||||
proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
||||||
# What if it contains "continue" and "break"? "break" needs
|
# What if it contains "continue" and "break"? "break" needs
|
||||||
# an explicit label too, but not the same!
|
# an explicit label too, but not the same!
|
||||||
|
|
||||||
# We fix this here by making every 'break' belong to its enclosing loop
|
# We fix this here by making every 'break' belong to its enclosing loop
|
||||||
# and changing all breaks that belong to a 'block' by annotating it with
|
# and changing all breaks that belong to a 'block' by annotating it with
|
||||||
# a label (if it hasn't one already).
|
# a label (if it hasn't one already).
|
||||||
|
|
@ -239,7 +239,7 @@ proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
||||||
result[0] = newSymNode(labl).PTransNode
|
result[0] = newSymNode(labl).PTransNode
|
||||||
result[1] = transform(c, n)
|
result[1] = transform(c, n)
|
||||||
discard c.contSyms.pop()
|
discard c.contSyms.pop()
|
||||||
else:
|
else:
|
||||||
result = transform(c, n)
|
result = transform(c, n)
|
||||||
|
|
||||||
proc transformWhile(c: PTransf; n: PNode): PTransNode =
|
proc transformWhile(c: PTransf; n: PNode): PTransNode =
|
||||||
|
|
@ -273,27 +273,27 @@ proc transformBreak(c: PTransf, n: PNode): PTransNode =
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
result[0] = newSymNode(labl).PTransNode
|
result[0] = newSymNode(labl).PTransNode
|
||||||
|
|
||||||
proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
|
proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
|
||||||
# XXX: BUG: what if `n` is an expression with side-effects?
|
# XXX: BUG: what if `n` is an expression with side-effects?
|
||||||
for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
|
for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
|
||||||
add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
||||||
transform(c, newTupleAccess(n, i))))
|
transform(c, newTupleAccess(n, i))))
|
||||||
|
|
||||||
proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
|
proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
result = transformSym(c, n)
|
result = transformSym(c, n)
|
||||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||||
# nothing to be done for leaves:
|
# nothing to be done for leaves:
|
||||||
result = PTransNode(n)
|
result = PTransNode(n)
|
||||||
of nkVarSection, nkLetSection:
|
of nkVarSection, nkLetSection:
|
||||||
result = transformVarSection(c, n)
|
result = transformVarSection(c, n)
|
||||||
else:
|
else:
|
||||||
result = newTransNode(n)
|
result = newTransNode(n)
|
||||||
for i in countup(0, sonsLen(n)-1):
|
for i in countup(0, sonsLen(n)-1):
|
||||||
result[i] = introduceNewLocalVars(c, n.sons[i])
|
result[i] = introduceNewLocalVars(c, n.sons[i])
|
||||||
|
|
||||||
proc transformYield(c: PTransf, n: PNode): PTransNode =
|
proc transformYield(c: PTransf, n: PNode): PTransNode =
|
||||||
result = newTransNode(nkStmtList, n.info, 0)
|
result = newTransNode(nkStmtList, n.info, 0)
|
||||||
var e = n.sons[0]
|
var e = n.sons[0]
|
||||||
# c.transCon.forStmt.len == 3 means that there is one for loop variable
|
# c.transCon.forStmt.len == 3 means that there is one for loop variable
|
||||||
|
|
@ -301,21 +301,21 @@ proc transformYield(c: PTransf, n: PNode): PTransNode =
|
||||||
if skipTypes(e.typ, {tyGenericInst}).kind == tyTuple and
|
if skipTypes(e.typ, {tyGenericInst}).kind == tyTuple and
|
||||||
c.transCon.forStmt.len != 3:
|
c.transCon.forStmt.len != 3:
|
||||||
e = skipConv(e)
|
e = skipConv(e)
|
||||||
if e.kind == nkPar:
|
if e.kind == nkPar:
|
||||||
for i in countup(0, sonsLen(e) - 1):
|
for i in countup(0, sonsLen(e) - 1):
|
||||||
add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
||||||
transform(c, e.sons[i])))
|
transform(c, e.sons[i])))
|
||||||
else:
|
else:
|
||||||
unpackTuple(c, e, result)
|
unpackTuple(c, e, result)
|
||||||
else:
|
else:
|
||||||
var x = transform(c, e)
|
var x = transform(c, e)
|
||||||
add(result, newAsgnStmt(c, c.transCon.forStmt.sons[0], x))
|
add(result, newAsgnStmt(c, c.transCon.forStmt.sons[0], x))
|
||||||
|
|
||||||
inc(c.transCon.yieldStmts)
|
inc(c.transCon.yieldStmts)
|
||||||
if c.transCon.yieldStmts <= 1:
|
if c.transCon.yieldStmts <= 1:
|
||||||
# common case
|
# common case
|
||||||
add(result, c.transCon.forLoopBody)
|
add(result, c.transCon.forLoopBody)
|
||||||
else:
|
else:
|
||||||
# we need to introduce new local variables:
|
# we need to introduce new local variables:
|
||||||
add(result, introduceNewLocalVars(c, c.transCon.forLoopBody.PNode))
|
add(result, introduceNewLocalVars(c, c.transCon.forLoopBody.PNode))
|
||||||
|
|
||||||
|
|
@ -340,25 +340,25 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
|
||||||
if n.sons[0].kind == a or n.sons[0].kind == b:
|
if n.sons[0].kind == a or n.sons[0].kind == b:
|
||||||
# addr ( deref ( x )) --> x
|
# addr ( deref ( x )) --> x
|
||||||
result = PTransNode(n.sons[0].sons[0])
|
result = PTransNode(n.sons[0].sons[0])
|
||||||
|
|
||||||
proc transformConv(c: PTransf, n: PNode): PTransNode =
|
proc transformConv(c: PTransf, n: PNode): PTransNode =
|
||||||
# numeric types need range checks:
|
# numeric types need range checks:
|
||||||
var dest = skipTypes(n.typ, abstractVarRange)
|
var dest = skipTypes(n.typ, abstractVarRange)
|
||||||
var source = skipTypes(n.sons[1].typ, abstractVarRange)
|
var source = skipTypes(n.sons[1].typ, abstractVarRange)
|
||||||
case dest.kind
|
case dest.kind
|
||||||
of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32:
|
of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32:
|
||||||
# we don't include uint and uint64 here as these are no ordinal types ;-)
|
# we don't include uint and uint64 here as these are no ordinal types ;-)
|
||||||
if not isOrdinalType(source):
|
if not isOrdinalType(source):
|
||||||
# float -> int conversions. ugh.
|
# float -> int conversions. ugh.
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
elif firstOrd(n.typ) <= firstOrd(n.sons[1].typ) and
|
elif firstOrd(n.typ) <= firstOrd(n.sons[1].typ) and
|
||||||
lastOrd(n.sons[1].typ) <= lastOrd(n.typ):
|
lastOrd(n.sons[1].typ) <= lastOrd(n.typ):
|
||||||
# BUGFIX: simply leave n as it is; we need a nkConv node,
|
# BUGFIX: simply leave n as it is; we need a nkConv node,
|
||||||
# but no range check:
|
# but no range check:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
else:
|
else:
|
||||||
# generate a range check:
|
# generate a range check:
|
||||||
if dest.kind == tyInt64 or source.kind == tyInt64:
|
if dest.kind == tyInt64 or source.kind == tyInt64:
|
||||||
result = newTransNode(nkChckRange64, n, 3)
|
result = newTransNode(nkChckRange64, n, 3)
|
||||||
else:
|
else:
|
||||||
result = newTransNode(nkChckRange, n, 3)
|
result = newTransNode(nkChckRange, n, 3)
|
||||||
|
|
@ -368,7 +368,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
|
||||||
result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
|
result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
|
||||||
of tyFloat..tyFloat128:
|
of tyFloat..tyFloat128:
|
||||||
# XXX int64 -> float conversion?
|
# XXX int64 -> float conversion?
|
||||||
if skipTypes(n.typ, abstractVar).kind == tyRange:
|
if skipTypes(n.typ, abstractVar).kind == tyRange:
|
||||||
result = newTransNode(nkChckRangeF, n, 3)
|
result = newTransNode(nkChckRangeF, n, 3)
|
||||||
dest = skipTypes(n.typ, abstractVar)
|
dest = skipTypes(n.typ, abstractVar)
|
||||||
result[0] = transform(c, n.sons[1])
|
result[0] = transform(c, n.sons[1])
|
||||||
|
|
@ -378,81 +378,81 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
result = transform(c, n.sons[1])
|
result = transform(c, n.sons[1])
|
||||||
of tyCString:
|
of tyCString:
|
||||||
if source.kind == tyString:
|
if source.kind == tyString:
|
||||||
result = newTransNode(nkStringToCString, n, 1)
|
result = newTransNode(nkStringToCString, n, 1)
|
||||||
result[0] = transform(c, n.sons[1])
|
result[0] = transform(c, n.sons[1])
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
of tyString:
|
of tyString:
|
||||||
if source.kind == tyCString:
|
if source.kind == tyCString:
|
||||||
result = newTransNode(nkCStringToString, n, 1)
|
result = newTransNode(nkCStringToString, n, 1)
|
||||||
result[0] = transform(c, n.sons[1])
|
result[0] = transform(c, n.sons[1])
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
of tyRef, tyPtr:
|
of tyRef, tyPtr:
|
||||||
dest = skipTypes(dest, abstractPtrs)
|
dest = skipTypes(dest, abstractPtrs)
|
||||||
source = skipTypes(source, abstractPtrs)
|
source = skipTypes(source, abstractPtrs)
|
||||||
if source.kind == tyObject:
|
if source.kind == tyObject:
|
||||||
var diff = inheritanceDiff(dest, source)
|
var diff = inheritanceDiff(dest, source)
|
||||||
if diff < 0:
|
if diff < 0:
|
||||||
result = newTransNode(nkObjUpConv, n, 1)
|
result = newTransNode(nkObjUpConv, n, 1)
|
||||||
result[0] = transform(c, n.sons[1])
|
result[0] = transform(c, n.sons[1])
|
||||||
elif diff > 0:
|
elif diff > 0:
|
||||||
result = newTransNode(nkObjDownConv, n, 1)
|
result = newTransNode(nkObjDownConv, n, 1)
|
||||||
result[0] = transform(c, n.sons[1])
|
result[0] = transform(c, n.sons[1])
|
||||||
else:
|
else:
|
||||||
result = transform(c, n.sons[1])
|
result = transform(c, n.sons[1])
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
of tyObject:
|
of tyObject:
|
||||||
var diff = inheritanceDiff(dest, source)
|
var diff = inheritanceDiff(dest, source)
|
||||||
if diff < 0:
|
if diff < 0:
|
||||||
result = newTransNode(nkObjUpConv, n, 1)
|
result = newTransNode(nkObjUpConv, n, 1)
|
||||||
result[0] = transform(c, n.sons[1])
|
result[0] = transform(c, n.sons[1])
|
||||||
elif diff > 0:
|
elif diff > 0:
|
||||||
result = newTransNode(nkObjDownConv, n, 1)
|
result = newTransNode(nkObjDownConv, n, 1)
|
||||||
result[0] = transform(c, n.sons[1])
|
result[0] = transform(c, n.sons[1])
|
||||||
else:
|
else:
|
||||||
result = transform(c, n.sons[1])
|
result = transform(c, n.sons[1])
|
||||||
of tyGenericParam, tyOrdinal:
|
of tyGenericParam, tyOrdinal:
|
||||||
result = transform(c, n.sons[1])
|
result = transform(c, n.sons[1])
|
||||||
# happens sometimes for generated assignments, etc.
|
# happens sometimes for generated assignments, etc.
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
|
|
||||||
type
|
type
|
||||||
TPutArgInto = enum
|
TPutArgInto = enum
|
||||||
paDirectMapping, paFastAsgn, paVarAsgn
|
paDirectMapping, paFastAsgn, paVarAsgn
|
||||||
|
|
||||||
proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
|
proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
|
||||||
# This analyses how to treat the mapping "formal <-> arg" in an
|
# This analyses how to treat the mapping "formal <-> arg" in an
|
||||||
# inline context.
|
# inline context.
|
||||||
if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
|
if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
|
||||||
return paDirectMapping # XXX really correct?
|
return paDirectMapping # XXX really correct?
|
||||||
# what if ``arg`` has side-effects?
|
# what if ``arg`` has side-effects?
|
||||||
case arg.kind
|
case arg.kind
|
||||||
of nkEmpty..nkNilLit:
|
of nkEmpty..nkNilLit:
|
||||||
result = paDirectMapping
|
result = paDirectMapping
|
||||||
of nkPar, nkCurly, nkBracket:
|
of nkPar, nkCurly, nkBracket:
|
||||||
result = paFastAsgn
|
result = paFastAsgn
|
||||||
for i in countup(0, sonsLen(arg) - 1):
|
for i in countup(0, sonsLen(arg) - 1):
|
||||||
if putArgInto(arg.sons[i], formal) != paDirectMapping: return
|
if putArgInto(arg.sons[i], formal) != paDirectMapping: return
|
||||||
result = paDirectMapping
|
result = paDirectMapping
|
||||||
else:
|
else:
|
||||||
if skipTypes(formal, abstractInst).kind == tyVar: result = paVarAsgn
|
if skipTypes(formal, abstractInst).kind == tyVar: result = paVarAsgn
|
||||||
else: result = paFastAsgn
|
else: result = paFastAsgn
|
||||||
|
|
||||||
proc findWrongOwners(c: PTransf, n: PNode) =
|
proc findWrongOwners(c: PTransf, n: PNode) =
|
||||||
if n.kind == nkVarSection:
|
if n.kind == nkVarSection:
|
||||||
let x = n.sons[0].sons[0]
|
let x = n.sons[0].sons[0]
|
||||||
if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
|
if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
|
||||||
internalError(x.info, "bah " & x.sym.name.s & " " &
|
internalError(x.info, "bah " & x.sym.name.s & " " &
|
||||||
x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
|
x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
|
||||||
else:
|
else:
|
||||||
for i in 0 .. <safeLen(n): findWrongOwners(c, n.sons[i])
|
for i in 0 .. <safeLen(n): findWrongOwners(c, n.sons[i])
|
||||||
|
|
||||||
proc transformFor(c: PTransf, n: PNode): PTransNode =
|
proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
# generate access statements for the parameters (unless they are constant)
|
# generate access statements for the parameters (unless they are constant)
|
||||||
# put mapping from formal parameters to actual parameters
|
# put mapping from formal parameters to actual parameters
|
||||||
if n.kind != nkForStmt: internalError(n.info, "transformFor")
|
if n.kind != nkForStmt: internalError(n.info, "transformFor")
|
||||||
|
|
@ -466,26 +466,26 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
result[0] = newSymNode(labl).PTransNode
|
result[0] = newSymNode(labl).PTransNode
|
||||||
|
|
||||||
if call.typ.kind != tyIter and
|
if call.typ.kind != tyIter and
|
||||||
(call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
|
(call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
|
||||||
call.sons[0].sym.kind != skIterator):
|
call.sons[0].sym.kind != skIterator):
|
||||||
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
|
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
|
||||||
result[1] = lambdalifting.liftForLoop(n).PTransNode
|
result[1] = lambdalifting.liftForLoop(n).PTransNode
|
||||||
discard c.breakSyms.pop
|
discard c.breakSyms.pop
|
||||||
return result
|
return result
|
||||||
|
|
||||||
#echo "transforming: ", renderTree(n)
|
#echo "transforming: ", renderTree(n)
|
||||||
var stmtList = newTransNode(nkStmtList, n.info, 0)
|
var stmtList = newTransNode(nkStmtList, n.info, 0)
|
||||||
|
|
||||||
var loopBody = transformLoopBody(c, n.sons[length-1])
|
var loopBody = transformLoopBody(c, n.sons[length-1])
|
||||||
|
|
||||||
result[1] = stmtList
|
result[1] = stmtList
|
||||||
discard c.breakSyms.pop
|
discard c.breakSyms.pop
|
||||||
|
|
||||||
var v = newNodeI(nkVarSection, n.info)
|
var v = newNodeI(nkVarSection, n.info)
|
||||||
for i in countup(0, length - 3):
|
for i in countup(0, length - 3):
|
||||||
addVar(v, copyTree(n.sons[i])) # declare new vars
|
addVar(v, copyTree(n.sons[i])) # declare new vars
|
||||||
add(stmtList, v.PTransNode)
|
add(stmtList, v.PTransNode)
|
||||||
|
|
||||||
# Bugfix: inlined locals belong to the invoking routine, not to the invoked
|
# Bugfix: inlined locals belong to the invoking routine, not to the invoked
|
||||||
# iterator!
|
# iterator!
|
||||||
let iter = call.sons[0].sym
|
let iter = call.sons[0].sym
|
||||||
|
|
@ -496,9 +496,9 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
if iter.kind != skIterator: return result
|
if iter.kind != skIterator: return result
|
||||||
# generate access statements for the parameters (unless they are constant)
|
# generate access statements for the parameters (unless they are constant)
|
||||||
pushTransCon(c, newC)
|
pushTransCon(c, newC)
|
||||||
for i in countup(1, sonsLen(call) - 1):
|
for i in countup(1, sonsLen(call) - 1):
|
||||||
var arg = transform(c, call.sons[i]).PNode
|
var arg = transform(c, call.sons[i]).PNode
|
||||||
var formal = skipTypes(iter.typ, abstractInst).n.sons[i].sym
|
var formal = skipTypes(iter.typ, abstractInst).n.sons[i].sym
|
||||||
if arg.typ.kind == tyIter: continue
|
if arg.typ.kind == tyIter: continue
|
||||||
case putArgInto(arg, formal.typ)
|
case putArgInto(arg, formal.typ)
|
||||||
of paDirectMapping:
|
of paDirectMapping:
|
||||||
|
|
@ -527,20 +527,20 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
popTransCon(c)
|
popTransCon(c)
|
||||||
# echo "transformed: ", stmtList.PNode.renderTree
|
# echo "transformed: ", stmtList.PNode.renderTree
|
||||||
|
|
||||||
proc getMagicOp(call: PNode): TMagic =
|
proc getMagicOp(call: PNode): TMagic =
|
||||||
if call.sons[0].kind == nkSym and
|
if call.sons[0].kind == nkSym and
|
||||||
call.sons[0].sym.kind in {skProc, skMethod, skConverter}:
|
call.sons[0].sym.kind in {skProc, skMethod, skConverter}:
|
||||||
result = call.sons[0].sym.magic
|
result = call.sons[0].sym.magic
|
||||||
else:
|
else:
|
||||||
result = mNone
|
result = mNone
|
||||||
|
|
||||||
proc transformCase(c: PTransf, n: PNode): PTransNode =
|
proc transformCase(c: PTransf, n: PNode): PTransNode =
|
||||||
# removes `elif` branches of a case stmt
|
# removes `elif` branches of a case stmt
|
||||||
# adds ``else: nil`` if needed for the code generator
|
# adds ``else: nil`` if needed for the code generator
|
||||||
result = newTransNode(nkCaseStmt, n, 0)
|
result = newTransNode(nkCaseStmt, n, 0)
|
||||||
var ifs = PTransNode(nil)
|
var ifs = PTransNode(nil)
|
||||||
for i in 0 .. sonsLen(n)-1:
|
for i in 0 .. sonsLen(n)-1:
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
var e = transform(c, it)
|
var e = transform(c, it)
|
||||||
case it.kind
|
case it.kind
|
||||||
|
|
@ -564,8 +564,8 @@ proc transformCase(c: PTransf, n: PNode): PTransNode =
|
||||||
var elseBranch = newTransNode(nkElse, n.info, 1)
|
var elseBranch = newTransNode(nkElse, n.info, 1)
|
||||||
elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
|
elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
|
||||||
add(result, elseBranch)
|
add(result, elseBranch)
|
||||||
|
|
||||||
proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
|
proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
|
||||||
# XXX this is really bad; transf should use a proper AST visitor
|
# XXX this is really bad; transf should use a proper AST visitor
|
||||||
if n.sons[0].kind == nkSym and n.sons[0].sym.kind == skType:
|
if n.sons[0].kind == nkSym and n.sons[0].sym.kind == skType:
|
||||||
result = n.PTransNode
|
result = n.PTransNode
|
||||||
|
|
@ -573,45 +573,45 @@ proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
|
||||||
result = newTransNode(n)
|
result = newTransNode(n)
|
||||||
for i in 0 .. < n.len:
|
for i in 0 .. < n.len:
|
||||||
result[i] = transform(c, skipConv(n.sons[i]))
|
result[i] = transform(c, skipConv(n.sons[i]))
|
||||||
|
|
||||||
proc getMergeOp(n: PNode): PSym =
|
proc getMergeOp(n: PNode): PSym =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
||||||
nkCallStrLit:
|
nkCallStrLit:
|
||||||
if (n.sons[0].kind == nkSym) and (n.sons[0].sym.kind == skProc) and
|
if (n.sons[0].kind == nkSym) and (n.sons[0].sym.kind == skProc) and
|
||||||
(sfMerge in n.sons[0].sym.flags):
|
(sfMerge in n.sons[0].sym.flags):
|
||||||
result = n.sons[0].sym
|
result = n.sons[0].sym
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc flattenTreeAux(d, a: PNode, op: PSym) =
|
proc flattenTreeAux(d, a: PNode, op: PSym) =
|
||||||
let op2 = getMergeOp(a)
|
let op2 = getMergeOp(a)
|
||||||
if op2 != nil and
|
if op2 != nil and
|
||||||
(op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
|
(op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
|
||||||
for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op)
|
for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op)
|
||||||
else:
|
else:
|
||||||
addSon(d, copyTree(a))
|
addSon(d, copyTree(a))
|
||||||
|
|
||||||
proc flattenTree(root: PNode): PNode =
|
proc flattenTree(root: PNode): PNode =
|
||||||
let op = getMergeOp(root)
|
let op = getMergeOp(root)
|
||||||
if op != nil:
|
if op != nil:
|
||||||
result = copyNode(root)
|
result = copyNode(root)
|
||||||
addSon(result, copyTree(root.sons[0]))
|
addSon(result, copyTree(root.sons[0]))
|
||||||
flattenTreeAux(result, root, op)
|
flattenTreeAux(result, root, op)
|
||||||
else:
|
else:
|
||||||
result = root
|
result = root
|
||||||
|
|
||||||
proc transformCall(c: PTransf, n: PNode): PTransNode =
|
proc transformCall(c: PTransf, n: PNode): PTransNode =
|
||||||
var n = flattenTree(n)
|
var n = flattenTree(n)
|
||||||
let op = getMergeOp(n)
|
let op = getMergeOp(n)
|
||||||
let magic = getMagic(n)
|
let magic = getMagic(n)
|
||||||
if op != nil and op.magic != mNone and n.len >= 3:
|
if op != nil and op.magic != mNone and n.len >= 3:
|
||||||
result = newTransNode(nkCall, n, 0)
|
result = newTransNode(nkCall, n, 0)
|
||||||
add(result, transform(c, n.sons[0]))
|
add(result, transform(c, n.sons[0]))
|
||||||
var j = 1
|
var j = 1
|
||||||
while j < sonsLen(n):
|
while j < sonsLen(n):
|
||||||
var a = transform(c, n.sons[j]).PNode
|
var a = transform(c, n.sons[j]).PNode
|
||||||
inc(j)
|
inc(j)
|
||||||
if isConstExpr(a):
|
if isConstExpr(a):
|
||||||
while (j < sonsLen(n)):
|
while (j < sonsLen(n)):
|
||||||
let b = transform(c, n.sons[j]).PNode
|
let b = transform(c, n.sons[j]).PNode
|
||||||
if not isConstExpr(b): break
|
if not isConstExpr(b): break
|
||||||
|
|
@ -640,7 +640,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
|
||||||
proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
|
proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
|
||||||
# symbols that expand to a complex constant (array, etc.) should not be
|
# symbols that expand to a complex constant (array, etc.) should not be
|
||||||
# inlined, unless it's the empty array:
|
# inlined, unless it's the empty array:
|
||||||
result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkBracket} and
|
result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkBracket} and
|
||||||
cnst.len != 0
|
cnst.len != 0
|
||||||
|
|
||||||
proc commonOptimizations*(c: PSym, n: PNode): PNode =
|
proc commonOptimizations*(c: PSym, n: PNode): PNode =
|
||||||
|
|
@ -673,11 +673,11 @@ proc commonOptimizations*(c: PSym, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
proc transform(c: PTransf, n: PNode): PTransNode =
|
proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
result = transformSym(c, n)
|
result = transformSym(c, n)
|
||||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||||
# nothing to be done for leaves:
|
# nothing to be done for leaves:
|
||||||
result = PTransNode(n)
|
result = PTransNode(n)
|
||||||
of nkBracketExpr: result = transformArrayAccess(c, n)
|
of nkBracketExpr: result = transformArrayAccess(c, n)
|
||||||
|
|
@ -702,7 +702,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
n.sons[bodyPos] = PNode(transform(c, s.getBody))
|
n.sons[bodyPos] = PNode(transform(c, s.getBody))
|
||||||
if n.kind == nkMethodDef: methodDef(s, false)
|
if n.kind == nkMethodDef: methodDef(s, false)
|
||||||
result = PTransNode(n)
|
result = PTransNode(n)
|
||||||
of nkForStmt:
|
of nkForStmt:
|
||||||
result = transformFor(c, n)
|
result = transformFor(c, n)
|
||||||
of nkParForStmt:
|
of nkParForStmt:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
|
|
@ -713,14 +713,14 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
add(result, PTransNode(newSymNode(labl)))
|
add(result, PTransNode(newSymNode(labl)))
|
||||||
of nkBreakStmt: result = transformBreak(c, n)
|
of nkBreakStmt: result = transformBreak(c, n)
|
||||||
of nkWhileStmt: result = transformWhile(c, n)
|
of nkWhileStmt: result = transformWhile(c, n)
|
||||||
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
||||||
nkCallStrLit:
|
nkCallStrLit:
|
||||||
result = transformCall(c, n)
|
result = transformCall(c, n)
|
||||||
of nkAddr, nkHiddenAddr:
|
of nkAddr, nkHiddenAddr:
|
||||||
result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
|
result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
|
||||||
of nkDerefExpr, nkHiddenDeref:
|
of nkDerefExpr, nkHiddenDeref:
|
||||||
result = transformAddrDeref(c, n, nkAddr, nkHiddenAddr)
|
result = transformAddrDeref(c, n, nkAddr, nkHiddenAddr)
|
||||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||||
result = transformConv(c, n)
|
result = transformConv(c, n)
|
||||||
of nkDiscardStmt:
|
of nkDiscardStmt:
|
||||||
result = PTransNode(n)
|
result = PTransNode(n)
|
||||||
|
|
@ -730,7 +730,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
# ensure that e.g. discard "some comment" gets optimized away
|
# ensure that e.g. discard "some comment" gets optimized away
|
||||||
# completely:
|
# completely:
|
||||||
result = PTransNode(newNode(nkCommentStmt))
|
result = PTransNode(newNode(nkCommentStmt))
|
||||||
of nkCommentStmt, nkTemplateDef:
|
of nkCommentStmt, nkTemplateDef:
|
||||||
return n.PTransNode
|
return n.PTransNode
|
||||||
of nkConstSection:
|
of nkConstSection:
|
||||||
# do not replace ``const c = 3`` with ``const 3 = 3``
|
# do not replace ``const c = 3`` with ``const 3 = 3``
|
||||||
|
|
@ -744,10 +744,10 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
result = transformVarSection(c, n)
|
result = transformVarSection(c, n)
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
of nkYieldStmt:
|
of nkYieldStmt:
|
||||||
if c.inlining > 0:
|
if c.inlining > 0:
|
||||||
result = transformYield(c, n)
|
result = transformYield(c, n)
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
of nkBlockStmt, nkBlockExpr:
|
of nkBlockStmt, nkBlockExpr:
|
||||||
result = transformBlock(c, n)
|
result = transformBlock(c, n)
|
||||||
|
|
@ -764,7 +764,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
if cnst != nil and not dontInlineConstant(n, cnst):
|
if cnst != nil and not dontInlineConstant(n, cnst):
|
||||||
result = PTransNode(cnst) # do not miss an optimization
|
result = PTransNode(cnst) # do not miss an optimization
|
||||||
|
|
||||||
proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
|
proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
|
||||||
# Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
|
# Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
|
||||||
# this step! We have to rely that the semantic pass transforms too errornous
|
# this step! We have to rely that the semantic pass transforms too errornous
|
||||||
# nodes into an empty node.
|
# nodes into an empty node.
|
||||||
|
|
@ -774,7 +774,7 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
|
||||||
popTransCon(c)
|
popTransCon(c)
|
||||||
incl(result.flags, nfTransf)
|
incl(result.flags, nfTransf)
|
||||||
|
|
||||||
proc openTransf(module: PSym, filename: string): PTransf =
|
proc openTransf(module: PSym, filename: string): PTransf =
|
||||||
new(result)
|
new(result)
|
||||||
result.contSyms = @[]
|
result.contSyms = @[]
|
||||||
result.breakSyms = @[]
|
result.breakSyms = @[]
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -68,7 +68,6 @@ proc renderType(n: PNode): string =
|
||||||
assert n[i].kind == nkIdent
|
assert n[i].kind == nkIdent
|
||||||
result.add(',' & typeStr)
|
result.add(',' & typeStr)
|
||||||
of nkTupleTy:
|
of nkTupleTy:
|
||||||
assert len(n) > 0
|
|
||||||
result = "tuple["
|
result = "tuple["
|
||||||
for i in 0 .. <len(n): result.add(renderType(n[i]) & ',')
|
for i in 0 .. <len(n): result.add(renderType(n[i]) & ',')
|
||||||
result[<len(result)] = ']'
|
result[<len(result)] = ']'
|
||||||
|
|
|
||||||
|
|
@ -239,7 +239,7 @@ proc pushSafePoint(f: PStackFrame; pc: int) =
|
||||||
|
|
||||||
proc popSafePoint(f: PStackFrame) = discard f.safePoints.pop()
|
proc popSafePoint(f: PStackFrame) = discard f.safePoints.pop()
|
||||||
|
|
||||||
proc cleanUpOnException(c: PCtx; tos: PStackFrame):
|
proc cleanUpOnException(c: PCtx; tos: PStackFrame):
|
||||||
tuple[pc: int, f: PStackFrame] =
|
tuple[pc: int, f: PStackFrame] =
|
||||||
let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs)
|
let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs)
|
||||||
var f = tos
|
var f = tos
|
||||||
|
|
@ -257,7 +257,7 @@ proc cleanUpOnException(c: PCtx; tos: PStackFrame):
|
||||||
let exceptType = c.types[c.code[pc2].regBx-wordExcess].skipTypes(
|
let exceptType = c.types[c.code[pc2].regBx-wordExcess].skipTypes(
|
||||||
abstractPtrs)
|
abstractPtrs)
|
||||||
if inheritanceDiff(exceptType, raisedType) <= 0:
|
if inheritanceDiff(exceptType, raisedType) <= 0:
|
||||||
# mark exception as handled but keep it in B for
|
# mark exception as handled but keep it in B for
|
||||||
# the getCurrentException() builtin:
|
# the getCurrentException() builtin:
|
||||||
c.currentExceptionB = c.currentExceptionA
|
c.currentExceptionB = c.currentExceptionA
|
||||||
c.currentExceptionA = nil
|
c.currentExceptionA = nil
|
||||||
|
|
@ -349,14 +349,14 @@ proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
|
||||||
if dest.kind != rkFloat:
|
if dest.kind != rkFloat:
|
||||||
myreset(dest); dest.kind = rkFloat
|
myreset(dest); dest.kind = rkFloat
|
||||||
case skipTypes(srctyp, abstractRange).kind
|
case skipTypes(srctyp, abstractRange).kind
|
||||||
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyBool, tyChar:
|
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyBool, tyChar:
|
||||||
dest.floatVal = toFloat(src.intVal.int)
|
dest.floatVal = toFloat(src.intVal.int)
|
||||||
else:
|
else:
|
||||||
dest.floatVal = src.floatVal
|
dest.floatVal = src.floatVal
|
||||||
else:
|
else:
|
||||||
asgnComplex(dest, src)
|
asgnComplex(dest, src)
|
||||||
|
|
||||||
proc compile(c: PCtx, s: PSym): int =
|
proc compile(c: PCtx, s: PSym): int =
|
||||||
result = vmgen.genProc(c, s)
|
result = vmgen.genProc(c, s)
|
||||||
when debugEchoCode: c.echoCode result
|
when debugEchoCode: c.echoCode result
|
||||||
#c.echoCode
|
#c.echoCode
|
||||||
|
|
@ -396,10 +396,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
pc = tos.comesFrom
|
pc = tos.comesFrom
|
||||||
tos = tos.next
|
tos = tos.next
|
||||||
let retVal = regs[0]
|
let retVal = regs[0]
|
||||||
if tos.isNil:
|
if tos.isNil:
|
||||||
#echo "RET ", retVal.rendertree
|
#echo "RET ", retVal.rendertree
|
||||||
return retVal
|
return retVal
|
||||||
|
|
||||||
move(regs, tos.slots)
|
move(regs, tos.slots)
|
||||||
assert c.code[pc].opcode in {opcIndCall, opcIndCallAsgn}
|
assert c.code[pc].opcode in {opcIndCall, opcIndCallAsgn}
|
||||||
if c.code[pc].opcode == opcIndCallAsgn:
|
if c.code[pc].opcode == opcIndCallAsgn:
|
||||||
|
|
@ -653,7 +653,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
of opcSubu:
|
of opcSubu:
|
||||||
decodeBC(rkInt)
|
decodeBC(rkInt)
|
||||||
regs[ra].intVal = regs[rb].intVal -% regs[rc].intVal
|
regs[ra].intVal = regs[rb].intVal -% regs[rc].intVal
|
||||||
of opcMulu:
|
of opcMulu:
|
||||||
decodeBC(rkInt)
|
decodeBC(rkInt)
|
||||||
regs[ra].intVal = regs[rb].intVal *% regs[rc].intVal
|
regs[ra].intVal = regs[rb].intVal *% regs[rc].intVal
|
||||||
of opcDivu:
|
of opcDivu:
|
||||||
|
|
@ -726,7 +726,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
of opcLeSet:
|
of opcLeSet:
|
||||||
decodeBC(rkInt)
|
decodeBC(rkInt)
|
||||||
regs[ra].intVal = ord(containsSets(regs[rb].node, regs[rc].node))
|
regs[ra].intVal = ord(containsSets(regs[rb].node, regs[rc].node))
|
||||||
of opcEqSet:
|
of opcEqSet:
|
||||||
decodeBC(rkInt)
|
decodeBC(rkInt)
|
||||||
regs[ra].intVal = ord(equalSets(regs[rb].node, regs[rc].node))
|
regs[ra].intVal = ord(equalSets(regs[rb].node, regs[rc].node))
|
||||||
of opcLtSet:
|
of opcLtSet:
|
||||||
|
|
@ -737,9 +737,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
of opcMulSet:
|
of opcMulSet:
|
||||||
decodeBC(rkNode)
|
decodeBC(rkNode)
|
||||||
createSet(regs[ra])
|
createSet(regs[ra])
|
||||||
move(regs[ra].node.sons,
|
move(regs[ra].node.sons,
|
||||||
nimsets.intersectSets(regs[rb].node, regs[rc].node).sons)
|
nimsets.intersectSets(regs[rb].node, regs[rc].node).sons)
|
||||||
of opcPlusSet:
|
of opcPlusSet:
|
||||||
decodeBC(rkNode)
|
decodeBC(rkNode)
|
||||||
createSet(regs[ra])
|
createSet(regs[ra])
|
||||||
move(regs[ra].node.sons,
|
move(regs[ra].node.sons,
|
||||||
|
|
@ -753,7 +753,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
decodeBC(rkNode)
|
decodeBC(rkNode)
|
||||||
createSet(regs[ra])
|
createSet(regs[ra])
|
||||||
move(regs[ra].node.sons,
|
move(regs[ra].node.sons,
|
||||||
nimsets.symdiffSets(regs[rb].node, regs[rc].node).sons)
|
nimsets.symdiffSets(regs[rb].node, regs[rc].node).sons)
|
||||||
of opcConcatStr:
|
of opcConcatStr:
|
||||||
decodeBC(rkNode)
|
decodeBC(rkNode)
|
||||||
createStr regs[ra]
|
createStr regs[ra]
|
||||||
|
|
@ -793,7 +793,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
assert c.code[pc].opcode == opcSubStr
|
assert c.code[pc].opcode == opcSubStr
|
||||||
let rd = c.code[pc].regA
|
let rd = c.code[pc].regA
|
||||||
createStr regs[ra]
|
createStr regs[ra]
|
||||||
regs[ra].node.strVal = substr(regs[rb].node.strVal,
|
regs[ra].node.strVal = substr(regs[rb].node.strVal,
|
||||||
regs[rc].intVal.int, regs[rd].intVal.int)
|
regs[rc].intVal.int, regs[rd].intVal.int)
|
||||||
of opcParseFloat:
|
of opcParseFloat:
|
||||||
decodeBC(rkInt)
|
decodeBC(rkInt)
|
||||||
|
|
@ -896,12 +896,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
# we know the next instruction is a 'fjmp':
|
# we know the next instruction is a 'fjmp':
|
||||||
let branch = c.constants[instr.regBx-wordExcess]
|
let branch = c.constants[instr.regBx-wordExcess]
|
||||||
var cond = false
|
var cond = false
|
||||||
for j in countup(0, sonsLen(branch) - 2):
|
for j in countup(0, sonsLen(branch) - 2):
|
||||||
if overlap(regs[ra].regToNode, branch.sons[j]):
|
if overlap(regs[ra].regToNode, branch.sons[j]):
|
||||||
cond = true
|
cond = true
|
||||||
break
|
break
|
||||||
assert c.code[pc+1].opcode == opcFJmp
|
assert c.code[pc+1].opcode == opcFJmp
|
||||||
inc pc
|
inc pc
|
||||||
# we skip this instruction so that the final 'inc(pc)' skips
|
# we skip this instruction so that the final 'inc(pc)' skips
|
||||||
# the following jump
|
# the following jump
|
||||||
if not cond:
|
if not cond:
|
||||||
|
|
@ -1273,7 +1273,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
of opcNSetIntVal:
|
of opcNSetIntVal:
|
||||||
decodeB(rkNode)
|
decodeB(rkNode)
|
||||||
var dest = regs[ra].node
|
var dest = regs[ra].node
|
||||||
if dest.kind in {nkCharLit..nkInt64Lit} and
|
if dest.kind in {nkCharLit..nkInt64Lit} and
|
||||||
regs[rb].kind in {rkInt}:
|
regs[rb].kind in {rkInt}:
|
||||||
dest.intVal = regs[rb].intVal
|
dest.intVal = regs[rb].intVal
|
||||||
else:
|
else:
|
||||||
|
|
@ -1281,24 +1281,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
of opcNSetFloatVal:
|
of opcNSetFloatVal:
|
||||||
decodeB(rkNode)
|
decodeB(rkNode)
|
||||||
var dest = regs[ra].node
|
var dest = regs[ra].node
|
||||||
if dest.kind in {nkFloatLit..nkFloat64Lit} and
|
if dest.kind in {nkFloatLit..nkFloat64Lit} and
|
||||||
regs[rb].kind in {rkFloat}:
|
regs[rb].kind in {rkFloat}:
|
||||||
dest.floatVal = regs[rb].floatVal
|
dest.floatVal = regs[rb].floatVal
|
||||||
else:
|
else:
|
||||||
stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
|
stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
|
||||||
of opcNSetSymbol:
|
of opcNSetSymbol:
|
||||||
decodeB(rkNode)
|
decodeB(rkNode)
|
||||||
var dest = regs[ra].node
|
var dest = regs[ra].node
|
||||||
if dest.kind == nkSym and regs[rb].node.kind == nkSym:
|
if dest.kind == nkSym and regs[rb].node.kind == nkSym:
|
||||||
dest.sym = regs[rb].node.sym
|
dest.sym = regs[rb].node.sym
|
||||||
else:
|
else:
|
||||||
stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
|
stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
|
||||||
of opcNSetIdent:
|
of opcNSetIdent:
|
||||||
decodeB(rkNode)
|
decodeB(rkNode)
|
||||||
var dest = regs[ra].node
|
var dest = regs[ra].node
|
||||||
if dest.kind == nkIdent and regs[rb].node.kind == nkIdent:
|
if dest.kind == nkIdent and regs[rb].node.kind == nkIdent:
|
||||||
dest.ident = regs[rb].node.ident
|
dest.ident = regs[rb].node.ident
|
||||||
else:
|
else:
|
||||||
stackTrace(c, tos, pc, errFieldXNotFound, "ident")
|
stackTrace(c, tos, pc, errFieldXNotFound, "ident")
|
||||||
of opcNSetType:
|
of opcNSetType:
|
||||||
decodeB(rkNode)
|
decodeB(rkNode)
|
||||||
|
|
@ -1309,7 +1309,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
of opcNSetStrVal:
|
of opcNSetStrVal:
|
||||||
decodeB(rkNode)
|
decodeB(rkNode)
|
||||||
var dest = regs[ra].node
|
var dest = regs[ra].node
|
||||||
if dest.kind in {nkStrLit..nkTripleStrLit} and
|
if dest.kind in {nkStrLit..nkTripleStrLit} and
|
||||||
regs[rb].kind in {rkNode}:
|
regs[rb].kind in {rkNode}:
|
||||||
dest.strVal = regs[rb].node.strVal
|
dest.strVal = regs[rb].node.strVal
|
||||||
else:
|
else:
|
||||||
|
|
@ -1435,8 +1435,9 @@ proc evalConstExprAux(module, prc: PSym, n: PNode, mode: TEvalMode): PNode =
|
||||||
newSeq(tos.slots, c.prc.maxSlots)
|
newSeq(tos.slots, c.prc.maxSlots)
|
||||||
#for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
|
#for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
|
||||||
result = rawExecute(c, start, tos).regToNode
|
result = rawExecute(c, start, tos).regToNode
|
||||||
|
if result.info.line < 0: result.info = n.info
|
||||||
|
|
||||||
proc evalConstExpr*(module: PSym, e: PNode): PNode =
|
proc evalConstExpr*(module: PSym, e: PNode): PNode =
|
||||||
result = evalConstExprAux(module, nil, e, emConst)
|
result = evalConstExprAux(module, nil, e, emConst)
|
||||||
|
|
||||||
proc evalStaticExpr*(module: PSym, e: PNode, prc: PSym): PNode =
|
proc evalStaticExpr*(module: PSym, e: PNode, prc: PSym): PNode =
|
||||||
|
|
@ -1496,6 +1497,7 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
|
||||||
# temporary storage:
|
# temporary storage:
|
||||||
#for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty)
|
#for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty)
|
||||||
result = rawExecute(c, start, tos).regToNode
|
result = rawExecute(c, start, tos).regToNode
|
||||||
|
if result.info.line < 0: result.info = n.info
|
||||||
if cyclicTree(result): globalError(n.info, errCyclicTree)
|
if cyclicTree(result): globalError(n.info, errCyclicTree)
|
||||||
dec(evalMacroCounter)
|
dec(evalMacroCounter)
|
||||||
c.callsite = nil
|
c.callsite = nil
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ path="$lib/pure/unidecode"
|
||||||
gcc.options.always = "-w"
|
gcc.options.always = "-w"
|
||||||
gcc.cpp.options.always = "-w -fpermissive"
|
gcc.cpp.options.always = "-w -fpermissive"
|
||||||
@else:
|
@else:
|
||||||
gcc.options.always = "-w"
|
gcc.options.always = "-w"
|
||||||
gcc.cpp.options.always = "-w -fpermissive"
|
gcc.cpp.options.always = "-w -fpermissive"
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
@ -151,7 +151,7 @@ clang.options.size = "-Os"
|
||||||
vcc.options.linker = "/DEBUG /Zi /Fd\"$projectName.pdb\" /F33554432" # set the stack size to 8 MB
|
vcc.options.linker = "/DEBUG /Zi /Fd\"$projectName.pdb\" /F33554432" # set the stack size to 8 MB
|
||||||
vcc.options.debug = "/Zi /Fd\"$projectName.pdb\""
|
vcc.options.debug = "/Zi /Fd\"$projectName.pdb\""
|
||||||
vcc.options.always = "/nologo"
|
vcc.options.always = "/nologo"
|
||||||
vcc.options.speed = "/Ox /arch:SSE2"
|
vcc.options.speed = "/O2 /arch:SSE2"
|
||||||
vcc.options.size = "/O1"
|
vcc.options.size = "/O1"
|
||||||
|
|
||||||
# Configuration for the Digital Mars C/C++ compiler:
|
# Configuration for the Digital Mars C/C++ compiler:
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,9 @@ Generic Operating System Services
|
||||||
This module implements the ability to monitor a directory/file for changes
|
This module implements the ability to monitor a directory/file for changes
|
||||||
using Posix's inotify API.
|
using Posix's inotify API.
|
||||||
|
|
||||||
|
* `asyncfile <asyncfile.html>`_
|
||||||
|
This module implements asynchronous file reading and writing using
|
||||||
|
``asyncdispatch``.
|
||||||
|
|
||||||
Math libraries
|
Math libraries
|
||||||
--------------
|
--------------
|
||||||
|
|
|
||||||
|
|
@ -351,7 +351,7 @@ dispatch.
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
type
|
type
|
||||||
Expression = object ## abstract base class for an expression
|
Expression = object of RootObj ## abstract base class for an expression
|
||||||
Literal = object of Expression
|
Literal = object of Expression
|
||||||
x: int
|
x: int
|
||||||
PlusExpr = object of Expression
|
PlusExpr = object of Expression
|
||||||
|
|
@ -387,7 +387,7 @@ dispatching:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
type
|
type
|
||||||
Thing = object
|
Thing = object of RootObj
|
||||||
Unit = object of Thing
|
Unit = object of Thing
|
||||||
x: int
|
x: int
|
||||||
|
|
||||||
|
|
|
||||||
2
koch.nim
2
koch.nim
|
|
@ -347,7 +347,7 @@ proc temp(args: string) =
|
||||||
if args.len > 0: exec(finalDest & " " & args)
|
if args.len > 0: exec(finalDest & " " & args)
|
||||||
|
|
||||||
proc showHelp() =
|
proc showHelp() =
|
||||||
quit(HelpText % [VersionAsString & repeatChar(44-len(VersionAsString)),
|
quit(HelpText % [VersionAsString & spaces(44-len(VersionAsString)),
|
||||||
CompileDate, CompileTime], QuitSuccess)
|
CompileDate, CompileTime], QuitSuccess)
|
||||||
|
|
||||||
var op = initOptParser()
|
var op = initOptParser()
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ type
|
||||||
nnkStmtListType, nnkBlockType,
|
nnkStmtListType, nnkBlockType,
|
||||||
nnkWith, nnkWithout,
|
nnkWith, nnkWithout,
|
||||||
nnkTypeOfExpr, nnkObjectTy,
|
nnkTypeOfExpr, nnkObjectTy,
|
||||||
nnkTupleTy, nnkTypeClassTy, nnkStaticTy,
|
nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy,
|
||||||
nnkRecList, nnkRecCase, nnkRecWhen,
|
nnkRecList, nnkRecCase, nnkRecWhen,
|
||||||
nnkRefTy, nnkPtrTy, nnkVarTy,
|
nnkRefTy, nnkPtrTy, nnkVarTy,
|
||||||
nnkConstTy, nnkMutableTy,
|
nnkConstTy, nnkMutableTy,
|
||||||
|
|
@ -343,7 +343,7 @@ proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
|
||||||
## checks that `n` is of kind `k`. If this is not the case,
|
## checks that `n` is of kind `k`. If this is not the case,
|
||||||
## compilation aborts with an error message. This is useful for writing
|
## compilation aborts with an error message. This is useful for writing
|
||||||
## macros that check the AST that is passed to them.
|
## macros that check the AST that is passed to them.
|
||||||
if n.kind != k: error("macro expects a node of kind: " & $k)
|
if n.kind != k: error("Expected a node of kind " & $k & ", got " & $n.kind)
|
||||||
|
|
||||||
proc expectMinLen*(n: PNimrodNode, min: int) {.compileTime.} =
|
proc expectMinLen*(n: PNimrodNode, min: int) {.compileTime.} =
|
||||||
## checks that `n` has at least `min` children. If this is not the case,
|
## checks that `n` has at least `min` children. If this is not the case,
|
||||||
|
|
@ -581,10 +581,8 @@ const
|
||||||
CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
|
CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
|
||||||
nnkCallStrLit, nnkHiddenCallConv}
|
nnkCallStrLit, nnkHiddenCallConv}
|
||||||
|
|
||||||
from strutils import cmpIgnoreStyle, format
|
|
||||||
|
|
||||||
proc expectKind*(n: PNimrodNode; k: set[TNimrodNodeKind]) {.compileTime.} =
|
proc expectKind*(n: PNimrodNode; k: set[TNimrodNodeKind]) {.compileTime.} =
|
||||||
assert n.kind in k, "Expected one of $1, got $2".format(k, n.kind)
|
assert n.kind in k, "Expected one of " & $k & ", got " & $n.kind
|
||||||
|
|
||||||
proc newProc*(name = newEmptyNode(); params: openArray[PNimrodNode] = [newEmptyNode()];
|
proc newProc*(name = newEmptyNode(); params: openArray[PNimrodNode] = [newEmptyNode()];
|
||||||
body: PNimrodNode = newStmtList(), procType = nnkProcDef): PNimrodNode {.compileTime.} =
|
body: PNimrodNode = newStmtList(), procType = nnkProcDef): PNimrodNode {.compileTime.} =
|
||||||
|
|
@ -654,7 +652,7 @@ proc `pragma=`*(someProc: PNimrodNode; val: PNimrodNode){.compileTime.}=
|
||||||
|
|
||||||
|
|
||||||
template badNodeKind(k; f): stmt{.immediate.} =
|
template badNodeKind(k; f): stmt{.immediate.} =
|
||||||
assert false, "Invalid node kind $# for macros.`$2`".format(k, f)
|
assert false, "Invalid node kind " & $k & " for macros.`" & $f & "`"
|
||||||
|
|
||||||
proc body*(someProc: PNimrodNode): PNimrodNode {.compileTime.} =
|
proc body*(someProc: PNimrodNode): PNimrodNode {.compileTime.} =
|
||||||
case someProc.kind:
|
case someProc.kind:
|
||||||
|
|
@ -776,6 +774,22 @@ proc copy*(node: PNimrodNode): PNimrodNode {.compileTime.} =
|
||||||
## An alias for copyNimTree().
|
## An alias for copyNimTree().
|
||||||
return node.copyNimTree()
|
return node.copyNimTree()
|
||||||
|
|
||||||
|
proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} =
|
||||||
|
proc toLower(c: char): char {.inline.} =
|
||||||
|
if c in {'A'..'Z'}: result = chr(ord(c) + (ord('a') - ord('A')))
|
||||||
|
else: result = c
|
||||||
|
var i = 0
|
||||||
|
var j = 0
|
||||||
|
while true:
|
||||||
|
while a[i] == '_': inc(i)
|
||||||
|
while b[j] == '_': inc(j) # BUGFIX: typo
|
||||||
|
var aa = toLower(a[i])
|
||||||
|
var bb = toLower(b[j])
|
||||||
|
result = ord(aa) - ord(bb)
|
||||||
|
if result != 0 or aa == '\0': break
|
||||||
|
inc(i)
|
||||||
|
inc(j)
|
||||||
|
|
||||||
proc eqIdent* (a, b: string): bool = cmpIgnoreStyle(a, b) == 0
|
proc eqIdent* (a, b: string): bool = cmpIgnoreStyle(a, b) == 0
|
||||||
## Check if two idents are identical.
|
## Check if two idents are identical.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,9 +66,9 @@ type
|
||||||
ppointer = ptr pointer
|
ppointer = ptr pointer
|
||||||
pbyteArray = ptr array[0.. 0xffff, int8]
|
pbyteArray = ptr array[0.. 0xffff, int8]
|
||||||
|
|
||||||
TGenSeq = object
|
TGenericSeq {.importc.} = object
|
||||||
len, space: int
|
len, space: int
|
||||||
PGenSeq = ptr TGenSeq
|
PGenSeq = ptr TGenericSeq
|
||||||
|
|
||||||
const
|
const
|
||||||
GenericSeqSize = (2 * sizeof(int))
|
GenericSeqSize = (2 * sizeof(int))
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,16 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
## This module contains code for reading from `stdin`:idx:. On UNIX the GNU
|
## This module contains code for reading from `stdin`:idx:. On UNIX the GNU
|
||||||
## readline library is wrapped and set up to provide default key bindings
|
## readline library is wrapped and set up to provide default key bindings
|
||||||
## (e.g. you can navigate with the arrow keys). On Windows ``system.readLine``
|
## (e.g. you can navigate with the arrow keys). On Windows ``system.readLine``
|
||||||
## is used. This suffices because Windows' console already provides the
|
## is used. This suffices because Windows' console already provides the
|
||||||
## wanted functionality.
|
## wanted functionality.
|
||||||
|
|
||||||
{.deadCodeElim: on.}
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
proc readLineFromStdin*(prompt: string): TaintedString {.
|
proc readLineFromStdin*(prompt: string): TaintedString {.
|
||||||
tags: [ReadIOEffect, WriteIOEffect].} =
|
tags: [ReadIOEffect, WriteIOEffect].} =
|
||||||
## Reads a line from stdin.
|
## Reads a line from stdin.
|
||||||
stdout.write(prompt)
|
stdout.write(prompt)
|
||||||
result = readLine(stdin)
|
result = readLine(stdin)
|
||||||
|
|
@ -33,27 +33,71 @@ when defined(Windows):
|
||||||
stdout.write(prompt)
|
stdout.write(prompt)
|
||||||
result = readLine(stdin, line)
|
result = readLine(stdin, line)
|
||||||
|
|
||||||
|
import winlean
|
||||||
|
|
||||||
|
const
|
||||||
|
VK_SHIFT* = 16
|
||||||
|
VK_CONTROL* = 17
|
||||||
|
VK_MENU* = 18
|
||||||
|
KEY_EVENT* = 1
|
||||||
|
|
||||||
|
type
|
||||||
|
KEY_EVENT_RECORD = object
|
||||||
|
bKeyDown: WinBool
|
||||||
|
wRepeatCount: uint16
|
||||||
|
wVirtualKeyCode: uint16
|
||||||
|
wVirtualScanCode: uint16
|
||||||
|
unicodeChar: uint16
|
||||||
|
dwControlKeyState: uint32
|
||||||
|
INPUT_RECORD = object
|
||||||
|
eventType*: int16
|
||||||
|
reserved*: int16
|
||||||
|
event*: KEY_EVENT_RECORD
|
||||||
|
safetyBuffer: array[0..5, DWORD]
|
||||||
|
|
||||||
|
proc readConsoleInputW*(hConsoleInput: THANDLE, lpBuffer: var INPUTRECORD,
|
||||||
|
nLength: uint32,
|
||||||
|
lpNumberOfEventsRead: var uint32): WINBOOL{.
|
||||||
|
stdcall, dynlib: "kernel32", importc: "ReadConsoleInputW".}
|
||||||
|
|
||||||
|
proc getch(): uint16 =
|
||||||
|
let hStdin = getStdHandle(STD_INPUT_HANDLE)
|
||||||
|
var
|
||||||
|
irInputRecord: INPUT_RECORD
|
||||||
|
dwEventsRead: uint32
|
||||||
|
|
||||||
|
while readConsoleInputW(hStdin, irInputRecord, 1, dwEventsRead) != 0:
|
||||||
|
if irInputRecord.eventType == KEY_EVENT and
|
||||||
|
irInputRecord.event.wVirtualKeyCode notin {VK_SHIFT, VK_MENU, VK_CONTROL}:
|
||||||
|
result = irInputRecord.event.unicodeChar
|
||||||
|
discard readConsoleInputW(hStdin, irInputRecord, 1, dwEventsRead)
|
||||||
|
return result
|
||||||
|
|
||||||
|
from unicode import toUTF8, Rune, runeLenAt
|
||||||
|
|
||||||
proc readPasswordFromStdin*(prompt: string, password: var TaintedString):
|
proc readPasswordFromStdin*(prompt: string, password: var TaintedString):
|
||||||
bool {.tags: [ReadIOEffect, WriteIOEffect].} =
|
bool {.tags: [ReadIOEffect, WriteIOEffect].} =
|
||||||
## Reads a `password` from stdin without printing it. `password` must not
|
## Reads a `password` from stdin without printing it. `password` must not
|
||||||
## be ``nil``! Returns ``false`` if the end of the file has been reached,
|
## be ``nil``! Returns ``false`` if the end of the file has been reached,
|
||||||
## ``true`` otherwise.
|
## ``true`` otherwise.
|
||||||
proc getch(): cint {.header: "<conio.h>", importc: "_getch".}
|
|
||||||
|
|
||||||
password.setLen(0)
|
password.setLen(0)
|
||||||
var c: char
|
|
||||||
stdout.write(prompt)
|
stdout.write(prompt)
|
||||||
while true:
|
while true:
|
||||||
c = getch().char
|
let c = getch()
|
||||||
case c
|
case c.char
|
||||||
of '\r', chr(0xA):
|
of '\r', chr(0xA):
|
||||||
break
|
break
|
||||||
of '\b':
|
of '\b':
|
||||||
password.setLen(password.len - 1)
|
# ensure we delete the whole UTF-8 character:
|
||||||
|
var i = 0
|
||||||
|
var x = 1
|
||||||
|
while i < password.len:
|
||||||
|
x = runeLenAt(password, i)
|
||||||
|
inc i, x
|
||||||
|
password.setLen(password.len - x)
|
||||||
else:
|
else:
|
||||||
password.add(c)
|
password.add(toUTF8(c.Rune))
|
||||||
stdout.write "\n"
|
stdout.write "\n"
|
||||||
# TODO: How to detect EOF on Windows?
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
import readline, history, termios, unsigned
|
import readline, history, termios, unsigned
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ proc rawCompile(pattern: string, flags: cint): PPcre =
|
||||||
offset: cint
|
offset: cint
|
||||||
result = pcre.compile(pattern, flags, addr(msg), addr(offset), nil)
|
result = pcre.compile(pattern, flags, addr(msg), addr(offset), nil)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
raiseInvalidRegex($msg & "\n" & pattern & "\n" & repeatChar(offset) & "^\n")
|
raiseInvalidRegex($msg & "\n" & pattern & "\n" & spaces(offset) & "^\n")
|
||||||
|
|
||||||
proc finalizeRegEx(x: Regex) =
|
proc finalizeRegEx(x: Regex) =
|
||||||
# XXX This is a hack, but PCRE does not export its "free" function properly.
|
# XXX This is a hack, but PCRE does not export its "free" function properly.
|
||||||
|
|
@ -291,7 +291,7 @@ proc replace*(s: string, sub: Regex, by = ""): string =
|
||||||
## accessed in `by`. Examples:
|
## accessed in `by`. Examples:
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
## "var1=key; var2=key2".replace(re"(\w+)'='(\w+)")
|
## "var1=key; var2=key2".replace(re"(\w+)=(\w+)")
|
||||||
##
|
##
|
||||||
## Results in:
|
## Results in:
|
||||||
##
|
##
|
||||||
|
|
@ -313,7 +313,7 @@ proc replacef*(s: string, sub: Regex, by: string): string =
|
||||||
## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
|
## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
## "var1=key; var2=key2".replacef(re"(\w+)'='(\w+)", "$1<-$2$2")
|
## "var1=key; var2=key2".replacef(re"(\w+)=(\w+)", "$1<-$2$2")
|
||||||
##
|
##
|
||||||
## Results in:
|
## Results in:
|
||||||
##
|
##
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ __clang__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
|
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
|
||||||
# define NIM_THREADVAR __declspec(thread)
|
# define NIM_THREADVAR __declspec(thread)
|
||||||
#else
|
#else
|
||||||
# define NIM_THREADVAR __thread
|
# define NIM_THREADVAR __thread
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -103,7 +103,11 @@ __clang__
|
||||||
# define N_FASTCALL_PTR(rettype, name) rettype (__fastcall *name)
|
# define N_FASTCALL_PTR(rettype, name) rettype (__fastcall *name)
|
||||||
# define N_SAFECALL_PTR(rettype, name) rettype (__safecall *name)
|
# define N_SAFECALL_PTR(rettype, name) rettype (__safecall *name)
|
||||||
|
|
||||||
# define N_LIB_EXPORT extern __declspec(dllexport)
|
# ifdef __cplusplus
|
||||||
|
# define N_LIB_EXPORT extern "C" __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define N_LIB_EXPORT extern __declspec(dllexport)
|
||||||
|
# endif
|
||||||
# define N_LIB_IMPORT extern __declspec(dllimport)
|
# define N_LIB_IMPORT extern __declspec(dllimport)
|
||||||
#else
|
#else
|
||||||
# define N_CDECL(rettype, name) rettype name
|
# define N_CDECL(rettype, name) rettype name
|
||||||
|
|
@ -118,7 +122,11 @@ __clang__
|
||||||
# define N_FASTCALL_PTR(rettype, name) rettype (*name)
|
# define N_FASTCALL_PTR(rettype, name) rettype (*name)
|
||||||
# define N_SAFECALL_PTR(rettype, name) rettype (*name)
|
# define N_SAFECALL_PTR(rettype, name) rettype (*name)
|
||||||
|
|
||||||
# define N_LIB_EXPORT extern
|
# ifdef __cplusplus
|
||||||
|
# define N_LIB_EXPORT extern "C"
|
||||||
|
# else
|
||||||
|
# define N_LIB_EXPORT extern
|
||||||
|
# endif
|
||||||
# define N_LIB_IMPORT extern
|
# define N_LIB_IMPORT extern
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -345,7 +353,7 @@ struct TFrame {
|
||||||
#define nimln(n, file) \
|
#define nimln(n, file) \
|
||||||
F.line = n; F.filename = file;
|
F.line = n; F.filename = file;
|
||||||
|
|
||||||
#define NIM_POSIX_INIT __attribute__((constructor))
|
#define NIM_POSIX_INIT __attribute__((constructor))
|
||||||
|
|
||||||
#if defined(_MSCVER) && defined(__i386__)
|
#if defined(_MSCVER) && defined(__i386__)
|
||||||
__declspec(naked) int __fastcall NimXadd(volatile int* pNum, int val) {
|
__declspec(naked) int __fastcall NimXadd(volatile int* pNum, int val) {
|
||||||
|
|
@ -380,7 +388,7 @@ static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Test to see if Nim and the C compiler agree on the size of a pointer.
|
/* Test to see if Nim and the C compiler agree on the size of a pointer.
|
||||||
On disagreement, your C compiler will say something like:
|
On disagreement, your C compiler will say something like:
|
||||||
"error: 'assert_numbits' declared as an array with a negative size" */
|
"error: 'assert_numbits' declared as an array with a negative size" */
|
||||||
typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8 ? 1 : -1];
|
typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8 ? 1 : -1];
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -398,4 +406,6 @@ typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
# include <types/vxWind.h>
|
# include <types/vxWind.h>
|
||||||
# include <tool/gnu/toolMacros.h>
|
# include <tool/gnu/toolMacros.h>
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
# include <sys/types.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,7 @@ proc getIndent(L: var TLexer, tok: var TToken) =
|
||||||
tok.line = L.line
|
tok.line = L.line
|
||||||
L.col = tok.ival
|
L.col = tok.ival
|
||||||
tok.ival = max(tok.ival - L.baseIndent, 0)
|
tok.ival = max(tok.ival - L.baseIndent, 0)
|
||||||
tok.symbol = "\n" & repeatChar(tok.ival)
|
tok.symbol = "\n" & spaces(tok.ival)
|
||||||
|
|
||||||
proc rawGetTok(L: var TLexer, tok: var TToken) =
|
proc rawGetTok(L: var TLexer, tok: var TToken) =
|
||||||
tok.symbol = ""
|
tok.symbol = ""
|
||||||
|
|
@ -963,7 +963,7 @@ proc parseLiteralBlock(p: var TRstParser): PRstNode =
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
add(n.text, "\n")
|
add(n.text, "\n")
|
||||||
add(n.text, repeatChar(p.tok[p.idx].ival - indent))
|
add(n.text, spaces(p.tok[p.idx].ival - indent))
|
||||||
inc(p.idx)
|
inc(p.idx)
|
||||||
else:
|
else:
|
||||||
add(n.text, p.tok[p.idx].symbol)
|
add(n.text, p.tok[p.idx].symbol)
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||||
const
|
const
|
||||||
lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+']
|
lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+']
|
||||||
if n == nil: return
|
if n == nil: return
|
||||||
var ind = repeatChar(d.indent)
|
var ind = spaces(d.indent)
|
||||||
case n.kind
|
case n.kind
|
||||||
of rnInner:
|
of rnInner:
|
||||||
renderRstSons(d, n, result)
|
renderRstSons(d, n, result)
|
||||||
|
|
@ -124,7 +124,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||||
|
|
||||||
result.add("\n")
|
result.add("\n")
|
||||||
result.add(ind)
|
result.add(ind)
|
||||||
result.add repeatChar(headlineLen, lvlToChar[n.level])
|
result.add repeat(lvlToChar[n.level], headlineLen)
|
||||||
of rnOverline:
|
of rnOverline:
|
||||||
result.add("\n")
|
result.add("\n")
|
||||||
result.add(ind)
|
result.add(ind)
|
||||||
|
|
@ -132,7 +132,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||||
var headline = ""
|
var headline = ""
|
||||||
renderRstSons(d, n, headline)
|
renderRstSons(d, n, headline)
|
||||||
|
|
||||||
let lvl = repeatChar(headline.len - d.indent, lvlToChar[n.level])
|
let lvl = repeat(lvlToChar[n.level], headline.len - d.indent)
|
||||||
result.add(lvl)
|
result.add(lvl)
|
||||||
result.add("\n")
|
result.add("\n")
|
||||||
result.add(headline)
|
result.add(headline)
|
||||||
|
|
@ -143,7 +143,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||||
of rnTransition:
|
of rnTransition:
|
||||||
result.add("\n\n")
|
result.add("\n\n")
|
||||||
result.add(ind)
|
result.add(ind)
|
||||||
result.add repeatChar(78-d.indent, '-')
|
result.add repeat('-', 78-d.indent)
|
||||||
result.add("\n\n")
|
result.add("\n\n")
|
||||||
of rnParagraph:
|
of rnParagraph:
|
||||||
result.add("\n\n")
|
result.add("\n\n")
|
||||||
|
|
@ -196,7 +196,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
|
||||||
result.add ':'
|
result.add ':'
|
||||||
result.add tmp
|
result.add tmp
|
||||||
result.add ':'
|
result.add ':'
|
||||||
result.add repeatChar(L - tmp.len - 2)
|
result.add spaces(L - tmp.len - 2)
|
||||||
renderRstToRst(d, n.sons[1], result)
|
renderRstToRst(d, n.sons[1], result)
|
||||||
|
|
||||||
dec(d.indent, L)
|
dec(d.indent, L)
|
||||||
|
|
|
||||||
|
|
@ -461,9 +461,9 @@ proc indentToLevel(level: var int, newLevel: int): string =
|
||||||
if level == newLevel:
|
if level == newLevel:
|
||||||
return
|
return
|
||||||
if newLevel > level:
|
if newLevel > level:
|
||||||
result = repeatStr(newLevel - level, "<ul>")
|
result = repeat("<ul>", newLevel - level)
|
||||||
else:
|
else:
|
||||||
result = repeatStr(level - newLevel, "</ul>")
|
result = repeat("</ul>", level - newLevel)
|
||||||
level = newLevel
|
level = newLevel
|
||||||
|
|
||||||
proc generateDocumentationTOC(entries: seq[TIndexEntry]): string =
|
proc generateDocumentationTOC(entries: seq[TIndexEntry]): string =
|
||||||
|
|
@ -701,7 +701,7 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
|
||||||
# Generate index entry using spaces to indicate TOC level for the output HTML.
|
# Generate index entry using spaces to indicate TOC level for the output HTML.
|
||||||
assert n.level >= 0
|
assert n.level >= 0
|
||||||
setIndexTerm(d, refname, tmp.stripTOCHTML,
|
setIndexTerm(d, refname, tmp.stripTOCHTML,
|
||||||
repeatChar(max(0, n.level), ' ') & tmp)
|
spaces(max(0, n.level)) & tmp)
|
||||||
|
|
||||||
proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
|
proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
|
||||||
if d.meta[metaTitle].len == 0:
|
if d.meta[metaTitle].len == 0:
|
||||||
|
|
|
||||||
|
|
@ -11,15 +11,15 @@
|
||||||
|
|
||||||
type
|
type
|
||||||
SortOrder* = enum ## sort order
|
SortOrder* = enum ## sort order
|
||||||
Descending, Ascending
|
Descending, Ascending
|
||||||
|
|
||||||
{.deprecated: [TSortOrder: SortOrder].}
|
{.deprecated: [TSortOrder: SortOrder].}
|
||||||
|
|
||||||
|
|
||||||
proc `*`*(x: int, order: SortOrder): int {.inline.} =
|
proc `*`*(x: int, order: SortOrder): int {.inline.} =
|
||||||
## flips `x` if ``order == Descending``;
|
## flips `x` if ``order == Descending``;
|
||||||
## if ``order == Ascending`` then `x` is returned.
|
## if ``order == Ascending`` then `x` is returned.
|
||||||
## `x` is supposed to be the result of a comparator, ie ``< 0`` for
|
## `x` is supposed to be the result of a comparator, ie ``< 0`` for
|
||||||
## *less than*, ``== 0`` for *equal*, ``> 0`` for *greater than*.
|
## *less than*, ``== 0`` for *equal*, ``> 0`` for *greater than*.
|
||||||
var y = order.ord - 1
|
var y = order.ord - 1
|
||||||
result = (x xor y) - y
|
result = (x xor y) - y
|
||||||
|
|
@ -73,14 +73,15 @@ const
|
||||||
onlySafeCode = true
|
onlySafeCode = true
|
||||||
|
|
||||||
proc lowerBound*[T](a: openArray[T], key: T, cmp: proc(x,y: T): int {.closure.}): int =
|
proc lowerBound*[T](a: openArray[T], key: T, cmp: proc(x,y: T): int {.closure.}): int =
|
||||||
## same as binarySearch except that if key is not in `a` then this
|
## same as binarySearch except that if key is not in `a` then this
|
||||||
## returns the location where `key` would be if it were. In other
|
## returns the location where `key` would be if it were. In other
|
||||||
## words if you have a sorted sequence and you call insert(thing, elm, lowerBound(thing, elm))
|
## words if you have a sorted sequence and you call
|
||||||
## the sequence will still be sorted
|
## insert(thing, elm, lowerBound(thing, elm))
|
||||||
|
## the sequence will still be sorted.
|
||||||
|
##
|
||||||
|
## `cmp` is the comparator function to use, the expected return values are
|
||||||
|
## the same as that of system.cmp.
|
||||||
##
|
##
|
||||||
## `cmp` is the comparator function to use, the expected return values are the same as
|
|
||||||
## that of system.cmp
|
|
||||||
##
|
|
||||||
## example::
|
## example::
|
||||||
##
|
##
|
||||||
## var arr = @[1,2,3,5,6,7,8,9]
|
## var arr = @[1,2,3,5,6,7,8,9]
|
||||||
|
|
@ -102,9 +103,9 @@ proc lowerBound*[T](a: openArray[T], key: T, cmp: proc(x,y: T): int {.closure.})
|
||||||
count = step
|
count = step
|
||||||
|
|
||||||
proc lowerBound*[T](a: openArray[T], key: T): int = lowerBound(a, key, cmp[T])
|
proc lowerBound*[T](a: openArray[T], key: T): int = lowerBound(a, key, cmp[T])
|
||||||
proc merge[T](a, b: var openArray[T], lo, m, hi: int,
|
proc merge[T](a, b: var openArray[T], lo, m, hi: int,
|
||||||
cmp: proc (x, y: T): int {.closure.}, order: SortOrder) =
|
cmp: proc (x, y: T): int {.closure.}, order: SortOrder) =
|
||||||
template `<-` (a, b: expr) =
|
template `<-` (a, b: expr) =
|
||||||
when false:
|
when false:
|
||||||
a = b
|
a = b
|
||||||
elif onlySafeCode:
|
elif onlySafeCode:
|
||||||
|
|
@ -151,10 +152,10 @@ proc merge[T](a, b: var openArray[T], lo, m, hi: int,
|
||||||
proc sort*[T](a: var openArray[T],
|
proc sort*[T](a: var openArray[T],
|
||||||
cmp: proc (x, y: T): int {.closure.},
|
cmp: proc (x, y: T): int {.closure.},
|
||||||
order = SortOrder.Ascending) =
|
order = SortOrder.Ascending) =
|
||||||
## Default Nim sort. The sorting is guaranteed to be stable and
|
## Default Nim sort. The sorting is guaranteed to be stable and
|
||||||
## the worst case is guaranteed to be O(n log n).
|
## the worst case is guaranteed to be O(n log n).
|
||||||
## The current implementation uses an iterative
|
## The current implementation uses an iterative
|
||||||
## mergesort to achieve this. It uses a temporary sequence of
|
## mergesort to achieve this. It uses a temporary sequence of
|
||||||
## length ``a.len div 2``. Currently Nim does not support a
|
## length ``a.len div 2``. Currently Nim does not support a
|
||||||
## sensible default argument for ``cmp``, so you have to provide one
|
## sensible default argument for ``cmp``, so you have to provide one
|
||||||
## of your own. However, the ``system.cmp`` procs can be used:
|
## of your own. However, the ``system.cmp`` procs can be used:
|
||||||
|
|
@ -187,6 +188,35 @@ proc sort*[T](a: var openArray[T],
|
||||||
dec(m, s*2)
|
dec(m, s*2)
|
||||||
s = s*2
|
s = s*2
|
||||||
|
|
||||||
|
proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.},
|
||||||
|
order = SortOrder.Ascending): seq[T] =
|
||||||
|
## returns `a` sorted by `cmp` in the specified `order`.
|
||||||
|
result = newSeq[T](a.len)
|
||||||
|
for i in 0 .. a.high:
|
||||||
|
result[i] = a[i]
|
||||||
|
sort(result, cmp, order)
|
||||||
|
|
||||||
|
template sortByIt*(seq1, op: expr): expr =
|
||||||
|
## Convenience template around the ``sorted`` proc to reduce typing.
|
||||||
|
##
|
||||||
|
## The template injects the ``it`` variable which you can use directly in an
|
||||||
|
## expression. Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
##
|
||||||
|
## var users: seq[tuple[id: int, name: string]] =
|
||||||
|
## @[(0, "Smith"), (1, "Pratt"), (2, "Sparrow")]
|
||||||
|
##
|
||||||
|
## echo users.sortByIt(it.name)
|
||||||
|
##
|
||||||
|
var result {.gensym.} = sorted(seq1, proc(x, y: type(seq1[0])): int =
|
||||||
|
var it {.inject.} = x
|
||||||
|
let a = op
|
||||||
|
it = y
|
||||||
|
let b = op
|
||||||
|
result = cmp(a, b))
|
||||||
|
result
|
||||||
|
|
||||||
proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
|
proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
|
||||||
## produces the Cartesian product of the array. Warning: complexity
|
## produces the Cartesian product of the array. Warning: complexity
|
||||||
## may explode.
|
## may explode.
|
||||||
|
|
|
||||||
|
|
@ -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,29 +1315,40 @@ 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.} =
|
||||||
|
# -> {.push warning[resultshadowed]: off.}
|
||||||
# -> var result: T
|
# -> var result: T
|
||||||
|
# -> {.pop.}
|
||||||
# -> <proc_body>
|
# -> <proc_body>
|
||||||
# -> complete(retFuture, result)
|
# -> complete(retFuture, result)
|
||||||
var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter")
|
var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter")
|
||||||
var procBody = prc[6].processBody(retFutureSym, subtypeIsVoid, nil)
|
var procBody = prc[6].processBody(retFutureSym, subtypeIsVoid, nil)
|
||||||
if not subtypeIsVoid:
|
if not subtypeIsVoid:
|
||||||
procBody.insert(0, newNimNode(nnkVarSection, prc[6]).add(
|
procBody.insert(0, newNimNode(nnkPragma).add(newIdentNode("push"),
|
||||||
|
newNimNode(nnkExprColonExpr).add(newNimNode(nnkBracketExpr).add(
|
||||||
|
newIdentNode("warning"), newIdentNode("resultshadowed")),
|
||||||
|
newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.}
|
||||||
|
|
||||||
|
procBody.insert(1, newNimNode(nnkVarSection, prc[6]).add(
|
||||||
newIdentDefs(newIdentNode("result"), returnType[1]))) # -> var result: T
|
newIdentDefs(newIdentNode("result"), returnType[1]))) # -> var result: T
|
||||||
|
|
||||||
|
procBody.insert(2, newNimNode(nnkPragma).add(
|
||||||
|
newIdentNode("pop"))) # -> {.pop.})
|
||||||
|
|
||||||
procBody.add(
|
procBody.add(
|
||||||
newCall(newIdentNode("complete"),
|
newCall(newIdentNode("complete"),
|
||||||
retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result)
|
retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result)
|
||||||
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 +1362,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 +1388,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 +1399,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")
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
## This module implements asynchronous file handling.
|
## This module implements asynchronous file reading and writing.
|
||||||
##
|
##
|
||||||
## .. code-block:: Nim
|
## .. code-block:: Nim
|
||||||
## import asyncfile, asyncdispatch, os
|
## import asyncfile, asyncdispatch, os
|
||||||
|
|
@ -24,17 +24,17 @@
|
||||||
|
|
||||||
import asyncdispatch, os
|
import asyncdispatch, os
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows) or defined(nimdoc):
|
||||||
import winlean
|
import winlean
|
||||||
else:
|
else:
|
||||||
import posix
|
import posix
|
||||||
|
|
||||||
type
|
type
|
||||||
AsyncFile = ref object
|
AsyncFile* = ref object
|
||||||
fd: TAsyncFd
|
fd: TAsyncFd
|
||||||
offset: int64
|
offset: int64
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows) or defined(nimdoc):
|
||||||
proc getDesiredAccess(mode: FileMode): int32 =
|
proc getDesiredAccess(mode: FileMode): int32 =
|
||||||
case mode
|
case mode
|
||||||
of fmRead:
|
of fmRead:
|
||||||
|
|
@ -70,7 +70,7 @@ else:
|
||||||
|
|
||||||
proc getFileSize(f: AsyncFile): int64 =
|
proc getFileSize(f: AsyncFile): int64 =
|
||||||
## Retrieves the specified file's size.
|
## Retrieves the specified file's size.
|
||||||
when defined(windows):
|
when defined(windows) or defined(nimdoc):
|
||||||
var high: DWord
|
var high: DWord
|
||||||
let low = getFileSize(f.fd.THandle, addr high)
|
let low = getFileSize(f.fd.THandle, addr high)
|
||||||
if low == INVALID_FILE_SIZE:
|
if low == INVALID_FILE_SIZE:
|
||||||
|
|
@ -81,7 +81,7 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile =
|
||||||
## Opens a file specified by the path in ``filename`` using
|
## Opens a file specified by the path in ``filename`` using
|
||||||
## the specified ``mode`` asynchronously.
|
## the specified ``mode`` asynchronously.
|
||||||
new result
|
new result
|
||||||
when defined(windows):
|
when defined(windows) or defined(nimdoc):
|
||||||
let flags = FILE_FLAG_OVERLAPPED or FILE_ATTRIBUTE_NORMAL
|
let flags = FILE_FLAG_OVERLAPPED or FILE_ATTRIBUTE_NORMAL
|
||||||
let desiredAccess = getDesiredAccess(mode)
|
let desiredAccess = getDesiredAccess(mode)
|
||||||
let creationDisposition = getCreationDisposition(mode, filename)
|
let creationDisposition = getCreationDisposition(mode, filename)
|
||||||
|
|
@ -120,7 +120,7 @@ proc read*(f: AsyncFile, size: int): Future[string] =
|
||||||
## returned.
|
## returned.
|
||||||
var retFuture = newFuture[string]("asyncfile.read")
|
var retFuture = newFuture[string]("asyncfile.read")
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows) or defined(nimdoc):
|
||||||
var buffer = alloc0(size)
|
var buffer = alloc0(size)
|
||||||
|
|
||||||
var ol = PCustomOverlapped()
|
var ol = PCustomOverlapped()
|
||||||
|
|
@ -224,7 +224,7 @@ proc setFilePos*(f: AsyncFile, pos: int64) =
|
||||||
## Sets the position of the file pointer that is used for read/write
|
## Sets the position of the file pointer that is used for read/write
|
||||||
## operations. The file's first byte has the index zero.
|
## operations. The file's first byte has the index zero.
|
||||||
f.offset = pos
|
f.offset = pos
|
||||||
when not defined(windows):
|
when not defined(windows) and not defined(nimdoc):
|
||||||
let ret = lseek(f.fd.cint, pos, SEEK_SET)
|
let ret = lseek(f.fd.cint, pos, SEEK_SET)
|
||||||
if ret == -1:
|
if ret == -1:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
|
@ -245,7 +245,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
|
||||||
## specified file.
|
## specified file.
|
||||||
var retFuture = newFuture[void]("asyncfile.write")
|
var retFuture = newFuture[void]("asyncfile.write")
|
||||||
var copy = data
|
var copy = data
|
||||||
when defined(windows):
|
when defined(windows) or defined(nimdoc):
|
||||||
var buffer = alloc0(data.len)
|
var buffer = alloc0(data.len)
|
||||||
copyMem(buffer, addr copy[0], data.len)
|
copyMem(buffer, addr copy[0], data.len)
|
||||||
|
|
||||||
|
|
@ -316,7 +316,7 @@ proc write*(f: AsyncFile, data: string): Future[void] =
|
||||||
|
|
||||||
proc close*(f: AsyncFile) =
|
proc close*(f: AsyncFile) =
|
||||||
## Closes the file specified.
|
## Closes the file specified.
|
||||||
when defined(windows):
|
when defined(windows) or defined(nimdoc):
|
||||||
if not closeHandle(f.fd.THandle).bool:
|
if not closeHandle(f.fd.THandle).bool:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,24 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
|
||||||
result[i] = itm
|
result[i] = itm
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
||||||
|
proc repeat*[T](s: seq[T], n: Natural): seq[T] =
|
||||||
|
## Returns a new sequence with the items of `s` repeated `n` times.
|
||||||
|
##
|
||||||
|
## Example:
|
||||||
|
##
|
||||||
|
## .. code-block:
|
||||||
|
##
|
||||||
|
## let
|
||||||
|
## s = @[1, 2, 3]
|
||||||
|
## total = s.repeat(3)
|
||||||
|
## assert total == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
|
||||||
|
result = newSeq[T](n * s.len)
|
||||||
|
var o = 0
|
||||||
|
for x in 1..n:
|
||||||
|
for e in s:
|
||||||
|
result[o] = e
|
||||||
|
inc o
|
||||||
|
|
||||||
proc deduplicate*[T](seq1: seq[T]): seq[T] =
|
proc deduplicate*[T](seq1: seq[T]): seq[T] =
|
||||||
## Returns a new sequence without duplicates.
|
## Returns a new sequence without duplicates.
|
||||||
##
|
##
|
||||||
|
|
@ -86,7 +104,7 @@ proc zip*[S, T](seq1: seq[S], seq2: seq[T]): seq[tuple[a: S, b: T]] =
|
||||||
newSeq(result, m)
|
newSeq(result, m)
|
||||||
for i in 0 .. m-1: result[i] = (seq1[i], seq2[i])
|
for i in 0 .. m-1: result[i] = (seq1[i], seq2[i])
|
||||||
|
|
||||||
proc distribute*[T](s: seq[T], num: int, spread = true): seq[seq[T]] =
|
proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
|
||||||
## Splits and distributes a sequence `s` into `num` sub sequences.
|
## Splits and distributes a sequence `s` into `num` sub sequences.
|
||||||
##
|
##
|
||||||
## Returns a sequence of `num` sequences. For some input values this is the
|
## Returns a sequence of `num` sequences. For some input values this is the
|
||||||
|
|
@ -113,11 +131,12 @@ proc distribute*[T](s: seq[T], num: int, spread = true): seq[seq[T]] =
|
||||||
## assert numbers.distribute(6)[0] == @[1, 2]
|
## assert numbers.distribute(6)[0] == @[1, 2]
|
||||||
## assert numbers.distribute(6)[5] == @[7]
|
## assert numbers.distribute(6)[5] == @[7]
|
||||||
assert(not s.isNil, "`s` can't be nil")
|
assert(not s.isNil, "`s` can't be nil")
|
||||||
assert(num > 0, "`num` has to be greater than zero")
|
|
||||||
if num < 2:
|
if num < 2:
|
||||||
result = @[s]
|
result = @[s]
|
||||||
return
|
return
|
||||||
|
|
||||||
|
let num = int(num) # XXX probably only needed because of .. bug
|
||||||
|
|
||||||
# Create the result and calculate the stride size and the remainder if any.
|
# Create the result and calculate the stride size and the remainder if any.
|
||||||
result = newSeq[seq[T]](num)
|
result = newSeq[seq[T]](num)
|
||||||
var
|
var
|
||||||
|
|
@ -587,4 +606,14 @@ when isMainModule:
|
||||||
seq2D[0][1] = true
|
seq2D[0][1] = true
|
||||||
doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
|
doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
|
||||||
|
|
||||||
|
block: # repeat tests
|
||||||
|
let
|
||||||
|
a = @[1, 2, 3]
|
||||||
|
b: seq[int] = @[]
|
||||||
|
|
||||||
|
doAssert a.repeat(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
|
||||||
|
doAssert a.repeat(0) == @[]
|
||||||
|
#doAssert a.repeat(-1) == @[] # will not compile!
|
||||||
|
doAssert b.repeat(3) == @[]
|
||||||
|
|
||||||
echo "Finished doc tests"
|
echo "Finished doc tests"
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,11 @@ proc mget*[A, B](t: var Table[A, B], key: A): var B =
|
||||||
var hc: THash
|
var hc: THash
|
||||||
var index = rawGet(t, key, hc)
|
var index = rawGet(t, key, hc)
|
||||||
if index >= 0: result = t.data[index].val
|
if index >= 0: result = t.data[index].val
|
||||||
else: raise newException(KeyError, "key not found: " & $key)
|
else:
|
||||||
|
when compiles($key):
|
||||||
|
raise newException(KeyError, "key not found: " & $key)
|
||||||
|
else:
|
||||||
|
raise newException(KeyError, "key not found")
|
||||||
|
|
||||||
iterator allValues*[A, B](t: Table[A, B]; key: A): B =
|
iterator allValues*[A, B](t: Table[A, B]; key: A): B =
|
||||||
## iterates over any value in the table `t` that belongs to the given `key`.
|
## iterates over any value in the table `t` that belongs to the given `key`.
|
||||||
|
|
|
||||||
|
|
@ -365,9 +365,9 @@ proc polar*(z: Complex): tuple[r, phi: float] =
|
||||||
result.phi = phase(z)
|
result.phi = phase(z)
|
||||||
|
|
||||||
proc rect*(r: float, phi: float): Complex =
|
proc rect*(r: float, phi: float): Complex =
|
||||||
## Returns the complex number with poolar coordinates `r` and `phi`.
|
## Returns the complex number with polar coordinates `r` and `phi`.
|
||||||
result.re = r * cos(phi)
|
result.re = r * cos(phi)
|
||||||
result.im = sin(phi)
|
result.im = r * sin(phi)
|
||||||
|
|
||||||
|
|
||||||
proc `$`*(z: Complex): string =
|
proc `$`*(z: Complex): string =
|
||||||
|
|
@ -438,5 +438,6 @@ when isMainModule:
|
||||||
assert( arccoth(a) =~ arctanh(1/a) )
|
assert( arccoth(a) =~ arctanh(1/a) )
|
||||||
|
|
||||||
assert( phase(a) == 1.1071487177940904 )
|
assert( phase(a) == 1.1071487177940904 )
|
||||||
assert( polar(a) =~ (2.23606797749979, 1.1071487177940904) )
|
var t = polar(a)
|
||||||
|
assert( rect(t.r, t.phi) =~ a )
|
||||||
assert( rect(1.0, 2.0) =~ (-0.4161468365471424, 0.9092974268256817) )
|
assert( rect(1.0, 2.0) =~ (-0.4161468365471424, 0.9092974268256817) )
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,8 @@
|
||||||
## proc hash(x: Something): THash =
|
## proc hash(x: Something): THash =
|
||||||
## ## Computes a THash from `x`.
|
## ## Computes a THash from `x`.
|
||||||
## var h: THash = 0
|
## var h: THash = 0
|
||||||
## h = h &! hash(x.foo)
|
## h = h !& hash(x.foo)
|
||||||
## h = h &! hash(x.bar)
|
## h = h !& hash(x.bar)
|
||||||
## result = !$h
|
## result = !$h
|
||||||
|
|
||||||
import
|
import
|
||||||
|
|
|
||||||
|
|
@ -390,8 +390,11 @@ proc request*(url: string, httpMethod: string, extraHeaders = "",
|
||||||
## server takes longer than specified an ETimeout exception will be raised.
|
## server takes longer than specified an ETimeout exception will be raised.
|
||||||
var r = if proxy == nil: parseUri(url) else: proxy.url
|
var r = if proxy == nil: parseUri(url) else: proxy.url
|
||||||
var headers = substr(httpMethod, len("http"))
|
var headers = substr(httpMethod, len("http"))
|
||||||
|
# TODO: Use generateHeaders further down once it supports proxies.
|
||||||
if proxy == nil:
|
if proxy == nil:
|
||||||
headers.add(" " & r.path)
|
headers.add ' '
|
||||||
|
if r.path[0] != '/': headers.add '/'
|
||||||
|
headers.add(r.path)
|
||||||
if r.query.len > 0:
|
if r.query.len > 0:
|
||||||
headers.add("?" & r.query)
|
headers.add("?" & r.query)
|
||||||
else:
|
else:
|
||||||
|
|
@ -567,9 +570,12 @@ proc downloadFile*(url: string, outputFilename: string,
|
||||||
|
|
||||||
proc generateHeaders(r: Uri, httpMethod: string,
|
proc generateHeaders(r: Uri, httpMethod: string,
|
||||||
headers: StringTableRef): string =
|
headers: StringTableRef): string =
|
||||||
|
# TODO: Use this in the blocking HttpClient once it supports proxies.
|
||||||
result = substr(httpMethod, len("http"))
|
result = substr(httpMethod, len("http"))
|
||||||
# TODO: Proxies
|
# TODO: Proxies
|
||||||
result.add(" " & r.path)
|
result.add ' '
|
||||||
|
if r.path[0] != '/': result.add '/'
|
||||||
|
result.add(r.path)
|
||||||
if r.query.len > 0:
|
if r.query.len > 0:
|
||||||
result.add("?" & r.query)
|
result.add("?" & r.query)
|
||||||
result.add(" HTTP/1.1\c\L")
|
result.add(" HTTP/1.1\c\L")
|
||||||
|
|
|
||||||
|
|
@ -816,7 +816,7 @@ proc copy*(p: JsonNode): JsonNode =
|
||||||
# ------------- pretty printing ----------------------------------------------
|
# ------------- pretty printing ----------------------------------------------
|
||||||
|
|
||||||
proc indent(s: var string, i: int) =
|
proc indent(s: var string, i: int) =
|
||||||
s.add(repeatChar(i))
|
s.add(spaces(i))
|
||||||
|
|
||||||
proc newIndent(curr, indent: int, ml: bool): int =
|
proc newIndent(curr, indent: int, ml: bool): int =
|
||||||
if ml: return curr + indent
|
if ml: return curr + indent
|
||||||
|
|
|
||||||
|
|
@ -165,5 +165,5 @@ proc getCurrentLine(L: BaseLexer, marker: bool = true): string =
|
||||||
inc(i)
|
inc(i)
|
||||||
add(result, "\n")
|
add(result, "\n")
|
||||||
if marker:
|
if marker:
|
||||||
add(result, repeatChar(getColNumber(L, L.bufpos)) & "^\n")
|
add(result, spaces(getColNumber(L, L.bufpos)) & "^\n")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,23 @@ type
|
||||||
TReadLineResult: ReadLineResult, TSOBool: SOBool, PSocket: Socket,
|
TReadLineResult: ReadLineResult, TSOBool: SOBool, PSocket: Socket,
|
||||||
TSocketImpl: SocketImpl].}
|
TSocketImpl: SocketImpl].}
|
||||||
|
|
||||||
|
type
|
||||||
|
IpAddressFamily* {.pure.} = enum ## Describes the type of an IP address
|
||||||
|
IPv6, ## IPv6 address
|
||||||
|
IPv4 ## IPv4 address
|
||||||
|
|
||||||
|
TIpAddress* = object ## stores an arbitrary IP address
|
||||||
|
case family*: IpAddressFamily ## the type of the IP address (IPv4 or IPv6)
|
||||||
|
of IpAddressFamily.IPv6:
|
||||||
|
address_v6*: array[0..15, uint8] ## Contains the IP address in bytes in
|
||||||
|
## case of IPv6
|
||||||
|
of IpAddressFamily.IPv4:
|
||||||
|
address_v4*: array[0..3, uint8] ## Contains the IP address in bytes in
|
||||||
|
## case of IPv4
|
||||||
|
|
||||||
|
proc isIpAddress*(address_str: string): bool {.tags: [].}
|
||||||
|
proc parseIpAddress*(address_str: string): TIpAddress
|
||||||
|
|
||||||
proc isDisconnectionError*(flags: set[SocketFlag],
|
proc isDisconnectionError*(flags: set[SocketFlag],
|
||||||
lastError: OSErrorCode): bool =
|
lastError: OSErrorCode): bool =
|
||||||
## Determines whether ``lastError`` is a disconnection error. Only does this
|
## Determines whether ``lastError`` is a disconnection error. Only does this
|
||||||
|
|
@ -511,6 +528,12 @@ proc connect*(socket: Socket, address: string, port = Port(0),
|
||||||
|
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
|
# RFC3546 for SNI specifies that IP addresses are not allowed.
|
||||||
|
if not isIpAddress(address):
|
||||||
|
# Discard result in case OpenSSL version doesn't support SNI, or we're
|
||||||
|
# not using TLSv1+
|
||||||
|
discard SSL_set_tlsext_host_name(socket.sslHandle, address)
|
||||||
|
|
||||||
let ret = SSLConnect(socket.sslHandle)
|
let ret = SSLConnect(socket.sslHandle)
|
||||||
socketError(socket, ret)
|
socketError(socket, ret)
|
||||||
|
|
||||||
|
|
@ -969,20 +992,6 @@ proc isSsl*(socket: Socket): bool =
|
||||||
proc getFd*(socket: Socket): SocketHandle = return socket.fd
|
proc getFd*(socket: Socket): SocketHandle = return socket.fd
|
||||||
## Returns the socket's file descriptor
|
## Returns the socket's file descriptor
|
||||||
|
|
||||||
type
|
|
||||||
IpAddressFamily* {.pure.} = enum ## Describes the type of an IP address
|
|
||||||
IPv6, ## IPv6 address
|
|
||||||
IPv4 ## IPv4 address
|
|
||||||
|
|
||||||
TIpAddress* = object ## stores an arbitrary IP address
|
|
||||||
case family*: IpAddressFamily ## the type of the IP address (IPv4 or IPv6)
|
|
||||||
of IpAddressFamily.IPv6:
|
|
||||||
address_v6*: array[0..15, uint8] ## Contains the IP address in bytes in
|
|
||||||
## case of IPv6
|
|
||||||
of IpAddressFamily.IPv4:
|
|
||||||
address_v4*: array[0..3, uint8] ## Contains the IP address in bytes in
|
|
||||||
## case of IPv4
|
|
||||||
|
|
||||||
proc IPv4_any*(): TIpAddress =
|
proc IPv4_any*(): TIpAddress =
|
||||||
## Returns the IPv4 any address, which can be used to listen on all available
|
## Returns the IPv4 any address, which can be used to listen on all available
|
||||||
## network adapters
|
## network adapters
|
||||||
|
|
@ -1241,7 +1250,7 @@ proc parseIPv6Address(address_str: string): TIpAddress =
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"Invalid IP Address. The address consists of too many groups")
|
"Invalid IP Address. The address consists of too many groups")
|
||||||
|
|
||||||
proc parseIpAddress*(address_str: string): TIpAddress =
|
proc parseIpAddress(address_str: string): TIpAddress =
|
||||||
## Parses an IP address
|
## Parses an IP address
|
||||||
## Raises EInvalidValue on error
|
## Raises EInvalidValue on error
|
||||||
if address_str == nil:
|
if address_str == nil:
|
||||||
|
|
@ -1250,3 +1259,13 @@ proc parseIpAddress*(address_str: string): TIpAddress =
|
||||||
return parseIPv6Address(address_str)
|
return parseIPv6Address(address_str)
|
||||||
else:
|
else:
|
||||||
return parseIPv4Address(address_str)
|
return parseIPv4Address(address_str)
|
||||||
|
|
||||||
|
|
||||||
|
proc isIpAddress(address_str: string): bool =
|
||||||
|
## Checks if a string is an IP address
|
||||||
|
## Returns true if it is, false otherwise
|
||||||
|
try:
|
||||||
|
discard parseIpAddress(address_str)
|
||||||
|
except ValueError:
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,12 @@
|
||||||
## It supports one convenience iterator over all command line options and some
|
## It supports one convenience iterator over all command line options and some
|
||||||
## lower-level features.
|
## lower-level features.
|
||||||
##
|
##
|
||||||
## **Deprecated since version 0.9.3:** Use the `parseopt2 <parseopt2.html>`_
|
## Supported syntax:
|
||||||
## module instead as this version has issues with spaces in arguments.
|
##
|
||||||
{.deprecated.}
|
## 1. short options - ``-abcd``, where a, b, c, d are names
|
||||||
|
## 2. long option - ``--foo:bar``, ``--foo=bar`` or ``--foo``
|
||||||
|
## 3. argument - everything else
|
||||||
|
|
||||||
{.push debugger: off.}
|
{.push debugger: off.}
|
||||||
|
|
||||||
include "system/inclrtl"
|
include "system/inclrtl"
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,7 @@ proc open*(my: var XmlParser, input: Stream, filename: string,
|
||||||
my.kind = xmlError
|
my.kind = xmlError
|
||||||
my.a = ""
|
my.a = ""
|
||||||
my.b = ""
|
my.b = ""
|
||||||
|
my.c = nil
|
||||||
my.options = options
|
my.options = options
|
||||||
|
|
||||||
proc close*(my: var XmlParser) {.inline.} =
|
proc close*(my: var XmlParser) {.inline.} =
|
||||||
|
|
@ -138,43 +139,43 @@ proc kind*(my: XmlParser): XmlEventKind {.inline.} =
|
||||||
## returns the current event type for the XML parser
|
## returns the current event type for the XML parser
|
||||||
return my.kind
|
return my.kind
|
||||||
|
|
||||||
proc charData*(my: XmlParser): string {.inline.} =
|
template charData*(my: XmlParser): string =
|
||||||
## returns the character data for the events: ``xmlCharData``,
|
## returns the character data for the events: ``xmlCharData``,
|
||||||
## ``xmlWhitespace``, ``xmlComment``, ``xmlCData``, ``xmlSpecial``
|
## ``xmlWhitespace``, ``xmlComment``, ``xmlCData``, ``xmlSpecial``
|
||||||
assert(my.kind in {xmlCharData, xmlWhitespace, xmlComment, xmlCData,
|
assert(my.kind in {xmlCharData, xmlWhitespace, xmlComment, xmlCData,
|
||||||
xmlSpecial})
|
xmlSpecial})
|
||||||
return my.a
|
my.a
|
||||||
|
|
||||||
proc elementName*(my: XmlParser): string {.inline.} =
|
template elementName*(my: XmlParser): string =
|
||||||
## returns the element name for the events: ``xmlElementStart``,
|
## returns the element name for the events: ``xmlElementStart``,
|
||||||
## ``xmlElementEnd``, ``xmlElementOpen``
|
## ``xmlElementEnd``, ``xmlElementOpen``
|
||||||
assert(my.kind in {xmlElementStart, xmlElementEnd, xmlElementOpen})
|
assert(my.kind in {xmlElementStart, xmlElementEnd, xmlElementOpen})
|
||||||
return my.a
|
my.a
|
||||||
|
|
||||||
proc entityName*(my: XmlParser): string {.inline.} =
|
template entityName*(my: XmlParser): string =
|
||||||
## returns the entity name for the event: ``xmlEntity``
|
## returns the entity name for the event: ``xmlEntity``
|
||||||
assert(my.kind == xmlEntity)
|
assert(my.kind == xmlEntity)
|
||||||
return my.a
|
my.a
|
||||||
|
|
||||||
proc attrKey*(my: XmlParser): string {.inline.} =
|
template attrKey*(my: XmlParser): string =
|
||||||
## returns the attribute key for the event ``xmlAttribute``
|
## returns the attribute key for the event ``xmlAttribute``
|
||||||
assert(my.kind == xmlAttribute)
|
assert(my.kind == xmlAttribute)
|
||||||
return my.a
|
my.a
|
||||||
|
|
||||||
proc attrValue*(my: XmlParser): string {.inline.} =
|
template attrValue*(my: XmlParser): string =
|
||||||
## returns the attribute value for the event ``xmlAttribute``
|
## returns the attribute value for the event ``xmlAttribute``
|
||||||
assert(my.kind == xmlAttribute)
|
assert(my.kind == xmlAttribute)
|
||||||
return my.b
|
my.b
|
||||||
|
|
||||||
proc piName*(my: XmlParser): string {.inline.} =
|
template piName*(my: XmlParser): string =
|
||||||
## returns the processing instruction name for the event ``xmlPI``
|
## returns the processing instruction name for the event ``xmlPI``
|
||||||
assert(my.kind == xmlPI)
|
assert(my.kind == xmlPI)
|
||||||
return my.a
|
my.a
|
||||||
|
|
||||||
proc piRest*(my: XmlParser): string {.inline.} =
|
template piRest*(my: XmlParser): string =
|
||||||
## returns the rest of the processing instruction for the event ``xmlPI``
|
## returns the rest of the processing instruction for the event ``xmlPI``
|
||||||
assert(my.kind == xmlPI)
|
assert(my.kind == xmlPI)
|
||||||
return my.b
|
my.b
|
||||||
|
|
||||||
proc rawData*(my: XmlParser): string {.inline.} =
|
proc rawData*(my: XmlParser): string {.inline.} =
|
||||||
## returns the underlying 'data' string by reference.
|
## returns the underlying 'data' string by reference.
|
||||||
|
|
@ -621,7 +622,7 @@ proc next*(my: var XmlParser) =
|
||||||
of stateEmptyElementTag:
|
of stateEmptyElementTag:
|
||||||
my.state = stateNormal
|
my.state = stateNormal
|
||||||
my.kind = xmlElementEnd
|
my.kind = xmlElementEnd
|
||||||
if not isNil(my.c):
|
if not my.c.isNil:
|
||||||
my.a = my.c
|
my.a = my.c
|
||||||
of stateError:
|
of stateError:
|
||||||
my.kind = xmlError
|
my.kind = xmlError
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ when useUnicode:
|
||||||
const
|
const
|
||||||
InlineThreshold = 5 ## number of leaves; -1 to disable inlining
|
InlineThreshold = 5 ## number of leaves; -1 to disable inlining
|
||||||
MaxSubpatterns* = 20 ## defines the maximum number of subpatterns that
|
MaxSubpatterns* = 20 ## defines the maximum number of subpatterns that
|
||||||
## can be captured. More subpatterns cannot be captured!
|
## can be captured. More subpatterns cannot be captured!
|
||||||
|
|
||||||
type
|
type
|
||||||
PegKind = enum
|
PegKind = enum
|
||||||
|
|
@ -85,14 +85,14 @@ type
|
||||||
of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns]
|
of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns]
|
||||||
else: sons: seq[TNode]
|
else: sons: seq[TNode]
|
||||||
NonTerminal* = ref NonTerminalObj
|
NonTerminal* = ref NonTerminalObj
|
||||||
|
|
||||||
Peg* = TNode ## type that represents a PEG
|
Peg* = TNode ## type that represents a PEG
|
||||||
|
|
||||||
{.deprecated: [TPeg: Peg].}
|
{.deprecated: [TPeg: Peg].}
|
||||||
|
|
||||||
proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} =
|
proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} =
|
||||||
## constructs a PEG from a terminal string
|
## constructs a PEG from a terminal string
|
||||||
if t.len != 1:
|
if t.len != 1:
|
||||||
result.kind = pkTerminal
|
result.kind = pkTerminal
|
||||||
result.term = t
|
result.term = t
|
||||||
else:
|
else:
|
||||||
|
|
@ -116,7 +116,7 @@ proc term*(t: char): Peg {.nosideEffect, rtl, extern: "npegs$1Char".} =
|
||||||
assert t != '\0'
|
assert t != '\0'
|
||||||
result.kind = pkChar
|
result.kind = pkChar
|
||||||
result.ch = t
|
result.ch = t
|
||||||
|
|
||||||
proc charSet*(s: set[char]): Peg {.nosideEffect, rtl, extern: "npegs$1".} =
|
proc charSet*(s: set[char]): Peg {.nosideEffect, rtl, extern: "npegs$1".} =
|
||||||
## constructs a PEG from a character set `s`
|
## constructs a PEG from a character set `s`
|
||||||
assert '\0' notin s
|
assert '\0' notin s
|
||||||
|
|
@ -129,12 +129,12 @@ proc add(d: var Peg, s: Peg) {.inline.} = add(d.sons, s)
|
||||||
|
|
||||||
proc addChoice(dest: var Peg, elem: Peg) =
|
proc addChoice(dest: var Peg, elem: Peg) =
|
||||||
var L = dest.len-1
|
var L = dest.len-1
|
||||||
if L >= 0 and dest.sons[L].kind == pkCharChoice:
|
if L >= 0 and dest.sons[L].kind == pkCharChoice:
|
||||||
# caution! Do not introduce false aliasing here!
|
# caution! Do not introduce false aliasing here!
|
||||||
case elem.kind
|
case elem.kind
|
||||||
of pkCharChoice:
|
of pkCharChoice:
|
||||||
dest.sons[L] = charSet(dest.sons[L].charChoice[] + elem.charChoice[])
|
dest.sons[L] = charSet(dest.sons[L].charChoice[] + elem.charChoice[])
|
||||||
of pkChar:
|
of pkChar:
|
||||||
dest.sons[L] = charSet(dest.sons[L].charChoice[] + {elem.ch})
|
dest.sons[L] = charSet(dest.sons[L].charChoice[] + {elem.ch})
|
||||||
else: add(dest, elem)
|
else: add(dest, elem)
|
||||||
else: add(dest, elem)
|
else: add(dest, elem)
|
||||||
|
|
@ -158,12 +158,12 @@ proc `/`*(a: varargs[Peg]): Peg {.
|
||||||
|
|
||||||
proc addSequence(dest: var Peg, elem: Peg) =
|
proc addSequence(dest: var Peg, elem: Peg) =
|
||||||
var L = dest.len-1
|
var L = dest.len-1
|
||||||
if L >= 0 and dest.sons[L].kind == pkTerminal:
|
if L >= 0 and dest.sons[L].kind == pkTerminal:
|
||||||
# caution! Do not introduce false aliasing here!
|
# caution! Do not introduce false aliasing here!
|
||||||
case elem.kind
|
case elem.kind
|
||||||
of pkTerminal:
|
of pkTerminal:
|
||||||
dest.sons[L] = term(dest.sons[L].term & elem.term)
|
dest.sons[L] = term(dest.sons[L].term & elem.term)
|
||||||
of pkChar:
|
of pkChar:
|
||||||
dest.sons[L] = term(dest.sons[L].term & elem.ch)
|
dest.sons[L] = term(dest.sons[L].term & elem.ch)
|
||||||
else: add(dest, elem)
|
else: add(dest, elem)
|
||||||
else: add(dest, elem)
|
else: add(dest, elem)
|
||||||
|
|
@ -172,7 +172,7 @@ proc sequence*(a: varargs[Peg]): Peg {.
|
||||||
nosideEffect, rtl, extern: "npegs$1".} =
|
nosideEffect, rtl, extern: "npegs$1".} =
|
||||||
## constructs a sequence with all the PEGs from `a`
|
## constructs a sequence with all the PEGs from `a`
|
||||||
multipleOp(pkSequence, addSequence)
|
multipleOp(pkSequence, addSequence)
|
||||||
|
|
||||||
proc `?`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsOptional".} =
|
proc `?`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsOptional".} =
|
||||||
## constructs an optional for the PEG `a`
|
## constructs an optional for the PEG `a`
|
||||||
if a.kind in {pkOption, pkGreedyRep, pkGreedyAny, pkGreedyRepChar,
|
if a.kind in {pkOption, pkGreedyRep, pkGreedyAny, pkGreedyRepChar,
|
||||||
|
|
@ -207,7 +207,7 @@ proc `!*`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsSearch".} =
|
||||||
result.kind = pkSearch
|
result.kind = pkSearch
|
||||||
result.sons = @[a]
|
result.sons = @[a]
|
||||||
|
|
||||||
proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl,
|
proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl,
|
||||||
extern: "npgegsCapturedSearch".} =
|
extern: "npgegsCapturedSearch".} =
|
||||||
## constructs a "captured search" for the PEG `a`
|
## constructs a "captured search" for the PEG `a`
|
||||||
result.kind = pkCapturedSearch
|
result.kind = pkCapturedSearch
|
||||||
|
|
@ -216,7 +216,7 @@ proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl,
|
||||||
proc `+`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsGreedyPosRep".} =
|
proc `+`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsGreedyPosRep".} =
|
||||||
## constructs a "greedy positive repetition" with the PEG `a`
|
## constructs a "greedy positive repetition" with the PEG `a`
|
||||||
return sequence(a, *a)
|
return sequence(a, *a)
|
||||||
|
|
||||||
proc `&`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsAndPredicate".} =
|
proc `&`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsAndPredicate".} =
|
||||||
## constructs an "and predicate" with the PEG `a`
|
## constructs an "and predicate" with the PEG `a`
|
||||||
result.kind = pkAndPredicate
|
result.kind = pkAndPredicate
|
||||||
|
|
@ -239,33 +239,33 @@ proc newLine*: Peg {.inline.} =
|
||||||
## constructs the PEG `newline`:idx: (``\n``)
|
## constructs the PEG `newline`:idx: (``\n``)
|
||||||
result.kind = pkNewLine
|
result.kind = pkNewLine
|
||||||
|
|
||||||
proc unicodeLetter*: Peg {.inline.} =
|
proc unicodeLetter*: Peg {.inline.} =
|
||||||
## constructs the PEG ``\letter`` which matches any Unicode letter.
|
## constructs the PEG ``\letter`` which matches any Unicode letter.
|
||||||
result.kind = pkLetter
|
result.kind = pkLetter
|
||||||
|
|
||||||
proc unicodeLower*: Peg {.inline.} =
|
|
||||||
## constructs the PEG ``\lower`` which matches any Unicode lowercase letter.
|
|
||||||
result.kind = pkLower
|
|
||||||
|
|
||||||
proc unicodeUpper*: Peg {.inline.} =
|
proc unicodeLower*: Peg {.inline.} =
|
||||||
|
## constructs the PEG ``\lower`` which matches any Unicode lowercase letter.
|
||||||
|
result.kind = pkLower
|
||||||
|
|
||||||
|
proc unicodeUpper*: Peg {.inline.} =
|
||||||
## constructs the PEG ``\upper`` which matches any Unicode uppercase letter.
|
## constructs the PEG ``\upper`` which matches any Unicode uppercase letter.
|
||||||
result.kind = pkUpper
|
result.kind = pkUpper
|
||||||
|
|
||||||
proc unicodeTitle*: Peg {.inline.} =
|
proc unicodeTitle*: Peg {.inline.} =
|
||||||
## constructs the PEG ``\title`` which matches any Unicode title letter.
|
## constructs the PEG ``\title`` which matches any Unicode title letter.
|
||||||
result.kind = pkTitle
|
result.kind = pkTitle
|
||||||
|
|
||||||
proc unicodeWhitespace*: Peg {.inline.} =
|
proc unicodeWhitespace*: Peg {.inline.} =
|
||||||
## constructs the PEG ``\white`` which matches any Unicode
|
## constructs the PEG ``\white`` which matches any Unicode
|
||||||
## whitespace character.
|
## whitespace character.
|
||||||
result.kind = pkWhitespace
|
result.kind = pkWhitespace
|
||||||
|
|
||||||
proc startAnchor*: Peg {.inline.} =
|
proc startAnchor*: Peg {.inline.} =
|
||||||
## constructs the PEG ``^`` which matches the start of the input.
|
## constructs the PEG ``^`` which matches the start of the input.
|
||||||
result.kind = pkStartAnchor
|
result.kind = pkStartAnchor
|
||||||
|
|
||||||
proc endAnchor*: Peg {.inline.} =
|
proc endAnchor*: Peg {.inline.} =
|
||||||
## constructs the PEG ``$`` which matches the end of the input.
|
## constructs the PEG ``$`` which matches the end of the input.
|
||||||
result = !any()
|
result = !any()
|
||||||
|
|
||||||
proc capture*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsCapture".} =
|
proc capture*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsCapture".} =
|
||||||
|
|
@ -274,21 +274,21 @@ proc capture*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsCapture".} =
|
||||||
result.sons = @[a]
|
result.sons = @[a]
|
||||||
|
|
||||||
proc backref*(index: range[1..MaxSubpatterns]): Peg {.
|
proc backref*(index: range[1..MaxSubpatterns]): Peg {.
|
||||||
nosideEffect, rtl, extern: "npegs$1".} =
|
nosideEffect, rtl, extern: "npegs$1".} =
|
||||||
## constructs a back reference of the given `index`. `index` starts counting
|
## constructs a back reference of the given `index`. `index` starts counting
|
||||||
## from 1.
|
## from 1.
|
||||||
result.kind = pkBackRef
|
result.kind = pkBackRef
|
||||||
result.index = index-1
|
result.index = index-1
|
||||||
|
|
||||||
proc backrefIgnoreCase*(index: range[1..MaxSubpatterns]): Peg {.
|
proc backrefIgnoreCase*(index: range[1..MaxSubpatterns]): Peg {.
|
||||||
nosideEffect, rtl, extern: "npegs$1".} =
|
nosideEffect, rtl, extern: "npegs$1".} =
|
||||||
## constructs a back reference of the given `index`. `index` starts counting
|
## constructs a back reference of the given `index`. `index` starts counting
|
||||||
## from 1. Ignores case for matching.
|
## from 1. Ignores case for matching.
|
||||||
result.kind = pkBackRefIgnoreCase
|
result.kind = pkBackRefIgnoreCase
|
||||||
result.index = index-1
|
result.index = index-1
|
||||||
|
|
||||||
proc backrefIgnoreStyle*(index: range[1..MaxSubpatterns]): Peg {.
|
proc backrefIgnoreStyle*(index: range[1..MaxSubpatterns]): Peg {.
|
||||||
nosideEffect, rtl, extern: "npegs$1".}=
|
nosideEffect, rtl, extern: "npegs$1".}=
|
||||||
## constructs a back reference of the given `index`. `index` starts counting
|
## constructs a back reference of the given `index`. `index` starts counting
|
||||||
## from 1. Ignores style for matching.
|
## from 1. Ignores style for matching.
|
||||||
result.kind = pkBackRefIgnoreStyle
|
result.kind = pkBackRefIgnoreStyle
|
||||||
|
|
@ -298,7 +298,7 @@ proc spaceCost(n: Peg): int =
|
||||||
case n.kind
|
case n.kind
|
||||||
of pkEmpty: discard
|
of pkEmpty: discard
|
||||||
of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar,
|
of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar,
|
||||||
pkGreedyRepChar, pkCharChoice, pkGreedyRepSet,
|
pkGreedyRepChar, pkCharChoice, pkGreedyRepSet,
|
||||||
pkAny..pkWhitespace, pkGreedyAny:
|
pkAny..pkWhitespace, pkGreedyAny:
|
||||||
result = 1
|
result = 1
|
||||||
of pkNonTerminal:
|
of pkNonTerminal:
|
||||||
|
|
@ -310,7 +310,7 @@ proc spaceCost(n: Peg): int =
|
||||||
if result >= InlineThreshold: break
|
if result >= InlineThreshold: break
|
||||||
|
|
||||||
proc nonterminal*(n: NonTerminal): Peg {.
|
proc nonterminal*(n: NonTerminal): Peg {.
|
||||||
nosideEffect, rtl, extern: "npegs$1".} =
|
nosideEffect, rtl, extern: "npegs$1".} =
|
||||||
## constructs a PEG that consists of the nonterminal symbol
|
## constructs a PEG that consists of the nonterminal symbol
|
||||||
assert n != nil
|
assert n != nil
|
||||||
if ntDeclared in n.flags and spaceCost(n.rule) < InlineThreshold:
|
if ntDeclared in n.flags and spaceCost(n.rule) < InlineThreshold:
|
||||||
|
|
@ -331,7 +331,7 @@ proc newNonTerminal*(name: string, line, column: int): NonTerminal {.
|
||||||
template letters*: expr =
|
template letters*: expr =
|
||||||
## expands to ``charset({'A'..'Z', 'a'..'z'})``
|
## expands to ``charset({'A'..'Z', 'a'..'z'})``
|
||||||
charSet({'A'..'Z', 'a'..'z'})
|
charSet({'A'..'Z', 'a'..'z'})
|
||||||
|
|
||||||
template digits*: expr =
|
template digits*: expr =
|
||||||
## expands to ``charset({'0'..'9'})``
|
## expands to ``charset({'0'..'9'})``
|
||||||
charSet({'0'..'9'})
|
charSet({'0'..'9'})
|
||||||
|
|
@ -339,11 +339,11 @@ template digits*: expr =
|
||||||
template whitespace*: expr =
|
template whitespace*: expr =
|
||||||
## expands to ``charset({' ', '\9'..'\13'})``
|
## expands to ``charset({' ', '\9'..'\13'})``
|
||||||
charSet({' ', '\9'..'\13'})
|
charSet({' ', '\9'..'\13'})
|
||||||
|
|
||||||
template identChars*: expr =
|
template identChars*: expr =
|
||||||
## expands to ``charset({'a'..'z', 'A'..'Z', '0'..'9', '_'})``
|
## expands to ``charset({'a'..'z', 'A'..'Z', '0'..'9', '_'})``
|
||||||
charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'})
|
charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'})
|
||||||
|
|
||||||
template identStartChars*: expr =
|
template identStartChars*: expr =
|
||||||
## expands to ``charset({'A'..'Z', 'a'..'z', '_'})``
|
## expands to ``charset({'A'..'Z', 'a'..'z', '_'})``
|
||||||
charSet({'a'..'z', 'A'..'Z', '_'})
|
charSet({'a'..'z', 'A'..'Z', '_'})
|
||||||
|
|
@ -352,14 +352,14 @@ template ident*: expr =
|
||||||
## same as ``[a-zA-Z_][a-zA-z_0-9]*``; standard identifier
|
## same as ``[a-zA-Z_][a-zA-z_0-9]*``; standard identifier
|
||||||
sequence(charSet({'a'..'z', 'A'..'Z', '_'}),
|
sequence(charSet({'a'..'z', 'A'..'Z', '_'}),
|
||||||
*charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'}))
|
*charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'}))
|
||||||
|
|
||||||
template natural*: expr =
|
template natural*: expr =
|
||||||
## same as ``\d+``
|
## same as ``\d+``
|
||||||
+digits
|
+digits
|
||||||
|
|
||||||
# ------------------------- debugging -----------------------------------------
|
# ------------------------- debugging -----------------------------------------
|
||||||
|
|
||||||
proc esc(c: char, reserved = {'\0'..'\255'}): string =
|
proc esc(c: char, reserved = {'\0'..'\255'}): string =
|
||||||
case c
|
case c
|
||||||
of '\b': result = "\\b"
|
of '\b': result = "\\b"
|
||||||
of '\t': result = "\\t"
|
of '\t': result = "\\t"
|
||||||
|
|
@ -374,38 +374,38 @@ proc esc(c: char, reserved = {'\0'..'\255'}): string =
|
||||||
elif c < ' ' or c >= '\128': result = '\\' & $ord(c)
|
elif c < ' ' or c >= '\128': result = '\\' & $ord(c)
|
||||||
elif c in reserved: result = '\\' & c
|
elif c in reserved: result = '\\' & c
|
||||||
else: result = $c
|
else: result = $c
|
||||||
|
|
||||||
proc singleQuoteEsc(c: char): string = return "'" & esc(c, {'\''}) & "'"
|
proc singleQuoteEsc(c: char): string = return "'" & esc(c, {'\''}) & "'"
|
||||||
|
|
||||||
proc singleQuoteEsc(str: string): string =
|
proc singleQuoteEsc(str: string): string =
|
||||||
result = "'"
|
result = "'"
|
||||||
for c in items(str): add result, esc(c, {'\''})
|
for c in items(str): add result, esc(c, {'\''})
|
||||||
add result, '\''
|
add result, '\''
|
||||||
|
|
||||||
proc charSetEscAux(cc: set[char]): string =
|
proc charSetEscAux(cc: set[char]): string =
|
||||||
const reserved = {'^', '-', ']'}
|
const reserved = {'^', '-', ']'}
|
||||||
result = ""
|
result = ""
|
||||||
var c1 = 0
|
var c1 = 0
|
||||||
while c1 <= 0xff:
|
while c1 <= 0xff:
|
||||||
if chr(c1) in cc:
|
if chr(c1) in cc:
|
||||||
var c2 = c1
|
var c2 = c1
|
||||||
while c2 < 0xff and chr(succ(c2)) in cc: inc(c2)
|
while c2 < 0xff and chr(succ(c2)) in cc: inc(c2)
|
||||||
if c1 == c2:
|
if c1 == c2:
|
||||||
add result, esc(chr(c1), reserved)
|
add result, esc(chr(c1), reserved)
|
||||||
elif c2 == succ(c1):
|
elif c2 == succ(c1):
|
||||||
add result, esc(chr(c1), reserved) & esc(chr(c2), reserved)
|
add result, esc(chr(c1), reserved) & esc(chr(c2), reserved)
|
||||||
else:
|
else:
|
||||||
add result, esc(chr(c1), reserved) & '-' & esc(chr(c2), reserved)
|
add result, esc(chr(c1), reserved) & '-' & esc(chr(c2), reserved)
|
||||||
c1 = c2
|
c1 = c2
|
||||||
inc(c1)
|
inc(c1)
|
||||||
|
|
||||||
proc charSetEsc(cc: set[char]): string =
|
proc charSetEsc(cc: set[char]): string =
|
||||||
if card(cc) >= 128+64:
|
if card(cc) >= 128+64:
|
||||||
result = "[^" & charSetEscAux({'\1'..'\xFF'} - cc) & ']'
|
result = "[^" & charSetEscAux({'\1'..'\xFF'} - cc) & ']'
|
||||||
else:
|
else:
|
||||||
result = '[' & charSetEscAux(cc) & ']'
|
result = '[' & charSetEscAux(cc) & ']'
|
||||||
|
|
||||||
proc toStrAux(r: Peg, res: var string) =
|
proc toStrAux(r: Peg, res: var string) =
|
||||||
case r.kind
|
case r.kind
|
||||||
of pkEmpty: add(res, "()")
|
of pkEmpty: add(res, "()")
|
||||||
of pkAny: add(res, '.')
|
of pkAny: add(res, '.')
|
||||||
|
|
@ -469,25 +469,25 @@ proc toStrAux(r: Peg, res: var string) =
|
||||||
toStrAux(r.sons[0], res)
|
toStrAux(r.sons[0], res)
|
||||||
of pkCapture:
|
of pkCapture:
|
||||||
add(res, '{')
|
add(res, '{')
|
||||||
toStrAux(r.sons[0], res)
|
toStrAux(r.sons[0], res)
|
||||||
add(res, '}')
|
add(res, '}')
|
||||||
of pkBackRef:
|
of pkBackRef:
|
||||||
add(res, '$')
|
add(res, '$')
|
||||||
add(res, $r.index)
|
add(res, $r.index)
|
||||||
of pkBackRefIgnoreCase:
|
of pkBackRefIgnoreCase:
|
||||||
add(res, "i$")
|
add(res, "i$")
|
||||||
add(res, $r.index)
|
add(res, $r.index)
|
||||||
of pkBackRefIgnoreStyle:
|
of pkBackRefIgnoreStyle:
|
||||||
add(res, "y$")
|
add(res, "y$")
|
||||||
add(res, $r.index)
|
add(res, $r.index)
|
||||||
of pkRule:
|
of pkRule:
|
||||||
toStrAux(r.sons[0], res)
|
toStrAux(r.sons[0], res)
|
||||||
add(res, " <- ")
|
add(res, " <- ")
|
||||||
toStrAux(r.sons[1], res)
|
toStrAux(r.sons[1], res)
|
||||||
of pkList:
|
of pkList:
|
||||||
for i in 0 .. high(r.sons):
|
for i in 0 .. high(r.sons):
|
||||||
toStrAux(r.sons[i], res)
|
toStrAux(r.sons[i], res)
|
||||||
add(res, "\n")
|
add(res, "\n")
|
||||||
of pkStartAnchor:
|
of pkStartAnchor:
|
||||||
add(res, '^')
|
add(res, '^')
|
||||||
|
|
||||||
|
|
@ -506,8 +506,8 @@ type
|
||||||
|
|
||||||
{.deprecated: [TCaptures: Captures].}
|
{.deprecated: [TCaptures: Captures].}
|
||||||
|
|
||||||
proc bounds*(c: Captures,
|
proc bounds*(c: Captures,
|
||||||
i: range[0..MaxSubpatterns-1]): tuple[first, last: int] =
|
i: range[0..MaxSubpatterns-1]): tuple[first, last: int] =
|
||||||
## returns the bounds ``[first..last]`` of the `i`'th capture.
|
## returns the bounds ``[first..last]`` of the `i`'th capture.
|
||||||
result = c.matches[i]
|
result = c.matches[i]
|
||||||
|
|
||||||
|
|
@ -527,7 +527,7 @@ when not useUnicode:
|
||||||
|
|
||||||
proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||||
nosideEffect, rtl, extern: "npegs$1".} =
|
nosideEffect, rtl, extern: "npegs$1".} =
|
||||||
## low-level matching proc that implements the PEG interpreter. Use this
|
## low-level matching proc that implements the PEG interpreter. Use this
|
||||||
## for maximum efficiency (every other PEG operation ends up calling this
|
## for maximum efficiency (every other PEG operation ends up calling this
|
||||||
## proc).
|
## proc).
|
||||||
## Returns -1 if it does not match, else the length of the match
|
## Returns -1 if it does not match, else the length of the match
|
||||||
|
|
@ -541,7 +541,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||||
result = runeLenAt(s, start)
|
result = runeLenAt(s, start)
|
||||||
else:
|
else:
|
||||||
result = -1
|
result = -1
|
||||||
of pkLetter:
|
of pkLetter:
|
||||||
if s[start] != '\0':
|
if s[start] != '\0':
|
||||||
var a: Rune
|
var a: Rune
|
||||||
result = start
|
result = start
|
||||||
|
|
@ -550,7 +550,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||||
else: result = -1
|
else: result = -1
|
||||||
else:
|
else:
|
||||||
result = -1
|
result = -1
|
||||||
of pkLower:
|
of pkLower:
|
||||||
if s[start] != '\0':
|
if s[start] != '\0':
|
||||||
var a: Rune
|
var a: Rune
|
||||||
result = start
|
result = start
|
||||||
|
|
@ -559,7 +559,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||||
else: result = -1
|
else: result = -1
|
||||||
else:
|
else:
|
||||||
result = -1
|
result = -1
|
||||||
of pkUpper:
|
of pkUpper:
|
||||||
if s[start] != '\0':
|
if s[start] != '\0':
|
||||||
var a: Rune
|
var a: Rune
|
||||||
result = start
|
result = start
|
||||||
|
|
@ -568,16 +568,16 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||||
else: result = -1
|
else: result = -1
|
||||||
else:
|
else:
|
||||||
result = -1
|
result = -1
|
||||||
of pkTitle:
|
of pkTitle:
|
||||||
if s[start] != '\0':
|
if s[start] != '\0':
|
||||||
var a: Rune
|
var a: Rune
|
||||||
result = start
|
result = start
|
||||||
fastRuneAt(s, result, a)
|
fastRuneAt(s, result, a)
|
||||||
if isTitle(a): dec(result, start)
|
if isTitle(a): dec(result, start)
|
||||||
else: result = -1
|
else: result = -1
|
||||||
else:
|
else:
|
||||||
result = -1
|
result = -1
|
||||||
of pkWhitespace:
|
of pkWhitespace:
|
||||||
if s[start] != '\0':
|
if s[start] != '\0':
|
||||||
var a: Rune
|
var a: Rune
|
||||||
result = start
|
result = start
|
||||||
|
|
@ -641,7 +641,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||||
when false: echo "leave: ", p.nt.name
|
when false: echo "leave: ", p.nt.name
|
||||||
if result < 0: c.ml = oldMl
|
if result < 0: c.ml = oldMl
|
||||||
of pkSequence:
|
of pkSequence:
|
||||||
var oldMl = c.ml
|
var oldMl = c.ml
|
||||||
result = 0
|
result = 0
|
||||||
for i in 0..high(p.sons):
|
for i in 0..high(p.sons):
|
||||||
var x = rawMatch(s, p.sons[i], start+result, c)
|
var x = rawMatch(s, p.sons[i], start+result, c)
|
||||||
|
|
@ -723,11 +723,11 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
|
||||||
#else: silently ignore the capture
|
#else: silently ignore the capture
|
||||||
else:
|
else:
|
||||||
c.ml = idx
|
c.ml = idx
|
||||||
of pkBackRef..pkBackRefIgnoreStyle:
|
of pkBackRef..pkBackRefIgnoreStyle:
|
||||||
if p.index >= c.ml: return -1
|
if p.index >= c.ml: return -1
|
||||||
var (a, b) = c.matches[p.index]
|
var (a, b) = c.matches[p.index]
|
||||||
var n: Peg
|
var n: Peg
|
||||||
n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef))
|
n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef))
|
||||||
n.term = s.substr(a, b)
|
n.term = s.substr(a, b)
|
||||||
result = rawMatch(s, n, start, c)
|
result = rawMatch(s, n, start, c)
|
||||||
of pkStartAnchor:
|
of pkStartAnchor:
|
||||||
|
|
@ -755,7 +755,7 @@ proc match*(s: string, pattern: Peg, matches: var openArray[string],
|
||||||
result = rawMatch(s, pattern, start, c) == len(s) - start
|
result = rawMatch(s, pattern, start, c) == len(s) - start
|
||||||
if result: fillMatches(s, matches, c)
|
if result: fillMatches(s, matches, c)
|
||||||
|
|
||||||
proc match*(s: string, pattern: Peg,
|
proc match*(s: string, pattern: Peg,
|
||||||
start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} =
|
start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} =
|
||||||
## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``.
|
## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``.
|
||||||
var c: Captures
|
var c: Captures
|
||||||
|
|
@ -773,7 +773,7 @@ proc matchLen*(s: string, pattern: Peg, matches: var openArray[string],
|
||||||
result = rawMatch(s, pattern, start, c)
|
result = rawMatch(s, pattern, start, c)
|
||||||
if result >= 0: fillMatches(s, matches, c)
|
if result >= 0: fillMatches(s, matches, c)
|
||||||
|
|
||||||
proc matchLen*(s: string, pattern: Peg,
|
proc matchLen*(s: string, pattern: Peg,
|
||||||
start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
|
start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
|
||||||
## the same as ``match``, but it returns the length of the match,
|
## the same as ``match``, but it returns the length of the match,
|
||||||
## if there is no match, -1 is returned. Note that a match length
|
## if there is no match, -1 is returned. Note that a match length
|
||||||
|
|
@ -797,11 +797,11 @@ proc find*(s: string, pattern: Peg, matches: var openArray[string],
|
||||||
return i
|
return i
|
||||||
return -1
|
return -1
|
||||||
# could also use the pattern here: (!P .)* P
|
# could also use the pattern here: (!P .)* P
|
||||||
|
|
||||||
proc findBounds*(s: string, pattern: Peg, matches: var openArray[string],
|
proc findBounds*(s: string, pattern: Peg, matches: var openArray[string],
|
||||||
start = 0): tuple[first, last: int] {.
|
start = 0): tuple[first, last: int] {.
|
||||||
nosideEffect, rtl, extern: "npegs$1Capture".} =
|
nosideEffect, rtl, extern: "npegs$1Capture".} =
|
||||||
## returns the starting position and end position of ``pattern`` in ``s``
|
## returns the starting position and end position of ``pattern`` in ``s``
|
||||||
## and the captured
|
## and the captured
|
||||||
## substrings in the array ``matches``. If it does not match, nothing
|
## substrings in the array ``matches``. If it does not match, nothing
|
||||||
## is written into ``matches`` and (-1,0) is returned.
|
## is written into ``matches`` and (-1,0) is returned.
|
||||||
|
|
@ -814,8 +814,8 @@ proc findBounds*(s: string, pattern: Peg, matches: var openArray[string],
|
||||||
fillMatches(s, matches, c)
|
fillMatches(s, matches, c)
|
||||||
return (i, i+L-1)
|
return (i, i+L-1)
|
||||||
return (-1, 0)
|
return (-1, 0)
|
||||||
|
|
||||||
proc find*(s: string, pattern: Peg,
|
proc find*(s: string, pattern: Peg,
|
||||||
start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
|
start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
|
||||||
## returns the starting position of ``pattern`` in ``s``. If it does not
|
## returns the starting position of ``pattern`` in ``s``. If it does not
|
||||||
## match, -1 is returned.
|
## match, -1 is returned.
|
||||||
|
|
@ -824,8 +824,8 @@ proc find*(s: string, pattern: Peg,
|
||||||
for i in start .. s.len-1:
|
for i in start .. s.len-1:
|
||||||
if rawMatch(s, pattern, i, c) >= 0: return i
|
if rawMatch(s, pattern, i, c) >= 0: return i
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
iterator findAll*(s: string, pattern: Peg, start = 0): string =
|
iterator findAll*(s: string, pattern: Peg, start = 0): string =
|
||||||
## yields all matching *substrings* of `s` that match `pattern`.
|
## yields all matching *substrings* of `s` that match `pattern`.
|
||||||
var c: Captures
|
var c: Captures
|
||||||
c.origStart = start
|
c.origStart = start
|
||||||
|
|
@ -838,23 +838,23 @@ iterator findAll*(s: string, pattern: Peg, start = 0): string =
|
||||||
else:
|
else:
|
||||||
yield substr(s, i, i+L-1)
|
yield substr(s, i, i+L-1)
|
||||||
inc(i, L)
|
inc(i, L)
|
||||||
|
|
||||||
proc findAll*(s: string, pattern: Peg, start = 0): seq[string] {.
|
proc findAll*(s: string, pattern: Peg, start = 0): seq[string] {.
|
||||||
nosideEffect, rtl, extern: "npegs$1".} =
|
nosideEffect, rtl, extern: "npegs$1".} =
|
||||||
## returns all matching *substrings* of `s` that match `pattern`.
|
## returns all matching *substrings* of `s` that match `pattern`.
|
||||||
## If it does not match, @[] is returned.
|
## If it does not match, @[] is returned.
|
||||||
accumulateResult(findAll(s, pattern, start))
|
accumulateResult(findAll(s, pattern, start))
|
||||||
|
|
||||||
when not defined(nimhygiene):
|
when not defined(nimhygiene):
|
||||||
{.pragma: inject.}
|
{.pragma: inject.}
|
||||||
|
|
||||||
template `=~`*(s: string, pattern: Peg): bool =
|
template `=~`*(s: string, pattern: Peg): bool =
|
||||||
## This calls ``match`` with an implicit declared ``matches`` array that
|
## This calls ``match`` with an implicit declared ``matches`` array that
|
||||||
## can be used in the scope of the ``=~`` call:
|
## can be used in the scope of the ``=~`` call:
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
##
|
##
|
||||||
## if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}":
|
## if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}":
|
||||||
## # matches a key=value pair:
|
## # matches a key=value pair:
|
||||||
## echo("Key: ", matches[0])
|
## echo("Key: ", matches[0])
|
||||||
## echo("Value: ", matches[1])
|
## echo("Value: ", matches[1])
|
||||||
|
|
@ -865,7 +865,7 @@ template `=~`*(s: string, pattern: Peg): bool =
|
||||||
## echo("comment: ", matches[0])
|
## echo("comment: ", matches[0])
|
||||||
## else:
|
## else:
|
||||||
## echo("syntax error")
|
## echo("syntax error")
|
||||||
##
|
##
|
||||||
bind MaxSubpatterns
|
bind MaxSubpatterns
|
||||||
when not declaredInScope(matches):
|
when not declaredInScope(matches):
|
||||||
var matches {.inject.}: array[0..MaxSubpatterns-1, string]
|
var matches {.inject.}: array[0..MaxSubpatterns-1, string]
|
||||||
|
|
@ -902,7 +902,7 @@ proc replacef*(s: string, sub: Peg, by: string): string {.
|
||||||
## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
|
## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
## "var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2")
|
## "var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2")
|
||||||
##
|
##
|
||||||
## Results in:
|
## Results in:
|
||||||
##
|
##
|
||||||
|
|
@ -941,10 +941,10 @@ proc replace*(s: string, sub: Peg, by = ""): string {.
|
||||||
add(result, by)
|
add(result, by)
|
||||||
inc(i, x)
|
inc(i, x)
|
||||||
add(result, substr(s, i))
|
add(result, substr(s, i))
|
||||||
|
|
||||||
proc parallelReplace*(s: string, subs: varargs[
|
proc parallelReplace*(s: string, subs: varargs[
|
||||||
tuple[pattern: Peg, repl: string]]): string {.
|
tuple[pattern: Peg, repl: string]]): string {.
|
||||||
nosideEffect, rtl, extern: "npegs$1".} =
|
nosideEffect, rtl, extern: "npegs$1".} =
|
||||||
## Returns a modified copy of `s` with the substitutions in `subs`
|
## Returns a modified copy of `s` with the substitutions in `subs`
|
||||||
## applied in parallel.
|
## applied in parallel.
|
||||||
result = ""
|
result = ""
|
||||||
|
|
@ -964,8 +964,8 @@ proc parallelReplace*(s: string, subs: varargs[
|
||||||
add(result, s[i])
|
add(result, s[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
# copy the rest:
|
# copy the rest:
|
||||||
add(result, substr(s, i))
|
add(result, substr(s, i))
|
||||||
|
|
||||||
proc transformFile*(infile, outfile: string,
|
proc transformFile*(infile, outfile: string,
|
||||||
subs: varargs[tuple[pattern: Peg, repl: string]]) {.
|
subs: varargs[tuple[pattern: Peg, repl: string]]) {.
|
||||||
rtl, extern: "npegs$1".} =
|
rtl, extern: "npegs$1".} =
|
||||||
|
|
@ -974,7 +974,7 @@ proc transformFile*(infile, outfile: string,
|
||||||
## error occurs. This is supposed to be used for quick scripting.
|
## error occurs. This is supposed to be used for quick scripting.
|
||||||
var x = readFile(infile).string
|
var x = readFile(infile).string
|
||||||
writeFile(outfile, x.parallelReplace(subs))
|
writeFile(outfile, x.parallelReplace(subs))
|
||||||
|
|
||||||
iterator split*(s: string, sep: Peg): string =
|
iterator split*(s: string, sep: Peg): string =
|
||||||
## Splits the string `s` into substrings.
|
## Splits the string `s` into substrings.
|
||||||
##
|
##
|
||||||
|
|
@ -1049,14 +1049,14 @@ type
|
||||||
tkBackref, ## '$'
|
tkBackref, ## '$'
|
||||||
tkDollar, ## '$'
|
tkDollar, ## '$'
|
||||||
tkHat ## '^'
|
tkHat ## '^'
|
||||||
|
|
||||||
TToken {.final.} = object ## a token
|
TToken {.final.} = object ## a token
|
||||||
kind: TTokKind ## the type of the token
|
kind: TTokKind ## the type of the token
|
||||||
modifier: TModifier
|
modifier: TModifier
|
||||||
literal: string ## the parsed (string) literal
|
literal: string ## the parsed (string) literal
|
||||||
charset: set[char] ## if kind == tkCharSet
|
charset: set[char] ## if kind == tkCharSet
|
||||||
index: int ## if kind == tkBackref
|
index: int ## if kind == tkBackref
|
||||||
|
|
||||||
PegLexer {.inheritable.} = object ## the lexer object.
|
PegLexer {.inheritable.} = object ## the lexer object.
|
||||||
bufpos: int ## the current position within the buffer
|
bufpos: int ## the current position within the buffer
|
||||||
buf: cstring ## the buffer itself
|
buf: cstring ## the buffer itself
|
||||||
|
|
@ -1086,7 +1086,7 @@ proc handleLF(L: var PegLexer, pos: int): int =
|
||||||
result = pos+1
|
result = pos+1
|
||||||
L.lineStart = result
|
L.lineStart = result
|
||||||
|
|
||||||
proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) =
|
proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) =
|
||||||
L.buf = input
|
L.buf = input
|
||||||
L.bufpos = 0
|
L.bufpos = 0
|
||||||
L.lineNumber = line
|
L.lineNumber = line
|
||||||
|
|
@ -1094,69 +1094,69 @@ proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) =
|
||||||
L.lineStart = 0
|
L.lineStart = 0
|
||||||
L.filename = filename
|
L.filename = filename
|
||||||
|
|
||||||
proc getColumn(L: PegLexer): int {.inline.} =
|
proc getColumn(L: PegLexer): int {.inline.} =
|
||||||
result = abs(L.bufpos - L.lineStart) + L.colOffset
|
result = abs(L.bufpos - L.lineStart) + L.colOffset
|
||||||
|
|
||||||
proc getLine(L: PegLexer): int {.inline.} =
|
proc getLine(L: PegLexer): int {.inline.} =
|
||||||
result = L.lineNumber
|
result = L.lineNumber
|
||||||
|
|
||||||
proc errorStr(L: PegLexer, msg: string, line = -1, col = -1): string =
|
proc errorStr(L: PegLexer, msg: string, line = -1, col = -1): string =
|
||||||
var line = if line < 0: getLine(L) else: line
|
var line = if line < 0: getLine(L) else: line
|
||||||
var col = if col < 0: getColumn(L) else: col
|
var col = if col < 0: getColumn(L) else: col
|
||||||
result = "$1($2, $3) Error: $4" % [L.filename, $line, $col, msg]
|
result = "$1($2, $3) Error: $4" % [L.filename, $line, $col, msg]
|
||||||
|
|
||||||
proc handleHexChar(c: var PegLexer, xi: var int) =
|
proc handleHexChar(c: var PegLexer, xi: var int) =
|
||||||
case c.buf[c.bufpos]
|
case c.buf[c.bufpos]
|
||||||
of '0'..'9':
|
of '0'..'9':
|
||||||
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'))
|
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0'))
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
of 'a'..'f':
|
of 'a'..'f':
|
||||||
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10)
|
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10)
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
of 'A'..'F':
|
of 'A'..'F':
|
||||||
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
|
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc getEscapedChar(c: var PegLexer, tok: var TToken) =
|
proc getEscapedChar(c: var PegLexer, tok: var TToken) =
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
case c.buf[c.bufpos]
|
case c.buf[c.bufpos]
|
||||||
of 'r', 'R', 'c', 'C':
|
of 'r', 'R', 'c', 'C':
|
||||||
add(tok.literal, '\c')
|
add(tok.literal, '\c')
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
of 'l', 'L':
|
of 'l', 'L':
|
||||||
add(tok.literal, '\L')
|
add(tok.literal, '\L')
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
of 'f', 'F':
|
of 'f', 'F':
|
||||||
add(tok.literal, '\f')
|
add(tok.literal, '\f')
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
of 'e', 'E':
|
of 'e', 'E':
|
||||||
add(tok.literal, '\e')
|
add(tok.literal, '\e')
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
of 'a', 'A':
|
of 'a', 'A':
|
||||||
add(tok.literal, '\a')
|
add(tok.literal, '\a')
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
of 'b', 'B':
|
of 'b', 'B':
|
||||||
add(tok.literal, '\b')
|
add(tok.literal, '\b')
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
of 'v', 'V':
|
of 'v', 'V':
|
||||||
add(tok.literal, '\v')
|
add(tok.literal, '\v')
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
of 't', 'T':
|
of 't', 'T':
|
||||||
add(tok.literal, '\t')
|
add(tok.literal, '\t')
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
of 'x', 'X':
|
of 'x', 'X':
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
var xi = 0
|
var xi = 0
|
||||||
handleHexChar(c, xi)
|
handleHexChar(c, xi)
|
||||||
handleHexChar(c, xi)
|
handleHexChar(c, xi)
|
||||||
if xi == 0: tok.kind = tkInvalid
|
if xi == 0: tok.kind = tkInvalid
|
||||||
else: add(tok.literal, chr(xi))
|
else: add(tok.literal, chr(xi))
|
||||||
of '0'..'9':
|
of '0'..'9':
|
||||||
var val = ord(c.buf[c.bufpos]) - ord('0')
|
var val = ord(c.buf[c.bufpos]) - ord('0')
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
var i = 1
|
var i = 1
|
||||||
while (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}):
|
while (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}):
|
||||||
val = val * 10 + ord(c.buf[c.bufpos]) - ord('0')
|
val = val * 10 + ord(c.buf[c.bufpos]) - ord('0')
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
@ -1169,32 +1169,32 @@ proc getEscapedChar(c: var PegLexer, tok: var TToken) =
|
||||||
else:
|
else:
|
||||||
add(tok.literal, c.buf[c.bufpos])
|
add(tok.literal, c.buf[c.bufpos])
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
|
|
||||||
proc skip(c: var PegLexer) =
|
proc skip(c: var PegLexer) =
|
||||||
var pos = c.bufpos
|
var pos = c.bufpos
|
||||||
var buf = c.buf
|
var buf = c.buf
|
||||||
while true:
|
while true:
|
||||||
case buf[pos]
|
case buf[pos]
|
||||||
of ' ', '\t':
|
of ' ', '\t':
|
||||||
inc(pos)
|
inc(pos)
|
||||||
of '#':
|
of '#':
|
||||||
while not (buf[pos] in {'\c', '\L', '\0'}): inc(pos)
|
while not (buf[pos] in {'\c', '\L', '\0'}): inc(pos)
|
||||||
of '\c':
|
of '\c':
|
||||||
pos = handleCR(c, pos)
|
pos = handleCR(c, pos)
|
||||||
buf = c.buf
|
buf = c.buf
|
||||||
of '\L':
|
of '\L':
|
||||||
pos = handleLF(c, pos)
|
pos = handleLF(c, pos)
|
||||||
buf = c.buf
|
buf = c.buf
|
||||||
else:
|
else:
|
||||||
break # EndOfFile also leaves the loop
|
break # EndOfFile also leaves the loop
|
||||||
c.bufpos = pos
|
c.bufpos = pos
|
||||||
|
|
||||||
proc getString(c: var PegLexer, tok: var TToken) =
|
proc getString(c: var PegLexer, tok: var TToken) =
|
||||||
tok.kind = tkStringLit
|
tok.kind = tkStringLit
|
||||||
var pos = c.bufpos + 1
|
var pos = c.bufpos + 1
|
||||||
var buf = c.buf
|
var buf = c.buf
|
||||||
var quote = buf[pos-1]
|
var quote = buf[pos-1]
|
||||||
while true:
|
while true:
|
||||||
case buf[pos]
|
case buf[pos]
|
||||||
of '\\':
|
of '\\':
|
||||||
c.bufpos = pos
|
c.bufpos = pos
|
||||||
|
|
@ -1205,13 +1205,13 @@ proc getString(c: var PegLexer, tok: var TToken) =
|
||||||
break
|
break
|
||||||
elif buf[pos] == quote:
|
elif buf[pos] == quote:
|
||||||
inc(pos)
|
inc(pos)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
add(tok.literal, buf[pos])
|
add(tok.literal, buf[pos])
|
||||||
inc(pos)
|
inc(pos)
|
||||||
c.bufpos = pos
|
c.bufpos = pos
|
||||||
|
|
||||||
proc getDollar(c: var PegLexer, tok: var TToken) =
|
proc getDollar(c: var PegLexer, tok: var TToken) =
|
||||||
var pos = c.bufpos + 1
|
var pos = c.bufpos + 1
|
||||||
var buf = c.buf
|
var buf = c.buf
|
||||||
if buf[pos] in {'0'..'9'}:
|
if buf[pos] in {'0'..'9'}:
|
||||||
|
|
@ -1223,8 +1223,8 @@ proc getDollar(c: var PegLexer, tok: var TToken) =
|
||||||
else:
|
else:
|
||||||
tok.kind = tkDollar
|
tok.kind = tkDollar
|
||||||
c.bufpos = pos
|
c.bufpos = pos
|
||||||
|
|
||||||
proc getCharSet(c: var PegLexer, tok: var TToken) =
|
proc getCharSet(c: var PegLexer, tok: var TToken) =
|
||||||
tok.kind = tkCharSet
|
tok.kind = tkCharSet
|
||||||
tok.charset = {}
|
tok.charset = {}
|
||||||
var pos = c.bufpos + 1
|
var pos = c.bufpos + 1
|
||||||
|
|
@ -1247,7 +1247,7 @@ proc getCharSet(c: var PegLexer, tok: var TToken) =
|
||||||
of '\C', '\L', '\0':
|
of '\C', '\L', '\0':
|
||||||
tok.kind = tkInvalid
|
tok.kind = tkInvalid
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
ch = buf[pos]
|
ch = buf[pos]
|
||||||
inc(pos)
|
inc(pos)
|
||||||
incl(tok.charset, ch)
|
incl(tok.charset, ch)
|
||||||
|
|
@ -1267,18 +1267,18 @@ proc getCharSet(c: var PegLexer, tok: var TToken) =
|
||||||
of '\C', '\L', '\0':
|
of '\C', '\L', '\0':
|
||||||
tok.kind = tkInvalid
|
tok.kind = tkInvalid
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
ch2 = buf[pos]
|
ch2 = buf[pos]
|
||||||
inc(pos)
|
inc(pos)
|
||||||
for i in ord(ch)+1 .. ord(ch2):
|
for i in ord(ch)+1 .. ord(ch2):
|
||||||
incl(tok.charset, chr(i))
|
incl(tok.charset, chr(i))
|
||||||
c.bufpos = pos
|
c.bufpos = pos
|
||||||
if caret: tok.charset = {'\1'..'\xFF'} - tok.charset
|
if caret: tok.charset = {'\1'..'\xFF'} - tok.charset
|
||||||
|
|
||||||
proc getSymbol(c: var PegLexer, tok: var TToken) =
|
proc getSymbol(c: var PegLexer, tok: var TToken) =
|
||||||
var pos = c.bufpos
|
var pos = c.bufpos
|
||||||
var buf = c.buf
|
var buf = c.buf
|
||||||
while true:
|
while true:
|
||||||
add(tok.literal, buf[pos])
|
add(tok.literal, buf[pos])
|
||||||
inc(pos)
|
inc(pos)
|
||||||
if buf[pos] notin strutils.IdentChars: break
|
if buf[pos] notin strutils.IdentChars: break
|
||||||
|
|
@ -1294,7 +1294,7 @@ proc getBuiltin(c: var PegLexer, tok: var TToken) =
|
||||||
tok.kind = tkEscaped
|
tok.kind = tkEscaped
|
||||||
getEscapedChar(c, tok) # may set tok.kind to tkInvalid
|
getEscapedChar(c, tok) # may set tok.kind to tkInvalid
|
||||||
|
|
||||||
proc getTok(c: var PegLexer, tok: var TToken) =
|
proc getTok(c: var PegLexer, tok: var TToken) =
|
||||||
tok.kind = tkInvalid
|
tok.kind = tkInvalid
|
||||||
tok.modifier = modNone
|
tok.modifier = modNone
|
||||||
setLen(tok.literal, 0)
|
setLen(tok.literal, 0)
|
||||||
|
|
@ -1309,11 +1309,11 @@ proc getTok(c: var PegLexer, tok: var TToken) =
|
||||||
else:
|
else:
|
||||||
tok.kind = tkCurlyLe
|
tok.kind = tkCurlyLe
|
||||||
add(tok.literal, '{')
|
add(tok.literal, '{')
|
||||||
of '}':
|
of '}':
|
||||||
tok.kind = tkCurlyRi
|
tok.kind = tkCurlyRi
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
add(tok.literal, '}')
|
add(tok.literal, '}')
|
||||||
of '[':
|
of '[':
|
||||||
getCharSet(c, tok)
|
getCharSet(c, tok)
|
||||||
of '(':
|
of '(':
|
||||||
tok.kind = tkParLe
|
tok.kind = tkParLe
|
||||||
|
|
@ -1323,7 +1323,7 @@ proc getTok(c: var PegLexer, tok: var TToken) =
|
||||||
tok.kind = tkParRi
|
tok.kind = tkParRi
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
add(tok.literal, ')')
|
add(tok.literal, ')')
|
||||||
of '.':
|
of '.':
|
||||||
tok.kind = tkAny
|
tok.kind = tkAny
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
add(tok.literal, '.')
|
add(tok.literal, '.')
|
||||||
|
|
@ -1331,16 +1331,16 @@ proc getTok(c: var PegLexer, tok: var TToken) =
|
||||||
tok.kind = tkAnyRune
|
tok.kind = tkAnyRune
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
add(tok.literal, '_')
|
add(tok.literal, '_')
|
||||||
of '\\':
|
of '\\':
|
||||||
getBuiltin(c, tok)
|
getBuiltin(c, tok)
|
||||||
of '\'', '"': getString(c, tok)
|
of '\'', '"': getString(c, tok)
|
||||||
of '$': getDollar(c, tok)
|
of '$': getDollar(c, tok)
|
||||||
of '\0':
|
of '\0':
|
||||||
tok.kind = tkEof
|
tok.kind = tkEof
|
||||||
tok.literal = "[EOF]"
|
tok.literal = "[EOF]"
|
||||||
of 'a'..'z', 'A'..'Z', '\128'..'\255':
|
of 'a'..'z', 'A'..'Z', '\128'..'\255':
|
||||||
getSymbol(c, tok)
|
getSymbol(c, tok)
|
||||||
if c.buf[c.bufpos] in {'\'', '"'} or
|
if c.buf[c.bufpos] in {'\'', '"'} or
|
||||||
c.buf[c.bufpos] == '$' and c.buf[c.bufpos+1] in {'0'..'9'}:
|
c.buf[c.bufpos] == '$' and c.buf[c.bufpos+1] in {'0'..'9'}:
|
||||||
case tok.literal
|
case tok.literal
|
||||||
of "i": tok.modifier = modIgnoreCase
|
of "i": tok.modifier = modIgnoreCase
|
||||||
|
|
@ -1388,7 +1388,7 @@ proc getTok(c: var PegLexer, tok: var TToken) =
|
||||||
tok.kind = tkAt
|
tok.kind = tkAt
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
add(tok.literal, '@')
|
add(tok.literal, '@')
|
||||||
if c.buf[c.bufpos] == '@':
|
if c.buf[c.bufpos] == '@':
|
||||||
tok.kind = tkCurlyAt
|
tok.kind = tkCurlyAt
|
||||||
inc(c.bufpos)
|
inc(c.bufpos)
|
||||||
add(tok.literal, '@')
|
add(tok.literal, '@')
|
||||||
|
|
@ -1407,7 +1407,7 @@ proc arrowIsNextTok(c: PegLexer): bool =
|
||||||
result = c.buf[pos] == '<' and c.buf[pos+1] == '-'
|
result = c.buf[pos] == '<' and c.buf[pos+1] == '-'
|
||||||
|
|
||||||
# ----------------------------- parser ----------------------------------------
|
# ----------------------------- parser ----------------------------------------
|
||||||
|
|
||||||
type
|
type
|
||||||
EInvalidPeg* = object of ValueError ## raised if an invalid
|
EInvalidPeg* = object of ValueError ## raised if an invalid
|
||||||
## PEG has been detected
|
## PEG has been detected
|
||||||
|
|
@ -1425,7 +1425,7 @@ proc pegError(p: PegParser, msg: string, line = -1, col = -1) =
|
||||||
e.msg = errorStr(p, msg, line, col)
|
e.msg = errorStr(p, msg, line, col)
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
proc getTok(p: var PegParser) =
|
proc getTok(p: var PegParser) =
|
||||||
getTok(p, p.tok)
|
getTok(p, p.tok)
|
||||||
if p.tok.kind == tkInvalid: pegError(p, "invalid token")
|
if p.tok.kind == tkInvalid: pegError(p, "invalid token")
|
||||||
|
|
||||||
|
|
@ -1475,7 +1475,7 @@ proc builtin(p: var PegParser): Peg =
|
||||||
of "white": result = unicodeWhitespace()
|
of "white": result = unicodeWhitespace()
|
||||||
else: pegError(p, "unknown built-in: " & p.tok.literal)
|
else: pegError(p, "unknown built-in: " & p.tok.literal)
|
||||||
|
|
||||||
proc token(terminal: Peg, p: PegParser): Peg =
|
proc token(terminal: Peg, p: PegParser): Peg =
|
||||||
if p.skip.kind == pkEmpty: result = terminal
|
if p.skip.kind == pkEmpty: result = terminal
|
||||||
else: result = sequence(p.skip, terminal)
|
else: result = sequence(p.skip, terminal)
|
||||||
|
|
||||||
|
|
@ -1496,7 +1496,7 @@ proc primary(p: var PegParser): Peg =
|
||||||
else: discard
|
else: discard
|
||||||
case p.tok.kind
|
case p.tok.kind
|
||||||
of tkIdentifier:
|
of tkIdentifier:
|
||||||
if p.identIsVerbatim:
|
if p.identIsVerbatim:
|
||||||
var m = p.tok.modifier
|
var m = p.tok.modifier
|
||||||
if m == modNone: m = p.modifier
|
if m == modNone: m = p.modifier
|
||||||
result = modifiedTerm(p.tok.literal, m).token(p)
|
result = modifiedTerm(p.tok.literal, m).token(p)
|
||||||
|
|
@ -1539,17 +1539,17 @@ proc primary(p: var PegParser): Peg =
|
||||||
of tkEscaped:
|
of tkEscaped:
|
||||||
result = term(p.tok.literal[0]).token(p)
|
result = term(p.tok.literal[0]).token(p)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
of tkDollar:
|
of tkDollar:
|
||||||
result = endAnchor()
|
result = endAnchor()
|
||||||
getTok(p)
|
getTok(p)
|
||||||
of tkHat:
|
of tkHat:
|
||||||
result = startAnchor()
|
result = startAnchor()
|
||||||
getTok(p)
|
getTok(p)
|
||||||
of tkBackref:
|
of tkBackref:
|
||||||
var m = p.tok.modifier
|
var m = p.tok.modifier
|
||||||
if m == modNone: m = p.modifier
|
if m == modNone: m = p.modifier
|
||||||
result = modifiedBackref(p.tok.index, m).token(p)
|
result = modifiedBackref(p.tok.index, m).token(p)
|
||||||
if p.tok.index < 0 or p.tok.index > p.captures:
|
if p.tok.index < 0 or p.tok.index > p.captures:
|
||||||
pegError(p, "invalid back reference index: " & $p.tok.index)
|
pegError(p, "invalid back reference index: " & $p.tok.index)
|
||||||
getTok(p)
|
getTok(p)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1573,7 +1573,7 @@ proc seqExpr(p: var PegParser): Peg =
|
||||||
while true:
|
while true:
|
||||||
case p.tok.kind
|
case p.tok.kind
|
||||||
of tkAmp, tkNot, tkAt, tkStringLit, tkCharSet, tkParLe, tkCurlyLe,
|
of tkAmp, tkNot, tkAt, tkStringLit, tkCharSet, tkParLe, tkCurlyLe,
|
||||||
tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref,
|
tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref,
|
||||||
tkHat, tkCurlyAt:
|
tkHat, tkCurlyAt:
|
||||||
result = sequence(result, primary(p))
|
result = sequence(result, primary(p))
|
||||||
of tkIdentifier:
|
of tkIdentifier:
|
||||||
|
|
@ -1587,7 +1587,7 @@ proc parseExpr(p: var PegParser): Peg =
|
||||||
while p.tok.kind == tkBar:
|
while p.tok.kind == tkBar:
|
||||||
getTok(p)
|
getTok(p)
|
||||||
result = result / seqExpr(p)
|
result = result / seqExpr(p)
|
||||||
|
|
||||||
proc parseRule(p: var PegParser): NonTerminal =
|
proc parseRule(p: var PegParser): NonTerminal =
|
||||||
if p.tok.kind == tkIdentifier and arrowIsNextTok(p):
|
if p.tok.kind == tkIdentifier and arrowIsNextTok(p):
|
||||||
result = getNonTerminal(p, p.tok.literal)
|
result = getNonTerminal(p, p.tok.literal)
|
||||||
|
|
@ -1601,7 +1601,7 @@ proc parseRule(p: var PegParser): NonTerminal =
|
||||||
incl(result.flags, ntDeclared) # NOW inlining may be attempted
|
incl(result.flags, ntDeclared) # NOW inlining may be attempted
|
||||||
else:
|
else:
|
||||||
pegError(p, "rule expected, but found: " & p.tok.literal)
|
pegError(p, "rule expected, but found: " & p.tok.literal)
|
||||||
|
|
||||||
proc rawParse(p: var PegParser): Peg =
|
proc rawParse(p: var PegParser): Peg =
|
||||||
## parses a rule or a PEG expression
|
## parses a rule or a PEG expression
|
||||||
while p.tok.kind == tkBuiltin:
|
while p.tok.kind == tkBuiltin:
|
||||||
|
|
@ -1680,7 +1680,7 @@ when isMainModule:
|
||||||
assert(not match("W_HI_L", peg"\y 'while'"))
|
assert(not match("W_HI_L", peg"\y 'while'"))
|
||||||
assert(not match("W_HI_Le", peg"\y v'while'"))
|
assert(not match("W_HI_Le", peg"\y v'while'"))
|
||||||
assert match("W_HI_Le", peg"y'while'")
|
assert match("W_HI_Le", peg"y'while'")
|
||||||
|
|
||||||
assert($ +digits == $peg"\d+")
|
assert($ +digits == $peg"\d+")
|
||||||
assert "0158787".match(peg"\d+")
|
assert "0158787".match(peg"\d+")
|
||||||
assert "ABC 0232".match(peg"\w+\s+\d+")
|
assert "ABC 0232".match(peg"\w+\s+\d+")
|
||||||
|
|
@ -1693,14 +1693,14 @@ when isMainModule:
|
||||||
|
|
||||||
var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident)
|
var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident)
|
||||||
assert matchLen("key1= cal9", pattern) == 11
|
assert matchLen("key1= cal9", pattern) == 11
|
||||||
|
|
||||||
var ws = newNonTerminal("ws", 1, 1)
|
var ws = newNonTerminal("ws", 1, 1)
|
||||||
ws.rule = *whitespace
|
ws.rule = *whitespace
|
||||||
|
|
||||||
var expr = newNonTerminal("expr", 1, 1)
|
var expr = newNonTerminal("expr", 1, 1)
|
||||||
expr.rule = sequence(capture(ident), *sequence(
|
expr.rule = sequence(capture(ident), *sequence(
|
||||||
nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr)))
|
nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr)))
|
||||||
|
|
||||||
var c: Captures
|
var c: Captures
|
||||||
var s = "a+b + c +d+e+f"
|
var s = "a+b + c +d+e+f"
|
||||||
assert rawMatch(s, expr.rule, 0, c) == len(s)
|
assert rawMatch(s, expr.rule, 0, c) == len(s)
|
||||||
|
|
@ -1722,7 +1722,7 @@ when isMainModule:
|
||||||
assert matches[0] == "abc"
|
assert matches[0] == "abc"
|
||||||
else:
|
else:
|
||||||
assert false
|
assert false
|
||||||
|
|
||||||
var g2 = peg"""S <- A B / C D
|
var g2 = peg"""S <- A B / C D
|
||||||
A <- 'a'+
|
A <- 'a'+
|
||||||
B <- 'b'+
|
B <- 'b'+
|
||||||
|
|
@ -1753,13 +1753,13 @@ when isMainModule:
|
||||||
|
|
||||||
for x in findAll("abcdef", peg"^{.}", 3):
|
for x in findAll("abcdef", peg"^{.}", 3):
|
||||||
assert x == "d"
|
assert x == "d"
|
||||||
|
|
||||||
if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')":
|
if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')":
|
||||||
assert matches[0] == "f"
|
assert matches[0] == "f"
|
||||||
assert matches[1] == "a, b"
|
assert matches[1] == "a, b"
|
||||||
else:
|
else:
|
||||||
assert false
|
assert false
|
||||||
|
|
||||||
assert match("eine übersicht und außerdem", peg"(\letter \white*)+")
|
assert match("eine übersicht und außerdem", peg"(\letter \white*)+")
|
||||||
# ß is not a lower cased letter?!
|
# ß is not a lower cased letter?!
|
||||||
assert match("eine übersicht und auerdem", peg"(\lower \white*)+")
|
assert match("eine übersicht und auerdem", peg"(\lower \white*)+")
|
||||||
|
|
|
||||||
|
|
@ -798,6 +798,22 @@ proc zunionstore*(r: Redis, destination: string, numkeys: string,
|
||||||
|
|
||||||
return r.readInteger()
|
return r.readInteger()
|
||||||
|
|
||||||
|
# HyperLogLog
|
||||||
|
|
||||||
|
proc pfadd*(r: Redis, key: string, elements: varargs[string]): RedisInteger =
|
||||||
|
## Add variable number of elements into special 'HyperLogLog' set type
|
||||||
|
r.sendCommand("PFADD", key, elements)
|
||||||
|
return r.readInteger()
|
||||||
|
|
||||||
|
proc pfcount*(r: Redis, key: string): RedisInteger =
|
||||||
|
## Count approximate number of elements in 'HyperLogLog'
|
||||||
|
r.sendCommand("PFCOUNT", key)
|
||||||
|
return r.readInteger()
|
||||||
|
|
||||||
|
proc pfmerge*(r: Redis, destination: string, sources: varargs[string]) =
|
||||||
|
## Merge several source HyperLogLog's into one specified by destKey
|
||||||
|
r.sendCommand("PFMERGE", destination, sources)
|
||||||
|
raiseNoOK(r.readStatus(), r.pipeline.enabled)
|
||||||
|
|
||||||
# Pub/Sub
|
# Pub/Sub
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -224,10 +224,12 @@ proc ssReadData(s: Stream, buffer: pointer, bufLen: int): int =
|
||||||
|
|
||||||
proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) =
|
proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) =
|
||||||
var s = StringStream(s)
|
var s = StringStream(s)
|
||||||
if bufLen > 0:
|
if bufLen <= 0:
|
||||||
setLen(s.data, s.data.len + bufLen)
|
return
|
||||||
copyMem(addr(s.data[s.pos]), buffer, bufLen)
|
if s.pos + bufLen > s.data.len:
|
||||||
inc(s.pos, bufLen)
|
setLen(s.data, s.pos + bufLen)
|
||||||
|
copyMem(addr(s.data[s.pos]), buffer, bufLen)
|
||||||
|
inc(s.pos, bufLen)
|
||||||
|
|
||||||
proc ssClose(s: Stream) =
|
proc ssClose(s: Stream) =
|
||||||
var s = StringStream(s)
|
var s = StringStream(s)
|
||||||
|
|
|
||||||
|
|
@ -499,26 +499,47 @@ proc parseEnum*[T: enum](s: string, default: T): T =
|
||||||
return e
|
return e
|
||||||
result = default
|
result = default
|
||||||
|
|
||||||
proc repeatChar*(count: int, c: char = ' '): string {.noSideEffect,
|
proc repeat*(c: char, count: int): string {.noSideEffect,
|
||||||
rtl, extern: "nsuRepeatChar".} =
|
rtl, extern: "nsuRepeatChar".} =
|
||||||
## Returns a string of length `count` consisting only of
|
## Returns a string of length `count` consisting only of
|
||||||
## the character `c`. You can use this proc to left align strings. Example:
|
## the character `c`. You can use this proc to left align strings. Example:
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
|
## proc tabexpand(indent: int, text: string, tabsize: int = 4) =
|
||||||
|
## echo '\t'.repeat(indent div tabsize), ' '.repeat(indent mod tabsize), text
|
||||||
|
##
|
||||||
|
## tabexpand(4, "At four")
|
||||||
|
## tabexpand(5, "At five")
|
||||||
|
## tabexpand(6, "At six")
|
||||||
|
result = newString(count)
|
||||||
|
for i in 0..count-1: result[i] = c
|
||||||
|
|
||||||
|
proc repeat*(s: string, n: int): string {.noSideEffect,
|
||||||
|
rtl, extern: "nsuRepeatStr".} =
|
||||||
|
## Returns String `s` concatenated `n` times. Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
## echo "+++ STOP ".repeat(4), "+++"
|
||||||
|
result = newStringOfCap(n * s.len)
|
||||||
|
for i in 1..n: result.add(s)
|
||||||
|
|
||||||
|
template spaces*(n: int): string = repeat(' ',n)
|
||||||
|
## Returns a String with `n` space characters. You can use this proc
|
||||||
|
## to left align strings. Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
## let
|
## let
|
||||||
## width = 15
|
## width = 15
|
||||||
## text1 = "Hello user!"
|
## text1 = "Hello user!"
|
||||||
## text2 = "This is a very long string"
|
## text2 = "This is a very long string"
|
||||||
## echo text1 & repeatChar(max(0, width - text1.len)) & "|"
|
## echo text1 & spaces(max(0, width - text1.len)) & "|"
|
||||||
## echo text2 & repeatChar(max(0, width - text2.len)) & "|"
|
## echo text2 & spaces(max(0, width - text2.len)) & "|"
|
||||||
result = newString(count)
|
|
||||||
for i in 0..count-1: result[i] = c
|
|
||||||
|
|
||||||
proc repeatStr*(count: int, s: string): string {.noSideEffect,
|
proc repeatChar*(count: int, c: char = ' '): string {.deprecated.} = repeat(c, count)
|
||||||
rtl, extern: "nsuRepeatStr".} =
|
## deprecated: use repeat() or spaces()
|
||||||
## Returns `s` concatenated `count` times.
|
|
||||||
result = newStringOfCap(count*s.len)
|
proc repeatStr*(count: int, s: string): string {.deprecated.} = repeat(s, count)
|
||||||
for i in 0..count-1: result.add(s)
|
## deprecated: use repeat(string, count) or string.repeat(count)
|
||||||
|
|
||||||
proc align*(s: string, count: int, padding = ' '): string {.
|
proc align*(s: string, count: int, padding = ' '): string {.
|
||||||
noSideEffect, rtl, extern: "nsuAlignString".} =
|
noSideEffect, rtl, extern: "nsuAlignString".} =
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@ when defined(windows):
|
||||||
var
|
var
|
||||||
oldAttr = getAttributes()
|
oldAttr = getAttributes()
|
||||||
|
|
||||||
proc winGetch(): cint {.header: "<conio.h>", importc: "_getch".}
|
|
||||||
else:
|
else:
|
||||||
import termios, unsigned
|
import termios, unsigned
|
||||||
|
|
||||||
|
|
@ -344,7 +343,7 @@ proc isatty*(f: File): bool =
|
||||||
else:
|
else:
|
||||||
proc isatty(fildes: FileHandle): cint {.
|
proc isatty(fildes: FileHandle): cint {.
|
||||||
importc: "_isatty", header: "<io.h>".}
|
importc: "_isatty", header: "<io.h>".}
|
||||||
|
|
||||||
result = isatty(getFileHandle(f)) != 0'i32
|
result = isatty(getFileHandle(f)) != 0'i32
|
||||||
|
|
||||||
proc styledEchoProcessArg(s: string) = write stdout, s
|
proc styledEchoProcessArg(s: string) = write stdout, s
|
||||||
|
|
@ -364,12 +363,11 @@ macro styledEcho*(m: varargs[expr]): stmt =
|
||||||
result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n")))
|
result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n")))
|
||||||
result.add(newCall(bindSym"resetAttributes"))
|
result.add(newCall(bindSym"resetAttributes"))
|
||||||
|
|
||||||
proc getch*(): char =
|
when not defined(windows):
|
||||||
## Read a single character from the terminal, blocking until it is entered.
|
proc getch*(): char =
|
||||||
## The character is not printed to the terminal.
|
## Read a single character from the terminal, blocking until it is entered.
|
||||||
when defined(windows):
|
## The character is not printed to the terminal. This is not available for
|
||||||
result = winGetch().char
|
## Windows.
|
||||||
else:
|
|
||||||
let fd = getFileHandle(stdin)
|
let fd = getFileHandle(stdin)
|
||||||
var oldMode: Termios
|
var oldMode: Termios
|
||||||
discard fd.tcgetattr(addr oldMode)
|
discard fd.tcgetattr(addr oldMode)
|
||||||
|
|
@ -387,5 +385,5 @@ when isMainModule:
|
||||||
setForeGroundColor(fgBlue)
|
setForeGroundColor(fgBlue)
|
||||||
writeln(stdout, "ordinary text")
|
writeln(stdout, "ordinary text")
|
||||||
|
|
||||||
styledEcho("styled text ", {styleBright, styleBlink, styleUnderscore})
|
styledEcho("styled text ", {styleBright, styleBlink, styleUnderscore})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -628,25 +628,25 @@ proc formatToken(info: TimeInfo, token: string, buf: var string) =
|
||||||
var fr = ($info.year).len()-2
|
var fr = ($info.year).len()-2
|
||||||
if fr < 0: fr = 0
|
if fr < 0: fr = 0
|
||||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
||||||
if fyear.len != 2: fyear = repeatChar(2-fyear.len(), '0') & fyear
|
if fyear.len != 2: fyear = repeat('0', 2-fyear.len()) & fyear
|
||||||
buf.add(fyear)
|
buf.add(fyear)
|
||||||
of "yyy":
|
of "yyy":
|
||||||
var fr = ($info.year).len()-3
|
var fr = ($info.year).len()-3
|
||||||
if fr < 0: fr = 0
|
if fr < 0: fr = 0
|
||||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
||||||
if fyear.len != 3: fyear = repeatChar(3-fyear.len(), '0') & fyear
|
if fyear.len != 3: fyear = repeat('0', 3-fyear.len()) & fyear
|
||||||
buf.add(fyear)
|
buf.add(fyear)
|
||||||
of "yyyy":
|
of "yyyy":
|
||||||
var fr = ($info.year).len()-4
|
var fr = ($info.year).len()-4
|
||||||
if fr < 0: fr = 0
|
if fr < 0: fr = 0
|
||||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
||||||
if fyear.len != 4: fyear = repeatChar(4-fyear.len(), '0') & fyear
|
if fyear.len != 4: fyear = repeat('0', 4-fyear.len()) & fyear
|
||||||
buf.add(fyear)
|
buf.add(fyear)
|
||||||
of "yyyyy":
|
of "yyyyy":
|
||||||
var fr = ($info.year).len()-5
|
var fr = ($info.year).len()-5
|
||||||
if fr < 0: fr = 0
|
if fr < 0: fr = 0
|
||||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
||||||
if fyear.len != 5: fyear = repeatChar(5-fyear.len(), '0') & fyear
|
if fyear.len != 5: fyear = repeat('0', 5-fyear.len()) & fyear
|
||||||
buf.add(fyear)
|
buf.add(fyear)
|
||||||
of "z":
|
of "z":
|
||||||
let hrs = (info.timezone div 60) div 60
|
let hrs = (info.timezone div 60) div 60
|
||||||
|
|
|
||||||
|
|
@ -118,21 +118,35 @@ proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} =
|
||||||
elif i <=% 0x07FF:
|
elif i <=% 0x07FF:
|
||||||
result = newString(2)
|
result = newString(2)
|
||||||
result[0] = chr((i shr 6) or 0b110_00000)
|
result[0] = chr((i shr 6) or 0b110_00000)
|
||||||
result[1] = chr((i and ones(6)) or 0b10_000000)
|
result[1] = chr((i and ones(6)) or 0b10_0000_00)
|
||||||
elif i <=% 0xFFFF:
|
elif i <=% 0xFFFF:
|
||||||
result = newString(3)
|
result = newString(3)
|
||||||
result[0] = chr(i shr 12 or 0b1110_0000)
|
result[0] = chr(i shr 12 or 0b1110_0000)
|
||||||
result[1] = chr(i shr 6 and ones(6) or 0b10_0000_00)
|
result[1] = chr(i shr 6 and ones(6) or 0b10_0000_00)
|
||||||
result[2] = chr(i and ones(6) or 0b10_0000_00)
|
result[2] = chr(i and ones(6) or 0b10_0000_00)
|
||||||
elif i <=% 0x0010FFFF:
|
elif i <=% 0x001FFFFF:
|
||||||
result = newString(4)
|
result = newString(4)
|
||||||
result[0] = chr(i shr 18 or 0b1111_0000)
|
result[0] = chr(i shr 18 or 0b1111_0000)
|
||||||
result[1] = chr(i shr 12 and ones(6) or 0b10_0000_00)
|
result[1] = chr(i shr 12 and ones(6) or 0b10_0000_00)
|
||||||
result[2] = chr(i shr 6 and ones(6) or 0b10_0000_00)
|
result[2] = chr(i shr 6 and ones(6) or 0b10_0000_00)
|
||||||
result[3] = chr(i and ones(6) or 0b10_0000_00)
|
result[3] = chr(i and ones(6) or 0b10_0000_00)
|
||||||
|
elif i <=% 0x03FFFFFF:
|
||||||
|
result = newString(5)
|
||||||
|
result[0] = chr(i shr 24 or 0b111110_00)
|
||||||
|
result[1] = chr(i shr 18 and ones(6) or 0b10_0000_00)
|
||||||
|
result[2] = chr(i shr 12 and ones(6) or 0b10_0000_00)
|
||||||
|
result[3] = chr(i shr 6 and ones(6) or 0b10_0000_00)
|
||||||
|
result[4] = chr(i and ones(6) or 0b10_0000_00)
|
||||||
|
elif i <=% 0x7FFFFFFF:
|
||||||
|
result = newString(6)
|
||||||
|
result[0] = chr(i shr 30 or 0b1111110_0)
|
||||||
|
result[1] = chr(i shr 24 and ones(6) or 0b10_0000_00)
|
||||||
|
result[2] = chr(i shr 18 and ones(6) or 0b10_0000_00)
|
||||||
|
result[3] = chr(i shr 12 and ones(6) or 0b10_0000_00)
|
||||||
|
result[4] = chr(i shr 6 and ones(6) or 0b10_0000_00)
|
||||||
|
result[5] = chr(i and ones(6) or 0b10_0000_00)
|
||||||
else:
|
else:
|
||||||
result = newString(1)
|
discard # error, exception?
|
||||||
result[0] = chr(i)
|
|
||||||
|
|
||||||
proc `$`*(rune: Rune): string =
|
proc `$`*(rune: Rune): string =
|
||||||
## converts a rune to a string
|
## converts a rune to a string
|
||||||
|
|
|
||||||
|
|
@ -285,6 +285,16 @@ proc `$`*(u: Uri): string =
|
||||||
result.add(u.anchor)
|
result.add(u.anchor)
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
|
block:
|
||||||
|
let str = "http://localhost"
|
||||||
|
let test = parseUri(str)
|
||||||
|
doAssert test.path == ""
|
||||||
|
|
||||||
|
block:
|
||||||
|
let str = "http://localhost/"
|
||||||
|
let test = parseUri(str)
|
||||||
|
doAssert test.path == "/"
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let str = "http://localhost:8080/test"
|
let str = "http://localhost:8080/test"
|
||||||
let test = parseUri(str)
|
let test = parseUri(str)
|
||||||
|
|
|
||||||
|
|
@ -1083,7 +1083,7 @@ proc addEscaped(s: string): string =
|
||||||
else: result.add(c)
|
else: result.add(c)
|
||||||
|
|
||||||
proc nodeToXml(n: PNode, indent: int = 0): string =
|
proc nodeToXml(n: PNode, indent: int = 0): string =
|
||||||
result = repeatChar(indent, ' ') & "<" & n.nodeName
|
result = spaces(indent) & "<" & n.nodeName
|
||||||
if not isNil(n.attributes):
|
if not isNil(n.attributes):
|
||||||
for i in items(n.attributes):
|
for i in items(n.attributes):
|
||||||
result.add(" " & i.name & "=\"" & addEscaped(i.value) & "\"")
|
result.add(" " & i.name & "=\"" & addEscaped(i.value) & "\"")
|
||||||
|
|
@ -1098,23 +1098,23 @@ proc nodeToXml(n: PNode, indent: int = 0): string =
|
||||||
of ElementNode:
|
of ElementNode:
|
||||||
result.add(nodeToXml(i, indent + 2))
|
result.add(nodeToXml(i, indent + 2))
|
||||||
of TextNode:
|
of TextNode:
|
||||||
result.add(repeatChar(indent * 2, ' '))
|
result.add(spaces(indent * 2))
|
||||||
result.add(addEscaped(i.nodeValue))
|
result.add(addEscaped(i.nodeValue))
|
||||||
of CDataSectionNode:
|
of CDataSectionNode:
|
||||||
result.add(repeatChar(indent * 2, ' '))
|
result.add(spaces(indent * 2))
|
||||||
result.add("<![CDATA[" & i.nodeValue & "]]>")
|
result.add("<![CDATA[" & i.nodeValue & "]]>")
|
||||||
of ProcessingInstructionNode:
|
of ProcessingInstructionNode:
|
||||||
result.add(repeatChar(indent * 2, ' '))
|
result.add(spaces(indent * 2))
|
||||||
result.add("<?" & PProcessingInstruction(i).target & " " &
|
result.add("<?" & PProcessingInstruction(i).target & " " &
|
||||||
PProcessingInstruction(i).data & " ?>")
|
PProcessingInstruction(i).data & " ?>")
|
||||||
of CommentNode:
|
of CommentNode:
|
||||||
result.add(repeatChar(indent * 2, ' '))
|
result.add(spaces(indent * 2))
|
||||||
result.add("<!-- " & i.nodeValue & " -->")
|
result.add("<!-- " & i.nodeValue & " -->")
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
result.add("\n")
|
result.add("\n")
|
||||||
# Add the ending tag - </tag>
|
# Add the ending tag - </tag>
|
||||||
result.add(repeatChar(indent, ' ') & "</" & n.nodeName & ">")
|
result.add(spaces(indent) & "</" & n.nodeName & ">")
|
||||||
|
|
||||||
proc `$`*(doc: PDocument): string =
|
proc `$`*(doc: PDocument): string =
|
||||||
## Converts a PDocument object into a string representation of it's XML
|
## Converts a PDocument object into a string representation of it's XML
|
||||||
|
|
|
||||||
204
lib/system.nim
204
lib/system.nim
|
|
@ -89,7 +89,7 @@ type
|
||||||
SomeOrdinal* = int|int8|int16|int32|int64|bool|enum|uint8|uint16|uint32
|
SomeOrdinal* = int|int8|int16|int32|int64|bool|enum|uint8|uint16|uint32
|
||||||
## type class matching all ordinal types; however this includes enums with
|
## type class matching all ordinal types; however this includes enums with
|
||||||
## holes.
|
## holes.
|
||||||
|
|
||||||
SomeReal* = float|float32|float64
|
SomeReal* = float|float32|float64
|
||||||
## type class matching all floating point number types
|
## type class matching all floating point number types
|
||||||
|
|
||||||
|
|
@ -181,7 +181,7 @@ proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {.
|
||||||
## freeing the object. Note: The `finalizer` refers to the type `T`, not to
|
## freeing the object. Note: The `finalizer` refers to the type `T`, not to
|
||||||
## the object! This means that for each object of type `T` the finalizer
|
## the object! This means that for each object of type `T` the finalizer
|
||||||
## will be called!
|
## will be called!
|
||||||
|
|
||||||
proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.}
|
proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.}
|
||||||
## resets an object `obj` to its initial (binary zero) value. This needs to
|
## resets an object `obj` to its initial (binary zero) value. This needs to
|
||||||
## be called before any possible `object branch transition`:idx:.
|
## be called before any possible `object branch transition`:idx:.
|
||||||
|
|
@ -348,7 +348,7 @@ type
|
||||||
## This field is filled automatically in the
|
## This field is filled automatically in the
|
||||||
## ``raise`` statement.
|
## ``raise`` statement.
|
||||||
msg* {.exportc: "message".}: string ## the exception's message. Not
|
msg* {.exportc: "message".}: string ## the exception's message. Not
|
||||||
## providing an exception message
|
## providing an exception message
|
||||||
## is bad style.
|
## is bad style.
|
||||||
trace: string
|
trace: string
|
||||||
|
|
||||||
|
|
@ -483,7 +483,7 @@ type
|
||||||
|
|
||||||
E_Base: Exception, ESystem: SystemError, EIO: IOError,
|
E_Base: Exception, ESystem: SystemError, EIO: IOError,
|
||||||
EOS: OSError, EInvalidLibrary: LibraryError,
|
EOS: OSError, EInvalidLibrary: LibraryError,
|
||||||
EResourceExhausted: ResourceExhaustedError,
|
EResourceExhausted: ResourceExhaustedError,
|
||||||
EArithmetic: ArithmeticError, EDivByZero: DivByZeroError,
|
EArithmetic: ArithmeticError, EDivByZero: DivByZeroError,
|
||||||
EOverflow: OverflowError, EAccessViolation: AccessViolationError,
|
EOverflow: OverflowError, EAccessViolation: AccessViolationError,
|
||||||
EAssertionFailed: AssertionError, EInvalidValue: ValueError,
|
EAssertionFailed: AssertionError, EInvalidValue: ValueError,
|
||||||
|
|
@ -494,7 +494,7 @@ type
|
||||||
EInvalidObjectAssignment: ObjectAssignmentError,
|
EInvalidObjectAssignment: ObjectAssignmentError,
|
||||||
EInvalidObjectConversion: ObjectConversionError,
|
EInvalidObjectConversion: ObjectConversionError,
|
||||||
EDeadThread: DeadThreadError,
|
EDeadThread: DeadThreadError,
|
||||||
EFloatInexact: FloatInexactError,
|
EFloatInexact: FloatInexactError,
|
||||||
EFloatUnderflow: FloatUnderflowError,
|
EFloatUnderflow: FloatUnderflowError,
|
||||||
EFloatingPoint: FloatingPointError,
|
EFloatingPoint: FloatingPointError,
|
||||||
EFloatInvalidOp: FloatInvalidOpError,
|
EFloatInvalidOp: FloatInvalidOpError,
|
||||||
|
|
@ -511,11 +511,11 @@ proc sizeof*[T](x: T): Natural {.magic: "SizeOf", noSideEffect.}
|
||||||
|
|
||||||
proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.}
|
proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.}
|
||||||
## unary ``<`` that can be used for nice looking excluding ranges:
|
## unary ``<`` that can be used for nice looking excluding ranges:
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
## for i in 0 .. <10: echo i
|
## for i in 0 .. <10: echo i
|
||||||
##
|
##
|
||||||
## Semantically this is the same as ``pred``.
|
## Semantically this is the same as ``pred``.
|
||||||
|
|
||||||
proc succ*[T](x: Ordinal[T], y = 1): T {.magic: "Succ", noSideEffect.}
|
proc succ*[T](x: Ordinal[T], y = 1): T {.magic: "Succ", noSideEffect.}
|
||||||
## returns the ``y``-th successor of the value ``x``. ``T`` has to be
|
## returns the ``y``-th successor of the value ``x``. ``T`` has to be
|
||||||
|
|
@ -536,7 +536,7 @@ proc dec*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Dec", noSideEffect.
|
||||||
## decrements the ordinal ``x`` by ``y``. If such a value does not
|
## decrements the ordinal ``x`` by ``y``. If such a value does not
|
||||||
## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
|
## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
|
||||||
## short notation for: ``x = pred(x, y)``.
|
## short notation for: ``x = pred(x, y)``.
|
||||||
|
|
||||||
proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
|
proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
|
||||||
## creates a new sequence of type ``seq[T]`` with length ``len``.
|
## creates a new sequence of type ``seq[T]`` with length ``len``.
|
||||||
## This is equivalent to ``s = @[]; setlen(s, len)``, but more
|
## This is equivalent to ``s = @[]; setlen(s, len)``, but more
|
||||||
|
|
@ -636,7 +636,7 @@ when not defined(JS):
|
||||||
|
|
||||||
proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.}
|
proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.}
|
||||||
## treats `x` as unsigned and converts it to a byte by taking the last 8 bits
|
## treats `x` as unsigned and converts it to a byte by taking the last 8 bits
|
||||||
## from `x`.
|
## from `x`.
|
||||||
proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect.}
|
proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect.}
|
||||||
## treats `x` as unsigned and converts it to an ``int16`` by taking the last
|
## treats `x` as unsigned and converts it to an ``int16`` by taking the last
|
||||||
## 16 bits from `x`.
|
## 16 bits from `x`.
|
||||||
|
|
@ -800,7 +800,7 @@ proc `%%` *(x, y: int64): int64 {.magic: "ModU", noSideEffect.}
|
||||||
## The result is truncated to fit into the result.
|
## The result is truncated to fit into the result.
|
||||||
## This implements modulo arithmetic.
|
## This implements modulo arithmetic.
|
||||||
## No overflow errors are possible.
|
## No overflow errors are possible.
|
||||||
|
|
||||||
proc `<=%` *(x, y: IntMax32): bool {.magic: "LeU", noSideEffect.}
|
proc `<=%` *(x, y: IntMax32): bool {.magic: "LeU", noSideEffect.}
|
||||||
proc `<=%` *(x, y: int64): bool {.magic: "LeU64", noSideEffect.}
|
proc `<=%` *(x, y: int64): bool {.magic: "LeU64", noSideEffect.}
|
||||||
## treats `x` and `y` as unsigned and compares them.
|
## treats `x` and `y` as unsigned and compares them.
|
||||||
|
|
@ -889,7 +889,7 @@ template `notin` * (x, y: expr): expr {.immediate, dirty.} = not contains(y, x)
|
||||||
|
|
||||||
proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
|
proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
|
||||||
## Checks if T is of the same type as S
|
## Checks if T is of the same type as S
|
||||||
##
|
##
|
||||||
## .. code-block:: Nim
|
## .. code-block:: Nim
|
||||||
## proc test[T](a: T): int =
|
## proc test[T](a: T): int =
|
||||||
## when (T is int):
|
## when (T is int):
|
||||||
|
|
@ -924,7 +924,7 @@ proc cmp*(x, y: string): int {.noSideEffect, procvar.}
|
||||||
proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {.
|
proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {.
|
||||||
magic: "ArrToSeq", nosideeffect.}
|
magic: "ArrToSeq", nosideeffect.}
|
||||||
## turns an array into a sequence. This most often useful for constructing
|
## turns an array into a sequence. This most often useful for constructing
|
||||||
## sequences with the array constructor: ``@[1, 2, 3]`` has the type
|
## sequences with the array constructor: ``@[1, 2, 3]`` has the type
|
||||||
## ``seq[int]``, while ``[1, 2, 3]`` has the type ``array[0..2, int]``.
|
## ``seq[int]``, while ``[1, 2, 3]`` has the type ``array[0..2, int]``.
|
||||||
|
|
||||||
proc setLen*[T](s: var seq[T], newlen: int) {.
|
proc setLen*[T](s: var seq[T], newlen: int) {.
|
||||||
|
|
@ -933,14 +933,14 @@ proc setLen*[T](s: var seq[T], newlen: int) {.
|
||||||
## ``T`` may be any sequence type.
|
## ``T`` may be any sequence type.
|
||||||
## If the current length is greater than the new length,
|
## If the current length is greater than the new length,
|
||||||
## ``s`` will be truncated. `s` cannot be nil! To initialize a sequence with
|
## ``s`` will be truncated. `s` cannot be nil! To initialize a sequence with
|
||||||
## a size, use ``newSeq`` instead.
|
## a size, use ``newSeq`` instead.
|
||||||
|
|
||||||
proc setLen*(s: var string, newlen: int) {.
|
proc setLen*(s: var string, newlen: int) {.
|
||||||
magic: "SetLengthStr", noSideEffect.}
|
magic: "SetLengthStr", noSideEffect.}
|
||||||
## sets the length of `s` to `newlen`.
|
## sets the length of `s` to `newlen`.
|
||||||
## If the current length is greater than the new length,
|
## If the current length is greater than the new length,
|
||||||
## ``s`` will be truncated. `s` cannot be nil! To initialize a string with
|
## ``s`` will be truncated. `s` cannot be nil! To initialize a string with
|
||||||
## a size, use ``newString`` instead.
|
## a size, use ``newString`` instead.
|
||||||
|
|
||||||
proc newString*(len: int): string {.
|
proc newString*(len: int): string {.
|
||||||
magic: "NewString", importc: "mnewString", noSideEffect.}
|
magic: "NewString", importc: "mnewString", noSideEffect.}
|
||||||
|
|
@ -953,7 +953,7 @@ proc newString*(len: int): string {.
|
||||||
proc newStringOfCap*(cap: int): string {.
|
proc newStringOfCap*(cap: int): string {.
|
||||||
magic: "NewStringOfCap", importc: "rawNewString", noSideEffect.}
|
magic: "NewStringOfCap", importc: "rawNewString", noSideEffect.}
|
||||||
## returns a new string of length ``0`` but with capacity `cap`.This
|
## returns a new string of length ``0`` but with capacity `cap`.This
|
||||||
## procedure exists only for optimization purposes; the same effect can
|
## procedure exists only for optimization purposes; the same effect can
|
||||||
## be achieved with the ``&`` operator or with ``add``.
|
## be achieved with the ``&`` operator or with ``add``.
|
||||||
|
|
||||||
proc `&` * (x: string, y: char): string {.
|
proc `&` * (x: string, y: char): string {.
|
||||||
|
|
@ -982,7 +982,7 @@ proc `&` * (x: char, y: string): string {.
|
||||||
## assert('a' & "bc" == "abc")
|
## assert('a' & "bc" == "abc")
|
||||||
|
|
||||||
# implementation note: These must all have the same magic value "ConStrStr" so
|
# implementation note: These must all have the same magic value "ConStrStr" so
|
||||||
# that the merge optimization works properly.
|
# that the merge optimization works properly.
|
||||||
|
|
||||||
proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.}
|
proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.}
|
||||||
## Appends `y` to `x` in place
|
## Appends `y` to `x` in place
|
||||||
|
|
@ -1039,15 +1039,15 @@ proc compileOption*(option: string): bool {.
|
||||||
## can be used to determine an on|off compile-time option. Example:
|
## can be used to determine an on|off compile-time option. Example:
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
## when compileOption("floatchecks"):
|
## when compileOption("floatchecks"):
|
||||||
## echo "compiled with floating point NaN and Inf checks"
|
## echo "compiled with floating point NaN and Inf checks"
|
||||||
|
|
||||||
proc compileOption*(option, arg: string): bool {.
|
proc compileOption*(option, arg: string): bool {.
|
||||||
magic: "CompileOptionArg", noSideEffect.}
|
magic: "CompileOptionArg", noSideEffect.}
|
||||||
## can be used to determine an enum compile-time option. Example:
|
## can be used to determine an enum compile-time option. Example:
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
## when compileOption("opt", "size") and compileOption("gc", "boehm"):
|
## when compileOption("opt", "size") and compileOption("gc", "boehm"):
|
||||||
## echo "compiled with optimization for size and uses Boehm's GC"
|
## echo "compiled with optimization for size and uses Boehm's GC"
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -1056,16 +1056,16 @@ const
|
||||||
taintMode = compileOption("taintmode")
|
taintMode = compileOption("taintmode")
|
||||||
|
|
||||||
when taintMode:
|
when taintMode:
|
||||||
type TaintedString* = distinct string ## a distinct string type that
|
type TaintedString* = distinct string ## a distinct string type that
|
||||||
## is `tainted`:idx:. It is an alias for
|
## is `tainted`:idx:. It is an alias for
|
||||||
## ``string`` if the taint mode is not
|
## ``string`` if the taint mode is not
|
||||||
## turned on. Use the ``-d:taintMode``
|
## turned on. Use the ``-d:taintMode``
|
||||||
## command line switch to turn the taint
|
## command line switch to turn the taint
|
||||||
## mode on.
|
## mode on.
|
||||||
|
|
||||||
proc len*(s: TaintedString): int {.borrow.}
|
proc len*(s: TaintedString): int {.borrow.}
|
||||||
else:
|
else:
|
||||||
type TaintedString* = string ## a distinct string type that
|
type TaintedString* = string ## a distinct string type that
|
||||||
## is `tainted`:idx:. It is an alias for
|
## is `tainted`:idx:. It is an alias for
|
||||||
## ``string`` if the taint mode is not
|
## ``string`` if the taint mode is not
|
||||||
## turned on. Use the ``-d:taintMode``
|
## turned on. Use the ``-d:taintMode``
|
||||||
|
|
@ -1136,25 +1136,25 @@ proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
|
||||||
proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".}
|
proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".}
|
||||||
## use this instead of `=` for a `shallow copy`:idx:. The shallow copy
|
## use this instead of `=` for a `shallow copy`:idx:. The shallow copy
|
||||||
## only changes the semantics for sequences and strings (and types which
|
## only changes the semantics for sequences and strings (and types which
|
||||||
## contain those). Be careful with the changed semantics though! There
|
## contain those). Be careful with the changed semantics though! There
|
||||||
## is a reason why the default assignment does a deep copy of sequences
|
## is a reason why the default assignment does a deep copy of sequences
|
||||||
## and strings.
|
## and strings.
|
||||||
|
|
||||||
proc del*[T](x: var seq[T], i: int) {.noSideEffect.} =
|
proc del*[T](x: var seq[T], i: int) {.noSideEffect.} =
|
||||||
## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
|
## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
|
||||||
## This is an O(1) operation.
|
## This is an O(1) operation.
|
||||||
let xl = x.len
|
let xl = x.len
|
||||||
shallowCopy(x[i], x[xl-1])
|
shallowCopy(x[i], x[xl-1])
|
||||||
setLen(x, xl-1)
|
setLen(x, xl-1)
|
||||||
|
|
||||||
proc delete*[T](x: var seq[T], i: int) {.noSideEffect.} =
|
proc delete*[T](x: var seq[T], i: int) {.noSideEffect.} =
|
||||||
## deletes the item at index `i` by moving ``x[i+1..]`` by one position.
|
## deletes the item at index `i` by moving ``x[i+1..]`` by one position.
|
||||||
## This is an O(n) operation.
|
## This is an O(n) operation.
|
||||||
let xl = x.len
|
let xl = x.len
|
||||||
for j in i..xl-2: shallowCopy(x[j], x[j+1])
|
for j in i..xl-2: shallowCopy(x[j], x[j+1])
|
||||||
setLen(x, xl-1)
|
setLen(x, xl-1)
|
||||||
|
|
||||||
proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} =
|
proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} =
|
||||||
## inserts `item` into `x` at position `i`.
|
## inserts `item` into `x` at position `i`.
|
||||||
let xl = x.len
|
let xl = x.len
|
||||||
setLen(x, xl+1)
|
setLen(x, xl+1)
|
||||||
|
|
@ -1233,7 +1233,7 @@ type # these work for most platforms:
|
||||||
## This is binary compatible to the type ``char**`` in *C*. The array's
|
## This is binary compatible to the type ``char**`` in *C*. The array's
|
||||||
## high value is large enough to disable bounds checking in practice.
|
## high value is large enough to disable bounds checking in practice.
|
||||||
## Use `cstringArrayToSeq` to convert it into a ``seq[string]``.
|
## Use `cstringArrayToSeq` to convert it into a ``seq[string]``.
|
||||||
|
|
||||||
PFloat32* = ptr float32 ## an alias for ``ptr float32``
|
PFloat32* = ptr float32 ## an alias for ``ptr float32``
|
||||||
PFloat64* = ptr float64 ## an alias for ``ptr float64``
|
PFloat64* = ptr float64 ## an alias for ``ptr float64``
|
||||||
PInt64* = ptr int64 ## an alias for ``ptr int64``
|
PInt64* = ptr int64 ## an alias for ``ptr int64``
|
||||||
|
|
@ -1280,7 +1280,7 @@ proc addQuitProc*(QuitProc: proc() {.noconv.}) {.
|
||||||
proc copy*(s: string, first = 0): string {.
|
proc copy*(s: string, first = 0): string {.
|
||||||
magic: "CopyStr", importc: "copyStr", noSideEffect, deprecated.}
|
magic: "CopyStr", importc: "copyStr", noSideEffect, deprecated.}
|
||||||
proc copy*(s: string, first, last: int): string {.
|
proc copy*(s: string, first, last: int): string {.
|
||||||
magic: "CopyStrLast", importc: "copyStrLast", noSideEffect,
|
magic: "CopyStrLast", importc: "copyStrLast", noSideEffect,
|
||||||
deprecated.}
|
deprecated.}
|
||||||
## copies a slice of `s` into a new string and returns this new
|
## copies a slice of `s` into a new string and returns this new
|
||||||
## string. The bounds `first` and `last` denote the indices of
|
## string. The bounds `first` and `last` denote the indices of
|
||||||
|
|
@ -1358,7 +1358,7 @@ when not defined(nimrodVM):
|
||||||
## The allocated memory belongs to its allocating thread!
|
## The allocated memory belongs to its allocating thread!
|
||||||
## Use `createShared` to allocate from a shared heap.
|
## Use `createShared` to allocate from a shared heap.
|
||||||
cast[ptr T](alloc0(T.sizeof * size))
|
cast[ptr T](alloc0(T.sizeof * size))
|
||||||
proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [],
|
proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [],
|
||||||
benign.}
|
benign.}
|
||||||
## grows or shrinks a given memory block. If p is **nil** then a new
|
## grows or shrinks a given memory block. If p is **nil** then a new
|
||||||
## memory block is returned. In either way the block has at least
|
## memory block is returned. In either way the block has at least
|
||||||
|
|
@ -1381,7 +1381,7 @@ when not defined(nimrodVM):
|
||||||
## ``realloc``. This procedure is dangerous! If one forgets to
|
## ``realloc``. This procedure is dangerous! If one forgets to
|
||||||
## free the memory a leak occurs; if one tries to access freed
|
## free the memory a leak occurs; if one tries to access freed
|
||||||
## memory (or just freeing it twice!) a core dump may happen
|
## memory (or just freeing it twice!) a core dump may happen
|
||||||
## or other memory may be corrupted.
|
## or other memory may be corrupted.
|
||||||
## The freed memory must belong to its allocating thread!
|
## The freed memory must belong to its allocating thread!
|
||||||
## Use `deallocShared` to deallocate from a shared heap.
|
## Use `deallocShared` to deallocate from a shared heap.
|
||||||
proc free*[T](p: ptr T) {.inline, benign.} =
|
proc free*[T](p: ptr T) {.inline, benign.} =
|
||||||
|
|
@ -1390,30 +1390,30 @@ when not defined(nimrodVM):
|
||||||
## allocates a new memory block on the shared heap with at
|
## allocates a new memory block on the shared heap with at
|
||||||
## least ``size`` bytes. The block has to be freed with
|
## least ``size`` bytes. The block has to be freed with
|
||||||
## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
|
## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
|
||||||
## is not initialized, so reading from it before writing to it is
|
## is not initialized, so reading from it before writing to it is
|
||||||
## undefined behaviour!
|
## undefined behaviour!
|
||||||
proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline,
|
proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline,
|
||||||
benign.} =
|
benign.} =
|
||||||
## allocates a new memory block on the shared heap with at
|
## allocates a new memory block on the shared heap with at
|
||||||
## least ``T.sizeof * size`` bytes. The block has to be freed with
|
## least ``T.sizeof * size`` bytes. The block has to be freed with
|
||||||
## ``resizeShared(block, 0)`` or ``freeShared(block)``. The block
|
## ``resizeShared(block, 0)`` or ``freeShared(block)``. The block
|
||||||
## is not initialized, so reading from it before writing to it is
|
## is not initialized, so reading from it before writing to it is
|
||||||
## undefined behaviour!
|
## undefined behaviour!
|
||||||
cast[ptr T](allocShared(T.sizeof * size))
|
cast[ptr T](allocShared(T.sizeof * size))
|
||||||
proc allocShared0*(size: int): pointer {.noconv, rtl, benign.}
|
proc allocShared0*(size: int): pointer {.noconv, rtl, benign.}
|
||||||
## allocates a new memory block on the shared heap with at
|
## allocates a new memory block on the shared heap with at
|
||||||
## least ``size`` bytes. The block has to be freed with
|
## least ``size`` bytes. The block has to be freed with
|
||||||
## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
|
## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
|
||||||
## The block is initialized with all bytes
|
## The block is initialized with all bytes
|
||||||
## containing zero, so it is somewhat safer than ``allocShared``.
|
## containing zero, so it is somewhat safer than ``allocShared``.
|
||||||
proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
|
proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
|
||||||
## allocates a new memory block on the shared heap with at
|
## allocates a new memory block on the shared heap with at
|
||||||
## least ``T.sizeof * size`` bytes. The block has to be freed with
|
## least ``T.sizeof * size`` bytes. The block has to be freed with
|
||||||
## ``resizeShared(block, 0)`` or ``freeShared(block)``.
|
## ``resizeShared(block, 0)`` or ``freeShared(block)``.
|
||||||
## The block is initialized with all bytes
|
## The block is initialized with all bytes
|
||||||
## containing zero, so it is somewhat safer than ``createSharedU``.
|
## containing zero, so it is somewhat safer than ``createSharedU``.
|
||||||
cast[ptr T](allocShared0(T.sizeof * size))
|
cast[ptr T](allocShared0(T.sizeof * size))
|
||||||
proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl,
|
proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl,
|
||||||
benign.}
|
benign.}
|
||||||
## grows or shrinks a given memory block on the heap. If p is **nil**
|
## grows or shrinks a given memory block on the heap. If p is **nil**
|
||||||
## then a new memory block is returned. In either way the block has at
|
## then a new memory block is returned. In either way the block has at
|
||||||
|
|
@ -1525,7 +1525,7 @@ const
|
||||||
NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
|
NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
|
||||||
## is the version of Nim as a string.
|
## is the version of Nim as a string.
|
||||||
|
|
||||||
{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion,
|
{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion,
|
||||||
NimrodMajor: NimMajor, NimrodMinor: NimMinor, NimrodPatch: NimPatch].}
|
NimrodMajor: NimMajor, NimrodMinor: NimMinor, NimrodPatch: NimPatch].}
|
||||||
|
|
||||||
# GC interface:
|
# GC interface:
|
||||||
|
|
@ -1805,7 +1805,7 @@ proc `==` *[I, T](x, y: array[I, T]): bool =
|
||||||
return
|
return
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc `@`*[T](a: openArray[T]): seq[T] =
|
proc `@`*[T](a: openArray[T]): seq[T] =
|
||||||
## turns an openarray into a sequence. This is not as efficient as turning
|
## turns an openarray into a sequence. This is not as efficient as turning
|
||||||
## a fixed length array into a sequence as it always copies every element
|
## a fixed length array into a sequence as it always copies every element
|
||||||
## of `a`.
|
## of `a`.
|
||||||
|
|
@ -1853,7 +1853,7 @@ when not defined(NimrodVM):
|
||||||
else:
|
else:
|
||||||
proc seqToPtr[T](x: seq[T]): pointer {.asmNoStackFrame, nosideeffect.} =
|
proc seqToPtr[T](x: seq[T]): pointer {.asmNoStackFrame, nosideeffect.} =
|
||||||
asm """return `x`"""
|
asm """return `x`"""
|
||||||
|
|
||||||
proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} =
|
proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} =
|
||||||
## Generic equals operator for sequences: relies on a equals operator for
|
## Generic equals operator for sequences: relies on a equals operator for
|
||||||
## the element type `T`.
|
## the element type `T`.
|
||||||
|
|
@ -1879,7 +1879,7 @@ proc contains*[T](a: openArray[T], item: T): bool {.inline.}=
|
||||||
## for ``find(a, item) >= 0``.
|
## for ``find(a, item) >= 0``.
|
||||||
return find(a, item) >= 0
|
return find(a, item) >= 0
|
||||||
|
|
||||||
proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} =
|
proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} =
|
||||||
## returns the last item of `s` and decreases ``s.len`` by one. This treats
|
## returns the last item of `s` and decreases ``s.len`` by one. This treats
|
||||||
## `s` as a stack and implements the common *pop* operation.
|
## `s` as a stack and implements the common *pop* operation.
|
||||||
var L = s.len-1
|
var L = s.len-1
|
||||||
|
|
@ -1941,7 +1941,7 @@ iterator fields*[T: tuple|object](x: T): RootObj {.
|
||||||
iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[a,b: expr] {.
|
iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[a,b: expr] {.
|
||||||
magic: "Fields", noSideEffect.}
|
magic: "Fields", noSideEffect.}
|
||||||
## iterates over every field of `x` and `y`.
|
## iterates over every field of `x` and `y`.
|
||||||
## Warning: This is really transforms the 'for' and unrolls the loop.
|
## Warning: This is really transforms the 'for' and unrolls the loop.
|
||||||
## The current implementation also has a bug that affects symbol binding
|
## The current implementation also has a bug that affects symbol binding
|
||||||
## in the loop body.
|
## in the loop body.
|
||||||
iterator fieldPairs*[T: tuple|object](x: T): RootObj {.
|
iterator fieldPairs*[T: tuple|object](x: T): RootObj {.
|
||||||
|
|
@ -1982,18 +1982,18 @@ iterator fieldPairs*[S: tuple|object, T: tuple|object](x: S, y: T): tuple[
|
||||||
a, b: expr] {.
|
a, b: expr] {.
|
||||||
magic: "FieldPairs", noSideEffect.}
|
magic: "FieldPairs", noSideEffect.}
|
||||||
## iterates over every field of `x` and `y`.
|
## iterates over every field of `x` and `y`.
|
||||||
## Warning: This really transforms the 'for' and unrolls the loop.
|
## Warning: This really transforms the 'for' and unrolls the loop.
|
||||||
## The current implementation also has a bug that affects symbol binding
|
## The current implementation also has a bug that affects symbol binding
|
||||||
## in the loop body.
|
## in the loop body.
|
||||||
|
|
||||||
proc `==`*[T: tuple|object](x, y: T): bool =
|
proc `==`*[T: tuple|object](x, y: T): bool =
|
||||||
## generic ``==`` operator for tuples that is lifted from the components
|
## generic ``==`` operator for tuples that is lifted from the components
|
||||||
## of `x` and `y`.
|
## of `x` and `y`.
|
||||||
for a, b in fields(x, y):
|
for a, b in fields(x, y):
|
||||||
if a != b: return false
|
if a != b: return false
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc `<=`*[T: tuple](x, y: T): bool =
|
proc `<=`*[T: tuple](x, y: T): bool =
|
||||||
## generic ``<=`` operator for tuples that is lifted from the components
|
## generic ``<=`` operator for tuples that is lifted from the components
|
||||||
## of `x` and `y`. This implementation uses `cmp`.
|
## of `x` and `y`. This implementation uses `cmp`.
|
||||||
for a, b in fields(x, y):
|
for a, b in fields(x, y):
|
||||||
|
|
@ -2002,7 +2002,7 @@ proc `<=`*[T: tuple](x, y: T): bool =
|
||||||
if c > 0: return false
|
if c > 0: return false
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc `<`*[T: tuple](x, y: T): bool =
|
proc `<`*[T: tuple](x, y: T): bool =
|
||||||
## generic ``<`` operator for tuples that is lifted from the components
|
## generic ``<`` operator for tuples that is lifted from the components
|
||||||
## of `x` and `y`. This implementation uses `cmp`.
|
## of `x` and `y`. This implementation uses `cmp`.
|
||||||
for a, b in fields(x, y):
|
for a, b in fields(x, y):
|
||||||
|
|
@ -2011,7 +2011,7 @@ proc `<`*[T: tuple](x, y: T): bool =
|
||||||
if c > 0: return false
|
if c > 0: return false
|
||||||
return false
|
return false
|
||||||
|
|
||||||
proc `$`*[T: tuple|object](x: T): string =
|
proc `$`*[T: tuple|object](x: T): string =
|
||||||
## generic ``$`` operator for tuples that is lifted from the components
|
## generic ``$`` operator for tuples that is lifted from the components
|
||||||
## of `x`. Example:
|
## of `x`. Example:
|
||||||
##
|
##
|
||||||
|
|
@ -2021,13 +2021,13 @@ proc `$`*[T: tuple|object](x: T): string =
|
||||||
result = "("
|
result = "("
|
||||||
var firstElement = true
|
var firstElement = true
|
||||||
for name, value in fieldPairs(x):
|
for name, value in fieldPairs(x):
|
||||||
if not(firstElement): result.add(", ")
|
if not firstElement: result.add(", ")
|
||||||
result.add(name)
|
result.add(name)
|
||||||
result.add(": ")
|
result.add(": ")
|
||||||
result.add($value)
|
result.add($value)
|
||||||
firstElement = false
|
firstElement = false
|
||||||
result.add(")")
|
result.add(")")
|
||||||
|
|
||||||
proc collectionToString[T](x: T, b, e: string): string =
|
proc collectionToString[T](x: T, b, e: string): string =
|
||||||
result = b
|
result = b
|
||||||
var firstElement = true
|
var firstElement = true
|
||||||
|
|
@ -2037,7 +2037,7 @@ proc collectionToString[T](x: T, b, e: string): string =
|
||||||
firstElement = false
|
firstElement = false
|
||||||
result.add(e)
|
result.add(e)
|
||||||
|
|
||||||
proc `$`*[T](x: set[T]): string =
|
proc `$`*[T](x: set[T]): string =
|
||||||
## generic ``$`` operator for sets that is lifted from the components
|
## generic ``$`` operator for sets that is lifted from the components
|
||||||
## of `x`. Example:
|
## of `x`. Example:
|
||||||
##
|
##
|
||||||
|
|
@ -2045,7 +2045,7 @@ proc `$`*[T](x: set[T]): string =
|
||||||
## ${23, 45} == "{23, 45}"
|
## ${23, 45} == "{23, 45}"
|
||||||
collectionToString(x, "{", "}")
|
collectionToString(x, "{", "}")
|
||||||
|
|
||||||
proc `$`*[T](x: seq[T]): string =
|
proc `$`*[T](x: seq[T]): string =
|
||||||
## generic ``$`` operator for seqs that is lifted from the components
|
## generic ``$`` operator for seqs that is lifted from the components
|
||||||
## of `x`. Example:
|
## of `x`. Example:
|
||||||
##
|
##
|
||||||
|
|
@ -2056,7 +2056,7 @@ proc `$`*[T](x: seq[T]): string =
|
||||||
when false:
|
when false:
|
||||||
# causes bootstrapping to fail as we use array of chars and cstring should
|
# causes bootstrapping to fail as we use array of chars and cstring should
|
||||||
# match better ...
|
# match better ...
|
||||||
proc `$`*[T, IDX](x: array[IDX, T]): string =
|
proc `$`*[T, IDX](x: array[IDX, T]): string =
|
||||||
collectionToString(x, "[", "]")
|
collectionToString(x, "[", "]")
|
||||||
|
|
||||||
# ----------------- GC interface ---------------------------------------------
|
# ----------------- GC interface ---------------------------------------------
|
||||||
|
|
@ -2098,14 +2098,14 @@ when not defined(nimrodVM) and hostOS != "standalone":
|
||||||
proc GC_getStatistics*(): string {.rtl, benign.}
|
proc GC_getStatistics*(): string {.rtl, benign.}
|
||||||
## returns an informative string about the GC's activity. This may be useful
|
## returns an informative string about the GC's activity. This may be useful
|
||||||
## for tweaking.
|
## for tweaking.
|
||||||
|
|
||||||
proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
|
proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
|
||||||
proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
|
proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
|
||||||
proc GC_ref*(x: string) {.magic: "GCref", benign.}
|
proc GC_ref*(x: string) {.magic: "GCref", benign.}
|
||||||
## marks the object `x` as referenced, so that it will not be freed until
|
## marks the object `x` as referenced, so that it will not be freed until
|
||||||
## it is unmarked via `GC_unref`. If called n-times for the same object `x`,
|
## it is unmarked via `GC_unref`. If called n-times for the same object `x`,
|
||||||
## n calls to `GC_unref` are needed to unmark `x`.
|
## n calls to `GC_unref` are needed to unmark `x`.
|
||||||
|
|
||||||
proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.}
|
proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.}
|
||||||
proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
|
proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
|
||||||
proc GC_unref*(x: string) {.magic: "GCunref", benign.}
|
proc GC_unref*(x: string) {.magic: "GCunref", benign.}
|
||||||
|
|
@ -2141,19 +2141,19 @@ var
|
||||||
## application code should never set this hook! You better know what you
|
## application code should never set this hook! You better know what you
|
||||||
## do when setting this. If ``localRaiseHook`` returns false, the exception
|
## do when setting this. If ``localRaiseHook`` returns false, the exception
|
||||||
## is caught and does not propagate further through the call stack.
|
## is caught and does not propagate further through the call stack.
|
||||||
|
|
||||||
outOfMemHook*: proc () {.nimcall, tags: [], benign.}
|
outOfMemHook*: proc () {.nimcall, tags: [], benign.}
|
||||||
## set this variable to provide a procedure that should be called
|
## set this variable to provide a procedure that should be called
|
||||||
## in case of an `out of memory`:idx: event. The standard handler
|
## in case of an `out of memory`:idx: event. The standard handler
|
||||||
## writes an error message and terminates the program. `outOfMemHook` can
|
## writes an error message and terminates the program. `outOfMemHook` can
|
||||||
## be used to raise an exception in case of OOM like so:
|
## be used to raise an exception in case of OOM like so:
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
##
|
##
|
||||||
## var gOutOfMem: ref EOutOfMemory
|
## var gOutOfMem: ref EOutOfMemory
|
||||||
## new(gOutOfMem) # need to be allocated *before* OOM really happened!
|
## new(gOutOfMem) # need to be allocated *before* OOM really happened!
|
||||||
## gOutOfMem.msg = "out of memory"
|
## gOutOfMem.msg = "out of memory"
|
||||||
##
|
##
|
||||||
## proc handleOOM() =
|
## proc handleOOM() =
|
||||||
## raise gOutOfMem
|
## raise gOutOfMem
|
||||||
##
|
##
|
||||||
|
|
@ -2210,7 +2210,7 @@ proc echo*(x: varargs[expr, `$`]) {.magic: "Echo", tags: [WriteIOEffect],
|
||||||
## <manual.html#nosideeffect-pragma>`_ you can use `debugEcho <#debugEcho>`_
|
## <manual.html#nosideeffect-pragma>`_ you can use `debugEcho <#debugEcho>`_
|
||||||
## instead.
|
## instead.
|
||||||
|
|
||||||
proc debugEcho*(x: varargs[expr, `$`]) {.magic: "Echo", noSideEffect,
|
proc debugEcho*(x: varargs[expr, `$`]) {.magic: "Echo", noSideEffect,
|
||||||
tags: [], raises: [].}
|
tags: [], raises: [].}
|
||||||
## Same as `echo <#echo>`_, but as a special semantic rule, ``debugEcho``
|
## Same as `echo <#echo>`_, but as a special semantic rule, ``debugEcho``
|
||||||
## pretends to be free of side effects, so that it can be used for debugging
|
## pretends to be free of side effects, so that it can be used for debugging
|
||||||
|
|
@ -2262,7 +2262,7 @@ proc abs*(x: int16): int16 {.magic: "AbsI", noSideEffect.} =
|
||||||
proc abs*(x: int32): int32 {.magic: "AbsI", noSideEffect.} =
|
proc abs*(x: int32): int32 {.magic: "AbsI", noSideEffect.} =
|
||||||
if x < 0: -x else: x
|
if x < 0: -x else: x
|
||||||
proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.} =
|
proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.} =
|
||||||
## returns the absolute value of `x`. If `x` is ``low(x)`` (that
|
## returns the absolute value of `x`. If `x` is ``low(x)`` (that
|
||||||
## is -MININT for its type), an overflow exception is thrown (if overflow
|
## is -MININT for its type), an overflow exception is thrown (if overflow
|
||||||
## checking is turned on).
|
## checking is turned on).
|
||||||
if x < 0: -x else: x
|
if x < 0: -x else: x
|
||||||
|
|
@ -2318,14 +2318,14 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
# we use binary mode in Windows:
|
# we use binary mode in Windows:
|
||||||
setmode(fileno(c_stdin), O_BINARY)
|
setmode(fileno(c_stdin), O_BINARY)
|
||||||
setmode(fileno(c_stdout), O_BINARY)
|
setmode(fileno(c_stdout), O_BINARY)
|
||||||
|
|
||||||
when defined(endb):
|
when defined(endb):
|
||||||
proc endbStep()
|
proc endbStep()
|
||||||
|
|
||||||
# ----------------- IO Part ------------------------------------------------
|
# ----------------- IO Part ------------------------------------------------
|
||||||
when hostOS != "standalone":
|
when hostOS != "standalone":
|
||||||
type
|
type
|
||||||
CFile {.importc: "FILE", header: "<stdio.h>",
|
CFile {.importc: "FILE", header: "<stdio.h>",
|
||||||
final, incompletestruct.} = object
|
final, incompletestruct.} = object
|
||||||
File* = ptr CFile ## The type representing a file handle.
|
File* = ptr CFile ## The type representing a file handle.
|
||||||
|
|
||||||
|
|
@ -2375,9 +2375,9 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
## Creates a ``TFile`` from a `filehandle` with given `mode`.
|
## Creates a ``TFile`` from a `filehandle` with given `mode`.
|
||||||
##
|
##
|
||||||
## Default mode is readonly. Returns true iff the file could be opened.
|
## Default mode is readonly. Returns true iff the file could be opened.
|
||||||
|
|
||||||
proc open*(filename: string,
|
proc open*(filename: string,
|
||||||
mode: FileMode = fmRead, bufSize: int = -1): File =
|
mode: FileMode = fmRead, bufSize: int = -1): File =
|
||||||
## Opens a file named `filename` with given `mode`.
|
## Opens a file named `filename` with given `mode`.
|
||||||
##
|
##
|
||||||
## Default mode is readonly. Raises an ``IO`` exception if the file
|
## Default mode is readonly. Raises an ``IO`` exception if the file
|
||||||
|
|
@ -2387,7 +2387,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
|
|
||||||
proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {.
|
proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {.
|
||||||
tags: [], benign.}
|
tags: [], benign.}
|
||||||
## reopens the file `f` with given `filename` and `mode`. This
|
## reopens the file `f` with given `filename` and `mode`. This
|
||||||
## is often used to redirect the `stdin`, `stdout` or `stderr`
|
## is often used to redirect the `stdin`, `stdout` or `stderr`
|
||||||
## file variables.
|
## file variables.
|
||||||
##
|
##
|
||||||
|
|
@ -2398,7 +2398,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
|
|
||||||
proc endOfFile*(f: File): bool {.tags: [], benign.}
|
proc endOfFile*(f: File): bool {.tags: [], benign.}
|
||||||
## Returns true iff `f` is at the end.
|
## Returns true iff `f` is at the end.
|
||||||
|
|
||||||
proc readChar*(f: File): char {.
|
proc readChar*(f: File): char {.
|
||||||
importc: "fgetc", header: "<stdio.h>", tags: [ReadIOEffect].}
|
importc: "fgetc", header: "<stdio.h>", tags: [ReadIOEffect].}
|
||||||
## Reads a single character from the stream `f`.
|
## Reads a single character from the stream `f`.
|
||||||
|
|
@ -2411,7 +2411,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
##
|
##
|
||||||
## Raises an IO exception in case of an error. It is an error if the
|
## Raises an IO exception in case of an error. It is an error if the
|
||||||
## current file position is not at the beginning of the file.
|
## current file position is not at the beginning of the file.
|
||||||
|
|
||||||
proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.}
|
proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.}
|
||||||
## Opens a file named `filename` for reading.
|
## Opens a file named `filename` for reading.
|
||||||
##
|
##
|
||||||
|
|
@ -2440,8 +2440,8 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
## reads a line of text from the file `f`. May throw an IO exception.
|
## reads a line of text from the file `f`. May throw an IO exception.
|
||||||
## A line of text may be delimited by ``CR``, ``LF`` or
|
## A line of text may be delimited by ``CR``, ``LF`` or
|
||||||
## ``CRLF``. The newline character(s) are not part of the returned string.
|
## ``CRLF``. The newline character(s) are not part of the returned string.
|
||||||
|
|
||||||
proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect],
|
proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect],
|
||||||
benign.}
|
benign.}
|
||||||
## reads a line of text from the file `f` into `line`. `line` must not be
|
## reads a line of text from the file `f` into `line`. `line` must not be
|
||||||
## ``nil``! May throw an IO exception.
|
## ``nil``! May throw an IO exception.
|
||||||
|
|
@ -2450,7 +2450,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
## Returns ``false`` if the end of the file has been reached, ``true``
|
## Returns ``false`` if the end of the file has been reached, ``true``
|
||||||
## otherwise. If ``false`` is returned `line` contains no new data.
|
## otherwise. If ``false`` is returned `line` contains no new data.
|
||||||
|
|
||||||
proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
|
proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
|
||||||
tags: [WriteIOEffect], benign.}
|
tags: [WriteIOEffect], benign.}
|
||||||
## writes the values `x` to `f` and then writes "\n".
|
## writes the values `x` to `f` and then writes "\n".
|
||||||
## May throw an IO exception.
|
## May throw an IO exception.
|
||||||
|
|
@ -2544,11 +2544,11 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
dealloc(a)
|
dealloc(a)
|
||||||
|
|
||||||
when not defined(NimrodVM):
|
when not defined(NimrodVM):
|
||||||
proc atomicInc*(memLoc: var int, x: int = 1): int {.inline,
|
proc atomicInc*(memLoc: var int, x: int = 1): int {.inline,
|
||||||
discardable, benign.}
|
discardable, benign.}
|
||||||
## atomic increment of `memLoc`. Returns the value after the operation.
|
## atomic increment of `memLoc`. Returns the value after the operation.
|
||||||
|
|
||||||
proc atomicDec*(memLoc: var int, x: int = 1): int {.inline,
|
proc atomicDec*(memLoc: var int, x: int = 1): int {.inline,
|
||||||
discardable, benign.}
|
discardable, benign.}
|
||||||
## atomic decrement of `memLoc`. Returns the value after the operation.
|
## atomic decrement of `memLoc`. Returns the value after the operation.
|
||||||
|
|
||||||
|
|
@ -2562,7 +2562,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
context: C_JmpBuf
|
context: C_JmpBuf
|
||||||
hasRaiseAction: bool
|
hasRaiseAction: bool
|
||||||
raiseAction: proc (e: ref Exception): bool {.closure.}
|
raiseAction: proc (e: ref Exception): bool {.closure.}
|
||||||
|
|
||||||
when declared(initAllocator):
|
when declared(initAllocator):
|
||||||
initAllocator()
|
initAllocator()
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
|
|
@ -2576,7 +2576,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
proc setControlCHook*(hook: proc () {.noconv.} not nil)
|
proc setControlCHook*(hook: proc () {.noconv.} not nil)
|
||||||
## allows you to override the behaviour of your application when CTRL+C
|
## allows you to override the behaviour of your application when CTRL+C
|
||||||
## is pressed. Only one such hook is supported.
|
## is pressed. Only one such hook is supported.
|
||||||
|
|
||||||
proc writeStackTrace*() {.tags: [WriteIOEffect].}
|
proc writeStackTrace*() {.tags: [WriteIOEffect].}
|
||||||
## writes the current stack trace to ``stderr``. This is only works
|
## writes the current stack trace to ``stderr``. This is only works
|
||||||
## for debug builds.
|
## for debug builds.
|
||||||
|
|
@ -2587,20 +2587,20 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
proc getStackTrace*(e: ref Exception): string
|
proc getStackTrace*(e: ref Exception): string
|
||||||
## gets the stack trace associated with `e`, which is the stack that
|
## gets the stack trace associated with `e`, which is the stack that
|
||||||
## lead to the ``raise`` statement. This only works for debug builds.
|
## lead to the ``raise`` statement. This only works for debug builds.
|
||||||
|
|
||||||
{.push stack_trace: off, profiler:off.}
|
{.push stack_trace: off, profiler:off.}
|
||||||
when hostOS == "standalone":
|
when hostOS == "standalone":
|
||||||
include "system/embedded"
|
include "system/embedded"
|
||||||
else:
|
else:
|
||||||
include "system/excpt"
|
include "system/excpt"
|
||||||
include "system/chcks"
|
include "system/chcks"
|
||||||
|
|
||||||
# we cannot compile this with stack tracing on
|
# we cannot compile this with stack tracing on
|
||||||
# as it would recurse endlessly!
|
# as it would recurse endlessly!
|
||||||
include "system/arithm"
|
include "system/arithm"
|
||||||
{.pop.} # stack trace
|
{.pop.} # stack trace
|
||||||
{.pop.} # stack trace
|
{.pop.} # stack trace
|
||||||
|
|
||||||
when hostOS != "standalone" and not defined(NimrodVM):
|
when hostOS != "standalone" and not defined(NimrodVM):
|
||||||
include "system/dyncalls"
|
include "system/dyncalls"
|
||||||
when not defined(NimrodVM):
|
when not defined(NimrodVM):
|
||||||
|
|
@ -2608,7 +2608,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
|
|
||||||
const
|
const
|
||||||
GenericSeqSize = (2 * sizeof(int))
|
GenericSeqSize = (2 * sizeof(int))
|
||||||
|
|
||||||
proc getDiscriminant(aa: pointer, n: ptr TNimNode): int =
|
proc getDiscriminant(aa: pointer, n: ptr TNimNode): int =
|
||||||
sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
|
sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
|
||||||
var d: int
|
var d: int
|
||||||
|
|
@ -2728,7 +2728,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
## process(value)
|
## process(value)
|
||||||
## else:
|
## else:
|
||||||
## echo "Value too big!"
|
## echo "Value too big!"
|
||||||
|
|
||||||
proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
|
proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
|
||||||
## Hints the optimizer that `val` is likely going to be false.
|
## Hints the optimizer that `val` is likely going to be false.
|
||||||
##
|
##
|
||||||
|
|
@ -2742,7 +2742,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
## echo "Value too big!"
|
## echo "Value too big!"
|
||||||
## else:
|
## else:
|
||||||
## process(value)
|
## process(value)
|
||||||
|
|
||||||
proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} =
|
proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} =
|
||||||
## retrieves the raw proc pointer of the closure `x`. This is
|
## retrieves the raw proc pointer of the closure `x`. This is
|
||||||
## useful for interfacing closures with C.
|
## useful for interfacing closures with C.
|
||||||
|
|
@ -2774,7 +2774,7 @@ elif defined(JS):
|
||||||
proc GC_enableMarkAndSweep() = discard
|
proc GC_enableMarkAndSweep() = discard
|
||||||
proc GC_disableMarkAndSweep() = discard
|
proc GC_disableMarkAndSweep() = discard
|
||||||
proc GC_getStatistics(): string = return ""
|
proc GC_getStatistics(): string = return ""
|
||||||
|
|
||||||
proc getOccupiedMem(): int = return -1
|
proc getOccupiedMem(): int = return -1
|
||||||
proc getFreeMem(): int = return -1
|
proc getFreeMem(): int = return -1
|
||||||
proc getTotalMem(): int = return -1
|
proc getTotalMem(): int = return -1
|
||||||
|
|
@ -2797,7 +2797,7 @@ elif defined(JS):
|
||||||
if x == y: return 0
|
if x == y: return 0
|
||||||
if x < y: return -1
|
if x < y: return -1
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
when defined(nimffi):
|
when defined(nimffi):
|
||||||
include "system/sysio"
|
include "system/sysio"
|
||||||
|
|
||||||
|
|
@ -2831,14 +2831,14 @@ template spliceImpl(s, a, L, b: expr): stmt {.immediate.} =
|
||||||
# cut down:
|
# cut down:
|
||||||
setLen(s, newLen)
|
setLen(s, newLen)
|
||||||
# fill the hole:
|
# fill the hole:
|
||||||
for i in 0 .. <b.len: s[i+a] = b[i]
|
for i in 0 .. <b.len: s[i+a] = b[i]
|
||||||
|
|
||||||
when hostOS != "standalone":
|
when hostOS != "standalone":
|
||||||
proc `[]`*(s: string, x: Slice[int]): string {.inline.} =
|
proc `[]`*(s: string, x: Slice[int]): string {.inline.} =
|
||||||
## slice operation for strings. Negative indexes are supported.
|
## slice operation for strings. Negative indexes are supported.
|
||||||
result = s.substr(x.a-|s, x.b-|s)
|
result = s.substr(x.a-|s, x.b-|s)
|
||||||
|
|
||||||
proc `[]=`*(s: var string, x: Slice[int], b: string) =
|
proc `[]=`*(s: var string, x: Slice[int], b: string) =
|
||||||
## slice assignment for strings. Negative indexes are supported. If
|
## slice assignment for strings. Negative indexes are supported. If
|
||||||
## ``b.len`` is not exactly the number of elements that are referred to
|
## ``b.len`` is not exactly the number of elements that are referred to
|
||||||
## by `x`, a `splice`:idx: is performed:
|
## by `x`, a `splice`:idx: is performed:
|
||||||
|
|
@ -2880,7 +2880,7 @@ proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[Idx]): seq[T] =
|
||||||
var L = ord(x.b) - ord(x.a) + 1
|
var L = ord(x.b) - ord(x.a) + 1
|
||||||
newSeq(result, L)
|
newSeq(result, L)
|
||||||
var j = x.a
|
var j = x.a
|
||||||
for i in 0.. <L:
|
for i in 0.. <L:
|
||||||
result[i] = a[j]
|
result[i] = a[j]
|
||||||
inc(j)
|
inc(j)
|
||||||
|
|
||||||
|
|
@ -2890,23 +2890,23 @@ proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[Idx], b: openArray[T]) =
|
||||||
var L = ord(x.b) - ord(x.a) + 1
|
var L = ord(x.b) - ord(x.a) + 1
|
||||||
if L == b.len:
|
if L == b.len:
|
||||||
var j = x.a
|
var j = x.a
|
||||||
for i in 0 .. <L:
|
for i in 0 .. <L:
|
||||||
a[j] = b[i]
|
a[j] = b[i]
|
||||||
inc(j)
|
inc(j)
|
||||||
else:
|
else:
|
||||||
sysFatal(RangeError, "different lengths for slice assignment")
|
sysFatal(RangeError, "different lengths for slice assignment")
|
||||||
|
|
||||||
proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] =
|
proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] =
|
||||||
## slice operation for sequences. Negative indexes are supported.
|
## slice operation for sequences. Negative indexes are supported.
|
||||||
var a = x.a-|s
|
var a = x.a-|s
|
||||||
var L = x.b-|s - a + 1
|
var L = x.b-|s - a + 1
|
||||||
newSeq(result, L)
|
newSeq(result, L)
|
||||||
for i in 0.. <L: result[i] = s[i + a]
|
for i in 0.. <L: result[i] = s[i + a]
|
||||||
|
|
||||||
proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) =
|
proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) =
|
||||||
## slice assignment for sequences. Negative indexes are supported. If
|
## slice assignment for sequences. Negative indexes are supported. If
|
||||||
## ``b.len`` is not exactly the number of elements that are referred to
|
## ``b.len`` is not exactly the number of elements that are referred to
|
||||||
## by `x`, a `splice`:idx: is performed.
|
## by `x`, a `splice`:idx: is performed.
|
||||||
var a = x.a-|s
|
var a = x.a-|s
|
||||||
var L = x.b-|s - a + 1
|
var L = x.b-|s - a + 1
|
||||||
if L == b.len:
|
if L == b.len:
|
||||||
|
|
@ -2937,7 +2937,7 @@ proc staticExec*(command: string, input = ""): string {.
|
||||||
## to the executed program.
|
## to the executed program.
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
## const buildInfo = "Revision " & staticExec("git rev-parse HEAD") &
|
## const buildInfo = "Revision " & staticExec("git rev-parse HEAD") &
|
||||||
## "\nCompiled on " & staticExec("uname -v")
|
## "\nCompiled on " & staticExec("uname -v")
|
||||||
##
|
##
|
||||||
## `gorge <#gorge>`_ is an alias for ``staticExec``. Note that you can use
|
## `gorge <#gorge>`_ is an alias for ``staticExec``. Note that you can use
|
||||||
|
|
@ -2979,7 +2979,7 @@ proc `&=`* (x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.}
|
||||||
proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.}
|
proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.}
|
||||||
## converts the AST of `x` into a string representation. This is very useful
|
## converts the AST of `x` into a string representation. This is very useful
|
||||||
## for debugging.
|
## for debugging.
|
||||||
|
|
||||||
proc instantiationInfo*(index = -1, fullPaths = false): tuple[
|
proc instantiationInfo*(index = -1, fullPaths = false): tuple[
|
||||||
filename: string, line: int] {. magic: "InstantiationInfo", noSideEffect.}
|
filename: string, line: int] {. magic: "InstantiationInfo", noSideEffect.}
|
||||||
## provides access to the compiler's instantiation stack line information.
|
## provides access to the compiler's instantiation stack line information.
|
||||||
|
|
@ -3090,16 +3090,16 @@ template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} =
|
||||||
## Sets an assertion failure handler that will intercept any assert
|
## Sets an assertion failure handler that will intercept any assert
|
||||||
## statements following `onFailedAssert` in the current lexical scope.
|
## statements following `onFailedAssert` in the current lexical scope.
|
||||||
## Can be defined multiple times in a single function.
|
## Can be defined multiple times in a single function.
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
##
|
##
|
||||||
## proc example(x: int): TErrorCode =
|
## proc example(x: int): TErrorCode =
|
||||||
## onFailedAssert(msg):
|
## onFailedAssert(msg):
|
||||||
## log msg
|
## log msg
|
||||||
## return E_FAIL
|
## return E_FAIL
|
||||||
##
|
##
|
||||||
## assert(...)
|
## assert(...)
|
||||||
##
|
##
|
||||||
## onFailedAssert(msg):
|
## onFailedAssert(msg):
|
||||||
## raise newException(EMyException, msg)
|
## raise newException(EMyException, msg)
|
||||||
##
|
##
|
||||||
|
|
@ -3111,7 +3111,7 @@ template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} =
|
||||||
|
|
||||||
proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
|
proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
|
||||||
## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not
|
## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not
|
||||||
## perform deep copies of `s`. This is only useful for optimization
|
## perform deep copies of `s`. This is only useful for optimization
|
||||||
## purposes.
|
## purposes.
|
||||||
when not defined(JS) and not defined(NimrodVM):
|
when not defined(JS) and not defined(NimrodVM):
|
||||||
var s = cast[PGenericSeq](s)
|
var s = cast[PGenericSeq](s)
|
||||||
|
|
@ -3119,7 +3119,7 @@ proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
|
||||||
|
|
||||||
proc shallow*(s: var string) {.noSideEffect, inline.} =
|
proc shallow*(s: var string) {.noSideEffect, inline.} =
|
||||||
## marks a string `s` as `shallow`:idx:. Subsequent assignments will not
|
## marks a string `s` as `shallow`:idx:. Subsequent assignments will not
|
||||||
## perform deep copies of `s`. This is only useful for optimization
|
## perform deep copies of `s`. This is only useful for optimization
|
||||||
## purposes.
|
## purposes.
|
||||||
when not defined(JS) and not defined(NimrodVM):
|
when not defined(JS) and not defined(NimrodVM):
|
||||||
var s = cast[PGenericSeq](s)
|
var s = cast[PGenericSeq](s)
|
||||||
|
|
@ -3141,13 +3141,13 @@ else:
|
||||||
when false:
|
when false:
|
||||||
template eval*(blk: stmt): stmt =
|
template eval*(blk: stmt): stmt =
|
||||||
## executes a block of code at compile time just as if it was a macro
|
## executes a block of code at compile time just as if it was a macro
|
||||||
## optionally, the block can return an AST tree that will replace the
|
## optionally, the block can return an AST tree that will replace the
|
||||||
## eval expression
|
## eval expression
|
||||||
macro payload: stmt {.gensym.} = blk
|
macro payload: stmt {.gensym.} = blk
|
||||||
payload()
|
payload()
|
||||||
|
|
||||||
when hostOS != "standalone":
|
when hostOS != "standalone":
|
||||||
proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} =
|
proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} =
|
||||||
## inserts `item` into `x` at position `i`.
|
## inserts `item` into `x` at position `i`.
|
||||||
var xl = x.len
|
var xl = x.len
|
||||||
setLen(x, xl+item.len)
|
setLen(x, xl+item.len)
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,9 @@ proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode) {.benign.} =
|
||||||
|
|
||||||
proc copyDeepString(src: NimString): NimString {.inline.} =
|
proc copyDeepString(src: NimString): NimString {.inline.} =
|
||||||
if src != nil:
|
if src != nil:
|
||||||
result = rawNewString(src.space)
|
result = rawNewStringNoInit(src.len)
|
||||||
result.len = src.len
|
result.len = src.len
|
||||||
c_memcpy(result.data, src.data, (src.len + 1) * sizeof(char))
|
c_memcpy(result.data, src.data, src.len + 1)
|
||||||
|
|
||||||
proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
|
proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
|
||||||
var
|
var
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Nim's Runtime Library
|
# Nim's Runtime Library
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2015 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
@ -48,7 +48,7 @@ type
|
||||||
TWalkOp = enum
|
TWalkOp = enum
|
||||||
waMarkGlobal, # part of the backup/debug mark&sweep
|
waMarkGlobal, # part of the backup/debug mark&sweep
|
||||||
waMarkPrecise, # part of the backup/debug mark&sweep
|
waMarkPrecise, # part of the backup/debug mark&sweep
|
||||||
waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack,
|
waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack,
|
||||||
waCollectWhite #, waDebug
|
waCollectWhite #, waDebug
|
||||||
|
|
||||||
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
|
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
|
||||||
|
|
@ -61,9 +61,9 @@ type
|
||||||
maxThreshold: int # max threshold that has been set
|
maxThreshold: int # max threshold that has been set
|
||||||
maxStackSize: int # max stack size
|
maxStackSize: int # max stack size
|
||||||
maxStackCells: int # max stack cells in ``decStack``
|
maxStackCells: int # max stack cells in ``decStack``
|
||||||
cycleTableSize: int # max entries in cycle table
|
cycleTableSize: int # max entries in cycle table
|
||||||
maxPause: int64 # max measured GC pause in nanoseconds
|
maxPause: int64 # max measured GC pause in nanoseconds
|
||||||
|
|
||||||
TGcHeap {.final, pure.} = object # this contains the zero count and
|
TGcHeap {.final, pure.} = object # this contains the zero count and
|
||||||
# non-zero count table
|
# non-zero count table
|
||||||
stackBottom: pointer
|
stackBottom: pointer
|
||||||
|
|
@ -88,11 +88,11 @@ var
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
instantiateForRegion(gch.region)
|
instantiateForRegion(gch.region)
|
||||||
|
|
||||||
template acquire(gch: TGcHeap) =
|
template acquire(gch: TGcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
acquireSys(HeapLock)
|
acquireSys(HeapLock)
|
||||||
|
|
||||||
template release(gch: TGcHeap) =
|
template release(gch: TGcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
releaseSys(HeapLock)
|
releaseSys(HeapLock)
|
||||||
|
|
||||||
|
|
@ -117,7 +117,7 @@ proc usrToCell(usr: pointer): PCell {.inline.} =
|
||||||
# convert pointer to userdata to object (=pointer to refcount)
|
# convert pointer to userdata to object (=pointer to refcount)
|
||||||
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
|
result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
|
||||||
|
|
||||||
proc canbeCycleRoot(c: PCell): bool {.inline.} =
|
proc canBeCycleRoot(c: PCell): bool {.inline.} =
|
||||||
result = ntfAcyclic notin c.typ.flags
|
result = ntfAcyclic notin c.typ.flags
|
||||||
|
|
||||||
proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
|
proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
|
||||||
|
|
@ -163,7 +163,7 @@ when hasThreadSupport and hasSharedHeap:
|
||||||
template `--`(x: expr): expr = atomicDec(x, rcIncrement) <% rcIncrement
|
template `--`(x: expr): expr = atomicDec(x, rcIncrement) <% rcIncrement
|
||||||
template `++`(x: expr): stmt = discard atomicInc(x, rcIncrement)
|
template `++`(x: expr): stmt = discard atomicInc(x, rcIncrement)
|
||||||
else:
|
else:
|
||||||
template `--`(x: expr): expr =
|
template `--`(x: expr): expr =
|
||||||
dec(x, rcIncrement)
|
dec(x, rcIncrement)
|
||||||
x <% rcIncrement
|
x <% rcIncrement
|
||||||
template `++`(x: expr): stmt = inc(x, rcIncrement)
|
template `++`(x: expr): stmt = inc(x, rcIncrement)
|
||||||
|
|
@ -181,7 +181,7 @@ proc prepareDealloc(cell: PCell) =
|
||||||
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
|
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
|
||||||
dec(gch.recGcLock)
|
dec(gch.recGcLock)
|
||||||
|
|
||||||
proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
|
proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
|
||||||
# we MUST access gch as a global here, because this crosses DLL boundaries!
|
# we MUST access gch as a global here, because this crosses DLL boundaries!
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
acquireSys(HeapLock)
|
acquireSys(HeapLock)
|
||||||
|
|
@ -211,7 +211,7 @@ proc decRef(c: PCell) {.inline.} =
|
||||||
rtlAddCycleRoot(c)
|
rtlAddCycleRoot(c)
|
||||||
#writeCell("decRef", c)
|
#writeCell("decRef", c)
|
||||||
|
|
||||||
proc incRef(c: PCell) {.inline.} =
|
proc incRef(c: PCell) {.inline.} =
|
||||||
gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
|
gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
|
||||||
c.refcount = c.refcount +% rcIncrement
|
c.refcount = c.refcount +% rcIncrement
|
||||||
# and not colorMask
|
# and not colorMask
|
||||||
|
|
@ -246,12 +246,12 @@ proc asgnRef(dest: PPointer, src: pointer) {.compilerProc, inline.} =
|
||||||
dest[] = src
|
dest[] = src
|
||||||
|
|
||||||
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerProc, inline.} =
|
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerProc, inline.} =
|
||||||
# the code generator calls this proc if it is known at compile time that no
|
# the code generator calls this proc if it is known at compile time that no
|
||||||
# cycle is possible.
|
# cycle is possible.
|
||||||
if src != nil:
|
if src != nil:
|
||||||
var c = usrToCell(src)
|
var c = usrToCell(src)
|
||||||
++c.refcount
|
++c.refcount
|
||||||
if dest[] != nil:
|
if dest[] != nil:
|
||||||
var c = usrToCell(dest[])
|
var c = usrToCell(dest[])
|
||||||
if --c.refcount:
|
if --c.refcount:
|
||||||
rtlAddZCT(c)
|
rtlAddZCT(c)
|
||||||
|
|
@ -269,7 +269,7 @@ proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerProc.} =
|
||||||
if cast[int](dest[]) >=% PageSize: decRef(usrToCell(dest[]))
|
if cast[int](dest[]) >=% PageSize: decRef(usrToCell(dest[]))
|
||||||
else:
|
else:
|
||||||
# can't be an interior pointer if it's a stack location!
|
# can't be an interior pointer if it's a stack location!
|
||||||
gcAssert(interiorAllocatedPtr(gch.region, dest) == nil,
|
gcAssert(interiorAllocatedPtr(gch.region, dest) == nil,
|
||||||
"stack loc AND interior pointer")
|
"stack loc AND interior pointer")
|
||||||
dest[] = src
|
dest[] = src
|
||||||
|
|
||||||
|
|
@ -321,7 +321,7 @@ when useMarkForDebug or useBackupGc:
|
||||||
echo "[GC] cannot register global variable; too many global variables"
|
echo "[GC] cannot register global variable; too many global variables"
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
proc cellsetReset(s: var TCellSet) =
|
proc cellsetReset(s: var TCellSet) =
|
||||||
deinit(s)
|
deinit(s)
|
||||||
init(s)
|
init(s)
|
||||||
|
|
||||||
|
|
@ -336,7 +336,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
|
||||||
if n.sons[i].typ.kind in {tyRef, tyString, tySequence}:
|
if n.sons[i].typ.kind in {tyRef, tyString, tySequence}:
|
||||||
doOperation(cast[PPointer](d +% n.sons[i].offset)[], op)
|
doOperation(cast[PPointer](d +% n.sons[i].offset)[], op)
|
||||||
else:
|
else:
|
||||||
forAllChildrenAux(cast[pointer](d +% n.sons[i].offset),
|
forAllChildrenAux(cast[pointer](d +% n.sons[i].offset),
|
||||||
n.sons[i].typ, op)
|
n.sons[i].typ, op)
|
||||||
else:
|
else:
|
||||||
forAllSlotsAux(dest, n.sons[i], op)
|
forAllSlotsAux(dest, n.sons[i], op)
|
||||||
|
|
@ -384,7 +384,7 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
|
||||||
# we check the last 8 entries (cache line) for a slot that could be reused.
|
# we check the last 8 entries (cache line) for a slot that could be reused.
|
||||||
# In 63% of all cases we succeed here! But we have to optimize the heck
|
# In 63% of all cases we succeed here! But we have to optimize the heck
|
||||||
# out of this small linear search so that ``newObj`` is not slowed down.
|
# out of this small linear search so that ``newObj`` is not slowed down.
|
||||||
#
|
#
|
||||||
# Slots to try cache hit
|
# Slots to try cache hit
|
||||||
# 1 32%
|
# 1 32%
|
||||||
# 4 59%
|
# 4 59%
|
||||||
|
|
@ -461,6 +461,9 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
|
proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||||
|
result = rawNewObj(typ, size, gch)
|
||||||
|
|
||||||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||||
result = rawNewObj(typ, size, gch)
|
result = rawNewObj(typ, size, gch)
|
||||||
zeroMem(result, size)
|
zeroMem(result, size)
|
||||||
|
|
@ -481,7 +484,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||||
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
|
sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
|
||||||
|
|
||||||
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
|
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
|
||||||
sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc")
|
sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc")
|
||||||
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
||||||
|
|
@ -510,7 +513,7 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||||
cast[PGenericSeq](result).len = len
|
cast[PGenericSeq](result).len = len
|
||||||
cast[PGenericSeq](result).reserved = len
|
cast[PGenericSeq](result).reserved = len
|
||||||
when defined(memProfiler): nimProfile(size)
|
when defined(memProfiler): nimProfile(size)
|
||||||
|
|
||||||
proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
|
|
@ -522,7 +525,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
||||||
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
|
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
|
||||||
var elemSize = 1
|
var elemSize = 1
|
||||||
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
||||||
|
|
||||||
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
||||||
copyMem(res, ol, oldsize + sizeof(TCell))
|
copyMem(res, ol, oldsize + sizeof(TCell))
|
||||||
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
|
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
|
||||||
|
|
@ -536,7 +539,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
||||||
writeCell("growObj new cell", res)
|
writeCell("growObj new cell", res)
|
||||||
gcTrace(ol, csZctFreed)
|
gcTrace(ol, csZctFreed)
|
||||||
gcTrace(res, csAllocated)
|
gcTrace(res, csAllocated)
|
||||||
when reallyDealloc:
|
when reallyDealloc:
|
||||||
sysAssert(allocInv(gch.region), "growObj before dealloc")
|
sysAssert(allocInv(gch.region), "growObj before dealloc")
|
||||||
if ol.refcount shr rcShift <=% 1:
|
if ol.refcount shr rcShift <=% 1:
|
||||||
# free immediately to save space:
|
# free immediately to save space:
|
||||||
|
|
@ -580,7 +583,7 @@ proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
|
||||||
prepareDealloc(c)
|
prepareDealloc(c)
|
||||||
gcTrace(c, csCycFreed)
|
gcTrace(c, csCycFreed)
|
||||||
when logGC: writeCell("cycle collector dealloc cell", c)
|
when logGC: writeCell("cycle collector dealloc cell", c)
|
||||||
when reallyDealloc:
|
when reallyDealloc:
|
||||||
sysAssert(allocInv(gch.region), "free cyclic cell")
|
sysAssert(allocInv(gch.region), "free cyclic cell")
|
||||||
rawDealloc(gch.region, c)
|
rawDealloc(gch.region, c)
|
||||||
else:
|
else:
|
||||||
|
|
@ -767,7 +770,7 @@ proc collectCycles(gch: var TGcHeap) =
|
||||||
gcAssert isAllocatedPtr(gch.region, c), "addBackStackRoots"
|
gcAssert isAllocatedPtr(gch.region, c), "addBackStackRoots"
|
||||||
gcAssert c.refcount >=% rcIncrement, "addBackStackRoots: dead cell"
|
gcAssert c.refcount >=% rcIncrement, "addBackStackRoots: dead cell"
|
||||||
if canBeCycleRoot(c):
|
if canBeCycleRoot(c):
|
||||||
#if c notin gch.cycleRoots:
|
#if c notin gch.cycleRoots:
|
||||||
inc cycleRootsLen
|
inc cycleRootsLen
|
||||||
incl(gch.cycleRoots, c)
|
incl(gch.cycleRoots, c)
|
||||||
gcAssert c.typ != nil, "addBackStackRoots 2"
|
gcAssert c.typ != nil, "addBackStackRoots 2"
|
||||||
|
|
@ -794,12 +797,12 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
|
||||||
add(gch.decStack, cell)
|
add(gch.decStack, cell)
|
||||||
sysAssert(allocInv(gch.region), "gcMark end")
|
sysAssert(allocInv(gch.region), "gcMark end")
|
||||||
|
|
||||||
proc markThreadStacks(gch: var TGcHeap) =
|
proc markThreadStacks(gch: var TGcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
{.error: "not fully implemented".}
|
{.error: "not fully implemented".}
|
||||||
var it = threadList
|
var it = threadList
|
||||||
while it != nil:
|
while it != nil:
|
||||||
# mark registers:
|
# mark registers:
|
||||||
for i in 0 .. high(it.registers): gcMark(gch, it.registers[i])
|
for i in 0 .. high(it.registers): gcMark(gch, it.registers[i])
|
||||||
var sp = cast[TAddress](it.stackBottom)
|
var sp = cast[TAddress](it.stackBottom)
|
||||||
var max = cast[TAddress](it.stackTop)
|
var max = cast[TAddress](it.stackTop)
|
||||||
|
|
@ -933,7 +936,7 @@ else:
|
||||||
while sp <=% max:
|
while sp <=% max:
|
||||||
gcMark(gch, cast[PPointer](sp)[])
|
gcMark(gch, cast[PPointer](sp)[])
|
||||||
sp = sp +% sizeof(pointer)
|
sp = sp +% sizeof(pointer)
|
||||||
|
|
||||||
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
||||||
forEachStackSlot(gch, gcMark)
|
forEachStackSlot(gch, gcMark)
|
||||||
|
|
||||||
|
|
@ -946,13 +949,13 @@ when useMarkForDebug or useBackupGc:
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
proc collectZCT(gch: var TGcHeap): bool =
|
proc collectZCT(gch: var TGcHeap): bool =
|
||||||
# Note: Freeing may add child objects to the ZCT! So essentially we do
|
# Note: Freeing may add child objects to the ZCT! So essentially we do
|
||||||
# deep freeing, which is bad for incremental operation. In order to
|
# deep freeing, which is bad for incremental operation. In order to
|
||||||
# avoid a deep stack, we move objects to keep the ZCT small.
|
# avoid a deep stack, we move objects to keep the ZCT small.
|
||||||
# This is performance critical!
|
# This is performance critical!
|
||||||
const workPackage = 100
|
const workPackage = 100
|
||||||
var L = addr(gch.zct.len)
|
var L = addr(gch.zct.len)
|
||||||
|
|
||||||
when withRealTime:
|
when withRealTime:
|
||||||
var steps = workPackage
|
var steps = workPackage
|
||||||
var t0: TTicks
|
var t0: TTicks
|
||||||
|
|
@ -962,15 +965,15 @@ proc collectZCT(gch: var TGcHeap): bool =
|
||||||
sysAssert(isAllocatedPtr(gch.region, c), "CollectZCT: isAllocatedPtr")
|
sysAssert(isAllocatedPtr(gch.region, c), "CollectZCT: isAllocatedPtr")
|
||||||
# remove from ZCT:
|
# remove from ZCT:
|
||||||
gcAssert((c.refcount and ZctFlag) == ZctFlag, "collectZCT")
|
gcAssert((c.refcount and ZctFlag) == ZctFlag, "collectZCT")
|
||||||
|
|
||||||
c.refcount = c.refcount and not ZctFlag
|
c.refcount = c.refcount and not ZctFlag
|
||||||
gch.zct.d[0] = gch.zct.d[L[] - 1]
|
gch.zct.d[0] = gch.zct.d[L[] - 1]
|
||||||
dec(L[])
|
dec(L[])
|
||||||
when withRealTime: dec steps
|
when withRealTime: dec steps
|
||||||
if c.refcount <% rcIncrement:
|
if c.refcount <% rcIncrement:
|
||||||
# It may have a RC > 0, if it is in the hardware stack or
|
# It may have a RC > 0, if it is in the hardware stack or
|
||||||
# it has not been removed yet from the ZCT. This is because
|
# it has not been removed yet from the ZCT. This is because
|
||||||
# ``incref`` does not bother to remove the cell from the ZCT
|
# ``incref`` does not bother to remove the cell from the ZCT
|
||||||
# as this might be too slow.
|
# as this might be too slow.
|
||||||
# In any case, it should be removed from the ZCT. But not
|
# In any case, it should be removed from the ZCT. But not
|
||||||
# freed. **KEEP THIS IN MIND WHEN MAKING THIS INCREMENTAL!**
|
# freed. **KEEP THIS IN MIND WHEN MAKING THIS INCREMENTAL!**
|
||||||
|
|
@ -983,7 +986,7 @@ proc collectZCT(gch: var TGcHeap): bool =
|
||||||
# access invalid memory. This is done by prepareDealloc():
|
# access invalid memory. This is done by prepareDealloc():
|
||||||
prepareDealloc(c)
|
prepareDealloc(c)
|
||||||
forAllChildren(c, waZctDecRef)
|
forAllChildren(c, waZctDecRef)
|
||||||
when reallyDealloc:
|
when reallyDealloc:
|
||||||
sysAssert(allocInv(gch.region), "collectZCT: rawDealloc")
|
sysAssert(allocInv(gch.region), "collectZCT: rawDealloc")
|
||||||
rawDealloc(gch.region, c)
|
rawDealloc(gch.region, c)
|
||||||
else:
|
else:
|
||||||
|
|
@ -994,7 +997,7 @@ proc collectZCT(gch: var TGcHeap): bool =
|
||||||
steps = workPackage
|
steps = workPackage
|
||||||
if gch.maxPause > 0:
|
if gch.maxPause > 0:
|
||||||
let duration = getticks() - t0
|
let duration = getticks() - t0
|
||||||
# the GC's measuring is not accurate and needs some cleanup actions
|
# the GC's measuring is not accurate and needs some cleanup actions
|
||||||
# (stack unmarking), so subtract some short amount of time in
|
# (stack unmarking), so subtract some short amount of time in
|
||||||
# order to miss deadlines less often:
|
# order to miss deadlines less often:
|
||||||
if duration >= gch.maxPause - 50_000:
|
if duration >= gch.maxPause - 50_000:
|
||||||
|
|
@ -1017,7 +1020,7 @@ proc collectCTBody(gch: var TGcHeap) =
|
||||||
when withRealTime:
|
when withRealTime:
|
||||||
let t0 = getticks()
|
let t0 = getticks()
|
||||||
sysAssert(allocInv(gch.region), "collectCT: begin")
|
sysAssert(allocInv(gch.region), "collectCT: begin")
|
||||||
|
|
||||||
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
|
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
|
||||||
sysAssert(gch.decStack.len == 0, "collectCT")
|
sysAssert(gch.decStack.len == 0, "collectCT")
|
||||||
prepareForInteriorPointerChecking(gch.region)
|
prepareForInteriorPointerChecking(gch.region)
|
||||||
|
|
@ -1036,7 +1039,7 @@ proc collectCTBody(gch: var TGcHeap) =
|
||||||
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
|
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
|
||||||
unmarkStackAndRegisters(gch)
|
unmarkStackAndRegisters(gch)
|
||||||
sysAssert(allocInv(gch.region), "collectCT: end")
|
sysAssert(allocInv(gch.region), "collectCT: end")
|
||||||
|
|
||||||
when withRealTime:
|
when withRealTime:
|
||||||
let duration = getticks() - t0
|
let duration = getticks() - t0
|
||||||
gch.stat.maxPause = max(gch.stat.maxPause, duration)
|
gch.stat.maxPause = max(gch.stat.maxPause, duration)
|
||||||
|
|
@ -1050,8 +1053,12 @@ when useMarkForDebug or useBackupGc:
|
||||||
markGlobals(gch)
|
markGlobals(gch)
|
||||||
|
|
||||||
proc collectCT(gch: var TGcHeap) =
|
proc collectCT(gch: var TGcHeap) =
|
||||||
if (gch.zct.len >= ZctThreshold or (cycleGC and
|
# stackMarkCosts prevents some pathological behaviour: Stack marking
|
||||||
getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
|
# becomes more expensive with large stacks and large stacks mean that
|
||||||
|
# cells with RC=0 are more likely to be kept alive by the stack.
|
||||||
|
let stackMarkCosts = max(stackSize() div (16*sizeof(int)), ZctThreshold)
|
||||||
|
if (gch.zct.len >= stackMarkCosts or (cycleGC and
|
||||||
|
getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
|
||||||
gch.recGcLock == 0:
|
gch.recGcLock == 0:
|
||||||
when useMarkForDebug:
|
when useMarkForDebug:
|
||||||
prepareForInteriorPointerChecking(gch.region)
|
prepareForInteriorPointerChecking(gch.region)
|
||||||
|
|
@ -1070,7 +1077,7 @@ when withRealTime:
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
gch.maxPause = us.toNano
|
gch.maxPause = us.toNano
|
||||||
if (gch.zct.len >= ZctThreshold or (cycleGC and
|
if (gch.zct.len >= ZctThreshold or (cycleGC and
|
||||||
getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or
|
getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or
|
||||||
strongAdvice:
|
strongAdvice:
|
||||||
collectCTBody(gch)
|
collectCTBody(gch)
|
||||||
release(gch)
|
release(gch)
|
||||||
|
|
@ -1078,13 +1085,13 @@ when withRealTime:
|
||||||
proc GC_step*(us: int, strongAdvice = false) = GC_step(gch, us, strongAdvice)
|
proc GC_step*(us: int, strongAdvice = false) = GC_step(gch, us, strongAdvice)
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
proc GC_disable() =
|
proc GC_disable() =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
discard atomicInc(gch.recGcLock, 1)
|
discard atomicInc(gch.recGcLock, 1)
|
||||||
else:
|
else:
|
||||||
inc(gch.recGcLock)
|
inc(gch.recGcLock)
|
||||||
proc GC_enable() =
|
proc GC_enable() =
|
||||||
if gch.recGcLock > 0:
|
if gch.recGcLock > 0:
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
discard atomicDec(gch.recGcLock, 1)
|
discard atomicDec(gch.recGcLock, 1)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -593,7 +593,7 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
|
||||||
return
|
return
|
||||||
add(gch.zct, res)
|
add(gch.zct, res)
|
||||||
|
|
||||||
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1: bool): pointer =
|
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1 = false): pointer =
|
||||||
# generates a new object and sets its reference counter to 0
|
# generates a new object and sets its reference counter to 0
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,13 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
# A simple mark&sweep garbage collector for Nim. Define the
|
# A simple mark&sweep garbage collector for Nim. Define the
|
||||||
# symbol ``gcUseBitvectors`` to generate a variant of this GC.
|
# symbol ``gcUseBitvectors`` to generate a variant of this GC.
|
||||||
{.push profiler:off.}
|
{.push profiler:off.}
|
||||||
|
|
||||||
const
|
const
|
||||||
InitialThreshold = 4*1024*1024 # X MB because marking&sweeping is slow
|
InitialThreshold = 4*1024*1024 # X MB because marking&sweeping is slow
|
||||||
withBitvectors = defined(gcUseBitvectors)
|
withBitvectors = defined(gcUseBitvectors)
|
||||||
# bitvectors are significantly faster for GC-bench, but slower for
|
# bitvectors are significantly faster for GC-bench, but slower for
|
||||||
# bootstrapping and use more memory
|
# bootstrapping and use more memory
|
||||||
rcWhite = 0
|
rcWhite = 0
|
||||||
|
|
@ -29,21 +29,21 @@ type
|
||||||
TWalkOp = enum
|
TWalkOp = enum
|
||||||
waMarkGlobal, # we need to mark conservatively for global marker procs
|
waMarkGlobal, # we need to mark conservatively for global marker procs
|
||||||
# as these may refer to a global var and not to a thread
|
# as these may refer to a global var and not to a thread
|
||||||
# local
|
# local
|
||||||
waMarkPrecise # fast precise marking
|
waMarkPrecise # fast precise marking
|
||||||
|
|
||||||
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
|
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
|
||||||
# A ref type can have a finalizer that is called before the object's
|
# A ref type can have a finalizer that is called before the object's
|
||||||
# storage is freed.
|
# storage is freed.
|
||||||
|
|
||||||
TGlobalMarkerProc = proc () {.nimcall, benign.}
|
TGlobalMarkerProc = proc () {.nimcall, benign.}
|
||||||
|
|
||||||
TGcStat = object
|
TGcStat = object
|
||||||
collections: int # number of performed full collections
|
collections: int # number of performed full collections
|
||||||
maxThreshold: int # max threshold that has been set
|
maxThreshold: int # max threshold that has been set
|
||||||
maxStackSize: int # max stack size
|
maxStackSize: int # max stack size
|
||||||
freedObjects: int # max entries in cycle table
|
freedObjects: int # max entries in cycle table
|
||||||
|
|
||||||
TGcHeap = object # this contains the zero count and
|
TGcHeap = object # this contains the zero count and
|
||||||
# non-zero count table
|
# non-zero count table
|
||||||
stackBottom: pointer
|
stackBottom: pointer
|
||||||
|
|
@ -64,11 +64,11 @@ var
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
instantiateForRegion(gch.region)
|
instantiateForRegion(gch.region)
|
||||||
|
|
||||||
template acquire(gch: TGcHeap) =
|
template acquire(gch: TGcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
acquireSys(HeapLock)
|
acquireSys(HeapLock)
|
||||||
|
|
||||||
template release(gch: TGcHeap) =
|
template release(gch: TGcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
releaseSys(HeapLock)
|
releaseSys(HeapLock)
|
||||||
|
|
||||||
|
|
@ -134,7 +134,7 @@ proc prepareDealloc(cell: PCell) =
|
||||||
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
|
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
|
||||||
dec(gch.recGcLock)
|
dec(gch.recGcLock)
|
||||||
|
|
||||||
proc nimGCref(p: pointer) {.compilerProc.} =
|
proc nimGCref(p: pointer) {.compilerProc.} =
|
||||||
# we keep it from being collected by pretending it's not even allocated:
|
# we keep it from being collected by pretending it's not even allocated:
|
||||||
when false:
|
when false:
|
||||||
when withBitvectors: excl(gch.allocated, usrToCell(p))
|
when withBitvectors: excl(gch.allocated, usrToCell(p))
|
||||||
|
|
@ -261,6 +261,10 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||||
zeroMem(result, size)
|
zeroMem(result, size)
|
||||||
when defined(memProfiler): nimProfile(size)
|
when defined(memProfiler): nimProfile(size)
|
||||||
|
|
||||||
|
proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||||
|
result = rawNewObj(typ, size, gch)
|
||||||
|
when defined(memProfiler): nimProfile(size)
|
||||||
|
|
||||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||||
# `newObj` already uses locks, so no need for them here.
|
# `newObj` already uses locks, so no need for them here.
|
||||||
let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
|
let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
|
||||||
|
|
@ -273,25 +277,25 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||||
result = rawNewObj(typ, size, gch)
|
result = rawNewObj(typ, size, gch)
|
||||||
zeroMem(result, size)
|
zeroMem(result, size)
|
||||||
when defined(memProfiler): nimProfile(size)
|
when defined(memProfiler): nimProfile(size)
|
||||||
|
|
||||||
proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||||
let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
|
let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
|
||||||
result = newObj(typ, size)
|
result = newObj(typ, size)
|
||||||
cast[PGenericSeq](result).len = len
|
cast[PGenericSeq](result).len = len
|
||||||
cast[PGenericSeq](result).reserved = len
|
cast[PGenericSeq](result).reserved = len
|
||||||
when defined(memProfiler): nimProfile(size)
|
when defined(memProfiler): nimProfile(size)
|
||||||
|
|
||||||
proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
var ol = usrToCell(old)
|
var ol = usrToCell(old)
|
||||||
sysAssert(ol.typ != nil, "growObj: 1")
|
sysAssert(ol.typ != nil, "growObj: 1")
|
||||||
gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
|
gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
|
||||||
|
|
||||||
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
|
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
|
||||||
var elemSize = 1
|
var elemSize = 1
|
||||||
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
||||||
|
|
||||||
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
||||||
copyMem(res, ol, oldsize + sizeof(TCell))
|
copyMem(res, ol, oldsize + sizeof(TCell))
|
||||||
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
|
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
|
||||||
|
|
@ -401,7 +405,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
|
||||||
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
|
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
|
||||||
if objStart != nil:
|
if objStart != nil:
|
||||||
mark(gch, objStart)
|
mark(gch, objStart)
|
||||||
|
|
||||||
# ----------------- stack management --------------------------------------
|
# ----------------- stack management --------------------------------------
|
||||||
# inspired from Smart Eiffel
|
# inspired from Smart Eiffel
|
||||||
|
|
||||||
|
|
@ -536,7 +540,7 @@ proc collectCTBody(gch: var TGcHeap) =
|
||||||
markStackAndRegisters(gch)
|
markStackAndRegisters(gch)
|
||||||
markGlobals(gch)
|
markGlobals(gch)
|
||||||
sweep(gch)
|
sweep(gch)
|
||||||
|
|
||||||
inc(gch.stat.collections)
|
inc(gch.stat.collections)
|
||||||
when withBitvectors:
|
when withBitvectors:
|
||||||
deinit(gch.marked)
|
deinit(gch.marked)
|
||||||
|
|
@ -544,19 +548,19 @@ proc collectCTBody(gch: var TGcHeap) =
|
||||||
gch.cycleThreshold = max(InitialThreshold, getOccupiedMem().mulThreshold)
|
gch.cycleThreshold = max(InitialThreshold, getOccupiedMem().mulThreshold)
|
||||||
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
|
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
|
||||||
sysAssert(allocInv(gch.region), "collectCT: end")
|
sysAssert(allocInv(gch.region), "collectCT: end")
|
||||||
|
|
||||||
proc collectCT(gch: var TGcHeap) =
|
proc collectCT(gch: var TGcHeap) =
|
||||||
if getOccupiedMem(gch.region) >= gch.cycleThreshold and gch.recGcLock == 0:
|
if getOccupiedMem(gch.region) >= gch.cycleThreshold and gch.recGcLock == 0:
|
||||||
collectCTBody(gch)
|
collectCTBody(gch)
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
proc GC_disable() =
|
proc GC_disable() =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
atomicInc(gch.recGcLock, 1)
|
atomicInc(gch.recGcLock, 1)
|
||||||
else:
|
else:
|
||||||
inc(gch.recGcLock)
|
inc(gch.recGcLock)
|
||||||
proc GC_enable() =
|
proc GC_enable() =
|
||||||
if gch.recGcLock > 0:
|
if gch.recGcLock > 0:
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
atomicDec(gch.recGcLock, 1)
|
atomicDec(gch.recGcLock, 1)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ when declared(NimString):
|
||||||
# we are in system module:
|
# we are in system module:
|
||||||
{.pragma: codegenType, compilerproc.}
|
{.pragma: codegenType, compilerproc.}
|
||||||
else:
|
else:
|
||||||
{.pragma: codegenType.}
|
{.pragma: codegenType, importc.}
|
||||||
|
|
||||||
type
|
type
|
||||||
# This should be he same as ast.TTypeKind
|
# This should be he same as ast.TTypeKind
|
||||||
|
|
@ -65,7 +65,7 @@ type
|
||||||
tyBigNum,
|
tyBigNum,
|
||||||
|
|
||||||
TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
|
TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
|
||||||
TNimNode {.codegenType, final.} = object
|
TNimNode {.codegenType.} = object
|
||||||
kind: TNimNodeKind
|
kind: TNimNodeKind
|
||||||
offset: int
|
offset: int
|
||||||
typ: ptr TNimType
|
typ: ptr TNimType
|
||||||
|
|
@ -78,7 +78,7 @@ type
|
||||||
ntfAcyclic = 1, # type cannot form a cycle
|
ntfAcyclic = 1, # type cannot form a cycle
|
||||||
ntfEnumHole = 2 # enum has holes and thus `$` for them needs the slow
|
ntfEnumHole = 2 # enum has holes and thus `$` for them needs the slow
|
||||||
# version
|
# version
|
||||||
TNimType {.codegenType, final.} = object
|
TNimType {.codegenType.} = object
|
||||||
size: int
|
size: int
|
||||||
kind: TNimKind
|
kind: TNimKind
|
||||||
flags: set[TNimTypeFlag]
|
flags: set[TNimTypeFlag]
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Nim's Runtime Library
|
# Nim's Runtime Library
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2015 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
@ -23,7 +23,7 @@ const
|
||||||
leakDetector = false
|
leakDetector = false
|
||||||
overwriteFree = false
|
overwriteFree = false
|
||||||
trackAllocationSource = leakDetector
|
trackAllocationSource = leakDetector
|
||||||
|
|
||||||
cycleGC = true # (de)activate the cycle GC
|
cycleGC = true # (de)activate the cycle GC
|
||||||
reallyDealloc = true # for debugging purposes this can be set to false
|
reallyDealloc = true # for debugging purposes this can be set to false
|
||||||
reallyOsDealloc = true
|
reallyOsDealloc = true
|
||||||
|
|
@ -71,13 +71,13 @@ when defined(boehmgc):
|
||||||
const boehmLib = "libgc.dylib"
|
const boehmLib = "libgc.dylib"
|
||||||
else:
|
else:
|
||||||
const boehmLib = "/usr/lib/libgc.so.1"
|
const boehmLib = "/usr/lib/libgc.so.1"
|
||||||
|
|
||||||
proc boehmGCinit {.importc: "GC_init", dynlib: boehmLib.}
|
proc boehmGCinit {.importc: "GC_init", dynlib: boehmLib.}
|
||||||
proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.}
|
proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.}
|
||||||
proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.}
|
proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.}
|
||||||
proc boehmGCincremental {.
|
proc boehmGCincremental {.
|
||||||
importc: "GC_enable_incremental", dynlib: boehmLib.}
|
importc: "GC_enable_incremental", dynlib: boehmLib.}
|
||||||
proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.}
|
proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.}
|
||||||
proc boehmAlloc(size: int): pointer {.
|
proc boehmAlloc(size: int): pointer {.
|
||||||
importc: "GC_malloc", dynlib: boehmLib.}
|
importc: "GC_malloc", dynlib: boehmLib.}
|
||||||
proc boehmAllocAtomic(size: int): pointer {.
|
proc boehmAllocAtomic(size: int): pointer {.
|
||||||
|
|
@ -85,7 +85,7 @@ when defined(boehmgc):
|
||||||
proc boehmRealloc(p: pointer, size: int): pointer {.
|
proc boehmRealloc(p: pointer, size: int): pointer {.
|
||||||
importc: "GC_realloc", dynlib: boehmLib.}
|
importc: "GC_realloc", dynlib: boehmLib.}
|
||||||
proc boehmDealloc(p: pointer) {.importc: "GC_free", dynlib: boehmLib.}
|
proc boehmDealloc(p: pointer) {.importc: "GC_free", dynlib: boehmLib.}
|
||||||
|
|
||||||
proc boehmGetHeapSize: int {.importc: "GC_get_heap_size", dynlib: boehmLib.}
|
proc boehmGetHeapSize: int {.importc: "GC_get_heap_size", dynlib: boehmLib.}
|
||||||
## Return the number of bytes in the heap. Excludes collector private
|
## Return the number of bytes in the heap. Excludes collector private
|
||||||
## data structures. Includes empty blocks and fragmentation loss.
|
## data structures. Includes empty blocks and fragmentation loss.
|
||||||
|
|
@ -108,7 +108,7 @@ when defined(boehmgc):
|
||||||
zeroMem(result, size)
|
zeroMem(result, size)
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
|
|
||||||
proc alloc(size: int): pointer =
|
proc alloc(size: int): pointer =
|
||||||
result = boehmAlloc(size)
|
result = boehmAlloc(size)
|
||||||
if result == nil: raiseOutOfMem()
|
if result == nil: raiseOutOfMem()
|
||||||
|
|
@ -119,7 +119,7 @@ when defined(boehmgc):
|
||||||
result = boehmRealloc(p, newsize)
|
result = boehmRealloc(p, newsize)
|
||||||
if result == nil: raiseOutOfMem()
|
if result == nil: raiseOutOfMem()
|
||||||
proc dealloc(p: pointer) = boehmDealloc(p)
|
proc dealloc(p: pointer) = boehmDealloc(p)
|
||||||
|
|
||||||
proc allocShared(size: int): pointer =
|
proc allocShared(size: int): pointer =
|
||||||
result = boehmAlloc(size)
|
result = boehmAlloc(size)
|
||||||
if result == nil: raiseOutOfMem()
|
if result == nil: raiseOutOfMem()
|
||||||
|
|
@ -148,14 +148,14 @@ when defined(boehmgc):
|
||||||
proc GC_enableMarkAndSweep() = discard
|
proc GC_enableMarkAndSweep() = discard
|
||||||
proc GC_disableMarkAndSweep() = discard
|
proc GC_disableMarkAndSweep() = discard
|
||||||
proc GC_getStatistics(): string = return ""
|
proc GC_getStatistics(): string = return ""
|
||||||
|
|
||||||
proc getOccupiedMem(): int = return boehmGetHeapSize()-boehmGetFreeBytes()
|
proc getOccupiedMem(): int = return boehmGetHeapSize()-boehmGetFreeBytes()
|
||||||
proc getFreeMem(): int = return boehmGetFreeBytes()
|
proc getFreeMem(): int = return boehmGetFreeBytes()
|
||||||
proc getTotalMem(): int = return boehmGetHeapSize()
|
proc getTotalMem(): int = return boehmGetHeapSize()
|
||||||
|
|
||||||
proc setStackBottom(theStackBottom: pointer) = discard
|
proc setStackBottom(theStackBottom: pointer) = discard
|
||||||
|
|
||||||
proc initGC() =
|
proc initGC() =
|
||||||
when defined(macosx): boehmGCinit()
|
when defined(macosx): boehmGCinit()
|
||||||
|
|
||||||
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
|
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
|
||||||
|
|
@ -171,7 +171,7 @@ when defined(boehmgc):
|
||||||
|
|
||||||
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
|
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
|
||||||
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
|
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
|
||||||
|
|
||||||
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||||
dest[] = src
|
dest[] = src
|
||||||
proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||||
|
|
@ -181,20 +181,20 @@ when defined(boehmgc):
|
||||||
|
|
||||||
type
|
type
|
||||||
TMemRegion = object {.final, pure.}
|
TMemRegion = object {.final, pure.}
|
||||||
|
|
||||||
proc alloc(r: var TMemRegion, size: int): pointer =
|
proc alloc(r: var TMemRegion, size: int): pointer =
|
||||||
result = boehmAlloc(size)
|
result = boehmAlloc(size)
|
||||||
if result == nil: raiseOutOfMem()
|
if result == nil: raiseOutOfMem()
|
||||||
proc alloc0(r: var TMemRegion, size: int): pointer =
|
proc alloc0(r: var TMemRegion, size: int): pointer =
|
||||||
result = alloc(size)
|
result = alloc(size)
|
||||||
zeroMem(result, size)
|
zeroMem(result, size)
|
||||||
proc dealloc(r: var TMemRegion, p: pointer) = boehmDealloc(p)
|
proc dealloc(r: var TMemRegion, p: pointer) = boehmDealloc(p)
|
||||||
proc deallocOsPages(r: var TMemRegion) {.inline.} = discard
|
proc deallocOsPages(r: var TMemRegion) {.inline.} = discard
|
||||||
proc deallocOsPages() {.inline.} = discard
|
proc deallocOsPages() {.inline.} = discard
|
||||||
|
|
||||||
include "system/cellsets"
|
include "system/cellsets"
|
||||||
elif defined(nogc) and defined(useMalloc):
|
elif defined(nogc) and defined(useMalloc):
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
proc alloc(size: int): pointer =
|
proc alloc(size: int): pointer =
|
||||||
result = cmalloc(size)
|
result = cmalloc(size)
|
||||||
|
|
@ -206,7 +206,7 @@ elif defined(nogc) and defined(useMalloc):
|
||||||
result = crealloc(p, newsize)
|
result = crealloc(p, newsize)
|
||||||
if result == nil: raiseOutOfMem()
|
if result == nil: raiseOutOfMem()
|
||||||
proc dealloc(p: pointer) = cfree(p)
|
proc dealloc(p: pointer) = cfree(p)
|
||||||
|
|
||||||
proc allocShared(size: int): pointer =
|
proc allocShared(size: int): pointer =
|
||||||
result = cmalloc(size)
|
result = cmalloc(size)
|
||||||
if result == nil: raiseOutOfMem()
|
if result == nil: raiseOutOfMem()
|
||||||
|
|
@ -225,11 +225,11 @@ elif defined(nogc) and defined(useMalloc):
|
||||||
proc GC_enableMarkAndSweep() = discard
|
proc GC_enableMarkAndSweep() = discard
|
||||||
proc GC_disableMarkAndSweep() = discard
|
proc GC_disableMarkAndSweep() = discard
|
||||||
proc GC_getStatistics(): string = return ""
|
proc GC_getStatistics(): string = return ""
|
||||||
|
|
||||||
proc getOccupiedMem(): int = discard
|
proc getOccupiedMem(): int = discard
|
||||||
proc getFreeMem(): int = discard
|
proc getFreeMem(): int = discard
|
||||||
proc getTotalMem(): int = discard
|
proc getTotalMem(): int = discard
|
||||||
|
|
||||||
proc setStackBottom(theStackBottom: pointer) = discard
|
proc setStackBottom(theStackBottom: pointer) = discard
|
||||||
|
|
||||||
proc initGC() = discard
|
proc initGC() = discard
|
||||||
|
|
@ -240,13 +240,15 @@ elif defined(nogc) and defined(useMalloc):
|
||||||
result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
|
result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
|
||||||
cast[PGenericSeq](result).len = len
|
cast[PGenericSeq](result).len = len
|
||||||
cast[PGenericSeq](result).reserved = len
|
cast[PGenericSeq](result).reserved = len
|
||||||
|
proc newObjNoInit(typ: PNimType, size: int): pointer =
|
||||||
|
result = alloc(size)
|
||||||
|
|
||||||
proc growObj(old: pointer, newsize: int): pointer =
|
proc growObj(old: pointer, newsize: int): pointer =
|
||||||
result = realloc(old, newsize)
|
result = realloc(old, newsize)
|
||||||
|
|
||||||
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
|
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
|
||||||
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
|
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
|
||||||
|
|
||||||
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||||
dest[] = src
|
dest[] = src
|
||||||
proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||||
|
|
@ -256,7 +258,7 @@ elif defined(nogc) and defined(useMalloc):
|
||||||
|
|
||||||
type
|
type
|
||||||
TMemRegion = object {.final, pure.}
|
TMemRegion = object {.final, pure.}
|
||||||
|
|
||||||
proc alloc(r: var TMemRegion, size: int): pointer =
|
proc alloc(r: var TMemRegion, size: int): pointer =
|
||||||
result = alloc(size)
|
result = alloc(size)
|
||||||
proc alloc0(r: var TMemRegion, size: int): pointer =
|
proc alloc0(r: var TMemRegion, size: int): pointer =
|
||||||
|
|
@ -272,9 +274,9 @@ elif defined(nogc):
|
||||||
# object, because C does not support this operation... Even though every
|
# object, because C does not support this operation... Even though every
|
||||||
# possible implementation has to have a way to determine the object's size.
|
# possible implementation has to have a way to determine the object's size.
|
||||||
# C just sucks.
|
# C just sucks.
|
||||||
when appType == "lib":
|
when appType == "lib":
|
||||||
{.warning: "nogc in a library context may not work".}
|
{.warning: "nogc in a library context may not work".}
|
||||||
|
|
||||||
include "system/alloc"
|
include "system/alloc"
|
||||||
|
|
||||||
proc initGC() = discard
|
proc initGC() = discard
|
||||||
|
|
@ -285,10 +287,14 @@ elif defined(nogc):
|
||||||
proc GC_enableMarkAndSweep() = discard
|
proc GC_enableMarkAndSweep() = discard
|
||||||
proc GC_disableMarkAndSweep() = discard
|
proc GC_disableMarkAndSweep() = discard
|
||||||
proc GC_getStatistics(): string = return ""
|
proc GC_getStatistics(): string = return ""
|
||||||
|
|
||||||
|
|
||||||
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
|
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
|
||||||
result = alloc0(size)
|
result = alloc0(size)
|
||||||
|
|
||||||
|
proc newObjNoInit(typ: PNimType, size: int): pointer =
|
||||||
|
result = alloc(size)
|
||||||
|
|
||||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
|
proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
|
||||||
result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
|
result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
|
||||||
cast[PGenericSeq](result).len = len
|
cast[PGenericSeq](result).len = len
|
||||||
|
|
@ -299,7 +305,7 @@ elif defined(nogc):
|
||||||
proc setStackBottom(theStackBottom: pointer) = discard
|
proc setStackBottom(theStackBottom: pointer) = discard
|
||||||
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
|
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
|
||||||
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
|
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
|
||||||
|
|
||||||
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||||
dest[] = src
|
dest[] = src
|
||||||
proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
|
||||||
|
|
@ -327,6 +333,6 @@ else:
|
||||||
include "system/gc"
|
include "system/gc"
|
||||||
else:
|
else:
|
||||||
include "system/gc"
|
include "system/gc"
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -145,8 +145,8 @@ proc readAllFile(file: File): string =
|
||||||
proc readAll(file: File): TaintedString =
|
proc readAll(file: File): TaintedString =
|
||||||
# Separate handling needed because we need to buffer when we
|
# Separate handling needed because we need to buffer when we
|
||||||
# don't know the overall length of the File.
|
# don't know the overall length of the File.
|
||||||
var len = rawFileSize(file)
|
let len = if file != stdin: rawFileSize(file) else: -1
|
||||||
if len >= 0:
|
if len > 0:
|
||||||
result = readAllFile(file, len).TaintedString
|
result = readAllFile(file, len).TaintedString
|
||||||
else:
|
else:
|
||||||
result = readAllBuffer(file).TaintedString
|
result = readAllBuffer(file).TaintedString
|
||||||
|
|
|
||||||
|
|
@ -30,18 +30,30 @@ proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
|
||||||
if a == b: return true
|
if a == b: return true
|
||||||
if a == nil or b == nil: return false
|
if a == nil or b == nil: return false
|
||||||
return a.len == b.len and
|
return a.len == b.len and
|
||||||
c_memcmp(a.data, b.data, a.len * sizeof(char)) == 0'i32
|
c_memcmp(a.data, b.data, a.len) == 0'i32
|
||||||
|
|
||||||
when declared(allocAtomic):
|
when declared(allocAtomic):
|
||||||
template allocStr(size: expr): expr =
|
template allocStr(size: expr): expr =
|
||||||
cast[NimString](allocAtomic(size))
|
cast[NimString](allocAtomic(size))
|
||||||
|
|
||||||
|
template allocStrNoInit(size: expr): expr =
|
||||||
|
cast[NimString](boehmAllocAtomic(size))
|
||||||
else:
|
else:
|
||||||
template allocStr(size: expr): expr =
|
template allocStr(size: expr): expr =
|
||||||
cast[NimString](newObj(addr(strDesc), size))
|
cast[NimString](newObj(addr(strDesc), size))
|
||||||
|
|
||||||
|
template allocStrNoInit(size: expr): expr =
|
||||||
|
cast[NimString](newObjNoInit(addr(strDesc), size))
|
||||||
|
|
||||||
|
proc rawNewStringNoInit(space: int): NimString {.compilerProc.} =
|
||||||
|
var s = space
|
||||||
|
if s < 7: s = 7
|
||||||
|
result = allocStrNoInit(sizeof(TGenericSeq) + s + 1)
|
||||||
|
result.reserved = s
|
||||||
|
|
||||||
proc rawNewString(space: int): NimString {.compilerProc.} =
|
proc rawNewString(space: int): NimString {.compilerProc.} =
|
||||||
var s = space
|
var s = space
|
||||||
if s < 8: s = 7
|
if s < 7: s = 7
|
||||||
result = allocStr(sizeof(TGenericSeq) + s + 1)
|
result = allocStr(sizeof(TGenericSeq) + s + 1)
|
||||||
result.reserved = s
|
result.reserved = s
|
||||||
|
|
||||||
|
|
@ -53,10 +65,10 @@ proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} =
|
||||||
var start = max(start, 0)
|
var start = max(start, 0)
|
||||||
var len = min(last, s.len-1) - start + 1
|
var len = min(last, s.len-1) - start + 1
|
||||||
if len > 0:
|
if len > 0:
|
||||||
result = rawNewString(len)
|
result = rawNewStringNoInit(len)
|
||||||
result.len = len
|
result.len = len
|
||||||
c_memcpy(result.data, addr(s.data[start]), len * sizeof(char))
|
c_memcpy(result.data, addr(s.data[start]), len)
|
||||||
#result.data[len] = '\0'
|
result.data[len] = '\0'
|
||||||
else:
|
else:
|
||||||
result = rawNewString(len)
|
result = rawNewString(len)
|
||||||
|
|
||||||
|
|
@ -64,10 +76,9 @@ proc copyStr(s: NimString, start: int): NimString {.compilerProc.} =
|
||||||
result = copyStrLast(s, start, s.len-1)
|
result = copyStrLast(s, start, s.len-1)
|
||||||
|
|
||||||
proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} =
|
proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} =
|
||||||
result = rawNewString(len)
|
result = rawNewStringNoInit(len)
|
||||||
result.len = len
|
result.len = len
|
||||||
c_memcpy(result.data, str, (len+1) * sizeof(char))
|
c_memcpy(result.data, str, len + 1)
|
||||||
#result.data[len] = '\0' # readline relies on this!
|
|
||||||
|
|
||||||
proc cstrToNimstr(str: cstring): NimString {.compilerRtl.} =
|
proc cstrToNimstr(str: cstring): NimString {.compilerRtl.} =
|
||||||
result = toNimStr(str, c_strlen(str))
|
result = toNimStr(str, c_strlen(str))
|
||||||
|
|
@ -77,23 +88,24 @@ proc copyString(src: NimString): NimString {.compilerRtl.} =
|
||||||
if (src.reserved and seqShallowFlag) != 0:
|
if (src.reserved and seqShallowFlag) != 0:
|
||||||
result = src
|
result = src
|
||||||
else:
|
else:
|
||||||
result = rawNewString(src.space)
|
result = rawNewStringNoInit(src.len)
|
||||||
result.len = src.len
|
result.len = src.len
|
||||||
c_memcpy(result.data, src.data, (src.len + 1) * sizeof(char))
|
c_memcpy(result.data, src.data, src.len + 1)
|
||||||
|
|
||||||
proc copyStringRC1(src: NimString): NimString {.compilerRtl.} =
|
proc copyStringRC1(src: NimString): NimString {.compilerRtl.} =
|
||||||
if src != nil:
|
if src != nil:
|
||||||
var s = src.space
|
|
||||||
if s < 8: s = 7
|
|
||||||
when declared(newObjRC1):
|
when declared(newObjRC1):
|
||||||
|
var s = src.len
|
||||||
|
if s < 7: s = 7
|
||||||
result = cast[NimString](newObjRC1(addr(strDesc), sizeof(TGenericSeq) +
|
result = cast[NimString](newObjRC1(addr(strDesc), sizeof(TGenericSeq) +
|
||||||
s+1))
|
s+1))
|
||||||
|
result.reserved = s
|
||||||
else:
|
else:
|
||||||
result = allocStr(sizeof(TGenericSeq) + s + 1)
|
result = rawNewStringNoInit(src.len)
|
||||||
result.reserved = s
|
|
||||||
result.len = src.len
|
result.len = src.len
|
||||||
c_memcpy(result.data, src.data, src.len + 1)
|
c_memcpy(result.data, src.data, src.len + 1)
|
||||||
|
|
||||||
|
|
||||||
proc hashString(s: string): int {.compilerproc.} =
|
proc hashString(s: string): int {.compilerproc.} =
|
||||||
# the compiler needs exactly the same hash function!
|
# the compiler needs exactly the same hash function!
|
||||||
# this used to be used for efficient generation of string case statements
|
# this used to be used for efficient generation of string case statements
|
||||||
|
|
@ -113,7 +125,7 @@ proc addChar(s: NimString, c: char): NimString =
|
||||||
if result.len >= result.space:
|
if result.len >= result.space:
|
||||||
result.reserved = resize(result.space)
|
result.reserved = resize(result.space)
|
||||||
result = cast[NimString](growObj(result,
|
result = cast[NimString](growObj(result,
|
||||||
sizeof(TGenericSeq) + (result.reserved+1) * sizeof(char)))
|
sizeof(TGenericSeq) + result.reserved + 1))
|
||||||
result.data[result.len] = c
|
result.data[result.len] = c
|
||||||
result.data[result.len+1] = '\0'
|
result.data[result.len+1] = '\0'
|
||||||
inc(result.len)
|
inc(result.len)
|
||||||
|
|
@ -157,7 +169,7 @@ proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} =
|
||||||
result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1))
|
result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1))
|
||||||
result.reserved = sp
|
result.reserved = sp
|
||||||
#result = rawNewString(sp)
|
#result = rawNewString(sp)
|
||||||
#copyMem(result, dest, dest.len * sizeof(char) + sizeof(TGenericSeq))
|
#copyMem(result, dest, dest.len + sizeof(TGenericSeq))
|
||||||
# DO NOT UPDATE LEN YET: dest.len = newLen
|
# DO NOT UPDATE LEN YET: dest.len = newLen
|
||||||
|
|
||||||
proc appendString(dest, src: NimString) {.compilerproc, inline.} =
|
proc appendString(dest, src: NimString) {.compilerproc, inline.} =
|
||||||
|
|
@ -203,7 +215,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
|
||||||
GenericSeqSize))
|
GenericSeqSize))
|
||||||
elif newLen < result.len:
|
elif newLen < result.len:
|
||||||
# we need to decref here, otherwise the GC leaks!
|
# we need to decref here, otherwise the GC leaks!
|
||||||
when not defined(boehmGC) and not defined(nogc) and
|
when not defined(boehmGC) and not defined(nogc) and
|
||||||
not defined(gcMarkAndSweep):
|
not defined(gcMarkAndSweep):
|
||||||
when compileOption("gc", "v2"):
|
when compileOption("gc", "v2"):
|
||||||
for i in newLen..result.len-1:
|
for i in newLen..result.len-1:
|
||||||
|
|
@ -220,7 +232,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
|
||||||
forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +%
|
forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +%
|
||||||
GenericSeqSize +% (i*%elemSize)),
|
GenericSeqSize +% (i*%elemSize)),
|
||||||
extGetCellType(result).base, waZctDecRef)
|
extGetCellType(result).base, waZctDecRef)
|
||||||
|
|
||||||
# XXX: zeroing out the memory can still result in crashes if a wiped-out
|
# XXX: zeroing out the memory can still result in crashes if a wiped-out
|
||||||
# cell is aliased by another pointer (ie proc parameter or a let variable).
|
# cell is aliased by another pointer (ie proc parameter or a let variable).
|
||||||
# This is a tought problem, because even if we don't zeroMem here, in the
|
# This is a tought problem, because even if we don't zeroMem here, in the
|
||||||
|
|
@ -258,13 +270,23 @@ proc nimFloatToStr(f: float): string {.compilerproc.} =
|
||||||
if buf[i] == ',':
|
if buf[i] == ',':
|
||||||
buf[i] = '.'
|
buf[i] = '.'
|
||||||
hasDot = true
|
hasDot = true
|
||||||
elif buf[i] in {'a'..'z', 'A'..'Z', '.'}:
|
elif buf[i] in {'a'..'z', 'A'..'Z', '.'}:
|
||||||
hasDot = true
|
hasDot = true
|
||||||
if not hasDot:
|
if not hasDot:
|
||||||
buf[n] = '.'
|
buf[n] = '.'
|
||||||
buf[n+1] = '0'
|
buf[n+1] = '0'
|
||||||
buf[n+2] = '\0'
|
buf[n+2] = '\0'
|
||||||
result = $buf
|
# On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' are produced.
|
||||||
|
# We want to get rid of these here:
|
||||||
|
if buf[n-1] == 'N':
|
||||||
|
result = "nan"
|
||||||
|
elif buf[n-1] == 'F':
|
||||||
|
if buf[0] == '-':
|
||||||
|
result = "-inf"
|
||||||
|
else:
|
||||||
|
result = "inf"
|
||||||
|
else:
|
||||||
|
result = $buf
|
||||||
|
|
||||||
proc strtod(buf: cstring, endptr: ptr cstring): float64 {.importc,
|
proc strtod(buf: cstring, endptr: ptr cstring): float64 {.importc,
|
||||||
header: "<stdlib.h>", noSideEffect.}
|
header: "<stdlib.h>", noSideEffect.}
|
||||||
|
|
@ -299,7 +321,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
||||||
template addToBuf(c) =
|
template addToBuf(c) =
|
||||||
if ti < t.high:
|
if ti < t.high:
|
||||||
t[ti] = c; inc(ti)
|
t[ti] = c; inc(ti)
|
||||||
|
|
||||||
# Sign?
|
# Sign?
|
||||||
if s[i] == '+' or s[i] == '-':
|
if s[i] == '+' or s[i] == '-':
|
||||||
if s[i] == '-':
|
if s[i] == '-':
|
||||||
|
|
@ -320,7 +342,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
||||||
if s[i] == 'I' or s[i] == 'i':
|
if s[i] == 'I' or s[i] == 'i':
|
||||||
if s[i+1] == 'N' or s[i+1] == 'n':
|
if s[i+1] == 'N' or s[i+1] == 'n':
|
||||||
if s[i+2] == 'F' or s[i+2] == 'f':
|
if s[i+2] == 'F' or s[i+2] == 'f':
|
||||||
if s[i+3] notin IdentChars:
|
if s[i+3] notin IdentChars:
|
||||||
number = Inf*sign
|
number = Inf*sign
|
||||||
return i+3 - start
|
return i+3 - start
|
||||||
return 0
|
return 0
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ when useWinVersion:
|
||||||
from winlean import SocketHandle
|
from winlean import SocketHandle
|
||||||
else:
|
else:
|
||||||
const
|
const
|
||||||
versions = "(.10|.1.0.1|.1.0.0|.0.9.9|.0.9.8|.0.9.7|.0.9.6|.0.9.5|.0.9.4)"
|
versions = "(.10|.1.0.1|.1.0.0|.0.9.9|.0.9.8)"
|
||||||
when defined(macosx):
|
when defined(macosx):
|
||||||
const
|
const
|
||||||
DLLSSLName = "libssl" & versions & ".dylib"
|
DLLSSLName = "libssl" & versions & ".dylib"
|
||||||
|
|
@ -141,6 +141,14 @@ const
|
||||||
SSL_CTRL_GET_MAX_CERT_LIST* = 50
|
SSL_CTRL_GET_MAX_CERT_LIST* = 50
|
||||||
SSL_CTRL_SET_MAX_CERT_LIST* = 51 #* Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success
|
SSL_CTRL_SET_MAX_CERT_LIST* = 51 #* Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success
|
||||||
# * when just a single record has been written): *
|
# * when just a single record has been written): *
|
||||||
|
SSL_CTRL_SET_TLSEXT_SERVERNAME_CB = 53
|
||||||
|
SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG = 54
|
||||||
|
SSL_CTRL_SET_TLSEXT_HOSTNAME = 55
|
||||||
|
TLSEXT_NAMETYPE_host_name* = 0
|
||||||
|
SSL_TLSEXT_ERR_OK* = 0
|
||||||
|
SSL_TLSEXT_ERR_ALERT_WARNING* = 1
|
||||||
|
SSL_TLSEXT_ERR_ALERT_FATAL* = 2
|
||||||
|
SSL_TLSEXT_ERR_NOACK* = 3
|
||||||
SSL_MODE_ENABLE_PARTIAL_WRITE* = 1 #* Make it possible to retry SSL_write() with changed buffer location
|
SSL_MODE_ENABLE_PARTIAL_WRITE* = 1 #* Make it possible to retry SSL_write() with changed buffer location
|
||||||
# * (buffer contents must stay the same!); this is not the default to avoid
|
# * (buffer contents must stay the same!); this is not the default to avoid
|
||||||
# * the misconception that non-blocking SSL_write() behaves like
|
# * the misconception that non-blocking SSL_write() behaves like
|
||||||
|
|
@ -296,9 +304,41 @@ proc CRYPTO_malloc_init*() =
|
||||||
proc SSL_CTX_ctrl*(ctx: SslCtx, cmd: cInt, larg: int, parg: pointer): int{.
|
proc SSL_CTX_ctrl*(ctx: SslCtx, cmd: cInt, larg: int, parg: pointer): int{.
|
||||||
cdecl, dynlib: DLLSSLName, importc.}
|
cdecl, dynlib: DLLSSLName, importc.}
|
||||||
|
|
||||||
|
proc SSL_CTX_callback_ctrl(ctx: SslCtx, typ: cInt, fp: PFunction): int{.
|
||||||
|
cdecl, dynlib: DLLSSLName, importc.}
|
||||||
|
|
||||||
proc SSLCTXSetMode*(ctx: SslCtx, mode: int): int =
|
proc SSLCTXSetMode*(ctx: SslCtx, mode: int): int =
|
||||||
result = SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, mode, nil)
|
result = SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, mode, nil)
|
||||||
|
|
||||||
|
proc SSL_ctrl*(ssl: SslPtr, cmd: cInt, larg: int, parg: pointer): int{.
|
||||||
|
cdecl, dynlib: DLLSSLName, importc.}
|
||||||
|
|
||||||
|
proc SSL_set_tlsext_host_name*(ssl: SslPtr, name: cstring): int =
|
||||||
|
result = SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, name)
|
||||||
|
## Set the SNI server name extension to be used in a client hello.
|
||||||
|
## Returns 1 if SNI was set, 0 if current SSL configuration doesn't support SNI.
|
||||||
|
|
||||||
|
|
||||||
|
proc SSL_get_servername*(ssl: SslPtr, typ: cInt = TLSEXT_NAMETYPE_host_name): cstring {.cdecl, dynlib: DLLSSLName, importc.}
|
||||||
|
## Retrieve the server name requested in the client hello. This can be used
|
||||||
|
## in the callback set in `SSL_CTX_set_tlsext_servername_callback` to
|
||||||
|
## implement virtual hosting. May return `nil`.
|
||||||
|
|
||||||
|
proc SSL_CTX_set_tlsext_servername_callback*(ctx: SslCtx, cb: proc(ssl: SslPtr, cb_id: int, arg: pointer): int {.cdecl.}): int =
|
||||||
|
## Set the callback to be used on listening SSL connections when the client hello is received.
|
||||||
|
##
|
||||||
|
## The callback should return one of:
|
||||||
|
## * SSL_TLSEXT_ERR_OK
|
||||||
|
## * SSL_TLSEXT_ERR_ALERT_WARNING
|
||||||
|
## * SSL_TLSEXT_ERR_ALERT_FATAL
|
||||||
|
## * SSL_TLSEXT_ERR_NOACK
|
||||||
|
result = SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, cast[PFunction](cb))
|
||||||
|
|
||||||
|
proc SSL_CTX_set_tlsext_servername_arg*(ctx: SslCtx, arg: pointer): int =
|
||||||
|
## Set the pointer to be used in the callback registered to ``SSL_CTX_set_tlsext_servername_callback``.
|
||||||
|
result = SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, arg)
|
||||||
|
|
||||||
|
|
||||||
proc bioNew*(b: PBIO_METHOD): BIO{.cdecl, dynlib: DLLUtilName, importc: "BIO_new".}
|
proc bioNew*(b: PBIO_METHOD): BIO{.cdecl, dynlib: DLLUtilName, importc: "BIO_new".}
|
||||||
proc bioFreeAll*(b: BIO){.cdecl, dynlib: DLLUtilName, importc: "BIO_free_all".}
|
proc bioFreeAll*(b: BIO){.cdecl, dynlib: DLLUtilName, importc: "BIO_free_all".}
|
||||||
proc bioSMem*(): PBIO_METHOD{.cdecl, dynlib: DLLUtilName, importc: "BIO_s_mem".}
|
proc bioSMem*(): PBIO_METHOD{.cdecl, dynlib: DLLUtilName, importc: "BIO_s_mem".}
|
||||||
|
|
@ -341,8 +381,6 @@ else:
|
||||||
dynlib: DLLSSLName, importc.}
|
dynlib: DLLSSLName, importc.}
|
||||||
|
|
||||||
proc SslSetFd*(s: PSSL, fd: cInt): cInt{.cdecl, dynlib: DLLSSLName, importc.}
|
proc SslSetFd*(s: PSSL, fd: cInt): cInt{.cdecl, dynlib: DLLSSLName, importc.}
|
||||||
proc SslCtrl*(ssl: PSSL, cmd: cInt, larg: int, parg: Pointer): int{.cdecl,
|
|
||||||
dynlib: DLLSSLName, importc.}
|
|
||||||
proc SslCTXCtrl*(ctx: PSSL_CTX, cmd: cInt, larg: int, parg: Pointer): int{.
|
proc SslCTXCtrl*(ctx: PSSL_CTX, cmd: cInt, larg: int, parg: Pointer): int{.
|
||||||
cdecl, dynlib: DLLSSLName, importc.}
|
cdecl, dynlib: DLLSSLName, importc.}
|
||||||
|
|
||||||
|
|
|
||||||
21
readme.md
21
readme.md
|
|
@ -1,5 +1,5 @@
|
||||||
# Nim Compiler
|
# Nim Compiler
|
||||||
This repo contains the Nim compiler, Nim's stdlib, tools and
|
This repo contains the Nim compiler, Nim's stdlib, tools and
|
||||||
documentation.
|
documentation.
|
||||||
|
|
||||||
## Compiling
|
## Compiling
|
||||||
|
|
@ -8,17 +8,13 @@ the Nim compiler itself is written in the Nim programming language
|
||||||
the C source of an older version of the compiler are needed to bootstrap the
|
the C source of an older version of the compiler are needed to bootstrap the
|
||||||
latest version. The C sources are available in a separate repo [here](http://github.com/nim-lang/csources).
|
latest version. The C sources are available in a separate repo [here](http://github.com/nim-lang/csources).
|
||||||
|
|
||||||
Pre-compiled snapshots of the compiler are also available on
|
The compiler currently supports the following platform and architecture
|
||||||
[Nimbuild](http://build.nim-lang.org/). Your platform however may not
|
|
||||||
currently be built for.
|
|
||||||
|
|
||||||
The compiler currently supports the following platform and architecture
|
|
||||||
combinations:
|
combinations:
|
||||||
|
|
||||||
* Windows (Windows XP or greater) - x86 and x86_64
|
* Windows (Windows XP or greater) - x86 and x86_64
|
||||||
* Linux (most, if not all, distributions) - x86, x86_64, ppc64 and armv6l
|
* Linux (most, if not all, distributions) - x86, x86_64, ppc64 and armv6l
|
||||||
* Mac OS X 10.04 or higher - x86, x86_64 and ppc64
|
* Mac OS X 10.04 or higher - x86, x86_64 and ppc64
|
||||||
|
|
||||||
In reality a lot more are supported, however they are not tested regularly.
|
In reality a lot more are supported, however they are not tested regularly.
|
||||||
|
|
||||||
To build from source you will need:
|
To build from source you will need:
|
||||||
|
|
@ -39,8 +35,7 @@ $ bin/nim c koch
|
||||||
$ ./koch boot -d:release
|
$ ./koch boot -d:release
|
||||||
```
|
```
|
||||||
|
|
||||||
``koch install [dir]`` may then be used to install Nim, or you can simply
|
``koch install [dir]`` may then be used to install Nim, but lots of things don't work then so don't do that. Add it to your PATH instead. More ``koch`` related options are documented in
|
||||||
add it to your PATH. More ``koch`` related options are documented in
|
|
||||||
[doc/koch.txt](doc/koch.txt).
|
[doc/koch.txt](doc/koch.txt).
|
||||||
|
|
||||||
The above steps can be performed on Windows in a similar fashion, the
|
The above steps can be performed on Windows in a similar fashion, the
|
||||||
|
|
@ -55,9 +50,9 @@ questions, and you can also get help in the IRC channel on
|
||||||
tag](http://stackoverflow.com/questions/tagged/nim).
|
tag](http://stackoverflow.com/questions/tagged/nim).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
The compiler and the standard library are licensed under the MIT license,
|
The compiler and the standard library are licensed under the MIT license,
|
||||||
except for some modules where the documentation suggests otherwise. This means
|
except for some modules where the documentation suggests otherwise. This means
|
||||||
that you can use any license for your own programs developed with Nim,
|
that you can use any license for your own programs developed with Nim,
|
||||||
allowing you to create commercial applications.
|
allowing you to create commercial applications.
|
||||||
|
|
||||||
Read copying.txt for more details.
|
Read copying.txt for more details.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
line: 21
|
output: "action 3 arg"
|
||||||
errormsg: "invalid type: 'Table[string, proc (string){.gcsafe.}]'"
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import tables
|
import tables
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,14 @@ discard """
|
||||||
WARNING: false first assertion from bar
|
WARNING: false first assertion from bar
|
||||||
ERROR: false second assertion from bar
|
ERROR: false second assertion from bar
|
||||||
-1
|
-1
|
||||||
tests/assert/tfailedassert.nim:27 false assertion from foo
|
tfailedassert.nim:27 false assertion from foo
|
||||||
'''
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
type
|
type
|
||||||
TLineInfo = tuple[filename: string, line: int]
|
TLineInfo = tuple[filename: string, line: int]
|
||||||
|
|
||||||
TMyError = object of E_Base
|
TMyError = object of Exception
|
||||||
lineinfo: TLineInfo
|
lineinfo: TLineInfo
|
||||||
|
|
||||||
EMyError = ref TMyError
|
EMyError = ref TMyError
|
||||||
|
|
|
||||||
30
tests/ccgbugs/tmissingderef.nim
Normal file
30
tests/ccgbugs/tmissingderef.nim
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
discard """
|
||||||
|
output: '''255
|
||||||
|
1 1
|
||||||
|
0.5'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #1181
|
||||||
|
|
||||||
|
type
|
||||||
|
TFoo = object
|
||||||
|
x: int32
|
||||||
|
|
||||||
|
proc mainowar =
|
||||||
|
var foo: TFoo
|
||||||
|
foo.x = 0xff
|
||||||
|
var arr1 = cast[ptr array[4, uint8]](addr foo)[] # Fails.
|
||||||
|
echo arr1[when cpuEndian == littleEndian: 0 else: 3]
|
||||||
|
|
||||||
|
var i = 1i32
|
||||||
|
let x = addr i
|
||||||
|
var arr2 = cast[ptr array[4, uint8]](x)[] # Fails.
|
||||||
|
echo arr2[when cpuEndian == littleEndian: 0 else: 3], " ", i
|
||||||
|
|
||||||
|
# bug #1715
|
||||||
|
var a: array[2, float32] = [0.5'f32, 0.7]
|
||||||
|
let p = addr a
|
||||||
|
var b = p[]
|
||||||
|
echo b[0]
|
||||||
|
|
||||||
|
mainowar()
|
||||||
15
tests/ccgbugs/tstringslice.nim
Normal file
15
tests/ccgbugs/tstringslice.nim
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
discard """
|
||||||
|
disabled: "true"
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Now the compiler fails with OOM. yay.
|
||||||
|
|
||||||
|
# bug #794
|
||||||
|
type TRange = range[0..3]
|
||||||
|
|
||||||
|
const str = "123456789"
|
||||||
|
|
||||||
|
for i in TRange.low .. TRange.high:
|
||||||
|
echo str[i] #This works fine
|
||||||
|
echo str[int(i) .. int(TRange.high)] #So does this
|
||||||
|
echo str[i .. TRange.high] #The compiler complains about this
|
||||||
80
tests/ccgbugs/tuple_canon.nim
Normal file
80
tests/ccgbugs/tuple_canon.nim
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
# bug #2250
|
||||||
|
|
||||||
|
import
|
||||||
|
math, strutils
|
||||||
|
|
||||||
|
type
|
||||||
|
Meters = float
|
||||||
|
Point2[T] = tuple[x, y: T]
|
||||||
|
|
||||||
|
HexState* = enum
|
||||||
|
hsOn, hsOff
|
||||||
|
|
||||||
|
Index = uint16
|
||||||
|
|
||||||
|
HexGrid* = object
|
||||||
|
w, h: int ## Width and height of the hex grid.
|
||||||
|
radius: Meters ## Radius of circle that circumscribes a hexagon.
|
||||||
|
grid: seq[HexState] ## Information on what hexes are drawn.
|
||||||
|
|
||||||
|
HexVtxIndex = enum
|
||||||
|
hiA, hiB, hiC, hiD, hiE, hiF
|
||||||
|
|
||||||
|
HexCoord* = Point2[int]
|
||||||
|
|
||||||
|
const
|
||||||
|
HexDY = sqrt(1.0 - (0.5 * 0.5)) # dy from center to midpoint of 1-2
|
||||||
|
HexDX = sqrt(1.0 - (HexDY * HexDY)) # dx from center to midpoint of 1-5 (0.5)
|
||||||
|
|
||||||
|
|
||||||
|
let
|
||||||
|
hexOffsets : array[HexVtxIndex, Point2[float]] = [
|
||||||
|
(-1.0, 0.0),
|
||||||
|
(-HexDX, -HexDY),
|
||||||
|
(HexDX, -HexDY),
|
||||||
|
(1.0, 0.0),
|
||||||
|
(HexDX, HexDY),
|
||||||
|
(-HexDX, HexDY)]
|
||||||
|
|
||||||
|
evenSharingOffsets : array[HexVtxIndex, tuple[hc: HexCoord; idx: HexVtxIndex]] = [
|
||||||
|
((0,0), hiA),
|
||||||
|
((0,0), hiB),
|
||||||
|
((1,-1), hiA),
|
||||||
|
((1,0), hiB),
|
||||||
|
((1,0), hiA),
|
||||||
|
((0,1), hiB)]
|
||||||
|
|
||||||
|
oddSharingOffsets : array[HexVtxIndex, tuple[hc: HexCoord; idx: HexVtxIndex]] = [
|
||||||
|
((0,0), hiA),
|
||||||
|
((0,0), hiB),
|
||||||
|
((1,0), hiA),
|
||||||
|
((1,1), hiB),
|
||||||
|
((1,1), hiA),
|
||||||
|
((0,1), hiB)]
|
||||||
|
|
||||||
|
template odd*(i: int) : expr =
|
||||||
|
(i and 1) != 0
|
||||||
|
|
||||||
|
proc vidx(hg: HexGrid; col, row: int; i: HexVtxIndex) : Index =
|
||||||
|
#NOTE: this variation compiles
|
||||||
|
#var offset : type(evenSharingOffsets[i])
|
||||||
|
#
|
||||||
|
#if odd(col):
|
||||||
|
# offset = oddSharingOffsets[i]
|
||||||
|
#else:
|
||||||
|
# offset = evenSharingOffsets[i]
|
||||||
|
|
||||||
|
let
|
||||||
|
#NOTE: this line generates the bad code
|
||||||
|
offset = (if odd(col): oddSharingOffsets[i] else: evenSharingOffsets[i])
|
||||||
|
x = col + 1 + offset.hc.x
|
||||||
|
y = row + 1 + offset.hc.y
|
||||||
|
|
||||||
|
result = Index(x*2 + y * (hg.w + 2)*2 + int(offset.idx))
|
||||||
|
|
||||||
|
proc go() =
|
||||||
|
var hg : HexGrid
|
||||||
|
|
||||||
|
echo "vidx ", $vidx(hg, 1, 2, hiC)
|
||||||
|
|
||||||
|
go()
|
||||||
8
tests/clearmsg/tconsttypemismatch.nim
Normal file
8
tests/clearmsg/tconsttypemismatch.nim
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
discard """
|
||||||
|
file: "tconsttypemismatch.nim"
|
||||||
|
line: 7
|
||||||
|
errormsg: "type mismatch"
|
||||||
|
"""
|
||||||
|
# bug #2252
|
||||||
|
const foo: int = 1000 / 30
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
cmd: "nim cpp $target"
|
cmd: "nim cpp $file"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import rawsockets
|
import rawsockets
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
discard """
|
discard """
|
||||||
cmd: "nim cpp $target"
|
cmd: "nim cpp $file"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import typeinfo
|
import typeinfo
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
discard """
|
discard """
|
||||||
line: 9
|
nimout: "a is deprecated [Deprecated]"
|
||||||
errormsg: "'a' is deprecated [Deprecated]"
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
var
|
var
|
||||||
a {.deprecated.}: array[0..11, int]
|
a {.deprecated.}: array[0..11, int]
|
||||||
|
|
||||||
a[8] = 1
|
a[8] = 1
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
line: 20
|
line: 23
|
||||||
errormsg: " usage of a type with a destructor in a non destructible context"
|
nimout: " usage of a type with a destructor in a non destructible context"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
{.experimental.}
|
{.experimental.}
|
||||||
|
|
@ -19,5 +19,9 @@ proc open: TMyObj =
|
||||||
|
|
||||||
proc `$`(x: TMyObj): string = $x.y
|
proc `$`(x: TMyObj): string = $x.y
|
||||||
|
|
||||||
echo open()
|
proc foo =
|
||||||
|
discard open()
|
||||||
|
|
||||||
|
# XXX doesn't trigger this yet:
|
||||||
|
#echo open()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
line: 7
|
line: 7
|
||||||
errormsg: "expression 'items' cannot be called"
|
errormsg: "undeclared identifier: 'items'"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
type a = enum b,c,d
|
type a = enum b,c,d
|
||||||
|
|
|
||||||
18
tests/exception/tdefer1.nim
Normal file
18
tests/exception/tdefer1.nim
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
discard """
|
||||||
|
output: '''hi
|
||||||
|
hi'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #1742
|
||||||
|
|
||||||
|
template test(): expr =
|
||||||
|
let a = 0
|
||||||
|
defer: echo "hi"
|
||||||
|
a
|
||||||
|
|
||||||
|
let i = test()
|
||||||
|
|
||||||
|
import strutils
|
||||||
|
let x = try: parseInt("133a")
|
||||||
|
except: -1
|
||||||
|
finally: echo "hi"
|
||||||
6
tests/exprs/tresultwarning.nim
Normal file
6
tests/exprs/tresultwarning.nim
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
discard """
|
||||||
|
nimout: "Special variable 'result' is shadowed. [ResultShadowed]"
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc test(): string =
|
||||||
|
var result = "foo"
|
||||||
|
|
@ -188,7 +188,7 @@ proc traceTree[T,D](root: PNode[T,D]) =
|
||||||
write stdout, space
|
write stdout, space
|
||||||
|
|
||||||
proc doTrace(n: PNode[T,D], level: int) =
|
proc doTrace(n: PNode[T,D], level: int) =
|
||||||
var space = repeatChar(2 * level)
|
var space = spaces(2 * level)
|
||||||
traceln(space)
|
traceln(space)
|
||||||
write stdout, "node: "
|
write stdout, "node: "
|
||||||
if n == nil:
|
if n == nil:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
# Bug #2022
|
# Bug #2022
|
||||||
|
|
||||||
|
discard """
|
||||||
|
output: '''@[97, 45]
|
||||||
|
@[true, false]
|
||||||
|
@[false, false]'''
|
||||||
|
"""
|
||||||
|
|
||||||
## The goal of this snippet is to provide and test a construct for general-
|
## The goal of this snippet is to provide and test a construct for general-
|
||||||
## purpose, random-access mapping. I use an AST-manipulation-based approach
|
## purpose, random-access mapping. I use an AST-manipulation-based approach
|
||||||
## because it's more efficient than using procedure pointers and less
|
## because it's more efficient than using procedure pointers and less
|
||||||
|
|
@ -31,6 +37,7 @@ type Mapped[Input; predicate: static[string]] = object
|
||||||
input: Input
|
input: Input
|
||||||
|
|
||||||
macro map(input, predicate: expr): expr =
|
macro map(input, predicate: expr): expr =
|
||||||
|
let predicate = callsite()[2]
|
||||||
newNimNode(nnkObjConstr).add(
|
newNimNode(nnkObjConstr).add(
|
||||||
newNimNode(nnkBracketExpr).add(
|
newNimNode(nnkBracketExpr).add(
|
||||||
ident"Mapped",
|
ident"Mapped",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
file: "toop1.nim"
|
|
||||||
output: "in globalaux2: 10\ntotal globals: 2\nint value: 100\nstring value: second"
|
output: "in globalaux2: 10\ntotal globals: 2\nint value: 100\nstring value: second"
|
||||||
|
disabled: "true"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import globalaux, globalaux2
|
import globalaux, globalaux2
|
||||||
|
|
|
||||||
54
tests/init/tuninit2.nim
Normal file
54
tests/init/tuninit2.nim
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
# bug #2316
|
||||||
|
|
||||||
|
type
|
||||||
|
EventType = enum
|
||||||
|
QuitEvent = 5
|
||||||
|
AppMain* = ref object of RootObj
|
||||||
|
width: int
|
||||||
|
height: int
|
||||||
|
title: string
|
||||||
|
running: bool
|
||||||
|
event_type: EventType
|
||||||
|
App* = ref object of AppMain
|
||||||
|
draw_proc: proc(app: AppMain): void {.closure.}
|
||||||
|
events_proc: proc(app: AppMain): void {.closure.}
|
||||||
|
update_proc: proc(app: AppMain, dt: float): void {.closure.}
|
||||||
|
load_proc: proc(app: AppMain): void {.closure.}
|
||||||
|
|
||||||
|
|
||||||
|
proc initApp*(t: string, w, h: int): App =
|
||||||
|
App(width: w, height: h, title: t, event_type: EventType.QuitEvent)
|
||||||
|
|
||||||
|
|
||||||
|
method getTitle*(self: AppMain): string = self.title
|
||||||
|
method getWidth*(self: AppMain): int = self.width
|
||||||
|
method getHeight*(self: AppMain): int = self.height
|
||||||
|
|
||||||
|
|
||||||
|
method draw*(self: App, draw: proc(app: AppMain)): void =
|
||||||
|
self.draw_proc = draw
|
||||||
|
|
||||||
|
method load*(self: App, load: proc(a: AppMain)): void =
|
||||||
|
self.load_proc = load
|
||||||
|
|
||||||
|
method events*(self: App, events: proc(app: AppMain)): void =
|
||||||
|
self.events_proc = events
|
||||||
|
|
||||||
|
method update*(self: App, update: proc(app: AppMain, delta: float)): void =
|
||||||
|
self.update_proc = update
|
||||||
|
|
||||||
|
method run*(self: App): void = discard
|
||||||
|
|
||||||
|
var mygame = initApp("Example", 800, 600)
|
||||||
|
|
||||||
|
mygame.load(proc(app: AppMain): void =
|
||||||
|
echo app.getTitle()
|
||||||
|
echo app.getWidth()
|
||||||
|
echo app.getHeight()
|
||||||
|
)
|
||||||
|
|
||||||
|
mygame.events(proc(app: AppMain): void =
|
||||||
|
discard
|
||||||
|
)
|
||||||
|
|
||||||
|
mygame.run()
|
||||||
|
|
@ -471,7 +471,7 @@ proc build_help*(expected: seq[Tparameter_specification] = @[],
|
||||||
let width = prefixes.map(proc (x: string): int = 3 + len(x)).max
|
let width = prefixes.map(proc (x: string): int = 3 + len(x)).max
|
||||||
|
|
||||||
for line in zip(prefixes, helps):
|
for line in zip(prefixes, helps):
|
||||||
result.add(line.a & repeatChar(width - line.a.len) & line.b)
|
result.add(line.a & spaces(width - line.a.len) & line.b)
|
||||||
|
|
||||||
|
|
||||||
proc echo_help*(expected: seq[Tparameter_specification] = @[],
|
proc echo_help*(expected: seq[Tparameter_specification] = @[],
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import streams
|
import streams
|
||||||
from strutils import repeatChar
|
from strutils import repeat
|
||||||
|
|
||||||
proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): TaintedString =
|
proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): TaintedString =
|
||||||
var lastChr = length
|
var lastChr = length
|
||||||
|
|
@ -10,7 +10,7 @@ proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): TaintedString =
|
||||||
proc writePaddedStr*(s: PStream, str: string, length: int, padChar = '\0') =
|
proc writePaddedStr*(s: PStream, str: string, length: int, padChar = '\0') =
|
||||||
if str.len < length:
|
if str.len < length:
|
||||||
s.write(str)
|
s.write(str)
|
||||||
s.write(repeatChar(length - str.len, padChar))
|
s.write(repeat(padChar, length - str.len))
|
||||||
elif str.len > length:
|
elif str.len > length:
|
||||||
s.write(str.substr(0, length - 1))
|
s.write(str.substr(0, length - 1))
|
||||||
else:
|
else:
|
||||||
|
|
@ -37,7 +37,7 @@ when isMainModule:
|
||||||
testStream.setPosition 0
|
testStream.setPosition 0
|
||||||
testStream.writePaddedStr("Sup", 10)
|
testStream.writePaddedStr("Sup", 10)
|
||||||
echo(repr(testStream), testStream.data.len)
|
echo(repr(testStream), testStream.data.len)
|
||||||
doAssert testStream.data == "Sup"&repeatChar(7, '\0')
|
doAssert testStream.data == "Sup"&repeat('\0', 7)
|
||||||
|
|
||||||
testStream.setPosition 0
|
testStream.setPosition 0
|
||||||
res = testStream.readPaddedStr(10)
|
res = testStream.readPaddedStr(10)
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ when isMainModule:
|
||||||
discard """block:
|
discard """block:
|
||||||
var
|
var
|
||||||
TestFile: FileChallengePair
|
TestFile: FileChallengePair
|
||||||
contents = repeatStr(2, "abcdefghijklmnopqrstuvwxyz")
|
contents = repeat("abcdefghijklmnopqrstuvwxyz", 2)
|
||||||
testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32)
|
testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32)
|
||||||
testFile.file = checksumStr(contents)
|
testFile.file = checksumStr(contents)
|
||||||
myAssets.add testFile"""
|
myAssets.add testFile"""
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ when defined(recordMode):
|
||||||
isRecording = false
|
isRecording = false
|
||||||
proc zeroPad*(s: string; minLen: int): string =
|
proc zeroPad*(s: string; minLen: int): string =
|
||||||
if s.len < minLen:
|
if s.len < minLen:
|
||||||
result = repeatChar(minLen - s.len, '0')
|
result = repeat(0, minLen - s.len)
|
||||||
result.add s
|
result.add s
|
||||||
else:
|
else:
|
||||||
result = s
|
result = s
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,9 @@ when isMainModule:
|
||||||
var res = t.map(proc(z: int): int = result = z * 10)
|
var res = t.map(proc(z: int): int = result = z * 10)
|
||||||
dumpSeq res
|
dumpSeq res
|
||||||
|
|
||||||
from strutils import toHex, repeatStr
|
from strutils import toHex
|
||||||
var foocakes = t.map(proc(z: int): string =
|
var foocakes = t.map(proc(z: int): string =
|
||||||
result = toHex((z * 23).biggestInt, 4))
|
result = toHex((z * 23).BiggestInt, 4))
|
||||||
dumpSeq foocakes
|
dumpSeq foocakes
|
||||||
|
|
||||||
t.mapInPlace(proc(z: int): int = result = z * 30)
|
t.mapInPlace(proc(z: int): int = result = z * 30)
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue